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 并不是一个好的选择。