2252 lines
65 KiB
C++
2252 lines
65 KiB
C++
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|||
|
|
|||
|
Copyright (c) 1996 - 2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name :
|
|||
|
|
|||
|
asyncu.c
|
|||
|
|
|||
|
Abstract :
|
|||
|
|
|||
|
This file contains the ndr async uuid implementation.
|
|||
|
|
|||
|
Author :
|
|||
|
|
|||
|
Ryszard K. Kott (ryszardk) Oct 1997
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
---------------------------------------------------------------------*/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#define USE_STUBLESS_PROXY
|
|||
|
#define CINTERFACE
|
|||
|
|
|||
|
#include "ndrp.h"
|
|||
|
#include "ndrole.h"
|
|||
|
#include "rpcproxy.h"
|
|||
|
#include "mulsyntx.h"
|
|||
|
#include "hndl.h"
|
|||
|
#include "interp2.h"
|
|||
|
#include "asyncu.h"
|
|||
|
#include "attack.h"
|
|||
|
#include <stddef.h>
|
|||
|
|
|||
|
#include <stdarg.h>
|
|||
|
|
|||
|
#pragma code_seg(".orpc")
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
NdrpBeginDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
unsigned char * StartofStack
|
|||
|
);
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
NdrpFinishDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
unsigned char * StartofStack
|
|||
|
);
|
|||
|
|
|||
|
const IID * RPC_ENTRY
|
|||
|
NdrGetProxyIID(
|
|||
|
const void *pThis);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NdrpAsyncDCOMFreeParams(
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg )
|
|||
|
{
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Frees the parameters for both the begin and finish calls.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pAsyncMsg - Supplies a pointer to the async message.
|
|||
|
|
|||
|
Return Value:
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
if ( pAsyncMsg->BeginStack )
|
|||
|
{
|
|||
|
|
|||
|
if ( pAsyncMsg->FinishStack )
|
|||
|
{
|
|||
|
|
|||
|
// Clear out the IN OUT parameters on the begin stack
|
|||
|
// so that they are not freed twice.
|
|||
|
int n;
|
|||
|
REGISTER_TYPE *pBeginStack = (REGISTER_TYPE *)pAsyncMsg->BeginStack;
|
|||
|
PPARAM_DESCRIPTION BeginParams = (PPARAM_DESCRIPTION)pAsyncMsg->BeginParams;
|
|||
|
int BeginNumberParams = (int)pAsyncMsg->nBeginParams;
|
|||
|
|
|||
|
for( n = 0; n < BeginNumberParams; n++ )
|
|||
|
{
|
|||
|
|
|||
|
if ( BeginParams[n].ParamAttr.IsIn &&
|
|||
|
BeginParams[n].ParamAttr.IsOut )
|
|||
|
{
|
|||
|
|
|||
|
pBeginStack[ BeginParams[ n ].StackOffset / sizeof(REGISTER_TYPE) ] = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NdrpFreeParams( & (pAsyncMsg->StubMsg),
|
|||
|
pAsyncMsg->nBeginParams,
|
|||
|
(PPARAM_DESCRIPTION)pAsyncMsg->BeginParams,
|
|||
|
pAsyncMsg->BeginStack );
|
|||
|
}
|
|||
|
|
|||
|
if ( pAsyncMsg->FinishStack )
|
|||
|
{
|
|||
|
|
|||
|
NdrpFreeParams( & (pAsyncMsg->StubMsg),
|
|||
|
pAsyncMsg->nFinishParams,
|
|||
|
(PPARAM_DESCRIPTION)pAsyncMsg->FinishParams,
|
|||
|
pAsyncMsg->FinishStack );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
CLIENT_CALL_RETURN RPC_VAR_ENTRY
|
|||
|
NdrDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
...
|
|||
|
)
|
|||
|
/*
|
|||
|
This entry is used by the stubless proxy invoker and also by OLE thunks.
|
|||
|
Sync stubless proxies would invoke to NdrClientCall2.
|
|||
|
On ia64, this entry would be used by -Oic generated code.
|
|||
|
|
|||
|
Note that signaling on the client happens behind the async proxy's back
|
|||
|
as channel effectively signals to the app and the app issues the Finish.
|
|||
|
*/
|
|||
|
|
|||
|
{
|
|||
|
va_list ArgList;
|
|||
|
unsigned char * StartofStack;
|
|||
|
CLIENT_CALL_RETURN Ret;
|
|||
|
ulong ProcNum;
|
|||
|
//
|
|||
|
// Get address of argument to this function following pFormat. This
|
|||
|
// is the address of the address of the first argument of the function
|
|||
|
// calling this function.
|
|||
|
// Then get the address of the stack where the parameters are.
|
|||
|
//
|
|||
|
INIT_ARG( ArgList, pFormat);
|
|||
|
GET_FIRST_IN_ARG(ArgList);
|
|||
|
StartofStack = (uchar *) GET_STACK_START(ArgList);
|
|||
|
|
|||
|
// Object proc layout is fixed for anything that can show up here.
|
|||
|
|
|||
|
ProcNum = *(ushort *)(pFormat+6);
|
|||
|
|
|||
|
if ( ProcNum & 0x1 )
|
|||
|
{
|
|||
|
// An odd proc number means a Begin call (0,1,2,Begin,Finish, ...).
|
|||
|
|
|||
|
Ret.Simple = NdrpBeginDcomAsyncClientCall( pStubDescriptor,
|
|||
|
pFormat,
|
|||
|
StartofStack );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Ret.Simple = NdrpFinishDcomAsyncClientCall( pStubDescriptor,
|
|||
|
pFormat,
|
|||
|
StartofStack );
|
|||
|
}
|
|||
|
|
|||
|
return Ret;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if defined(_IA64_)
|
|||
|
CLIENT_CALL_RETURN RPC_ENTRY
|
|||
|
NdrpDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
unsigned char * StartofStack
|
|||
|
)
|
|||
|
/*
|
|||
|
Used only on ia64,
|
|||
|
this entry is used by the stubless proxy invoker and also by OLE thunks.
|
|||
|
Sync stubless proxies would invoke to NdrpClientCall2.
|
|||
|
|
|||
|
Note that signaling on the client happens behind the async proxy's back
|
|||
|
as channel effectively signals to the app and the app issues the Finish.
|
|||
|
*/
|
|||
|
|
|||
|
{
|
|||
|
CLIENT_CALL_RETURN Ret;
|
|||
|
ulong ProcNum;
|
|||
|
|
|||
|
// Object proc layout is fixed for anything that can show up here.
|
|||
|
|
|||
|
ProcNum = *(ushort *)(pFormat+6);
|
|||
|
|
|||
|
if ( ProcNum & 0x1 )
|
|||
|
{
|
|||
|
// An odd proc number means a Begin call (0,1,2,Begin,Finish, ...).
|
|||
|
|
|||
|
Ret.Simple = NdrpBeginDcomAsyncClientCall( pStubDescriptor,
|
|||
|
pFormat,
|
|||
|
StartofStack );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Ret.Simple = NdrpFinishDcomAsyncClientCall( pStubDescriptor,
|
|||
|
pFormat,
|
|||
|
StartofStack );
|
|||
|
}
|
|||
|
|
|||
|
return Ret;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpBeginDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
unsigned char * StartofStack
|
|||
|
)
|
|||
|
/*
|
|||
|
Notes: OLE Refcounting.
|
|||
|
The model for async_uuid() is that async proxies or stubs
|
|||
|
are created with RefCount==1 and should never ever be
|
|||
|
addrefed by the engine.
|
|||
|
What the engine does is only the AsyncMsg clean up when done.
|
|||
|
|
|||
|
The decision to destroy the AsyncPB or AsyncSB object is
|
|||
|
up to the client side PM or channel's SM for the server side.
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
|
|||
|
RPC_MESSAGE * pRpcMsg;
|
|||
|
MIDL_STUB_MESSAGE * pStubMsg;
|
|||
|
PFORMAT_STRING pFormatParam;
|
|||
|
|
|||
|
uchar * pArg;
|
|||
|
void * pThis = *(void **)StartofStack;
|
|||
|
INTERPRETER_FLAGS OldOiFlags;
|
|||
|
INTERPRETER_OPT_FLAGS NewOiFlags;
|
|||
|
PPARAM_DESCRIPTION Params;
|
|||
|
long NumberParams;
|
|||
|
long n;
|
|||
|
|
|||
|
RPC_STATUS Status;
|
|||
|
PNDR_DCOM_OI2_PROC_HEADER pProcHeader = (PNDR_DCOM_OI2_PROC_HEADER)pFormat;
|
|||
|
PNDR_PROC_HEADER_EXTS pHeaderExts = 0;
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB;
|
|||
|
const IID * piid;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
BOOL fSendCalled = FALSE;
|
|||
|
NDR_PROC_CONTEXT * pContext = NULL;
|
|||
|
|
|||
|
pAsyncPB = (CStdAsyncProxyBuffer*)
|
|||
|
((uchar*)pThis - offsetof(CStdProxyBuffer, pProxyVtbl));
|
|||
|
|
|||
|
piid = NdrGetProxyIID( pThis );
|
|||
|
|
|||
|
Status = NdrpSetupBeginClientCall( pAsyncPB,
|
|||
|
StartofStack,
|
|||
|
pProcHeader->StackSize,
|
|||
|
*piid );
|
|||
|
if ( !SUCCEEDED(Status) )
|
|||
|
return Status;
|
|||
|
|
|||
|
pAsyncMsg = (PNDR_DCOM_ASYNC_MESSAGE)pAsyncPB->CallState.pAsyncMsg;
|
|||
|
|
|||
|
// We need to switch to our copy of the stack everywhere, including pStubMsg.
|
|||
|
|
|||
|
StartofStack = pAsyncMsg->ProcContext.StartofStack;
|
|||
|
|
|||
|
pRpcMsg = & pAsyncMsg->RpcMsg;
|
|||
|
pStubMsg = & pAsyncMsg->StubMsg;
|
|||
|
pContext = ( NDR_PROC_CONTEXT * ) &pAsyncMsg->ProcContext;
|
|||
|
pStubMsg->pContext = pContext;
|
|||
|
pContext->StartofStack = StartofStack;
|
|||
|
|
|||
|
pStubMsg->FullPtrXlatTables = 0;
|
|||
|
|
|||
|
OldOiFlags = pProcHeader->OldOiFlags;
|
|||
|
NewOiFlags = pProcHeader->Oi2Flags;
|
|||
|
NumberParams = pProcHeader->NumberParams;
|
|||
|
|
|||
|
//
|
|||
|
// Parameter descriptions are nicely spit out by MIDL.
|
|||
|
//
|
|||
|
Params = (PPARAM_DESCRIPTION)(pFormat + sizeof(NDR_DCOM_OI2_PROC_HEADER));
|
|||
|
|
|||
|
// Proc header extentions, from NDR ver. 5.2, MIDL 5.0.+
|
|||
|
// Params must be set correctly here because of exceptions.
|
|||
|
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pHeaderExts = (NDR_PROC_HEADER_EXTS *)Params;
|
|||
|
Params = (PPARAM_DESCRIPTION)((uchar*)Params + pHeaderExts->Size);
|
|||
|
}
|
|||
|
|
|||
|
pAsyncMsg->nBeginParams = pContext->NumberParams = NumberParams;
|
|||
|
pAsyncMsg->BeginParams = pContext->Params = Params;
|
|||
|
pAsyncMsg->pThis = pThis;
|
|||
|
pContext->DceTypeFormatString = pStubDescriptor->pFormatTypes;
|
|||
|
|
|||
|
// This is OLE only code path - use a single TryExcept.
|
|||
|
// After catching it just map it to OLE exception.
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
ulong RpcFlags;
|
|||
|
|
|||
|
// Note, pProcHeader->ProcNum is the async proc number.
|
|||
|
|
|||
|
NdrProxyInitialize( pThis,
|
|||
|
pRpcMsg,
|
|||
|
pStubMsg,
|
|||
|
pStubDescriptor,
|
|||
|
(pProcHeader->ProcNum + 3)/2 // sync proc number
|
|||
|
);
|
|||
|
|
|||
|
pStubMsg->pAsyncMsg = (struct _NDR_ASYNC_MESSAGE *) pAsyncMsg;
|
|||
|
|
|||
|
if ( OldOiFlags.FullPtrUsed )
|
|||
|
pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit( 0, XLAT_CLIENT );
|
|||
|
|
|||
|
// Set Rpc flags after the call to client initialize.
|
|||
|
RpcFlags= *(ulong UNALIGNED *)(pFormat + 2);
|
|||
|
pStubMsg->RpcMsg->RpcFlags = RpcFlags;
|
|||
|
|
|||
|
// Must do this before the sizing pass!
|
|||
|
pStubMsg->StackTop = pContext->StartofStack = StartofStack;
|
|||
|
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pStubMsg->fHasExtensions = 1;
|
|||
|
pStubMsg->fHasNewCorrDesc = pHeaderExts->Flags2.HasNewCorrDesc;
|
|||
|
if ( pHeaderExts->Flags2.ClientCorrCheck )
|
|||
|
{
|
|||
|
void * pCache = NdrpAlloca( &pAsyncMsg->ProcContext.AllocateContext, NDR_DEFAULT_CORR_CACHE_SIZE );
|
|||
|
|
|||
|
NdrCorrelationInitialize( pStubMsg,
|
|||
|
pCache,
|
|||
|
NDR_DEFAULT_CORR_CACHE_SIZE,
|
|||
|
0 /* flags */ );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// ----------------------------------------------------------------
|
|||
|
// Sizing Pass.
|
|||
|
// ----------------------------------------------------------------
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Get the compile time computed buffer size.
|
|||
|
//
|
|||
|
pStubMsg->BufferLength = pProcHeader->ClientBufferSize;
|
|||
|
|
|||
|
//
|
|||
|
// Check ref pointers and do object proc [out] zeroing.
|
|||
|
//
|
|||
|
|
|||
|
for ( n = 0; n < NumberParams; n++ )
|
|||
|
{
|
|||
|
pArg = StartofStack + Params[n].StackOffset;
|
|||
|
|
|||
|
if ( Params[n].ParamAttr.IsSimpleRef )
|
|||
|
{
|
|||
|
// We can raise the exception here as there is no out only args.
|
|||
|
|
|||
|
if ( ! *((uchar **)pArg) )
|
|||
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|||
|
}
|
|||
|
|
|||
|
// [out] only argument on the Begin call.
|
|||
|
if ( ! Params[n].ParamAttr.IsIn &&
|
|||
|
Params[n].ParamAttr.IsOut &&
|
|||
|
! Params[n].ParamAttr.IsReturn)
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Skip buffer size pass if possible.
|
|||
|
//
|
|||
|
if ( NewOiFlags.ClientMustSize )
|
|||
|
{
|
|||
|
NdrpSizing( pStubMsg,
|
|||
|
TRUE ); // IsObject
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do the GetBuffer.
|
|||
|
//
|
|||
|
|
|||
|
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
|||
|
|
|||
|
NdrProxyGetBuffer( pThis, pStubMsg );
|
|||
|
|
|||
|
NDR_ASSERT( pStubMsg->fBufferValid, "Invalid buffer" );
|
|||
|
|
|||
|
pAsyncMsg->StubPhase = STUB_MARSHAL;
|
|||
|
|
|||
|
//
|
|||
|
// ----------------------------------------------------------
|
|||
|
// Marshall Pass.
|
|||
|
// ----------------------------------------------------------
|
|||
|
//
|
|||
|
|
|||
|
NdrpClientMarshal ( pStubMsg,
|
|||
|
TRUE ); // IsObject
|
|||
|
//
|
|||
|
// Make the RPC call.
|
|||
|
//
|
|||
|
|
|||
|
pAsyncMsg->StubPhase = NDR_ASYNC_CALL_PHASE;
|
|||
|
|
|||
|
fSendCalled = NdrpDcomAsyncClientSend( pStubMsg,
|
|||
|
pAsyncPB->punkOuter ); // PM's entry
|
|||
|
if ( fSendCalled )
|
|||
|
hr = S_OK;
|
|||
|
}
|
|||
|
RpcExcept( 1 )
|
|||
|
{
|
|||
|
RPC_STATUS ExceptionCode = RpcExceptionCode();
|
|||
|
|
|||
|
pAsyncPB->CallState.Flags.BeginError = 1;
|
|||
|
|
|||
|
// Actually dismantle the call.
|
|||
|
// This is a request call and there is nothing left at the runtime.
|
|||
|
|
|||
|
pAsyncMsg->StubPhase = NDR_ASYNC_ERROR_PHASE;
|
|||
|
pAsyncMsg->ErrorCode = ExceptionCode;
|
|||
|
|
|||
|
hr = NdrHrFromWin32Error(ExceptionCode);
|
|||
|
pAsyncPB->CallState.Hr = hr;
|
|||
|
|
|||
|
// Async call in request phase: don't touch [out] params.
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
// "Finally"
|
|||
|
// Dont touch anything, the client has to call the Finish method anyway.
|
|||
|
|
|||
|
pAsyncPB->CallState.Flags.BeginDone = 1;
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
NdrpCloneInOnlyCorrArgs( pAsyncMsg, pAsyncMsg->StubMsg.StubDesc->pFormatTypes );
|
|||
|
// Channel will prompt signal
|
|||
|
}
|
|||
|
else
|
|||
|
if (!fSendCalled )
|
|||
|
NdrpAsyncProxySignal( pAsyncPB );
|
|||
|
|
|||
|
// No need to release, our refcount should be 1 at this point.
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NdrpCloneInOnlyCorrArgs(
|
|||
|
NDR_DCOM_ASYNC_MESSAGE * pAsyncMsg,
|
|||
|
PFORMAT_STRING pTypeFormat
|
|||
|
)
|
|||
|
/*
|
|||
|
Walk the client stack looking for an in only argument flagged to clone.
|
|||
|
For each one, replace the arg with a clone that we control.
|
|||
|
Assumption is, we do it before returning to the user from the Begin call
|
|||
|
and also we clone walking the copy of the app's stack not the app stack.
|
|||
|
|
|||
|
The stack modified in this way will be the one to access for the weird
|
|||
|
crossreferenced correlated args.
|
|||
|
|
|||
|
This issue doesn't happen on the server, as we keep the Begin stack around
|
|||
|
when the Finish call is processed.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
unsigned char * pBeginStack = pAsyncMsg->BeginStack;
|
|||
|
PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION)pAsyncMsg->BeginParams;
|
|||
|
int NumberParams = (int)pAsyncMsg->nBeginParams;
|
|||
|
unsigned char * pArg;
|
|||
|
int n;
|
|||
|
|
|||
|
for ( n = 0; n < NumberParams; n++ )
|
|||
|
{
|
|||
|
if ( Params[n].ParamAttr.SaveForAsyncFinish )
|
|||
|
{
|
|||
|
// Note that the arguments that need cloning come from top level size_is,
|
|||
|
// length_is etc, switch_is and iid_is attributes.
|
|||
|
// Hence, the only types of interest are uuid clones and integral types
|
|||
|
// different from hyper.
|
|||
|
// On top of it, we deal with stack-slot chunks of memory, so we don't
|
|||
|
// have to care about mac issues.
|
|||
|
|
|||
|
pArg = pBeginStack + Params[n].StackOffset;
|
|||
|
|
|||
|
if ( Params[n].ParamAttr.IsBasetype )
|
|||
|
{
|
|||
|
if ( Params[n].ParamAttr.IsSimpleRef )
|
|||
|
{
|
|||
|
void * pPointee = AsyncAlloca( pAsyncMsg, 8 );
|
|||
|
|
|||
|
// The assignment needs to follow the type.
|
|||
|
RpcpMemoryCopy( pPointee, *(void **)pArg,
|
|||
|
SIMPLE_TYPE_MEMSIZE( Params[n].SimpleType.Type ) );
|
|||
|
*(void**)pArg = pPointee;
|
|||
|
}
|
|||
|
// else the stack slot has the simple value already.
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// If it's not a base type, then it cannot be by value.
|
|||
|
// It has to be a pointer to a simple type or to an iid.
|
|||
|
|
|||
|
PFORMAT_STRING pParamFormat;
|
|||
|
|
|||
|
pParamFormat = pTypeFormat +
|
|||
|
Params[n].TypeOffset;
|
|||
|
|
|||
|
if ( IS_BASIC_POINTER(*pParamFormat) ) // not FC_IP
|
|||
|
{
|
|||
|
if ( SIMPLE_POINTER(pParamFormat[1]) )
|
|||
|
{
|
|||
|
// Covers things like a unique pointer to a size
|
|||
|
// Essentially the same as for the simple ref above.
|
|||
|
|
|||
|
void * pPointee = AsyncAlloca( pAsyncMsg, 8 );
|
|||
|
|
|||
|
// The assignment needs to follow the type.
|
|||
|
RpcpMemoryCopy( pPointee, *(void **)pArg,
|
|||
|
SIMPLE_TYPE_MEMSIZE( pParamFormat[2] ) );
|
|||
|
*(void**)pArg = pPointee;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// has to be the riid case.
|
|||
|
// REFIID* comes out as FC_?P -> FC_?P -> FC_STRUCT
|
|||
|
|
|||
|
PFORMAT_STRING pFormat;
|
|||
|
|
|||
|
pFormat = pParamFormat + *(short *)(pParamFormat + 2);
|
|||
|
|
|||
|
if ( IS_BASIC_POINTER(*pFormat) &&
|
|||
|
! SIMPLE_POINTER(pParamFormat[1]) )
|
|||
|
{
|
|||
|
pParamFormat = pFormat + *(short *)(pFormat + 2);
|
|||
|
|
|||
|
if ( *pParamFormat == FC_STRUCT )
|
|||
|
{
|
|||
|
// one alloc for REFIID and IID itself.
|
|||
|
IID** ppIID =
|
|||
|
(IID**)AsyncAlloca( pAsyncMsg,
|
|||
|
sizeof(IID *) + sizeof(IID));
|
|||
|
IID* pIID = (IID *)(ppIID + 1);
|
|||
|
|
|||
|
|
|||
|
*ppIID = pIID; //set pointer
|
|||
|
RpcpMemoryCopy( pIID, **(IID ***)pArg, sizeof(IID));
|
|||
|
*(IID ***)pArg = ppIID;
|
|||
|
}
|
|||
|
else
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
}
|
|||
|
else
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// has to be the riid case.
|
|||
|
// REFIID comes out as FC_STRUCT
|
|||
|
|
|||
|
if ( *pParamFormat == FC_STRUCT )
|
|||
|
{
|
|||
|
IID *pIID = (IID*)AsyncAlloca( pAsyncMsg, sizeof(IID) );
|
|||
|
|
|||
|
RpcpMemoryCopy( pIID, *(IID **)pArg, sizeof(IID));
|
|||
|
*(IID **)pArg = pIID;
|
|||
|
}
|
|||
|
else
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpFinishDcomAsyncClientCall(
|
|||
|
PMIDL_STUB_DESC pStubDescriptor,
|
|||
|
PFORMAT_STRING pFormat,
|
|||
|
unsigned char * StartofStack
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_MESSAGE * pRpcMsg;
|
|||
|
MIDL_STUB_MESSAGE * pStubMsg;
|
|||
|
|
|||
|
PFORMAT_STRING pFormatParam;
|
|||
|
|
|||
|
uchar * pArg;
|
|||
|
void * pThis = *(void **)StartofStack;
|
|||
|
CLIENT_CALL_RETURN ReturnValue;
|
|||
|
|
|||
|
INTERPRETER_FLAGS OldOiFlags; // Finish proc flags
|
|||
|
INTERPRETER_OPT_FLAGS NewOiFlags; //
|
|||
|
PPARAM_DESCRIPTION Params; //
|
|||
|
long NumberParams;
|
|||
|
long n;
|
|||
|
NDR_ASYNC_CALL_FLAGS CallFlags;
|
|||
|
|
|||
|
PNDR_DCOM_OI2_PROC_HEADER pProcHeader = (PNDR_DCOM_OI2_PROC_HEADER)pFormat;
|
|||
|
PNDR_PROC_HEADER_EXTS pHeaderExts = 0;
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB;
|
|||
|
const IID * piid;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
NDR_PROC_CONTEXT * pContext = NULL;
|
|||
|
|
|||
|
ReturnValue.Simple = 0;
|
|||
|
|
|||
|
pAsyncPB = (CStdAsyncProxyBuffer*)
|
|||
|
((uchar*)pThis - offsetof(CStdProxyBuffer, pProxyVtbl));
|
|||
|
|
|||
|
piid = NdrGetProxyIID( pThis );
|
|||
|
|
|||
|
hr = NdrpSetupFinishClientCall( pAsyncPB,
|
|||
|
StartofStack,
|
|||
|
pProcHeader->StackSize,
|
|||
|
*piid,
|
|||
|
pProcHeader->ProcNum );
|
|||
|
if ( !SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
// Note that we cant call to NdrProxyInitialize again.
|
|||
|
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg =
|
|||
|
(PNDR_DCOM_ASYNC_MESSAGE)pAsyncPB->CallState.pAsyncMsg;
|
|||
|
|
|||
|
pRpcMsg = & pAsyncMsg->RpcMsg;
|
|||
|
pStubMsg = & pAsyncMsg->StubMsg;
|
|||
|
pContext = ( NDR_PROC_CONTEXT * )pStubMsg->pContext;
|
|||
|
|
|||
|
OldOiFlags = pProcHeader->OldOiFlags;
|
|||
|
NewOiFlags = pProcHeader->Oi2Flags;
|
|||
|
NumberParams = pProcHeader->NumberParams;
|
|||
|
|
|||
|
//
|
|||
|
// Parameter descriptions are nicely spit out by MIDL.
|
|||
|
//
|
|||
|
Params = (PPARAM_DESCRIPTION)(pFormat + sizeof(NDR_DCOM_OI2_PROC_HEADER));
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pHeaderExts = (NDR_PROC_HEADER_EXTS *)Params;
|
|||
|
Params = (PPARAM_DESCRIPTION)((uchar*)Params + pHeaderExts->Size);
|
|||
|
}
|
|||
|
|
|||
|
CallFlags = pAsyncMsg->Flags;
|
|||
|
|
|||
|
// Initialize the stack top in the stub msg to be
|
|||
|
// this stack, the stack for the finish call parameters.
|
|||
|
pAsyncMsg->nFinishParams = pContext->NumberParams = NumberParams;
|
|||
|
pAsyncMsg->FinishParams = pContext->Params = Params;
|
|||
|
pStubMsg->StackTop = pContext->StartofStack = StartofStack;
|
|||
|
|
|||
|
// OLE only code path - single RpcTryExcept.
|
|||
|
//
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
BOOL fRaiseExcFlag = FALSE;
|
|||
|
|
|||
|
if ( CallFlags.ErrorPending )
|
|||
|
RpcRaiseException( pAsyncMsg->ErrorCode );
|
|||
|
|
|||
|
// We need to zero out the [out] parameters and to check
|
|||
|
// the ref pointers.
|
|||
|
|
|||
|
for ( n = 0; n < NumberParams; n++ )
|
|||
|
{
|
|||
|
pArg = StartofStack + Params[n].StackOffset;
|
|||
|
|
|||
|
if ( Params[n].ParamAttr.IsSimpleRef )
|
|||
|
{
|
|||
|
// We cannot raise the exception here,
|
|||
|
// as some out args may not be zeroed out yet.
|
|||
|
|
|||
|
if ( ! *((uchar **)pArg) )
|
|||
|
{
|
|||
|
fRaiseExcFlag = TRUE;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// We do the basetype check to cover the
|
|||
|
// [out] simple ref to basetype case.
|
|||
|
//
|
|||
|
if ( Params[n].ParamAttr.IsPartialIgnore ||
|
|||
|
( ! Params[n].ParamAttr.IsIn &&
|
|||
|
! Params[n].ParamAttr.IsReturn ) )
|
|||
|
{
|
|||
|
if ( Params[n].ParamAttr.IsBasetype )
|
|||
|
{
|
|||
|
// [out] only arg can only be ref, we checked that above.
|
|||
|
MIDL_memset( *(uchar **)pArg,
|
|||
|
0,
|
|||
|
(size_t)SIMPLE_TYPE_MEMSIZE( Params[n].SimpleType.Type ));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pFormatParam = pStubDescriptor->pFormatTypes +
|
|||
|
Params[n].TypeOffset;
|
|||
|
|
|||
|
NdrClientZeroOut(
|
|||
|
pStubMsg,
|
|||
|
pFormatParam,
|
|||
|
*(uchar **)pArg );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( fRaiseExcFlag )
|
|||
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|||
|
|
|||
|
|
|||
|
NdrDcomAsyncReceive( pStubMsg );
|
|||
|
|
|||
|
//
|
|||
|
// ----------------------------------------------------------
|
|||
|
// Unmarshall Pass.
|
|||
|
// ----------------------------------------------------------
|
|||
|
//
|
|||
|
|
|||
|
NdrpClientUnMarshal( pStubMsg,
|
|||
|
&ReturnValue );
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// DCOM interface must have HRESULT as return value.
|
|||
|
hr = (HRESULT) ReturnValue.Simple;
|
|||
|
}
|
|||
|
RpcExcept( 1 )
|
|||
|
{
|
|||
|
RPC_STATUS ExceptionCode = RpcExceptionCode();
|
|||
|
|
|||
|
//
|
|||
|
// In OLE, since they don't know about error_status_t and wanted to
|
|||
|
// reinvent the wheel, check to see if we need to map the exception.
|
|||
|
// In either case, set the return value and then try to free the
|
|||
|
// [out] params, if required.
|
|||
|
//
|
|||
|
hr = NdrHrFromWin32Error(ExceptionCode);
|
|||
|
|
|||
|
//
|
|||
|
// Set the Buffer endpoints so the NdrFree routines work.
|
|||
|
//
|
|||
|
pStubMsg->BufferStart = 0;
|
|||
|
pStubMsg->BufferEnd = 0;
|
|||
|
|
|||
|
for ( n = 0; n < NumberParams; n++ )
|
|||
|
{
|
|||
|
//
|
|||
|
// Skip everything but [out] only parameters. We make
|
|||
|
// the basetype check to cover [out] simple ref pointers
|
|||
|
// to basetypes.
|
|||
|
//
|
|||
|
if ( !Params[n].ParamAttr.IsPartialIgnore )
|
|||
|
{
|
|||
|
if ( Params[n].ParamAttr.IsIn ||
|
|||
|
Params[n].ParamAttr.IsReturn ||
|
|||
|
Params[n].ParamAttr.IsBasetype )
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
pArg = StartofStack + Params[n].StackOffset;
|
|||
|
|
|||
|
pFormatParam = pStubDescriptor->pFormatTypes +
|
|||
|
Params[n].TypeOffset;
|
|||
|
|
|||
|
NdrClearOutParameters( pStubMsg,
|
|||
|
pFormatParam,
|
|||
|
*((uchar **)pArg) );
|
|||
|
}
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
// Finish
|
|||
|
// Cleanup everything. However, don't free pAsyncPB itself.
|
|||
|
|
|||
|
NdrpAsyncProxyMsgDestructor( pAsyncPB );
|
|||
|
|
|||
|
// Never addref or release async proxy object, this is app's/PM's job.
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT RPC_ENTRY
|
|||
|
NdrDcomAsyncStubCall(
|
|||
|
struct IRpcStubBuffer * pThis,
|
|||
|
struct IRpcChannelBuffer * pChannel,
|
|||
|
PRPC_MESSAGE pRpcMsg,
|
|||
|
ulong * pdwStubPhase
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description :
|
|||
|
|
|||
|
Server Interpreter entry point for DCOM async procs.
|
|||
|
This is the Begin entry for channel (regular dispatch entry from stub.c).
|
|||
|
The Finish happen when the channel calls stub's Synchronize::Signal method
|
|||
|
on the stub object. The call then comes to NdrpAsyncStubSignal later below.
|
|||
|
|
|||
|
Arguments :
|
|||
|
|
|||
|
pThis - Object proc's 'this' pointer.
|
|||
|
pChannel - Object proc's Channel Buffer.
|
|||
|
pRpcMsg - The RPC message.
|
|||
|
pdwStubPhase - Used to track the current interpreter's activity.
|
|||
|
|
|||
|
Return :
|
|||
|
|
|||
|
Status of S_OK.
|
|||
|
|
|||
|
Notes :
|
|||
|
The engine never calls a signal on behalf of the user, regardless what kind of
|
|||
|
errors happen during begin (cannot setup begin, cannot unmarshal, app dies in invoke).
|
|||
|
In each of these cases, the engine simply returns an error code to the channel.
|
|||
|
|
|||
|
The only time the engine would call FreeBuffer on the server is if the engine died
|
|||
|
between a successful GetBuffer and the final Send.
|
|||
|
|
|||
|
Notes on OLE Refcounting.
|
|||
|
The model for async_uuid() is that async proxies or stubs are created
|
|||
|
with RefCount==1 and should never ever be addrefed by the engine.
|
|||
|
What the engine does is only the AsyncMsg clean up when done.
|
|||
|
|
|||
|
The decision to destroy the AsyncPB or AsyncSB object is
|
|||
|
up to the client side PM or channel's SM for the server side.
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
|
|||
|
PMIDL_SERVER_INFO pServerInfo;
|
|||
|
PMIDL_STUB_DESC pStubDesc;
|
|||
|
const SERVER_ROUTINE * DispatchTable;
|
|||
|
unsigned long ProcNum;
|
|||
|
|
|||
|
ushort FormatOffset;
|
|||
|
PFORMAT_STRING pFormat;
|
|||
|
PFORMAT_STRING pFormatParam;
|
|||
|
|
|||
|
PMIDL_STUB_MESSAGE pStubMsg;
|
|||
|
|
|||
|
uchar * pArgBuffer;
|
|||
|
uchar * pArg;
|
|||
|
uchar ** ppArg;
|
|||
|
|
|||
|
PPARAM_DESCRIPTION Params;
|
|||
|
INTERPRETER_FLAGS OldOiFlags;
|
|||
|
INTERPRETER_OPT_FLAGS NewOiFlags;
|
|||
|
long NumberParams;
|
|||
|
|
|||
|
BOOL fBadStubDataException = FALSE;
|
|||
|
BOOL fManagerCodeInvoked = FALSE;
|
|||
|
long n;
|
|||
|
PNDR_DCOM_OI2_PROC_HEADER pProcHeader;
|
|||
|
PNDR_PROC_HEADER_EXTS pHeaderExts = 0;
|
|||
|
|
|||
|
CStdAsyncStubBuffer * pAsyncSB;
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
const IID * piid = 0;
|
|||
|
BOOL fErrorInInvoke = FALSE;
|
|||
|
BOOL fRecoverableErrorInInvoke = FALSE;
|
|||
|
|
|||
|
IUnknown * pSrvObj;
|
|||
|
CInterfaceStubVtbl * pStubVTable;
|
|||
|
NDR_PROC_CONTEXT * pContext = NULL ;
|
|||
|
RPC_STATUS ExceptionCode = 0;
|
|||
|
|
|||
|
NDR_ASSERT( ! ((ULONG_PTR)pRpcMsg->Buffer & 0x7),
|
|||
|
"marshaling buffer misaligned at server" );
|
|||
|
|
|||
|
// The channel dispatches to the engine with the sync proc num.
|
|||
|
// We need only async proc num at the engine level.
|
|||
|
ProcNum = pRpcMsg->ProcNum;
|
|||
|
ProcNum = 2 * ProcNum - 3; // Begin method #
|
|||
|
|
|||
|
pSrvObj = (IUnknown *)((CStdStubBuffer *)pThis)->pvServerObject;
|
|||
|
DispatchTable = (SERVER_ROUTINE *)pSrvObj->lpVtbl;
|
|||
|
|
|||
|
pStubVTable = (CInterfaceStubVtbl *)
|
|||
|
(*((uchar **)pThis) - sizeof(CInterfaceStubHeader));
|
|||
|
|
|||
|
piid = pStubVTable->header.piid;
|
|||
|
pServerInfo = (PMIDL_SERVER_INFO) pStubVTable->header.pServerInfo;
|
|||
|
|
|||
|
pStubDesc = pServerInfo->pStubDesc;
|
|||
|
FormatOffset = pServerInfo->FmtStringOffset[ ProcNum ];
|
|||
|
pFormat = &((pServerInfo->ProcString)[FormatOffset]);
|
|||
|
|
|||
|
// The proc header has a fixed layout now.
|
|||
|
|
|||
|
pProcHeader = (PNDR_DCOM_OI2_PROC_HEADER) pFormat;
|
|||
|
|
|||
|
pAsyncSB = (CStdAsyncStubBuffer *)
|
|||
|
((uchar *)pThis - offsetof(CStdAsyncStubBuffer,lpVtbl));
|
|||
|
|
|||
|
hr = NdrpSetupBeginStubCall( pAsyncSB,
|
|||
|
pProcHeader->StackSize,
|
|||
|
*piid );
|
|||
|
if ( FAILED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
pAsyncMsg = (PNDR_DCOM_ASYNC_MESSAGE)pAsyncSB->CallState.pAsyncMsg;
|
|||
|
pStubMsg = & pAsyncMsg->StubMsg;
|
|||
|
pContext = &pAsyncMsg->ProcContext;
|
|||
|
|
|||
|
// Both rpc runtime and channel require that we use a copy of the rpc message.
|
|||
|
|
|||
|
RpcpMemoryCopy( & pAsyncMsg->RpcMsg, pRpcMsg, sizeof(RPC_MESSAGE) );
|
|||
|
pRpcMsg = & pAsyncMsg->RpcMsg;
|
|||
|
|
|||
|
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
|||
|
|
|||
|
// The arg buffer is zeroed out already.
|
|||
|
pArgBuffer = pAsyncMsg->ProcContext.StartofStack;
|
|||
|
|
|||
|
//
|
|||
|
// Get new interpreter info.
|
|||
|
//
|
|||
|
OldOiFlags = pProcHeader->OldOiFlags;
|
|||
|
NewOiFlags = pProcHeader->Oi2Flags;
|
|||
|
NumberParams = pProcHeader->NumberParams;
|
|||
|
|
|||
|
Params = (PPARAM_DESCRIPTION)(pFormat + sizeof(NDR_DCOM_OI2_PROC_HEADER));
|
|||
|
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pHeaderExts = (NDR_PROC_HEADER_EXTS *)Params;
|
|||
|
Params = (PPARAM_DESCRIPTION)((uchar*)Params + pHeaderExts->Size);
|
|||
|
}
|
|||
|
|
|||
|
pAsyncMsg->nBeginParams = pContext->NumberParams = NumberParams;
|
|||
|
pAsyncMsg->BeginParams = pContext->Params = Params;
|
|||
|
pAsyncMsg->pThis = pThis;
|
|||
|
pContext->DceTypeFormatString = pStubDesc->pFormatTypes;
|
|||
|
|
|||
|
//
|
|||
|
// Wrap the unmarshalling and the invoke call in the try block of
|
|||
|
// a try-finally. Put the free phase in the associated finally block.
|
|||
|
//
|
|||
|
// We abstract the level of indirection here.
|
|||
|
|
|||
|
RpcTryFinally
|
|||
|
{
|
|||
|
// OLE: put pThis in first dword of stack.
|
|||
|
//
|
|||
|
((void **)pArgBuffer)[0] = ((CStdStubBuffer *)pThis)->pvServerObject;
|
|||
|
|
|||
|
// Initialize the Stub message.
|
|||
|
//
|
|||
|
NdrStubInitialize( pRpcMsg,
|
|||
|
pStubMsg,
|
|||
|
pStubDesc,
|
|||
|
pChannel );
|
|||
|
|
|||
|
pStubMsg->pAsyncMsg = (struct _NDR_ASYNC_MESSAGE *) pAsyncMsg;
|
|||
|
|
|||
|
pAsyncMsg->pdwStubPhase = pdwStubPhase; // the phase is STUB_UNMARSHAL
|
|||
|
|
|||
|
// Raise exceptions after initializing the stub.
|
|||
|
|
|||
|
if ( OldOiFlags.FullPtrUsed )
|
|||
|
pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit( 0, XLAT_SERVER );
|
|||
|
else
|
|||
|
pStubMsg->FullPtrXlatTables = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Set StackTop AFTER the initialize call, since it zeros the field
|
|||
|
// out.
|
|||
|
//
|
|||
|
pStubMsg->StackTop = pArgBuffer;
|
|||
|
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pStubMsg->fHasExtensions = 1;
|
|||
|
pStubMsg->fHasNewCorrDesc = pHeaderExts->Flags2.HasNewCorrDesc;
|
|||
|
|
|||
|
if ( pHeaderExts->Flags2.ServerCorrCheck )
|
|||
|
{
|
|||
|
void * pCache = NdrpAlloca( &pAsyncMsg->ProcContext.AllocateContext, NDR_DEFAULT_CORR_CACHE_SIZE );
|
|||
|
|
|||
|
NdrCorrelationInitialize( pStubMsg,
|
|||
|
pCache,
|
|||
|
NDR_DEFAULT_CORR_CACHE_SIZE,
|
|||
|
0 /* flags */ );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// StubPhase set up by invoke is STUB_UNMARSHAL
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
|
|||
|
// --------------------------------
|
|||
|
// Unmarshall all of our parameters.
|
|||
|
// --------------------------------
|
|||
|
|
|||
|
NdrpServerUnMarshal( pStubMsg );
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Last ditch checks.
|
|||
|
|
|||
|
if ( pRpcMsg->BufferLength <
|
|||
|
(uint)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer) )
|
|||
|
{
|
|||
|
RpcRaiseException( RPC_X_BAD_STUB_DATA );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RpcExcept( NdrServerUnmarshallExceptionFlag(GetExceptionInformation()) )
|
|||
|
{
|
|||
|
ExceptionCode = RpcExceptionCode();
|
|||
|
// Filter set in rpcndr.h to catch one of the following
|
|||
|
// STATUS_ACCESS_VIOLATION
|
|||
|
// STATUS_DATATYPE_MISALIGNMENT
|
|||
|
// RPC_X_BAD_STUB_DATA
|
|||
|
|
|||
|
fBadStubDataException = TRUE;
|
|||
|
|
|||
|
pAsyncMsg->Flags.BadStubData = 1;
|
|||
|
pAsyncMsg->Flags.ErrorPending = 1;
|
|||
|
|
|||
|
if ( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
|
|||
|
{
|
|||
|
ExceptionCode = RPC_X_BAD_STUB_DATA;
|
|||
|
}
|
|||
|
pAsyncMsg->ErrorCode = ExceptionCode;
|
|||
|
|
|||
|
NdrpFreeMemoryList( pStubMsg );
|
|||
|
pAsyncSB->CallState.Flags.BeginError = 1;
|
|||
|
pAsyncSB->CallState.Hr = NdrHrFromWin32Error( ExceptionCode);
|
|||
|
|
|||
|
RpcRaiseException( ExceptionCode );
|
|||
|
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
//
|
|||
|
// Do [out] initialization before the invoke.
|
|||
|
//
|
|||
|
for ( n = 0; n < NumberParams; n++ )
|
|||
|
{
|
|||
|
if ( Params[n].ParamAttr.IsIn ||
|
|||
|
Params[n].ParamAttr.IsReturn )
|
|||
|
continue;
|
|||
|
|
|||
|
// This is a Begin call, there cannot be any [out] only args.
|
|||
|
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// OLE interfaces use pdwStubPhase in the exception filter.
|
|||
|
// See CStdStubBuffer_Invoke in stub.c.
|
|||
|
//
|
|||
|
*pdwStubPhase = STUB_CALL_SERVER;
|
|||
|
|
|||
|
// We need to catch exception in the manager code separately
|
|||
|
// as the model implies that there will be no other call from
|
|||
|
// the server app to clean up.
|
|||
|
|
|||
|
pAsyncSB->CallState.Flags.BeginDone = 1;
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
//
|
|||
|
// Check for a thunk. Compiler does all the setup for us.
|
|||
|
//
|
|||
|
if ( pServerInfo->ThunkTable && pServerInfo->ThunkTable[ ProcNum ] )
|
|||
|
{
|
|||
|
fManagerCodeInvoked = TRUE;
|
|||
|
pServerInfo->ThunkTable[ ProcNum ]( pStubMsg );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Note that this ArgNum is not the number of arguments declared
|
|||
|
// in the function we called, but really the number of
|
|||
|
// REGISTER_TYPEs occupied by the arguments to a function.
|
|||
|
//
|
|||
|
long ArgNum;
|
|||
|
MANAGER_FUNCTION pFunc;
|
|||
|
REGISTER_TYPE ReturnValue;
|
|||
|
|
|||
|
pFunc = (MANAGER_FUNCTION) DispatchTable[ ProcNum ];
|
|||
|
ArgNum = (long)pProcHeader->StackSize / sizeof(REGISTER_TYPE);
|
|||
|
|
|||
|
//
|
|||
|
// The StackSize includes the size of the return. If we want
|
|||
|
// just the number of REGISTER_TYPES, then ArgNum must be reduced
|
|||
|
// by 1 when there is a return value AND the current ArgNum count
|
|||
|
// is greater than 0.
|
|||
|
//
|
|||
|
if ( ArgNum && NewOiFlags.HasReturn )
|
|||
|
ArgNum--;
|
|||
|
|
|||
|
// Being here means that we can expect results. Note that the user
|
|||
|
// can call RpcCompleteCall from inside of the manager code.
|
|||
|
|
|||
|
fManagerCodeInvoked = TRUE;
|
|||
|
ReturnValue = Invoke( pFunc,
|
|||
|
(REGISTER_TYPE *)pArgBuffer,
|
|||
|
#if defined(_IA64_)
|
|||
|
NewOiFlags.HasExtensions ? ((PNDR_PROC_HEADER_EXTS64)pHeaderExts)->FloatArgMask
|
|||
|
: 0,
|
|||
|
#endif
|
|||
|
ArgNum);
|
|||
|
|
|||
|
if ( NewOiFlags.HasReturn )
|
|||
|
{
|
|||
|
// Pass the app's HR from Begin call to the channel.
|
|||
|
(*pfnDcomChannelSetHResult)( pRpcMsg,
|
|||
|
NULL, // reserved
|
|||
|
(HRESULT) ReturnValue);
|
|||
|
}
|
|||
|
|
|||
|
// We are discarding the return value as it is not the real one.
|
|||
|
}
|
|||
|
}
|
|||
|
RpcExcept( 1 )
|
|||
|
{
|
|||
|
fErrorInInvoke = TRUE;
|
|||
|
|
|||
|
pAsyncMsg->Flags.ErrorPending = 1;
|
|||
|
pAsyncMsg->ErrorCode = RpcExceptionCode();
|
|||
|
|
|||
|
pAsyncSB->CallState.Flags.BeginError = 1;
|
|||
|
pAsyncSB->CallState.Hr = NdrHrFromWin32Error( RpcExceptionCode());
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
// Done with invoking Begin
|
|||
|
}
|
|||
|
RpcFinally
|
|||
|
{
|
|||
|
if ( !fManagerCodeInvoked )
|
|||
|
{
|
|||
|
// Failed without invoking Begin - return an error. Remember the error.
|
|||
|
|
|||
|
if ( fBadStubDataException )
|
|||
|
pAsyncMsg->ErrorCode = RPC_X_BAD_STUB_DATA;
|
|||
|
|
|||
|
pAsyncSB->CallState.Flags.BeginDone = 1;
|
|||
|
hr = pAsyncSB->CallState.Hr;
|
|||
|
}
|
|||
|
else // fManagerCodeInvoked
|
|||
|
{
|
|||
|
hr = S_OK;
|
|||
|
|
|||
|
if ( fErrorInInvoke )
|
|||
|
hr = pAsyncSB->CallState.Hr;
|
|||
|
}
|
|||
|
}
|
|||
|
RpcEndFinally
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NdrpCloneInOutStubArgs(
|
|||
|
NDR_DCOM_ASYNC_MESSAGE * pAsyncMsg )
|
|||
|
/*
|
|||
|
Walk the second stack looking for an in-out argument.
|
|||
|
For each one, find the corresponding in-out atgument from the first stack
|
|||
|
and clone it to the second stack.
|
|||
|
|
|||
|
Note, we need to do it only on the server side where we preserver the first
|
|||
|
stack, the dispatch buffer and all the arguments from the first stack.
|
|||
|
|
|||
|
On the client, this is the app's task to supply meaningful in-out arguments
|
|||
|
for the second stack.
|
|||
|
*/
|
|||
|
{
|
|||
|
REGISTER_TYPE * pBeginStack = (REGISTER_TYPE *)pAsyncMsg->BeginStack;
|
|||
|
REGISTER_TYPE * pFinishStack = (REGISTER_TYPE *)pAsyncMsg->FinishStack;
|
|||
|
|
|||
|
PPARAM_DESCRIPTION BeginParams = (PPARAM_DESCRIPTION)pAsyncMsg->BeginParams;
|
|||
|
int BeginNumberParams = (int)pAsyncMsg->nBeginParams;
|
|||
|
|
|||
|
PPARAM_DESCRIPTION FinishParams = (PPARAM_DESCRIPTION)pAsyncMsg->FinishParams;
|
|||
|
int FinishNumberParams = pAsyncMsg->nFinishParams;
|
|||
|
|
|||
|
int FirstIO = 0;
|
|||
|
int n;
|
|||
|
|
|||
|
for ( n = 0; n < FinishNumberParams; n++ )
|
|||
|
{
|
|||
|
// Find in-out arg that needs cloning.
|
|||
|
|
|||
|
if ( FinishParams[n].ParamAttr.IsIn &&
|
|||
|
FinishParams[n].ParamAttr.IsOut )
|
|||
|
{
|
|||
|
// Find the first IO on the first stack
|
|||
|
|
|||
|
while ( FirstIO < BeginNumberParams )
|
|||
|
{
|
|||
|
if ( BeginParams[ FirstIO ].ParamAttr.IsIn &&
|
|||
|
BeginParams[ FirstIO ].ParamAttr.IsOut )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
FirstIO++;
|
|||
|
}
|
|||
|
|
|||
|
if ( BeginNumberParams <= FirstIO )
|
|||
|
RpcRaiseException( RPC_S_INTERNAL_ERROR );
|
|||
|
|
|||
|
// Clone it to the second stack
|
|||
|
|
|||
|
pFinishStack[ FinishParams[n].StackOffset / sizeof(REGISTER_TYPE) ] =
|
|||
|
pBeginStack[ BeginParams[ FirstIO ].StackOffset / sizeof(REGISTER_TYPE) ];
|
|||
|
FirstIO++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpCompleteDcomAsyncStubCall(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description :
|
|||
|
|
|||
|
Complete an async call on the server side.
|
|||
|
|
|||
|
Arguments :
|
|||
|
|
|||
|
AsyncHandle - raw or object handle (if pointer) as appropriate,
|
|||
|
pAsyncMsg - pointer to async msg structure,
|
|||
|
pReturnValue - from the user to pass back to caller.
|
|||
|
|
|||
|
Return :
|
|||
|
|
|||
|
Status of S_OK.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
|
|||
|
PMIDL_SERVER_INFO pServerInfo;
|
|||
|
PMIDL_STUB_DESC pStubDesc; // should be the same
|
|||
|
const SERVER_ROUTINE * DispatchTable; // should be the same
|
|||
|
unsigned long ProcNum; // should be 1+
|
|||
|
|
|||
|
ushort FormatOffset;
|
|||
|
PFORMAT_STRING pFormat;
|
|||
|
PFORMAT_STRING pFormatParam;
|
|||
|
|
|||
|
RPC_MESSAGE * pRpcMsg;
|
|||
|
MIDL_STUB_MESSAGE * pStubMsg;
|
|||
|
|
|||
|
INTERPRETER_FLAGS OldOiFlags; // Finish flags
|
|||
|
INTERPRETER_OPT_FLAGS NewOiFlags; // Finish flags
|
|||
|
PPARAM_DESCRIPTION Params; // Finish params
|
|||
|
uchar * pArgBuffer; // new stack
|
|||
|
|
|||
|
// MZ, BUG BUG, Fix after ship
|
|||
|
// ulong * pdwStubPhase;
|
|||
|
|
|||
|
uchar * pArg;
|
|||
|
|
|||
|
long NumberParams;
|
|||
|
long n;
|
|||
|
PNDR_DCOM_OI2_PROC_HEADER pProcHeader;
|
|||
|
PNDR_PROC_HEADER_EXTS pHeaderExts = 0;
|
|||
|
|
|||
|
IUnknown * pSrvObj;
|
|||
|
CInterfaceStubVtbl * pStubVTable;
|
|||
|
void * pThis;
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
const IID * piid; // should be the same
|
|||
|
|
|||
|
BOOL fManagerCodeInvoked = FALSE;
|
|||
|
BOOL fErrorInInvoke = FALSE;
|
|||
|
RPC_STATUS ExceptionCode = 0;
|
|||
|
boolean fParamsFreed = FALSE;
|
|||
|
NDR_PROC_CONTEXT * pContext = NULL;
|
|||
|
|
|||
|
// We validated both the stub and the async context in the signal call.
|
|||
|
|
|||
|
// We validated the pAsyncSB in the Signal call.
|
|||
|
// Do additional checks.
|
|||
|
|
|||
|
pAsyncMsg = (PNDR_DCOM_ASYNC_MESSAGE)pAsyncSB->CallState.pAsyncMsg;
|
|||
|
pThis = pAsyncMsg->pThis;
|
|||
|
|
|||
|
// See if channel calls on the right stub
|
|||
|
if ( & pAsyncSB->lpVtbl != pThis)
|
|||
|
return E_INVALIDARG;
|
|||
|
|
|||
|
|
|||
|
pRpcMsg = & pAsyncMsg->RpcMsg;
|
|||
|
pStubMsg = & pAsyncMsg->StubMsg;
|
|||
|
// We have preserved the sync proc num that the channel used.
|
|||
|
// We need only async proc num at the engine level.
|
|||
|
//
|
|||
|
|
|||
|
ProcNum = pRpcMsg->ProcNum;
|
|||
|
ProcNum = 2 * ProcNum - 3 + 1; // Finish method #
|
|||
|
|
|||
|
pSrvObj = (IUnknown *)((CStdStubBuffer *)pThis)->pvServerObject;
|
|||
|
DispatchTable = (SERVER_ROUTINE *)pSrvObj->lpVtbl;
|
|||
|
|
|||
|
pStubVTable = (CInterfaceStubVtbl *)
|
|||
|
(*((uchar **)pThis) - sizeof(CInterfaceStubHeader));
|
|||
|
|
|||
|
piid = pStubVTable->header.piid;
|
|||
|
pServerInfo = (PMIDL_SERVER_INFO) pStubVTable->header.pServerInfo;
|
|||
|
|
|||
|
pStubDesc = pServerInfo->pStubDesc;
|
|||
|
FormatOffset = pServerInfo->FmtStringOffset[ ProcNum ];
|
|||
|
pFormat = &((pServerInfo->ProcString)[ FormatOffset ]);
|
|||
|
|
|||
|
// The proc header has a fixed layout now.
|
|||
|
|
|||
|
pProcHeader = (PNDR_DCOM_OI2_PROC_HEADER) pFormat;
|
|||
|
|
|||
|
// Validate and setup for finish.
|
|||
|
|
|||
|
hr = NdrpSetupFinishStubCall( pAsyncSB,
|
|||
|
pProcHeader->StackSize,
|
|||
|
*piid );
|
|||
|
if ( hr )
|
|||
|
return hr;
|
|||
|
|
|||
|
// The arg buffer is zeroed out already. Note, this is the second stack.
|
|||
|
|
|||
|
pContext = &pAsyncMsg->ProcContext;
|
|||
|
pArgBuffer = pContext->StartofStack;
|
|||
|
pStubMsg->StackTop = pArgBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Get new interpreter info.
|
|||
|
//
|
|||
|
OldOiFlags = pProcHeader->OldOiFlags;
|
|||
|
NewOiFlags = pProcHeader->Oi2Flags;
|
|||
|
NumberParams = pProcHeader->NumberParams;
|
|||
|
|
|||
|
Params = (PPARAM_DESCRIPTION)(pFormat + sizeof(NDR_DCOM_OI2_PROC_HEADER));
|
|||
|
|
|||
|
if ( NewOiFlags.HasExtensions )
|
|||
|
{
|
|||
|
pHeaderExts = (NDR_PROC_HEADER_EXTS *)Params;
|
|||
|
Params = (PPARAM_DESCRIPTION)((uchar*)Params + pHeaderExts->Size);
|
|||
|
}
|
|||
|
|
|||
|
pAsyncMsg->nFinishParams = pContext->NumberParams = NumberParams;
|
|||
|
pAsyncMsg->FinishParams = pContext->Params = Params;
|
|||
|
pContext->DceTypeFormatString = pStubDesc->pFormatTypes;
|
|||
|
pStubMsg->pContext = pContext;
|
|||
|
|
|||
|
// Wrap the unmarshalling, mgr call and marshalling in the try block of
|
|||
|
// a try-finally. Put the free phase in the associated finally block.
|
|||
|
//
|
|||
|
RpcTryFinally
|
|||
|
{
|
|||
|
if ( pAsyncMsg->Flags.ErrorPending )
|
|||
|
RpcRaiseException( pAsyncMsg->ErrorCode );
|
|||
|
|
|||
|
// Initialize the args of the new stack.
|
|||
|
|
|||
|
// OLE: put pThis in first dword of stack.
|
|||
|
//
|
|||
|
((void **)pArgBuffer)[0] = ((CStdStubBuffer *)pThis)->pvServerObject;
|
|||
|
|
|||
|
//
|
|||
|
// Do [out] initialization before invoking Finish
|
|||
|
//
|
|||
|
|
|||
|
NdrpCloneInOutStubArgs( pAsyncMsg );
|
|||
|
NdrpServerOutInit( pStubMsg );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// OLE interfaces use pdwStubPhase in the exception filter.
|
|||
|
// See CStdStubBuffer_Invoke in stub.c.
|
|||
|
//
|
|||
|
|
|||
|
// MZ, BUG BUG, fix after ship
|
|||
|
// *pdwStubPhase = STUB_CALL_SERVER;
|
|||
|
|
|||
|
// We need to catch exception in the manager code separately
|
|||
|
// as the model implies that there will be no other call from
|
|||
|
// the server app to clean up.
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
//
|
|||
|
// Check for a thunk. Compiler does all the setup for us.
|
|||
|
//
|
|||
|
if ( pServerInfo->ThunkTable && pServerInfo->ThunkTable[ProcNum] )
|
|||
|
{
|
|||
|
fManagerCodeInvoked = TRUE;
|
|||
|
pServerInfo->ThunkTable[ProcNum]( pStubMsg );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Note that this ArgNum is not the number of arguments declared
|
|||
|
// in the function we called, but really the number of
|
|||
|
// REGISTER_TYPEs occupied by the arguments to a function.
|
|||
|
//
|
|||
|
long ArgNum;
|
|||
|
MANAGER_FUNCTION pFunc;
|
|||
|
REGISTER_TYPE ReturnValue;
|
|||
|
|
|||
|
pFunc = (MANAGER_FUNCTION) DispatchTable[ProcNum];
|
|||
|
ArgNum = (long)pProcHeader->StackSize / sizeof(REGISTER_TYPE);
|
|||
|
|
|||
|
//
|
|||
|
// The StackSize includes the size of the return. If we want
|
|||
|
// just the number of REGISTER_TYPES, then ArgNum must be reduced
|
|||
|
// by 1 when there is a return value AND the current ArgNum count
|
|||
|
// is greater than 0.
|
|||
|
//
|
|||
|
if ( ArgNum && NewOiFlags.HasReturn )
|
|||
|
ArgNum--;
|
|||
|
|
|||
|
fManagerCodeInvoked = TRUE;
|
|||
|
ReturnValue = Invoke( pFunc,
|
|||
|
(REGISTER_TYPE *)pArgBuffer,
|
|||
|
#if defined(_IA64_)
|
|||
|
NewOiFlags.HasExtensions ? ((PNDR_PROC_HEADER_EXTS64)pHeaderExts)->FloatArgMask
|
|||
|
: 0,
|
|||
|
#endif
|
|||
|
ArgNum);
|
|||
|
|
|||
|
// This is the return value that should be marshaled back.
|
|||
|
if ( NewOiFlags.HasReturn )
|
|||
|
{
|
|||
|
((REGISTER_TYPE *)pArgBuffer)[ArgNum] = ReturnValue;
|
|||
|
// Pass the app's HR to the channel.
|
|||
|
(*pfnDcomChannelSetHResult)( pRpcMsg,
|
|||
|
NULL, // reserved
|
|||
|
(HRESULT) ReturnValue);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
RpcExcept( 1 )
|
|||
|
{
|
|||
|
pAsyncMsg->Flags.ErrorPending = 1;
|
|||
|
|
|||
|
pAsyncMsg->ErrorCode = RpcExceptionCode();
|
|||
|
fErrorInInvoke = TRUE;
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
// Done with invoking Finish
|
|||
|
|
|||
|
if ( pAsyncMsg->Flags.ErrorPending )
|
|||
|
RpcRaiseException( pAsyncMsg->ErrorCode );
|
|||
|
|
|||
|
//
|
|||
|
// Buffer size pass.
|
|||
|
//
|
|||
|
pStubMsg->BufferLength = pProcHeader->ServerBufferSize;
|
|||
|
|
|||
|
if ( NewOiFlags.ServerMustSize )
|
|||
|
{
|
|||
|
NdrpSizing( pStubMsg,
|
|||
|
FALSE ); // IsClient
|
|||
|
}
|
|||
|
|
|||
|
// Get buffer.
|
|||
|
|
|||
|
NdrStubGetBuffer( (IRpcStubBuffer*)pAsyncMsg->pThis,
|
|||
|
pStubMsg->pRpcChannelBuffer,
|
|||
|
pStubMsg );
|
|||
|
|
|||
|
//
|
|||
|
// Marshall pass.
|
|||
|
//
|
|||
|
NdrpServerMarshal( pStubMsg,
|
|||
|
TRUE ); // IsObject
|
|||
|
|
|||
|
|
|||
|
if ( pRpcMsg->BufferLength <
|
|||
|
(uint)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer) )
|
|||
|
{
|
|||
|
NDR_ASSERT( 0, "NdrStubCall2 marshal: buffer overflow!" );
|
|||
|
RpcRaiseException( RPC_X_BAD_STUB_DATA );
|
|||
|
}
|
|||
|
|
|||
|
pRpcMsg->BufferLength = (ulong)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer);
|
|||
|
|
|||
|
// We don't drop to the runtime like for synchronous calls,
|
|||
|
// we send the last buffer explicitly.
|
|||
|
|
|||
|
fParamsFreed = TRUE;
|
|||
|
// see comment on async.cxx on why we call this twice.
|
|||
|
|
|||
|
NdrpAsyncDCOMFreeParams( pAsyncMsg );
|
|||
|
|
|||
|
NdrpDcomAsyncSend( pStubMsg,
|
|||
|
0 ); // server doesn't pass pSynchronize back to channel.
|
|||
|
}
|
|||
|
RpcFinally
|
|||
|
{
|
|||
|
// Don't free parameters if we died because of bad stub data in unmarshaling.
|
|||
|
|
|||
|
if ( ! pAsyncMsg->Flags.BadStubData && !fParamsFreed)
|
|||
|
{
|
|||
|
|
|||
|
NdrpAsyncDCOMFreeParams( pAsyncMsg );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( pAsyncMsg->Flags.ErrorPending )
|
|||
|
hr = NdrHrFromWin32Error( pAsyncMsg->ErrorCode );
|
|||
|
else
|
|||
|
hr = S_OK;
|
|||
|
|
|||
|
// If we are here, error or not, it means that we can (and need to) dispose of
|
|||
|
// the async context information
|
|||
|
|
|||
|
NdrpAsyncStubMsgDestructor( pAsyncSB );
|
|||
|
|
|||
|
// The engine never addrefs or releases the call object.
|
|||
|
}
|
|||
|
RpcEndFinally
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncProxyMsgConstructor(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB )
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncPB->CallState;
|
|||
|
|
|||
|
pCallState->Lock = 0;
|
|||
|
pCallState->Signature = NDR_ASYNC_PROXY_SIGNATURE;
|
|||
|
pCallState->pAsyncMsg = 0;
|
|||
|
*((long*)&pCallState->Flags) = 0;
|
|||
|
pCallState->Hr = 0;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncStubMsgConstructor(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB )
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncSB->CallState;
|
|||
|
|
|||
|
pCallState->Lock = 0;
|
|||
|
pCallState->Signature = NDR_ASYNC_STUB_SIGNATURE;
|
|||
|
pCallState->pAsyncMsg = 0;
|
|||
|
*((long*)&pCallState->Flags) = 0;
|
|||
|
pCallState->Hr = 0;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncProxyMsgDestructor(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB )
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncPB->CallState;
|
|||
|
|
|||
|
if ( pCallState->pAsyncMsg )
|
|||
|
{
|
|||
|
NdrpFreeDcomAsyncMsg( (PNDR_DCOM_ASYNC_MESSAGE)pCallState->pAsyncMsg );
|
|||
|
pCallState->pAsyncMsg = 0;
|
|||
|
}
|
|||
|
*((long*)&pCallState->Flags) = 0;
|
|||
|
pCallState->Hr = 0;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncStubMsgDestructor(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB )
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncSB->CallState;
|
|||
|
|
|||
|
if ( pCallState->pAsyncMsg )
|
|||
|
{
|
|||
|
NdrpFreeDcomAsyncMsg( (PNDR_DCOM_ASYNC_MESSAGE)pCallState->pAsyncMsg );
|
|||
|
pCallState->pAsyncMsg = 0;
|
|||
|
}
|
|||
|
*((long*)&pCallState->Flags) = 0;
|
|||
|
pCallState->Hr = 0;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpValidateAsyncProxyCall(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB
|
|||
|
)
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncPB->CallState;
|
|||
|
|
|||
|
if ( pCallState->Signature != NDR_ASYNC_PROXY_SIGNATURE )
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
RpcEndExcept;
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpValidateAsyncStubCall(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB
|
|||
|
)
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
NdrDcomAsyncCallState * pCallState = & pAsyncSB->CallState;
|
|||
|
|
|||
|
if ( pCallState->Signature != NDR_ASYNC_STUB_SIGNATURE )
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
RpcEndExcept;
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpValidateDcomAsyncMsg(
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg )
|
|||
|
{
|
|||
|
HRESULT hr = RPC_S_OK;
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
if ( pAsyncMsg->Signature != NDR_DCOM_ASYNC_SIGNATURE ||
|
|||
|
pAsyncMsg->Version != NDR_DCOM_ASYNC_VERSION )
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
hr = E_INVALIDARG;
|
|||
|
}
|
|||
|
RpcEndExcept;
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpSetupBeginClientCall(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB,
|
|||
|
void * StartofStack,
|
|||
|
unsigned short StackSize,
|
|||
|
REFIID riid )
|
|||
|
/*
|
|||
|
This method creates and initializes async msg.
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
hr = NdrpValidateAsyncProxyCall( pAsyncPB );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
if ( pAsyncPB->CallState.pAsyncMsg != 0 ||
|
|||
|
pAsyncPB->CallState.Flags.BeginStarted )
|
|||
|
return E_FAIL;
|
|||
|
|
|||
|
// Do this first to simplify error conditions.
|
|||
|
|
|||
|
pAsyncMsg = (NDR_DCOM_ASYNC_MESSAGE*)
|
|||
|
I_RpcBCacheAllocate( sizeof(NDR_DCOM_ASYNC_MESSAGE) +
|
|||
|
StackSize + NDR_ASYNC_GUARD_SIZE );
|
|||
|
if ( ! pAsyncMsg )
|
|||
|
{
|
|||
|
NdrpAsyncProxySignal( pAsyncPB );
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
// Initialize the async message properly
|
|||
|
|
|||
|
MIDL_memset( pAsyncMsg, 0x0, sizeof( NDR_DCOM_ASYNC_MESSAGE) );
|
|||
|
|
|||
|
pAsyncMsg->Signature = NDR_DCOM_ASYNC_SIGNATURE;
|
|||
|
pAsyncMsg->Version = NDR_DCOM_ASYNC_VERSION;
|
|||
|
pAsyncMsg->SyntaxType = XFER_SYNTAX_DCE;
|
|||
|
|
|||
|
pAsyncMsg->ProcContext.StartofStack = (uchar *) & pAsyncMsg->AppStack;
|
|||
|
pAsyncMsg->BeginStack = (uchar *) & pAsyncMsg->AppStack;
|
|||
|
pAsyncMsg->BeginStackSize = StackSize;
|
|||
|
pAsyncMsg->StubPhase = NDR_ASYNC_PREP_PHASE;
|
|||
|
|
|||
|
NdrpAllocaInit( &pAsyncMsg->ProcContext.AllocateContext );
|
|||
|
|
|||
|
// Client: copy stack from the app's request call.
|
|||
|
RpcpMemoryCopy( & pAsyncMsg->AppStack, StartofStack, StackSize );
|
|||
|
|
|||
|
MIDL_memset( ((char *)& pAsyncMsg->AppStack) + StackSize,
|
|||
|
0x71,
|
|||
|
NDR_ASYNC_GUARD_SIZE );
|
|||
|
|
|||
|
pAsyncMsg->pAsyncPB = pAsyncPB;
|
|||
|
pAsyncPB->CallState.Flags.BeginStarted = 1;
|
|||
|
pAsyncPB->CallState.pAsyncMsg = pAsyncMsg;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpSetupFinishClientCall(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB,
|
|||
|
void * StartofStack,
|
|||
|
unsigned short StackSize,
|
|||
|
REFIID riid,
|
|||
|
unsigned long FinishProcNum )
|
|||
|
/*
|
|||
|
This method creates and initializes async msg.
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
hr = NdrpValidateAsyncProxyCall( pAsyncPB );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
if ( !pAsyncPB->CallState.Flags.BeginStarted ||
|
|||
|
!pAsyncPB->CallState.Flags.BeginDone ||
|
|||
|
pAsyncPB->CallState.Flags.FinishStarted )
|
|||
|
return E_FAIL;
|
|||
|
|
|||
|
pAsyncMsg = (PNDR_DCOM_ASYNC_MESSAGE)pAsyncPB->CallState.pAsyncMsg;
|
|||
|
|
|||
|
hr = NdrpValidateDcomAsyncMsg( pAsyncMsg );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
if ( (FinishProcNum + 3)/2 != (pAsyncMsg->RpcMsg.ProcNum & 0x7fff) )
|
|||
|
return E_FAIL;
|
|||
|
|
|||
|
// Initialize the async message properly
|
|||
|
|
|||
|
pAsyncMsg->ProcContext.StartofStack = (uchar *) StartofStack;
|
|||
|
pAsyncMsg->FinishStack = (uchar *) StartofStack;
|
|||
|
pAsyncMsg->FinishStackSize = StackSize;
|
|||
|
pAsyncMsg->StubPhase = NDR_ASYNC_PREP_PHASE;
|
|||
|
|
|||
|
// Dont allocate or copy the new stack anywhere.
|
|||
|
|
|||
|
pAsyncPB->CallState.Flags.FinishStarted = 1;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpSetupBeginStubCall(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB,
|
|||
|
unsigned short StackSize,
|
|||
|
REFIID riid )
|
|||
|
/*
|
|||
|
This method creates and initializes async msg.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
hr = NdrpValidateAsyncStubCall( pAsyncSB );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
if ( pAsyncSB->CallState.pAsyncMsg != 0 ||
|
|||
|
pAsyncSB->CallState.Flags.BeginStarted )
|
|||
|
hr = E_FAIL;
|
|||
|
else
|
|||
|
{
|
|||
|
pAsyncMsg = (NDR_DCOM_ASYNC_MESSAGE*)
|
|||
|
I_RpcBCacheAllocate( sizeof( NDR_DCOM_ASYNC_MESSAGE) +
|
|||
|
StackSize + NDR_ASYNC_GUARD_SIZE );
|
|||
|
if ( ! pAsyncMsg )
|
|||
|
hr = E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
// The stub never signals.
|
|||
|
|
|||
|
pAsyncSB->CallState.Flags.BeginError = 1;
|
|||
|
pAsyncSB->CallState.Hr = hr;
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
// Initialize the async message properly
|
|||
|
|
|||
|
MIDL_memset( pAsyncMsg, 0x0, sizeof( NDR_DCOM_ASYNC_MESSAGE) );
|
|||
|
|
|||
|
pAsyncMsg->Signature = NDR_DCOM_ASYNC_SIGNATURE;
|
|||
|
pAsyncMsg->Version = NDR_DCOM_ASYNC_VERSION;
|
|||
|
pAsyncMsg->SyntaxType = XFER_SYNTAX_DCE;
|
|||
|
|
|||
|
pAsyncMsg->ProcContext.StartofStack = (uchar *) & pAsyncMsg->AppStack;
|
|||
|
pAsyncMsg->BeginStack = (uchar *) & pAsyncMsg->AppStack;
|
|||
|
pAsyncMsg->BeginStackSize = StackSize;
|
|||
|
pAsyncMsg->StubPhase = STUB_UNMARSHAL;
|
|||
|
pAsyncMsg->StubMsg.pContext = &pAsyncMsg->ProcContext;
|
|||
|
|
|||
|
NdrpAllocaInit( &pAsyncMsg->ProcContext.AllocateContext );
|
|||
|
|
|||
|
// Server: zero out stack for allocs.
|
|||
|
MIDL_memset( & pAsyncMsg->AppStack, 0x0, StackSize );
|
|||
|
|
|||
|
MIDL_memset( ((char *)& pAsyncMsg->AppStack) + StackSize,
|
|||
|
0x71,
|
|||
|
NDR_ASYNC_GUARD_SIZE );
|
|||
|
|
|||
|
pAsyncSB->CallState.pAsyncMsg = pAsyncMsg;
|
|||
|
pAsyncSB->CallState.Flags.BeginStarted = 1;
|
|||
|
pAsyncMsg->pAsyncSB = pAsyncSB;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpSetupFinishStubCall(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB,
|
|||
|
unsigned short StackSize,
|
|||
|
REFIID riid )
|
|||
|
/*
|
|||
|
This method creates and initializes async msg.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg;
|
|||
|
uchar * pFinishStack;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
|
|||
|
hr = NdrpValidateAsyncStubCall( pAsyncSB );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
if ( !pAsyncSB->CallState.Flags.BeginStarted ||
|
|||
|
!pAsyncSB->CallState.Flags.BeginDone ||
|
|||
|
pAsyncSB->CallState.Flags.FinishStarted )
|
|||
|
return E_FAIL;
|
|||
|
|
|||
|
if ( pAsyncSB->CallState.Hr != 0 )
|
|||
|
return pAsyncSB->CallState.Hr;
|
|||
|
|
|||
|
pAsyncMsg = (PNDR_DCOM_ASYNC_MESSAGE)pAsyncSB->CallState.pAsyncMsg;
|
|||
|
|
|||
|
hr = NdrpValidateDcomAsyncMsg( pAsyncMsg );
|
|||
|
if ( ! SUCCEEDED(hr) )
|
|||
|
return hr;
|
|||
|
|
|||
|
// We need to create the second stack for the app invoke.
|
|||
|
// Do this first to simplify error conditions.
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
pFinishStack = (uchar*) AsyncAlloca( pAsyncMsg,
|
|||
|
StackSize + NDR_ASYNC_GUARD_SIZE );
|
|||
|
}
|
|||
|
RpcExcept( 1 )
|
|||
|
{
|
|||
|
NdrpAsyncStubMsgDestructor( pAsyncSB );
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
// Initialize the async message properly
|
|||
|
|
|||
|
pAsyncMsg->ProcContext.StartofStack = (uchar *) pFinishStack;
|
|||
|
pAsyncMsg->FinishStack = (uchar *) pFinishStack;
|
|||
|
pAsyncMsg->FinishStackSize = StackSize;
|
|||
|
pAsyncMsg->StubMsg.pContext = &pAsyncMsg->ProcContext;
|
|||
|
|
|||
|
// Server: zero out stack for allocs.
|
|||
|
MIDL_memset( pFinishStack, 0x0, StackSize );
|
|||
|
|
|||
|
MIDL_memset( (char *)pFinishStack + StackSize,
|
|||
|
0x72,
|
|||
|
NDR_ASYNC_GUARD_SIZE );
|
|||
|
|
|||
|
pAsyncSB->CallState.Flags.FinishStarted = 1;
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncProxySignal(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB )
|
|||
|
{
|
|||
|
ISynchronize * pSynchronize;
|
|||
|
HRESULT hr;
|
|||
|
IUnknown * punkOuter = pAsyncPB->punkOuter;
|
|||
|
|
|||
|
hr = punkOuter->lpVtbl->QueryInterface( punkOuter,
|
|||
|
IID_ISynchronize,
|
|||
|
(void**)&pSynchronize );
|
|||
|
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
pSynchronize->lpVtbl->Signal( pSynchronize );
|
|||
|
pSynchronize->lpVtbl->Release( pSynchronize );
|
|||
|
}
|
|||
|
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
_inline
|
|||
|
HRESULT
|
|||
|
NdrpCallStateLock(
|
|||
|
NdrDcomAsyncCallState * pCallState )
|
|||
|
{
|
|||
|
if ( 0 != InterlockedCompareExchange( (long*)& pCallState->Lock, 1, 0 ) )
|
|||
|
{
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
_inline
|
|||
|
void
|
|||
|
NdrpCallStateUnlock(
|
|||
|
NdrDcomAsyncCallState * pCallState )
|
|||
|
{
|
|||
|
InterlockedDecrement( (long*)& pCallState->Lock );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncProxyLock(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB )
|
|||
|
{
|
|||
|
return NdrpCallStateLock( & pAsyncPB->CallState );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NdrpAsyncProxyUnlock(
|
|||
|
CStdAsyncProxyBuffer * pAsyncPB )
|
|||
|
{
|
|||
|
NdrpCallStateUnlock( & pAsyncPB->CallState );
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncStubLock(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB )
|
|||
|
{
|
|||
|
return NdrpCallStateLock( & pAsyncSB->CallState );
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
NdrpAsyncStubUnlock(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB )
|
|||
|
{
|
|||
|
NdrpCallStateUnlock( & pAsyncSB->CallState );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NdrpFreeDcomAsyncMsg(
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg )
|
|||
|
/*
|
|||
|
This routine would free the AsyncMsg but not the AsyncHandle, as on the server
|
|||
|
the user may need it and on the client it is user's to begin with.
|
|||
|
*/
|
|||
|
{
|
|||
|
if ( pAsyncMsg )
|
|||
|
{
|
|||
|
PMIDL_STUB_MESSAGE pStubMsg = & pAsyncMsg->StubMsg;
|
|||
|
|
|||
|
NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
|
|||
|
|
|||
|
// in NDR64, we are using allocacontext to hold corr info, so we don't
|
|||
|
// want to free it there.
|
|||
|
if ( pAsyncMsg->SyntaxType == XFER_SYNTAX_DCE )
|
|||
|
NdrCorrelationFree( pStubMsg );
|
|||
|
|
|||
|
// Free the RPC buffer.
|
|||
|
|
|||
|
if ( pStubMsg->IsClient )
|
|||
|
{
|
|||
|
if ( ! pAsyncMsg->Flags.RuntimeCleanedUp )
|
|||
|
{
|
|||
|
void * pThis = *(void **)pAsyncMsg->ProcContext.StartofStack;
|
|||
|
|
|||
|
NdrProxyFreeBuffer( pThis, pStubMsg );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NdrpAllocaDestroy( &pAsyncMsg->ProcContext.AllocateContext );
|
|||
|
|
|||
|
// Prevent reusing of a handle that has been freed;
|
|||
|
pAsyncMsg->Signature = NDR_FREED_ASYNC_SIGNATURE;
|
|||
|
|
|||
|
I_RpcBCacheFree( pAsyncMsg );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
NdrpDcomAsyncSend(
|
|||
|
PMIDL_STUB_MESSAGE pStubMsg,
|
|||
|
ISynchronize * pSynchronize )
|
|||
|
/*
|
|||
|
Call the channel to send.
|
|||
|
On the client, pass the app's pSynchronize to it, such that channel can signal
|
|||
|
the app.
|
|||
|
On the server, pass NULL instead of a pSynchronize.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
BOOL fSendCalled = FALSE;
|
|||
|
|
|||
|
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
|||
|
|
|||
|
if ( pStubMsg->pRpcChannelBuffer )
|
|||
|
{
|
|||
|
IAsyncRpcChannelBuffer * pAsChannel;
|
|||
|
IRpcChannelBuffer * pChannel = (IRpcChannelBuffer *)
|
|||
|
pStubMsg->pRpcChannelBuffer;
|
|||
|
|
|||
|
hr = pChannel->lpVtbl->QueryInterface( pChannel,
|
|||
|
IID_IAsyncRpcChannelBuffer,
|
|||
|
(void**)& pAsChannel );
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
fSendCalled = TRUE;
|
|||
|
hr = pAsChannel->lpVtbl->Send( pAsChannel,
|
|||
|
(RPCOLEMESSAGE *)pRpcMsg,
|
|||
|
pSynchronize,
|
|||
|
(ulong*)& Status );
|
|||
|
|
|||
|
pAsChannel->lpVtbl->Release( pAsChannel );
|
|||
|
|
|||
|
// The channel never returns this code now for new async.
|
|||
|
NDR_ASSERT( Status != RPC_S_SEND_INCOMPLETE, "Unexpected channel error" );
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
hr = E_NOINTERFACE;
|
|||
|
|
|||
|
// Alex:
|
|||
|
if ( SUCCEEDED(hr) && Status == RPC_S_OK )
|
|||
|
pStubMsg->fBufferValid = TRUE;
|
|||
|
else
|
|||
|
RpcRaiseException( Status );
|
|||
|
|
|||
|
return fSendCalled;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
NdrpDcomAsyncClientSend(
|
|||
|
PMIDL_STUB_MESSAGE pStubMsg,
|
|||
|
IUnknown * punkOuter )
|
|||
|
/*
|
|||
|
Call the channel to send.
|
|||
|
On the client pass app's pSynchronize to it, such that channel can signal
|
|||
|
the app.
|
|||
|
On the server pass NULL instead of a pSynchronize.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
|
|||
|
HRESULT hr = S_OK;
|
|||
|
BOOL fSendCalled = FALSE;
|
|||
|
|
|||
|
ISynchronize * pSynchronize = 0;
|
|||
|
|
|||
|
// Channel needs somebody to signal to, this will be the app.
|
|||
|
|
|||
|
hr = punkOuter->lpVtbl->QueryInterface( punkOuter,
|
|||
|
IID_ISynchronize,
|
|||
|
(void**) &pSynchronize );
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
fSendCalled = NdrpDcomAsyncSend( pStubMsg, pSynchronize );
|
|||
|
|
|||
|
if ( pSynchronize )
|
|||
|
pSynchronize->lpVtbl->Release( pSynchronize );
|
|||
|
|
|||
|
return fSendCalled;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
NdrDcomAsyncReceive(
|
|||
|
PMIDL_STUB_MESSAGE pStubMsg )
|
|||
|
{
|
|||
|
PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
HRESULT hr;
|
|||
|
|
|||
|
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
|||
|
pRpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;
|
|||
|
|
|||
|
// A complete call.
|
|||
|
|
|||
|
if ( pStubMsg->pRpcChannelBuffer )
|
|||
|
{
|
|||
|
IAsyncRpcChannelBuffer * pAsyncChannel = (IAsyncRpcChannelBuffer *)
|
|||
|
pStubMsg->pRpcChannelBuffer;
|
|||
|
|
|||
|
hr = pAsyncChannel->lpVtbl->Receive( pAsyncChannel,
|
|||
|
(PRPCOLEMESSAGE) pRpcMsg,
|
|||
|
(unsigned long *)&Status );
|
|||
|
}
|
|||
|
|
|||
|
if ( Status )
|
|||
|
{
|
|||
|
// No pending, the call would have blocked, real bug happened.
|
|||
|
|
|||
|
if ( pStubMsg->pAsyncMsg )
|
|||
|
((PNDR_DCOM_ASYNC_MESSAGE)pStubMsg->pAsyncMsg)->Flags.RuntimeCleanedUp = 1;
|
|||
|
|
|||
|
RpcRaiseException(Status);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pStubMsg->Buffer = (uchar*) pRpcMsg->Buffer;
|
|||
|
|
|||
|
pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer;
|
|||
|
pStubMsg->BufferEnd = (uchar*)pRpcMsg->Buffer + pRpcMsg->BufferLength;
|
|||
|
pStubMsg->fBufferValid = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
HRESULT
|
|||
|
Ndr64pCompleteDcomAsyncStubCall(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB
|
|||
|
);
|
|||
|
|
|||
|
HRESULT
|
|||
|
NdrpAsyncStubSignal(
|
|||
|
CStdAsyncStubBuffer * pAsyncSB )
|
|||
|
/*
|
|||
|
Signal on the async stub object:
|
|||
|
The channel signals that the Finish call should be executed.
|
|||
|
|
|||
|
See if the stub object is active (or find one that is).
|
|||
|
If the stub object is not active then the call fails.
|
|||
|
*/
|
|||
|
{
|
|||
|
HRESULT hr = S_OK;
|
|||
|
BOOL fFoundActiveCall = FALSE;
|
|||
|
|
|||
|
while ( SUCCEEDED(hr) && ! fFoundActiveCall )
|
|||
|
{
|
|||
|
hr = NdrpValidateAsyncStubCall( pAsyncSB );
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
if ( pAsyncSB->CallState.Flags.BeginStarted )
|
|||
|
{
|
|||
|
fFoundActiveCall = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Switch to the base interface call object. In case of
|
|||
|
// delegation one of the base interface objects would be active.
|
|||
|
|
|||
|
IRpcStubBuffer * pBaseStubBuffer = pAsyncSB->pBaseStubBuffer;
|
|||
|
|
|||
|
if ( pBaseStubBuffer )
|
|||
|
{
|
|||
|
pAsyncSB = (CStdAsyncStubBuffer *) ((uchar *)pBaseStubBuffer
|
|||
|
- offsetof(CStdAsyncStubBuffer,lpVtbl));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// None of the stubs active and a signal came.
|
|||
|
hr = E_FAIL;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
PNDR_DCOM_ASYNC_MESSAGE pAsyncMsg =
|
|||
|
(PNDR_DCOM_ASYNC_MESSAGE)pAsyncSB->CallState.pAsyncMsg;
|
|||
|
hr = NdrpValidateDcomAsyncMsg( pAsyncMsg );
|
|||
|
if ( SUCCEEDED(hr) )
|
|||
|
{
|
|||
|
#if defined(BUILD_NDR64)
|
|||
|
if ( pAsyncMsg->SyntaxType == XFER_SYNTAX_DCE )
|
|||
|
hr = NdrpCompleteDcomAsyncStubCall( pAsyncSB );
|
|||
|
else
|
|||
|
hr = Ndr64pCompleteDcomAsyncStubCall( pAsyncSB );
|
|||
|
#else
|
|||
|
hr = NdrpCompleteDcomAsyncStubCall( pAsyncSB );
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
return hr;
|
|||
|
}
|