Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

629 lines
20 KiB

/*==========================================================================
*
* Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
*
* File: Enum.cpp
* Content: Enumeration routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 04/10/00 mjn Created
* 04/17/00 mjn Fixed DNCompleteEnumQuery to clean up properly
* 04/18/00 mjn Return User Buffer in DNProcessEnumQuery
* 04/19/00 mjn Removed DPN_BUFFER_DESC from DPNMSG_ENUM_HOSTS_QUERY and DPNMSG_ENUM_HOSTS_RESPONSE structs
* 05/02/00 mjn Allow application to reject ENUM_QUERY's
* 06/25/00 mjn Fixed payload problem in DNProcessEnumQuery()
* 07/10/00 mjn Removed DNCompleteEnumQuery() and DNCompleteEnumResponse()
* 07/12/00 mjn Ensure connected before replying to ENUMs
* 07/29/00 mjn Verify enum responses sizes
* 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 08/05/00 mjn Ensure cancelled operations don't proceed
* 08/29/00 mjn Cancel EnumHosts if non-DPN_OK returned from response notification
* 09/04/00 mjn Added CApplicationDesc
* 09/14/00 mjn AddRef Protocol refcount when invoking protocol
* 01/22/01 mjn Add SP reference on AsyncOp in DNProcessEnumQuery()
* 01/25/01 mjn Fixed 64-bit alignment problem in received messages
* 03/13/01 mjn Don't copy user response buffer when responding to enums
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
//**********************************************************************
// ------------------------------
// DNProcessEnumQuery - process enum query
//
// Entry: Pointer to this DNet interface object
// Pointer to the associated listen operation
// Pointer to protocol's enum data
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessEnumQuery"
void DNProcessEnumQuery(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pListen,
const PROTOCOL_ENUM_DATA *const pEnumQueryData )
{
HRESULT hResultCode;
DPNMSG_ENUM_HOSTS_QUERY AppData;
CPackedBuffer PackedBuffer;
CRefCountBuffer *pRefCountBuffer;
CAsyncOp *pAsyncOp;
HANDLE hProtocol;
const DN_ENUM_QUERY_PAYLOAD *pEnumQueryPayload;
DN_ENUM_RESPONSE_OP_DATA *pEnumResponseOpData;
DN_ENUM_RESPONSE_PAYLOAD *pEnumResponsePayload;
DWORD dwPayloadOffset;
IDP8ServiceProvider *pIDP8SP;
SPGETCAPSDATA spGetCapsData;
CServiceProvider *pSP;
DWORD dwBufferCount;
BOOL fNeedToReturnBuffer;
DPFX(DPFPREP, 6,"Parameters: pListen [0x%p], pEnumQueryData [0x%p]",pListen,pEnumQueryData);
DNASSERT( pdnObject != NULL );
DNASSERT( pListen != NULL );
DNASSERT( pEnumQueryData != NULL );
pAsyncOp = NULL;
pRefCountBuffer = NULL;
pIDP8SP = NULL;
pSP = NULL;
fNeedToReturnBuffer = FALSE; // Is this needed ?
//
// Ensure we are in a position to reply to this message.
// We must be CONNECTED and not be HOST_MIGRATING
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) || (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFX(DPFPREP, 7, "Not connected or host is migrating (object 0x%p flags = 0x%x), ignoring enum.", pdnObject, pdnObject->dwFlags);
goto Failure;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Check to see if this message is for this game type. Since the application
// GUID cannot be changed while the session is running, there's no need to
// enter a critical section.
//
pEnumQueryPayload = reinterpret_cast<DN_ENUM_QUERY_PAYLOAD*>( pEnumQueryData->ReceivedData.pBufferData );
if ( pEnumQueryPayload == NULL )
{
//
// no enum payload (there needs to be at least one byte!)
//
DPFX(DPFPREP, 4, "No enum payload, object 0x%p ignoring enum.", pdnObject);
goto Failure;
}
dwPayloadOffset = 0;
switch ( pEnumQueryPayload->QueryType )
{
//
// an application guid was specified, make sure it matches this application's
// guid before further processing
//
case DN_ENUM_QUERY_WITH_APPLICATION_GUID:
{
if ( pEnumQueryData->ReceivedData.dwBufferSize < sizeof( DN_ENUM_QUERY_PAYLOAD ) )
{
DNASSERTX( ! "Received data too small to be valid enum query with application guid!", 2 );
goto Failure;
}
if ( !pdnObject->ApplicationDesc.IsEqualApplicationGuid( &pEnumQueryPayload->guidApplication ) )
{
#ifdef DBG
GUID guidApplication;
//
// GUID might not be aligned, so copy it to a temp variable
//
guidApplication = pEnumQueryPayload->guidApplication;
DPFX(DPFPREP, 7, "Application GUID {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X} doesn't match, object 0x%p, ignoring enum.",
guidApplication.Data1,
guidApplication.Data2,
guidApplication.Data3,
guidApplication.Data4[0],
guidApplication.Data4[1],
guidApplication.Data4[2],
guidApplication.Data4[3],
guidApplication.Data4[4],
guidApplication.Data4[5],
guidApplication.Data4[6],
guidApplication.Data4[7],
pdnObject);
#endif // DBG
goto Failure;
}
dwPayloadOffset = sizeof( DN_ENUM_QUERY_PAYLOAD );
break;
}
//
// no application guid was specified, continue processing
//
case DN_ENUM_QUERY_WITHOUT_APPLICATION_GUID:
{
if ( pEnumQueryData->ReceivedData.dwBufferSize < ( sizeof( DN_ENUM_QUERY_PAYLOAD ) - sizeof( GUID ) ) )
{
DNASSERTX( ! "Received data too small to be valid enum query without application guid!", 2 );
goto Failure;
}
dwPayloadOffset = sizeof( DN_ENUM_QUERY_PAYLOAD ) - sizeof( GUID );
break;
}
default:
{
DNASSERTX( ! "Unrecognized enum query payload type!", 2 );
goto Failure;
break;
}
}
//
// buld message structure, be nice and clear the user payload pointer if
// there is no payload
//
AppData.dwSize = sizeof( AppData );
AppData.pAddressSender = pEnumQueryData->pSenderAddress;
AppData.pAddressDevice = pEnumQueryData->pDeviceAddress;
DPFX(DPFPREP, 7,"AppData.pAddressSender: [0x%p]",AppData.pAddressSender);
DPFX(DPFPREP, 7,"AppData.pAddressDevice: [0x%p]",AppData.pAddressDevice);
if (pEnumQueryData->ReceivedData.dwBufferSize > dwPayloadOffset)
{
DNASSERT( pEnumQueryData->ReceivedData.pBufferData );
DNASSERT( pEnumQueryData->ReceivedData.dwBufferSize );
AppData.pvReceivedData = static_cast<void*>(static_cast<BYTE*>(pEnumQueryData->ReceivedData.pBufferData) + dwPayloadOffset);
AppData.dwReceivedDataSize = pEnumQueryData->ReceivedData.dwBufferSize - dwPayloadOffset;
}
else
{
AppData.pvReceivedData = NULL;
AppData.dwReceivedDataSize = 0;
}
//
// Response Info
//
AppData.pvResponseData = NULL;
AppData.dwResponseDataSize = 0;
AppData.pvResponseContext = NULL;
//
// Determine max size of response
// - Get SP interface from listen SP (listen's parent)
// - Get SP caps on the interface to determine the total available buffer size
// - Figure out what the DNET enum response size will be
// - Determine space available to user
//
DNASSERT(pListen->GetParent() != NULL);
DNASSERT(pListen->GetParent()->GetSP() != NULL);
pListen->GetParent()->GetSP()->AddRef();
pSP = pListen->GetParent()->GetSP();
if ((hResultCode = pSP->GetInterfaceRef( &pIDP8SP )) != DPN_OK)
{
DPFERR("Could not get ListenSP SP interface");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
memset( &spGetCapsData, 0x00, sizeof( SPGETCAPSDATA ) );
spGetCapsData.dwSize = sizeof( SPGETCAPSDATA );
spGetCapsData.hEndpoint = INVALID_HANDLE_VALUE;
if ((hResultCode = IDP8ServiceProvider_GetCaps( pIDP8SP, &spGetCapsData )) != DPN_OK)
{
DPFERR("Could not get SP caps");
DisplayDNError(0,hResultCode);
goto Failure;
}
IDP8ServiceProvider_Release( pIDP8SP );
pIDP8SP = NULL;
PackedBuffer.Initialize(NULL,0);
PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
AppData.dwMaxResponseDataSize = spGetCapsData.dwEnumFrameSize - PackedBuffer.GetSizeRequired();
//
// pass message to the user
//
hResultCode = DNUserEnumQuery(pdnObject,&AppData);
//
// Only ENUMs which are accepted get responded to
//
if (hResultCode != DPN_OK)
{
DPFX(DPFPREP, 9, "EnumQuery rejected");
DisplayDNError(9, hResultCode);
goto Failure;
}
//
// get an async operation to track the progress of the response
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not allocate Async Op struct for enum response");
DisplayDNError( 0, hResultCode );
DNASSERT( FALSE );
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_ENUM_RESPONSE );
//
// compute the size needed to pack up an application description with any
// user data and send it back
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
PackedBuffer.Initialize(NULL,0);
PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
hResultCode = pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
DNASSERT( hResultCode == DPNERR_BUFFERTOOSMALL );
//
// Ensure this enum response will fit in SP enum frame - only indicate this if there was a response
//
if (((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0)) &&
(PackedBuffer.GetSizeRequired() + AppData.dwResponseDataSize > spGetCapsData.dwEnumFrameSize))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFERR("Enum response is too large");
DNUserReturnBuffer(pdnObject,DPNERR_ENUMRESPONSETOOLARGE,AppData.pvResponseData,AppData.pvResponseContext);
goto Failure;
}
hResultCode = RefCountBufferNew(pdnObject,
PackedBuffer.GetSizeRequired(),
EnumReplyMemoryBlockAlloc,
EnumReplyMemoryBlockFree,
&pRefCountBuffer);
if ( hResultCode != DPN_OK )
{
DNASSERT( FALSE );
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Failure;
}
PackedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),
pRefCountBuffer->GetBufferSize());
pEnumResponsePayload = static_cast<DN_ENUM_RESPONSE_PAYLOAD*>(PackedBuffer.GetHeadAddress());
hResultCode = PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
if (hResultCode != DPN_OK)
{
DNASSERT(FALSE);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Failure;
}
if ((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0))
{
pEnumResponsePayload->dwResponseOffset = pRefCountBuffer->GetBufferSize();
pEnumResponsePayload->dwResponseSize = AppData.dwResponseDataSize;
}
else
{
pEnumResponsePayload->dwResponseOffset = 0;
pEnumResponsePayload->dwResponseSize = 0;
}
pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
if ( hResultCode != DPN_OK )
{
DNASSERT( FALSE );
goto Failure;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// build enum response and send it down to the protocol
//
pEnumResponseOpData = pAsyncOp->GetLocalEnumResponseOpData();
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD].pBufferData = pRefCountBuffer->GetBufferAddress();
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD].dwBufferSize = pRefCountBuffer->GetBufferSize();
pAsyncOp->SetCompletion( DNCompleteEnumResponse );
pAsyncOp->SetRefCountBuffer( pRefCountBuffer );
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
if ((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0))
{
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData = static_cast<BYTE*>(AppData.pvResponseData);
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].dwBufferSize = AppData.dwResponseDataSize;
pEnumResponseOpData->pvUserContext = AppData.pvResponseContext;
dwBufferCount = DN_ENUM_BUFFERDESC_RESPONSE_COUNT;
}
else
{
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData = NULL;
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].dwBufferSize = 0;
pEnumResponseOpData->pvUserContext = NULL;
dwBufferCount = DN_ENUM_BUFFERDESC_RESPONSE_COUNT - 1;
}
DNASSERT(pListen->GetParent() != NULL);
DNASSERT(pListen->GetParent()->GetSP() != NULL);
DNASSERT(pListen->GetParent()->GetSP()->GetHandle() != NULL);
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNPEnumRespond( pdnObject->pdnProtocolData,
pListen->GetParent()->GetSP()->GetHandle(),
pEnumQueryData->hEnumQuery,
&pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD],
dwBufferCount,
0,
reinterpret_cast<void*>(pAsyncOp),
&hProtocol);
if ( hResultCode != DPNERR_PENDING )
{
pAsyncOp->Release();
DNProtocolRelease(pdnObject);
goto Failure;
}
//
// Save Protocol Handle
//
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled())
{
HRESULT hrCancel;
pAsyncOp->Unlock();
DPFX(DPFPREP, 7,"Operation marked for cancel");
if ((hrCancel = DNPCancelCommand(pdnObject->pdnProtocolData,hProtocol)) == DPN_OK)
{
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
DPFERR("Could not cancel operation");
DisplayDNError(0,hrCancel);
pAsyncOp->Lock();
}
pAsyncOp->SetSP( pSP );
pAsyncOp->SetProtocolHandle(hProtocol);
pAsyncOp->Unlock();
pAsyncOp->Release();
pAsyncOp = NULL;
pSP->Release();
pSP = NULL;
Exit:
DPFX(DPFPREP, 6,"Returning");
return;
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pIDP8SP)
{
IDP8ServiceProvider_Release(pIDP8SP);
pIDP8SP = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNProcessEnumResponse - process response to enum query
//
// Entry: Pointer to this DNet interface object
// Pointer to the associated enum operation
// Pointer to protocol's enum response data
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessEnumResponse"
void DNProcessEnumResponse(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp,
const PROTOCOL_ENUM_RESPONSE_DATA *const pEnumResponseData)
{
HRESULT hResultCode;
DPNMSG_ENUM_HOSTS_RESPONSE AppData;
BYTE *pWorkingItem;
UNALIGNED DN_ENUM_RESPONSE_PAYLOAD *pEnumResponsePayload;
DPN_APPLICATION_DESC dpnAppDesc;
UNALIGNED DPN_APPLICATION_DESC_INFO *pInfo;
BYTE AppDescReservedData[DPN_MAX_APPDESC_RESERVEDDATA_SIZE];
DNASSERT( pdnObject != NULL );
DNASSERT( pAsyncOp != NULL );
DNASSERT( pEnumResponseData != NULL );
pWorkingItem = pEnumResponseData->ReceivedData.pBufferData;
//
// Unpack the ENUM response.
// It will be in the following format:
// <UserResponseOffset>
// <UserResponseSize>
// <AppDescInfo>
//
//
// Verify buffer size
//
if (pEnumResponseData->ReceivedData.dwBufferSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)))
{
DPFERR("Received invalid enum response - buffer is smaller than minimum size");
goto Exit;
}
pEnumResponsePayload = reinterpret_cast<DN_ENUM_RESPONSE_PAYLOAD*>(pEnumResponseData->ReceivedData.pBufferData);
//
// Application Description
//
pInfo = reinterpret_cast<DPN_APPLICATION_DESC_INFO*>(pEnumResponsePayload + 1);
memset(&dpnAppDesc,0,sizeof(DPN_APPLICATION_DESC));
if (pInfo->dwSessionNameOffset)
{
if ((pInfo->dwSessionNameOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
(pInfo->dwSessionNameOffset+pInfo->dwSessionNameSize > pEnumResponseData->ReceivedData.dwBufferSize))
{
DPFERR("Received invalid enum response - session name is outside of buffer");
goto Exit;
}
dpnAppDesc.pwszSessionName = reinterpret_cast<WCHAR*>(pWorkingItem + pInfo->dwSessionNameOffset);
}
if (pInfo->dwReservedDataOffset)
{
if ((pInfo->dwReservedDataOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
(pInfo->dwReservedDataOffset+pInfo->dwReservedDataSize > pEnumResponseData->ReceivedData.dwBufferSize))
{
DPFERR("Received invalid enum response - reserved data is outside of buffer");
goto Exit;
}
dpnAppDesc.pvReservedData = static_cast<void*>(pWorkingItem + pInfo->dwReservedDataOffset);
dpnAppDesc.dwReservedDataSize = pInfo->dwReservedDataSize;
//
// If we understand the reserved data, we want to pad the buffer so the user doesn't
// assume the data is less than DPN_MAX_APPDESC_RESERVEDDATA_SIZE bytes long.
//
if ((dpnAppDesc.dwReservedDataSize == sizeof(SPSESSIONDATA_XNET)) &&
(*((DWORD*) dpnAppDesc.pvReservedData) == SPSESSIONDATAINFO_XNET))
{
SPSESSIONDATA_XNET * pSessionDataXNet;
pSessionDataXNet = (SPSESSIONDATA_XNET*) AppDescReservedData;
memcpy(pSessionDataXNet, dpnAppDesc.pvReservedData, dpnAppDesc.dwReservedDataSize);
memset((pSessionDataXNet + 1),
(((BYTE*) (&pSessionDataXNet->ullKeyID))[1] ^ ((BYTE*) (&pSessionDataXNet->guidKey))[2]),
(DPN_MAX_APPDESC_RESERVEDDATA_SIZE - sizeof(SPSESSIONDATA_XNET)));
dpnAppDesc.pvReservedData = AppDescReservedData;
dpnAppDesc.dwReservedDataSize = DPN_MAX_APPDESC_RESERVEDDATA_SIZE;
}
}
if (pInfo->dwApplicationReservedDataOffset)
{
if ((pInfo->dwApplicationReservedDataOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
(pInfo->dwApplicationReservedDataOffset+pInfo->dwApplicationReservedDataSize > pEnumResponseData->ReceivedData.dwBufferSize))
{
DPFERR("Received invalid enum response - application reserved data is outside of buffer");
goto Exit;
}
dpnAppDesc.pvApplicationReservedData = static_cast<void*>(pWorkingItem + pInfo->dwApplicationReservedDataOffset);
dpnAppDesc.dwApplicationReservedDataSize = pInfo->dwApplicationReservedDataSize;
}
dpnAppDesc.guidApplication = pInfo->guidApplication;
dpnAppDesc.guidInstance = pInfo->guidInstance;
dpnAppDesc.dwFlags = pInfo->dwFlags;
dpnAppDesc.dwCurrentPlayers = pInfo->dwCurrentPlayers;
dpnAppDesc.dwMaxPlayers = pInfo->dwMaxPlayers;
dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
//
// Fill in AppData
//
AppData.dwSize = sizeof( AppData );
AppData.pAddressSender = pEnumResponseData->pSenderAddress;
AppData.pAddressDevice = pEnumResponseData->pDeviceAddress;
AppData.pApplicationDescription = &dpnAppDesc;
AppData.dwRoundTripLatencyMS = pEnumResponseData->dwRoundTripTime;
if (pEnumResponsePayload->dwResponseOffset)
{
if ((pEnumResponsePayload->dwResponseOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
(pEnumResponsePayload->dwResponseOffset+pEnumResponsePayload->dwResponseSize > pEnumResponseData->ReceivedData.dwBufferSize))
{
DPFERR("Received invalid enum response - response data is outside of buffer");
goto Exit;
}
AppData.pvResponseData = (pEnumResponseData->ReceivedData.pBufferData + pEnumResponsePayload->dwResponseOffset);
AppData.dwResponseDataSize = pEnumResponsePayload->dwResponseSize;
}
else
{
AppData.pvResponseData = NULL;
AppData.dwResponseDataSize = 0;
}
AppData.pvUserContext = pAsyncOp->GetContext();
//
// pass message to the user
//
hResultCode = DNUserEnumResponse(pdnObject,&AppData);
//
// Check to see if this is to be cancelled
//
if (hResultCode != DPN_OK)
{
CAsyncOp *pCancelOp = NULL;
//
// Get top level operation (may be async op handle)
//
pAsyncOp->Lock();
pCancelOp = pAsyncOp;
while (pCancelOp->IsChild())
{
DNASSERT(pCancelOp->GetParent() != NULL);
pCancelOp = pCancelOp->GetParent();
}
pCancelOp->AddRef();
pAsyncOp->Unlock();
//
// Cancel
//
DNCancelChildren(pdnObject,pCancelOp);
pCancelOp->Release();
pCancelOp = NULL;
}
Exit:
return;
}