Skip to content

Instantly share code, notes, and snippets.

@rixtox
Created January 29, 2024 05:41
Show Gist options
  • Save rixtox/a8b2fdea2f18c4697e2649cd2e1affc5 to your computer and use it in GitHub Desktop.
Save rixtox/a8b2fdea2f18c4697e2649cd2e1affc5 to your computer and use it in GitHub Desktop.
WinRT HTTP example in (almost) pure C
#define INITGUID
#include <guiddef.h>
#include <windows.web.http.h>
extern "C" {
const IID IID_IUnknown = __uuidof(IUnknown);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CIHttpClient = __uuidof(ABI::Windows::Web::Http::IHttpClient);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CIHttpClientFactory = __uuidof(ABI::Windows::Web::Http::IHttpClientFactory);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CIHttpRequestMessageFactory = __uuidof(ABI::Windows::Web::Http::IHttpRequestMessageFactory);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CIHttpMethodFactory = __uuidof(ABI::Windows::Web::Http::IHttpMethodFactory);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CIHttpMethodStatics = __uuidof(ABI::Windows::Web::Http::IHttpMethodStatics);
const IID IID___x_ABI_CWindows_CFoundation_CIUriRuntimeClassFactory = __uuidof(ABI::Windows::Foundation::IUriRuntimeClassFactory);
const IID IID___x_ABI_CWindows_CWeb_CHttp_CFilters_CIHttpBaseProtocolFilter = __uuidof(ABI::Windows::Web::Http::Filters::IHttpBaseProtocolFilter);
//const IID IID___FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress = __uuidof(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<ABI::Windows::Web::Http::HttpResponseMessage*, struct ABI::Windows::Web::Http::HttpProgress>);
DEFINE_GUID(IID___FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress, 0xbeadb572, 0xf9a3, 0x5e93, 0xb6, 0xca, 0xe3, 0x11, 0xb6, 0x59, 0x33, 0xfc);
//const IID IID___FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64 = __uuidof(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<HSTRING, UINT64>);
DEFINE_GUID(IID___FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64, 0xbd75eebe, 0xe7b5, 0x5af6, 0x84, 0x15, 0xa4, 0xb9, 0xc9, 0x04, 0x52, 0x02);
}
#include <stdio.h>
#include <roapi.h>
#include <crtdbg.h>
#include <winstring.h>
#include <windows.web.http.h>
typedef struct ReadContentOperationCompleteHandler ReadContentOperationCompleteHandler;
struct ReadContentOperationCompleteHandler {
__FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64 super;
ULONG count;
HANDLE completeEvent;
};
HRESULT STDMETHODCALLTYPE readContentOperationCompleteQueryInterface(
__FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64* This,
REFIID riid,
void** ppvObject
) {
HRESULT result = S_OK;
if (!IsEqualIID(riid, &IID___FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64) && !IsEqualIID(riid, &IID_IUnknown))
{
*ppvObject = NULL;
result = E_NOINTERFACE;
goto bail;
}
*ppvObject = This;
This->lpVtbl->AddRef(This);
bail:
return result;
}
ULONG STDMETHODCALLTYPE readContentOperationCompleteAddRef(
__FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64* This
) {
ReadContentOperationCompleteHandler* handler = (ReadContentOperationCompleteHandler*)This;
++handler->count;
return handler->count;
}
ULONG STDMETHODCALLTYPE readContentOperationCompleteRelease(
__FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64* This
) {
ReadContentOperationCompleteHandler* handler = (ReadContentOperationCompleteHandler*)This;
--handler->count;
if (handler->count == 0)
{
GlobalFree(handler);
return 0;
}
return handler->count;
}
HRESULT STDMETHODCALLTYPE readContentOperationCompleteInvoke(
__FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64* This,
__FIAsyncOperationWithProgress_2_HSTRING_UINT64* readContentOperation,
AsyncStatus asyncStatus
) {
HRESULT result = S_OK;
ReadContentOperationCompleteHandler* handler = (ReadContentOperationCompleteHandler*)This;
if (asyncStatus != Completed) {
goto bail;
}
HSTRING body = NULL;
result = readContentOperation->lpVtbl->GetResults(readContentOperation, &body);
_ASSERT(result == S_OK);
wprintf(L"%s", WindowsGetStringRawBuffer(body, NULL));
SetEvent(handler->completeEvent);
bail:
return result;
}
CONST_VTBL struct __FIAsyncOperationWithProgressCompletedHandler_2_HSTRING_UINT64Vtbl gReadContentOperationCompleteVtbl = {
.QueryInterface = readContentOperationCompleteQueryInterface,
.AddRef = readContentOperationCompleteAddRef,
.Release = readContentOperationCompleteRelease,
.Invoke = readContentOperationCompleteInvoke,
};
typedef struct SendRequestOperationCompleteHandler SendRequestOperationCompleteHandler;
struct SendRequestOperationCompleteHandler {
__FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress super;
ULONG count;
HANDLE completeEvent;
};
HRESULT STDMETHODCALLTYPE sendRequestOperationCompleteQueryInterface(
__FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* This,
REFIID riid,
void** ppvObject
) {
HRESULT result = S_OK;
if (!IsEqualIID(riid, &IID___FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress) && !IsEqualIID(riid, &IID_IUnknown))
{
*ppvObject = NULL;
result = E_NOINTERFACE;
goto bail;
}
*ppvObject = This;
This->lpVtbl->AddRef(This);
bail:
return result;
}
ULONG STDMETHODCALLTYPE sendRequestOperationCompleteAddRef(
__FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* This
) {
SendRequestOperationCompleteHandler* handler = (SendRequestOperationCompleteHandler*)This;
++handler->count;
return handler->count;
}
ULONG STDMETHODCALLTYPE sendRequestOperationCompleteRelease(
__FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* This
) {
SendRequestOperationCompleteHandler* handler = (SendRequestOperationCompleteHandler*)This;
--handler->count;
if (handler->count == 0)
{
GlobalFree(handler);
return 0;
}
return handler->count;
}
static HRESULT STDMETHODCALLTYPE sendRequestOperationCompleteInvoke(
__FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* This,
__FIAsyncOperationWithProgress_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* sendRequestOperation,
AsyncStatus asyncStatus
) {
HRESULT result = S_OK;
SendRequestOperationCompleteHandler* handler = (SendRequestOperationCompleteHandler*)This;
if (asyncStatus != Completed) {
goto bail;
}
__x_ABI_CWindows_CWeb_CHttp_CIHttpResponseMessage* response = NULL;
result = sendRequestOperation->lpVtbl->GetResults(sendRequestOperation, &response);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpContent* content = NULL;
result = response->lpVtbl->get_Content(response, &content);
_ASSERT(result == S_OK);
__FIAsyncOperationWithProgress_2_HSTRING_UINT64* readContentOperation = NULL;
result = content->lpVtbl->ReadAsStringAsync(content, &readContentOperation);
_ASSERT(result == S_OK);
ReadContentOperationCompleteHandler* completeHandler = GlobalAlloc(GMEM_FIXED, sizeof(*completeHandler));
_ASSERT(completeHandler != NULL);
completeHandler->super.lpVtbl = &gReadContentOperationCompleteVtbl;
completeHandler->completeEvent = handler->completeEvent;
result = readContentOperation->lpVtbl->put_Completed(readContentOperation, &completeHandler->super);
_ASSERT(result == S_OK);
bail:
return result;
}
CONST_VTBL struct __FIAsyncOperationWithProgressCompletedHandler_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgressVtbl gSendRequestOperationCompleteVtbl = {
.QueryInterface = sendRequestOperationCompleteQueryInterface,
.AddRef = sendRequestOperationCompleteAddRef,
.Release = sendRequestOperationCompleteRelease,
.Invoke = sendRequestOperationCompleteInvoke,
};
int main()
{
HRESULT result;
result = RoInitialize(RO_INIT_MULTITHREADED);
HSTRING_HEADER CLSNameHttpClient_header;
HSTRING CLSNameHttpClient;
result = WindowsCreateStringReference(
InterfaceName_Windows_Web_Http_IHttpContent,
(UINT32)wcslen(InterfaceName_Windows_Web_Http_IHttpContent),
&CLSNameHttpClient_header,
&CLSNameHttpClient
);
_ASSERT(result == S_OK);
HSTRING_HEADER RuntimeClass_Windows_Web_Http_HttpClient_header;
HSTRING RuntimeClass_Windows_Web_Http_HttpClient_hstring;
result = WindowsCreateStringReference(
RuntimeClass_Windows_Web_Http_HttpClient,
(UINT32)wcslen(RuntimeClass_Windows_Web_Http_HttpClient),
&RuntimeClass_Windows_Web_Http_HttpClient_header,
&RuntimeClass_Windows_Web_Http_HttpClient_hstring
);
_ASSERT(result == S_OK);
HSTRING_HEADER RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_header;
HSTRING RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_hstring;
result = WindowsCreateStringReference(
RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter,
(UINT32)wcslen(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter),
&RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_header,
&RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_hstring
);
_ASSERT(result == S_OK);
HSTRING_HEADER RuntimeClass_Windows_Web_Http_HttpMethod_header;
HSTRING RuntimeClass_Windows_Web_Http_HttpMethod_hstring;
result = WindowsCreateStringReference(
RuntimeClass_Windows_Web_Http_HttpMethod,
(UINT32)wcslen(RuntimeClass_Windows_Web_Http_HttpMethod),
&RuntimeClass_Windows_Web_Http_HttpMethod_header,
&RuntimeClass_Windows_Web_Http_HttpMethod_hstring
);
_ASSERT(result == S_OK);
HSTRING_HEADER InterfaceName_Windows_Web_Http_IHttpMethodStatics_header;
HSTRING InterfaceName_Windows_Web_Http_IHttpMethodStatics_hstring;
result = WindowsCreateStringReference(
InterfaceName_Windows_Web_Http_IHttpMethodStatics,
(UINT32)wcslen(InterfaceName_Windows_Web_Http_IHttpMethodStatics),
&InterfaceName_Windows_Web_Http_IHttpMethodStatics_header,
&InterfaceName_Windows_Web_Http_IHttpMethodStatics_hstring
);
_ASSERT(result == S_OK);
HSTRING_HEADER RuntimeClass_Windows_Foundation_Uri_header;
HSTRING RuntimeClass_Windows_Foundation_Uri_hstring;
result = WindowsCreateStringReference(
RuntimeClass_Windows_Foundation_Uri,
(UINT32)wcslen(RuntimeClass_Windows_Foundation_Uri),
&RuntimeClass_Windows_Foundation_Uri_header,
&RuntimeClass_Windows_Foundation_Uri_hstring
);
_ASSERT(result == S_OK);
WCHAR example_uri_wchar[] = L"https://example.com";
HSTRING_HEADER example_uri_header;
HSTRING example_uri_hstring;
result = WindowsCreateStringReference(
example_uri_wchar,
(UINT32)wcslen(example_uri_wchar),
&example_uri_header,
&example_uri_hstring
);
_ASSERT(result == S_OK);
HSTRING_HEADER RuntimeClass_Windows_Web_Http_HttpRequestMessage_header;
HSTRING RuntimeClass_Windows_Web_Http_HttpRequestMessage_hstring;
result = WindowsCreateStringReference(
RuntimeClass_Windows_Web_Http_HttpRequestMessage,
(UINT32)wcslen(RuntimeClass_Windows_Web_Http_HttpRequestMessage),
&RuntimeClass_Windows_Web_Http_HttpRequestMessage_header,
&RuntimeClass_Windows_Web_Http_HttpRequestMessage_hstring
);
_ASSERT(result == S_OK);
_ASSERT(CLSNameHttpClient && "should not be null!");
_ASSERT(RuntimeClass_Windows_Web_Http_HttpClient_hstring && "should not be null!");
_ASSERT(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_hstring && "should not be null!");
_ASSERT(RuntimeClass_Windows_Web_Http_HttpMethod_hstring && "should not be null!");
_ASSERT(InterfaceName_Windows_Web_Http_IHttpMethodStatics_hstring && "should not be null!");
_ASSERT(RuntimeClass_Windows_Foundation_Uri_hstring && "should not be null!");
_ASSERT(example_uri_hstring && "should not be null!");
_ASSERT(RuntimeClass_Windows_Web_Http_HttpRequestMessage_hstring && "should not be null!");
__x_ABI_CWindows_CWeb_CHttp_CIHttpClientFactory* httpClientFactory = NULL;
result = RoGetActivationFactory(RuntimeClass_Windows_Web_Http_HttpClient_hstring, &IID___x_ABI_CWindows_CWeb_CHttp_CIHttpClientFactory, (LPVOID*)&httpClientFactory);
_ASSERT(result == S_OK);
IInspectable* httpBaseProtocolFilterAsInspectable = NULL;
result = RoActivateInstance(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter_hstring, &httpBaseProtocolFilterAsInspectable);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CFilters_CIHttpFilter* httpFilter = NULL;
result = httpBaseProtocolFilterAsInspectable->lpVtbl->QueryInterface(httpBaseProtocolFilterAsInspectable, &IID___x_ABI_CWindows_CWeb_CHttp_CFilters_CIHttpBaseProtocolFilter, &httpFilter);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpClient* httpClient = NULL;
result = httpClientFactory->lpVtbl->Create(httpClientFactory, httpFilter, &httpClient);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpRequestMessageFactory* httpRequestMessageFactory = NULL;
result = RoGetActivationFactory(RuntimeClass_Windows_Web_Http_HttpRequestMessage_hstring, &IID___x_ABI_CWindows_CWeb_CHttp_CIHttpRequestMessageFactory, (LPVOID*)&httpRequestMessageFactory);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpMethodFactory* httpMethodFactory = NULL;
result = RoGetActivationFactory(RuntimeClass_Windows_Web_Http_HttpMethod_hstring, &IID___x_ABI_CWindows_CWeb_CHttp_CIHttpMethodFactory, (LPVOID*)&httpMethodFactory);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpMethodStatics* httpMethodStatics = NULL;
result = httpMethodFactory->lpVtbl->QueryInterface(httpMethodFactory, &IID___x_ABI_CWindows_CWeb_CHttp_CIHttpMethodStatics, &httpMethodStatics);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpMethod* httpGetMethod = NULL;
result = httpMethodStatics->lpVtbl->get_Get(httpMethodStatics, &httpGetMethod);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CFoundation_CIUriRuntimeClassFactory* uriFactory = NULL;
result = RoGetActivationFactory(RuntimeClass_Windows_Foundation_Uri_hstring, &IID___x_ABI_CWindows_CFoundation_CIUriRuntimeClassFactory, (LPVOID*)&uriFactory);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CFoundation_CIUriRuntimeClass* uri = NULL;
result = uriFactory->lpVtbl->CreateUri(uriFactory, example_uri_hstring, &uri);
_ASSERT(result == S_OK);
__x_ABI_CWindows_CWeb_CHttp_CIHttpRequestMessage* httpRequestMessage = NULL;
result = httpRequestMessageFactory->lpVtbl->Create(httpRequestMessageFactory, httpGetMethod, uri, &httpRequestMessage);
_ASSERT(result == S_OK);
__FIAsyncOperationWithProgress_2_Windows__CWeb__CHttp__CHttpResponseMessage_Windows__CWeb__CHttp__CHttpProgress* sendRequestOperation = NULL;
result = httpClient->lpVtbl->SendRequestAsync(httpClient, httpRequestMessage, &sendRequestOperation);
_ASSERT(result == S_OK);
HANDLE completeEvent = CreateEventW(
NULL,
TRUE,
FALSE,
L"CompleteEvent"
);
_ASSERT(completeEvent != NULL);
SendRequestOperationCompleteHandler* completeHandler = GlobalAlloc(GMEM_FIXED, sizeof(*completeHandler));
_ASSERT(completeHandler != NULL);
completeHandler->super.lpVtbl = &gSendRequestOperationCompleteVtbl;
completeHandler->completeEvent = completeEvent;
result = sendRequestOperation->lpVtbl->put_Completed(sendRequestOperation, &completeHandler->super);
_ASSERT(result == S_OK);
DWORD dwWaitResult = WaitForSingleObject(
completeEvent,
INFINITE);
_ASSERT(dwWaitResult == WAIT_OBJECT_0);
CloseHandle(completeEvent);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment