Created
January 29, 2024 05:41
-
-
Save rixtox/a8b2fdea2f18c4697e2649cd2e1affc5 to your computer and use it in GitHub Desktop.
WinRT HTTP example in (almost) pure C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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