windows-nt/Source/XPSP1/NT/com/rpc/midl/codegen/ccb.cxx
2020-09-26 16:20:57 +08:00

2123 lines
57 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
ccb.cxx
Abstract:
Some method implementations of the ccb code generation class.
Notes:
History:
Sep-20-1993 VibhasC Created.
----------------------------------------------------------------------------*/
#pragma warning ( disable : 4505 )
/****************************************************************************
* include files
***************************************************************************/
#include "becls.hxx"
#pragma hdrstop
extern CMD_ARG * pCommand;
/****************************************************************************
* local definitions
***************************************************************************/
/****************************************************************************
* local data
***************************************************************************/
/****************************************************************************
* externs
***************************************************************************/
/****************************************************************************/
CCB::CCB(
PNAME pGBRtnName,
PNAME pSRRtnName,
PNAME pFBRtnName,
OPTIM_OPTION OptimOption,
BOOL fManagerEpv,
BOOL fNoDefEpv,
BOOL fOldNames,
unsigned long Mode,
BOOL fRpcSSSwitchSetInCompiler,
BOOL fMustCheckAllocError,
BOOL fCheckRef,
BOOL fCheckEnum,
BOOL fCheckBounds,
BOOL fCheckStubData )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Arguments:
pGBRtnName - default get buffer routine name
pSRRtnName - default send receive routine name
pFBRtnName - default free buffer routine name
OptimOption - optimisation options.
fManagerEpvFlag - manager epv flag.
fOldNames - Do we want MIDL 1.0 style names.
fNoDefEpv - we dont want a default epv generated.
Mode - Compiler mode : 0 for osf, 1 for ms_ext
fRpcSSSwitchSetInCompiler - corresponds to -rpcss enabled
fMustCheckAllocError - corresponds to -error allocation on command line
fCheckRef - Check ref pointers
fCheckEnum - Check enums
fCheckBounds - Check array bounds.
fCheckStubData - Check for bad stub data.
Return Value:
Notes:
If the manager epv was set, then we generate the epv calls. Else produce
statically linked stubs (default behaviour).
----------------------------------------------------------------------------*/
{
SetStream( 0, NULL );
SetOptimOption( OptimOption );
// We can't use SetRuntimeRtnNames here because if any of the names
// are NULL the member won't get initialized. This also make the
// existing version of SetRuntimeRtnNames obsolete.
pGetBufferRtnName = pGBRtnName;
pSendReceiveRtnName = pSRRtnName;
pFreeBufferRtnName = pFBRtnName;
// These don't appear to be used
pIUnknownCG = 0;
pIClassfCG = 0;
pStubDescResource = 0;
// These all seem to be lazily initialized so strictly speaking they don't
// need to be initialized here but it's lots safer
EmbeddingLevel = 0;
IndirectionLevel = 0;
fDeferPointee = 0;
fAtLeastOneDeferredPointee = 0;
fMemoryAllocDone = 0;
fRefAllocDone = 0;
fReturnContext = 0;
pInterfaceCG = 0;
pFileCG = 0;
pInterfaceName = 0;
MajorVersion = 0;
MinorVersion = 0;
CurrentProcNum = 0;
CurrentVarNum = 0;
RpcFlags = 0;
pAllocRtnName = 0;
pFreeRtnName = 0;
pResDictDatabase = 0;
pCurrentSizePointer = 0;
lcid = 0;
// There is no "uninitialized" value to set CodeGenPhase and CodeGenSide
// to nor any logical value to initialize them to at this point. Manual
// inspection seems to indicate that they are properly set as needed.
// CodeGenPhase = ??
// CodeGenSide = ??
//
// GetPtrToPtrInBuffer is used in CG_POINTER::PointerChecks but nobody
// seems to call SetPtrInPtrInBuffer so this may be dead wood
//
PtrToPtrInBuffer = 0;
pFormatString = NULL;
pProcFormatString = NULL;
pExprFormatString = NULL;
pGenericHandleRegistry = new TREGISTRY;
pContextHandleRegistry = new TREGISTRY;
pPresentedTypeRegistry = new TREGISTRY;
pRepAsWireTypeRegistry = new TREGISTRY;
pQuintupleRegistry = new TREGISTRY;
pExprEvalRoutineRegistry= new TREGISTRY;
pSizingRoutineRegistry = new TREGISTRY;
pMarshallRoutineRegistry= new TREGISTRY;
pUnMarshallRoutineRegistry = new TREGISTRY;
pFreeRoutineRegistry = new TREGISTRY;
pMemorySizingRoutineRegistry = new TREGISTRY;
pTypeAlignSizeRegistry = new TREGISTRY;
pTypeEncodeRegistry = new TREGISTRY;
pTypeDecodeRegistry = new TREGISTRY;
pTypeFreeRegistry = new TREGISTRY;
pPickledTypeList = new IndexedList;
pProcEncodeDecodeRegistry= new TREGISTRY;
pCallAsRoutineRegistry = new TREGISTRY;
pRecPointerFixupRegistry = NULL;
SetImplicitHandleIDNode( 0 );
SetCGNodeContext( NULL );
pCurrentRegionField = NULL;
SetLastPlaceholderClass( NULL );
SetPrefix( 0 );
pGenericIndexMgr = new CCB_RTN_INDEX_MGR();
pContextIndexMgr = new CCB_RTN_INDEX_MGR();
pExprEvalIndexMgr = new CCB_RTN_INDEX_MGR();
pExprFrmtStrIndexMgr = NULL;
pTransmitAsIndexMgr = new CCB_RTN_INDEX_MGR();
pRepAsIndexMgr = new CCB_RTN_INDEX_MGR();
pQuintupleDictionary = new QuintupleDict;
pQuadrupleDictionary = new QuadrupleDict;
pRepAsPadExprDictionary = new RepAsPadExprDict();
pRepAsSizeDictionary = new RepAsSizeDict();
SetImbedingMemSize(0);
SetImbedingBufSize(0);
ClearInCallback();
fMEpV = fManagerEpv;
fNoDefaultEpv = fNoDefEpv;
fInterpretedRoutinesUseGenHandle = 0;
ClearOptionalExternFlags();
fSkipFormatStreamGeneration = 1;
SetOldNames( (fOldNames == TRUE) ? 1 : 0 );
SetMode( Mode );
SetInObjectInterface( FALSE );
SetRpcSSSwitchSet( fRpcSSSwitchSetInCompiler );
SetMustCheckAllocationError( fMustCheckAllocError );
SetMustCheckRef( fCheckRef );
SetMustCheckEnum( fCheckEnum );
SetMustCheckBounds( fCheckBounds );
SetMustCheckStubData( fCheckStubData );
pCreateTypeLib = NULL;
pCreateTypeInfo = NULL;
szDllName = NULL;
SetInDispinterface(FALSE);
SetCurrentParam( 0 );
SetInterpreterOutSize( 0 );
SetNdr64Format( NULL );
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
These routines simply bounce to the file level routines. They really
should be inline but the depencies between ccb.hxx and filecls.cxx are
really ugly and I haven't figured them out yet
----------------------------------------------------------------------------*/
BOOL CCB::GetMallocAndFreeStructExternEmitted()
{
return pFile->GetMallocAndFreeStructExternEmitted();
}
void CCB::SetMallocAndFreeStructExternEmitted()
{
pFile->SetMallocAndFreeStructExternEmitted();
}
char *
CCB::GenMangledName()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Given an input name, mangle it with the interface name and version.
Arguments:
Return Value:
A pointer to allocated string containing the complete mangled string.
Notes:
This is how the mangling takes place:
<interface-name>_v<Major>_<Minor>_<pInputName>
This is what is returned by the routine:
"v<Major>_<Minor>"
or
""
----------------------------------------------------------------------------*/
{
static char TempBuf[30];
unsigned short M,m;
GetVersion( &M, &m );
if( IsOldNames() )
{
TempBuf[ 0 ] = '\0';
}
else
{
sprintf( TempBuf,
"_v%d_%d",
M,
m );
}
return TempBuf;
}
RESOURCE *
CCB::GetStandardResource(
STANDARD_RES_ID ResID )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Search for a resource with a standard name.
Arguments:
ResID - The standard resource ID.
Return Value:
Notes:
Translate the enum to the name. Search in all dictionaries.
----------------------------------------------------------------------------*/
{
PNAME pName;
RESOURCE * pResource;
static char * LocalResIDToResName[] =
{
RPC_MESSAGE_VAR_NAME
,STUB_MESSAGE_VAR_NAME
,GetInterfaceCG()->GetStubDescName()
,BUFFER_POINTER_VAR_NAME
,RPC_STATUS_VAR_NAME
,LENGTH_VAR_NAME
,BH_LOCAL_VAR_NAME
,PXMIT_VAR_NAME
};
static char * ParamResIDToResName[] =
{
PRPC_MESSAGE_VAR_NAME
};
static char * GlobalResIDToResName[] =
{
AUTO_BH_VAR_NAME
};
if( IS_STANDARD_LOCAL_RESOURCE( ResID ) )
{
pName = LocalResIDToResName[ ResID - ST_LOCAL_RESOURCE_START ];
}
else if( IS_STANDARD_PARAM_RESOURCE( ResID ) )
{
pName = ParamResIDToResName[ ResID - ST_PARAM_RESOURCE_START ];
}
else if( IS_STANDARD_GLOBAL_RESOURCE( ResID ) )
{
pName = GlobalResIDToResName[ ResID - ST_GLOBAL_RESOURCE_START ];
}
#if defined(MIDL_ENABLE_ASSERTS)
else MIDL_ASSERT(0);
#endif
if ( ( pResource = GetResDictDatabase()->GetLocalResourceDict()->Search( pName ) ) == 0 )
{
if ( ( pResource = GetResDictDatabase()->GetParamResourceDict()->Search( pName ) ) == 0)
{
if ( (pResource = GetResDictDatabase()->GetTransientResourceDict()->Search(pName) ) == 0)
{
if ( ( pResource=GetResDictDatabase()->GetGlobalResourceDict()->Search(pName) ) == 0 )
return 0;
}
}
}
return pResource;
}
RESOURCE *
CCB::DoAddResource(
RESOURCE_DICT * pResDict,
PNAME pName,
node_skl * pType )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Add a resource to a dictionary.
Arguments:
pResDict - A pointer to the resource dictionary.
pName - The resource name.
pType - The type of the resource.
Return Value:
Notes:
If the type of the resource does not indicate a param node, assume it
is an ID node and create an id node for it.
----------------------------------------------------------------------------*/
{
RESOURCE * pRes;
if( (pRes = pResDict->Search( pName )) == 0 )
{
pRes = pResDict->Insert( pName, pType );
}
return pRes;
}
RESOURCE *
CCB::SetStubDescResource()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Set up the stub descriptor resource.
Arguments:
None.
Return Value:
None.
Notes:
----------------------------------------------------------------------------*/
{
node_id * pStubDescVar = new node_id( GetInterfaceCG()->GetStubDescName() );
pStubDescVar->SetBasicType( (node_skl *)
new node_def( STUB_DESC_STRUCT_TYPE_NAME ) );
pStubDescVar->SetEdgeType( EDGE_USE );
pStubDescResource = new RESOURCE( GetInterfaceCG()->GetStubDescName(),
(node_skl *)pStubDescVar );
return pStubDescResource;
}
void
CCB::OutputRundownRoutineTable()
{
OutputSimpleRoutineTable( pContextIndexMgr,
RUNDOWN_ROUTINE_TABLE_TYPE,
RUNDOWN_ROUTINE_TABLE_VAR );
}
void
CCB::OutputExprEvalRoutineTable()
{
OutputSimpleRoutineTable( pExprEvalIndexMgr,
EXPR_EVAL_ROUTINE_TABLE_TYPE,
EXPR_EVAL_ROUTINE_TABLE_VAR );
}
void
CCB::OutputSimpleRoutineTable(
CCB_RTN_INDEX_MGR * pIndexMgr,
char * pTableTypeName,
char * pTableVarName
)
{
long i;
char * pName;
pStream->NewLine();
pStream->Write( "static const " );
pStream->Write( pTableTypeName );
pStream->Write( ' ' );
pStream->Write( pTableVarName );
pStream->Write( "[] = ");
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
for ( i = 1; ( pName = pIndexMgr->Lookup(i) ) != 0 ; i++ )
{
if ( i != 1 )
pStream->Write( ',' );
pStream->Write( pName );
pStream->NewLine();
}
pStream->Write( "};" );
pStream->IndentDec();
pStream->NewLine( 2 );
}
void
CCB::OutputOldExprEvalRoutine(EXPR_EVAL_CONTEXT *pExprEvalContext)
{
CG_NDR * pContainer = pExprEvalContext->pContainer;
expr_node * pMinExpr = pExprEvalContext->pMinExpr;
expr_node * pSizeExpr = pExprEvalContext->pSizeExpr;
char * pRoutineName= pExprEvalContext->pRoutineName;
unsigned long Displacement= pExprEvalContext->Displacement;
pStream = GetStream();
// generate the header of the evaluation routine
pStream->NewLine();
pStream->Write( "static void __RPC_USER " );
pStream->Write( pRoutineName );
pStream->Write( "( PMIDL_STUB_MESSAGE pStubMsg )" );
pStream->NewLine();
pStream->Write( '{');
pStream->IndentInc();
pStream->NewLine();
//
// Get the proper struct type.
//
char * pContainerTypeName = 0;
MIDL_ASSERT( pContainer->IsStruct() || pContainer->IsProc() );
if ( pContainer->IsProc() )
{
MIDL_ASSERT( GetOptimOption() | OPTIMIZE_INTERPRETER );
SetCGNodeContext( pContainer );
((CG_PROC *)pContainer)->GenNdrInterpreterParamStruct( this );
pContainerTypeName = PARAM_STRUCT_TYPE_NAME;
}
else
{
pContainerTypeName = ((CG_STRUCT *)pContainer)->
GetType()->GetSymName();
}
expr_node * pExpr = new expr_variable( "pStubMsg->StackTop" );
if ( Displacement )
{
expr_constant * pConstExpr =
new expr_constant( (long) Displacement );
expr_op_binary * pSubtrExpr = new expr_op_binary( OP_MINUS,
pExpr,
pConstExpr );
pExpr = pSubtrExpr;
}
//
// Don't change this call - Dave.
//
node_id * pId;
if ( pContainer->IsProc() )
{
pId = MakePtrIDNodeFromTypeNameWithCastedExpr(
"pS",
pContainerTypeName,
pExpr );
}
else
{
pId = MakePtrIDNodeWithCastedExpr(
"pS",
pContainer->GetType(),
pExpr );
}
pId->PrintType( PRT_ID_DECLARATION, pStream );
pStream->NewLine();
// generate calculation for the Offset field
char TotalPrefix[256];
strcpy( TotalPrefix, "pS->" );
strcat( TotalPrefix, pExprEvalContext->pPrintPrefix );
pStream->Write( "pStubMsg->Offset = " );
if ( pMinExpr )
{
pMinExpr->PrintWithPrefix( pStream, TotalPrefix );
pStream->Write( ';' );
}
else
pStream->Write( "0;" );
pStream->NewLine();
// generate calculation for MaxCount.
if ( pCommand->Is64BitEnv() )
{
// pStubMsg->MaxCount = (ULONG_PTR) ...
pStream->Write( "pStubMsg->MaxCount = (ULONG_PTR) ( " );
}
else
{
// pStubMsg->MaxCount = ( unsigned long ) ...
pStream->Write( "pStubMsg->MaxCount = ( unsigned long ) ( " );
}
pSizeExpr->PrintWithPrefix( pStream, TotalPrefix );
pStream->Write( " );" );
/***
*** Let's leave this out as the default for now. This means first_is() with
last_is() is broken, but first_is() with length_is() will work.
if ( pMinExpr )
{
pStream->Write( " - pStubMsg->Offset;" );
}
else
pStream->Write( ";" );
***
***/
// generate the closing of the evaluation routine
pStream->IndentDec();
pStream->NewLine();
pStream->Write( '}' );
pStream->NewLine();
}
void
CCB::OutputRegisteredExprEvalRoutines()
{
ITERATOR RegisteredRoutines;
EXPR_EVAL_CONTEXT * pExprEvalContext;
GetListOfExprEvalRoutines( RegisteredRoutines);
while ( ITERATOR_GETNEXT( RegisteredRoutines, pExprEvalContext ) )
{
OutputOldExprEvalRoutine(pExprEvalContext);
}
}
void
CCB::OutputExpressionFormatString()
{
CCB_EXPR_INDEX_MGR * pIndexMgr = GetExprFrmtStrIndexMgr();
char Buf[200];
pStream->NewLine();
pStream->Write("static const unsigned short "EXPR_FORMAT_STRING_OFFSET_TABLE "[] =") ;
pStream->NewLine();
pStream->Write("{");
pStream->NewLine();
for (long i = 1; i < pIndexMgr->GetIndex(); i++)
{
pStream->Write( MIDL_ITOA(pIndexMgr->GetOffset(i), Buf, 10 ) );
pStream->NewLine();
}
pStream->Write("};");
pStream->NewLine();
// GetExprFormatString()->OutputExprEvalFormatString(GetStream());
}
// ========================================================================
// user_marshall Quadruple table
// ========================================================================
void
CCB::OutputQuadrupleTable()
{
static char * QuadrupleNames[] =
{
USER_MARSHAL_SIZE,
USER_MARSHAL_MARSHALL,
USER_MARSHAL_UNMARSHALL,
USER_MARSHAL_FREE
};
static char * Ndr64QuadrupleNames[] =
{
NDR64_USER_MARSHAL_SIZE,
NDR64_USER_MARSHAL_MARSHALL,
NDR64_USER_MARSHAL_UNMARSHALL,
NDR64_USER_MARSHAL_FREE
};
long NoOfEntries = GetQuadrupleDictionary()->GetCount();
pStream->NewLine();
pStream->Write("static const " USER_MARSHAL_ROUTINE_TABLE_TYPE );
if ( pCommand->IsNDR64Run() )
{
pStream->Write( " " NDR64_USER_MARSHAL_ROUTINE_TABLE_VAR
"[ " WIRE_MARSHAL_TABLE_SIZE " ] = " );
}
else
{
pStream->Write( " " USER_MARSHAL_ROUTINE_TABLE_VAR
"[ " WIRE_MARSHAL_TABLE_SIZE " ] = " );
}
pStream->IndentInc();
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->IndentInc();
pStream->NewLine();
USER_MARSHAL_CONTEXT * * QuadrupleLookupTable;
USER_MARSHAL_CONTEXT * pQContext;
int i;
QuadrupleLookupTable = new USER_MARSHAL_CONTEXT *[ NoOfEntries ];
ITERATOR Quadruples;
GetQuadrupleDictionary()->GetListOfItems( Quadruples );
for ( i = 0;
ITERATOR_GETNEXT( Quadruples, pQContext );
i++ )
{
MIDL_ASSERT( pQContext->Index < NoOfEntries && "look up index violation" );
QuadrupleLookupTable[ pQContext->Index ] = pQContext;
}
MIDL_ASSERT( i == NoOfEntries );
ISTREAM * pStream = GetStream();
for ( i = 0; i < NoOfEntries; i++ )
{
pQContext = QuadrupleLookupTable[i];
if ( i )
pStream->Write( ',' );
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
for ( int FuncNo = 0; FuncNo < 4; FuncNo++)
{
if ( FuncNo )
pStream->Write( ',' );
pStream->Write( pQContext->pTypeName );
if ( pCommand->IsNDR64Run() )
pStream->Write( Ndr64QuadrupleNames[ FuncNo ] );
else
pStream->Write( QuadrupleNames[ FuncNo ] );
pStream->NewLine();
}
pStream->Write( '}' );
}
pStream->IndentDec();
pStream->NewLine( 2 );
pStream->Write( "};" );
pStream->IndentDec();
pStream->IndentDec();
pStream->NewLine( 2 );
delete QuadrupleLookupTable;
}
// =======================================================================
// International character sizing/conversion routine table
// =======================================================================
void CCB::OutputCsRoutineTables()
{
char *pRoutineSuffix[4] =
{
CS_NET_SIZE,
CS_TO_NET_CS,
CS_LOCAL_SIZE,
CS_FROM_NET_CS
};
//
// Output the sizing/conversion routines table
//
pStream->Write( CS_SIZE_CONVERT_ROUTINE_TABLE_TYPE );
pStream->Write( ' ' );
pStream->Write( CS_SIZE_CONVERT_ROUTINE_TABLE_VAR );
pStream->Write( "[] =" );
pStream->IndentInc();
pStream->WriteOnNewLine( '{' );
pStream->IndentInc();
PNAME pType;
bool fFirst = true;
ITERATOR_INIT( CsTypes );
while ( ITERATOR_GETNEXT( CsTypes, pType ) )
{
if ( ! fFirst )
pStream->Write( ',' );
pStream->WriteOnNewLine( '{' );
for (int i = 0; i < 4; i++ )
{
pStream->WriteOnNewLine( pType );
pStream->Write( pRoutineSuffix[i] );
pStream->Write( ',' );
}
pStream->WriteOnNewLine( '}' );
fFirst = false;
}
pStream->IndentDec();
pStream->WriteOnNewLine( "};" );
pStream->IndentDec();
pStream->NewLine();
//
// Output the tag routines table
//
if ( 0 != CsTagRoutines.GetCount() )
{
pStream->WriteOnNewLine( CS_TAG_ROUTINE_TABLE_TYPE );
pStream->Write( ' ' );
pStream->Write( CS_TAG_ROUTINE_TABLE_VAR );
pStream->Write( "[] =" );
pStream->IndentInc();
pStream->WriteOnNewLine( '{' );
fFirst = true;
ITERATOR_INIT( CsTagRoutines );
while ( ITERATOR_GETNEXT( CsTagRoutines, pType ) )
{
if ( ! fFirst )
pStream->Write( ',' );
pStream->WriteOnNewLine( pType );
fFirst = false;
}
pStream->WriteOnNewLine( "};" );
pStream->IndentDec();
pStream->NewLine();
}
//
// Output the pointers-to-tables structure
//
pStream->WriteOnNewLine( CS_ROUTINE_TABLES_TYPE );
pStream->Write( ' ' );
pStream->Write( CS_ROUTINE_TABLES_VAR );
pStream->Write( " =" );
pStream->IndentInc();
pStream->WriteOnNewLine( '{' );
pStream->WriteOnNewLine( CS_SIZE_CONVERT_ROUTINE_TABLE_VAR );
pStream->Write( ',' );
pStream->WriteOnNewLine( ( 0 != CsTagRoutines.GetCount() )
? CS_TAG_ROUTINE_TABLE_VAR
: "0" );
pStream->WriteOnNewLine( "};" );
pStream->IndentDec();
pStream->NewLine();
}
// =======================================================================
// Transmit as and Represent As tables.
// =======================================================================
char *
MakeAnXmitName(
char * pTypeName,
char * pRoutineName,
unsigned short )
/*++
makes the following name: <type_name>_<routine_name>_<index>
--*/
{
MIDL_ASSERT( pTypeName && pRoutineName );
char * pXmitName = new char[ strlen(pTypeName) +
strlen(pRoutineName) + 1 ];
strcpy( pXmitName, pTypeName );
strcat( pXmitName, pRoutineName );
return( pXmitName );
}
#define QUINTUPLE_SIZE 4
typedef struct _QUINTUPLE_NAMES
{
char * TableType;
char * TableVar;
char * FuncName[ QUINTUPLE_SIZE ];
} QUINTUPLE_NAMES;
void
CCB::OutputQuintupleTable()
{
static QUINTUPLE_NAMES TransmitNames =
{
XMIT_AS_ROUTINE_TABLE_TYPE,
XMIT_AS_ROUTINE_TABLE_VAR,
XMIT_TO_XMIT,
XMIT_FROM_XMIT,
XMIT_FREE_XMIT,
XMIT_FREE_INST
};
static QUINTUPLE_NAMES RepNames=
{
REP_AS_ROUTINE_TABLE_TYPE,
REP_AS_ROUTINE_TABLE_VAR,
REP_FROM_LOCAL,
REP_TO_LOCAL,
REP_FREE_INST,
REP_FREE_LOCAL
};
long NoOfEntries = GetQuintupleDictionary()->GetCount();
pStream->NewLine();
pStream->Write("static const "XMIT_AS_ROUTINE_TABLE_TYPE );
pStream->Write( " " XMIT_AS_ROUTINE_TABLE_VAR
"[ " TRANSMIT_AS_TABLE_SIZE " ] = " );
pStream->IndentInc();
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->IndentInc();
pStream->NewLine();
// Now construct a lookup table with entries in the order of indexes.
// (we have to keep index managers separate for rep_as and xmit_as
// and we still have a common table)
XMIT_AS_CONTEXT * * QuintupleLookupTable;
XMIT_AS_CONTEXT * pQContext;
int i;
QuintupleLookupTable = new XMIT_AS_CONTEXT *[ NoOfEntries ];
ITERATOR Quintuples;
GetListOfQuintuples( Quintuples );
for ( i = 0;
ITERATOR_GETNEXT( Quintuples, pQContext );
i++ )
{
MIDL_ASSERT( pQContext->Index < NoOfEntries && "look up index violation" );
QuintupleLookupTable[ pQContext->Index ] = pQContext;
}
ISTREAM * pStream = GetStream();
for ( i = 0; i < NoOfEntries; i++ )
{
pQContext = QuintupleLookupTable[i];
char * pName = pQContext->fXmit
? pQContext->pTypeName
: ((CG_REPRESENT_AS *)pQContext->pXmitNode)->
GetTransmittedType()->GetSymName();
unsigned short Index = pQContext->Index;
MIDL_ASSERT( (i == Index) && " xmit index violation" );
QUINTUPLE_NAMES * pQNames = pQContext->fXmit ? & TransmitNames
: & RepNames;
if ( i )
pStream->Write( ',' );
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
for ( int FuncNo = 0; FuncNo < QUINTUPLE_SIZE; FuncNo++)
{
char * pTempName = MakeAnXmitName( pName,
pQNames->FuncName[ FuncNo ],
Index );
if ( FuncNo )
pStream->Write( ',' );
pStream->Write( pTempName );
pStream->NewLine();
delete pTempName;
}
pStream->Write( '}' );
}
pStream->IndentDec();
pStream->NewLine( 2 );
pStream->Write( "};" );
pStream->IndentDec();
pStream->IndentDec();
pStream->NewLine( 2 );
delete QuintupleLookupTable;
}
// =======================================================================
// helpers for Transmit as and Represent As routines
// =======================================================================
static void
OpenXmitOrRepRoutine(
ISTREAM * pStream,
char * pName )
/*++
Routine description:
This routine emits the header of a *_as helper routine:
void __RPC_API
<name>( PMIDL_STUB_MESSAGE pStubMsg )
{
Note:
There is a side effect here that the name of the routine is deleted
(this is always the name created by a call to MakeAnXmitName).
--*/
{
pStream->Write ( "NDR_SHAREABLE void __RPC_USER" );
pStream->NewLine();
pStream->Write ( pName );
pStream->Write ( "( PMIDL_STUB_MESSAGE pStubMsg )" );
pStream->NewLine();
pStream->Write( '{');
pStream->IndentInc();
pStream->NewLine();
delete pName;
}
static void
CloseXmitOrRepRoutine(
ISTREAM * pStream )
/*++
Routine description:
Just a complement to the OpenXmitOrRepRoutine:
}
--*/
{
pStream->IndentDec();
pStream->NewLine();
pStream->Write( '}');
pStream->NewLine();
}
static void
OutputPresentedTypeInit(
ISTREAM * pStream,
char * pPresentedTypeName )
/*++
Routine description:
Emits
memset( pStubMsg->pPresentedType, 0, sizeof( <presented type> ));
--*/
{
pStream->NewLine();
pStream->Write( MIDL_MEMSET_RTN_NAME "( "PSTUB_MESSAGE_PAR_NAME"->pPresentedType, 0, sizeof(" );
pStream->Write( pPresentedTypeName );
pStream->Write( " ));" );
}
static void
OutputCastedPtr(
ISTREAM * pStream,
char * pTypeName,
char * pVarName )
{
pStream->Write( '(' );
pStream->Write( pTypeName );
pStream->Write( " *) " );
pStream->Write( pVarName );
}
// =======================================================================
// Transmit as
// =======================================================================
//
// The presented type size problem.
// The engine doesn't use pStubMsg->PresentedTypeSize field anymore.
// The presented type size nowadays is passed within the format code.
//
static void
OutputToXmitCall(
ISTREAM * pStream,
char * pPresentedTypeName,
char * pTransmitTypeName )
{
pStream->Write( pPresentedTypeName );
pStream->Write( "_to_xmit( " );
OutputCastedPtr( pStream,
pPresentedTypeName,
PSTUB_MESSAGE_PAR_NAME"->pPresentedType, " );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '(' );
pStream->Write( pTransmitTypeName );
pStream->Write( " * *) &pStubMsg->pTransmitType );" );
pStream->IndentDec();
// pStream->NewLine();
}
static void
OutputFreeXmitCall(
ISTREAM * pStream,
char * pPresentedTypeName,
char * pTransmitTypeName )
{
pStream->Write( pPresentedTypeName );
pStream->Write( "_free_xmit( " );
OutputCastedPtr( pStream, pTransmitTypeName, "pStubMsg->pTransmitType );" );
}
void
CCB::OutputTransmitAsQuintuple(
void * pQuintupleContext
)
/*++
Routine description:
This routine emits the following helper routines for a transmit as type:
static void __RPC_API
<pres_type>_Xmit_ToXmit_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<pres_type>_to_xmit( (<pres_type> *) pStubMsg->pPresentedType,
(<tran_type> * *) &pStubMsg->pTransmitType );
}
static void __RPC_API
<pres_type>_Xmit_FromXmit_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<pres_type>_from_xmit(
(<tran_type> *) pStubMsg->pTransmitType,
(<pres_type> *) pStubMsg->pPresentedType );
}
static void __RPC_API
<pres_type>_Xmit_FreeXmit_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<pres_type>_free_xmit(
(<tran_type> *) pStubMsg-p>TransmitType );
}
static void __RPC_API
<pres_type>_Xmit_FreeInst_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<pres_type>_free_xmit(
(<pres_type> *) pStubMsg->pPresentedType );
}
--*/
{
XMIT_AS_CONTEXT * pTransmitAsContext = (XMIT_AS_CONTEXT*) pQuintupleContext;
int i = pTransmitAsContext->Index;
ISTREAM * pStream = GetStream();
pStream->NewLine();
CG_TRANSMIT_AS* pXmitNode = (CG_TRANSMIT_AS *)
pTransmitAsContext->pXmitNode;
char * pPresentedTypeName = pXmitNode->GetPresentedType()->GetSymName();
char * pTransmitTypeName = pXmitNode->GetTransmittedType()->
GetSymName();
// *_XmitTranslateToXmit
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pPresentedTypeName,
XMIT_TO_XMIT,
unsigned short(i) ) );
OutputToXmitCall( pStream, pPresentedTypeName, pTransmitTypeName );
CloseXmitOrRepRoutine( pStream );
// *_XmitTranslateFromXmit
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pPresentedTypeName,
XMIT_FROM_XMIT,
unsigned short(i) ) );
pStream->Write( pPresentedTypeName );
pStream->Write( "_from_xmit( " );
OutputCastedPtr( pStream, pTransmitTypeName, "pStubMsg->pTransmitType, " );
pStream->IndentInc();
pStream->NewLine();
OutputCastedPtr( pStream, pPresentedTypeName, "pStubMsg->pPresentedType ); " );
pStream->IndentDec();
CloseXmitOrRepRoutine( pStream );
// *_XmitFreeXmit
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pPresentedTypeName,
XMIT_FREE_XMIT,
unsigned short(i) ) );
OutputFreeXmitCall( pStream, pPresentedTypeName, pTransmitTypeName );
CloseXmitOrRepRoutine( pStream );
// *_XmitFreeInst
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pPresentedTypeName,
XMIT_FREE_INST,
unsigned short(i) ) );
pStream->Write( pPresentedTypeName );
pStream->Write( "_free_inst( " );
OutputCastedPtr( pStream, pPresentedTypeName, "pStubMsg->pPresentedType ); " );
CloseXmitOrRepRoutine( pStream );
}
void
CCB::OutputQuintupleRoutines()
/*++
--*/
{
ITERATOR Quintuples;
XMIT_AS_CONTEXT * pQuintupleContext;
int i;
// Multi-interface problem: This routine is only called after the last
// interface.
GetListOfQuintuples( Quintuples );
for ( i = 1;
ITERATOR_GETNEXT( Quintuples, pQuintupleContext );
i++ )
{
if ( pQuintupleContext->fXmit )
OutputTransmitAsQuintuple( pQuintupleContext );
else
OutputRepAsQuintuple( pQuintupleContext );
}
}
// ========================================================================
// Represent As
// ========================================================================
//
// There is a lot of symmetry between transmit as and represent as.
// We use that where possible. So, among other things there is the following
// mapping between represent as routines and the transmit as ones.
// (So called quintuple actually has 4 routines now.)
//
// wrapers
// pfnTranslateToXmit *_to_xmit *_from_local
// pfnTranslateFromXmit *_from_xmit *_to_local
// pfnFreeXmit *_free_xmit *_free_inst
// pfnFreeInst *_free_inst *_free_local
//
// The presented type size problem.
// This is either known and put into the format code explicitely,
// or unknown and then put there via a C-compile macro.
//
// The presented type alignment problem.
// There is a problem when there is a padding preceding a represent as
// field. The engine needs to know what the alignment for the represent
// as field is. As we may not know its type at the midl compile time,
// the only way to deal with it is to use the parent structure name,
// and the represent as field name.
//
static void
OutputToLocalCall(
ISTREAM * pStream,
char * pLocalTypeName,
char * pTransmitTypeName )
{
pStream->Write( pTransmitTypeName );
pStream->Write( "_to_local( " );
OutputCastedPtr( pStream, pTransmitTypeName,
PSTUB_MESSAGE_PAR_NAME"->pTransmitType, " );
pStream->IndentInc();
pStream->NewLine();
OutputCastedPtr( pStream, pLocalTypeName,
PSTUB_MESSAGE_PAR_NAME"->pPresentedType ); " );
pStream->IndentDec();
}
static void
OutputFromLocalCall(
ISTREAM * pStream,
char * pLocalTypeName,
char * pTransmitTypeName )
{
pStream->Write( pTransmitTypeName );
pStream->Write( "_from_local( " );
OutputCastedPtr( pStream, pLocalTypeName,
PSTUB_MESSAGE_PAR_NAME"->pPresentedType, " );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '(' );
pStream->Write( pTransmitTypeName );
pStream->Write( " * *) &pStubMsg->pTransmitType );" );
pStream->IndentDec();
}
static void
OutputRepAsFreeInstCall(
ISTREAM * pStream,
char * pTransmitTypeName )
{
pStream->Write( pTransmitTypeName );
pStream->Write( "_free_inst( " );
OutputCastedPtr( pStream, pTransmitTypeName,
PSTUB_MESSAGE_PAR_NAME"->pTransmitType );" );
}
void
CCB::OutputRepAsQuintuple(
void * pQuintupleContext
)
/*++
Routine description:
This routine emits the following helper routines for a transmit as type:
static void __RPC_API
<trans_type>_RepAsFromLocal_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<trans_type>_from_local(
(<pres_type> *) pStubMsg->pPresentedType,
(<tran_type> * *) &pStubMsg->pTransmitType );
}
static void __RPC_API
<trans_type>_RepAsToLocal_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<trans_type>_to_local(
(<tran_type> *) pStubMsg->pTransmitType,
(<pres_type> *) pStubMsg->pPresentedType );
}
static void __RPC_API
<trans_type>_RepAsFreeInst_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<trans_type>_free_inst(
(<tran_type> *) pStubMsg-p>TransmitType );
}
static void __RPC_API
<trans_type>_RepAsFreeLocal_<index>( PMIDL_STUB_MESSAGE pStubMsg )
{
<trans_type>_free_local(
(<pres_type> *) pStubMsg->pPresentedType );
}
--*/
{
XMIT_AS_CONTEXT * pRepAsContext = (XMIT_AS_CONTEXT*) pQuintupleContext;
int i = pRepAsContext->Index;
ISTREAM * pStream = GetStream();
CG_REPRESENT_AS * pRepAsNode = (CG_REPRESENT_AS *)
pRepAsContext->pXmitNode;
char * pLocalTypeName = pRepAsNode->GetRepAsTypeName();
char * pTransmitTypeName = pRepAsNode->GetTransmittedType()->
GetSymName();
// *_RepAsTranslateToLocal
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pTransmitTypeName,
REP_TO_LOCAL,
unsigned short(i) ) );
OutputToLocalCall( pStream, pLocalTypeName, pTransmitTypeName );
CloseXmitOrRepRoutine( pStream );
// *_RepAsTranslateFromLocal
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pTransmitTypeName,
REP_FROM_LOCAL,
unsigned short(i) ) );
OutputFromLocalCall( pStream, pLocalTypeName, pTransmitTypeName );
CloseXmitOrRepRoutine( pStream );
// *_RepAsFreeInst
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pTransmitTypeName,
REP_FREE_INST,
unsigned short(i) ) );
OutputRepAsFreeInstCall( pStream, pTransmitTypeName );
CloseXmitOrRepRoutine( pStream );
// *_RepAsFreeLocal
OpenXmitOrRepRoutine( pStream, MakeAnXmitName( pTransmitTypeName,
REP_FREE_LOCAL,
unsigned short(i) ) );
pStream->Write( pTransmitTypeName );
pStream->Write( "_free_local( " );
OutputCastedPtr( pStream, pLocalTypeName, "pStubMsg->pPresentedType ); " );
CloseXmitOrRepRoutine( pStream );
}
// ========================================================================
// end of Transmit As and Represent As
// ========================================================================
BOOL
CCB::HasBindingRoutines( CG_HANDLE * pImplicitHandle )
{
return ! pGenericIndexMgr->IsEmpty() ||
(pImplicitHandle &&
pImplicitHandle->IsGenericHandle());
}
void
CCB::OutputBindingRoutines()
{
long i;
char * pName;
pStream->NewLine();
pStream->Write( "static const " BINDING_ROUTINE_TABLE_TYPE );
pStream->Write( " " BINDING_ROUTINE_TABLE_VAR
"[ " GENERIC_BINDING_TABLE_SIZE " ] = " );
pStream->IndentInc();
pStream->IndentInc();
pStream->NewLine();
pStream->Write( '{' );
pStream->NewLine();
for ( i = 1; ( pName = pGenericIndexMgr->Lookup(i) ) != 0 ; i++ )
{
if ( i != 1 )
pStream->Write( ',' );
pStream->Write( '{' );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( "(" GENERIC_BINDING_ROUTINE_TYPE ")" );
pStream->Write( pName );
pStream->Write( "_bind" );
pStream->Write( ',' );
pStream->NewLine();
pStream->Write( "(" GENERIC_UNBINDING_ROUTINE_TYPE ")" );
pStream->Write( pName );
pStream->Write( "_unbind" );
pStream->IndentDec();
pStream->NewLine();
pStream->Write( " }" );
pStream->NewLine();
}
pStream->NewLine();
pStream->Write( "};" );
pStream->IndentDec();
pStream->IndentDec();
pStream->NewLine();
pStream->NewLine();
}
void
CCB::OutputMallocAndFreeStruct()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Outputs the malloc and free struct for the RpcSsm connection.
This is needed only at the client side and non object interfaces.
If the [enable_allocate] affects a remote routine, the client side stub
defaults to malloc and free when unmarshalling regardless of the
compiler mode (osf vs. non-osf).
Therefore, the structure gets generated:
- always in the osf mode or
- in non-osf when at least one routine is affected by the attribute.
This is one-per-many-interfaces structure.
Because of win16 DS register problems, malloc and free have to be
accessed via wrappers with appropriate calling conventions.
To simplify, we generate wrappers for every platform.
REVIEW: win16 is gone, we should be able to get rid of the wrappers.
----------------------------------------------------------------------------*/
{
// malloc and free wrappers.
pStream->NewLine();
pStream->Write( "static void * __RPC_USER" );
pStream->NewLine();
pStream->Write( GetInterfaceName() );
pStream->Write( "_malloc_wrapper( size_t _Size )" );
pStream->NewLine();
pStream->Write( "{" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( "return( malloc( _Size ) );" );
pStream->IndentDec();
pStream->NewLine();
pStream->Write( "}" );
pStream->NewLine();
pStream->NewLine();
pStream->Write( "static void __RPC_USER" );
pStream->NewLine();
pStream->Write( GetInterfaceName() );
pStream->Write( "_free_wrapper( void * _p )" );
pStream->NewLine();
pStream->Write( "{" );
pStream->IndentInc();
pStream->NewLine();
pStream->Write( "free( _p );" );
pStream->IndentDec();
pStream->NewLine();
pStream->Write( "}" );
pStream->NewLine();
// The structure.
pStream->NewLine();
pStream->Write( "static " MALLOC_FREE_STRUCT_TYPE_NAME );
pStream->Write( " " MALLOC_FREE_STRUCT_VAR_NAME " = ");
pStream->NewLine();
pStream->Write( "{");
pStream->IndentInc();
pStream->NewLine();
pStream->Write( GetInterfaceName() );
pStream->Write( "_malloc_wrapper," );
pStream->NewLine();
pStream->Write( GetInterfaceName() );
pStream->Write( "_free_wrapper" );
pStream->IndentDec();
pStream->NewLine();
pStream->Write( "};" );
pStream->NewLine();
}
// ========================================================================
void
CCB::OutputExternsToMultipleInterfaceTables()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the tables that may be common to multiple interfaces.
Arguments:
pCCB - A pointer to the code gen controller block.
Return Value:
None.
Notes:
----------------------------------------------------------------------------*/
{
CGSIDE Side = GetCodeGenSide();
pStream->NewLine();
//
// Emit extern to the rundown routine table on the server Oi side,
// if needed.
//
if ( (Side == CGSIDE_SERVER) &&
( GetOptimOption() & OPTIMIZE_INTERPRETER) &&
HasRundownRoutines() && ! GetRundownExternEmitted() )
{
pStream->Write( "extern const " RUNDOWN_ROUTINE_TABLE_TYPE );
pStream->Write( " " RUNDOWN_ROUTINE_TABLE_VAR "[];" );
pStream->NewLine();
SetRundownExternEmitted();
}
//
// Emit extern to the binding routine pair table on the client Oi stub
// if needed.
//
if ( (Side == CGSIDE_CLIENT) &&
GetInterpretedRoutinesUseGenHandle() &&
! GetGenericHExternEmitted()
)
{
pStream->Write( "extern const " BINDING_ROUTINE_TABLE_TYPE );
pStream->Write( " " BINDING_ROUTINE_TABLE_VAR
"[ " GENERIC_BINDING_TABLE_SIZE " ];" );
pStream->NewLine();
SetGenericHExternEmitted();
}
//
// Emit extern to the expr eval routine table on both sides.
//
if ( HasExprEvalRoutines() && ! GetExprEvalExternEmitted() )
{
pStream->Write( "extern const " EXPR_EVAL_ROUTINE_TABLE_TYPE );
pStream->Write( " " EXPR_EVAL_ROUTINE_TABLE_VAR "[];" );
pStream->NewLine();
SetExprEvalExternEmitted();
}
//
// Emit extrn to the transmit as and rep as routine table on both sides.
//
if ( HasQuintupleRoutines() && ! GetQuintupleExternEmitted() )
{
pStream->Write( "extern const " XMIT_AS_ROUTINE_TABLE_TYPE );
pStream->Write( " " XMIT_AS_ROUTINE_TABLE_VAR
"[ " TRANSMIT_AS_TABLE_SIZE " ];" );
pStream->NewLine();
SetQuintupleExternEmitted();
}
//
// Emit extrn to the user_marshal routine table on both sides.
//
if ( HasQuadrupleRoutines() && ! GetQuadrupleExternEmitted() )
{
if ( pCommand->NeedsNDR64Run() )
{
pStream->Write( "extern const " USER_MARSHAL_ROUTINE_TABLE_TYPE );
pStream->Write( " " NDR64_USER_MARSHAL_ROUTINE_TABLE_VAR
"[ " WIRE_MARSHAL_TABLE_SIZE " ];" );
pStream->NewLine();
}
if ( pCommand->NeedsNDRRun() )
{
pStream->Write( "extern const " USER_MARSHAL_ROUTINE_TABLE_TYPE );
pStream->Write( " " USER_MARSHAL_ROUTINE_TABLE_VAR
"[ " WIRE_MARSHAL_TABLE_SIZE " ];" );
pStream->NewLine();
}
SetQuadrupleExternEmitted();
}
if ( HasCsTypes() )
{
//
// Emit the international character sizing/conversion routine table
//
OutputCsRoutineTables();
}
}
void
OutputPlatformCheck( ISTREAM * pStream )
/*++
Routine Description :
Outputs an ifdef checking if the platform usage is as expected
Arguments :
pStream - Stream to output the format string to.
--*/
{
pStream->NewLine();
if ( pCommand->GetEnv() == ENV_WIN64 )
{
pStream->Write( "#if !defined(__RPC_WIN64__)" );
}
else
pStream->Write( "#if !defined(__RPC_WIN32__)" );
pStream->NewLine();
pStream->Write( "#error Invalid build platform for this stub." );
pStream->NewLine();
pStream->Write( "#endif" );
pStream->NewLine();
}
const char * Nt51Guard[] =
{
"#if !(TARGET_IS_NT51_OR_LATER)",
"#error You need a Windows XP or later to run this stub because it uses these features:",
0
};
const char * Nt50Guard[] =
{
"",
"#if !(TARGET_IS_NT50_OR_LATER)",
"#error You need a Windows 2000 or later to run this stub because it uses these features:",
0
};
const char * Nt40Guard[] =
{
"",
"#if !(TARGET_IS_NT40_OR_LATER)",
"#error You need a Windows NT 4.0 or later to run this stub because it uses these features:",
0
};
const char * Nt351win95Guard[] =
{
"",
"#if !(TARGET_IS_NT351_OR_WIN95_OR_LATER)",
"#error You need a Windows NT 3.51 or Windows95 or later to run this stub because it uses these features:",
0
};
const char * NtGuardClose[] =
{
"#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems.",
"#error This app will die there with the RPC_X_WRONG_STUB_VERSION error.",
"#endif",
0
};
void
OutputMultilineMessage(
ISTREAM * pStream,
const char * Message[] )
{
for (int i = 0; Message[i]; i++)
{
pStream->Write( Message[i] );
pStream->NewLine();
}
}
// should be local OutputVersion Guard but it can't.
class MessageSet
{
private:
char * Messages[10];
int MessageCount;
ISTREAM * pStream;
public:
MessageSet( ISTREAM * pIStream )
: MessageCount(0),
pStream( pIStream )
{
}
void AddMessage( char * Message )
{
if ( MessageCount < 10 )
Messages[ MessageCount++ ] = Message;
}
void PrintMessages()
{
pStream->Write( "#error " );
for (int i = 0; i < MessageCount; i++ )
{
pStream->Write( Messages[i] );
pStream->Write( (i < MessageCount -1) ? ", "
: ".\n" );
}
}
};
void
OutputNdrVersionGuard( ISTREAM * pStream )
/*++
Routine Description :
Outputs target release guards.
Arguments :
pStream - Stream to output the format string to.
--*/
{
MessageSet Features( pStream );
NdrVersionControl & VC = pCommand->GetNdrVersionControl();
if ( VC.HasNdr60Feature() )
{
OutputMultilineMessage( pStream, Nt51Guard );
if ( VC.HasStructPadN() )
Features.AddMessage( "large structure padding" );
if ( VC.HasForceAllocate() )
Features.AddMessage( "The [force_allocate] attribte" );
if ( VC.HasPartialIgnore() )
Features.AddMessage( "The [partial_ignore] attribute" );
if ( VC.HasMultiTransferSyntax() )
Features.AddMessage( "Uses -protocol all or -protocol ndr64" );
}
else if ( VC.HasNdr50Feature() )
{
OutputMultilineMessage( pStream, Nt50Guard );
if ( VC.HasAsyncHandleRpc() )
Features.AddMessage( "[async] attribute" );
if ( VC.HasNT5VTableSize() )
Features.AddMessage( "more than 110 methods in the interface" );
if ( VC.HasDOA() )
Features.AddMessage( "/robust command line switch" );
if ( VC.HasAsyncUUID() )
Features.AddMessage( "[async_uuid] attribute" );
if ( VC.HasInterpretedNotify() )
Features.AddMessage( "[notify] or [notify_flag] attribute in interpreted mode" );
if ( VC.HasContextSerialization() )
Features.AddMessage( "[serialize] or [noserialize] attribute" );
if ( VC.HasOicfPickling() )
Features.AddMessage( "[encode] or [decode] with -Oicf" );
}
else if ( VC.HasNdr20Feature() )
{
OutputMultilineMessage( pStream, Nt40Guard );
if ( VC.HasOi2() )
Features.AddMessage( "-Oif or -Oicf" );
if ( VC.HasUserMarshal() )
Features.AddMessage( "[wire_marshal] or [user_marshal] attribute" );
if ( VC.HasRawPipes() )
Features.AddMessage( "idl pipes" );
if ( VC.HasMoreThan64DelegatedProcs() )
Features.AddMessage( "more than 64 delegated procs" );
if ( VC.HasFloatOrDoubleInOi() )
Features.AddMessage( "float, double or hyper in -Oif or -Oicf" );
if ( VC.HasMessageAttr() )
Features.AddMessage( "[message] attribute" );
if ( VC.HasNT4VTableSize() )
Features.AddMessage( "more than 32 methods in the interface" );
}
else if ( VC.HasNdr11Feature() )
{
OutputMultilineMessage( pStream, Nt351win95Guard );
if ( VC.HasStublessProxies() )
Features.AddMessage( "old (-Oic) stubless proxies" );
if ( VC.HasCommFaultStatusInOi12() )
Features.AddMessage( "[comm_status] or [fault_status] in an -Oi* mode" );
}
else
return;
Features.PrintMessages();
OutputMultilineMessage( pStream, NtGuardClose );
pStream->NewLine();
}
void
CCB::OutputMultipleInterfaceTables()
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the tables that may be common to multiple interfaces.
Arguments:
Return Value:
None.
Notes:
----------------------------------------------------------------------------*/
{
CGSIDE Side = GetCodeGenSide();
// First, output the platform consistency check.
OutputPlatformCheck( pStream );
// Now, the ndr version guard against usage on old platforms.
if ( pCommand->GetEnv() == ENV_WIN32 )
OutputNdrVersionGuard( pStream );
MIDL_ASSERT( pCommand->IsNDRRun() || pCommand->IsNDR64Run() );
if ( pCommand->IsNDRRun() )
{
if ( pCommand->IsNDRRun() )
GetProcFormatString()->Output( pStream,
PROC_FORMAT_STRING_TYPE_NAME,
PROC_FORMAT_STRING_STRUCT_NAME,
GetRepAsPadExprDict(),
GetRepAsSizeDict() );
FixupRecPointers();
GetFormatString()->Output( pStream,
FORMAT_STRING_TYPE_NAME,
FORMAT_STRING_STRUCT_NAME,
GetRepAsPadExprDict(),
GetRepAsSizeDict() );
}
else
{
// If this is the 64bit transfer syntax run, then the proc and type format strings
// should be NULL.
MIDL_ASSERT( NULL == GetProcFormatString() );
MIDL_ASSERT( NULL == GetFormatString() );
GetNdr64Format()->Output();
}
if ( HasQuadrupleRoutines() )
{
//
// Emit the user_marshall table on both sides.
//
OutputQuadrupleTable();
}
//
// Emit the rundown routine table on the server side, if needed.
//
SetNoOutputIn2ndCodegen( this );
if ( (Side == CGSIDE_SERVER) &&
(GetOptimOption() & OPTIMIZE_INTERPRETER) &&
HasRundownRoutines()
)
{
OutputRundownRoutineTable();
}
//
// Emit the binding routine pair table on the client interpreted stub
// if needed.
//
if ( (Side == CGSIDE_CLIENT) &&
GetInterpretedRoutinesUseGenHandle() )
{
OutputBindingRoutines();
}
if ( HasExprEvalRoutines() )
{
//
// Emit the expr eval routines both sides.
//
OutputRegisteredExprEvalRoutines();
//
// Emit the expr eval routine table on both sides.
//
OutputExprEvalRoutineTable();
}
if ( HasExprFormatString() )
{
OutputExpressionFormatString();
}
if ( HasQuintupleRoutines() )
{
//
// Emit transmit as and represent as routines both sides.
//
OutputQuintupleRoutines();
//
// Emit the xmit as and rep as routine table on both sides.
//
OutputQuintupleTable();
}
if ( GetMallocAndFreeStructExternEmitted() )
{
// This is needed for the RpcSs support.
OutputMallocAndFreeStruct();
}
ResetNoOutputIn2ndCodegen( this );
}
long
CCB_RTN_INDEX_MGR::Lookup( char * pName )
{
long i;
for ( i = 1; i < NextIndex; i++ )
if ( ! strcmp(NameId[i],pName) )
return i;
//
// Insert a new entry
//
MIDL_ASSERT( NextIndex < MGR_INDEX_TABLE_SIZE );
NameId[NextIndex] = new char[strlen(pName) + 1];
strcpy(NameId[NextIndex],pName);
NextIndex++;
return NextIndex - 1;
}
char *
CCB_RTN_INDEX_MGR::Lookup( long Index )
{
if ( Index >= NextIndex )
return NULL;
return NameId[Index];
}
long
CCB_EXPR_INDEX_MGR::Lookup( char * pName )
{
long i;
for ( i = 1; i < NextIndex; i++ )
if ( ! strcmp(NameId[i],pName) )
return i;
//
// Insert a new entry
//
MIDL_ASSERT( NextIndex < MGR_INDEX_TABLE_SIZE );
NameId[NextIndex] = new char[strlen(pName) + 1];
strcpy(NameId[NextIndex],pName);
NextIndex++;
return NextIndex - 1;
}
char *
CCB_EXPR_INDEX_MGR::Lookup( long Index )
{
if ( Index >= NextIndex )
return NULL;
return NameId[Index];
}
PNAME
CCB::GenTRNameOffLastParam( char * pPrefix )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Generate the name for a temporary resource.
Arguments:
pPrefix - A null terminated prefix string. If this is null, nothing is
added.
Return Value:
A freshly allocated resource name string.
Notes:
----------------------------------------------------------------------------*/
{
char TempBuffer[ 30 ];
sprintf( TempBuffer,
"_%sM",
pPrefix ? pPrefix : ""
);
PNAME pName = (PNAME) new char [ strlen(TempBuffer) + 1 ];
strcpy( pName, TempBuffer );
return pName;
}