/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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: _v__ This is what is returned by the routine: "v_" 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: __ --*/ { 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 ( 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( )); --*/ { 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 _Xmit_ToXmit_( PMIDL_STUB_MESSAGE pStubMsg ) { _to_xmit( ( *) pStubMsg->pPresentedType, ( * *) &pStubMsg->pTransmitType ); } static void __RPC_API _Xmit_FromXmit_( PMIDL_STUB_MESSAGE pStubMsg ) { _from_xmit( ( *) pStubMsg->pTransmitType, ( *) pStubMsg->pPresentedType ); } static void __RPC_API _Xmit_FreeXmit_( PMIDL_STUB_MESSAGE pStubMsg ) { _free_xmit( ( *) pStubMsg-p>TransmitType ); } static void __RPC_API _Xmit_FreeInst_( PMIDL_STUB_MESSAGE pStubMsg ) { _free_xmit( ( *) 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 _RepAsFromLocal_( PMIDL_STUB_MESSAGE pStubMsg ) { _from_local( ( *) pStubMsg->pPresentedType, ( * *) &pStubMsg->pTransmitType ); } static void __RPC_API _RepAsToLocal_( PMIDL_STUB_MESSAGE pStubMsg ) { _to_local( ( *) pStubMsg->pTransmitType, ( *) pStubMsg->pPresentedType ); } static void __RPC_API _RepAsFreeInst_( PMIDL_STUB_MESSAGE pStubMsg ) { _free_inst( ( *) pStubMsg-p>TransmitType ); } static void __RPC_API _RepAsFreeLocal_( PMIDL_STUB_MESSAGE pStubMsg ) { _free_local( ( *) 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; }