【问题标题】:How to consume WinRT IAsyncOperation* object in "native c++" environment如何在“native c++”环境中使用 WinRT IAsyncOperation* 对象
【发布时间】:2018-08-30 18:46:31
【问题描述】:

我有应该移植到 Windows 8 Metro (WinRT) 的 C/C++ SDK 库。 库大部分与操作系统无关,但它包含一些使用操作系统提供的 API 与硬件交互的模块。

在将其移植到 WinRT 时,我决定尽可能使用 WRL 而不是 C++/CX。所以现在我可以创建和使用大部分必需的 WinRT 对象。 但是在使用由 WinRT 提供的异步对象时,我遇到了绝对的障碍。

例如,我使用以下代码枚举硬件设备:

// create interface to "static" members of DeviceInformation class
ComPtr<IDeviceInformationStatics>   DeviceInformationStatics;
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &DeviceInformationStatics);

ComPtr<IAsyncOperation<DeviceInformationCollection*>> operation;
hr = DeviceInformationStatics->FindAllAsyncDeviceClass( DeviceClass_All, &operation);

此时我有有效的 IAsyncOperation 指针。我认为它可以这样使用:

task<ComPtr<DeviceInformationCollection*>> tsk(operation);

但我失败了,因为接受 IAsyncOperation 的 task 构造函数在 ppltasks.h 中的“#if defined(__cplusplus_winrt)”下声明,而这又取决于 /ZW 编译器选项。

在这种情况下我应该如何使用 IAsyncOperation 对象?其实我只需要等待操作完成即可。

【问题讨论】:

    标签: c++ asynchronous windows-runtime


    【解决方案1】:

    以防万一其他人在 C++/WinRT 中寻找它:

        auto asyncOp = someFunctionReturningIAsyncOperation();
    
        asyncOp.Completed([](auto &&result, auto && status) {
            // do whatever with result and status
        });
    

    【讨论】:

    • 最好使用co_await而不是显式设置完成委托。
    • @ChrisGuzak 假设它甚至可用。我正在使用 Clang 构建 C++/WinRT 代码,并使用 co_await 让编译器发出一个非常诡异的“指令不支配所有使用![...] 致命错误:后端错误:发现损坏的函数,编译中止!” .它甚至在构建 32 位时都不起作用,因为 IAsyncOperation 的 coroutine_traits 假定 lambda 可以转换为具有特定调用约定的函数指针,而 Clang 不能。
    【解决方案2】:

    根据我的 C++/CX 经验,您可以构造一个 AsyncOperationCompletedHandler&lt;DeviceInformationCollection*&gt; 对象,使用类中的成员函数对其进行初始化,并将其分配给 IAsyncOperation 的 Completed 属性。

    在 C++/CX 中,您只需使用两个参数构造 AsyncOperationCompletedHandler&lt;&gt; 对象 - 来自调用类的 this 和指向回调方法的成员指针。像这样:

    MyAsyncOp->Completed = ref new AsyncOperationCompletedHandler<ResultType ^>(this, &MyClass::OnDone);
    

    OnDone 的定义如下:

    void MyClass::OnDone(IAsyncOperation<ResultType ^> ^AsOp, AsyncStatus s)
    {
         ResultType ^Result = AsOp->GetResults();
    }
    

    我不确定如何在 WRL 中调用构造函数。你想办法解决这个问题。

    此外,完成处理程序将在随机线程上调用。如果您需要将某些内容传回 UI 线程,Dispatcher-&gt;RunAsync() 是您的朋友。大多数 XAML 类中都有一个 Dispatcher 成员。

    编辑:现在我正在查看示例,似乎有一个名为 Callback 的非托管帮助器类,您围绕 this 和指向成员的指针构建它。查一下。仍然不确定如何将一个连接到 IAsyncOperation...

    【讨论】:

    • 谢谢,会试试的。当我设置“已完成”处理程序操作完成后,我不确定竞争条件。
    • 我不会担心比赛条件。由于无法从一开始就获得带有完成处理程序预设的 IAsyncOperation,因此他们必须在设置处理程序之前操作完成时处理这种情况。天真的实现中潜在的竞争条件太明显了。
    【解决方案3】:

    这是一个老问题......但如果有人像我一样需要答案:

    MSDN documentation 展示了如何在本机 C++ 中完成此操作。这很简单。您初始化 WRL 运行时,即您感兴趣的对象,然后创建将在事件触发时调用的事件和回调处理程序。

    【讨论】:

      【解决方案4】:

      如果 library 硬件特定模块已经在 Win32 上运行,我建议你保持这种状态。安装一个 Win32 服务与硬件交互,然后 Metro 应用只需要与服务进行通信(许多 IPC 选项,例如套接字、管道,我相信即使在受限的 Metro 沙箱中你也能找到一个也能正常工作的)。

      【讨论】:

      • SDK 是跨平台的,应该可以在装有 Windows 8 的基于 ARM 的设备上工作。不确定在这种情况下是否可以使用 win32。
      • @Zakhar:抱歉,我的意思是特定于硬件的模块。
      【解决方案5】:

      IAsyncOperation 是一种可等待类型,因此您应该使用 await 的等价物,或者将其称为 Result 属性。

      【讨论】:

      • await 是 C++/CX 关键字。 OP 要求提供本机 C++ 解决方案。
      • C++ 有co_await,C++ WinRT 支持这一点,让消费更轻松。
      猜你喜欢
      • 2017-01-22
      • 1970-01-01
      • 2011-12-09
      • 2019-09-21
      • 2015-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多