错误 C2664 'HRESULT IUnknown::QueryInterface(const IID &,void **)': 无法将参数 1 从 'const winrt::guid' 转换为 'const IID &'

Error C2664 'HRESULT IUnknown::QueryInterface(const IID &,void **)': cannot convert argument 1 from 'const winrt::guid' to 'const IID &'

当我使用 microsoft docs to migrate to winrt from cx. I see a similar question here 的辅助函数时,我遇到了这个错误,但提到的解决方案似乎对我不起作用。此处提到的解决方案在出现此错误的文件中的任何其他 winrt headers 之前添加 #include

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;
}

这是整个文件:

#pragma once

#include <Unknwn.h>
#include <winrt/Windows.Foundation.h>

namespace x {
namespace y {

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;
}

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

winrt::guid_of() returns a winrt::guid. Per What's new in C++/WinRT:

  • Breaking change. GUID is now projected as winrt::guid. For APIs that you implement, you must use winrt::guid for GUID parameters. Otherwise, winrt::guid converts to GUID, as long as you include unknwn.h before you include any C++/WinRT headers. See Interoperating with the ABI's GUID struct.

根据 Interoperating with the ABI's GUID struct:

GUID is projected as winrt::guid. For APIs that you implement, you must use winrt::guid for GUID parameters. Otherwise, there are automatic conversions between winrt::guid and GUID as long as you include unknwn.h (implicitly included by <windows.h> and many other header files) before you include any C++/WinRT headers.

If you don't do that, then you can hard-reinterpret_cast between them.

因此,要么确保 unknwn.h 包含在 WinRT headers 之前,要么您可以明确 reinterpret_cast,例如:

template <typename T>
T from_cx(Platform::Object ^ from) {
    T to{nullptr};
    winrt::guid iid = winrt::guid_of<T>();

    winrt::check_hresult(
        reinterpret_cast<::IUnknown*>(from)->QueryInterface(
            reinterpret_cast<GUID&>(iid),
            reinterpret_cast<void**>(winrt::put_abi(to)))
    );

    return to;
}

IInspectable 的评论对我也有用:

If you #include <Unknwn.h>, make sure you really include it prior to any winrt headers. When using precompiled headers, that's where you have to include Unknwn.h as well.

.....It's vital that your compilation units have the Unknwn.h included before any other winrt header files. Compilation units commonly have a file extension of .cpp, .cc, or .cxx.

我认为 header 必须包含在定义这些辅助函数的文件中。