AsyncAdd3ImplicitExample
Cet exemple illustre l’implémentation d’une fonction asynchrone complexe à l’aide de WsAsyncExecute.
L’exemple implémente une fonction asynchrone « AddThree » qui ajoute trois entiers ensemble en s’appuyant sur une fonction Add existante qui peut ajouter deux entiers de manière asynchrone.
AsyncAdd3Implicit.cpp
//------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
//------------------------------------------------------------
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <WebServices.h>
#pragma comment(lib, "WebServices.lib")
// Worker function that adds two numbers
HRESULT DoAdd(int a, int b, int* result, WS_ERROR* error)
{
HRESULT hr;
static const WS_STRING errorString = WS_STRING_VALUE(L"Negative numbers are not supported.");
// To illustrate error handling, we won't support negative numbers
if (a < 0 || b < 0)
{
// Add error information to error object
if (error != NULL)
{
WsAddErrorString(error, &errorString);
}
hr = E_NOTIMPL;
}
else
{
*result = a + b;
hr = NOERROR;
}
return hr;
}
// A struct to maintain the in/out parameters to the Add function
struct AddParameters
{
int a;
int b;
int* sumPointer;
WS_ERROR* error;
WS_ASYNC_CONTEXT asyncContext;
};
// A thread function that adds two numbers
DWORD WINAPI AdderThread(void* threadParameter)
{
// Get the parameters for Add which were passed in CreateThread
AddParameters* addParameters = (AddParameters*)threadParameter;
// Do the addition
HRESULT hr = DoAdd(
addParameters->a,
addParameters->b,
addParameters->sumPointer,
addParameters->error);
// Make a copy of the async context
WS_ASYNC_CONTEXT asyncContext = addParameters->asyncContext;
// Free the parameters
HeapFree(GetProcessHeap(), 0, addParameters);
// Notify the caller that the async operation is complete
// Since we have a dedicated thread for the callback, we can invoke long
(asyncContext.callback)(hr, WS_LONG_CALLBACK, asyncContext.callbackState);
return 1;
}
// An example of a function that can be called asynchronously
HRESULT Add(int a, int b, int* sumPointer, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
if (asyncContext == NULL)
{
// Invoked synchronously, so do the addition on calling thread
return DoAdd(a, b, sumPointer, error);
}
else
{
// Invoked asynchronously
// Decide whether to complete synchronously or asynchronously
if (b == 0)
{
// Complete synchronously. We have this case just as an illustration
// that synchronous completion is possible when invoked asynchronously.
return DoAdd(a, b, sumPointer, error);
}
else
{
// Complete asynchronously
// Alloc space for in/out parameters
AddParameters* addParameters;
addParameters = (AddParameters*)HeapAlloc(GetProcessHeap(), 0, sizeof(AddParameters));
if (addParameters == NULL)
{
return E_OUTOFMEMORY;
}
// Make a copy of in/out parameters
addParameters->a = a;
addParameters->b = b;
addParameters->sumPointer = sumPointer;
addParameters->error = error;
addParameters->asyncContext = *asyncContext;
// Create a thread which will do the work, passing parameters
HANDLE threadHandle = CreateThread(NULL, 0, AdderThread, addParameters, 0, NULL);
if (threadHandle == NULL)
{
// Free the parameters
HeapFree(GetProcessHeap(), 0, addParameters);
return HRESULT_FROM_WIN32(GetLastError());
}
// Close returned thread handle
CloseHandle(threadHandle);
// Indicate asynchronous completion
return WS_S_ASYNC;
}
}
}
// Caller allocated state for use by AddThree. In c++, this might be a class and
// the caller would be unaware of the internal details.
struct ADD_STATE
{
WS_ASYNC_STATE asyncState;
int a;
int b;
int c;
int sum;
int* result;
};
HRESULT CALLBACK Add1(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error);
HRESULT CALLBACK Add2(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error);
HRESULT CALLBACK Add3(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error);
HRESULT CALLBACK Add1(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
UNREFERENCED_PARAMETER(callbackModel);
ADD_STATE* addState = (ADD_STATE*)state;
if (FAILED(hr))
{
return hr;
}
// Set up the next function execute after Add completes
next->function = Add2;
return Add(addState->a, addState->b, &addState->sum, asyncContext, error);
}
HRESULT CALLBACK Add2(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
UNREFERENCED_PARAMETER(callbackModel);
ADD_STATE* addState = (ADD_STATE*)state;
if (FAILED(hr))
{
return hr;
}
// Set up the next function execute after Add completes
next->function = Add3;
return Add(addState->sum, addState->c, &addState->sum, asyncContext, error);
}
HRESULT CALLBACK Add3(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state, WS_ASYNC_OPERATION* next, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
UNREFERENCED_PARAMETER(callbackModel);
UNREFERENCED_PARAMETER(next);
UNREFERENCED_PARAMETER(asyncContext);
UNREFERENCED_PARAMETER(error);
ADD_STATE* addState = (ADD_STATE*)state;
if (FAILED(hr))
{
return hr;
}
// The operation succeeded, set the out parameter
*addState->result = addState->sum;
// No more functions to execute, so don't set next->function, and WsAsyncExecute will terminate.
return NOERROR;
}
HRESULT CALLBACK AddThree(ADD_STATE* addState, int a, int b, int c, int* result, const WS_ASYNC_CONTEXT* asyncContext, WS_ERROR* error)
{
// Set up the state for the operation
addState->a = a;
addState->b = b;
addState->c = c;
addState->sum = 0;
addState->result = result;
// Start the operation at Add1
return WsAsyncExecute(&addState->asyncState, Add1, WS_SHORT_CALLBACK, addState, asyncContext, error);
}
void CALLBACK AddThreeComplete(HRESULT hr, WS_CALLBACK_MODEL callbackModel, void* state)
{
UNREFERENCED_PARAMETER(hr);
UNREFERENCED_PARAMETER(callbackModel);
HANDLE handle = (HANDLE)state;
SetEvent(handle);
}
// Main entry point
int __cdecl wmain(int argc, __in_ecount(argc) wchar_t **argv)
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
HRESULT hr = NOERROR;
// Some numbers to add asynchronously
// Add has the behavior that if the second parameter is 0, it will perform synchronously
int ints[] =
{
1, 0, 0, // First add sync, second add sync
2, 1, 0, // First add async, second add sync
3, 0, 2, // First add sync, second add async
4, 3, 2, // First add async, second add async
};
// Set up the event that will get signaled each time AddThree is complete
HANDLE handle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (handle == NULL)
{
goto Exit;
}
// Set up the callback to use when performing the addition asynchronously
WS_ASYNC_CONTEXT addThreeComplete;
addThreeComplete.callback = AddThreeComplete;
addThreeComplete.callbackState = handle;
// Declare private data for AddThree
ADD_STATE addState;
// Perform the additions synchronously and asynchronously
for (ULONG loop = 0; loop < 2; loop++)
{
// Add sets of integers that will cause different execution behavior when added asynchronously
for (ULONG i = 0; i < sizeof(ints) / sizeof(int); i += 3)
{
wprintf(L"Adding %d,%d,%d %s...\n", ints[i], ints[i + 1], ints[i + 2], (loop == 0 ? L"synchronously" : L"asynchronously"));
// Set up how the function will be called
WS_ASYNC_CONTEXT* asyncContext;
if (loop == 0)
{
// Perform the addition synchronously
asyncContext = NULL;
}
else
{
// Perform the addition asynchronously
asyncContext = &addThreeComplete;
}
// Perform the addition
int sum;
hr = AddThree(&addState, ints[i], ints[i + 1], ints[i + 2], &sum, asyncContext, NULL);
if (hr == WS_S_ASYNC)
{
// If the operation is being performed asynchronously, then wait for it to complete
WaitForSingleObject(handle, INFINITE);
}
if (SUCCEEDED(hr))
{
wprintf(L"Result: %d\n", sum);
}
else
{
wprintf(L"AddThree failed.\n");
}
}
}
Exit:
if (handle != NULL)
{
CloseHandle(handle);
}
fflush(stdout);
return SUCCEEDED(hr) ? 0 : -1;
}