libdbus:从 DBusMessage 参数中获取字符串列表
libdbus: get a list of strings from DBusMessage arguments
我最近一直在学习 libdbus
,方法是编写一个向活动媒体播放器发送 mpris 消息的简单工具。
第一步是通过 DBus 获取媒体播放器列表:
// send the ListNames command over the DBus
DBusMessage* msg = dbus_message_new_method_call(
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListNames");
// send the message
DBusPendingCall* call;
dbus_bool_t success = dbus_connection_send_with_reply(con, msg, &call, 100);
if (!success || call == NULL) return 1;
// wait for a reply
dbus_pending_call_block(call);
// check reply
DBusMessage* reply = dbus_pending_call_steal_reply(call);
我现在必须解析 DBus 回复以获取媒体播放器名称列表。
阅读参考资料 material 后,我相信这应该可以通过 dbus_message_get_args 实现,如文档所述:
arrays of string, object path, and signature are supported; but these are returned as allocated memory and must be freed with dbus_free_string_array(). [...] To get a string array pass in "char ***array_location" and "int *n_elements".
这让我写下了以下内容:
// pull list of players from reply
const int MAX_ARGS = 10;
const char** args;
dbus_message_get_args(reply, &err, DBUS_TYPE_ARRAY, &args, &MAX_ARGS);
但是在检查我的 DBusError 时,我收到以下消息:
DBus Error:
org.freedesktop.DBus.Error.InvalidArgs
Argument 0 is specified to be an array of "unknown", but is actually an array of "string"
我本来以为我一定是通过了一个糟糕的 DBUS_TYPE
但找不到比 DBUS_TYPE_ARRAY
更合适的了。
我知道这也可以通过使用 dbus_message_iter
调用来实现,但文档似乎表明这不是必需的,甚至建议尽可能使用 get_message_args
。
所以实际的问题是...我是不是遗漏了一些关于文档的内容,或者函数调用有误?或者实际上无法使用此方法获取字符串列表?
建议不要使用 libdbus-1
,因为它是一个非常低级的 D-Bus 库 — 正如您所发现的,它很难使用。
使用更高级别的 D-Bus 库,例如 GDBus or QtDBus。你会让你的生活轻松很多。
参见。
我建议阅读 libdbus 源代码以确保确定,但我的回忆是这样的:
dbus_message_get_args(reply, &err, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING, &args, &len, DBUS_TYPE_INVALID);
请注意,len
不是您可以指定的最大长度:libdbus 将在那里写入数组的实际长度。我不是 100% 确定这里的参数顺序,您可能需要阅读源代码才能确定。
如果您现在在想“但是那会很奇怪 API 文档不好”……您是对的:正如 Philip 提到的那样,在 2020 年使用 libdbus 并不是一个好的选择。
我最近一直在学习 libdbus
,方法是编写一个向活动媒体播放器发送 mpris 消息的简单工具。
第一步是通过 DBus 获取媒体播放器列表:
// send the ListNames command over the DBus
DBusMessage* msg = dbus_message_new_method_call(
"org.freedesktop.DBus",
"/",
"org.freedesktop.DBus",
"ListNames");
// send the message
DBusPendingCall* call;
dbus_bool_t success = dbus_connection_send_with_reply(con, msg, &call, 100);
if (!success || call == NULL) return 1;
// wait for a reply
dbus_pending_call_block(call);
// check reply
DBusMessage* reply = dbus_pending_call_steal_reply(call);
我现在必须解析 DBus 回复以获取媒体播放器名称列表。 阅读参考资料 material 后,我相信这应该可以通过 dbus_message_get_args 实现,如文档所述:
arrays of string, object path, and signature are supported; but these are returned as allocated memory and must be freed with dbus_free_string_array(). [...] To get a string array pass in "char ***array_location" and "int *n_elements".
这让我写下了以下内容:
// pull list of players from reply
const int MAX_ARGS = 10;
const char** args;
dbus_message_get_args(reply, &err, DBUS_TYPE_ARRAY, &args, &MAX_ARGS);
但是在检查我的 DBusError 时,我收到以下消息:
DBus Error: org.freedesktop.DBus.Error.InvalidArgs Argument 0 is specified to be an array of "unknown", but is actually an array of "string"
我本来以为我一定是通过了一个糟糕的 DBUS_TYPE
但找不到比 DBUS_TYPE_ARRAY
更合适的了。
我知道这也可以通过使用 dbus_message_iter
调用来实现,但文档似乎表明这不是必需的,甚至建议尽可能使用 get_message_args
。
所以实际的问题是...我是不是遗漏了一些关于文档的内容,或者函数调用有误?或者实际上无法使用此方法获取字符串列表?
建议不要使用 libdbus-1
,因为它是一个非常低级的 D-Bus 库 — 正如您所发现的,它很难使用。
使用更高级别的 D-Bus 库,例如 GDBus or QtDBus。你会让你的生活轻松很多。
参见
我建议阅读 libdbus 源代码以确保确定,但我的回忆是这样的:
dbus_message_get_args(reply, &err, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING, &args, &len, DBUS_TYPE_INVALID);
请注意,len
不是您可以指定的最大长度:libdbus 将在那里写入数组的实际长度。我不是 100% 确定这里的参数顺序,您可能需要阅读源代码才能确定。
如果您现在在想“但是那会很奇怪 API 文档不好”……您是对的:正如 Philip 提到的那样,在 2020 年使用 libdbus 并不是一个好的选择。