Leaked source code of windows server 2003
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.

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