Does anyone know what is the proper way to create a WinRT object in C?
I'm trying to convert my C++ code that uses WinRT API to plain C code.
And right now I'm able to get a few WinRT static functions working.
However, for the objects required by the static function, like the __FIAsyncOperation_1_Windows_CDevicesCEnumerationCDeviceInformation
for the get_Completed
function in FIAsyncOperation_1_WindowsCDevicesCHumanInterfaceDevice_CHidDeviceVtbl
, I can't find a proper way to create the object.
First, I can't find the iid of this object in the idl file.
Second, I'm not sure about the namespace of the object.
I did find how this class being declare in C++ macro,
#ifndef DEF___FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation_USE
#define DEF___FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation_USE
#if !defined(RO_NO_TEMPLATE_NAME)
namespace ABI { namespace Windows { namespace Foundation {
template <>
struct __declspec(uuid("07faa053-eb2f-5cba-b25b-d9d57be6715f"))
IAsyncOperation<ABI::Windows::Devices::Enumeration::DeviceInformation*> : IAsyncOperation_impl<ABI::Windows::Foundation::Internal::AggregateType<ABI::Windows::Devices::Enumeration::DeviceInformation*, ABI::Windows::Devices::Enumeration::IDeviceInformation*>>
{
static const wchar_t* z_get_rc_name_impl()
{
return L"Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformation>";
}
};
// Define a typedef for the parameterized interface specialization's mangled name.
// This allows code which uses the mangled name for the parameterized interface to access the
// correct parameterized interface specialization.
typedef IAsyncOperation<ABI::Windows::Devices::Enumeration::DeviceInformation*> __FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation_t;
#define __FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation ABI::Windows::Foundation::__FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation_t
/* Foundation */ } /* Windows */ } /* ABI */ }
#endif // !defined(RO_NO_TEMPLATE_NAME)
#endif /* DEF___FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation_USE */
So, I tried to use this uuid and name_impl here to create the object, like this
namespace = L"Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformation>";
hr = WindowsCreateStringReferenceFunc(namespace, (UINT32)wcslen(namespace), &namespace_string_header, &namespace_string);
static const IID async_iid = { 0x07faa053, 0xeb2f, 0x5cba, { 0xb2, 0x5b, 0xd9, 0xd5, 0x7b, 0xe6, 0x71, 0x5f } };
if (SUCCEEDED(hr)) {
__FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation* test;
hr = RoGetActivationFactoryFunc(namespace_string, &async_iid, &test);
if (!SUCCEEDED(hr)) {
printf("Couldn't find Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformation>: %d\n", hr);
}
}
And after the build, the program return
Couldn't find Windows.Foundation.IAsyncOperation`1<Windows.Devices.Enumeration.DeviceInformation>: -2147221164
As I don't have the error code mapping, I don't know which part goes wrong. So can anyone tell me the correct way to create an object of WinRT in c?
I had asked this question in the Microsoft forum and they replied their Q&A currently not support this type of question. And I had also read this question before, but the answer cannot solve my problem.
Update1: This is the code that I want to convert from C++ to C
hstring selector = winrt::to_hstring("System.Devices.InterfaceClassGuid:=\"{4D1E55B2-F16F-11CF-88CB-001111000030}\"") +
winrt::to_hstring(" System.DeviceInterface.Hid.VendorId: = ") + winrt::to_hstring(0x0d28) +
winrt::to_hstring(" AND System.DeviceInterface.Hid.ProductId : = ") + winrt::to_hstring(0x0204);
Windows::Foundation::Collections::IVector<hstring> prop{ winrt::single_threaded_vector<hstring>() };
prop.Append(to_hstring("System.ItemNameDisplay"));
prop.Append(to_hstring("System.Devices.DeviceInstanceId"));
prop.Append(to_hstring("System.Devices.Parent"));
prop.Append(to_hstring("System.Devices.LocationPaths"));
prop.Append(to_hstring("System.Devices.Children"));
prop.Append(to_hstring("System.Devices.DeviceManufacturer"));
DeviceInformationCollection collection = DeviceInformation::FindAllAsync(selector, prop).get();
As there is no get function in C, I would need to create an async object to handle the async operation in C. I also need to create a IVector object to enumerate the additional properties of the devices.
Okay, so after a few investigations from a GitHub repo and some help from the comment, I found the answer to my question.
There is actually no contrustor function for objects like the __FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformation
What I need to do is to implement the functions listed in the vtbl struct.
For example when I want to have a object of __FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection
, I will need to implement the functions listed in __FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollectionVtbl
, which are
typedef struct __FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollectionVtbl
{
BEGIN_INTERFACE
HRESULT (STDMETHODCALLTYPE* QueryInterface)(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This,
REFIID riid,
void** ppvObject);
ULONG (STDMETHODCALLTYPE* AddRef)(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This);
ULONG (STDMETHODCALLTYPE* Release)(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This);
HRESULT (STDMETHODCALLTYPE* Invoke)(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This,
__FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* asyncInfo,
AsyncStatus asyncStatus);
END_INTERFACE
} __FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollectionVtbl;
So I should have something like this
static HRESULT STDMETHODCALLTYPE async_query_interface(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This,
REFIID riid,
void** ppvObject)
{
if (!ppvObject) {
return E_INVALIDARG;
}
*ppvObject = NULL;
static const IID async_iid = { 0x4a458732, 0x527e, 0x5c73, { 0x9a, 0x68, 0xa7, 0x3d, 0xa3, 0x70, 0xf7, 0x82 } };
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &async_iid)) {
*ppvObject = This;
This->lpVtbl->AddRef(This);
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG STDMETHODCALLTYPE async_add_ref(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This)
{
return 1;
}
static ULONG STDMETHODCALLTYPE async_release(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This)
{
return 1;
}
static HRESULT STDMETHODCALLTYPE async_invoke(__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* This,
__FIAsyncOperation_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection* asyncInfo,
AsyncStatus asyncStatus)
{
//The callback when the async complete or have some problem
}
And the iid here static const IID async_iid = { 0x4a458732, 0x527e, 0x5c73, { 0x9a, 0x68, 0xa7, 0x3d, 0xa3, 0x70, 0xf7, 0x82 } };
can be found in the header file in the winrt folder(windows.devices.enumeration.h),
namespace ABI { namespace Windows { namespace Foundation {
template <>
struct __declspec(uuid("4a458732-527e-5c73-9a68-a73da370f782"))
IAsyncOperationCompletedHandler<ABI::Windows::Devices::Enumeration::DeviceInformationCollection*> : IAsyncOperationCompletedHandler_impl<ABI::Windows::Foundation::Internal::AggregateType<ABI::Windows::Devices::Enumeration::DeviceInformationCollection*, __FIVectorView_1_Windows__CDevices__CEnumeration__CDeviceInformation*>>
{
static const wchar_t* z_get_rc_name_impl()
{
return L"Windows.Foundation.AsyncOperationCompletedHandler`1<Windows.Devices.Enumeration.DeviceInformationCollection>";
}
};
And when all these been prepared, I just need to do this to get the __FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection
object
__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollection async_op;
__FIAsyncOperationCompletedHandler_1_Windows__CDevices__CEnumeration__CDeviceInformationCollectionVtbl async_vtbl = {
.QueryInterface = async_query_interface,
.AddRef = async_add_ref,
.Release = async_release,
.Invoke = async_invoke,
};
async_op.lpVtbl = &async_vtbl;
hr = async_dev_collection->lpVtbl->put_Completed(async_dev_collection, &async_op);
For the example that I found my answer, it uses this method to create a __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController
object, anyone who interested or still don't understand from my answer can have a look.