/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1998-2000 Microsoft Corporation Module Name: netmon.cxx Abstract: Generate C code for the stub DLL's used for Netmon debugging Notes: Two files are generated by this file: xxx_netmon_stub.c xxx_netmob_stub_obj.c History: - Created 7/28/98 by Max Attar Feingold ----------------------------------------------------------------------------*/ #include "becls.hxx" // Stub version #define NETMON_STUB_VERSION "(float) 1.0" #pragma hdrstop CG_STATUS CG_NETMONSTUB_FILE::GenCode( CCB * pCCB) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the Netmon stub file for classic and object interfaces Arguments: pCCB - The code gen controller block. Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ { ISTREAM Stream( GetFileName(), 4 ); ISTREAM * pStream = pCCB->SetStream( &Stream, this ); m_pCCB = pCCB; m_pStream = pStream; // Scan for interfaces of the appropriate type ScanInterfaces(); if (!m_bDoObject && !m_bClassic || m_bDoObject && !m_bObject) { m_pStream->Close(); return CG_OK; } // If m_bDoObject is TRUE, then we're producing a stub file for object interfaces; // otherwise, we're doing classic interfaces if (m_bDoObject) { EmitFileHeadingBlock (pCCB, "code for an object interface Netmon stub DLL", "This file should be compiled as source for a DLL, linked with rpcrt4.lib"); } else { EmitFileHeadingBlock (pCCB, "code for a classic interface Netmon stub DLL", "This file should be compiled as source for a DLL, linked with rpcrt4.lib"); } // Write standard include files EmitStandardIncludes(); // Write local include files EmitLocalIncludes(); // Write definitions (#defines and variables needed by the code) EmitDefinitions(); if (m_bDoObject) { // We seem to need this to solve a link error OpenComment(); EmitComment ("This implementation is needed to solve a link error"); CloseComment(); pStream->NewLine(); pStream->Write ("ULONG STDMETHODCALLTYPE CStdStubBuffer_Release "\ "(IRpcStubBuffer *This) { ULONG u = 0; return u; }"); // Write the special data for object interfaces EmitObjectInterfaceData(); } // Write the server and client debug procedures for each interface EmitDebugProcedures(); // Write the data tables EmitDataTables(); // Close the header block EmitFileClosingBlock( pCCB ); // Close the stream pStream->Close(); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Descriptions: Determine which types of interfaces (object or classic) we have and how many, adding the names to the interface table Arguments: Return Value: TRUE if yes FALSE if no Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::ScanInterfaces() { CG_ITERATOR I; CG_NDR * pCG; GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { // We check GetChild()'s non-nullness here and elsewhere in the code because // there are object interfaces without children that cause problems, such as IUnknown if (pCG->GetChild()) { switch(pCG->GetCGID()) { case ID_CG_INTERFACE: m_bClassic = TRUE; m_lNumClassicInterfaces ++; m_itInterfaceTable.AddInterface (((CG_INTERFACE*)pCG)->GetInterfaceName()); break; case ID_CG_OBJECT_INTERFACE: m_bObject = TRUE; m_lNumObjectInterfaces ++; m_itInterfaceTable.AddInterface (((CG_INTERFACE*)pCG)->GetInterfaceName()); break; default: break; } } } return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Descriptions: Respectively, -Open a comment block -Write comments -Close a comment block Arguments: pszString is the comment that should be emitted Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::OpenComment() { m_pStream->NewLine(); m_pStream->NewLine(); m_pStream->Write ("/*"); return CG_OK; } CG_STATUS CG_NETMONSTUB_FILE::EmitComment (char* pszString) { m_pStream->NewLine(); m_pStream->Write (" * "); m_pStream->Write (pszString); return CG_OK; } CG_STATUS CG_NETMONSTUB_FILE::CloseComment() { m_pStream->NewLine(); m_pStream->Write (" */"); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the standard includes for the netmon stub dll Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitStandardIncludes() { m_pStream->NewLine(); m_pStream->Write ("#include "); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the local includes for the netmon stub dll. Arguments: Return Value: CG_OK if all is well. Notes: Local includes are the proxy and iid files for object interfaces and the stub file for classic interfaces. ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitLocalIncludes() { m_pStream->NewLine(2); // This is defined to avoid target errors m_pStream->Write ("#define _WIN32_DCOM"); // Write includes m_pStream->NewLine(); if (m_bDoObject) { m_pStream->Write ("#include \""); m_pStream->Write (pCommand->GetProxyFName()); m_pStream->Write ("\""); m_pStream->NewLine(); m_pStream->Write ("#include \""); m_pStream->Write (pCommand->GetIIDFName()); m_pStream->Write ("\""); m_pStream->NewLine(); } else { m_pStream->Write ("#include \""); m_pStream->Write (pCommand->GetSstubFName()); m_pStream->Write ("\""); m_pStream->NewLine(); } return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate any definitions needed by the netmon stub dll. Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ const char* ppszIncludeBlock[] = { "#define DLL_EXPORT_PROC(x) __declspec(dllexport) GLOBAL_INTERFACE_DATA* GetGlobalInterfaceData__##x () { return &GlobalInterfaceData__##x ; }", "#define NetmonStubAllocate(x) malloc(x)", "#define Debug() *pNull = 0", "static DWORD* pNull = NULL;", NULL }; const char* ppszGlobalInterfaceDataStructure[] = { "float Version;", "char* InterfaceName;", "DWORD ProcFormatStringSize;", "DWORD NumProcedures;", "char** ProcedureNames;", "SERVER_ROUTINE* ServerRoutineTable;", "SERVER_ROUTINE* ClientRoutineTable;", "RPC_SERVER_INTERFACE* RpcServerInterface;", "void* DebugArgumentBuffer;", NULL }; CG_STATUS CG_NETMONSTUB_FILE::EmitDefinitions() { if (!m_bDoObject) { m_pStream->NewLine(); m_pStream->Write ("#pragma warning (disable : 4700) /* No warnings from the "\ "use of uninitialized variables */"); m_pStream->NewLine(); } m_pStream->WriteBlock (ppszIncludeBlock); OpenComment(); EmitComment ("Structure used to encapsulate all relevant interface information"); CloseComment(); m_pStream->NewLine(2); m_pStream->Write ("typedef struct _GLOBAL_INTERFACE_DATA {"); Out_IndentInc( m_pCCB ); m_pStream->WriteBlock (ppszGlobalInterfaceDataStructure); Out_IndentDec( m_pCCB ); m_pStream->NewLine(); m_pStream->Write ("} GLOBAL_INTERFACE_DATA;"); OpenComment(); EmitComment ("Function used to view unmarshalled argument buffers"); CloseComment(); m_pStream->NewLine(); m_pStream->Write ("static void DebugArgumentBuffer (BYTE* ArgumentBuffer, DWORD BufferSize) "\ "{ Debug(); }"); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the data used specifically by object interfaces. Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitObjectInterfaceData() { CG_ITERATOR I; CG_NDR * pCG; OpenComment(); EmitComment ("Data used specifically by object interfaces"); CloseComment(); // Loop through all interfaces GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { if (pCG->GetChild()) { switch(pCG->GetCGID()) { case ID_CG_OBJECT_INTERFACE: // Emit the object interface RPC_SERVER_INTERFACE structures OpenComment(); EmitComment ("RPC_SERVER_INTERFACE structure for object interface "); m_pStream->Write (pCG->GetSymName()); CloseComment(); EmitRPCServerInterface ((CG_INTERFACE*) pCG); break; default: break; } } } return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate an RPC_SERVER_INTERFACE structure for the given interface Arguments: Return Value: CG_OK if all is well. Notes: Most of the code was taken from misccls.cxx -> CG_INTERFACE::GenServerStub ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitRPCServerInterface (CG_INTERFACE* pCG) { GUID_STRS TransferSyntaxGuid( TRANSFER_SYNTAX_GUID_STR_1, TRANSFER_SYNTAX_GUID_STR_2, TRANSFER_SYNTAX_GUID_STR_3, TRANSFER_SYNTAX_GUID_STR_4, TRANSFER_SYNTAX_GUID_STR_5); GUID_STRS GuidStrs; unsigned short M, m; char Buffer[ _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 1 ]; long ProtSeqEPCount = 0; ITERATOR * pProtSeqIterator; GuidStrs = pCG->GetGuidStrs(); m_pCCB->SetInterfaceCG (pCG); m_pCCB->SetInterfaceName (pCG->GetInterfaceName()); m_pCCB->GetVersion( &M,&m ); sprintf( Buffer, "&%s_%s_DispatchTable", pCG->GetInterfaceName(), m_pCCB->GenMangledName() ); if ( ( pProtSeqIterator = pCG->GetProtSeqEps() ) != 0 ) { ProtSeqEPCount = ITERATOR_GETCOUNT( *pProtSeqIterator ); Out_EP_Info( m_pCCB, pProtSeqIterator ); } Out_IFInfo( m_pCCB, // controller block. RPC_S_INT_INFO_TYPE_NAME, // interface info type name. RPC_S_INT_INFO_STRUCT_NAME, // variable name. SIZEOF_RPC_SERVER_INTERFACE, // string speicifying size. GuidStrs, // Guid specified in idl M, // user specified major version m, // user specified minor version // TransferSyntaxGuid, // ndr identifying guid. // NDR_UUID_MAJOR_VERSION, // ndr's version // NDR_UUID_MINOR_VERSION, NULL, //Buffer, ProtSeqEPCount, // if this is 0, then the next // 2 fields are ignored by the call. PROTSEQ_EP_TYPE_NAME, // RPC_PROTSEQ_ENDPOINT PROTSEQ_EP_VAR_NAME, // ___RpcProtSeqEndpoint m_pCCB->IsNoDefaultEpv(), 1, pCG->HasPipes() ); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the debug procedures for all interfaces Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitDebugProcedures() { CG_ITERATOR I; CG_NDR * pCG; CG_PROC * pProc; CG_INTERFACE * pInt; ID_CG idCg; ITERATOR IProc; char* pszInterfaceName, * pszLastInterfaceName, * pszOurInterfaceName; // Write midl malloc and free if we're writing a classic interface stub if (!m_bDoObject) { OpenComment(); EmitComment ("Procedures used by the runtime to allocate and free memory"); CloseComment(); m_pStream->NewLine(2); m_pStream->Write ( "static void * __RPC_API midl_user_allocate(size_t len) { return NetmonStubAllocate(len); }"); m_pStream->NewLine(); m_pStream->Write ( "static void __RPC_API midl_user_free(void * ptr) { free(ptr); }"); } OpenComment(); EmitComment ("Implementation of debug server and client functions for all "); if (m_bDoObject) { m_pStream->Write ("object"); } else { m_pStream->Write ("classic"); } m_pStream->Write (" interfaces"); CloseComment(); // Loop through all interfaces GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { if (pCG->GetChild()) { pInt = (CG_INTERFACE*) pCG; idCg = pCG->GetCGID(); switch(idCg) { case ID_CG_INTERFACE: if (!m_bDoObject) { // Loop through all member functions pInt->GetAllMemberFunctions( IProc ); while( ITERATOR_GETNEXT( IProc, pProc ) ) { EmitServerClientDebugProcedure (pProc, FALSE); // Emit the procedure as is (to avoid link errors) m_pStream->NewLine(2); m_pStream->Write ("static"); Out_ClientProcedureProlog( m_pCCB, pProc->GetType() ); Out_IndentInc( m_pCCB ); // Return a variable of the appropriate return value if (((node_proc*) pProc->GetType())->HasReturn()) { m_pStream->Spaces( STANDARD_STUB_TAB ); m_pStream->Write( pProc->GetReturnType()->GetSymName() ); m_pStream->Write(" RetVal;"); m_pStream->NewLine(); m_pStream->Write( "return RetVal;" ); } // Close the procedure Out_IndentDec( m_pCCB ); Out_ProcClosingBrace( m_pCCB ); } } break; case ID_CG_OBJECT_INTERFACE: if (m_bDoObject) { pszOurInterfaceName = pInt->GetInterfaceName(); pszLastInterfaceName = NULL; // Loop through all member functions pInt->GetAllMemberFunctions ( IProc); while( ITERATOR_GETNEXT( IProc, pProc ) ) { // Get the procedure's real interface name pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName(); // Write the function if: // a) We're its real interface. // b) The interface hasn't been used yet and it's not IUnknown // c) The interface name is the same as the last one we used // (so it's OK to use it again) if (strcmp (pszInterfaceName, pszOurInterfaceName) == 0 || (!m_itOutputInterfaceTable.FindInterface (pszInterfaceName) && strcmp (pszInterfaceName, "IUnknown") != 0) || (pszLastInterfaceName != NULL && strcmp (pszInterfaceName, pszLastInterfaceName) == 0) ) { // Write the server and client debug procedures EmitServerClientDebugProcedure (pProc, TRUE); // Add the interface name to the table of used interfaces m_itOutputInterfaceTable.AddInterface (pszInterfaceName); // Record the last interface name used pszLastInterfaceName = pszInterfaceName; } } } break; default: break; } } } return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate server, client and link stub procedures for a given procedure Arguments: pProc -> The procedure to be processed bIsObject -> TRUE if the procedure belongs to an object interface FALSE otherwise Return Value: CG_OK if all is well. Notes: This function is long and ugly ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitServerClientDebugProcedure (CG_PROC* pProc, BOOL bIsObject) { PNAME pszProcName, pszNewProcName; node_proc * pNodeProc = ((node_proc*) pProc->GetType()); node_param * pRetValParam, * pThisParam, * pParam; node_skl * pOldRetType; node_base_type * pVoidBaseType; type_node_list ITypeNodeList; short i, siNumArgs; PNAME* ppszOldArgName; PNAME* ppszNewArgName; node_base_attr * pNodeAttribIn, * pNodeAttribOut; BOOL bHasReturn = pNodeProc->HasReturn(); // Get the procedure name pszProcName = pProc->GetSymName(); // Rename the procedure to Server__InterfaceName__ProcName pszNewProcName = new char [strlen (pProc->GetInterfaceName()) + strlen (pszProcName) + 11]; sprintf ( pszNewProcName, "Server__%s__%s", pProc->GetInterfaceName(), pszProcName ); pNodeProc->SetSymName ( pszNewProcName ); // Set void type pVoidBaseType = new node_base_type( NODE_VOID, ATTR_BASE ); pVoidBaseType->SetSymName( "void" ); pOldRetType = pNodeProc->GetChild(); pNodeProc->SetChild( pVoidBaseType ); // Rename the arguments to IN__Name, OUT__Name or IN_OUT__name i = 0; siNumArgs = pNodeProc->GetNumberOfArguments(); ppszOldArgName = new PNAME [siNumArgs]; ppszNewArgName = new PNAME [siNumArgs]; pNodeProc->GetParameterList (&ITypeNodeList); while( ITERATOR_GETNEXT( ITypeNodeList, pParam ) ) { MIDL_ASSERT (i < siNumArgs); ppszOldArgName[i] = pParam->GetSymName(); ppszNewArgName[i] = new char [strlen (ppszOldArgName[i]) + 10]; if ((pNodeAttribIn = pParam->GetAttribute (ATTR_IN)) && (pNodeAttribOut = pParam->GetAttribute (ATTR_OUT))) { sprintf (ppszNewArgName[i], "IN_OUT__%s", ppszOldArgName[i]); } else { if (pNodeAttribIn) { sprintf (ppszNewArgName[i], "IN__%s", ppszOldArgName[i]); } else { sprintf (ppszNewArgName[i], "OUT__%s", ppszOldArgName[i]); } } pParam->SetSymName (ppszNewArgName[i]); i ++; delete []ppszOldArgName; delete []ppszNewArgName; } // If proc belongs to an object interface, add the 'this' pointer if (bIsObject) { pThisParam = new node_param(); pThisParam->SetAttribute (ATTR_IN); pThisParam->SetSymName ("this"); pThisParam->SetBasicType( (node_skl *) new node_def( "void*" )); pThisParam->SetEdgeType( EDGE_USE ); pNodeProc->AddFirstMember (pThisParam); } // Emit the server procedure m_pStream->NewLine(2); m_pStream->Write ("static"); Out_ClientProcedureProlog( m_pCCB, pNodeProc ); Out_IndentInc( m_pCCB ); m_pStream->Spaces( STANDARD_STUB_TAB ); m_pStream->Write( "Debug();" ); Out_IndentDec( m_pCCB ); Out_ProcClosingBrace( m_pCCB ); // Rename the procedure to Client__InterfaceName__ProcName sprintf( pszNewProcName, "Client__%s__%s", pProc->GetInterfaceName(), pszProcName ); // Add a RetVal parameter to the param list if the function isn't void if (bHasReturn) { pRetValParam = new node_param(); pRetValParam->SetAttribute (ATTR_IN); pRetValParam->SetSymName ("RetVal"); pRetValParam->SetBasicType( (node_skl *) new node_def( pProc->GetReturnType()->GetSymName() )); pRetValParam->SetEdgeType( EDGE_USE ); pNodeProc->AddLastMember (pRetValParam); } // Emit the client procedure m_pStream->NewLine(2); m_pStream->Write ("static"); Out_ClientProcedureProlog( m_pCCB, pNodeProc ); Out_IndentInc( m_pCCB ); m_pStream->Spaces( STANDARD_STUB_TAB ); m_pStream->Write( "Debug();" ); Out_IndentDec( m_pCCB ); Out_ProcClosingBrace( m_pCCB ); // Delete the this parameter we created if (bIsObject) { pNodeProc->RemoveFirstMember(); delete pThisParam; } // Delete the RetVal from the param List if (bHasReturn) { pNodeProc->RemoveLastMember(); delete pRetValParam; } // Restore the procedure's name pNodeProc->SetSymName( pszProcName ); // Restore the procedure's parameter names if (siNumArgs > 0) { i = 0; pNodeProc->GetParameterList (&ITypeNodeList); while( ITERATOR_GETNEXT( ITypeNodeList, pParam ) ) { pParam->SetSymName (ppszOldArgName[i]); delete [] ppszNewArgName[i]; i ++; } delete [] ppszNewArgName; delete [] ppszOldArgName; } // Restore the node's return type pNodeProc->SetChild( pOldRetType ); // Delete the fake void type node we created delete pVoidBaseType; // Delete the new name we created delete [] pszNewProcName; return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate data tables for each interface Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitDataTables() { // Write procedure name tables for each interface EmitProcNameTables(); // Write the server and client lookup tables for each interface EmitServerClientTables(); // Write the global_interface_data structures and exports for each interface EmitGlobalInterfaceData(); return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate tables with each interface's procedure names and the number of procedures in each interface. Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitProcNameTables() { CG_ITERATOR I; CG_NDR * pCG; CG_INTERFACE* pInt; ITERATOR IProc; CG_PROC * pProc; long lNumProcs; BOOL bBeenHereBefore; char* pszInterfaceName; char pszTemp [1024]; GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { if (pCG->GetChild()) { pInt = (CG_INTERFACE*) pCG; if (m_bDoObject && pCG->GetCGID() == ID_CG_OBJECT_INTERFACE || !m_bDoObject && pCG->GetCGID() == ID_CG_INTERFACE) { lNumProcs = 0; bBeenHereBefore = FALSE; pszInterfaceName = pInt->GetInterfaceName(); OpenComment(); EmitComment ("Procedure tables for interface "); m_pStream->Write (pszInterfaceName); CloseComment(); m_pStream->NewLine(); sprintf (pszTemp, "static char* %s__ProcedureNames[] = {", pszInterfaceName); m_pStream->Write (pszTemp); Out_IndentInc( m_pCCB ); pInt->GetAllMemberFunctions ( IProc); while( ITERATOR_GETNEXT( IProc, pProc ) ) { pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName(); if (strcmp (pszInterfaceName, "IUnknown") != 0) { // Write a comma if we're not the first function in the list if (bBeenHereBefore) { m_pStream->Write (","); } else { bBeenHereBefore = TRUE; } // Write procedure name enclosed in quotes m_pStream->NewLine(); m_pStream->Write ("\""); m_pStream->Write (pProc->GetSymName()); m_pStream->Write ("\""); // Increment procedure count lNumProcs ++; } } Out_IndentDec( m_pCCB ); m_pStream->NewLine(); m_pStream->Write ("};"); // Set number of procedures in interface table m_itInterfaceTable.SetNumProcedures (pszInterfaceName, lNumProcs); } } // if } // while return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the server and client lookup tables for each interface Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitServerClientTables() { CG_ITERATOR I; CG_NDR * pCG; CG_INTERFACE* pInt; ITERATOR IProc; CG_PROC * pProc; char* pszInterfaceName; GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { if (pCG->GetChild()) { if (m_bDoObject && pCG->GetCGID() == ID_CG_OBJECT_INTERFACE || !m_bDoObject && pCG->GetCGID() == ID_CG_INTERFACE) { pInt = (CG_INTERFACE*) pCG; pszInterfaceName = pInt->GetInterfaceName(); // Write the server table OpenComment(); EmitComment ("Debug server procedures for interface "); m_pStream->Write (pszInterfaceName); CloseComment(); m_pStream->NewLine(); m_pStream->Write ("static SERVER_ROUTINE "); m_pStream->Write (pszInterfaceName); m_pStream->Write ("__ServerRoutineTable[] = {"); Out_IndentInc( m_pCCB ); // If we're processing an object interface, // we have to make room for the 3 IUnknown procedures if (m_bDoObject) { m_pStream->NewLine(); m_pStream->Write ("NULL,"); m_pStream->NewLine(); m_pStream->Write ("NULL,"); m_pStream->NewLine(); m_pStream->Write ("NULL,"); } pInt->GetAllMemberFunctions ( IProc); while( ITERATOR_GETNEXT( IProc, pProc ) ) { pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName(); if (strcmp (pszInterfaceName, "IUnknown") != 0) { m_pStream->NewLine(); m_pStream->Write ("(SERVER_ROUTINE)Server__"); m_pStream->Write (pProc->GetInterfaceNode()->GetSymName()); m_pStream->Write ("__"); m_pStream->Write (pProc->GetSymName()); m_pStream->Write (","); } } Out_IndentDec( m_pCCB ); m_pStream->NewLine(); m_pStream->Write ("};"); // Write client table OpenComment(); EmitComment ("Debug client procedures for interface "); m_pStream->Write (pszInterfaceName); CloseComment(); m_pStream->NewLine(); m_pStream->Write ("static SERVER_ROUTINE "); m_pStream->Write (pszInterfaceName); m_pStream->Write ("__ClientRoutineTable[] = {"); Out_IndentInc( m_pCCB ); // If we're processing an object interface, // we have to make room for the 3 IUnknown procedures if (m_bDoObject) { m_pStream->NewLine(); m_pStream->Write ("NULL,"); m_pStream->NewLine(); m_pStream->Write ("NULL,"); m_pStream->NewLine(); m_pStream->Write ("NULL,"); } pInt->GetAllMemberFunctions ( IProc); while( ITERATOR_GETNEXT( IProc, pProc ) ) { pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName(); if (strcmp (pszInterfaceName, "IUnknown") != 0) { m_pStream->NewLine(); m_pStream->Write ("(SERVER_ROUTINE)Client__"); m_pStream->Write (pProc->GetInterfaceNode()->GetSymName()); m_pStream->Write ("__"); m_pStream->Write (pProc->GetSymName()); m_pStream->Write (","); } } Out_IndentDec( m_pCCB ); m_pStream->NewLine(); m_pStream->Write ("};"); } } } return CG_OK; } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the global interface data structures for each interface, as well as the export functions that return them Arguments: Return Value: CG_OK if all is well. Notes: ----------------------------------------------------------------------------*/ CG_STATUS CG_NETMONSTUB_FILE::EmitGlobalInterfaceData() { CG_ITERATOR I; CG_NDR * pCG; ID_CG idCG; char pszTemp [100], * pszInterfaceName, * pszFixedUuid; char * p1, * p2, * p3, * p4, * p5; long lNumProcs; size_t lLength; GetMembers( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { idCG = pCG->GetCGID(); if (((idCG == ID_CG_OBJECT_INTERFACE && m_bDoObject) || (idCG == ID_CG_INTERFACE && !m_bDoObject)) && pCG->GetChild()) { // Get the underscored uuid ((CG_INTERFACE*) pCG)->GetGuidStrs().GetStrs (p1, p2, p3, p4, p5); lLength = (long) strlen (p1) + strlen (p2) + strlen (p3) + strlen (p4) + strlen (p5); pszFixedUuid = new char [lLength + 5]; sprintf (pszFixedUuid, "%s_%s_%s_%s_%s", p1, p2, p3, p4, p5); pszFixedUuid = _strlwr (pszFixedUuid); // Get the interface name pszInterfaceName = pCG->GetSymName(); // Write a comment OpenComment(); EmitComment ("GLOBAL_INTERFACE_DATA structure for interface "); m_pStream->Write (pszInterfaceName); CloseComment(); // Header m_pStream->NewLine(); m_pStream->Write ("static GLOBAL_INTERFACE_DATA GlobalInterfaceData__"); m_pStream->Write (pszFixedUuid); m_pStream->Write (" = {"); Out_IndentInc( m_pCCB ); // Version m_pStream->NewLine(); m_pStream->Write (NETMON_STUB_VERSION); m_pStream->Write (","); // Name m_pStream->NewLine(); m_pStream->Write ("\""); m_pStream->Write (pszInterfaceName); m_pStream->Write ("\","); // Proc format string size m_pStream->NewLine(); m_pStream->Write ("PROC_FORMAT_STRING_SIZE,"); // NumProcs m_pStream->NewLine(); if (m_itInterfaceTable.GetNumProcedures (pszInterfaceName, &lNumProcs)) { m_pStream->Write (_itoa (lNumProcs, pszTemp, 10)); } else { MIDL_ASSERT (FALSE); } m_pStream->Write (","); // Proc name table m_pStream->NewLine(); m_pStream->Write (pszInterfaceName); m_pStream->Write ("__ProcedureNames,"); // Server routine table m_pStream->NewLine(); m_pStream->Write (pszInterfaceName); m_pStream->Write ("__ServerRoutineTable,"); // Client routine table m_pStream->NewLine(); m_pStream->Write (pszInterfaceName); m_pStream->Write ("__ClientRoutineTable,"); // Rpc server interface pointer m_pStream->NewLine(); m_pStream->Write ("(RPC_SERVER_INTERFACE*) &"); m_pStream->Write (pszInterfaceName); m_pStream->Write ("___RpcServerInterface,"); // DebugArgumentBuffer m_pStream->NewLine(); m_pStream->Write ("(void*) DebugArgumentBuffer"); Out_IndentDec( m_pCCB ); m_pStream->NewLine(); m_pStream->Write ("};"); // Export function OpenComment(); EmitComment ("Export function for interface "); m_pStream->Write (pszInterfaceName); CloseComment(); m_pStream->NewLine(); m_pStream->Write ("DLL_EXPORT_PROC ("); m_pStream->Write (pszFixedUuid); m_pStream->Write (")"); delete [] pszFixedUuid; } } return CG_OK; } /**************************************************** * InterfaceTable implementations ****************************************************/ #define NUM_BUCKETS 100 NetmonStubFileInterfaceTable::NetmonStubFileInterfaceTable() { m_pTable = new NetmonStubFileInterfaceList [NUM_BUCKETS]; } NetmonStubFileInterfaceTable::~NetmonStubFileInterfaceTable() { delete [] m_pTable; } void NetmonStubFileInterfaceTable::AddInterface (char* pszInterface) { m_pTable[GetHashValue (pszInterface)].AddInterface (pszInterface); } // Return true if the interface name was found BOOL NetmonStubFileInterfaceTable::FindInterface (char* pszInterface) { return m_pTable[GetHashValue (pszInterface)].FindInterface (pszInterface); } // Set the number of procedures in the interface BOOL NetmonStubFileInterfaceTable::SetNumProcedures (char* pszInterface, long lNumProcs) { return m_pTable[GetHashValue (pszInterface)].SetNumProcedures (pszInterface, lNumProcs); } // Get the number of procedures in the interface BOOL NetmonStubFileInterfaceTable::GetNumProcedures (char* pszInterface, long* plNumProcs) { return m_pTable[GetHashValue (pszInterface)].GetNumProcedures (pszInterface, plNumProcs); } // The hash value is just the sum of the characters in the interface name // mod the number of buckets in the table long NetmonStubFileInterfaceTable::GetHashValue (char* pszInterface) { long i, lSum = 0, lLen = (long) strlen (pszInterface); for (i = 0; i < lLen; i ++) { lSum += (long) pszInterface[i]; } return lSum % NUM_BUCKETS; } /* InterfaceNode */ NetmonStubFileInterfaceNode::NetmonStubFileInterfaceNode (char* pszInterface) { m_pszInterface = new char [strlen (pszInterface) + 1]; strcpy (m_pszInterface, pszInterface); m_pNext = NULL; m_lNumProcs = 0; } NetmonStubFileInterfaceNode::~NetmonStubFileInterfaceNode() { delete [] m_pszInterface; } void NetmonStubFileInterfaceNode::SetNext (NetmonStubFileInterfaceNode* pNext) { m_pNext = pNext; } NetmonStubFileInterfaceNode* NetmonStubFileInterfaceNode::GetNext() { return m_pNext; } char* NetmonStubFileInterfaceNode::GetInterface() { return m_pszInterface; } void NetmonStubFileInterfaceNode::SetNumProcedures (long lNumProcs) { m_lNumProcs = lNumProcs; } long NetmonStubFileInterfaceNode::GetNumProcedures() { return m_lNumProcs; } /* InterfaceList */ NetmonStubFileInterfaceList::NetmonStubFileInterfaceList() { m_pHead = NULL; m_pTail = NULL; } NetmonStubFileInterfaceList::~NetmonStubFileInterfaceList() { NetmonStubFileInterfaceNode* pNode = m_pHead, *pDeleteNode; while (pNode != NULL) { pDeleteNode = pNode; pNode = pNode->GetNext(); delete pDeleteNode; } } void NetmonStubFileInterfaceList::AddInterface (char* pszInterface) { NetmonStubFileInterfaceNode* pNode = new NetmonStubFileInterfaceNode (pszInterface); if (m_pHead == NULL) { m_pHead = m_pTail = pNode; } else { m_pTail->SetNext (pNode); m_pTail = pNode; } } BOOL NetmonStubFileInterfaceList::FindInterface (char* pszInterface) { NetmonStubFileInterfaceNode* pNode = m_pHead; while (pNode != NULL) { if (strcmp (pszInterface, pNode->GetInterface()) == 0) { return TRUE; } pNode = pNode->GetNext(); } return FALSE; } BOOL NetmonStubFileInterfaceList::SetNumProcedures (char* pszInterface, long lNumProcs) { NetmonStubFileInterfaceNode* pNode = m_pHead; while (pNode != NULL) { if (strcmp (pszInterface, pNode->GetInterface()) == 0) { pNode->SetNumProcedures (lNumProcs); return TRUE; } pNode = pNode->GetNext(); } return FALSE; } BOOL NetmonStubFileInterfaceList::GetNumProcedures (char* pszInterface, long* plNumProcs) { NetmonStubFileInterfaceNode* pNode = m_pHead; while (pNode != NULL) { if (strcmp (pszInterface, pNode->GetInterface()) == 0) { *plNumProcs = pNode->GetNumProcedures(); return TRUE; } pNode = pNode->GetNext(); } return FALSE; }