c++ - 如何使用结构参数从 Qt 调用 D-Bus 接口(interface)

标签 c++ qt dbus qtdbus

我正在尝试向 polkit 请求授权,但我似乎无法找到如何提供结构作为参数。

QDBusArgument subject;
subject.beginStructure();
subject << "unix-process";
subject << QMap<QString, QVariant>{
    {"pid", static_cast<uint32_t>(QCoreApplication::applicationPid())},
    {"start-time", static_cast<uint64_t>(0)},
};
subject.endStructure();

QDBusInterface polkit("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority");
auto result = polkit.callWithArgumentList(
    QDBus::CallMode::AutoDetect,
    "CheckAuthorization",
    {
      // how to provide the subject here?
    }
);

QDBusArgument 显示了参数应该是什么样子,我需要以某种方式将其转换为可在 callWithArgumentList 中使用的格式。

FreeDesktop 这样指定结构:

{
  String               subject_kind,
  Dict<String,Variant> subject_details
}

更具体地说,我试图用 dbus 调用替换它:

// checkProcess is *QProcess
checkProcess->start("pkcheck", {
    "--process",
    QString::number(QCoreApplication::applicationPid()),
    "--action-id",
    "my-custom-action-id",
    "--allow-user-interaction"
});

最佳答案

我不太熟悉 D-Bus 或其 Qt 界面,但我碰巧有一个 linux 系统可以测试它。看来你已经在路上了,经过一些小的调整,我能够从 polkit 服务得到响应:

#include <QtDBus>

int main() {
    // Not all Qt types are compatible with the D-Bus interface by default:
    // QMap<QString, QVariant> is, but QMap<QString, QString> is not.
    // If you need such a type, even if only to pass an empty
    // Dict<String, String>, it must first be registered like so:
    qDBusRegisterMetaType<QMap<QString, QString>>();

    // Subject kind should be provided as a QString, integers as Qt types
    QDBusArgument subject;
    subject.beginStructure();
    subject << QString("unix-process");
    subject << QMap<QString, QVariant>{
        {"pid", static_cast<quint32>(QCoreApplication::applicationPid())},
        {"start-time", static_cast<quint64>(0)},
    };
    subject.endStructure();

    // PolicyKit1 is on the system bus
    QDBusInterface polkit(
        "org.freedesktop.PolicyKit1",
        "/org/freedesktop/PolicyKit1/Authority",
        "org.freedesktop.PolicyKit1.Authority",
        QDBusConnection::systemBus()
    );

    // callWithArgumentList only takes actual QVariantLists as the arguments,
    // call is a more convenient variadic function template 
    auto result = polkit.call(
        QDBus::CallMode::AutoDetect,
        "CheckAuthorization",
        QVariant::fromValue(subject),
        "org.freedesktop.login1.set-user-linger",
        QVariant::fromValue(QMap<QString, QString>{}),
        0x1u, // AllowUserInteraction = 0x00000001
        ""
    );
    
    qInfo() << result;
}

这导致了以下输出:

QDBusMessage(type=MethodReturn, service=":1.1", signature="(bba{ss})", contents=([Argument: (bba{ss}) false, true, [Argument: a{ss} {"polkit.retains_authorization_after_challenge" = "1"}]]) )

一些进一步的评论:

  • 在 D-Bus 类型系统中注册的类型必须可以通过 << 和 >> 运算符与 QDBusArgument 相互转换,这就是为什么在使用非 Qt 类型时会遇到问题。你可以implement these operators允许注册其他类型;
  • 传递给 D-Bus 调用的类型必须可以隐式转换为 QVariant。如果不是,您可以使用 QVariant::fromValue() 显式转换它们。

一旦满足这些要求,您应该能够从 D-Bus 获得有意义的输出,即使您传递了错误的参数。例如,省略 CheckAuthorization 的最后一个字符串参数会导致带有消息的 InvalidArgs 错误响应

Type of message, “((sa{sv})sa{ss}u)”, does not match expected type “((sa{sv})sa{ss}us)”

字符串编码了预期的类型

{
    { 
        String, 
        Dict<String, Variant>
    },
    String,
    Dict<String, String>,
    Uint32,
    String
}

关于c++ - 如何使用结构参数从 Qt 调用 D-Bus 接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74749863/

相关文章:

c++ - QDBusAbstractAdaptor 与 QDBusAbstractInterface

c++ - strptime() 的问题 - %p 未被考虑在内

c++ - 将 QImage(icon) 转换为 grayScale 格式,同时保留背景

qt - QMessageBox::critical不显示标题文本

c++ - 如果 QTimer 不停止会发生什么

python - 使用 Python3 通过 python-dbus 在 Linux 上显示屏幕保护程序状态

c++ - libuv 中 sd-bus 的事件循环处理

c++ - 从基类调用派生类函数而不使用虚函数

c++ - 是否仍然使用 register 关键字?

c++ - 调试错误-R6025 纯虚函数调用(No virtual called)