Как извлечь возвращенные данные из 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
.. что мы можем легко распечатать при отладке или преобразовать в сохраненное значение в объекте.