in Source/Task/AsyncLib.cpp [1044:1147]
STDAPI XAsyncGetResult(
_Inout_ XAsyncBlock* asyncBlock,
_In_opt_ const void* identity,
_In_ size_t bufferSize,
_Out_writes_bytes_to_opt_(bufferSize, *bufferUsed) void* buffer,
_Out_opt_ size_t* bufferUsed
) noexcept
{
HRESULT result = E_PENDING;
AsyncStateRef state;
bool resultsAlreadyReturned;
{
AsyncBlockInternalGuard internal{ asyncBlock };
result = internal.GetStatus();
state = internal.GetState();
resultsAlreadyReturned = internal.GetResultsRetrieved();
}
if (SUCCEEDED(result))
{
// If the call was successful and we've already returned
// results, fail now to prevent us interpreting a null
// state object as a zero payload success. Note if the
// call had completed with zero payload it gets cleaned
// up immediately and therefore a call to XAsyncGetResult
// never extracts and sets the results as retrieved. This
// means you can safely call this multiple times for calls
// that had no result payload, which is consistent with
// how XAsyncGetStatus works. We only want to guard against
// the case where results were offered once, but can't be
// offered again now that we've shut the call down.
RETURN_HR_IF(E_ILLEGAL_METHOD_CALL, resultsAlreadyReturned);
if (state == nullptr)
{
if (bufferUsed != nullptr)
{
*bufferUsed = 0;
}
}
else if (identity != state->identity)
{
// Call/Result mismatch. This XAsyncBlock was initiated by state->identityName
char buf[100];
int sprintfResult;
if (state->identityName != nullptr)
{
sprintfResult = snprintf(
buf,
sizeof(buf),
"Call/Result mismatch. This XAsyncBlock was initiated by '%s'.\r\n",
state->identityName);
}
else
{
sprintfResult = snprintf(buf, sizeof(buf), "Call/Result mismatch\r\n");
}
result = E_INVALIDARG;
ASYNC_LIB_TRACE(result, buf);
ASSERT(false);
ASSERT(sprintfResult > 0);
}
else if (state->providerData.bufferSize == 0)
{
// Caller has not supplied a payload
result = E_NOT_SUPPORTED;
}
else if (buffer == nullptr)
{
result = E_INVALIDARG;
}
else if (bufferSize < state->providerData.bufferSize)
{
result = E_NOT_SUFFICIENT_BUFFER;
}
else
{
if (bufferUsed != nullptr)
{
*bufferUsed = state->providerData.bufferSize;
}
state->providerData.bufferSize = bufferSize;
state->providerData.buffer = buffer;
result = state->provider(XAsyncOp::GetResult, &state->providerData);
}
}
// Cleanup state if needed.
if (result != E_PENDING && state != nullptr)
{
{
AsyncBlockInternalGuard internal{ asyncBlock };
internal.ExtractState(true);
}
CleanupState(std::move(state));
}
return result;
}