ssn
ssn

Reputation: 2711

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

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

Upvotes: 4

Views: 1048

Answers (2)

ssn
ssn

Reputation: 2711

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.

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 595319

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

Upvotes: 6

Related Questions