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.

2340 lines
64 KiB

  1. #
  2. # Scans a header file for interfaces and generates
  3. # proxies and stubs for the methods encountered.
  4. #
  5. # NOTE: This script's parser is very simple and targeted
  6. # at the formatting used in dbgeng.h. It will not work
  7. # with general header files.
  8. #
  9. $gPre = "__drpc_";
  10. # Parameter flags.
  11. $cPfIn = 1;
  12. $cPfOut = 2;
  13. $cPfOpt = 4;
  14. $cPfSizeIn = 8;
  15. # Parameter data array indices.
  16. $cParamFlags = 0;
  17. $cParamType = 1;
  18. $cParamName = 2;
  19. $cParamSizeIs = 3;
  20. $cParamAlignIs = 4;
  21. # The method returns no data and the return value
  22. # is uninteresting so do no send a return packet.
  23. # This is a significant savings in network activity
  24. # for often-called methods like output callbacks.
  25. $cNoReturn = 1;
  26. # Proxy code is provided elsewhere.
  27. $cCustomProxy = 2;
  28. # A template implementation in $gProxy/StubRepl should be used
  29. # instead of standard code generation.
  30. $cReplImplementation = 4;
  31. # Destroy in-parameter objects.
  32. $cDestroyInObjects = 8;
  33. # Omit the thread check.
  34. $cNoThreadCheck = 16;
  35. # Method object arguments are known to be proxies.
  36. $cObjectsAreProxies = 32;
  37. # Stub code is provided elsewhere.
  38. $cCustomStub = 64;
  39. # Method does not need a stub.
  40. $cNoStub = 128 | $cCustomStub;
  41. # Method cannot be remoted so generate proxy code that fails
  42. # and don't bother with a stub.
  43. $cNotRemotable = 256 | $cNoStub;
  44. # Method can be assumed to be thread safe as it is protected
  45. # by a higher-level lock.
  46. $cCallLocked = 512;
  47. $cCustomImplementation = $cCustomProxy | $cCustomStub;
  48. $gMethodFlagsTable{"*::QueryInterface"} = $cReplImplementation;
  49. $gMethodFlagsTable{"*::AddRef"} = $cReplImplementation | $cNoStub;
  50. $gMethodFlagsTable{"*::Release"} = $cReplImplementation;
  51. $gMethodFlagsTable{"IDebugBreakpoint::GetAdder"} =
  52. $cObjectsAreProxies;
  53. $gMethodFlagsTable{"IDebugClient::CreateClient"} =
  54. $cCustomProxy | $cObjectsAreProxies;
  55. $gMethodFlagsTable{"IDebugClient::ExitDispatch"} =
  56. $cNoThreadCheck | $cNoReturn | $cObjectsAreProxies;
  57. $gMethodFlagsTable{"IDebugClient::GetOtherOutputMask"} =
  58. $cObjectsAreProxies;
  59. $gMethodFlagsTable{"IDebugClient::SetOtherOutputMask"} =
  60. $cObjectsAreProxies;
  61. $gMethodFlagsTable{"IDebugClient::StartProcessServer"} =
  62. $cCustomProxy | $cCustomStub;
  63. $gMethodFlagsTable{"IDebugControl::AddBreakpoint"} =
  64. $cObjectsAreProxies;
  65. $gMethodFlagsTable{"IDebugControl::ControlledOutputVaList"} =
  66. $cCustomImplementation;
  67. $gMethodFlagsTable{"IDebugControl::GetBreakpointById"} =
  68. $cObjectsAreProxies;
  69. $gMethodFlagsTable{"IDebugControl::GetBreakpointByIndex"} =
  70. $cObjectsAreProxies;
  71. $gMethodFlagsTable{"IDebugControl::GetExtensionFunction"} =
  72. $cNotRemotable;
  73. $gMethodFlagsTable{"IDebugControl::GetWindbgExtensionApis32"} =
  74. $cNotRemotable;
  75. $gMethodFlagsTable{"IDebugControl::GetWindbgExtensionApis64"} =
  76. $cNotRemotable;
  77. $gMethodFlagsTable{"IDebugControl::OutputPromptVaList"} =
  78. $cCustomImplementation;
  79. $gMethodFlagsTable{"IDebugControl::OutputVaList"} =
  80. $cCustomImplementation;
  81. $gMethodFlagsTable{"IDebugControl::RemoveBreakpoint"} =
  82. $cDestroyInObjects | $cObjectsAreProxies;
  83. $gMethodFlagsTable{"IDebugControl::ReturnInput"} =
  84. $cNoThreadCheck | $cNoReturn;
  85. $gMethodFlagsTable{"IDebugControl::SetInterrupt"} =
  86. $cNoThreadCheck | $cNoReturn;
  87. $gMethodFlagsTable{"IDebugSymbols::CreateSymbolGroup"} =
  88. $cObjectsAreProxies;
  89. $gMethodFlagsTable{"IDebugSymbols::GetScopeSymbolGroup"} =
  90. $cObjectsAreProxies | $cDestroyInObjects;
  91. # All callback proxy methods need to allow any thread
  92. # but use the owning thread's connection because the
  93. # engine wants to dispatch callbacks to all clients
  94. # from a single thread.
  95. $gMethodFlagsTable{"IDebugEventCallbacks::ChangeDebuggeeState"} =
  96. $cNoThreadCheck | $cNoReturn;
  97. $gMethodFlagsTable{"IDebugEventCallbacks::ChangeEngineState"} =
  98. $cNoThreadCheck | $cNoReturn;
  99. $gMethodFlagsTable{"IDebugEventCallbacks::ChangeSymbolState"} =
  100. $cNoThreadCheck | $cNoReturn;
  101. $gMethodFlagsTable{"IDebugInputCallbacks::*"} =
  102. $cNoThreadCheck | $cNoReturn;
  103. $gMethodFlagsTable{"IDebugOutputCallbacks::*"} =
  104. $cNoThreadCheck | $cNoReturn;
  105. # RequestBreakIn operates asynchronously.
  106. $gMethodFlagsTable{"IUserDebugServices::RequestBreakIn"} =
  107. $cNoThreadCheck | $cNoReturn;
  108. # All low-level debug services routines are thread-safe
  109. # as they are only called when the engine lock is held.
  110. $gMethodFlagsTable{"IUserDebugServices::*"} =
  111. $cNoThreadCheck | $cCallLocked;
  112. $cTypeStringSize = -1;
  113. $cTypeBufferSize = -2;
  114. $gTypeSize{"LONG"} = 4;
  115. $gAddrOf{"LONG"} = "&";
  116. $gTypeSize{"PLONG"} = 4;
  117. $gTypeSize{"ULONG"} = 4;
  118. $gAddrOf{"ULONG"} = "&";
  119. $gTypeSize{"PULONG"} = 4;
  120. $gTypeSize{"BOOL"} = 4;
  121. $gAddrOf{"BOOL"} = "&";
  122. $gTypeSize{"PBOOL"} = 4;
  123. $gTypeSize{"ULONG64"} = 8;
  124. $gAddrOf{"ULONG64"} = "&";
  125. $gTypeSize{"PULONG64"} = 8;
  126. $gTypeSize{"PSTR"} = $cTypeStringSize;
  127. $gTypeSize{"PCSTR"} = $cTypeStringSize;
  128. $gTypeSize{"PVOID"} = $cTypeBufferSize;
  129. $gTypeSize{"PDEBUG_BREAKPOINT_PARAMETERS"} = 56;
  130. $gTypeAlign{"PDEBUG_BREAKPOINT_PARAMETERS"} = 8;
  131. $gTypeSize{"PDEBUG_STACK_FRAME"} = 128;
  132. $gTypeAlign{"PDEBUG_STACK_FRAME"} = 8;
  133. $gTypeSize{"PDEBUG_VALUE"} = 32;
  134. $gTypeAlign{"PDEBUG_VALUE"} = 8;
  135. $gTypeSize{"PDEBUG_REGISTER_DESCRIPTION"} = 32;
  136. $gTypeAlign{"PDEBUG_REGISTER_DESCRIPTION"} = 8;
  137. $gTypeSize{"PDEBUG_SYMBOL_PARAMETERS"} = 32;
  138. $gTypeAlign{"PDEBUG_SYMBOL_PARAMETERS"} = 8;
  139. $gTypeSize{"PDEBUG_MODULE_PARAMETERS"} = 64;
  140. $gTypeAlign{"PDEBUG_MODULE_PARAMETERS"} = 8;
  141. $gTypeSize{"PDEBUG_SPECIFIC_FILTER_PARAMETERS"} = 20;
  142. $gTypeAlign{"PDEBUG_SPECIFIC_FILTER_PARAMETERS"} = 4;
  143. $gTypeSize{"PDEBUG_EXCEPTION_FILTER_PARAMETERS"} = 24;
  144. $gTypeAlign{"PDEBUG_EXCEPTION_FILTER_PARAMETERS"} = 4;
  145. $gTypeSize{"PEXCEPTION_RECORD64"} = 152;
  146. $gTypeAlign{"PEXCEPTION_RECORD64"} = 8;
  147. $gTypeSize{"PMEMORY_BASIC_INFORMATION64"} = 48;
  148. $gTypeAlign{"PMEMORY_BASIC_INFORMATION64"} = 8;
  149. $gTypeSize{"PUSER_THREAD_INFO"} = 16;
  150. $gTypeAlign{"PUSER_THREAD_INFO"} = 16;
  151. $gProxyRepl{"*::QueryInterface"} = <<"EOQ";
  152. HRESULT Status;
  153. DbgRpcConnection* Conn;
  154. DbgRpcCall Call;
  155. PUCHAR Data;
  156. DbgRpcProxy* Proxy;
  157. IUnknown* Unk;
  158. if ((Conn = DbgRpcGetConnection(m_OwningThread)) == NULL ||
  159. (Data = Conn->StartCall(&Call, m_ObjectId,
  160. DBGRPC_STUB_INDEX(m_InterfaceIndex,
  161. DBGRPC_SMTH_<If>_QueryInterface),
  162. sizeof(IID) + sizeof(ULONG),
  163. sizeof(DbgRpcObjectId))) == NULL)
  164. {
  165. Status = E_OUTOFMEMORY;
  166. }
  167. else
  168. {
  169. ULONG IfUnique;
  170. if ((Status = DbgRpcPreallocProxy_<FileBase>(InterfaceId, (void **)&Unk,
  171. &Proxy, &IfUnique)) == S_OK)
  172. {
  173. *(LPIID)Data = InterfaceId;
  174. // IfUnique is a per-interface unique code generated
  175. // automatically based on the methods and parameters
  176. // in an attempt to create a version-specific identifier.
  177. // This gives us some interface-level protection
  178. // against version mismatches.
  179. *(PULONG)(Data + sizeof(IID)) = IfUnique;
  180. Status = Conn->SendReceive(&Call, &Data);
  181. if (Status == S_OK)
  182. {
  183. *Interface = (PVOID)
  184. Proxy->InitializeProxy(*(DbgRpcObjectId*)Data,
  185. Unk);
  186. }
  187. else
  188. {
  189. delete Unk;
  190. }
  191. }
  192. Conn->FreeData(Data);
  193. }
  194. return Status;
  195. EOQ
  196. #
  197. # Originally AddRefs were never sent across the wire as a
  198. # performance optimization. However, this caused a mismatch
  199. # in behavior between local and remote cases because in the
  200. # remote case objects stored by the engine do not receive
  201. # refcounts since the proxy at the engine side does not
  202. # forward the AddRef. This was changed, but AddRef could
  203. # not simply be added as a method as that would throw
  204. # method tables off. Instead the Release method is overloaded
  205. # to allow both AddRef and Release depending on whether
  206. # in arguments are given. Old binaries will never send
  207. # in arguments so the new stub will only do Release. New
  208. # binaries need to check for the DBGRPC_FULL_REMOTE_UNKNOWN flag
  209. # before sending new-style AddRef-through-Release calls.
  210. #
  211. $gProxyRepl{"*::AddRef"} = <<"EOQ";
  212. DbgRpcConnection* Conn;
  213. DbgRpcCall Call;
  214. PUCHAR Data;
  215. HRESULT Status;
  216. if ((Conn = DbgRpcGetConnection(m_OwningThread)) == NULL)
  217. {
  218. // Nothing that can really be done.
  219. return m_LocalRefs + m_RemoteRefs;
  220. }
  221. if ((Conn->m_Flags & DBGRPC_FULL_REMOTE_UNKNOWN) == 0)
  222. {
  223. return ++m_LocalRefs + m_RemoteRefs;
  224. }
  225. if ((Data = Conn->StartCall(&Call, m_ObjectId,
  226. DBGRPC_STUB_INDEX(m_InterfaceIndex,
  227. DBGRPC_SMTH_<If>_Release),
  228. sizeof(INT32), 0)) == NULL)
  229. {
  230. // Nothing that can really be done.
  231. return m_RemoteRefs;
  232. }
  233. *(INT32*)Data = 1;
  234. Status = Conn->SendReceive(&Call, &Data);
  235. Conn->FreeData(Data);
  236. return ++m_RemoteRefs;
  237. EOQ
  238. $gProxyRepl{"*::Release"} = <<"EOQ";
  239. if (m_LocalRefs > 0)
  240. {
  241. return --m_LocalRefs + m_RemoteRefs;
  242. }
  243. else
  244. {
  245. DbgRpcConnection* Conn;
  246. DbgRpcCall Call;
  247. PUCHAR Data;
  248. HRESULT Status;
  249. if ((Conn = DbgRpcGetConnection(m_OwningThread)) == NULL ||
  250. (Data = Conn->StartCall(&Call, m_ObjectId,
  251. DBGRPC_STUB_INDEX(m_InterfaceIndex,
  252. DBGRPC_SMTH_<If>_Release),
  253. 0, 0)) == NULL)
  254. {
  255. // Nothing that can really be done.
  256. return m_RemoteRefs;
  257. }
  258. Status = Conn->SendReceive(&Call, &Data);
  259. Conn->FreeData(Data);
  260. if (--m_RemoteRefs == 0)
  261. {
  262. delete this;
  263. return 0;
  264. }
  265. else
  266. {
  267. return m_RemoteRefs;
  268. }
  269. }
  270. EOQ
  271. $gStubRepl{"*::QueryInterface"} = <<"EOQ";
  272. ULONG IfUnique = *(PULONG)(${gPre}InData + sizeof(IID));
  273. if (IfUnique != DbgRpcGetIfUnique_<FileBase>(*(LPIID)${gPre}InData))
  274. {
  275. // Version mismatch between client and server.
  276. return RPC_E_VERSION_MISMATCH;
  277. }
  278. *(DbgRpcObjectId*)${gPre}OutData = 0;
  279. return ${gPre}If->QueryInterface(*(LPIID)${gPre}InData,
  280. (void **)${gPre}OutData);
  281. EOQ
  282. $gStubRepl{"*::Release"} = <<"EOQ";
  283. if (${gPre}InData > 0)
  284. {
  285. return (HRESULT)${gPre}If->AddRef();
  286. }
  287. else
  288. {
  289. return (HRESULT)${gPre}If->Release();
  290. }
  291. EOQ
  292. sub Error($)
  293. {
  294. warn "BUILDMSG: $0: $gHeaderFile($.): $_[0]\n";
  295. }
  296. sub ErrorExit($)
  297. {
  298. Error($_[0]);
  299. die;
  300. }
  301. sub Line($)
  302. {
  303. if (($gFile == \*PROXC && ($gMethodFlags & $cCustomProxy)) ||
  304. ($gFile == \*STUBC && ($gMethodFlags & $cCustomStub)))
  305. {
  306. return;
  307. }
  308. print $gFile " " x $gIndent;
  309. print $gFile $_[0];
  310. }
  311. sub CLine($)
  312. {
  313. if (($gMethodFlags & $cCustomProxy) == 0)
  314. {
  315. print PROXC " " x $gIndent;
  316. print PROXC $_[0];
  317. }
  318. if (($gMethodFlags & $cCustomStub) == 0)
  319. {
  320. print STUBC " " x $gIndent;
  321. print STUBC $_[0];
  322. }
  323. }
  324. sub CClean($)
  325. {
  326. if (($gMethodFlags & $cCustomProxy) == 0)
  327. {
  328. print PROXC " " x $gIndent;
  329. print PROXC $_[0];
  330. }
  331. if (($gMethodFlags & $cCustomStub) == 0 &&
  332. $gStubHasCleanup)
  333. {
  334. print STUBC " " x $gIndent;
  335. print STUBC $_[0];
  336. }
  337. }
  338. sub Print($)
  339. {
  340. if (($gFile == \*PROXC && ($gMethodFlags & $cCustomProxy)) ||
  341. ($gFile == \*STUBC && ($gMethodFlags & $cCustomStub)))
  342. {
  343. return;
  344. }
  345. print $gFile $_[0];
  346. }
  347. sub AddIfType($$)
  348. {
  349. my $IfType = $_[0];
  350. my $IfTypedef = $_[1];
  351. push @gIfTypeList, $IfType;
  352. $gIfTypes{$IfTypedef} = $IfType;
  353. $gIfTypes{"$IfTypedef*"} = $IfType;
  354. # Interfaces are represented by
  355. # DbgRpcObjectIds in the stream so
  356. # create artificial type size entries
  357. # that match that size.
  358. $gTypeSize{$IfTypedef} = 8;
  359. $gTypeSize{"$IfTypedef*"} = 8;
  360. # Every interface has a proxy class that
  361. # has some global manipulation code associated
  362. # with it.
  363. print PROXH "$IfType*\nDbgRpcPrealloc${IfType}Proxy(void);\n";
  364. }
  365. sub GenerateIfTypes()
  366. {
  367. my($IfType, $First, $IfCount);
  368. $IfCount = $#gIfTypeList + 1;
  369. $gFile = \*PROXC;
  370. $gIndent = 0;
  371. #
  372. # Generate trailing interface proxy global code for
  373. # each registered interface type.
  374. #
  375. Line("\n");
  376. Line("ULONG\n");
  377. Line("DbgRpcGetIfUnique_$gFileBase(REFIID InterfaceId)\n");
  378. Line("{\n");
  379. $gIndent += 4;
  380. $First = 1;
  381. foreach $IfType (@gIfTypeList)
  382. {
  383. if ($First)
  384. {
  385. $First = 0;
  386. Line("");
  387. }
  388. else
  389. {
  390. Line("else ");
  391. }
  392. Print("if (DbgIsEqualIID(IID_$IfType, InterfaceId))\n");
  393. Line("{\n");
  394. Line(" return DBGRPC_UNIQUE_$IfType;\n");
  395. Line("}\n");
  396. }
  397. Line("else\n");
  398. Line("{\n");
  399. Line(" return 0;\n");
  400. Line("}\n");
  401. $gIndent -= 4;
  402. Line("}\n");
  403. Line("\n");
  404. Line("HRESULT\n");
  405. Line("DbgRpcPreallocProxy_$gFileBase(REFIID InterfaceId, PVOID* Interface,\n");
  406. Line(" DbgRpcProxy** Proxy, PULONG IfUnique)\n");
  407. Line("{\n");
  408. $gIndent += 4;
  409. $First = 1;
  410. foreach $IfType (@gIfTypeList)
  411. {
  412. if ($First)
  413. {
  414. $First = 0;
  415. Line("");
  416. }
  417. else
  418. {
  419. Line("else ");
  420. }
  421. Print("if (DbgIsEqualIID(IID_$IfType, InterfaceId))\n");
  422. Line("{\n");
  423. $gIndent += 4;
  424. Line("Proxy$IfType* IProxy = new Proxy$IfType;\n");
  425. Line("*Interface = IProxy;\n");
  426. Line("*Proxy = IProxy;\n");
  427. Line("*IfUnique = DBGRPC_UNIQUE_$IfType;\n");
  428. $gIndent -= 4;
  429. Line("}\n");
  430. }
  431. Line("else\n");
  432. Line("{\n");
  433. Line(" return E_NOINTERFACE;\n");
  434. Line("}\n");
  435. Line("\n");
  436. Line("return *Interface != NULL ? S_OK : E_OUTOFMEMORY;\n");
  437. $gIndent -= 4;
  438. Line("}\n");
  439. foreach $IfType (@gIfTypeList)
  440. {
  441. Line("\n");
  442. Line("$IfType*\n");
  443. Line("DbgRpcPrealloc${IfType}Proxy(void)\n");
  444. Line("{\n");
  445. Line(" Proxy$IfType* Proxy = new Proxy$IfType;\n");
  446. Line(" return Proxy;\n");
  447. Line("}\n");
  448. }
  449. #
  450. # Now generate stub tables and their initialization functions.
  451. #
  452. $gFile = \*STUBC;
  453. Line("\n");
  454. Line("DbgRpcStubFunctionTable g_DbgRpcStubs_${gFileBase}[$IfCount];\n");
  455. Line("#if DBG\n");
  456. Line("PCSTR* g_DbgRpcStubNames_${gFileBase}[$IfCount];\n");
  457. Line("#endif // #if DBG\n");
  458. Line("\n");
  459. Line("void\n");
  460. Line("DbgRpcInitializeStubTables_$gFileBase(ULONG Base)\n");
  461. Line("{\n");
  462. $gIndent += 4;
  463. foreach $IfType (@gIfTypeList)
  464. {
  465. Line("g_DbgRpcStubs_${gFileBase}[DBGRPC_SIF_$IfType - Base]" .
  466. ".Functions = \n");
  467. Line(" g_DbgRpcStubs_${gFileBase}_$IfType;\n");
  468. Line("g_DbgRpcStubs_${gFileBase}[DBGRPC_SIF_$IfType - Base]" .
  469. ".Count = \n");
  470. Line(" DBGRPC_SMTH_${IfType}_COUNT;\n");
  471. }
  472. $gIndent -= 4;
  473. Line("\n");
  474. Line("#if DBG\n");
  475. $gIndent += 4;
  476. foreach $IfType (@gIfTypeList)
  477. {
  478. Line("g_DbgRpcStubNames_${gFileBase}[DBGRPC_SIF_$IfType - Base] = \n");
  479. Line(" g_DbgRpcStubNames_${gFileBase}_$IfType;\n");
  480. }
  481. $gIndent -= 4;
  482. Line("#endif // #if DBG\n");
  483. Line("}\n");
  484. }
  485. sub AccumulateUnique($)
  486. {
  487. my($Value, @Values);
  488. @Values = unpack("C*", $_[0]);
  489. foreach $Value (@Values)
  490. {
  491. $gIfUnique = ($gIfUnique + $Value) & 0xffffffff;
  492. }
  493. }
  494. sub BeginInterface($)
  495. {
  496. $gIface = $_[0];
  497. $gStubList = "";
  498. $gIfUnique = 0;
  499. print PROXH "\n";
  500. print PROXH "class Proxy$gIface : public $gIface, public DbgRpcProxy\n";
  501. print PROXH "{\n";
  502. print PROXH "public:\n";
  503. print PROXH " Proxy$gIface(void) : DbgRpcProxy(DBGRPC_SIF_$gIface) {}\n";
  504. }
  505. sub FindSizeParam($)
  506. {
  507. my $MatchParam = $_[0];
  508. my($Param);
  509. foreach $Param (@gParams)
  510. {
  511. # Look for the parameter named by size_is.
  512. if ($Param->[$cParamName] eq $MatchParam->[$cParamSizeIs])
  513. {
  514. return $Param;
  515. }
  516. }
  517. # Size parameters were already validated so just return a default.
  518. return "";
  519. }
  520. sub AddSize($$$)
  521. {
  522. my $Which = $_[0];
  523. my $TypeAlign = $_[1];
  524. my $AddSize = $_[2];
  525. Line("${gPre}${Which}Size = ");
  526. if ($TypeAlign > 1)
  527. {
  528. Print("INT_ALIGN2(${gPre}${Which}Size, $TypeAlign)");
  529. }
  530. else
  531. {
  532. Print("${gPre}${Which}Size");
  533. }
  534. Print(" + $AddSize;\n");
  535. }
  536. sub InParamObjectId($$)
  537. {
  538. my $Name = $_[0];
  539. my $IfName = $_[1];
  540. if ($gMethodFlags & $cObjectsAreProxies)
  541. {
  542. return "((Proxy$IfName*)$Name)->m_ObjectId";
  543. }
  544. else
  545. {
  546. return "(DbgRpcObjectId)$Name";
  547. }
  548. }
  549. sub AlignInData($)
  550. {
  551. my $TypeAlign = $_[0];
  552. if ($TypeAlign > 1)
  553. {
  554. Line("${gPre}InData = " .
  555. "PTR_ALIGN2(PUCHAR, ${gPre}InData, $TypeAlign);\n");
  556. }
  557. }
  558. sub AlignOutData($)
  559. {
  560. my $TypeAlign = $_[0];
  561. if ($TypeAlign > 1)
  562. {
  563. Line("${gPre}OutData = " .
  564. "PTR_ALIGN2(PUCHAR, ${gPre}OutData, $TypeAlign);\n");
  565. }
  566. }
  567. sub CollectParams()
  568. {
  569. my($LastParam, $Param);
  570. $LastParam = 0;
  571. @gParams = ();
  572. PARAMS:
  573. while (!$LastParam)
  574. {
  575. # Collect lines up to ',' or end.
  576. $Param = "";
  577. PARAM:
  578. for (;;)
  579. {
  580. $_ = <HEADER>;
  581. chop($_);
  582. $_ =~ s/^\s*//;
  583. if (/^\)( PURE)?;$/)
  584. {
  585. if ($1 ne " PURE")
  586. {
  587. Error("Expecting PURE");
  588. }
  589. $LastParam = 1;
  590. last PARAM;
  591. }
  592. if ($Param)
  593. {
  594. $Param .= " ";
  595. }
  596. $Param .= $_;
  597. if (/,$/)
  598. {
  599. last PARAM;
  600. }
  601. }
  602. if (!$Param)
  603. {
  604. # No arguments.
  605. last PARAMS;
  606. }
  607. print PROXH " " . $Param . "\n";
  608. Line("$Param\n");
  609. AccumulateUnique($Param);
  610. # Skip ...
  611. if ($Param eq "...")
  612. {
  613. next PARAMS;
  614. }
  615. # Trim off trailing chars.
  616. $Param =~ s/,?\s*$//;
  617. #
  618. # Analyze parameter and extract mode, type and name.
  619. #
  620. my($ParamParts, $Part, $InOut, $SizeIs, $AlignIs);
  621. my($ParamType, $ParamName);
  622. @ParamParts = split / /, $Param;
  623. $InOut = 0;
  624. $SizeIs = "";
  625. $AlignIs = "";
  626. $Part = shift @ParamParts;
  627. if ($Part eq "IN")
  628. {
  629. $InOut |= $cPfIn;
  630. $Part = shift @ParamParts;
  631. }
  632. if ($Part eq "OUT")
  633. {
  634. $InOut |= $cPfOut;
  635. $Part = shift @ParamParts;
  636. }
  637. if ($Part eq "OPTIONAL")
  638. {
  639. $InOut |= $cPfOpt;
  640. $Part = shift @ParamParts;
  641. }
  642. if ($Part eq "/*")
  643. {
  644. $Part = shift @ParamParts;
  645. if ($Part =~ /^size_is\((\w+)\)$/)
  646. {
  647. $SizeIs = $1;
  648. $Part = shift @ParamParts;
  649. }
  650. if ($Part =~ /^align_is\(([0-9]+)\)$/)
  651. {
  652. $AlignIs = $1;
  653. $Part = shift @ParamParts;
  654. }
  655. while ($Part ne "*/")
  656. {
  657. Error("Unknown directive $Part");
  658. if ($Part eq "")
  659. {
  660. ErrorExit("Unrecoverable error in directives\n");
  661. }
  662. $Part = shift @ParamParts;
  663. }
  664. # Get next part.
  665. $Part = shift @ParamParts;
  666. }
  667. if (($InOut & ($cPfIn | $cPfOut)) == 0)
  668. {
  669. Error("$gIfaceMethod: No in/out given");
  670. }
  671. $ParamType = $Part;
  672. $Part = shift @ParamParts;
  673. $ParamName = $Part;
  674. if (($InOut & ($cPfIn | $cPfOut)) == ($cPfIn | $cPfOut))
  675. {
  676. if ($gIfTypes{$ParamType} ne "")
  677. {
  678. Error("$gIfaceMethod: In-out interfaces not supported");
  679. }
  680. elsif ($gTypeSize{$ParamType} == $cTypeStringSize ||
  681. $gTypeSize{$ParamType} == $cTypeBufferSize)
  682. {
  683. if ($InOut & $cPfOpt)
  684. {
  685. Error("$gIfaceMethod: In-out optional buffers " .
  686. "not supported");
  687. }
  688. }
  689. }
  690. if (!$SizeIs)
  691. {
  692. # Buffers and out strings have unknown sizes initially.
  693. # By convention buffers and out strings must have a size_is
  694. # parameter of the same name with the suffix Size.
  695. $SizeIs = $gTypeSize{$ParamType};
  696. if ($SizeIs == $cTypeBufferSize ||
  697. ($SizeIs == $cTypeStringSize && ($InOut & $cPfOut)))
  698. {
  699. $SizeIs = $ParamName . "Size";
  700. }
  701. else
  702. {
  703. $SizeIs = "";
  704. }
  705. }
  706. elsif ($gVerbose)
  707. {
  708. warn "$gIfaceMethod: size_is($SizeIs) $ParamName\n";
  709. }
  710. # If no align_is was given use the natural alignment
  711. # for the type.
  712. if (!$AlignIs)
  713. {
  714. $AlignIs = $gTypeAlign{$ParamType};
  715. if (!$AlignIs)
  716. {
  717. $AlignIs = $gTypeSize{$ParamType};
  718. if ($AlignIs < 1)
  719. {
  720. $AlignIs = 1;
  721. }
  722. }
  723. }
  724. elsif ($gVerbose)
  725. {
  726. warn "$gIfaceMethod: align_is($AlignIs) $ParamName\n";
  727. }
  728. push @gParams, [($InOut, $ParamType, $ParamName, $SizeIs, $AlignIs)];
  729. }
  730. my($SizeParam);
  731. # For every sized in-parameter look up and mark the
  732. # corresponding sizing parameter.
  733. # This mark is used later to keep the sizing parameter before
  734. # the sized parameter and not in whatever arbitrary parameter
  735. # position it happens to be in.
  736. foreach $Param (@gParams)
  737. {
  738. if ($Param->[$cParamSizeIs])
  739. {
  740. $SizeParam = FindSizeParam($Param);
  741. if ($SizeParam)
  742. {
  743. if (($SizeParam->[$cParamFlags] &
  744. ($cPfIn | $cPfOut | $cPfOpt)) != $cPfIn)
  745. {
  746. Error("$gIfaceMethod $Param->[$cParamName] " .
  747. "size_is($Param->[$cParamSizeIs]), " .
  748. "size_is must be in-only\n");
  749. }
  750. # Optional parameters always have their own size
  751. # to mark their optionality so don't suppress
  752. # the sizing parameter in that case.
  753. if (($Param->[$cParamFlags] & ($cPfIn | $cPfOpt)) == $cPfIn)
  754. {
  755. if ($gVerbose)
  756. {
  757. warn "$gIfaceMethod: Mark $SizeParam->[$cParamName] " .
  758. "SizeIn for $Param->[$cParamName]\n";
  759. }
  760. $SizeParam->[$cParamFlags] |= $cPfSizeIn;
  761. }
  762. }
  763. elsif (($gMethodFlags & ($cCustomProxy | $cCustomStub)) !=
  764. ($cCustomProxy | $cCustomStub))
  765. {
  766. Error("Sized param $Param->[$cParamName] " .
  767. "has no matching size argument");
  768. }
  769. }
  770. }
  771. return @gParams;
  772. }
  773. # Prepare for object proxies and stubs.
  774. # Compute data size for in and out.
  775. sub ProxyInitializeParams($)
  776. {
  777. my $Param = $_[0];
  778. my($Size, $IfName, $SizeParam);
  779. $Size = $gTypeSize{$Param->[$cParamType]};
  780. $IfName = $gIfTypes{$Param->[$cParamType]};
  781. if ($IfName ne "")
  782. {
  783. if ($gVerbose)
  784. {
  785. warn "$gIfaceMethod: Object param $Param->[$cParamName]\n";
  786. }
  787. if ($Param->[$cParamFlags] & $cPfIn)
  788. {
  789. AddSize("In", $Param->[$cParamAlignIs], $Size);
  790. }
  791. elsif ($Param->[$cParamFlags] & $cPfOut)
  792. {
  793. if ($gMethodFlags & $cObjectsAreProxies)
  794. {
  795. # Prepare out parameters for proxies.
  796. Line("*$Param->[$cParamName] = " .
  797. "DbgRpcPrealloc${IfName}Proxy();\n");
  798. }
  799. AddSize("Out", $Param->[$cParamAlignIs], $Size);
  800. }
  801. }
  802. else
  803. {
  804. if ($Param->[$cParamFlags] & $cPfIn)
  805. {
  806. if ($Size > 0)
  807. {
  808. if ($Param->[$cParamSizeIs])
  809. {
  810. $SizeParam = FindSizeParam($Param);
  811. AddSize("In", $SizeParam->[$cParamAlignIs],
  812. $gTypeSize{$SizeParam->[$cParamType]});
  813. $Size .= " * $Param->[$cParamSizeIs]";
  814. }
  815. elsif ($Param->[$cParamFlags] & $cPfOpt)
  816. {
  817. # Optional pointer parameters generate
  818. # a size to mark whether they're non-NULL.
  819. AddSize("In", $gTypeSize{"ULONG"}, $gTypeSize{"ULONG"});
  820. }
  821. if ($Param->[$cParamFlags] & $cPfOpt)
  822. {
  823. Line("if ($Param->[$cParamName] != NULL)\n");
  824. Line("{\n");
  825. $gIndent += 4;
  826. }
  827. AddSize("In", $Param->[$cParamAlignIs], $Size);
  828. if ($Param->[$cParamFlags] & $cPfOpt)
  829. {
  830. $gIndent -= 4;
  831. Line("}\n");
  832. }
  833. }
  834. elsif ($Size == $cTypeStringSize)
  835. {
  836. if ($Param->[$cParamFlags] & $cPfOpt)
  837. {
  838. # Pass both a length and the string
  839. # to handle NULLs.
  840. Line("ULONG ${gPre}Len_$Param->[$cParamName] = " .
  841. "$Param->[$cParamName] != NULL ? " .
  842. "strlen($Param->[$cParamName]) + 1 : 0;\n");
  843. AddSize("In", $gTypeSize{"ULONG"},
  844. "${gPre}Len_$Param->[$cParamName] + " .
  845. $gTypeSize{"ULONG"});
  846. }
  847. else
  848. {
  849. Line("ULONG ${gPre}Len_$Param->[$cParamName] = " .
  850. "strlen($Param->[$cParamName]) + 1;\n");
  851. AddSize("In", 1, "${gPre}Len_$Param->[$cParamName]");
  852. }
  853. }
  854. elsif ($Size == $cTypeBufferSize)
  855. {
  856. $SizeParam = FindSizeParam($Param);
  857. if ($Param->[$cParamFlags] & $cPfOpt)
  858. {
  859. Line("$SizeParam->[$cParamName] = " .
  860. "$Param->[$cParamName] != NULL ? " .
  861. "$SizeParam->[$cParamName] : 0;\n");
  862. }
  863. # Include the size parameter.
  864. AddSize("In", $SizeParam->[$cParamAlignIs],
  865. $gTypeSize{$SizeParam->[$cParamType]});
  866. AddSize("In", $Param->[$cParamAlignIs],
  867. $SizeParam->[$cParamName]);
  868. }
  869. else
  870. {
  871. Error("Unknown in param size: $Param->[$cParamName]");
  872. }
  873. }
  874. if ($Param->[$cParamFlags] & $cPfOut)
  875. {
  876. if ($Size > 0)
  877. {
  878. # Non-size_is out parameters are always passed
  879. # on the stub side so always include space for
  880. # them even if they're optional and NULL. The
  881. # NULL check happens in the out-param write-back
  882. # code.
  883. if ($Param->[$cParamSizeIs])
  884. {
  885. # size_is pointers do need optionality checks.
  886. if ($Param->[$cParamFlags] & $cPfOpt)
  887. {
  888. Line("if ($Param->[$cParamName] != NULL)\n");
  889. Line("{\n");
  890. $gIndent += 4;
  891. }
  892. $Size .= " * $Param->[$cParamSizeIs]";
  893. }
  894. AddSize("Out", $Param->[$cParamAlignIs], $Size);
  895. if ($Param->[$cParamSizeIs] &&
  896. ($Param->[$cParamFlags] & $cPfOpt))
  897. {
  898. $gIndent -= 4;
  899. Line("}\n");
  900. }
  901. }
  902. elsif ($Size == $cTypeStringSize ||
  903. $Size == $cTypeBufferSize)
  904. {
  905. $SizeParam = FindSizeParam($Param);
  906. if ($Param->[$cParamFlags] & $cPfOpt)
  907. {
  908. Line("$SizeParam->[$cParamName] = " .
  909. "$Param->[$cParamName] != NULL ? " .
  910. "$SizeParam->[$cParamName] : 0;\n");
  911. }
  912. AddSize("Out", $Param->[$cParamAlignIs],
  913. $SizeParam->[$cParamName]);
  914. }
  915. else
  916. {
  917. Error("Unknown out param size: $Param->[$cParamName]");
  918. }
  919. }
  920. }
  921. }
  922. # Check object proxies.
  923. sub ProxyValidateParams($)
  924. {
  925. my $Param = $_[0];
  926. my($IfName);
  927. if ($Param->[$cParamFlags] & $cPfOut)
  928. {
  929. $IfName = $gIfTypes{$Param->[$cParamType]};
  930. if ($IfName ne "")
  931. {
  932. Line("if (*$Param->[$cParamName] == NULL)\n");
  933. Line("{\n");
  934. Line(" goto CheckStatus;\n");
  935. Line("}\n");
  936. }
  937. }
  938. }
  939. # Copy in-parameter data into packet.
  940. sub ProxyCopyInParams($)
  941. {
  942. my $Param = $_[0];
  943. my($Size, $IfName);
  944. $Size = $gTypeSize{$Param->[$cParamType]};
  945. $IfName = $gIfTypes{$Param->[$cParamType]};
  946. if ($IfName ne "")
  947. {
  948. AlignInData($Param->[$cParamAlignIs]);
  949. if ($Param->[$cParamFlags] & $cPfOpt)
  950. {
  951. Line("if ($Param->[$cParamName] == NULL)\n");
  952. Line("{\n");
  953. Line(" *(DbgRpcObjectId*)${gPre}InData = 0;\n");
  954. Line("}\n");
  955. Line("else\n");
  956. Line("{\n");
  957. $gIndent += 4;
  958. }
  959. Line("*(DbgRpcObjectId*)${gPre}InData = " .
  960. InParamObjectId($Param->[$cParamName], $IfName) . ";\n");
  961. if ($Param->[$cParamFlags] & $cPfOpt)
  962. {
  963. $gIndent -= 4;
  964. Line("}\n");
  965. }
  966. Line("${gPre}InData += $Size;\n");
  967. }
  968. elsif ($Size == $cTypeStringSize)
  969. {
  970. if ($Param->[$cParamFlags] & $cPfOpt)
  971. {
  972. # Always write out the size.
  973. AlignInData($gTypeSize{"ULONG"});
  974. Line("*(ULONG*)${gPre}InData = " .
  975. "${gPre}Len_$Param->[$cParamName];\n");
  976. Line("${gPre}InData += " . $gTypeSize{"ULONG"} . ";\n");
  977. }
  978. else
  979. {
  980. AlignInData($Param->[$cParamAlignIs]);
  981. }
  982. Line("memcpy(${gPre}InData, $Param->[$cParamName], " .
  983. "${gPre}Len_$Param->[$cParamName]);\n");
  984. Line("${gPre}InData += " .
  985. "${gPre}Len_$Param->[$cParamName];\n");
  986. }
  987. elsif ($Size == $cTypeBufferSize)
  988. {
  989. $SizeParam = FindSizeParam($Param);
  990. AlignInData($SizeParam->[$cParamAlignIs]);
  991. Line("*($SizeParam->[$cParamType]*)${gPre}InData = " .
  992. "$SizeParam->[$cParamName];\n");
  993. Line("${gPre}InData += " . $gTypeSize{$SizeParam->[$cParamType]} .
  994. ";\n");
  995. AlignInData($Param->[$cParamAlignIs]);
  996. Line("memcpy(${gPre}InData, $Param->[$cParamName], " .
  997. "$Param->[$cParamSizeIs]);\n");
  998. Line("${gPre}InData += $Param->[$cParamSizeIs];\n");
  999. }
  1000. else
  1001. {
  1002. my($AddrOf);
  1003. $AddrOf = $gAddrOf{$Param->[$cParamType]};
  1004. if ($Param->[$cParamSizeIs])
  1005. {
  1006. if ($AddrOf)
  1007. {
  1008. # size_is parameters should always be arrays.
  1009. ErrorExit("AddrOf for size_is parameter\n");
  1010. }
  1011. # Always write out the size.
  1012. $SizeParam = FindSizeParam($Param);
  1013. AlignInData($SizeParam->[$cParamAlignIs]);
  1014. if ($Param->[$cParamFlags] & $cPfOpt)
  1015. {
  1016. Line("*($SizeParam->[$cParamType]*)${gPre}InData = " .
  1017. "$Param->[$cParamName] != NULL ? " .
  1018. "$SizeParam->[$cParamName] : 0;\n");
  1019. }
  1020. else
  1021. {
  1022. Line("*($SizeParam->[$cParamType]*)${gPre}InData = " .
  1023. "$SizeParam->[$cParamName];\n");
  1024. }
  1025. Line("${gPre}InData += " .
  1026. $gTypeSize{$SizeParam->[$cParamType]} . ";\n");
  1027. $Size .= " * $SizeParam->[$cParamName]";
  1028. }
  1029. elsif ($Param->[$cParamFlags] & $cPfOpt)
  1030. {
  1031. AlignInData($gTypeSize{"ULONG"});
  1032. Line("*(ULONG*)${gPre}InData = " .
  1033. "$Param->[$cParamName] != NULL ? $Size : 0;\n");
  1034. Line("${gPre}InData += " . $gTypeSize{"ULONG"} . ";\n");
  1035. }
  1036. if ($Param->[$cParamFlags] & $cPfOpt)
  1037. {
  1038. Line("if ($Param->[$cParamName] != NULL)\n");
  1039. Line("{\n");
  1040. $gIndent += 4;
  1041. }
  1042. AlignInData($Param->[$cParamAlignIs]);
  1043. if ($AddrOf)
  1044. {
  1045. # If there's an AddrOf this is an atomic type
  1046. # so copy using the type rather than memcpy as
  1047. # the compiler can generate more efficient code
  1048. # since it can assume alignment.
  1049. Line("*($Param->[$cParamType]*)${gPre}InData = " .
  1050. "$Param->[$cParamName];\n");
  1051. }
  1052. else
  1053. {
  1054. Line("memcpy(${gPre}InData, $AddrOf" .
  1055. "$Param->[$cParamName], $Size);\n");
  1056. }
  1057. Line("${gPre}InData += $Size;\n");
  1058. if ($Param->[$cParamFlags] & $cPfOpt)
  1059. {
  1060. $gIndent -= 4;
  1061. Line("}\n");
  1062. }
  1063. }
  1064. }
  1065. # Copy out-parameter data to real out parameters.
  1066. # Initialize or clean up object proxies.
  1067. sub ProxyFinalizeParamsSuccess($)
  1068. {
  1069. my $Param = $_[0];
  1070. my($Size, $IfName, $SizeParam);
  1071. $Size = $gTypeSize{$Param->[$cParamType]};
  1072. $IfName = $gIfTypes{$Param->[$cParamType]};
  1073. if ($IfName ne "")
  1074. {
  1075. if ($Param->[$cParamFlags] & $cPfOut)
  1076. {
  1077. AlignOutData($Param->[$cParamAlignIs]);
  1078. if ($gMethodFlags & $cObjectsAreProxies)
  1079. {
  1080. Line("*$Param->[$cParamName] = ($IfName*)\n");
  1081. Line(" ((Proxy$IfName*)(*$Param->[$cParamName]))->\n");
  1082. Line(" InitializeProxy" .
  1083. "(*(DbgRpcObjectId*)${gPre}OutData,\n");
  1084. Line(" *(IUnknown **)$Param->[$cParamName]);\n");
  1085. }
  1086. else
  1087. {
  1088. Line("*$Param->[$cParamName] = ($IfName*)" .
  1089. "*(DbgRpcObjectId*)${gPre}OutData;\n");
  1090. }
  1091. Line("${gPre}OutData += $Size;\n");
  1092. }
  1093. }
  1094. elsif ($Param->[$cParamFlags] & $cPfOut)
  1095. {
  1096. if ($Size == $cTypeStringSize ||
  1097. $Size == $cTypeBufferSize)
  1098. {
  1099. AlignOutData($Param->[$cParamAlignIs]);
  1100. $SizeParam = FindSizeParam($Param);
  1101. Line("memcpy($Param->[$cParamName], ${gPre}OutData, " .
  1102. "$SizeParam->[$cParamName]);\n");
  1103. Line("${gPre}OutData += $SizeParam->[$cParamName];\n");
  1104. }
  1105. else
  1106. {
  1107. my($IsAtomic);
  1108. $IsAtomic = $Size <= 8;
  1109. if ($Param->[$cParamSizeIs])
  1110. {
  1111. $Size .= " * $Param->[$cParamSizeIs]";
  1112. $IsAtomic = 0;
  1113. }
  1114. if ($Param->[$cParamFlags] & $cPfOpt)
  1115. {
  1116. # If there's no size_is the out size is always
  1117. # added even if the parameter is NULL.
  1118. if (!$Param->[$cParamSizeIs])
  1119. {
  1120. AlignOutData($Param->[$cParamAlignIs]);
  1121. }
  1122. Line("if ($Param->[$cParamName] != NULL)\n");
  1123. Line("{\n");
  1124. $gIndent += 4;
  1125. if ($Param->[$cParamSizeIs])
  1126. {
  1127. AlignOutData($Param->[$cParamAlignIs]);
  1128. }
  1129. }
  1130. else
  1131. {
  1132. AlignOutData($Param->[$cParamAlignIs]);
  1133. }
  1134. if ($IsAtomic)
  1135. {
  1136. # If there's an AddrOf this is an atomic type
  1137. # so copy using the type rather than memcpy as
  1138. # the compiler can generate more efficient code
  1139. # since it can assume alignment.
  1140. Line("*$Param->[$cParamName] = *($Param->[$cParamType])" .
  1141. "${gPre}OutData;\n");
  1142. }
  1143. else
  1144. {
  1145. Line("memcpy($Param->[$cParamName], ${gPre}OutData, " .
  1146. "$Size);\n");
  1147. }
  1148. if (($Param->[$cParamFlags] & $cPfOpt) == 0)
  1149. {
  1150. Line("${gPre}OutData += $Size;\n");
  1151. }
  1152. else
  1153. {
  1154. if ($Param->[$cParamSizeIs])
  1155. {
  1156. Line("${gPre}OutData += $Size;\n");
  1157. }
  1158. $gIndent -= 4;
  1159. Line("}\n");
  1160. if (!$Param->[$cParamSizeIs])
  1161. {
  1162. Line("${gPre}OutData += $Size;\n");
  1163. }
  1164. }
  1165. }
  1166. }
  1167. }
  1168. sub ProxyFinalizeParamsFailure($)
  1169. {
  1170. my $Param = $_[0];
  1171. my($IfName);
  1172. # Clean up unused proxies and stubs.
  1173. if (($gMethodFlags & $cObjectsAreProxies) &&
  1174. ($Param->[$cParamFlags] & $cPfOut))
  1175. {
  1176. $IfName = $gIfTypes{$Param->[$cParamType]};
  1177. if ($IfName ne "")
  1178. {
  1179. Line("if (*$Param->[$cParamName] != NULL)\n");
  1180. Line("{\n");
  1181. Line(" delete (Proxy$IfName*)(*$Param->[$cParamName]);\n");
  1182. Line(" *$Param->[$cParamName] = NULL;\n");
  1183. Line("}\n");
  1184. }
  1185. }
  1186. }
  1187. # Get rid of proxies representing objects that
  1188. # were freed by the call.
  1189. sub ProxyDestroyInObjects($)
  1190. {
  1191. my $Param = $_[0];
  1192. my($IfName);
  1193. # Special case for cleaning up stubs for methods
  1194. # that destroy their input objects. This
  1195. # flag should only be set for cases where it is
  1196. # known that the objects are proxies.
  1197. if ($gMethodFlags & $cDestroyInObjects)
  1198. {
  1199. if ($Param->[$cParamFlags] & $cPfIn)
  1200. {
  1201. $IfName = $gIfTypes{$Param->[$cParamType]};
  1202. if ($IfName ne "")
  1203. {
  1204. Line("delete (Proxy$IfName *)$Param->[$cParamName];\n");
  1205. }
  1206. }
  1207. }
  1208. }
  1209. # Declares parameters and creates proxies for incoming objects.
  1210. sub StubInitializeParams($)
  1211. {
  1212. my $Param = $_[0];
  1213. my($IfName);
  1214. Line("$Param->[$cParamType] $Param->[$cParamName];\n");
  1215. if (($gMethodFlags & $cObjectsAreProxies) == 0 &&
  1216. ($Param->[$cParamFlags] & $cPfIn))
  1217. {
  1218. $IfName = $gIfTypes{$Param->[$cParamType]};
  1219. if ($IfName ne "")
  1220. {
  1221. Line("$Param->[$cParamName] = ($Param->[$cParamType])\n");
  1222. Line(" DbgRpcPrealloc${IfName}Proxy();\n");
  1223. $gStubHasCleanup = 1;
  1224. }
  1225. }
  1226. }
  1227. # Check object proxies.
  1228. sub StubValidateParams($)
  1229. {
  1230. my $Param = $_[0];
  1231. my($IfName);
  1232. if (($gMethodFlags & $cObjectsAreProxies) == 0 &&
  1233. ($Param->[$cParamFlags] & $cPfIn))
  1234. {
  1235. $IfName = $gIfTypes{$Param->[$cParamType]};
  1236. if ($IfName ne "")
  1237. {
  1238. Line("if ($Param->[$cParamName] == NULL)\n");
  1239. Line("{\n");
  1240. Line(" goto CheckStatus;\n");
  1241. Line("}\n");
  1242. }
  1243. }
  1244. }
  1245. sub StubOptPointer($$$$$)
  1246. {
  1247. my $DataPre = $_[0];
  1248. my $Param = $_[1];
  1249. my $SizeName = $_[2];
  1250. my $SizeType = $_[3];
  1251. my $SizeAdd = $_[4];
  1252. if (!$SizeAdd)
  1253. {
  1254. $SizeAdd = $SizeName;
  1255. }
  1256. # All optional parameters are assumed to be pointer
  1257. # variables preceeded by a ULONG size. If the
  1258. # size is zero, use NULL for the argument.
  1259. # In parameters need to retrieve the size now.
  1260. # Out parameters are done after all in parameters
  1261. # so their size should already be available.
  1262. if ($Param->[$cParamFlags] & $cPfIn)
  1263. {
  1264. if ($DataPre eq "Out")
  1265. {
  1266. AlignOutData($gTypeSize{$SizeType});
  1267. }
  1268. else
  1269. {
  1270. AlignInData($gTypeSize{$SizeType});
  1271. }
  1272. Line("$SizeName = *($SizeType*)${gPre}${DataPre}Data;\n");
  1273. Line("${gPre}${DataPre}Data += $gTypeSize{$SizeType};\n");
  1274. }
  1275. Line("if ($SizeName == 0)\n");
  1276. Line("{\n");
  1277. Line(" $Param->[$cParamName] = NULL;\n");
  1278. Line("}\n");
  1279. Line("else\n");
  1280. Line("{\n");
  1281. $gIndent += 4;
  1282. if ($DataPre eq "Out")
  1283. {
  1284. AlignOutData($Param->[$cParamAlignIs]);
  1285. }
  1286. else
  1287. {
  1288. AlignInData($Param->[$cParamAlignIs]);
  1289. }
  1290. Line("$Param->[$cParamName] = " .
  1291. "($Param->[$cParamType])${gPre}${DataPre}Data;\n");
  1292. Line("${gPre}${DataPre}Data += $SizeAdd;\n");
  1293. $gIndent -= 4;
  1294. Line("}\n");
  1295. }
  1296. # Assign in parameter values from incoming packet data.
  1297. sub StubAssignInParams($)
  1298. {
  1299. my $Param = $_[0];
  1300. my($Size, $IfName);
  1301. $Size = $gTypeSize{$Param->[$cParamType]};
  1302. $IfName = $gIfTypes{$Param->[$cParamType]};
  1303. if ($IfName ne "")
  1304. {
  1305. AlignInData($Param->[$cParamAlignIs]);
  1306. if ($gMethodFlags & $cObjectsAreProxies)
  1307. {
  1308. Line("$Param->[$cParamName] = " .
  1309. "*($Param->[$cParamType]*)${gPre}InData;\n");
  1310. }
  1311. else
  1312. {
  1313. Line("$Param->[$cParamName] = ($Param->[$cParamType])" .
  1314. "((Proxy$IfName*)$Param->[$cParamName])->\n");
  1315. Line(" InitializeProxy(*(DbgRpcObjectId*)${gPre}InData, " .
  1316. "(IUnknown*)$Param->[$cParamName]);\n");
  1317. }
  1318. Line("${gPre}InData += $Size;\n");
  1319. }
  1320. elsif ($Size == $cTypeStringSize)
  1321. {
  1322. if ($Param->[$cParamFlags] & $cPfOpt)
  1323. {
  1324. Line("ULONG ${gPre}Len_$Param->[$cParamName];\n");
  1325. StubOptPointer("In", $Param, "${gPre}Len_$Param->[$cParamName]",
  1326. "ULONG", "");
  1327. }
  1328. else
  1329. {
  1330. AlignInData($Param->[$cParamAlignIs]);
  1331. Line("$Param->[$cParamName] = " .
  1332. "($Param->[$cParamType])${gPre}InData;\n");
  1333. Line("${gPre}InData += " .
  1334. "strlen($Param->[$cParamName]) + 1;\n");
  1335. }
  1336. }
  1337. elsif ($Size == $cTypeBufferSize)
  1338. {
  1339. $SizeParam = FindSizeParam($Param);
  1340. Line("$SizeParam->[$cParamType] ${gPre}Len_$Param->[$cParamName];\n");
  1341. if ($Param->[$cParamFlags] & $cPfOpt)
  1342. {
  1343. StubOptPointer("In", $Param, "${gPre}Len_$Param->[$cParamName]",
  1344. $SizeParam->[$cParamType], "");
  1345. }
  1346. else
  1347. {
  1348. # Get size parameter first.
  1349. AlignInData($gTypeSize{$SizeParam->[$cParamType]});
  1350. Line("${gPre}Len_$Param->[$cParamName] = " .
  1351. "*($SizeParam->[$cParamType]*)${gPre}InData;\n");
  1352. Line("${gPre}InData += $gTypeSize{$SizeParam->[$cParamType]};\n");
  1353. AlignInData($Param->[$cParamAlignIs]);
  1354. Line("$Param->[$cParamName] = " .
  1355. "($Param->[$cParamType])${gPre}InData;\n");
  1356. Line("${gPre}InData += ${gPre}Len_$Param->[$cParamName];\n");
  1357. }
  1358. }
  1359. else
  1360. {
  1361. if ($Param->[$cParamFlags] & $cPfOpt)
  1362. {
  1363. if ($Param->[$cParamSizeIs])
  1364. {
  1365. $SizeParam = FindSizeParam($Param);
  1366. Line("$SizeParam->[$cParamType] " .
  1367. "${gPre}Len_$Param->[$cParamName];\n");
  1368. $Size .= " * ${gPre}Len_$Param->[$cParamName]";
  1369. StubOptPointer("In", $Param,
  1370. "${gPre}Len_$Param->[$cParamName]",
  1371. $SizeParam->[$cParamType], $Size);
  1372. }
  1373. else
  1374. {
  1375. Line("ULONG ${gPre}Len_$Param->[$cParamName];\n");
  1376. StubOptPointer("In", $Param,
  1377. "${gPre}Len_$Param->[$cParamName]",
  1378. "ULONG", "");
  1379. }
  1380. }
  1381. else
  1382. {
  1383. my($AddrOf);
  1384. $AddrOf = $gAddrOf{$Param->[$cParamType]};
  1385. if ($Param->[$cParamSizeIs])
  1386. {
  1387. # Get size parameter first.
  1388. $SizeParam = FindSizeParam($Param);
  1389. Line("$SizeParam->[$cParamType] " .
  1390. "${gPre}Len_$Param->[$cParamName];\n");
  1391. AlignInData($gTypeSize{$SizeParam->[$cParamType]});
  1392. Line("${gPre}Len_$Param->[$cParamName] = " .
  1393. "*($SizeParam->[$cParamType]*)${gPre}InData;\n");
  1394. Line("${gPre}InData += " .
  1395. "$gTypeSize{$SizeParam->[$cParamType]};\n");
  1396. $Size .= " * ${gPre}Len_$Param->[$cParamName]";
  1397. }
  1398. AlignInData($Param->[$cParamAlignIs]);
  1399. if ($AddrOf)
  1400. {
  1401. # If there's an AddrOf this is an atomic type
  1402. # so copy using the type rather than memcpy as
  1403. # the compiler can generate more efficient code
  1404. # since it can assume alignment.
  1405. Line("$Param->[$cParamName] = " .
  1406. "*($Param->[$cParamType]*)${gPre}InData;\n");
  1407. }
  1408. else
  1409. {
  1410. Line("$Param->[$cParamName] = ($Param->[$cParamType])" .
  1411. "${gPre}InData;\n");
  1412. }
  1413. Line("${gPre}InData += $Size;\n");
  1414. }
  1415. }
  1416. }
  1417. # Assign out parameter values by pointing into outgoing packet data.
  1418. sub StubAssignOutParams($)
  1419. {
  1420. my $Param = $_[0];
  1421. my($Size, $IfName);
  1422. $Size = $gTypeSize{$Param->[$cParamType]};
  1423. $IfName = $gIfTypes{$Param->[$cParamType]};
  1424. if ($IfName ne "")
  1425. {
  1426. AlignOutData($Param->[$cParamAlignIs]);
  1427. Line("*(DbgRpcObjectId*)${gPre}OutData = 0;\n");
  1428. Line("$Param->[$cParamName] = " .
  1429. "($Param->[$cParamType])${gPre}OutData;\n");
  1430. Line("${gPre}OutData += $Size;\n");
  1431. # If objects aren't proxies on the proxy side that
  1432. # means they're proxies on the stub side and
  1433. # need to be unwrapped when returning them.
  1434. if (($gMethodFlags & $cObjectsAreProxies) == 0)
  1435. {
  1436. $gStubReturnsProxies = 1;
  1437. }
  1438. }
  1439. elsif ($Size == $cTypeStringSize ||
  1440. $Size == $cTypeBufferSize)
  1441. {
  1442. $SizeParam = FindSizeParam($Param);
  1443. if ($Param->[$cParamFlags] & $cPfOpt)
  1444. {
  1445. StubOptPointer("Out", $Param, $SizeParam->[$cParamName],
  1446. $SizeParam->[$cParamType], "");
  1447. }
  1448. else
  1449. {
  1450. AlignOutData($Param->[$cParamAlignIs]);
  1451. if ($Param->[$cParamFlags] & $cPfIn)
  1452. {
  1453. # This is an in-out parameter so copy the
  1454. # input data over the output area to initialize
  1455. # it before the call.
  1456. # OutData is pointing to the output area and
  1457. # the parameter name has already been initialized
  1458. # to the input data from the input parameter pass.
  1459. if ($Size == $cTypeStringSize)
  1460. {
  1461. Line("strcpy((PSTR)${gPre}OutData, " .
  1462. "$Param->[$cParamName]);\n");
  1463. }
  1464. else
  1465. {
  1466. Line("memcpy(${gPre}OutData, $Param->[$cParamName], " .
  1467. "$SizeParam->[$cParamName]);\n");
  1468. }
  1469. }
  1470. Line("$Param->[$cParamName] = " .
  1471. "($Param->[$cParamType])${gPre}OutData;\n");
  1472. Line("${gPre}OutData += $SizeParam->[$cParamName];\n");
  1473. }
  1474. }
  1475. else
  1476. {
  1477. if ($Param->[$cParamSizeIs])
  1478. {
  1479. $SizeParam = FindSizeParam($Param);
  1480. $Size .= " * $SizeParam->[$cParamName]";
  1481. if ($Param->[$cParamFlags] & $cPfOpt)
  1482. {
  1483. StubOptPointer("Out", $Param, $SizeParam->[$cParamName],
  1484. $SizeParam->[$cParamType], $Size);
  1485. }
  1486. else
  1487. {
  1488. AlignOutData($Param->[$cParamAlignIs]);
  1489. Line("$Param->[$cParamName] = " .
  1490. "($Param->[$cParamType])${gPre}OutData;\n");
  1491. Line("${gPre}OutData += $Size;\n");
  1492. }
  1493. }
  1494. else
  1495. {
  1496. # Atomic out parameters are always given space in the
  1497. # output data even if they are optional. Always
  1498. # assign them to their appropriate out packet
  1499. # location and pass them in.
  1500. AlignOutData($Param->[$cParamAlignIs]);
  1501. Line("$Param->[$cParamName] = " .
  1502. "($Param->[$cParamType])${gPre}OutData;\n");
  1503. Line("${gPre}OutData += $Size;\n");
  1504. }
  1505. }
  1506. }
  1507. # Unwrap proxies if necessary.
  1508. sub StubFinalizeParamsSuccess($)
  1509. {
  1510. my $Param = $_[0];
  1511. my($IfName);
  1512. if ($Param->[$cParamFlags] & $cPfOut)
  1513. {
  1514. $IfName = $gIfTypes{$Param->[$cParamType]};
  1515. if ($IfName ne "")
  1516. {
  1517. Line("*(DbgRpcObjectId*)$Param->[$cParamName] = " .
  1518. "((Proxy$IfName*)*$Param->[$cParamName])->m_ObjectId;\n");
  1519. }
  1520. }
  1521. }
  1522. # Clean up any allocated proxies.
  1523. sub StubFinalizeParamsFailure($)
  1524. {
  1525. my $Param = $_[0];
  1526. my($IfName);
  1527. if (($gMethodFlags & $cObjectsAreProxies) == 0 &&
  1528. ($Param->[$cParamFlags] & $cPfIn))
  1529. {
  1530. $IfName = $gIfTypes{$Param->[$cParamType]};
  1531. if ($IfName ne "")
  1532. {
  1533. Line("delete (Proxy$IfName*)$Param->[$cParamName];\n");
  1534. }
  1535. }
  1536. }
  1537. sub IfMethod($$$)
  1538. {
  1539. my $Method = $_[0];
  1540. my $CallType = $_[1];
  1541. my $RetType = $_[2];
  1542. my($TableName, $Param, $Repl, $IfaceBase, $IfaceVer);
  1543. AccumulateUnique($Method);
  1544. AccumulateUnique($CallType);
  1545. AccumulateUnique($RetType);
  1546. $gMethod = $Method;
  1547. $gIfaceMethod = $gIface . "::" . $gMethod;
  1548. #
  1549. # Look for method flags for a method specific
  1550. # to this interface, then all previous interface
  1551. # versions, then a generic method.
  1552. #
  1553. # Get the interface version.
  1554. if ($gIface =~ /^(\w+)([0-9]+)$/)
  1555. {
  1556. $IfaceBase = $1;
  1557. $IfaceVer = $2;
  1558. }
  1559. else
  1560. {
  1561. $IfaceBase = $gIface;
  1562. $IfaceVer = 1;
  1563. }
  1564. # Search from the current version backwards.
  1565. while ($IfaceVer >= 1)
  1566. {
  1567. if ($IfaceVer == 1)
  1568. {
  1569. $TableName = $IfaceBase . "::" . $gMethod;
  1570. }
  1571. else
  1572. {
  1573. $TableName = $IfaceBase . $IfaceVer . "::" . $gMethod;
  1574. }
  1575. $gMethodFlags = $gMethodFlagsTable{$TableName};
  1576. if ($gMethodFlags)
  1577. {
  1578. break;
  1579. }
  1580. $IfaceVer--;
  1581. }
  1582. # Check for a generic method.
  1583. if ($gMethodFlags == 0)
  1584. {
  1585. $TableName = "*::" . $gMethod;
  1586. $gMethodFlags = $gMethodFlagsTable{$TableName};
  1587. if ($gMethodFlags == 0)
  1588. {
  1589. $TableName = $gIface . "::*";
  1590. $gMethodFlags = $gMethodFlagsTable{$TableName};
  1591. }
  1592. }
  1593. #
  1594. # Begin prototype and implementation.
  1595. # STDMETHODV methods are assumed to have a custom
  1596. # implementation as it is impossible to autogenerate
  1597. # code for them.
  1598. #
  1599. if ($CallType eq "V")
  1600. {
  1601. $gMethodFlags |= $cCustomProxy | $cNoStub;
  1602. }
  1603. $gFile = \*PROXC;
  1604. $gIndent = 0;
  1605. Line("\n");
  1606. if ($RetType)
  1607. {
  1608. print PROXH " STDMETHOD${CallType}_($RetType, $gMethod)(\n";
  1609. Line("STDMETHODIMP${CallType}_($RetType)\n");
  1610. }
  1611. else
  1612. {
  1613. print PROXH " STDMETHOD${CallType}($gMethod)(\n";
  1614. Line("STDMETHODIMP${CallType}\n");
  1615. }
  1616. Line("Proxy$gIfaceMethod(\n");
  1617. if (($gMethodFlags & $cNoStub) != $cNoStub)
  1618. {
  1619. $gStubList .= " DBGRPC_SMTH_${gIface}_${gMethod},\n";
  1620. if ($gMethodFlags & $cCustomStub)
  1621. {
  1622. $gFile = \*STUBH;
  1623. }
  1624. else
  1625. {
  1626. $gFile = \*STUBC;
  1627. }
  1628. Line("\n");
  1629. Line("HRESULT\nSFN_${gIface}_${gMethod}(\n");
  1630. Line(" IUnknown* ${gPre}If,\n");
  1631. Line(" DbgRpcConnection* ${gPre}Conn,\n");
  1632. Line(" DbgRpcCall* ${gPre}Call,\n");
  1633. Line(" PUCHAR ${gPre}InData,\n");
  1634. Line(" PUCHAR ${gPre}OutData\n");
  1635. }
  1636. #
  1637. # Process arguments and complete declarations.
  1638. #
  1639. # Skip THIS. Unnecessary since implementation is C++.
  1640. $_ = <HEADER>;
  1641. if (!/^\s+THIS_?\s*$/)
  1642. {
  1643. Error("Expecting THIS");
  1644. }
  1645. $gFile = \*PROXC;
  1646. $gIndent += 4;
  1647. CollectParams();
  1648. print PROXH " );\n";
  1649. if (($gMethodFlags & $cNoStub) == $cCustomStub)
  1650. {
  1651. print STUBH " );\n";
  1652. }
  1653. if (($gMethodFlags & $cCustomImplementation) == $cCustomImplementation)
  1654. {
  1655. # Both the proxy and stub are custom so skip
  1656. # all code generation.
  1657. return;
  1658. }
  1659. CLine(")\n");
  1660. $gIndent -= 4;
  1661. CLine("{\n");
  1662. $gIndent += 4;
  1663. #
  1664. # Generate code body.
  1665. #
  1666. if (($gMethodFlags & $cNotRemotable) == $cNotRemotable)
  1667. {
  1668. Line("// This method is not remotable.\n");
  1669. Line("return E_UNEXPECTED;\n");
  1670. goto FinishMethod;
  1671. }
  1672. if (($gMethodFlags & $cNoThreadCheck) == 0)
  1673. {
  1674. Line("if (::GetCurrentThreadId() != m_OwningThread)\n");
  1675. Line("{\n");
  1676. Line(" return E_INVALIDARG;\n");
  1677. Line("}\n");
  1678. }
  1679. else
  1680. {
  1681. Line("// Any thread allowed.\n");
  1682. }
  1683. if ($gMethodFlags & $cReplImplementation)
  1684. {
  1685. if (($gMethodFlags & $cCustomProxy) == 0)
  1686. {
  1687. $Repl = $gProxyRepl{$TableName};
  1688. $Repl =~ s/<If>/$gIface/g;
  1689. $Repl =~ s/<FileBase>/$gFileBase/g;
  1690. print PROXC $Repl;
  1691. }
  1692. if (($gMethodFlags & $cCustomStub) == 0)
  1693. {
  1694. $Repl = $gStubRepl{$TableName};
  1695. $Repl =~ s/<If>/$gIface/g;
  1696. $Repl =~ s/<FileBase>/$gFileBase/g;
  1697. print STUBC $Repl;
  1698. }
  1699. goto FinishMethod;
  1700. }
  1701. Line("DbgRpcConnection* ${gPre}Conn;\n");
  1702. Line("if ((${gPre}Conn = DbgRpcGetConnection(m_OwningThread)) == NULL)\n");
  1703. Line("{\n");
  1704. Line(" return RPC_E_CONNECTION_TERMINATED;\n");
  1705. Line("}\n");
  1706. CLine("HRESULT ${gPre}Status;\n");
  1707. Line("DbgRpcCall ${gPre}Call;\n");
  1708. Line("PUCHAR ${gPre}Data, ${gPre}InData, ${gPre}OutData;\n");
  1709. Line("ULONG ${gPre}InSize = 0, ${gPre}OutSize = 0;\n");
  1710. # First parameter pass.
  1711. # Prepare for object proxies and stubs.
  1712. # Compute data size for in and out.
  1713. $gStubHasCleanup = 0;
  1714. $gStubReturnsProxies = 0;
  1715. $gFile = \*STUBC;
  1716. foreach $Param (@gParams)
  1717. {
  1718. StubInitializeParams($Param);
  1719. }
  1720. $gFile = \*PROXC;
  1721. foreach $Param (@gParams)
  1722. {
  1723. ProxyInitializeParams($Param);
  1724. }
  1725. CClean("${gPre}Status = E_OUTOFMEMORY;\n");
  1726. # Start RPC call.
  1727. Line("if ((${gPre}Data = " .
  1728. "${gPre}Conn->StartCall(&${gPre}Call, m_ObjectId,\n");
  1729. Line(" DBGRPC_STUB_INDEX(m_InterfaceIndex,\n");
  1730. Line(" DBGRPC_SMTH_${gIface}_${gMethod}),\n");
  1731. Line(" ${gPre}InSize, ${gPre}OutSize)) == NULL)\n");
  1732. Line("{\n");
  1733. Line(" goto CheckStatus;\n");
  1734. Line("}\n");
  1735. if ($gMethodFlags & $cNoReturn)
  1736. {
  1737. Line("${gPre}Call.Flags |= DBGRPC_NO_RETURN;\n");
  1738. }
  1739. if ($gMethodFlags & $cCallLocked)
  1740. {
  1741. Line("${gPre}Call.Flags |= DBGRPC_LOCKED;\n");
  1742. }
  1743. # Second parameter pass.
  1744. # Check object proxies and stubs.
  1745. # Declare call variables.
  1746. if ($gStubHasCleanup)
  1747. {
  1748. $gFile = \*STUBC;
  1749. foreach $Param (@gParams)
  1750. {
  1751. StubValidateParams($Param);
  1752. }
  1753. }
  1754. if ($gMethodFlags & $cObjectsAreProxies)
  1755. {
  1756. $gFile = \*PROXC;
  1757. foreach $Param (@gParams)
  1758. {
  1759. ProxyValidateParams($Param);
  1760. }
  1761. }
  1762. # Third parameter pass.
  1763. # Copy parameter data into or out of packet.
  1764. $gFile = \*STUBC;
  1765. foreach $Param (@gParams)
  1766. {
  1767. if ($Param->[$cParamFlags] & $cPfIn)
  1768. {
  1769. StubAssignInParams($Param);
  1770. }
  1771. }
  1772. foreach $Param (@gParams)
  1773. {
  1774. if ($Param->[$cParamFlags] & $cPfOut)
  1775. {
  1776. StubAssignOutParams($Param);
  1777. }
  1778. }
  1779. $gFile = \*PROXC;
  1780. Line("${gPre}InData = ${gPre}Data;\n");
  1781. foreach $Param (@gParams)
  1782. {
  1783. if ($Param->[$cParamFlags] & $cPfIn)
  1784. {
  1785. ProxyCopyInParams($Param);
  1786. }
  1787. }
  1788. #
  1789. # Call real interface.
  1790. #
  1791. Line("${gPre}Status = ${gPre}Conn->SendReceive(&${gPre}Call, " .
  1792. "&${gPre}Data);\n");
  1793. my($FirstParam);
  1794. $gFile = \*STUBC;
  1795. Line("${gPre}Status = (($gIface*)${gPre}If)->$gMethod(\n");
  1796. $gIndent += 4;
  1797. $FirstParam = 1;
  1798. foreach $Param (@gParams)
  1799. {
  1800. if (!$FirstParam)
  1801. {
  1802. Print(",\n");
  1803. }
  1804. else
  1805. {
  1806. $FirstParam = 0;
  1807. }
  1808. Line("$Param->[$cParamName]");
  1809. }
  1810. Print("\n );\n");
  1811. $gIndent -= 4;
  1812. # Fourth parameter pass.
  1813. # Copy out-parameter data to real out parameters.
  1814. # Initialize or clean up object proxies.
  1815. $gIndent -= 4;
  1816. CClean("CheckStatus:\n");
  1817. $gIndent += 4;
  1818. if ($gStubReturnsProxies)
  1819. {
  1820. $gStubHasCleanup = 1;
  1821. }
  1822. CClean("if (SUCCEEDED(${gPre}Status))\n");
  1823. CClean("{\n");
  1824. $gIndent += 4;
  1825. if ($gStubReturnsProxies)
  1826. {
  1827. $gFile = \*STUBC;
  1828. foreach $Param (@gParams)
  1829. {
  1830. StubFinalizeParamsSuccess($Param);
  1831. }
  1832. }
  1833. $gFile = \*PROXC;
  1834. Line("${gPre}OutData = ${gPre}Data;\n");
  1835. foreach $Param (@gParams)
  1836. {
  1837. ProxyFinalizeParamsSuccess($Param);
  1838. }
  1839. foreach $Param (@gParams)
  1840. {
  1841. ProxyDestroyInObjects($Param);
  1842. }
  1843. $gIndent -= 4;
  1844. CClean("}\n");
  1845. CClean("else\n");
  1846. CClean("{\n");
  1847. $gIndent += 4;
  1848. if ($gStubHasCleanup)
  1849. {
  1850. $gFile = \*STUBC;
  1851. foreach $Param (@gParams)
  1852. {
  1853. StubFinalizeParamsFailure($Param);
  1854. }
  1855. }
  1856. $gFile = \*PROXC;
  1857. foreach $Param (@gParams)
  1858. {
  1859. ProxyFinalizeParamsFailure($Param);
  1860. }
  1861. $gIndent -= 4;
  1862. CClean("}\n");
  1863. Line("${gPre}Conn->FreeData(${gPre}Data);\n");
  1864. CLine("return ${gPre}Status;\n");
  1865. #
  1866. # Finish up.
  1867. #
  1868. FinishMethod:
  1869. $gIndent -= 4;
  1870. CLine("}\n");
  1871. }
  1872. sub EndInterface()
  1873. {
  1874. print PROXH "};\n";
  1875. print STUBH "\n";
  1876. print STUBH "#define DBGRPC_UNIQUE_$gIface $gIfUnique\n";
  1877. print STUBH "\n";
  1878. print STUBH "enum DBGRPC_SMTH_$gIface\n";
  1879. print STUBH "{\n";
  1880. print STUBH $gStubList;
  1881. print STUBH " DBGRPC_SMTH_${gIface}_COUNT\n";
  1882. print STUBH "};\n";
  1883. $gStubList =~ s/ DBGRPC_SMTH_/ SFN_/g;
  1884. print STUBC "\n";
  1885. print STUBC "DbgRpcStubFunction g_DbgRpcStubs_${gFileBase}_${gIface}[] =\n";
  1886. print STUBC "{\n";
  1887. print STUBC $gStubList;
  1888. print STUBC "};\n";
  1889. $gStubList =~ s/ SFN_(\w+)_(\w+),/ "$1::$2",/g;
  1890. print STUBC "\n";
  1891. print STUBC "#if DBG\n";
  1892. print STUBC "PCSTR g_DbgRpcStubNames_${gFileBase}_${gIface}[] =\n";
  1893. print STUBC "{\n";
  1894. print STUBC $gStubList;
  1895. print STUBC "};\n";
  1896. print STUBC "#endif // #if DBG\n";
  1897. $gIface = "";
  1898. $gMethodFlags = 0;
  1899. }
  1900. sub OpenGenFile(*$)
  1901. {
  1902. my $File = $_[0];
  1903. my $Name = $_[1];
  1904. open($File, ">$gGenDir\\" . $Name) ||
  1905. ErrorExit("Can't open $gGenDir\\$Name\n");
  1906. print $File "//-------------------------------------".
  1907. "--------------------------------------\n";
  1908. print $File "//\n";
  1909. print $File "// IMPORTANT: This file is automatically generated.\n";
  1910. print $File "// Do not edit by hand.\n";
  1911. print $File "//\n";
  1912. print $File "// Generated from $gHeaderFile " . localtime() . "\n";
  1913. print $File "//\n";
  1914. print $File "//-------------------------------------".
  1915. "--------------------------------------\n";
  1916. }
  1917. sub ScanHeader($)
  1918. {
  1919. my $File = $_[0];
  1920. my($InTypedef);
  1921. $File =~ /(?:[a-zA-Z]:(?:[\\\/])?)?(?:.+[\\\/])*(.+)(\.[a-zA-Z]+)/;
  1922. $gFileBase = $1;
  1923. $gHeaderFile = $gFileBase . $2;
  1924. open(HEADER, "<" . $File) ||
  1925. ErrorExit("Can't open " . $File);
  1926. OpenGenFile(\*PROXH, "${gFileBase}_p.hpp");
  1927. OpenGenFile(\*PROXC, "${gFileBase}_p.cpp");
  1928. OpenGenFile(\*STUBH, "${gFileBase}_s.hpp");
  1929. OpenGenFile(\*STUBC, "${gFileBase}_s.cpp");
  1930. print PROXH "\n";
  1931. print PROXH "ULONG DbgRpcGetIfUnique_$gFileBase(REFIID InterfaceId);\n";
  1932. print PROXH "HRESULT DbgRpcPreallocProxy_$gFileBase(REFIID InterfaceId, " .
  1933. "PVOID* Interface,\n";
  1934. print PROXH " DbgRpcProxy** Proxy, " .
  1935. "PULONG IfUnique);\n";
  1936. print PROXH "\n";
  1937. print STUBH "\n";
  1938. print STUBH "extern DbgRpcStubFunctionTable g_DbgRpcStubs_${gFileBase}[];\n";
  1939. print STUBH "#if DBG\n";
  1940. print STUBH "extern PCSTR* g_DbgRpcStubNames_${gFileBase}[];\n";
  1941. print STUBH "#endif\n";
  1942. print STUBH "void DbgRpcInitializeStubTables_${gFileBase}(ULONG Base);\n";
  1943. # Not in an interface or typedef.
  1944. $gIface = "";
  1945. $InTypedef = 0;
  1946. while (<HEADER>)
  1947. {
  1948. if (!$gIface)
  1949. {
  1950. # Not in an interface.
  1951. # Look for interface typedefs to automatically
  1952. # recognize interfaces.
  1953. # Look for interface declarations.
  1954. if ($InTypedef)
  1955. {
  1956. if (/^ (\w+)\*/)
  1957. {
  1958. my($IfType);
  1959. $IfType = $1;
  1960. # Accumulate lines until full statement.
  1961. LINES:
  1962. for (;;)
  1963. {
  1964. if (/;/)
  1965. {
  1966. last LINES;
  1967. }
  1968. else
  1969. {
  1970. $_ .= <HEADER>;
  1971. }
  1972. }
  1973. # Extract typedef name.
  1974. $_ =~ /\*\s+(\w+)\s*;\s*$/;
  1975. AddIfType($IfType, $1);
  1976. }
  1977. $InTypedef = 0;
  1978. }
  1979. elsif (/^typedef interface DECLSPEC_UUID/)
  1980. {
  1981. $InTypedef = 1;
  1982. }
  1983. elsif (/^DECLARE_INTERFACE_\((\w+), \w+\)$/)
  1984. {
  1985. BeginInterface($1);
  1986. }
  1987. }
  1988. else
  1989. {
  1990. # In an interface.
  1991. # Look for method declarations.
  1992. # Look for interface close.
  1993. if (/^\s+STDMETHOD(V?)\((\w+)\)\($/)
  1994. {
  1995. IfMethod($2, $1, "");
  1996. }
  1997. elsif (/^\s+STDMETHOD(V?)_\((\w+), (\w+)\)\($/)
  1998. {
  1999. IfMethod($3, $1, $2);
  2000. }
  2001. elsif (/^};$/)
  2002. {
  2003. EndInterface();
  2004. }
  2005. }
  2006. }
  2007. GenerateIfTypes();
  2008. close(HEADER);
  2009. close(PROXH);
  2010. close(PROXC);
  2011. close(STUBH);
  2012. close(STUBC);
  2013. }
  2014. ###############################################################################
  2015. #
  2016. # Main.
  2017. #
  2018. ###############################################################################
  2019. $gVerbose = 0;
  2020. $gGenDir = ".";
  2021. ARG:
  2022. while ($Arg = shift(@ARGV))
  2023. {
  2024. if ($Arg eq "-g")
  2025. {
  2026. $gGenDir = shift;
  2027. }
  2028. elsif ($Arg eq "-v")
  2029. {
  2030. $gVerbose = 1;
  2031. }
  2032. else
  2033. {
  2034. last ARG;
  2035. }
  2036. }
  2037. ScanHeader($Arg);