【问题标题】:Converting a winrt::UI::Xaml::Controls::TextBlock object to C++/CX object将 winrt::UI::Xaml::Controls::TextBlock 对象转换为 C++/CX 对象
【发布时间】:2020-11-27 04:54:18
【问题描述】:

我正在将我的项目从 C++/CX 移植到 C++/WinRT。为此,我需要做一些这样的互操作:https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-cx

Microsoft 建议使用此类帮助函数以实现互操作性。

from_cx 和 to_cx 函数 下面的帮助函数将 C++/CX 对象转换为等效的 C++/WinRT 对象。该函数将 C++/CX 对象转换为其底层 IUnknown 接口指针。然后,它在该指针上调用 QueryInterface 以查询 C++/WinRT 对象的默认接口。 QueryInterface 是与 C++/CX safe_cast 扩展等效的 Windows 运行时应用程序二进制接口 (ABI)。而且,winrt::put_abi 函数检索 C++/WinRT 对象的底层 IUnknown 接口指针的地址,以便可以将其设置为另一个值。

template <typename T>
T from_cx(Platform::Object^ from)
{
    T to{ nullptr };

    winrt::check_hresult(reinterpret_cast<::IUnknown*>(from)
        ->QueryInterface(winrt::guid_of<T>(),
            reinterpret_cast<void**>(winrt::put_abi(to))));

    return to;
}

下面的帮助函数将 C++/WinRT 对象转换为等效对象 C++/CX 对象。 winrt::get_abi 函数检索指向 C++/WinRT 对象的基础 IUnknown 接口。函数转换 在使用 C++/CX safe_cast 之前指向 C++/CX 对象的指针 查询请求的 C++/CX 类型的扩展。

template <typename T>
T^ to_cx(winrt::Windows::Foundation::IUnknown const& from)
{
    return safe_cast<T^>(reinterpret_cast<Platform::Object^>(winrt::get_abi(from)));
}

但是,当我这样做时:

auto text = winrt::Windows::UI::Xaml::Controls::TextBlock();
Windows::UI::Xaml::FrameworkElement^ cx = to_cx<Windows::UI::Xaml::FrameworkElement^>(text);

我收到一个错误:

没有函数模板“to_cx”的实例与参数列表匹配

参数类型有:(winrt::Windows::UI::Xanl::Controls::TextBlock)

但我确实看到 TextBlock 继承自 IUnknown。我错过了什么?

【问题讨论】:

    标签: windows xaml uwp-xaml c++-cx c++-winrt


    【解决方案1】:

    将 winrt::UI::Xaml::Controls::TextBlock 对象转换为 C++/CX 对象

    如果你想port 一个 C++/WinRT 对象到一个 C++/CX 对象。您可以为解决方案制作 Windows 运行时组件(C++/WinRT) 项目并将转换代码放入其中。然后让 C++/WinRT 项目引用 上面的组件(右键单击解决方案资源管理器中的C++/WinRT项目名称,单击添加,选择引用,在添加引用对话框中的项目下选择刚刚添加的组件名称)。

    注意

    您需要在 Windows 运行时组件(C++/WinRT) 项目中使用Consume Windows Runtime Extension>Yes(/ZM),而不是 C++/WinRT 项目。

    然后,在 Windows 运行时组件(C++/WinRT) 中,添加 cx 命名空间和 winrt 命名空间,以区分使用不同语言的不同对象。

    以下代码可以放入你的组件项目的类中。

    添加所需的标题,例如:

    #include <winrt/Windows.UI.Xaml.Controls.h>
    #include <winrt/Windows.UI.Xaml.h>
    
    In the cx namespace, add  using statements:
    namespace cx
    {
        using namespace Windows::Foundation;
        using namespace Windows::UI::Xaml;
    }
    
    // And, in the winrt namespace, add the needed using statements:
    
    namespace winrt
    {
        using namespace Windows;
        using namespace Windows::ApplicationModel::Core;
        using namespace Windows::Foundation;
        using namespace Windows::Foundation::Numerics;
        using namespace Windows::UI;
        using namespace Windows::UI::Core;
        using namespace Windows::UI::Composition;
        using namespace winrt::Windows::UI::Xaml::Controls;
        using namespace winrt::Windows::UI::Xaml;
    }
    Add the to_cx method:
    template <typename T>
    T^ to_cx(winrt::Windows::Foundation::IUnknown const& from)
    {
        return safe_cast<T^>(reinterpret_cast<Platform::Object^>(winrt::get_abi(from)));
    }
    
    //Change the code:
    
    /*auto text = winrt::Windows::UI::Xaml::Controls::TextBlock();
    Windows::UI::Xaml::FrameworkElement^ cx = to_cx<Windows::UI::Xaml::FrameworkElement^>(text);*/
    
    auto text = winrt::Windows::UI::Xaml::Controls::TextBlock();
            cx::FrameworkElement^ cx = to_cx<cx::FrameworkElement>(text);
    

    请注意:

    请不要将转换代码放入 XAML 页面,因为您的 XAML 页面类型需要完全是 C++/CX 或 完全 C++/WinRT。您可以在同一个项目中混合使用 XAML 页面类型之外的 C++/CX 和 C++/WinRT。

    在组件项目的类中使用转换代码的函数必须先在类的idl文件中声明,否则我们不能在另一个项目中引用该函数。

    更新:

    这里是我创建的一个简单的sample,当点击主项目中的按钮时,我调用了Windows Runtime Component的方法来触发to_cx方法,你可以检查一下。

    【讨论】:

    • 但是我仍然得到这个错误:没有函数模板“to_cx”的实例与参数列表匹配参数类型是:(winrt::Windows::UI::Xanml::Controls::TextBlock)
    • 我们已经上传了代码示例。请检查案例更新部分。
    • 对于 from_cx 我也收到类似这样的错误:“error C2664: 'HRESULT IUnknown::QueryInterface(const IID &,void **)': cannot convert argument 1 from 'const winrt::guid ' 到 'const IID &' 注意:原因:无法从 'const winrt::guid' 转换为 'const IID' 注意:没有可以执行此转换的用户定义的转换运算符,或者无法调用该运算符“任何知道我该如何解决这个问题?
    • winrt::guid 和 IID 之间的转换运算符依赖于在包含 C++/WinRT 之前可用的 IID 定义。实际上,您需要在 #include 任何 C++/WinRT 标头之前 #include
    猜你喜欢
    • 2021-04-05
    • 1970-01-01
    • 2016-04-24
    • 1970-01-01
    • 2011-01-23
    • 2021-03-10
    • 2021-01-28
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多