|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 <stdio.h>");
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 ++; } // 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; }
|