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.
2957 lines
83 KiB
2957 lines
83 KiB
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
procgen.cxx
|
|
|
|
Abstract:
|
|
|
|
code generation for procedures.
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
History:
|
|
|
|
Aug-15-1993 VibhasC Created.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
/****************************************************************************
|
|
* include files
|
|
***************************************************************************/
|
|
#include "becls.hxx"
|
|
#pragma hdrstop
|
|
|
|
/****************************************************************************
|
|
* externs
|
|
***************************************************************************/
|
|
extern CMD_ARG * pCommand;
|
|
void GenCorrInit( CCB* );
|
|
void GenCorrPassFree( CCB*, char* );
|
|
|
|
/****************************************************************************/
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenClientStub(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate client stub.
|
|
|
|
Arguments:
|
|
|
|
pCCB - pointer to code generation control block.
|
|
|
|
|
|
Return Value:
|
|
|
|
A status of the code generation.
|
|
|
|
Notes:
|
|
|
|
Set up local variables, parameters etc.
|
|
Perform buffer size and marshalling analysis.
|
|
Generate the stub.
|
|
|
|
|
|
The strategy for binding is now different than the old stubs. The actual
|
|
binding is performed AFTER the sizing is performed, right at the first
|
|
get buffer call. This allows us to combine the message init and the call
|
|
to get buffer and binding into one single call to an ndr routine.
|
|
Significant code / time savings.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ANALYSIS_INFO Analysis;
|
|
BOOL fHasExceptionHandler = FALSE;
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
// [nocode] procs get no client side stub; although they do get a
|
|
// server side stub
|
|
if ( IsNoCode() )
|
|
return CG_OK;
|
|
|
|
// call_as procs need additional prototypes
|
|
if ( pCallAsName )
|
|
pCCB->RegisterCallAsRoutine( (node_proc *)GetType() );
|
|
|
|
//
|
|
// Set the CCB code generation side.
|
|
//
|
|
pCCB->SetCodeGenSide( CGSIDE_CLIENT );
|
|
pCCB->SetCodeGenPhase( CGPHASE_MARSHALL );
|
|
|
|
//
|
|
// Change to -Os if needed because of number of param and/or stack size.
|
|
//
|
|
(void) MustUseSingleEngineCall( pCCB );
|
|
pCCB->SetOptimOption( GetOptimizationFlags() );
|
|
|
|
Analysis.SetCurrentSide( C_SIDE );
|
|
Analysis.SetOptimOption( pCCB->GetOptimOption() );
|
|
Analysis.SetMode( pCCB->GetMode() );
|
|
Analysis.SetRpcSSSwitchSet( (unsigned long)pCCB->IsRpcSSSwitchSet() );
|
|
|
|
// Declare pre-allocated resources. All params are registered as resources,
|
|
// The standard local variables : an rpc message and the stub message are
|
|
// also set up local variables.
|
|
|
|
C_PreAllocateResources( &Analysis );
|
|
|
|
// Set current phase. Perform buffer size, binding and marshalling analysis.
|
|
// The binding analysis usually sets up resources needed for binding.
|
|
|
|
Analysis.SetCurrentPhase( ANA_PHASE_CLIENT_MARSHALL );
|
|
|
|
C_BindingAnalysis( &Analysis );
|
|
MarshallAnalysis( &Analysis );
|
|
|
|
// Perform analysis to check if anything needs to be done for ref
|
|
// pointer checks. This is especially needed for arrays of ref pointers
|
|
// where we need to declare indexes for each array dimension.
|
|
|
|
RefCheckAnalysis( &Analysis );
|
|
|
|
// Perform the unmarshalling analysis. This allows the cg nodes to set
|
|
// up for unmarshall, figure out local variables needed if any.
|
|
|
|
Analysis.SetCurrentPhase( ANA_PHASE_CLIENT_UNMARSHALL );
|
|
UnMarshallAnalysis( &Analysis );
|
|
|
|
// Perform the Out Local analysis even on the client side, so the engine
|
|
// format string generation will get information if the pointer is
|
|
// allocated on stack. One the client side this call will NOT actually
|
|
// allocate a resource.
|
|
|
|
S_OutLocalAnalysis( &Analysis );
|
|
|
|
// Perform this analysis on the client side so the format string is
|
|
// correct for server. It is needed for -Oi RpcSs flag generation.
|
|
|
|
RpcSsPackageAnalysis( &Analysis );
|
|
|
|
// Find out which alloc and free routines should be put in the stub
|
|
// descriptor.
|
|
|
|
PNAME AllocRoutineName, FreeRoutineName;
|
|
|
|
GetCorrectAllocFreeRoutines( pCCB,
|
|
FALSE, //client
|
|
& AllocRoutineName,
|
|
& FreeRoutineName );
|
|
|
|
|
|
// Init the code gen. controller block for a new procedure. The resource
|
|
// dictionary data base is handed over to the code generation controller
|
|
// for use.
|
|
|
|
pCCB->InitForNewProc(
|
|
GetProcNum(),
|
|
(RPC_FLAGS) 0, // rpc flags
|
|
AllocRoutineName,
|
|
FreeRoutineName,
|
|
Analysis.GetResDictDatabase() // resource dict.
|
|
);
|
|
|
|
// If the single engine call is to be used, send message to the ndr
|
|
// code generator.
|
|
|
|
if ( MustUseSingleEngineCall( pCCB ) )
|
|
{
|
|
if ( IsObject() )
|
|
{
|
|
//
|
|
// Non-call_as object proxies are now stubless.
|
|
//
|
|
|
|
if (((CG_OBJECT_PROC *)this)->IsStublessProxy())
|
|
return CG_OK;
|
|
|
|
((CG_OBJECT_PROC *)this)->Out_ProxyFunctionPrototype(pCCB,0);
|
|
pStream->WriteOnNewLine( "{" );
|
|
pStream->NewLine();
|
|
}
|
|
else
|
|
{
|
|
// Generate the function header.
|
|
Out_ClientProcedureProlog( pCCB, GetType() );
|
|
|
|
Out_IndentInc( pCCB );
|
|
pStream->NewLine();
|
|
}
|
|
|
|
GenNdrSingleClientCall( pCCB );
|
|
|
|
Out_IndentDec( pCCB );
|
|
Out_ProcClosingBrace( pCCB );
|
|
|
|
// All done.
|
|
return CG_OK;
|
|
}
|
|
|
|
pCCB->SetCGNodeContext( this );
|
|
|
|
MIDL_ASSERT( pCommand->IsNDRRun() || pCommand->IsNDR64Run() );
|
|
|
|
//
|
|
// Always create the format string for the proc.
|
|
//
|
|
if ( pCommand->IsNDRRun() )
|
|
{
|
|
GenNdrFormat( pCCB );
|
|
}
|
|
else
|
|
{
|
|
pCCB->GetNdr64Format()->Generate( this );
|
|
}
|
|
|
|
// Generate the prolog, the sizing code. Then once the length has been
|
|
// calculated, go ahead and perform the binding using our ndr routines.
|
|
// The call to the ndr routine returns a buffer pointer ready for
|
|
// marshalling.
|
|
|
|
C_GenProlog( pCCB );
|
|
|
|
if ( ( fHasExceptionHandler = ( HasStatuses() || IsObject() ) ) == TRUE )
|
|
{
|
|
Out_RpcTryExcept( pCCB );
|
|
}
|
|
|
|
if ( HasFullPtr() )
|
|
Out_FullPointerInit( pCCB );
|
|
|
|
// Generate the null ref check code.
|
|
// For object interfaces we need to generate a call to initialize proxy
|
|
// first as we won't be able to walk parameters later for cleanup.
|
|
// For raw interfaces we don't ned to move initialization call
|
|
// as we don't have the walk problem.
|
|
|
|
if ( IsObject() )
|
|
C_GenBind( pCCB );
|
|
|
|
if( pCCB->MustCheckRef() )
|
|
GenRefChecks( pCCB );
|
|
|
|
Out_RpcTryFinally( pCCB);
|
|
|
|
if ( !IsObject() )
|
|
C_GenBind( pCCB );
|
|
|
|
// generate NdrCorrelationInitialize( _StubMsg, _NdrCorrCache, _NdrCorrCacheSize, _NdrCorrFlags );
|
|
// normally, /deny causes a switch to /Oicf. This code will be executed when a
|
|
// a switch to from /Os to /Oicf is not posible
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrInit( pCCB );
|
|
}
|
|
|
|
// If the rpc ss package is to be enabled, do so.
|
|
// It would need to be enabled explicitely on the client side when
|
|
// in non-osf mode, with the attribute on the operation AND
|
|
// - the routine is a callback,
|
|
// - the routine is not a callback and the interface doesn't
|
|
// have the attribute (if it does, we optimized via stub descr.)
|
|
|
|
if( pCCB->GetMode() && MustInvokeRpcSSAllocate()
|
|
&&
|
|
( GetCGID() == ID_CG_CALLBACK_PROC ||
|
|
GetCGID() != ID_CG_CALLBACK_PROC &&
|
|
! pCCB->GetInterfaceCG()->IsAllRpcSS())
|
|
)
|
|
{
|
|
Out_RpcSSSetClientToOsf( pCCB );
|
|
}
|
|
|
|
GenSizing( pCCB );
|
|
|
|
GenMarshall( pCCB );
|
|
|
|
// Generate the send receive.
|
|
|
|
C_GenSendReceive( pCCB );
|
|
|
|
// Before Win2000 Ndr<whatetver>SendReceive didn't set the BufferStart
|
|
// and BufferEnd fields. Do it now.
|
|
|
|
pStream->WriteOnNewLine( "_StubMsg.BufferStart = (unsigned char *) _RpcMessage.Buffer; ");
|
|
pStream->WriteOnNewLine( "_StubMsg.BufferEnd = _StubMsg.BufferStart + _RpcMessage.BufferLength;" );
|
|
pStream->NewLine();
|
|
|
|
pCCB->SetCodeGenPhase( CGPHASE_UNMARSHALL );
|
|
GenUnMarshall( pCCB );
|
|
|
|
// generate NdrCorrelationPass( _StubMsg );
|
|
// normally, /deny causes a switch to /Oicf. This code will be executed when a
|
|
// a switch to from /Os to /Oicf is not posible
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrPassFree( pCCB, CSTUB_CORR_PASS_RTN_NAME );
|
|
}
|
|
|
|
Out_RpcFinally( pCCB );
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrPassFree( pCCB, CSTUB_CORR_FREE_RTN_NAME );
|
|
}
|
|
if ( HasFullPtr() )
|
|
Out_FullPointerFree( pCCB );
|
|
C_GenFreeBuffer( pCCB );
|
|
C_GenUnBind( pCCB );
|
|
Out_RpcEndFinally( pCCB );
|
|
|
|
if( fHasExceptionHandler )
|
|
{
|
|
|
|
if(IsObject())
|
|
{
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
pStream->NewLine();
|
|
pStream->Write('}');
|
|
pStream->IndentDec();
|
|
pStream->NewLine();
|
|
pStream->Write( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)" );
|
|
pStream->IndentInc();
|
|
pStream->NewLine();
|
|
pStream->Write( '{' );
|
|
}
|
|
else
|
|
{
|
|
Out_RpcExcept( pCCB, "1" );
|
|
}
|
|
|
|
if(ReturnsHRESULT())
|
|
{
|
|
C_GenClearOutParams( pCCB );
|
|
C_GenMapHRESULT( pCCB );
|
|
}
|
|
else if( HasStatuses() )
|
|
{
|
|
C_GenMapCommAndFaultStatus( pCCB );
|
|
}
|
|
else
|
|
{
|
|
Out_RaiseException( pCCB, "RpcExceptionCode()" );
|
|
}
|
|
|
|
Out_RpcEndExcept( pCCB );
|
|
}
|
|
// All done, emit the final closed curly and we're done.
|
|
GenEpilog( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenMapCommAndFaultStatus(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pTemp = 0;
|
|
CG_NDR * pComm = 0;
|
|
CG_NDR * pFault = 0;
|
|
CG_NDR * pRT;
|
|
int i = 0;
|
|
expr_node * pCommExpr;
|
|
expr_node * pFaultExpr;
|
|
BOOL fReturnHasStatus = FALSE;
|
|
|
|
ITERATOR I;
|
|
|
|
GetMembers( I );
|
|
|
|
if ( (pRT = GetReturnType()) != 0 && (fReturnHasStatus = pRT->HasStatuses() ) == TRUE )
|
|
ITERATOR_INSERT( I, pRT );
|
|
|
|
while( ITERATOR_GETNEXT(I, pTemp ) && (i < 2) )
|
|
{
|
|
if( pTemp->HasStatuses() )
|
|
{
|
|
if( pTemp->GetStatuses() == STATUS_COMM )
|
|
pComm = pTemp;
|
|
if( pTemp->GetStatuses() == STATUS_FAULT )
|
|
pFault = pTemp;
|
|
if( pTemp->GetStatuses() == STATUS_BOTH )
|
|
{
|
|
pComm = pFault = pTemp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pComm )
|
|
{
|
|
if( pComm == pRT )
|
|
pCommExpr = MakeAddressExpressionNoMatterWhat( pRT->GetResource() );
|
|
else
|
|
pCommExpr = pComm->GetResource();
|
|
}
|
|
else
|
|
pCommExpr = new expr_constant(0L);
|
|
|
|
if( pFault )
|
|
{
|
|
if( pFault == pRT )
|
|
pFaultExpr = MakeAddressExpressionNoMatterWhat(pRT->GetResource());
|
|
else
|
|
pFaultExpr = pFault->GetResource();
|
|
}
|
|
else
|
|
pFaultExpr = new expr_constant(0L);
|
|
|
|
Out_CallNdrMapCommAndFaultStatus( pCCB,
|
|
MakeAddressExpressionNoMatterWhat(
|
|
pCCB->GetStandardResource(
|
|
ST_RES_STUB_MESSAGE_VARIABLE)),
|
|
GetStatusResource(),
|
|
pCommExpr,
|
|
pFaultExpr );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenClearOutParams(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate code to clear out params in the case of exceptions.
|
|
|
|
Arguments:
|
|
|
|
pCCB - The code gen controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK
|
|
|
|
Notes:
|
|
|
|
Generate a call to a varargs function which will take a stub message, a
|
|
format string offset and a list of all output parameters.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ITERATOR I;
|
|
expr_proc_call * pProc;
|
|
expr_node * pExpr;
|
|
short Count;
|
|
CG_PARAM * pParam;
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
// The first parameter is the stub message.
|
|
|
|
Count = GetOutParamList( I );
|
|
|
|
// For each of the output parameters, call the ndr clear out parameters
|
|
// procedure.
|
|
|
|
ITERATOR_INIT( I );
|
|
|
|
while( ITERATOR_GETNEXT( I, pParam ) )
|
|
{
|
|
pParam->GenNdrTopLevelAttributeSupport( pCCB, TRUE );
|
|
|
|
// Create a call to the procedure.
|
|
|
|
pProc = new expr_proc_call( C_NDR_CLEAR_OUT_PARAMS_RTN_NAME );
|
|
|
|
// First param is the address of the stub message.
|
|
|
|
pExpr = pCCB->GetStandardResource( ST_RES_STUB_MESSAGE_VARIABLE );
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PSTUB_MESSAGE_TYPE_NAME,
|
|
pExpr );
|
|
pProc->SetParam( pExpr );
|
|
|
|
|
|
// Second param is the format string offset of the first out parameter.
|
|
// Emitted as &__MIDL_FormatString[ ?? ]
|
|
|
|
|
|
pExpr = Make_1_ArrayExpressionFromVarName(
|
|
FORMAT_STRING_STRING_FIELD,
|
|
((CG_NDR *)(pParam->GetChild()))->GetFormatStringOffset() );
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName(
|
|
PFORMAT_STRING_TYPE_NAME,
|
|
pExpr);
|
|
|
|
pProc->SetParam( pExpr );
|
|
|
|
// The last param is the [out] parameter itself.
|
|
|
|
pProc->SetParam( MakeCastExprPtrToVoid(pParam->GetResource()) );
|
|
|
|
pStream->NewLine();
|
|
pProc->PrintCall( pStream, 0, 0 );
|
|
}
|
|
|
|
return CG_OK;
|
|
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenMapHRESULT(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generates code to map exceptions into HRESULT return values.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ISTREAM *pStream = pCCB->GetStream();
|
|
|
|
pStream->NewLine();
|
|
pStream->Write("_RetVal = NdrProxyErrorHandler(RpcExceptionCode());");
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenProlog(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the procedure prolog for the stub procedure.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise
|
|
|
|
Notes:
|
|
|
|
Increment the stream indentation at the end of the prolog.
|
|
Although we register params as param resources, we dont generate the
|
|
procedure signature using the PrintType/Decl facility.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
|
|
ITERATOR I;
|
|
ITERATOR T;
|
|
|
|
// Output the bare procedure declaration
|
|
|
|
Out_ClientProcedureProlog( pCCB, GetType() );
|
|
|
|
// Generate declarations for pre-allocated and analyser-determined locals.
|
|
|
|
pCCB->GetListOfLocalResources( I );
|
|
Out_ClientLocalVariables( pCCB, I );
|
|
|
|
pCCB->GetListOfTransientResources( T );
|
|
Out_ClientLocalVariables( pCCB, T );
|
|
|
|
// Increment the indentation of the output stream. Reset at epilog time.
|
|
|
|
Out_IndentInc( pCCB );
|
|
|
|
//
|
|
// This is where we output additional variable declarations to handle
|
|
// multidimensional conformant/varying arrays.
|
|
//
|
|
|
|
CG_ITERATOR Iterator;
|
|
ISTREAM * pStream;
|
|
CG_PARAM * pParam;
|
|
CG_NDR * pNdr;
|
|
|
|
pStream = pCCB->GetStream();
|
|
|
|
GetMembers( Iterator );
|
|
|
|
while ( ITERATOR_GETNEXT( Iterator, pParam ) )
|
|
{
|
|
pNdr = (CG_NDR *) pParam->GetChild();
|
|
|
|
if ( (pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsMultiConfOrVar()) ||
|
|
(pNdr->IsPointer() && ((CG_POINTER *)pNdr)->IsMultiSize()) )
|
|
Out_MultiDimVars( pCCB, pParam );
|
|
}
|
|
Iterator.Init();
|
|
while ( ITERATOR_GETNEXT( Iterator, pParam ) )
|
|
{
|
|
pNdr = (CG_NDR *) pParam->GetChild();
|
|
|
|
if ( (pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsMultiConfOrVar()) ||
|
|
(pNdr->IsPointer() && ((CG_POINTER *)pNdr)->IsMultiSize()) )
|
|
Out_MultiDimVarsInit( pCCB, pParam );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenBind(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate code to bind to server.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
pAna - A pointer to the analysis information.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
The binding process is a part of the stub message initialization. The
|
|
stub initializing routine takes the actual binding as a parameter. The
|
|
binding therefore is done as part of the call to this init routine. This
|
|
routine also calls rpc get buffer. This is a change from the erstwhile
|
|
stub generation when binding was done first before the size pass. With
|
|
this call which takes the length as a parameter which means that now we
|
|
will do the sizing pass before the binding pass.
|
|
|
|
In case of auto handles, the call is a slightly different one.
|
|
|
|
Also, we need to assign to the local buffer pointer variable only if there
|
|
is at least one param that is shipped.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ITERATOR BindingParamList;
|
|
expr_node * pExpr;
|
|
expr_node * pExprStubMsg;
|
|
BOOL fCallBack = (GetCGID() == ID_CG_CALLBACK_PROC);
|
|
|
|
//
|
|
// collect standard arguments to the init procedure.
|
|
//
|
|
|
|
// The rpc message variable.
|
|
|
|
pExpr = pCCB->GetStandardResource( ST_RES_RPC_MESSAGE_VARIABLE );
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PRPC_MESSAGE_TYPE_NAME, pExpr );
|
|
|
|
ITERATOR_INSERT(
|
|
BindingParamList,
|
|
pExpr
|
|
);
|
|
|
|
// The stub message variable.
|
|
|
|
pExpr = pCCB->GetStandardResource( ST_RES_STUB_MESSAGE_VARIABLE);
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PSTUB_MESSAGE_TYPE_NAME, pExpr );
|
|
pExprStubMsg = pExpr;
|
|
ITERATOR_INSERT(
|
|
BindingParamList,
|
|
pExpr
|
|
);
|
|
|
|
// The stub descriptor structure variable. This is not allocated as
|
|
// a resource explicitly.
|
|
|
|
pExpr = new RESOURCE( pCCB->GetInterfaceCG()->GetStubDescName(),
|
|
(node_skl *)0 );
|
|
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PSTUB_DESC_STRUCT_TYPE_NAME,
|
|
pExpr );
|
|
|
|
ITERATOR_INSERT( BindingParamList, pExpr );
|
|
|
|
//
|
|
// Proc num.
|
|
//
|
|
ITERATOR_INSERT( BindingParamList,
|
|
new expr_constant( (long) GetProcNum() ) );
|
|
|
|
// This call doesn't do much nowadays except for generating
|
|
// the initialize call and rpc flags assignment and so could
|
|
// be eliminated.
|
|
|
|
Out_HandleInitialize( pCCB,
|
|
BindingParamList,
|
|
0,
|
|
IsAutoHandle(),
|
|
(unsigned short) GetOperationBits()
|
|
);
|
|
|
|
// Generate an explicit binding call depending upon the handle or callback.
|
|
if( fCallBack )
|
|
{
|
|
pExpr = new expr_proc_call( CALLBACK_HANDLE_RTN_NAME );
|
|
pExpr = new expr_assign( GetBindingResource(), pExpr );
|
|
}
|
|
else
|
|
{
|
|
pExpr = GenBindOrUnBindExpression( pCCB,
|
|
TRUE // call to bind.
|
|
);
|
|
}
|
|
|
|
// Emit the handle init expression.
|
|
|
|
if( IsContextHandle() )
|
|
{
|
|
|
|
// Special for context handles:
|
|
// The bind expression will contain only the context handle expression,
|
|
// and not the assignment to the binding handle variable. This is to
|
|
// be done right here. This is because some special code has to be
|
|
// generated for context handles for error checking.
|
|
|
|
// if the context handle param is [in] generate code of the form:
|
|
// if( Context_Handle != 0 )
|
|
// {
|
|
// _Handle = NdrContextBinding( Context_Handle );
|
|
// }
|
|
// else
|
|
// {
|
|
// RpcRaiseException( RPC_X_SS_IN_NULL_CONTEXT );
|
|
// }
|
|
//
|
|
// if the context handle is [in, out] then generate code of the form:
|
|
// if( Context_Handle != 0 )
|
|
// {
|
|
// Handle = NdrContextBinding( Context_Handle );
|
|
// }
|
|
// else
|
|
// {
|
|
// _Handle = 0;
|
|
// }
|
|
|
|
// Note: The case of [out] context handle will never come here since
|
|
// this context handle is not a binding handle, and hence will be
|
|
// handled elsewhere.
|
|
//
|
|
|
|
ITERATOR I;
|
|
BOOL fIn = (SearchForBindingParam())->IsParamIn();
|
|
BOOL fInOut = ((SearchForBindingParam())->IsParamOut()
|
|
&&
|
|
fIn );
|
|
|
|
// For now assume we always have error checking on. When we get -error
|
|
// none implemented on procs, we can set it based on that.
|
|
|
|
BOOL fErrorCheckReqd = pCCB->MustCheckRef();
|
|
expr_node * pAss;
|
|
expr_node * pContextParam = ((CG_NDR *)SearchForBindingParam())->
|
|
GenBindOrUnBindExpression(
|
|
pCCB, TRUE );
|
|
|
|
|
|
pExpr = pContextParam;
|
|
pExpr = MakeExpressionOfCastToTypeName( CTXT_HDL_C_CONTEXT_TYPE_NAME,
|
|
pExpr
|
|
);
|
|
|
|
ITERATOR_INSERT( I, pExpr );
|
|
|
|
pExpr = MakeProcCallOutOfParamExprList( CTXT_HDL_BIND_RTN_NAME,
|
|
(node_skl *)0,
|
|
I
|
|
);
|
|
pAss= new expr_assign(GetBindingResource(), pExpr);
|
|
|
|
if( !fErrorCheckReqd )
|
|
{
|
|
pCCB->GetStream()->NewLine();
|
|
pAss->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
pCCB->GetStream()->Write(';');
|
|
pCCB->GetStream()->NewLine();
|
|
}
|
|
else
|
|
{
|
|
Out_If( pCCB, new expr_relational(OP_NOT_EQUAL,
|
|
pContextParam,
|
|
new expr_constant(0L) ) );
|
|
pCCB->GetStream()->NewLine();
|
|
pAss->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
pCCB->GetStream()->Write(';');
|
|
pCCB->GetStream()->NewLine();
|
|
Out_Endif( pCCB );
|
|
|
|
if( !fInOut )
|
|
{
|
|
Out_Else( pCCB );
|
|
Out_RaiseException( pCCB, "RPC_X_SS_IN_NULL_CONTEXT" );
|
|
Out_Endif( pCCB );
|
|
}
|
|
}
|
|
}
|
|
else if( pExpr )
|
|
{
|
|
pCCB->GetStream()->NewLine();
|
|
pExpr->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
pCCB->GetStream()->Write(';');
|
|
pCCB->GetStream()->NewLine();
|
|
|
|
if ( IsGenericHandle() )
|
|
{
|
|
// For generic handles generate a check that the handle
|
|
// is not null after calling user's bind routine.
|
|
|
|
Out_If( pCCB, new expr_relational( OP_EQUAL,
|
|
GetBindingResource(),
|
|
new expr_constant(0L) ) );
|
|
Out_RaiseException( pCCB, "RPC_S_INVALID_BINDING" );
|
|
Out_Endif( pCCB );
|
|
}
|
|
}
|
|
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenSendReceive(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate code to call the rpc runtime sendreceive.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
We will always call an ndr routine for the sendreceive call. This
|
|
is so that we can unify the buffer length updating in that one call.
|
|
The only difference is for Auto handles when we will have to call this
|
|
with an additional parameter.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
PNAME pProcName;
|
|
expr_proc_call * pProc;
|
|
expr_node * pExpr;
|
|
expr_node * pStubMsgExpr = pCCB->GetStandardResource(
|
|
ST_RES_STUB_MESSAGE_VARIABLE );
|
|
ITERATOR ParamsList;
|
|
|
|
//
|
|
// Check if we're targeting the ndr engine.
|
|
//
|
|
if ( pCCB->GetOptimOption() & OPTIMIZE_SIZE )
|
|
{
|
|
if ( IsAutoHandle() )
|
|
Out_NdrNsSendReceive( pCCB );
|
|
else
|
|
Out_NdrSendReceive( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
// update the param list with a pointer to the stub message.
|
|
|
|
pStubMsgExpr = MakeAddressExpressionNoMatterWhat( pStubMsgExpr );
|
|
|
|
ITERATOR_INSERT( ParamsList, pStubMsgExpr );
|
|
|
|
// In case of auto handles, an additional param is reqd, viz the
|
|
// address of the auto handle variable.
|
|
|
|
if( IsAutoHandle() )
|
|
{
|
|
pExpr = pCCB->GetStandardResource( ST_RES_AUTO_BH_VARIABLE );
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
ITERATOR_INSERT( ParamsList, pExpr );
|
|
pProcName = AUTO_SR_NDR_RTN_NAME;
|
|
}
|
|
else
|
|
{
|
|
pProcName = NORMAL_SR_NDR_RTN_NAME;
|
|
}
|
|
|
|
ITERATOR_INSERT( ParamsList,
|
|
new expr_variable( STUB_MSG_BUFFER_VAR_NAME ) );
|
|
|
|
// generate the procedure call expression.
|
|
|
|
pProc = MakeProcCallOutOfParamExprList( pProcName,
|
|
(node_skl *)0,
|
|
ParamsList
|
|
);
|
|
|
|
pCCB->GetStream()->NewLine();
|
|
pProc->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenUnBind(
|
|
CCB * pCCB)
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate code to unbind from server.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
Dont make unbind calls if not a generic handle.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
|
|
if( IsGenericHandle() )
|
|
{
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
expr_proc_call * pUnBindCall =
|
|
(expr_proc_call *)GenBindOrUnBindExpression( pCCB, FALSE );
|
|
|
|
pStream->NewLine();
|
|
Out_If( pCCB, GetBindingResource() );
|
|
pStream->NewLine();
|
|
|
|
pUnBindCall->PrintCall( pStream, 0, 0 );
|
|
|
|
Out_Endif( pCCB );
|
|
}
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::C_GenFreeBuffer(
|
|
CCB * pCCB)
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate code to call runtime to free the rpc buffer.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
The analyser will supply the binding information.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
if ( pCCB->GetOptimOption() & OPTIMIZE_SIZE )
|
|
{
|
|
Out_NdrFreeBuffer( pCCB );
|
|
return CG_OK;
|
|
}
|
|
|
|
Out_NormalFreeBuffer( pCCB );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenServerStub(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the server side unmarshalling stub.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ANALYSIS_INFO Analysis;
|
|
DISPATCH_TABLE_FLAGS Dtf;
|
|
BOOL fEmitCheckStubData;
|
|
|
|
// call_as procs need additional prototypes
|
|
if ( pCallAsName )
|
|
pCCB->RegisterCallAsRoutine( (node_proc *)GetType() );
|
|
|
|
BOOL fPicklingProcOrType = GetCGID() == ID_CG_ENCODE_PROC ||
|
|
GetCGID() == ID_CG_TYPE_ENCODE_PROC;
|
|
|
|
//
|
|
// Set the CCB code generation side.
|
|
//
|
|
pCCB->SetCodeGenSide( CGSIDE_SERVER );
|
|
pCCB->SetCodeGenPhase( CGPHASE_UNMARSHALL );
|
|
pCCB->SetOptimOption( GetOptimizationFlags() );
|
|
|
|
|
|
Analysis.SetCurrentSide( S_SIDE );
|
|
Analysis.SetOptimOption( pCCB->GetOptimOption() );
|
|
|
|
// Set the analysis phase to the correct one.
|
|
|
|
Analysis.SetCurrentPhase( ANA_PHASE_SERVER_UNMARSHALL );
|
|
|
|
//
|
|
// Change to -Os if needed because of number of param and/or stack size.
|
|
//
|
|
(void) MustUseSingleEngineCall( pCCB );
|
|
Analysis.SetOptimOption( pCCB->GetOptimOption() );
|
|
|
|
Analysis.SetMode( pCCB->GetMode() );
|
|
Analysis.SetRpcSSSwitchSet( (unsigned long)pCCB->IsRpcSSSwitchSet() );
|
|
|
|
|
|
// Preallocate param and local resources if needed. We do need at least
|
|
// one param resource - the rpc message pointer.
|
|
|
|
S_PreAllocateResources( &Analysis );
|
|
|
|
// The unmarshall analysis figures out the local variables needed,
|
|
// and their allocation type. This helps the code generator select the
|
|
// most optimal instruction. This is performed only for [in] and [in,out]
|
|
// params.
|
|
|
|
UnMarshallAnalysis( &Analysis );
|
|
|
|
|
|
// Perform the initialization analysis for the server side locals if
|
|
// allocated for the [out] ONLY parameters.
|
|
|
|
S_OutLocalAnalysis( &Analysis );
|
|
|
|
// Perform this analysis so the format string is correct for server.
|
|
// It is needed for -Oi RpcSs flag generation.
|
|
|
|
RpcSsPackageAnalysis( &Analysis );
|
|
|
|
// Perform InLocalAnalysis to allocate any in params( for now arrays of
|
|
// ref pointers only) on the server side stub stack.
|
|
|
|
InLocalAnalysis( &Analysis );
|
|
|
|
// Perform the size analysis for the marshalling part of the stub.
|
|
|
|
Analysis.SetCurrentPhase( ANA_PHASE_SERVER_MARSHALL );
|
|
|
|
MarshallAnalysis( &Analysis );
|
|
|
|
|
|
// Generate the unmarshalling code. Register this procedure with the
|
|
// dispatch table. Copy the resource dictionary from the analysis phase
|
|
// to be used during the code gen phase.
|
|
|
|
char * AllocRoutineName, * FreeRoutineName;
|
|
|
|
GetCorrectAllocFreeRoutines( pCCB,
|
|
TRUE, //client
|
|
&AllocRoutineName,
|
|
&FreeRoutineName );
|
|
|
|
|
|
pCCB->InitForNewProc(
|
|
GetProcNum(), // procedure number
|
|
(RPC_FLAGS)0, // flags, datagram etc
|
|
(PNAME) AllocRoutineName,
|
|
(PNAME) FreeRoutineName,
|
|
Analysis.GetResDictDatabase() // copy the resource database
|
|
);
|
|
|
|
if( HasNotify() || HasNotifyFlag() )
|
|
GetNotifyTableOffset( pCCB );
|
|
|
|
// Register the procedure for the dispatch table.
|
|
// If this proc is interpreted, then the dispatch table has an
|
|
// entry which specifies the NdrServerCall rather than the proc name itself.
|
|
|
|
if( GetOptimizationFlags() & OPTIMIZE_INTERPRETER )
|
|
{
|
|
Dtf = DTF_INTERPRETER;
|
|
}
|
|
else
|
|
{
|
|
Dtf = DTF_NONE;
|
|
}
|
|
|
|
if ( GetCGID() == ID_CG_ENCODE_PROC )
|
|
Dtf = (DISPATCH_TABLE_FLAGS) (Dtf | DTF_PICKLING_PROC);
|
|
|
|
if ( GetCGID() != ID_CG_TYPE_ENCODE_PROC )
|
|
pCCB->GetInterfaceCG()->RegisterProcedure( GetType(), Dtf );
|
|
|
|
if ( ! fPicklingProcOrType )
|
|
{
|
|
if ( MustUseSingleEngineCall( pCCB ) )
|
|
{
|
|
if ( UseOldInterpreterMode( pCCB ) )
|
|
{
|
|
GenNdrOldInterpretedServerStub( pCCB );
|
|
}
|
|
|
|
if ( NeedsServerThunk( pCCB, CGSIDE_SERVER ) )
|
|
{
|
|
GenNdrThunkInterpretedServerStub( pCCB );
|
|
}
|
|
|
|
//
|
|
// This will only do something for a [callback] proc when we're
|
|
// called while generating the client side.
|
|
//
|
|
MIDL_ASSERT( pCommand->IsNDRRun() || pCommand->IsNDR64Run() );
|
|
|
|
if ( pCommand->IsNDRRun() )
|
|
{
|
|
GenNdrFormat( pCCB );
|
|
}
|
|
else
|
|
{
|
|
pCCB->GetNdr64Format()->Generate( this );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
}
|
|
|
|
pCCB->SetCGNodeContext( this );
|
|
|
|
//
|
|
// Always create the format string for the proc.
|
|
//
|
|
|
|
if ( pCommand->IsNDRRun() )
|
|
{
|
|
GenNdrFormat( pCCB );
|
|
}
|
|
else
|
|
{
|
|
pCCB->GetNdr64Format()->Generate( this );
|
|
}
|
|
|
|
// Dont generate the stub itself for pickling.
|
|
|
|
if ( fPicklingProcOrType )
|
|
return( CG_OK );
|
|
|
|
// Generate the server side procedure prolog. This generates only the
|
|
// server side proc signature, the locals needed and the stub descriptor
|
|
// structure.
|
|
|
|
// This also generates the call to server initialize routine.
|
|
// Note, that it is out of RpcTryFinally, but this is ok as
|
|
// we shouldn't attempt to free parameters (they haven't been
|
|
// unmarshaled yet.
|
|
|
|
S_GenProlog( pCCB );
|
|
S_GenInitTopLevelStuff( pCCB );
|
|
|
|
S_GenInitInLocals( pCCB );
|
|
|
|
// Initialize the local variables allocated on the server side if necessary.
|
|
// Also make the initialization call for the server side stub message which
|
|
// updates the buffer pointer.
|
|
|
|
// Generate the unmarshalling code.
|
|
Out_RpcTryFinally( pCCB );
|
|
|
|
// If the user specifies the -error stub_data to check server unmarshall
|
|
// errors, we need to enclose the unmarshall in a try except, and in the
|
|
// except clause, raise a bad stub data exception.
|
|
|
|
fEmitCheckStubData = pCCB->IsMustCheckStubDataSpecified() && !IsObject();
|
|
|
|
if( fEmitCheckStubData )
|
|
{
|
|
Out_RpcTryExcept( pCCB );
|
|
}
|
|
|
|
if ( HasFullPtr() )
|
|
Out_FullPointerInit( pCCB );
|
|
|
|
// generate NdrCorrelationInitialize( _StubMsg, _NdrCorrCache, _NdrCorrCacheSize, _NdrCorrFlags );
|
|
// normally, /deny causes a switch to /Oicf. This code will be executed when a
|
|
// a switch to from /Os to /Oicf is not posible
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrInit( pCCB );
|
|
}
|
|
|
|
GenUnMarshall( pCCB );
|
|
|
|
// generate NdrCorrelationUninitialize( _StubMsg );
|
|
// normally, /deny causes a switch to /Oicf. This code will be executed when a
|
|
// a switch to from /Os to /Oicf is not posible
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrPassFree( pCCB, CSTUB_CORR_PASS_RTN_NAME );
|
|
}
|
|
|
|
// If the check for bad stub data must be made, then generate a
|
|
// Rpcexcept() to catch some exceptions here, and re-raise a bad
|
|
// stub data exception for them.
|
|
// Other exceptions would propagate unchanged.
|
|
|
|
if( fEmitCheckStubData )
|
|
{
|
|
Out_CheckUnMarshallPastBufferEnd( pCCB );
|
|
Out_RpcExcept( pCCB, "RPC_BAD_STUB_DATA_EXCEPTION_FILTER" );
|
|
Out_RaiseException( pCCB, "RPC_X_BAD_STUB_DATA" );
|
|
Out_RpcEndExcept( pCCB );
|
|
}
|
|
|
|
S_GenInitOutLocals( pCCB );
|
|
|
|
// Generate the call to the actual manager procedure.
|
|
|
|
S_GenCallManager( pCCB );
|
|
|
|
S_GenInitMarshall( pCCB );
|
|
|
|
pCCB->SetCodeGenPhase( CGPHASE_MARSHALL );
|
|
|
|
GenSizing( pCCB );
|
|
|
|
// Generate the server side marshall initialization.
|
|
|
|
// Marshall the outs and return value.
|
|
|
|
GenMarshall( pCCB );
|
|
|
|
Out_RpcFinally( pCCB );
|
|
if ( fHasDeny )
|
|
{
|
|
GenCorrPassFree( pCCB, CSTUB_CORR_FREE_RTN_NAME );
|
|
}
|
|
|
|
// When notify is used, guard also against an exception in freeing.
|
|
if( HasNotify() || HasNotifyFlag() )
|
|
{
|
|
Out_RpcTryFinally( pCCB );
|
|
}
|
|
|
|
// Free anything that needs freeing.
|
|
|
|
GenFree( pCCB );
|
|
|
|
if( MustInvokeRpcSSAllocate())
|
|
{
|
|
Out_RpcSSDisableAllocate( pCCB );
|
|
}
|
|
|
|
if ( HasFullPtr() )
|
|
Out_FullPointerFree( pCCB );
|
|
|
|
// If this is a notify procedure, generate the call to the notify procedure.
|
|
|
|
if( HasNotify() || HasNotifyFlag() )
|
|
{
|
|
Out_RpcFinally( pCCB );
|
|
GenNotify( pCCB , HasNotifyFlag() );
|
|
Out_RpcEndFinally( pCCB );
|
|
}
|
|
|
|
Out_RpcEndFinally( pCCB );
|
|
|
|
// For now, just return.
|
|
|
|
GenEpilog( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::S_GenInitMarshall(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the server side marshall init.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well,
|
|
error otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR Iterator;
|
|
ISTREAM * pStream;
|
|
CG_PARAM * pParam;
|
|
CG_NDR * pNdr;
|
|
|
|
//
|
|
// We have to fill in the arrays that we use for handling multidimensional
|
|
// arrays.
|
|
//
|
|
|
|
pStream = pCCB->GetStream();
|
|
|
|
GetMembers( Iterator );
|
|
|
|
while ( ITERATOR_GETNEXT( Iterator, pParam ) )
|
|
{
|
|
pNdr = (CG_NDR *) pParam->GetChild();
|
|
|
|
if ( (pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsMultiConfOrVar()) ||
|
|
(pNdr->IsPointer() && ((CG_POINTER *)pNdr)->IsMultiSize()) )
|
|
Out_MultiDimVarsInit( pCCB, pParam );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::S_GenInitOutLocals(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the initialization of the local variables.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well,
|
|
error otherwise.
|
|
|
|
Notes:
|
|
|
|
This method performs initalization of local variables on the server side.
|
|
Local variables may be declared in the server stub for [out] params, and
|
|
for in parameters which cannot reuse the buffer.
|
|
|
|
This method will also perform the stub descriptor structure initialization.
|
|
This method will also perform the server side stub message init.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR Iter;
|
|
CG_PARAM * pParam;
|
|
|
|
if( GetMembers( Iter ) )
|
|
{
|
|
while( ITERATOR_GETNEXT( Iter, pParam ) )
|
|
{
|
|
pParam->S_GenInitOutLocals( pCCB );
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have to catch initialization of returns of pointers to context
|
|
// handles here.
|
|
//
|
|
if ( GetReturnType() )
|
|
{
|
|
GetReturnType()->S_GenInitOutLocals( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::S_GenCallManager(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate a call to the manager routine.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error otherwise.
|
|
|
|
Notes:
|
|
|
|
Make a procedure node with all the parameters that need to be passed to
|
|
the manager code. The actual expression that needs to be passed to the
|
|
actual manager code is set up during earlier passes. This is called the
|
|
result expression.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR I;
|
|
PNAME pName;
|
|
expr_proc_call * pProc;
|
|
CG_PARAM * pParam;
|
|
expr_node * pExpr;
|
|
expr_node * pReturnExpr = 0;
|
|
CG_RETURN * pRT;
|
|
char * pSStubPrefix = NULL;
|
|
|
|
pSStubPrefix = pCommand->GetUserPrefix( PREFIX_SERVER_MGR );
|
|
|
|
if ( GetCallAsName() )
|
|
pName = (PNAME ) GenMangledCallAsName( pCCB );
|
|
else if ( pSStubPrefix )
|
|
{
|
|
pName = new char[ strlen(pSStubPrefix) + strlen(GetType()->GetSymName()) + 1];
|
|
strcpy( pName, pSStubPrefix );
|
|
strcat( pName, GetType()->GetSymName() );
|
|
}
|
|
else
|
|
pName = (PNAME ) GetType()->GetSymName();
|
|
|
|
pProc = new expr_proc_call( pName );
|
|
|
|
GetMembers( I );
|
|
|
|
while( ITERATOR_GETNEXT( I, pParam ) )
|
|
{
|
|
if ( pParam->IsOmittedParam() )
|
|
continue;
|
|
|
|
if ( ( pExpr = pParam->GetFinalExpression() ) != 0 )
|
|
{
|
|
CG_NDR * pChild = (CG_NDR *)pParam->GetChild();
|
|
|
|
//
|
|
// We have to dereference arrays because of how they are defined
|
|
// in the stub.
|
|
//
|
|
if ( pChild->IsArray() )
|
|
{
|
|
pExpr = new expr_u_deref( pExpr );
|
|
}
|
|
else if( (pChild->GetCGID() == ID_CG_GENERIC_HDL ) &&
|
|
(((CG_NDR *)pChild->GetChild())->IsArray() )
|
|
)
|
|
{
|
|
pExpr = new expr_u_deref( pExpr );
|
|
}
|
|
|
|
//
|
|
// Context handle param is handled differently.
|
|
//
|
|
if ( (pChild->GetCGID() == ID_CG_CONTEXT_HDL) ||
|
|
((pChild->GetCGID() == ID_CG_PTR) &&
|
|
(((CG_NDR *)pChild->GetChild())->GetCGID() ==
|
|
ID_CG_CONTEXT_HDL)) )
|
|
{
|
|
expr_proc_call * pCall;
|
|
|
|
pCall = new expr_proc_call( "NDRSContextValue" );
|
|
pCall->SetParam(
|
|
new expr_param(
|
|
new expr_variable(
|
|
pParam->GetResource()->GetResourceName() )) );
|
|
|
|
expr_node * pFinal;
|
|
|
|
if ( pChild->GetCGID() == ID_CG_CONTEXT_HDL )
|
|
pFinal = new expr_u_deref(pCall);
|
|
else
|
|
pFinal = pCall;
|
|
|
|
//
|
|
// Dereference a plain context handle.
|
|
//
|
|
pExpr = new expr_cast( pParam->GetType()->GetChild(),
|
|
pFinal );
|
|
}
|
|
|
|
pProc->SetParam( new expr_param( pExpr ) );
|
|
}
|
|
}
|
|
|
|
if ( ( pRT = GetReturnType() ) != 0 )
|
|
{
|
|
pReturnExpr = pRT->GetFinalExpression();
|
|
}
|
|
|
|
if ( HasNotifyFlag() )
|
|
{
|
|
// Assign TRUE to the notify flag variable.
|
|
|
|
expr_node * pNotifyFlag;
|
|
expr_node * pAssignExpr;
|
|
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
pNotifyFlag = new expr_variable( NOTIFY_FLAG_VAR_NAME );
|
|
pAssignExpr = new expr_assign( pNotifyFlag,
|
|
new expr_variable( "TRUE" ) );
|
|
pStream->NewLine();
|
|
pAssignExpr->Print( pStream );
|
|
pStream->Write( ';' );
|
|
pStream->NewLine();
|
|
}
|
|
|
|
Out_CallManager( pCCB,
|
|
pProc,
|
|
pReturnExpr,
|
|
(GetCGID() == ID_CG_CALLBACK_PROC)
|
|
);
|
|
|
|
return CG_OK;
|
|
|
|
}
|
|
CG_STATUS
|
|
CG_PROC::S_GenInitTopLevelStuff(
|
|
CCB * pCCB )
|
|
{
|
|
CG_ITERATOR Iter;
|
|
CG_NDR * pParam;
|
|
|
|
if( GetMembers( Iter ) )
|
|
{
|
|
while( ITERATOR_GETNEXT( Iter, pParam ) )
|
|
{
|
|
pParam->S_GenInitTopLevelStuff( pCCB );
|
|
}
|
|
}
|
|
|
|
if ( GetReturnType() )
|
|
GetReturnType()->S_GenInitTopLevelStuff( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::S_GenProlog(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the server side stub prolog.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
Print out the signature, locals, the stub descriptor if needed and the
|
|
adjust indent in anticipation of code.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
|
|
ITERATOR LocalsList;
|
|
ITERATOR ParamsList;
|
|
ITERATOR TransientList;
|
|
|
|
// Collect all the params and locals into lists ready to print.
|
|
|
|
pCCB->GetListOfLocalResources( LocalsList );
|
|
pCCB->GetListOfParamResources( ParamsList );
|
|
pCCB->GetListOfTransientResources( TransientList );
|
|
|
|
//
|
|
// Print out the procedure signature and the local variables.
|
|
//
|
|
Out_ServerProcedureProlog( pCCB,
|
|
GetType(),
|
|
LocalsList,
|
|
ParamsList,
|
|
TransientList
|
|
);
|
|
|
|
//
|
|
// Done for interpretation op. No indent needed either.
|
|
//
|
|
if ( pCCB->GetOptimOption() & OPTIMIZE_INTERPRETER )
|
|
return CG_OK;
|
|
|
|
//
|
|
// This is where we output additional variable declarations to handle
|
|
// multidimensional conformant/varying arrays.
|
|
//
|
|
|
|
CG_ITERATOR Iterator;
|
|
ISTREAM * pStream;
|
|
CG_PARAM * pParam;
|
|
CG_NDR * pNdr;
|
|
|
|
pStream = pCCB->GetStream();
|
|
|
|
GetMembers( Iterator );
|
|
|
|
while ( ITERATOR_GETNEXT( Iterator, pParam ) )
|
|
{
|
|
pNdr = (CG_NDR *) pParam->GetChild();
|
|
|
|
if ( (pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsMultiConfOrVar()) ||
|
|
(pNdr->IsPointer() && ((CG_POINTER *)pNdr)->IsMultiSize()) )
|
|
Out_MultiDimVars( pCCB, pParam );
|
|
}
|
|
|
|
pStream->NewLine();
|
|
|
|
// Removes warning if we don't use the _Status variable.
|
|
pStream->Write( "((void)(" RPC_STATUS_VAR_NAME "));" );
|
|
pStream->NewLine();
|
|
|
|
if ( HasNotifyFlag() )
|
|
{
|
|
// Assign FALSE to the notify flag variable.
|
|
|
|
expr_node * pNotifyFlag;
|
|
expr_node * pAssignExpr;
|
|
|
|
pNotifyFlag = new expr_variable( NOTIFY_FLAG_VAR_NAME );
|
|
pAssignExpr = new expr_assign( pNotifyFlag,
|
|
new expr_variable( "FALSE" ) );
|
|
pStream->NewLine();
|
|
pAssignExpr->Print( pStream );
|
|
pStream->Write( ';' );
|
|
pStream->NewLine();
|
|
}
|
|
|
|
//
|
|
// Call the NdrServerInitialize routine.
|
|
//
|
|
|
|
expr_proc_call * pCall;
|
|
|
|
pCall = new expr_proc_call( SSTUB_INIT_RTN_NAME );
|
|
|
|
pCall->SetParam( new expr_param (
|
|
new expr_variable( PRPC_MESSAGE_VAR_NAME ) ) );
|
|
|
|
pCall->SetParam( new expr_param (
|
|
new expr_u_address (
|
|
new expr_variable( STUB_MESSAGE_VAR_NAME ) ) ) );
|
|
|
|
pCall->SetParam( new expr_param (
|
|
new expr_u_address (
|
|
new expr_variable(
|
|
pCCB->GetInterfaceCG()->GetStubDescName() ) ) ) );
|
|
|
|
pCall->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
pStream->NewLine();
|
|
|
|
// if the rpc ss package is to be enabled, do so.
|
|
|
|
if( MustInvokeRpcSSAllocate() )
|
|
{
|
|
Out_RpcSSEnableAllocate( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenUnMarshall(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the unmarshalling code for the server side stub.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well,
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
|
|
The new server stubs will contain an ndr transformation phase which will
|
|
convert, in-situ, any incoming buffer that needs ndr transformations like
|
|
big-little endian conversions, char / float transformations etc.
|
|
|
|
Therefore the first thing the server stub does is to tranform the data into
|
|
the correct format and then the rest of the stub can proceed as if the
|
|
data came in little endian format.
|
|
|
|
Currently we will use the engine to tranform the data.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR Iterator;
|
|
ITERATOR ParamList;
|
|
CG_RETURN * pRT;
|
|
CGSIDE Side;
|
|
BOOL fReturnNeedsUnMarshall = FALSE;
|
|
long ParamTotal;
|
|
|
|
GetMembers( Iterator );
|
|
|
|
ParamTotal = ITERATOR_GETCOUNT( Iterator );
|
|
|
|
if ( GetReturnType() )
|
|
ParamTotal++;
|
|
|
|
pCCB->SetCodeGenPhase( CGPHASE_UNMARSHALL );
|
|
|
|
// Generate a call to tranform the data into the proper endianness.
|
|
|
|
S_XFormToProperFormat( pCCB );
|
|
|
|
// For all [in] params, generate the unmarshalling code.
|
|
|
|
if( (Side = pCCB->GetCodeGenSide()) == CGSIDE_CLIENT )
|
|
GetOutParamList( ParamList );
|
|
else
|
|
GetInParamList( ParamList );
|
|
|
|
if ( (Side == CGSIDE_CLIENT) && (pRT = GetReturnType()) != 0 )
|
|
fReturnNeedsUnMarshall = TRUE;
|
|
|
|
//
|
|
// Output the call to check for and perform endian or other transformations
|
|
// if needed.
|
|
//
|
|
if ( fReturnNeedsUnMarshall || ParamList.GetCount() )
|
|
Out_NdrConvert( pCCB,
|
|
GetFormatStringParamStart(),
|
|
ParamTotal,
|
|
GetOptimizationFlags() );
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
CG_PARAM * pS;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
// The extra fault/comm status param doesn't go on wire.
|
|
|
|
pS = (CG_PARAM *)ITERATOR_PEEKTHIS( ParamList );
|
|
|
|
pParam->GenUnMarshall( pCCB );
|
|
}
|
|
}
|
|
|
|
// For the client side, generate the unmarshall call if there is a return
|
|
// value.
|
|
|
|
if( fReturnNeedsUnMarshall )
|
|
{
|
|
pRT->GenUnMarshall( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenFree(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generates freeing code.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR ParamList;
|
|
CGSIDE Side;
|
|
CG_RETURN * pRT;
|
|
BOOL fReturnNeedsFree = FALSE;
|
|
|
|
if( (Side = pCCB->GetCodeGenSide()) == CGSIDE_CLIENT )
|
|
return CG_OK;
|
|
|
|
// Else it's the server side
|
|
|
|
GetMembers( ParamList );
|
|
|
|
if ( ( pRT = GetReturnType() ) != 0 )
|
|
fReturnNeedsFree = TRUE;
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
pParam->GenFree( pCCB );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Size the return value on the server side if needed.
|
|
//
|
|
if( fReturnNeedsFree )
|
|
{
|
|
pRT->GenFree( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenNotify(
|
|
CCB * pCCB,
|
|
BOOL fHasFlag )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the notify call for the procedure.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
We need to generate a call to foo_notify with all parameters, exactly
|
|
the same as the original procedure. The return value is a void.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
// Create an expression for the call to the notify procedure. The name
|
|
// of the notify procedure is the procname suffixed by _notify.
|
|
|
|
CSzBuffer ProcName;
|
|
|
|
ProcName.Set( GetType()->GetSymName() );
|
|
ProcName.Append( (fHasFlag ? NOTIFY_FLAG_SUFFIX
|
|
: NOTIFY_SUFFIX) );
|
|
|
|
expr_proc_call ProcExpr( ProcName.GetData(), 0 );
|
|
expr_variable * pVarNode;
|
|
expr_param * pFlagParam;
|
|
|
|
if ( fHasFlag )
|
|
{
|
|
pVarNode = new expr_variable( NOTIFY_FLAG_VAR_NAME );
|
|
pFlagParam = new expr_param( pVarNode );
|
|
|
|
ProcExpr.SetParam( pFlagParam );
|
|
}
|
|
|
|
// The call expression has been made. Emit it.
|
|
|
|
pStream->NewLine();
|
|
ProcExpr.PrintCall( pStream, 0, 0 );
|
|
pStream->NewLine();
|
|
|
|
// Clean up.
|
|
|
|
if ( fHasFlag )
|
|
{
|
|
delete pVarNode;
|
|
delete pFlagParam;
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenEpilog(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate the server side epilog for the procedure.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
Decrement the indent back to the initial, and emit the closing brace.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
if( (pCCB->GetCodeGenSide() == CGSIDE_CLIENT) && GetReturnType() )
|
|
{
|
|
expr_node * pExpr = new expr_variable( RETURN_VALUE_VAR_NAME );
|
|
pCCB->GetStream()->NewLine();
|
|
pCCB->GetStream()->Write( "return " );
|
|
pExpr->Print( pCCB->GetStream() );
|
|
pCCB->GetStream()->Write( ';' );
|
|
}
|
|
|
|
if ( (pCCB->GetCodeGenSide() == CGSIDE_SERVER) )
|
|
{
|
|
ISTREAM * pStream = pCCB->GetStream();
|
|
|
|
pStream->Write( PRPC_MESSAGE_VAR_NAME "->BufferLength = " );
|
|
pStream->NewLine();
|
|
pStream->Spaces( STANDARD_STUB_TAB );
|
|
pStream->Write( "(unsigned int)(" STUB_MESSAGE_VAR_NAME ".Buffer - ");
|
|
pStream->Write( "(unsigned char *)" PRPC_MESSAGE_VAR_NAME "->Buffer);" );
|
|
pStream->NewLine();
|
|
}
|
|
|
|
Out_IndentDec( pCCB );
|
|
Out_ProcClosingBrace( pCCB );
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenSizing(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate sizing code.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ITERATOR ParamList;
|
|
CGSIDE Side;
|
|
CG_RETURN * pRT;
|
|
BOOL fReturnNeedsSizing = FALSE;
|
|
short ParamCount = 0;
|
|
|
|
pCCB->GetStream()->NewLine();
|
|
|
|
|
|
if( (Side = pCCB->GetCodeGenSide()) == CGSIDE_CLIENT )
|
|
ParamCount = GetInParamList( ParamList );
|
|
else
|
|
ParamCount = GetOutParamList( ParamList );
|
|
|
|
if ( (Side == CGSIDE_SERVER) && (pRT = GetReturnType()) != 0 )
|
|
fReturnNeedsSizing = TRUE;
|
|
|
|
// On the server side if there are no out params and no returns, dont
|
|
// generate code for sizing and get buffer at all !
|
|
|
|
if( (Side == CGSIDE_SERVER) && (ParamCount == 0) && !fReturnNeedsSizing )
|
|
{
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Analyze all the parameters and compute the constant buffer.
|
|
//
|
|
|
|
long ConstantBufferSize = 0;
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
long ParamBufferSize = pParam->FixedBufferSize( pCCB );
|
|
pParam->SetFixedBufferSize( ParamBufferSize );
|
|
|
|
if (-1 != ParamBufferSize)
|
|
ConstantBufferSize += ParamBufferSize;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Size the return value on the server side if needed.
|
|
//
|
|
if( fReturnNeedsSizing )
|
|
{
|
|
long ReturnBufferSize = pRT->FixedBufferSize( pCCB );
|
|
pRT->SetFixedBufferSize( ReturnBufferSize );
|
|
|
|
if (-1 != ReturnBufferSize)
|
|
ConstantBufferSize += ReturnBufferSize;
|
|
}
|
|
|
|
//
|
|
// Init the length variable to 0.
|
|
//
|
|
|
|
Out_Assign( pCCB,
|
|
new expr_variable ( STUB_MSG_LENGTH_VAR_NAME, 0 ),
|
|
new expr_constant( ConstantBufferSize )
|
|
);
|
|
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
if (pParam->GetFixedBufferSize() == -1)
|
|
pParam->GenSizing( pCCB );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Size the return value on the server side if needed.
|
|
//
|
|
if( fReturnNeedsSizing )
|
|
{
|
|
if (pRT->GetFixedBufferSize() == -1)
|
|
pRT->GenSizing( pCCB );
|
|
}
|
|
|
|
GenGetBuffer( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenGetBuffer(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Get the message buffer.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
if ( IsAutoHandle() && (pCCB->GetCodeGenSide() == CGSIDE_CLIENT) )
|
|
Out_NdrNsGetBuffer( pCCB );
|
|
else
|
|
Out_NdrGetBuffer( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenMarshall(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Server side procedure to marshall out params.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ITERATOR ParamList;
|
|
CGSIDE Side;
|
|
CG_RETURN * pRT;
|
|
BOOL fReturnNeedsMarshall = FALSE;
|
|
|
|
pCCB->SetCodeGenPhase( CGPHASE_MARSHALL );
|
|
|
|
// Generate a call to tranform the data into the proper endianness.
|
|
|
|
S_XFormToProperFormat( pCCB );
|
|
|
|
// For all [in] params, generate the unmarshalling code.
|
|
|
|
if( (Side = pCCB->GetCodeGenSide()) == CGSIDE_CLIENT )
|
|
GetInParamList( ParamList );
|
|
else
|
|
GetOutParamList( ParamList );
|
|
|
|
if ( (Side == CGSIDE_SERVER) && (pRT = GetReturnType()) != 0 )
|
|
fReturnNeedsMarshall = TRUE;
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
CG_PARAM * pS;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
// IsExtraParam
|
|
|
|
pS = (CG_PARAM *)ITERATOR_PEEKTHIS( ParamList );
|
|
pParam->GenMarshall( pCCB );
|
|
}
|
|
}
|
|
|
|
// For the server side, generate the marshall call if there is a return
|
|
// value.
|
|
|
|
if( fReturnNeedsMarshall )
|
|
{
|
|
pRT->GenMarshall( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::GenRefChecks(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate ref checks for a procedure.
|
|
|
|
Arguments:
|
|
|
|
pCCB - The code gen block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
CG_ITERATOR ParamList;
|
|
CGSIDE Side;
|
|
|
|
// On the client side, perform ref checks for every pointer parameter.
|
|
// On the server side, dont perform any checks at all. If it is a top
|
|
// level ref, the stub allocates the pointee on the stack or in memory.
|
|
// if the allocation fails, the engine will always raise an exception.
|
|
// For embedded pointers, the engine checks anyhow.
|
|
//
|
|
// If the parameter is a cs tag (e.g. [cs_stag]), and the proc has
|
|
// a tag setting routine, the param will be allocated as a local variable
|
|
// so we don't need to check them.
|
|
|
|
if( (Side = pCCB->GetCodeGenSide()) == CGSIDE_CLIENT )
|
|
{
|
|
GetMembers( ParamList );
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
if( ( pCCB->GetOptimOption() & OPTIMIZE_SIZE )
|
|
&& ( NULL == GetCSTagRoutine() || !pParam->IsSomeCSTag() ) )
|
|
{
|
|
pParam->GenRefChecks( pCCB );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PROC::S_GenInitInLocals(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate in local initialization for the procedure.
|
|
|
|
Arguments:
|
|
|
|
pCCB - The code gen block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
ITERATOR ParamList;
|
|
|
|
GetInParamList( ParamList );
|
|
|
|
if( ITERATOR_GETCOUNT( ParamList ) )
|
|
{
|
|
CG_PARAM * pParam;
|
|
|
|
ITERATOR_INIT( ParamList );
|
|
|
|
while( ITERATOR_GETNEXT( ParamList, pParam ) )
|
|
{
|
|
pParam->S_GenInitInLocals( pCCB );
|
|
}
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* parameter code generation class implementation.
|
|
***************************************************************************/
|
|
CG_STATUS
|
|
CG_PARAM::S_GenInitInLocals(
|
|
CCB * pCCB )
|
|
{
|
|
pCCB->SetMemoryAllocDone();
|
|
pCCB->ResetRefAllocDone();
|
|
pCCB->SetSourceExpression( GetResource() );
|
|
pCCB->SetLastPlaceholderClass(this);
|
|
((CG_NDR *)GetChild())->S_GenInitInLocals( pCCB );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PARAM::S_GenInitOutLocals(
|
|
CCB * pCCB )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Generate local initialization for the parameters.
|
|
|
|
Arguments:
|
|
|
|
pCCB - A pointer to the code generation controller block.
|
|
|
|
Return Value:
|
|
|
|
CG_OK if all is well
|
|
error Otherwise.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
|
|
if ( IsParamPartialIgnore() )
|
|
{
|
|
|
|
// Evaluate toplevel size_is. Ignore first_is and length_is since
|
|
// the entire data needs to be allocated and cleared.
|
|
|
|
GenNdrTopLevelAttributeSupport( pCCB, TRUE );
|
|
|
|
char *pParamName = GetResource()->GetResourceName();
|
|
long FormatOffset = dynamic_cast<CG_NDR*>(GetChild())->GetFormatStringOffset();
|
|
|
|
Out_PartialIgnoreServerInitialize( pCCB,
|
|
pParamName,
|
|
FormatOffset );
|
|
return CG_OK;
|
|
}
|
|
|
|
else if( IsParamOut() && !IsParamIn() )
|
|
{
|
|
pCCB->SetMemoryAllocDone();
|
|
pCCB->ResetRefAllocDone();
|
|
pCCB->SetSourceExpression( GetResource() );
|
|
pCCB->SetLastPlaceholderClass(this);
|
|
((CG_NDR *)GetChild())->S_GenInitOutLocals( pCCB );
|
|
SetFinalExpression( GetResource() );
|
|
}
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PARAM::S_GenInitTopLevelStuff(
|
|
CCB * pCCB )
|
|
{
|
|
ISTREAM * pStream;
|
|
CG_NDR * pChild;
|
|
ID_CG ChildID;
|
|
|
|
pStream = pCCB->GetStream();
|
|
|
|
pChild = (CG_NDR *)GetChild();
|
|
ChildID = pChild->GetCGID();
|
|
|
|
if ( ChildID == ID_CG_GENERIC_HDL )
|
|
{
|
|
pChild = (CG_NDR *)pChild->GetChild();
|
|
ChildID = pChild->GetCGID();
|
|
}
|
|
|
|
//
|
|
// Initialize all [in] pointer and array params, and handle by-value
|
|
// structures and unions.
|
|
//
|
|
if ( pChild->IsArray() || pChild->IsSimpleType() )
|
|
{
|
|
expr_node * pParam;
|
|
expr_node * pExpr;
|
|
|
|
pParam = new expr_variable( GetResource()->GetResourceName() );
|
|
pExpr = new expr_assign( pParam,
|
|
new expr_constant( (long) 0 ) );
|
|
|
|
pStream->NewLine();
|
|
pExpr->Print( pStream );
|
|
pStream->Write( ';' );
|
|
}
|
|
|
|
if ( pChild->IsPointer() )
|
|
{
|
|
// const type* ptr or type* const ptr
|
|
// get initialized as (type*) ptr = 0;
|
|
expr_node* pParam;
|
|
expr_node* pExpr;
|
|
expr_node* pLHS;
|
|
|
|
pParam = new expr_variable( GetResource()->GetResourceName() );
|
|
|
|
node_skl* pType = GetChild()->GetType();
|
|
if ( pType != 0 && pType->NodeKind() != NODE_INTERFACE_REFERENCE )
|
|
{
|
|
expr_cast* pCast = new expr_cast( pType, pParam );
|
|
pCast->SetEmitModifiers( false );
|
|
pLHS = pCast;
|
|
}
|
|
else
|
|
{
|
|
pLHS = pParam;
|
|
}
|
|
|
|
pExpr = new expr_assign( pLHS, new expr_constant( (long) 0 ) );
|
|
pStream->NewLine();
|
|
pExpr->Print( pStream );
|
|
pStream->Write( ';' );
|
|
}
|
|
|
|
//
|
|
// If this is a by-value structure or union then we allocate a
|
|
// local which is a pointer to the same type.
|
|
//
|
|
if ( pChild->IsStruct() || pChild->IsUnion() ||
|
|
pChild->IsXmitRepOrUserMarshal() )
|
|
{
|
|
expr_node * pParam;
|
|
expr_node * pPointer;
|
|
expr_node * pExpr;
|
|
char * pPointerName;
|
|
char * pPlainName = GetResource()->GetResourceName();
|
|
|
|
pPointerName = new char[strlen( pPlainName ) + 10];
|
|
|
|
strcpy( pPointerName, LOCAL_NAME_POINTER_MANGLE);
|
|
strcat( pPointerName, pPlainName);
|
|
|
|
pParam = new expr_u_address (
|
|
new expr_variable( pPlainName ) );
|
|
|
|
pPointer = new expr_variable( pPointerName );
|
|
|
|
pExpr = new expr_assign( pPointer, pParam );
|
|
|
|
pStream->NewLine();
|
|
pExpr->Print( pStream );
|
|
pStream->Write( ';' );
|
|
|
|
//
|
|
// Memset [in], [in,out] by-value structs & unions in case we catch
|
|
// an exception before we finish unmarshalling them. If they have
|
|
// embedded pointers they must be zeroed before freeing.
|
|
//
|
|
if ( IsParamIn() &&
|
|
(pChild->IsStruct() || pChild->IsUnion()) )
|
|
{
|
|
Out_MemsetToZero( pCCB,
|
|
pPointer,
|
|
new expr_sizeof( pChild->GetType() ) );
|
|
}
|
|
|
|
// If there is a transmit_as etc, init the ptr to 0.
|
|
|
|
switch( ChildID )
|
|
{
|
|
case ID_CG_TRANSMIT_AS:
|
|
{
|
|
expr_proc_call * pProc = new expr_proc_call( MIDL_MEMSET_RTN_NAME );
|
|
pProc->SetParam( new expr_param( pPointer ) );
|
|
pProc->SetParam( new expr_param( new expr_constant( 0L ) ) );
|
|
pProc->SetParam(
|
|
new expr_param(
|
|
new expr_sizeof(
|
|
((CG_TRANSMIT_AS *)pChild)->GetPresentedType())));
|
|
pCCB->GetStream()->NewLine();
|
|
pProc->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
break;
|
|
}
|
|
case ID_CG_REPRESENT_AS:
|
|
{
|
|
node_skl * pNode = new node_def(
|
|
((CG_REPRESENT_AS *)pChild)->GetRepAsTypeName() );
|
|
expr_proc_call * pProc = new expr_proc_call( MIDL_MEMSET_RTN_NAME );
|
|
pProc->SetParam( new expr_param( pPointer ) );
|
|
pProc->SetParam( new expr_param( new expr_constant( 0L ) ) );
|
|
pProc->SetParam( new expr_param( new expr_sizeof( pNode ) ) );
|
|
pCCB->GetStream()->NewLine();
|
|
pProc->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
break;
|
|
}
|
|
case ID_CG_USER_MARSHAL:
|
|
{
|
|
node_skl * pNode = new node_def(
|
|
((CG_REPRESENT_AS *)pChild)->GetRepAsTypeName() );
|
|
expr_proc_call * pProc = new expr_proc_call( MIDL_MEMSET_RTN_NAME );
|
|
pProc->SetParam( new expr_param( pPointer ) );
|
|
pProc->SetParam( new expr_param( new expr_constant( 0L ) ) );
|
|
pProc->SetParam( new expr_param( new expr_sizeof( pNode ) ) );
|
|
pCCB->GetStream()->NewLine();
|
|
pProc->PrintCall( pCCB->GetStream(), 0, 0 );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ChildID == ID_CG_PRIMITIVE_HDL )
|
|
{
|
|
pStream->NewLine();
|
|
pStream->Write( GetType()->GetSymName() );
|
|
pStream->Write( " = " PRPC_MESSAGE_VAR_NAME "->Handle;" );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PARAM::GenMarshall(
|
|
CCB * pCCB )
|
|
{
|
|
CG_STATUS Status;
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
// The fault/comm additional parameter doesn't go on wire.
|
|
|
|
if ( IsExtraStatusParam() )
|
|
return CG_OK;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
GenNdrMarshallCall( pCCB );
|
|
Status = CG_OK;
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PARAM::GenUnMarshall(
|
|
CCB * pCCB )
|
|
{
|
|
CG_STATUS Status;
|
|
CG_NDR * pOldPlaceholder;
|
|
CG_NDR * pC = (CG_NDR *)GetChild();
|
|
BOOL fPtrToContext = FALSE;
|
|
expr_node * pFinalExpr = GetResource();
|
|
|
|
// The fault/comm additional parameter doesn't go on wire...
|
|
// However, we need to generate an assignment in its place.
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
if ( pC->GetCGID() == ID_CG_CONTEXT_HDL ||
|
|
( (fPtrToContext = ( pC->GetChild()) != 0 && pC->GetChild()->GetCGID() == ID_CG_CONTEXT_HDL ) ) == TRUE )
|
|
{
|
|
expr_node * pExpr;
|
|
expr_proc_call * pProc = new expr_proc_call( "NDRSContextValue" );
|
|
CG_CONTEXT_HANDLE * pCtxtHandle;
|
|
|
|
pProc->SetParam( new expr_param( GetResource() ) );
|
|
|
|
if( fPtrToContext )
|
|
{
|
|
pExpr = new expr_u_deref( pProc );
|
|
pCtxtHandle = (CG_CONTEXT_HANDLE *)pC->GetChild();
|
|
}
|
|
else
|
|
{
|
|
pExpr = pProc;
|
|
pCtxtHandle = (CG_CONTEXT_HANDLE *)pC;
|
|
}
|
|
|
|
pExpr = new expr_cast( GetType()->GetChild(), pExpr );
|
|
pFinalExpr = pExpr;
|
|
|
|
// Register the context handle for a rundown.
|
|
|
|
if( pCtxtHandle->GetHandleType()->NodeKind() == NODE_DEF )
|
|
pCCB->RegisterContextHandleType( pCtxtHandle->GetHandleType() );
|
|
}
|
|
|
|
|
|
GenNdrUnmarshallCall( pCCB );
|
|
SetFinalExpression( pFinalExpr );
|
|
Status = CG_OK;
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
CG_STATUS
|
|
CG_PARAM::GenSizing(
|
|
CCB * pCCB )
|
|
{
|
|
CG_STATUS Status;
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
// The fault/comm additional parameter doesn't go on wire.
|
|
|
|
if ( IsExtraStatusParam() || IsAsyncHandleParam() )
|
|
return CG_OK;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
GenNdrBufferSizeCall( pCCB );
|
|
|
|
Status = CG_OK;
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_PARAM::GenFree(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
if ( IsExtraStatusParam() )
|
|
return CG_OK;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
GenNdrFreeCall( pCCB );
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
|
|
return CG_OK;
|
|
}
|
|
CG_STATUS
|
|
CG_PARAM::GenRefChecks(
|
|
CCB * pCCB )
|
|
{
|
|
pCCB->ResetEmbeddingLevel();
|
|
pCCB->ResetIndirectionLevel();
|
|
pCCB->ResetReturnContext();
|
|
pCCB->ResetRefAllocDone();
|
|
pCCB->SetPrefix(0);
|
|
pCCB->SetSourceExpression( GetResource() );
|
|
((CG_NDR *)GetChild())->GenRefChecks( pCCB );
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CG_RETURN procedures.
|
|
*****************************************************************************/
|
|
CG_STATUS
|
|
CG_RETURN::GenMarshall(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
GenNdrMarshallCall( pCCB );
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_RETURN::GenSizing(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
pCCB->SetSourceExpression( GetResource() );
|
|
|
|
GenNdrBufferSizeCall( pCCB );
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_RETURN::GenUnMarshall(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pOldPlaceholder;
|
|
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
ISTREAM * pStream;
|
|
|
|
pStream = pCCB->GetStream();
|
|
|
|
//
|
|
// Initialize a pointer return type to 0.
|
|
//
|
|
if ( GetChild()->IsPointer() )
|
|
{
|
|
pStream->NewLine();
|
|
pStream->Write( RETURN_VALUE_VAR_NAME );
|
|
pStream->Write( " = 0;" );
|
|
}
|
|
|
|
//
|
|
// Initialize a struct or union return value.
|
|
//
|
|
if ( GetChild()->IsStruct() || GetChild()->IsUnion() ||
|
|
((CG_NDR *)GetChild())->IsXmitRepOrUserMarshal() )
|
|
{
|
|
pStream->NewLine();
|
|
pStream->Write( LOCAL_NAME_POINTER_MANGLE RETURN_VALUE_VAR_NAME );
|
|
pStream->Write( " = " );
|
|
pStream->Write( "(void *) &" RETURN_VALUE_VAR_NAME );
|
|
pStream->Write( ';' );
|
|
}
|
|
|
|
GenNdrUnmarshallCall( pCCB );
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_RETURN::S_GenInitOutLocals(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pNdr;
|
|
|
|
pNdr = (CG_NDR *) GetChild();
|
|
|
|
//
|
|
// The only return type we ever have to initialize is a context handle.
|
|
// A pointer to a context handle as a return type is forbidden.
|
|
//
|
|
if ( pNdr->GetCGID() == ID_CG_CONTEXT_HDL )
|
|
{
|
|
pCCB->SetLastPlaceholderClass(this);
|
|
pNdr->S_GenInitOutLocals( pCCB );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_RETURN::S_GenInitTopLevelStuff(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pChild;
|
|
expr_node * pExpr;
|
|
|
|
pChild = (CG_NDR *) GetChild();
|
|
|
|
pExpr = new expr_u_address (
|
|
new expr_variable( RETURN_VALUE_VAR_NAME ) );
|
|
|
|
if ( pChild->IsStruct() || pChild->IsUnion() )
|
|
{
|
|
Out_MemsetToZero( pCCB,
|
|
pExpr,
|
|
new expr_sizeof( pChild->GetType() ) );
|
|
}
|
|
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_RETURN::GenFree(
|
|
CCB * pCCB )
|
|
{
|
|
CG_NDR * pOldPlaceholder;
|
|
pOldPlaceholder = pCCB->SetLastPlaceholderClass( this );
|
|
|
|
GenNdrFreeCall( pCCB );
|
|
|
|
pCCB->SetLastPlaceholderClass( pOldPlaceholder );
|
|
return CG_OK;
|
|
}
|
|
|
|
expr_node *
|
|
CG_RETURN::GetFinalExpression()
|
|
{
|
|
expr_node * pReturnExpr;
|
|
BOOL fPtrToContext = FALSE;
|
|
CG_NDR * pC = (CG_NDR *)GetChild();
|
|
|
|
if( pC->GetCGID() == ID_CG_CONTEXT_HDL ||
|
|
( (fPtrToContext = ( pC->GetChild()) != 0 &&
|
|
pC->GetChild()->GetCGID() == ID_CG_CONTEXT_HDL ) ) == TRUE )
|
|
{
|
|
expr_node * pExpr;
|
|
expr_proc_call * pProc = new expr_proc_call( "NDRSContextValue" );
|
|
|
|
pProc->SetParam( new expr_param( GetResource() ) );
|
|
|
|
// cast the proc call to this type.
|
|
|
|
pExpr = MakeDerefExpressionOfCastPtrToType( GetType(), pProc );
|
|
|
|
pReturnExpr = pExpr;
|
|
}
|
|
else
|
|
pReturnExpr = GetResource();
|
|
|
|
return pReturnExpr;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_CALLBACK_PROC::GenClientStub( CCB * pCCB )
|
|
{
|
|
CGSIDE Side = pCCB->GetCodeGenSide();
|
|
|
|
pCCB->GetInterfaceCG()->SetDispatchTBLPtrForCallback();
|
|
pCCB->SetInCallback();
|
|
CG_PROC::GenServerStub( pCCB );
|
|
pCCB->ClearInCallback();
|
|
pCCB->GetInterfaceCG()->RestoreDispatchTBLPtr();
|
|
|
|
pCCB->SetCodeGenSide( Side );
|
|
return CG_OK;
|
|
}
|
|
|
|
CG_STATUS
|
|
CG_CALLBACK_PROC::GenServerStub( CCB * pCCB )
|
|
{
|
|
CGSIDE Side = pCCB->GetCodeGenSide();
|
|
|
|
pCCB->GetInterfaceCG()->SetDispatchTBLPtrForCallback();
|
|
pCCB->SetInCallback();
|
|
CG_PROC::GenClientStub( pCCB );
|
|
pCCB->ClearInCallback();
|
|
pCCB->GetInterfaceCG()->RestoreDispatchTBLPtr();
|
|
pCCB->SetCodeGenSide( Side );
|
|
return CG_OK;
|
|
}
|
|
|
|
void
|
|
CG_PROC::GetCorrectAllocFreeRoutines(
|
|
CCB * pCCB,
|
|
BOOL fServer,
|
|
char ** ppAllocName,
|
|
char ** ppFreeName )
|
|
/*++
|
|
Finds out correct Alloc and Free routine names, depending on the mode
|
|
(osf vs. msft) and need to enable memory management.
|
|
|
|
In object mode:
|
|
use NdrOleAllocate, NdrOleFree
|
|
|
|
In ms_ext mode and c-ext:
|
|
unless forced to enable allocate, use MIDL_user_*
|
|
|
|
In osf mode:
|
|
client always uses NdrRpcSsClient*
|
|
server use a default allocator or RpcSsAllocate.
|
|
|
|
++*/
|
|
{
|
|
*ppAllocName = (char *) DEFAULT_ALLOC_RTN_NAME; // MIDL_user_allocate
|
|
*ppFreeName = (char *) DEFAULT_FREE_RTN_NAME; // MIDL_user_free
|
|
|
|
if ( IsObject() )
|
|
{
|
|
*ppAllocName = (char *) OLE_ALLOC_RTN_NAME; // NdrOleAllocate
|
|
*ppFreeName = (char *) OLE_FREE_RTN_NAME; // NdrOleFree
|
|
}
|
|
else if ( MustInvokeRpcSSAllocate() )
|
|
{
|
|
// This means: msft mode - only when forced to enable
|
|
// osf mode - when there is a need or forced to.
|
|
|
|
if ( fServer )
|
|
{
|
|
*ppAllocName = (char *) RPC_SS_SERVER_ALLOCATE_RTN_NAME;
|
|
*ppFreeName = (char *) RPC_SS_SERVER_FREE_RTN_NAME;
|
|
}
|
|
else
|
|
{
|
|
*ppAllocName = (char *) RPC_SM_CLIENT_ALLOCATE_RTN_NAME;
|
|
*ppFreeName = (char *) RPC_SM_CLIENT_FREE_RTN_NAME;
|
|
}
|
|
}
|
|
else
|
|
if ( pCCB->GetMode() == 0 )
|
|
{
|
|
// osf, without having to enable memory manager
|
|
|
|
if ( fServer )
|
|
{
|
|
*ppAllocName = (char *) DEFAULT_ALLOC_OSF_RTN_NAME;
|
|
*ppFreeName = (char *) DEFAULT_FREE_OSF_RTN_NAME;
|
|
}
|
|
else
|
|
{
|
|
*ppAllocName = (char *) RPC_SM_CLIENT_ALLOCATE_RTN_NAME;
|
|
*ppFreeName = (char *) RPC_SM_CLIENT_FREE_RTN_NAME;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GenCorrInit (
|
|
CCB* pCCB
|
|
)
|
|
{
|
|
ISTREAM* pStream = pCCB->GetStream();
|
|
ITERATOR ParamList;
|
|
|
|
// _StubMsg
|
|
expr_node* pExpr = pCCB->GetStandardResource( ST_RES_STUB_MESSAGE_VARIABLE );
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PSTUB_MESSAGE_TYPE_NAME, pExpr );
|
|
ITERATOR_INSERT( ParamList, pExpr );
|
|
|
|
// _Cache
|
|
pExpr = pCCB->GetLocalResource( NDR_CORR_CACHE_VAR_NAME );
|
|
ITERATOR_INSERT( ParamList, pExpr );
|
|
|
|
// _CacheSize
|
|
unsigned long ulSize = NDR_CORR_CACHE_SIZE * sizeof( unsigned long );
|
|
pExpr = new expr_constant( ulSize );
|
|
ITERATOR_INSERT( ParamList, pExpr );
|
|
|
|
// _Flags
|
|
pExpr = new expr_constant( unsigned long( 0 ) );
|
|
ITERATOR_INSERT( ParamList, pExpr );
|
|
|
|
expr_proc_call* pProcCall = MakeProcCallOutOfParamExprList (
|
|
CSTUB_CORR_INIT_RTN_NAME,
|
|
0,
|
|
ParamList
|
|
);
|
|
pStream->NewLine();
|
|
pProcCall->PrintCall( pStream, 0, 0 );
|
|
pStream->NewLine();
|
|
}
|
|
|
|
void
|
|
GenCorrPassFree (
|
|
CCB* pCCB,
|
|
char* szRtn
|
|
)
|
|
{
|
|
ISTREAM* pStream = pCCB->GetStream();
|
|
expr_node* pExpr = pCCB->GetStandardResource( ST_RES_STUB_MESSAGE_VARIABLE );
|
|
|
|
pExpr = MakeAddressExpressionNoMatterWhat( pExpr );
|
|
pExpr = MakeExpressionOfCastToTypeName( PSTUB_MESSAGE_TYPE_NAME, pExpr );
|
|
|
|
ITERATOR ParamList;
|
|
ITERATOR_INSERT( ParamList, pExpr );
|
|
|
|
expr_proc_call* pProcCall = MakeProcCallOutOfParamExprList (
|
|
szRtn,
|
|
0,
|
|
ParamList
|
|
);
|
|
pStream->NewLine();
|
|
pProcCall->PrintCall( pStream, 0, 0 );
|
|
pStream->NewLine();
|
|
}
|