4

This error happens to me when I use the helper function from microsoft docs to migrate to winrt from cx. I see a similar question here, but the solution mentioned doesn't seem to work for me. The solution mentioned here add #include <Unknwn.h> before any other winrt headers in the file which has this error.

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

This is the entire file:

#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)));
    }
}
}
ssn
  • 2,631
  • 4
  • 24
  • 28
  • If you `#include `, 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. – IInspectable Aug 12 '20 at 19:30
  • Hi I made an edit above adding the entire contents of the file. I do have the include before any other header. – ssn Aug 13 '20 at 13:14
  • 1
    You have posted a header file. Header files aren't compilation units. 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. – IInspectable Aug 13 '20 at 13:48

2 Answers2

6

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.

Per 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.

So, either make sure unknwn.h is included before WinRT headers, or else you can reinterpret_cast explicitly, eg:

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;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

IInspectable's comment also worked for me:

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.

I thought the header had to be included in the file defining those helper functions.

ssn
  • 2,631
  • 4
  • 24
  • 28