Как извлечь возвращенные данные из QDBusMessage в вызове Qt DBus?

Я пытаюсь вызвать интерфейс DBus соискателя WPA с использованием библиотеки классов Qt QDBus. В частности, я пытаюсь использовать вызов свойства "Get" для получения значения свойства "Interfaces".

Спецификация DBus (через самоанализ) для "Get":

<interface name="org.freedesktop.DBus.Properties">
    <method name="Get">
        <arg name="interface" type="s" direction="in"/>
        <arg name="propname" type="s" direction="in"/>
        <arg name="value" type="v" direction="out"/>
    </method>
    ...
</interface>

Кажется достаточно простым. Ввод двух строк и вывод является вариантом (это типы DBus). Для свойства "Интерфейсы" я ожидаю, что вариант будет массивом путей к объектам (тип DBus "ao").

я использую QDBusInterface::call() вызвать метод DBus, который возвращает QDBusMessage, но я не могу понять, как извлечь из этого мои данные.

QDBusMessage::arguments() возвращает QList<QVariant>, Я пробовал различные преобразования элементов в этом списке, пытаясь найти свой массив путей к объектам, но вместо этого я просто получаю пустую строку.

QVariant::type() кажется, это должно помочь, но это только кажется, чтобы вернуть тип QDBusMessage, что явно не так. Например:

// 'message' is of type QDBusMessage
qDebug() << "Argument 0 type is" << message.arguments().at(0).type();

печатает:

Argument 0 type is QVariant::QDBusMessage

Как извлечь фактические данные сообщения?

3 ответа

Решение

Самый простой способ, который я нашел, это использовать qDebug() печатать результаты, как вы идете. Обычно это указывает на то, какой тип вам нужно преобразовать в следующий, пока вы, наконец, не достигнете самого внутреннего типа.

Qdbusviewer - полезный инструмент для определения необходимых параметров DBus. В этом случае:

  • Служба WPAS: "fi.w1.wpa_supplicant1"
  • Путь WPAS: "/ fi / w1 / wpa_supplicant1"
  • Идентификатор интерфейса свойств: "org.freedesktop.DBus.Properties"
  • Идентификатор интерфейса WPAS: "fi.w1.wpa_supplicant1"

В инициализации QDBusInterface для вызова Getнам нужно использоватьProperties интерфейс, так как это интерфейс, который обеспечивает Getметод.

В вызове Get с использованием QDBusInterface::call() метод, второй и третий параметры соответствуют параметрам, перечисленным в выводе самоанализа ("interface" а также "propname"). "interface" где можно найти недвижимость, которая для "Interfaces" свойство "fi.w1.wpa_supplicant1" (это можно подтвердить с помощью qdbusviewer).

"propname" Параметр - это просто имя свойства:"Interfaces" в этом случае.

Код до сих пор:

std::string getInterface()
{
    QDBusInterface interface( "fi.w1.wpa_supplicant1",
                              "/fi/w1/wpa_supplicant1",
                              "org.freedesktop.DBus.Properties",
                              QDBusConnection::systemBus() );

    // Calls DBus method
    QDBusMessage result = interface.call( "Get",
                                          "fi.w1.wpa_supplicant1",
                                          "Interfaces" );

Это сложная часть. QDBusInterface::call() возвращает QDBusMessage, который содержит информацию о нашей собственности в ловушке внутри.

    qDebug() << result;

Этот отладочный оператор печатает:

QDBusMessage(type=MethodReturn, service=":1.2431", signature="v", contents=([Variant: [ObjectPath: /fi/w1/wpa_supplicant1/Interfaces/7/Networks/0]]) )

Выглядит хорошо. "ObjectPath" - это то, что мы ищем, и оно определенно где-то там.

Далее нам нужно QDBusMessage::arguments(), который "Возвращает список аргументов, которые будут отправлены или получены от D-Bus". Возвращает QList<QVariant>,

    QList<QVariant> outArgs = result.arguments();
    qDebug() << outArgs;

Оператор отладки печатает:

(QVariant(QDBusVariant, ) )

Эта "нотация" немного неясна (означают ли скобки списки?), Но мы продолжим.

    QVariant first = outArgs.at(0);
    qDebug() << first;

печатает:

QVariant(QDBusVariant, )

Таким образом, внешние скобки, похоже, указывают на массив, хотя почему во внутреннем наборе используется запятая, а не во внешнем наборе, является загадкой.

Мы продолжаем конвертировать типы, когда сталкиваемся с ними:

    QDBusVariant dbvFirst = first.value<QDBusVariant>();
    //qDebug() << dbvFirst; // compile error!

qDebug() не понимает QDBusVariantпоэтому здесь нет отладочной печати. Вместо этого, если мы посмотрим на документацию дляQDBusVariantмы видим, что это обеспечивает variant() метод для преобразования в обычный QVariant тип.

    QVariant vFirst = dbvFirst.variant();
    qDebug() << vFirst;

Кажется, мы идем кругами, но на этот раз вывод на печать немного другой:

QVariant(QDBusArgument, )

Другое преобразование:

    QDBusArgument dbusArgs = vFirst.value<QDBusArgument>();

Unfortuately, qDebug() здесь тоже не работает QDBusArgumentТип может содержать несколько различных типов элементов, которые описаны в документации Qt. QDBusArgument::currentType() говорит, какой у вас тип. В нашем случае:

    qDebug() << "QDBusArgument current type is" << dbusArgs.currentType();

печатает:

QDBusArgument current type is 2

2 средства ArrayType,

Согласно QDBusArgument Документация, мы можем извлечь элементы массива, используя следующий код:

    QDBusObjectPath path;
    dbusArgs.beginArray();
    while (!dbusArgs.atEnd())
    {
        dbusArgs >> path;
        // append path to a vector here if you want to keep it
    }
    dbusArgs.endArray();

Я предположил, что тип элемента массива QDBusObjectPath, поскольку на данный момент имеет смысл, чтобы это было так. Будет ясно, если я прав.

Если вы получите сообщение об ошибке QDBusArgument: write from a read-only objectизменить объявление dbusArgs чтобы:

    const QDBusArgument &dbusArgs = vFirst.value<QDBusArgument>();

qDebug() не поддерживает QDBusObjectPath либо, ноQDBusObjectPath::path() возвращает QStringТаким образом, мы можем получить отладочную печать следующим образом:

    qDebug() << path.path();

печатает:

"/fi/w1/wpa_supplicant1/Interfaces/7"

Наконец!

Моей целью было получить путь к объекту, возвращаемый GetInterface метод fi.w1.wpa_supplicant1 интерфейс.

Ответ @MatthewD был действительно полезен для меня, чтобы начать эксперимент, но, к сожалению, не сработал для меня должным образом. Я перепробовал все возможности. Но в итоге каким-то образом я получил требуемый результат другим, более коротким путем.

Я сделал следующее:
- У меня был интерфейс:
QDBusInterface interface("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1", "fi.w1.wpa_supplicant1", QDBusConnection::systemBus());

- Вызвать метод и сохранить сообщение
QDBusMessage mesg = interface.call("GetInterface", "wlan0");

- Тогда получите первый аргумент
QVariant var = mesg.arguments().at(0);

- Тогда получите путь к объекту
QDBusObjectPath objpath = var.value<QDBusObjectPath>();

- И наконец
QString path_str = objpath.path();

Теперь вы распечатываете путь как строку:
printf("Object path: %s\n", path_str);

Что ж, спустя долгое время!

Думаю, отладив ответ и увидев его ...

в variant() метод QDBusVariant result возвращает вариант QDBus как объект .. таким образом, вызов:

      const auto &resultArg = result.arguments().at(0).value<QDBusVariant>().variant();

вернуть QVariant .. что мы можем легко распечатать при отладке или преобразовать в сохраненное значение в объекте.

Другие вопросы по тегам