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

1319 lines
39 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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;
}