Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1318 lines
39 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. netmon.cxx
  5. Abstract:
  6. Generate C code for the stub DLL's used for Netmon debugging
  7. Notes:
  8. Two files are generated by this file:
  9. xxx_netmon_stub.c
  10. xxx_netmob_stub_obj.c
  11. History:
  12. - Created 7/28/98 by Max Attar Feingold
  13. ----------------------------------------------------------------------------*/
  14. #include "becls.hxx"
  15. // Stub version
  16. #define NETMON_STUB_VERSION "(float) 1.0"
  17. #pragma hdrstop
  18. CG_STATUS
  19. CG_NETMONSTUB_FILE::GenCode(
  20. CCB * pCCB)
  21. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  22. Routine Description:
  23. Generate the Netmon stub file for classic and object interfaces
  24. Arguments:
  25. pCCB - The code gen controller block.
  26. Return Value:
  27. CG_OK if all is well.
  28. Notes:
  29. ----------------------------------------------------------------------------*/
  30. {
  31. ISTREAM Stream( GetFileName(), 4 );
  32. ISTREAM * pStream = pCCB->SetStream( &Stream, this );
  33. m_pCCB = pCCB;
  34. m_pStream = pStream;
  35. // Scan for interfaces of the appropriate type
  36. ScanInterfaces();
  37. if (!m_bDoObject && !m_bClassic ||
  38. m_bDoObject && !m_bObject) {
  39. m_pStream->Close();
  40. return CG_OK;
  41. }
  42. // If m_bDoObject is TRUE, then we're producing a stub file for object interfaces;
  43. // otherwise, we're doing classic interfaces
  44. if (m_bDoObject) {
  45. EmitFileHeadingBlock (pCCB, "code for an object interface Netmon stub DLL",
  46. "This file should be compiled as source for a DLL, linked with rpcrt4.lib");
  47. } else {
  48. EmitFileHeadingBlock (pCCB, "code for a classic interface Netmon stub DLL",
  49. "This file should be compiled as source for a DLL, linked with rpcrt4.lib");
  50. }
  51. // Write standard include files
  52. EmitStandardIncludes();
  53. // Write local include files
  54. EmitLocalIncludes();
  55. // Write definitions (#defines and variables needed by the code)
  56. EmitDefinitions();
  57. if (m_bDoObject) {
  58. // We seem to need this to solve a link error
  59. OpenComment();
  60. EmitComment ("This implementation is needed to solve a link error");
  61. CloseComment();
  62. pStream->NewLine();
  63. pStream->Write ("ULONG STDMETHODCALLTYPE CStdStubBuffer_Release "\
  64. "(IRpcStubBuffer *This) { ULONG u = 0; return u; }");
  65. // Write the special data for object interfaces
  66. EmitObjectInterfaceData();
  67. }
  68. // Write the server and client debug procedures for each interface
  69. EmitDebugProcedures();
  70. // Write the data tables
  71. EmitDataTables();
  72. // Close the header block
  73. EmitFileClosingBlock( pCCB );
  74. // Close the stream
  75. pStream->Close();
  76. return CG_OK;
  77. }
  78. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  79. Routine Descriptions:
  80. Determine which types of interfaces (object or classic) we have and how many,
  81. adding the names to the interface table
  82. Arguments:
  83. Return Value:
  84. TRUE if yes
  85. FALSE if no
  86. Notes:
  87. ----------------------------------------------------------------------------*/
  88. CG_STATUS CG_NETMONSTUB_FILE::ScanInterfaces() {
  89. CG_ITERATOR I;
  90. CG_NDR * pCG;
  91. GetMembers( I );
  92. while( ITERATOR_GETNEXT( I, pCG ) )
  93. {
  94. // We check GetChild()'s non-nullness here and elsewhere in the code because
  95. // there are object interfaces without children that cause problems, such as IUnknown
  96. if (pCG->GetChild()) {
  97. switch(pCG->GetCGID())
  98. {
  99. case ID_CG_INTERFACE:
  100. m_bClassic = TRUE;
  101. m_lNumClassicInterfaces ++;
  102. m_itInterfaceTable.AddInterface (((CG_INTERFACE*)pCG)->GetInterfaceName());
  103. break;
  104. case ID_CG_OBJECT_INTERFACE:
  105. m_bObject = TRUE;
  106. m_lNumObjectInterfaces ++;
  107. m_itInterfaceTable.AddInterface (((CG_INTERFACE*)pCG)->GetInterfaceName());
  108. break;
  109. default:
  110. break;
  111. }
  112. }
  113. }
  114. return CG_OK;
  115. }
  116. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  117. Routine Descriptions:
  118. Respectively,
  119. -Open a comment block
  120. -Write comments
  121. -Close a comment block
  122. Arguments:
  123. pszString is the comment that should be emitted
  124. Return Value:
  125. CG_OK if all is well.
  126. Notes:
  127. ----------------------------------------------------------------------------*/
  128. CG_STATUS CG_NETMONSTUB_FILE::OpenComment() {
  129. m_pStream->NewLine();
  130. m_pStream->NewLine();
  131. m_pStream->Write ("/*");
  132. return CG_OK;
  133. }
  134. CG_STATUS CG_NETMONSTUB_FILE::EmitComment (char* pszString) {
  135. m_pStream->NewLine();
  136. m_pStream->Write (" * ");
  137. m_pStream->Write (pszString);
  138. return CG_OK;
  139. }
  140. CG_STATUS CG_NETMONSTUB_FILE::CloseComment() {
  141. m_pStream->NewLine();
  142. m_pStream->Write (" */");
  143. return CG_OK;
  144. }
  145. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  146. Routine Description:
  147. Generate the standard includes for the netmon stub dll
  148. Arguments:
  149. Return Value:
  150. CG_OK if all is well.
  151. Notes:
  152. ----------------------------------------------------------------------------*/
  153. CG_STATUS CG_NETMONSTUB_FILE::EmitStandardIncludes() {
  154. m_pStream->NewLine();
  155. m_pStream->Write ("#include <stdio.h>");
  156. return CG_OK;
  157. }
  158. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  159. Routine Description:
  160. Generate the local includes for the netmon stub dll.
  161. Arguments:
  162. Return Value:
  163. CG_OK if all is well.
  164. Notes:
  165. Local includes are the proxy and iid files for object interfaces
  166. and the stub file for classic interfaces.
  167. ----------------------------------------------------------------------------*/
  168. CG_STATUS CG_NETMONSTUB_FILE::EmitLocalIncludes() {
  169. m_pStream->NewLine(2);
  170. // This is defined to avoid target errors
  171. m_pStream->Write ("#define _WIN32_DCOM");
  172. // Write includes
  173. m_pStream->NewLine();
  174. if (m_bDoObject) {
  175. m_pStream->Write ("#include \"");
  176. m_pStream->Write (pCommand->GetProxyFName());
  177. m_pStream->Write ("\"");
  178. m_pStream->NewLine();
  179. m_pStream->Write ("#include \"");
  180. m_pStream->Write (pCommand->GetIIDFName());
  181. m_pStream->Write ("\"");
  182. m_pStream->NewLine();
  183. } else {
  184. m_pStream->Write ("#include \"");
  185. m_pStream->Write (pCommand->GetSstubFName());
  186. m_pStream->Write ("\"");
  187. m_pStream->NewLine();
  188. }
  189. return CG_OK;
  190. }
  191. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  192. Routine Description:
  193. Generate any definitions needed by the netmon stub dll.
  194. Arguments:
  195. Return Value:
  196. CG_OK if all is well.
  197. Notes:
  198. ----------------------------------------------------------------------------*/
  199. const char* ppszIncludeBlock[] = {
  200. "#define DLL_EXPORT_PROC(x) __declspec(dllexport) GLOBAL_INTERFACE_DATA* GetGlobalInterfaceData__##x () { return &GlobalInterfaceData__##x ; }",
  201. "#define NetmonStubAllocate(x) malloc(x)",
  202. "#define Debug() *pNull = 0",
  203. "static DWORD* pNull = NULL;",
  204. NULL
  205. };
  206. const char* ppszGlobalInterfaceDataStructure[] = {
  207. "float Version;",
  208. "char* InterfaceName;",
  209. "DWORD ProcFormatStringSize;",
  210. "DWORD NumProcedures;",
  211. "char** ProcedureNames;",
  212. "SERVER_ROUTINE* ServerRoutineTable;",
  213. "SERVER_ROUTINE* ClientRoutineTable;",
  214. "RPC_SERVER_INTERFACE* RpcServerInterface;",
  215. "void* DebugArgumentBuffer;",
  216. NULL
  217. };
  218. CG_STATUS CG_NETMONSTUB_FILE::EmitDefinitions() {
  219. if (!m_bDoObject) {
  220. m_pStream->NewLine();
  221. m_pStream->Write ("#pragma warning (disable : 4700) /* No warnings from the "\
  222. "use of uninitialized variables */");
  223. m_pStream->NewLine();
  224. }
  225. m_pStream->WriteBlock (ppszIncludeBlock);
  226. OpenComment();
  227. EmitComment ("Structure used to encapsulate all relevant interface information");
  228. CloseComment();
  229. m_pStream->NewLine(2);
  230. m_pStream->Write ("typedef struct _GLOBAL_INTERFACE_DATA {");
  231. Out_IndentInc( m_pCCB );
  232. m_pStream->WriteBlock (ppszGlobalInterfaceDataStructure);
  233. Out_IndentDec( m_pCCB );
  234. m_pStream->NewLine();
  235. m_pStream->Write ("} GLOBAL_INTERFACE_DATA;");
  236. OpenComment();
  237. EmitComment ("Function used to view unmarshalled argument buffers");
  238. CloseComment();
  239. m_pStream->NewLine();
  240. m_pStream->Write ("static void DebugArgumentBuffer (BYTE* ArgumentBuffer, DWORD BufferSize) "\
  241. "{ Debug(); }");
  242. return CG_OK;
  243. }
  244. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  245. Routine Description:
  246. Generate the data used specifically by object interfaces.
  247. Arguments:
  248. Return Value:
  249. CG_OK if all is well.
  250. Notes:
  251. ----------------------------------------------------------------------------*/
  252. CG_STATUS CG_NETMONSTUB_FILE::EmitObjectInterfaceData() {
  253. CG_ITERATOR I;
  254. CG_NDR * pCG;
  255. OpenComment();
  256. EmitComment ("Data used specifically by object interfaces");
  257. CloseComment();
  258. // Loop through all interfaces
  259. GetMembers( I );
  260. while( ITERATOR_GETNEXT( I, pCG ) ) {
  261. if (pCG->GetChild()) {
  262. switch(pCG->GetCGID()) {
  263. case ID_CG_OBJECT_INTERFACE:
  264. // Emit the object interface RPC_SERVER_INTERFACE structures
  265. OpenComment();
  266. EmitComment ("RPC_SERVER_INTERFACE structure for object interface ");
  267. m_pStream->Write (pCG->GetSymName());
  268. CloseComment();
  269. EmitRPCServerInterface ((CG_INTERFACE*) pCG);
  270. break;
  271. default:
  272. break;
  273. }
  274. }
  275. }
  276. return CG_OK;
  277. }
  278. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  279. Routine Description:
  280. Generate an RPC_SERVER_INTERFACE structure for the given interface
  281. Arguments:
  282. Return Value:
  283. CG_OK if all is well.
  284. Notes:
  285. Most of the code was taken from misccls.cxx -> CG_INTERFACE::GenServerStub
  286. ----------------------------------------------------------------------------*/
  287. CG_STATUS CG_NETMONSTUB_FILE::EmitRPCServerInterface (CG_INTERFACE* pCG) {
  288. GUID_STRS TransferSyntaxGuid( TRANSFER_SYNTAX_GUID_STR_1,
  289. TRANSFER_SYNTAX_GUID_STR_2,
  290. TRANSFER_SYNTAX_GUID_STR_3,
  291. TRANSFER_SYNTAX_GUID_STR_4,
  292. TRANSFER_SYNTAX_GUID_STR_5);
  293. GUID_STRS GuidStrs;
  294. unsigned short M, m;
  295. char Buffer[ _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 1 ];
  296. long ProtSeqEPCount = 0;
  297. ITERATOR * pProtSeqIterator;
  298. GuidStrs = pCG->GetGuidStrs();
  299. m_pCCB->SetInterfaceCG (pCG);
  300. m_pCCB->SetInterfaceName (pCG->GetInterfaceName());
  301. m_pCCB->GetVersion( &M,&m );
  302. sprintf( Buffer,
  303. "&%s_%s_DispatchTable",
  304. pCG->GetInterfaceName(),
  305. m_pCCB->GenMangledName()
  306. );
  307. if ( ( pProtSeqIterator = pCG->GetProtSeqEps() ) != 0 )
  308. {
  309. ProtSeqEPCount = ITERATOR_GETCOUNT( *pProtSeqIterator );
  310. Out_EP_Info( m_pCCB, pProtSeqIterator );
  311. }
  312. Out_IFInfo( m_pCCB, // controller block.
  313. RPC_S_INT_INFO_TYPE_NAME, // interface info type name.
  314. RPC_S_INT_INFO_STRUCT_NAME, // variable name.
  315. SIZEOF_RPC_SERVER_INTERFACE, // string speicifying size.
  316. GuidStrs, // Guid specified in idl
  317. M, // user specified major version
  318. m, // user specified minor version
  319. // TransferSyntaxGuid, // ndr identifying guid.
  320. // NDR_UUID_MAJOR_VERSION, // ndr's version
  321. // NDR_UUID_MINOR_VERSION,
  322. NULL, //Buffer,
  323. ProtSeqEPCount, // if this is 0, then the next
  324. // 2 fields are ignored by the call.
  325. PROTSEQ_EP_TYPE_NAME, // RPC_PROTSEQ_ENDPOINT
  326. PROTSEQ_EP_VAR_NAME, // ___RpcProtSeqEndpoint
  327. m_pCCB->IsNoDefaultEpv(),
  328. 1,
  329. pCG->HasPipes()
  330. );
  331. return CG_OK;
  332. }
  333. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  334. Routine Description:
  335. Generate the debug procedures for all interfaces
  336. Arguments:
  337. Return Value:
  338. CG_OK if all is well.
  339. Notes:
  340. ----------------------------------------------------------------------------*/
  341. CG_STATUS CG_NETMONSTUB_FILE::EmitDebugProcedures() {
  342. CG_ITERATOR I;
  343. CG_NDR * pCG;
  344. CG_PROC * pProc;
  345. CG_INTERFACE * pInt;
  346. ID_CG idCg;
  347. ITERATOR IProc;
  348. char* pszInterfaceName, * pszLastInterfaceName, * pszOurInterfaceName;
  349. // Write midl malloc and free if we're writing a classic interface stub
  350. if (!m_bDoObject) {
  351. OpenComment();
  352. EmitComment ("Procedures used by the runtime to allocate and free memory");
  353. CloseComment();
  354. m_pStream->NewLine(2);
  355. m_pStream->Write (
  356. "static void * __RPC_API midl_user_allocate(size_t len) { return NetmonStubAllocate(len); }");
  357. m_pStream->NewLine();
  358. m_pStream->Write (
  359. "static void __RPC_API midl_user_free(void * ptr) { free(ptr); }");
  360. }
  361. OpenComment();
  362. EmitComment ("Implementation of debug server and client functions for all ");
  363. if (m_bDoObject) {
  364. m_pStream->Write ("object");
  365. } else {
  366. m_pStream->Write ("classic");
  367. }
  368. m_pStream->Write (" interfaces");
  369. CloseComment();
  370. // Loop through all interfaces
  371. GetMembers( I );
  372. while( ITERATOR_GETNEXT( I, pCG ) )
  373. {
  374. if (pCG->GetChild()) {
  375. pInt = (CG_INTERFACE*) pCG;
  376. idCg = pCG->GetCGID();
  377. switch(idCg) {
  378. case ID_CG_INTERFACE:
  379. if (!m_bDoObject) {
  380. // Loop through all member functions
  381. pInt->GetAllMemberFunctions( IProc );
  382. while( ITERATOR_GETNEXT( IProc, pProc ) ) {
  383. EmitServerClientDebugProcedure (pProc, FALSE);
  384. // Emit the procedure as is (to avoid link errors)
  385. m_pStream->NewLine(2);
  386. m_pStream->Write ("static");
  387. Out_ClientProcedureProlog( m_pCCB, pProc->GetType() );
  388. Out_IndentInc( m_pCCB );
  389. // Return a variable of the appropriate return value
  390. if (((node_proc*) pProc->GetType())->HasReturn()) {
  391. m_pStream->Spaces( STANDARD_STUB_TAB );
  392. m_pStream->Write( pProc->GetReturnType()->GetSymName() );
  393. m_pStream->Write(" RetVal;");
  394. m_pStream->NewLine();
  395. m_pStream->Write( "return RetVal;" );
  396. }
  397. // Close the procedure
  398. Out_IndentDec( m_pCCB );
  399. Out_ProcClosingBrace( m_pCCB );
  400. }
  401. }
  402. break;
  403. case ID_CG_OBJECT_INTERFACE:
  404. if (m_bDoObject) {
  405. pszOurInterfaceName = pInt->GetInterfaceName();
  406. pszLastInterfaceName = NULL;
  407. // Loop through all member functions
  408. pInt->GetAllMemberFunctions ( IProc);
  409. while( ITERATOR_GETNEXT( IProc, pProc ) ) {
  410. // Get the procedure's real interface name
  411. pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName();
  412. // Write the function if:
  413. // a) We're its real interface.
  414. // b) The interface hasn't been used yet and it's not IUnknown
  415. // c) The interface name is the same as the last one we used
  416. // (so it's OK to use it again)
  417. if (strcmp (pszInterfaceName, pszOurInterfaceName) == 0 ||
  418. (!m_itOutputInterfaceTable.FindInterface (pszInterfaceName) &&
  419. strcmp (pszInterfaceName, "IUnknown") != 0) ||
  420. (pszLastInterfaceName != NULL &&
  421. strcmp (pszInterfaceName, pszLastInterfaceName) == 0)
  422. ) {
  423. // Write the server and client debug procedures
  424. EmitServerClientDebugProcedure (pProc, TRUE);
  425. // Add the interface name to the table of used interfaces
  426. m_itOutputInterfaceTable.AddInterface (pszInterfaceName);
  427. // Record the last interface name used
  428. pszLastInterfaceName = pszInterfaceName;
  429. }
  430. }
  431. }
  432. break;
  433. default:
  434. break;
  435. }
  436. }
  437. }
  438. return CG_OK;
  439. }
  440. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  441. Routine Description:
  442. Generate server, client and link stub procedures for a given procedure
  443. Arguments:
  444. pProc -> The procedure to be processed
  445. bIsObject -> TRUE if the procedure belongs to an object interface
  446. FALSE otherwise
  447. Return Value:
  448. CG_OK if all is well.
  449. Notes:
  450. This function is long and ugly
  451. ----------------------------------------------------------------------------*/
  452. CG_STATUS CG_NETMONSTUB_FILE::EmitServerClientDebugProcedure (CG_PROC* pProc, BOOL bIsObject) {
  453. PNAME pszProcName, pszNewProcName;
  454. node_proc * pNodeProc = ((node_proc*) pProc->GetType());
  455. node_param * pRetValParam, * pThisParam, * pParam;
  456. node_skl * pOldRetType;
  457. node_base_type * pVoidBaseType;
  458. type_node_list ITypeNodeList;
  459. short i, siNumArgs;
  460. PNAME* ppszOldArgName;
  461. PNAME* ppszNewArgName;
  462. node_base_attr * pNodeAttribIn, * pNodeAttribOut;
  463. BOOL bHasReturn = pNodeProc->HasReturn();
  464. // Get the procedure name
  465. pszProcName = pProc->GetSymName();
  466. // Rename the procedure to Server__InterfaceName__ProcName
  467. pszNewProcName = new char [strlen (pProc->GetInterfaceName()) +
  468. strlen (pszProcName) + 11];
  469. sprintf ( pszNewProcName, "Server__%s__%s", pProc->GetInterfaceName(), pszProcName );
  470. pNodeProc->SetSymName ( pszNewProcName );
  471. // Set void type
  472. pVoidBaseType = new node_base_type( NODE_VOID, ATTR_BASE );
  473. pVoidBaseType->SetSymName( "void" );
  474. pOldRetType = pNodeProc->GetChild();
  475. pNodeProc->SetChild( pVoidBaseType );
  476. // Rename the arguments to IN__Name, OUT__Name or IN_OUT__name
  477. i = 0;
  478. siNumArgs = pNodeProc->GetNumberOfArguments();
  479. ppszOldArgName = new PNAME [siNumArgs];
  480. ppszNewArgName = new PNAME [siNumArgs];
  481. pNodeProc->GetParameterList (&ITypeNodeList);
  482. while( ITERATOR_GETNEXT( ITypeNodeList, pParam ) ) {
  483. MIDL_ASSERT (i < siNumArgs);
  484. ppszOldArgName[i] = pParam->GetSymName();
  485. ppszNewArgName[i] = new char [strlen (ppszOldArgName[i]) + 10];
  486. if ((pNodeAttribIn = pParam->GetAttribute (ATTR_IN)) &&
  487. (pNodeAttribOut = pParam->GetAttribute (ATTR_OUT))) {
  488. sprintf (ppszNewArgName[i], "IN_OUT__%s", ppszOldArgName[i]);
  489. } else {
  490. if (pNodeAttribIn) {
  491. sprintf (ppszNewArgName[i], "IN__%s", ppszOldArgName[i]);
  492. } else {
  493. sprintf (ppszNewArgName[i], "OUT__%s", ppszOldArgName[i]);
  494. }
  495. }
  496. pParam->SetSymName (ppszNewArgName[i]);
  497. i ++;
  498. }
  499. // If proc belongs to an object interface, add the 'this' pointer
  500. if (bIsObject) {
  501. pThisParam = new node_param();
  502. pThisParam->SetAttribute (ATTR_IN);
  503. pThisParam->SetSymName ("this");
  504. pThisParam->SetBasicType( (node_skl *) new node_def( "void*" ));
  505. pThisParam->SetEdgeType( EDGE_USE );
  506. pNodeProc->AddFirstMember (pThisParam);
  507. }
  508. // Emit the server procedure
  509. m_pStream->NewLine(2);
  510. m_pStream->Write ("static");
  511. Out_ClientProcedureProlog( m_pCCB, pNodeProc );
  512. Out_IndentInc( m_pCCB );
  513. m_pStream->Spaces( STANDARD_STUB_TAB );
  514. m_pStream->Write( "Debug();" );
  515. Out_IndentDec( m_pCCB );
  516. Out_ProcClosingBrace( m_pCCB );
  517. // Rename the procedure to Client__InterfaceName__ProcName
  518. sprintf( pszNewProcName, "Client__%s__%s", pProc->GetInterfaceName(), pszProcName );
  519. // Add a RetVal parameter to the param list if the function isn't void
  520. if (bHasReturn) {
  521. pRetValParam = new node_param();
  522. pRetValParam->SetAttribute (ATTR_IN);
  523. pRetValParam->SetSymName ("RetVal");
  524. pRetValParam->SetBasicType( (node_skl *) new node_def( pProc->GetReturnType()->GetSymName() ));
  525. pRetValParam->SetEdgeType( EDGE_USE );
  526. pNodeProc->AddLastMember (pRetValParam);
  527. }
  528. // Emit the client procedure
  529. m_pStream->NewLine(2);
  530. m_pStream->Write ("static");
  531. Out_ClientProcedureProlog( m_pCCB, pNodeProc );
  532. Out_IndentInc( m_pCCB );
  533. m_pStream->Spaces( STANDARD_STUB_TAB );
  534. m_pStream->Write( "Debug();" );
  535. Out_IndentDec( m_pCCB );
  536. Out_ProcClosingBrace( m_pCCB );
  537. // Delete the this parameter we created
  538. if (bIsObject) {
  539. pNodeProc->RemoveFirstMember();
  540. delete pThisParam;
  541. }
  542. // Delete the RetVal from the param List
  543. if (bHasReturn) {
  544. pNodeProc->RemoveLastMember();
  545. delete pRetValParam;
  546. }
  547. // Restore the procedure's name
  548. pNodeProc->SetSymName( pszProcName );
  549. // Restore the procedure's parameter names
  550. if (siNumArgs > 0) {
  551. i = 0;
  552. pNodeProc->GetParameterList (&ITypeNodeList);
  553. while( ITERATOR_GETNEXT( ITypeNodeList, pParam ) ) {
  554. pParam->SetSymName (ppszOldArgName[i]);
  555. delete [] ppszNewArgName[i];
  556. i ++;
  557. }
  558. delete [] ppszNewArgName;
  559. delete [] ppszOldArgName;
  560. }
  561. // Restore the node's return type
  562. pNodeProc->SetChild( pOldRetType );
  563. // Delete the fake void type node we created
  564. delete pVoidBaseType;
  565. // Delete the new name we created
  566. delete [] pszNewProcName;
  567. return CG_OK;
  568. }
  569. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  570. Routine Description:
  571. Generate data tables for each interface
  572. Arguments:
  573. Return Value:
  574. CG_OK if all is well.
  575. Notes:
  576. ----------------------------------------------------------------------------*/
  577. CG_STATUS CG_NETMONSTUB_FILE::EmitDataTables() {
  578. // Write procedure name tables for each interface
  579. EmitProcNameTables();
  580. // Write the server and client lookup tables for each interface
  581. EmitServerClientTables();
  582. // Write the global_interface_data structures and exports for each interface
  583. EmitGlobalInterfaceData();
  584. return CG_OK;
  585. }
  586. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  587. Routine Description:
  588. Generate tables with each interface's procedure names and the number of
  589. procedures in each interface.
  590. Arguments:
  591. Return Value:
  592. CG_OK if all is well.
  593. Notes:
  594. ----------------------------------------------------------------------------*/
  595. CG_STATUS CG_NETMONSTUB_FILE::EmitProcNameTables() {
  596. CG_ITERATOR I;
  597. CG_NDR * pCG;
  598. CG_INTERFACE* pInt;
  599. ITERATOR IProc;
  600. CG_PROC * pProc;
  601. long lNumProcs;
  602. BOOL bBeenHereBefore;
  603. char* pszInterfaceName;
  604. char pszTemp [1024];
  605. GetMembers( I );
  606. while( ITERATOR_GETNEXT( I, pCG ) ) {
  607. if (pCG->GetChild()) {
  608. pInt = (CG_INTERFACE*) pCG;
  609. if (m_bDoObject && pCG->GetCGID() == ID_CG_OBJECT_INTERFACE ||
  610. !m_bDoObject && pCG->GetCGID() == ID_CG_INTERFACE) {
  611. lNumProcs = 0;
  612. bBeenHereBefore = FALSE;
  613. pszInterfaceName = pInt->GetInterfaceName();
  614. OpenComment();
  615. EmitComment ("Procedure tables for interface ");
  616. m_pStream->Write (pszInterfaceName);
  617. CloseComment();
  618. m_pStream->NewLine();
  619. sprintf (pszTemp, "static char* %s__ProcedureNames[] = {", pszInterfaceName);
  620. m_pStream->Write (pszTemp);
  621. Out_IndentInc( m_pCCB );
  622. pInt->GetAllMemberFunctions ( IProc);
  623. while( ITERATOR_GETNEXT( IProc, pProc ) ) {
  624. pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName();
  625. if (strcmp (pszInterfaceName, "IUnknown") != 0) {
  626. // Write a comma if we're not the first function in the list
  627. if (bBeenHereBefore) {
  628. m_pStream->Write (",");
  629. } else {
  630. bBeenHereBefore = TRUE;
  631. }
  632. // Write procedure name enclosed in quotes
  633. m_pStream->NewLine();
  634. m_pStream->Write ("\"");
  635. m_pStream->Write (pProc->GetSymName());
  636. m_pStream->Write ("\"");
  637. // Increment procedure count
  638. lNumProcs ++;
  639. }
  640. }
  641. Out_IndentDec( m_pCCB );
  642. m_pStream->NewLine();
  643. m_pStream->Write ("};");
  644. // Set number of procedures in interface table
  645. m_itInterfaceTable.SetNumProcedures (pszInterfaceName, lNumProcs);
  646. }
  647. } // if
  648. } // while
  649. return CG_OK;
  650. }
  651. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  652. Routine Description:
  653. Generate the server and client lookup tables for each interface
  654. Arguments:
  655. Return Value:
  656. CG_OK if all is well.
  657. Notes:
  658. ----------------------------------------------------------------------------*/
  659. CG_STATUS CG_NETMONSTUB_FILE::EmitServerClientTables() {
  660. CG_ITERATOR I;
  661. CG_NDR * pCG;
  662. CG_INTERFACE* pInt;
  663. ITERATOR IProc;
  664. CG_PROC * pProc;
  665. char* pszInterfaceName;
  666. GetMembers( I );
  667. while( ITERATOR_GETNEXT( I, pCG ) ) {
  668. if (pCG->GetChild()) {
  669. if (m_bDoObject && pCG->GetCGID() == ID_CG_OBJECT_INTERFACE ||
  670. !m_bDoObject && pCG->GetCGID() == ID_CG_INTERFACE) {
  671. pInt = (CG_INTERFACE*) pCG;
  672. pszInterfaceName = pInt->GetInterfaceName();
  673. // Write the server table
  674. OpenComment();
  675. EmitComment ("Debug server procedures for interface ");
  676. m_pStream->Write (pszInterfaceName);
  677. CloseComment();
  678. m_pStream->NewLine();
  679. m_pStream->Write ("static SERVER_ROUTINE ");
  680. m_pStream->Write (pszInterfaceName);
  681. m_pStream->Write ("__ServerRoutineTable[] = {");
  682. Out_IndentInc( m_pCCB );
  683. // If we're processing an object interface,
  684. // we have to make room for the 3 IUnknown procedures
  685. if (m_bDoObject) {
  686. m_pStream->NewLine();
  687. m_pStream->Write ("NULL,");
  688. m_pStream->NewLine();
  689. m_pStream->Write ("NULL,");
  690. m_pStream->NewLine();
  691. m_pStream->Write ("NULL,");
  692. }
  693. pInt->GetAllMemberFunctions ( IProc);
  694. while( ITERATOR_GETNEXT( IProc, pProc ) ) {
  695. pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName();
  696. if (strcmp (pszInterfaceName, "IUnknown") != 0) {
  697. m_pStream->NewLine();
  698. m_pStream->Write ("(SERVER_ROUTINE)Server__");
  699. m_pStream->Write (pProc->GetInterfaceNode()->GetSymName());
  700. m_pStream->Write ("__");
  701. m_pStream->Write (pProc->GetSymName());
  702. m_pStream->Write (",");
  703. }
  704. }
  705. Out_IndentDec( m_pCCB );
  706. m_pStream->NewLine();
  707. m_pStream->Write ("};");
  708. // Write client table
  709. OpenComment();
  710. EmitComment ("Debug client procedures for interface ");
  711. m_pStream->Write (pszInterfaceName);
  712. CloseComment();
  713. m_pStream->NewLine();
  714. m_pStream->Write ("static SERVER_ROUTINE ");
  715. m_pStream->Write (pszInterfaceName);
  716. m_pStream->Write ("__ClientRoutineTable[] = {");
  717. Out_IndentInc( m_pCCB );
  718. // If we're processing an object interface,
  719. // we have to make room for the 3 IUnknown procedures
  720. if (m_bDoObject) {
  721. m_pStream->NewLine();
  722. m_pStream->Write ("NULL,");
  723. m_pStream->NewLine();
  724. m_pStream->Write ("NULL,");
  725. m_pStream->NewLine();
  726. m_pStream->Write ("NULL,");
  727. }
  728. pInt->GetAllMemberFunctions ( IProc);
  729. while( ITERATOR_GETNEXT( IProc, pProc ) ) {
  730. pszInterfaceName = pProc->GetInterfaceNode()->GetInterfaceName();
  731. if (strcmp (pszInterfaceName, "IUnknown") != 0) {
  732. m_pStream->NewLine();
  733. m_pStream->Write ("(SERVER_ROUTINE)Client__");
  734. m_pStream->Write (pProc->GetInterfaceNode()->GetSymName());
  735. m_pStream->Write ("__");
  736. m_pStream->Write (pProc->GetSymName());
  737. m_pStream->Write (",");
  738. }
  739. }
  740. Out_IndentDec( m_pCCB );
  741. m_pStream->NewLine();
  742. m_pStream->Write ("};");
  743. }
  744. }
  745. }
  746. return CG_OK;
  747. }
  748. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  749. Routine Description:
  750. Generate the global interface data structures for each interface, as well
  751. as the export functions that return them
  752. Arguments:
  753. Return Value:
  754. CG_OK if all is well.
  755. Notes:
  756. ----------------------------------------------------------------------------*/
  757. CG_STATUS CG_NETMONSTUB_FILE::EmitGlobalInterfaceData() {
  758. CG_ITERATOR I;
  759. CG_NDR * pCG;
  760. ID_CG idCG;
  761. char pszTemp [100], * pszInterfaceName, * pszFixedUuid;
  762. char * p1, * p2, * p3, * p4, * p5;
  763. long lNumProcs;
  764. size_t lLength;
  765. GetMembers( I );
  766. while( ITERATOR_GETNEXT( I, pCG ) ) {
  767. idCG = pCG->GetCGID();
  768. if (((idCG == ID_CG_OBJECT_INTERFACE && m_bDoObject) ||
  769. (idCG == ID_CG_INTERFACE && !m_bDoObject)) &&
  770. pCG->GetChild()) {
  771. // Get the underscored uuid
  772. ((CG_INTERFACE*) pCG)->GetGuidStrs().GetStrs (p1, p2, p3, p4, p5);
  773. lLength = (long) strlen (p1) + strlen (p2) + strlen (p3) + strlen (p4) + strlen (p5);
  774. pszFixedUuid = new char [lLength + 5];
  775. sprintf (pszFixedUuid, "%s_%s_%s_%s_%s", p1, p2, p3, p4, p5);
  776. pszFixedUuid = _strlwr (pszFixedUuid);
  777. // Get the interface name
  778. pszInterfaceName = pCG->GetSymName();
  779. // Write a comment
  780. OpenComment();
  781. EmitComment ("GLOBAL_INTERFACE_DATA structure for interface ");
  782. m_pStream->Write (pszInterfaceName);
  783. CloseComment();
  784. // Header
  785. m_pStream->NewLine();
  786. m_pStream->Write ("static GLOBAL_INTERFACE_DATA GlobalInterfaceData__");
  787. m_pStream->Write (pszFixedUuid);
  788. m_pStream->Write (" = {");
  789. Out_IndentInc( m_pCCB );
  790. // Version
  791. m_pStream->NewLine();
  792. m_pStream->Write (NETMON_STUB_VERSION);
  793. m_pStream->Write (",");
  794. // Name
  795. m_pStream->NewLine();
  796. m_pStream->Write ("\"");
  797. m_pStream->Write (pszInterfaceName);
  798. m_pStream->Write ("\",");
  799. // Proc format string size
  800. m_pStream->NewLine();
  801. m_pStream->Write ("PROC_FORMAT_STRING_SIZE,");
  802. // NumProcs
  803. m_pStream->NewLine();
  804. if (m_itInterfaceTable.GetNumProcedures (pszInterfaceName, &lNumProcs)) {
  805. m_pStream->Write (_itoa (lNumProcs, pszTemp, 10));
  806. } else {
  807. MIDL_ASSERT (FALSE);
  808. }
  809. m_pStream->Write (",");
  810. // Proc name table
  811. m_pStream->NewLine();
  812. m_pStream->Write (pszInterfaceName);
  813. m_pStream->Write ("__ProcedureNames,");
  814. // Server routine table
  815. m_pStream->NewLine();
  816. m_pStream->Write (pszInterfaceName);
  817. m_pStream->Write ("__ServerRoutineTable,");
  818. // Client routine table
  819. m_pStream->NewLine();
  820. m_pStream->Write (pszInterfaceName);
  821. m_pStream->Write ("__ClientRoutineTable,");
  822. // Rpc server interface pointer
  823. m_pStream->NewLine();
  824. m_pStream->Write ("(RPC_SERVER_INTERFACE*) &");
  825. m_pStream->Write (pszInterfaceName);
  826. m_pStream->Write ("___RpcServerInterface,");
  827. // DebugArgumentBuffer
  828. m_pStream->NewLine();
  829. m_pStream->Write ("(void*) DebugArgumentBuffer");
  830. Out_IndentDec( m_pCCB );
  831. m_pStream->NewLine();
  832. m_pStream->Write ("};");
  833. // Export function
  834. OpenComment();
  835. EmitComment ("Export function for interface ");
  836. m_pStream->Write (pszInterfaceName);
  837. CloseComment();
  838. m_pStream->NewLine();
  839. m_pStream->Write ("DLL_EXPORT_PROC (");
  840. m_pStream->Write (pszFixedUuid);
  841. m_pStream->Write (")");
  842. delete [] pszFixedUuid;
  843. }
  844. }
  845. return CG_OK;
  846. }
  847. /****************************************************
  848. * InterfaceTable implementations
  849. ****************************************************/
  850. #define NUM_BUCKETS 100
  851. NetmonStubFileInterfaceTable::NetmonStubFileInterfaceTable() {
  852. m_pTable = new NetmonStubFileInterfaceList [NUM_BUCKETS];
  853. }
  854. NetmonStubFileInterfaceTable::~NetmonStubFileInterfaceTable() {
  855. delete [] m_pTable;
  856. }
  857. void NetmonStubFileInterfaceTable::AddInterface (char* pszInterface) {
  858. m_pTable[GetHashValue (pszInterface)].AddInterface (pszInterface);
  859. }
  860. // Return true if the interface name was found
  861. BOOL NetmonStubFileInterfaceTable::FindInterface (char* pszInterface) {
  862. return m_pTable[GetHashValue (pszInterface)].FindInterface (pszInterface);
  863. }
  864. // Set the number of procedures in the interface
  865. BOOL NetmonStubFileInterfaceTable::SetNumProcedures (char* pszInterface, long lNumProcs) {
  866. return m_pTable[GetHashValue (pszInterface)].SetNumProcedures (pszInterface, lNumProcs);
  867. }
  868. // Get the number of procedures in the interface
  869. BOOL NetmonStubFileInterfaceTable::GetNumProcedures (char* pszInterface, long* plNumProcs) {
  870. return m_pTable[GetHashValue (pszInterface)].GetNumProcedures (pszInterface, plNumProcs);
  871. }
  872. // The hash value is just the sum of the characters in the interface name
  873. // mod the number of buckets in the table
  874. long NetmonStubFileInterfaceTable::GetHashValue (char* pszInterface) {
  875. long i, lSum = 0, lLen = (long) strlen (pszInterface);
  876. for (i = 0; i < lLen; i ++) {
  877. lSum += (long) pszInterface[i];
  878. }
  879. return lSum % NUM_BUCKETS;
  880. }
  881. /* InterfaceNode */
  882. NetmonStubFileInterfaceNode::NetmonStubFileInterfaceNode (char* pszInterface) {
  883. m_pszInterface = new char [strlen (pszInterface) + 1];
  884. strcpy (m_pszInterface, pszInterface);
  885. m_pNext = NULL;
  886. m_lNumProcs = 0;
  887. }
  888. NetmonStubFileInterfaceNode::~NetmonStubFileInterfaceNode() {
  889. delete [] m_pszInterface;
  890. }
  891. void NetmonStubFileInterfaceNode::SetNext (NetmonStubFileInterfaceNode* pNext) {
  892. m_pNext = pNext;
  893. }
  894. NetmonStubFileInterfaceNode* NetmonStubFileInterfaceNode::GetNext() {
  895. return m_pNext;
  896. }
  897. char* NetmonStubFileInterfaceNode::GetInterface() {
  898. return m_pszInterface;
  899. }
  900. void NetmonStubFileInterfaceNode::SetNumProcedures (long lNumProcs) {
  901. m_lNumProcs = lNumProcs;
  902. }
  903. long NetmonStubFileInterfaceNode::GetNumProcedures() {
  904. return m_lNumProcs;
  905. }
  906. /* InterfaceList */
  907. NetmonStubFileInterfaceList::NetmonStubFileInterfaceList() {
  908. m_pHead = NULL;
  909. m_pTail = NULL;
  910. }
  911. NetmonStubFileInterfaceList::~NetmonStubFileInterfaceList() {
  912. NetmonStubFileInterfaceNode* pNode = m_pHead, *pDeleteNode;
  913. while (pNode != NULL) {
  914. pDeleteNode = pNode;
  915. pNode = pNode->GetNext();
  916. delete pDeleteNode;
  917. }
  918. }
  919. void NetmonStubFileInterfaceList::AddInterface (char* pszInterface) {
  920. NetmonStubFileInterfaceNode* pNode = new NetmonStubFileInterfaceNode (pszInterface);
  921. if (m_pHead == NULL) {
  922. m_pHead = m_pTail = pNode;
  923. } else {
  924. m_pTail->SetNext (pNode);
  925. m_pTail = pNode;
  926. }
  927. }
  928. BOOL NetmonStubFileInterfaceList::FindInterface (char* pszInterface) {
  929. NetmonStubFileInterfaceNode* pNode = m_pHead;
  930. while (pNode != NULL) {
  931. if (strcmp (pszInterface, pNode->GetInterface()) == 0) {
  932. return TRUE;
  933. }
  934. pNode = pNode->GetNext();
  935. }
  936. return FALSE;
  937. }
  938. BOOL NetmonStubFileInterfaceList::SetNumProcedures (char* pszInterface, long lNumProcs) {
  939. NetmonStubFileInterfaceNode* pNode = m_pHead;
  940. while (pNode != NULL) {
  941. if (strcmp (pszInterface, pNode->GetInterface()) == 0) {
  942. pNode->SetNumProcedures (lNumProcs);
  943. return TRUE;
  944. }
  945. pNode = pNode->GetNext();
  946. }
  947. return FALSE;
  948. }
  949. BOOL NetmonStubFileInterfaceList::GetNumProcedures (char* pszInterface, long* plNumProcs) {
  950. NetmonStubFileInterfaceNode* pNode = m_pHead;
  951. while (pNode != NULL) {
  952. if (strcmp (pszInterface, pNode->GetInterface()) == 0) {
  953. *plNumProcs = pNode->GetNumProcedures();
  954. return TRUE;
  955. }
  956. pNode = pNode->GetNext();
  957. }
  958. return FALSE;
  959. }