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.

2035 lines
59 KiB

  1. @rem = '--*-Perl-*--
  2. @echo off
  3. if "%OS%" == "Windows_NT" goto WinNT
  4. perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
  5. goto endofperl
  6. :WinNT
  7. perl -x -S "%0" %*
  8. if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
  9. if %errorlevel% == 9009 echo You do not have Perl in your PATH.
  10. goto endofperl
  11. @rem ';
  12. #!perl
  13. #line 14
  14. #
  15. # This Perl program generates the "IsolationAware" stubs
  16. # in winbase.inl, winuser.inl, prsht.h, commctrl.h, commdlg.h.
  17. #
  18. # It is run by the makefile.inc files in
  19. # base\published
  20. # windows\published
  21. # shell\published\inc
  22. #
  23. # The name "shfusion2" comes from these stubs being the public replacement
  24. # for "shfusion" -- shell\lib\shfusion.
  25. #
  26. # Generation of the stubs is driven by declarations in the .w files.
  27. # The stubs vary in a few ways.
  28. # Some are just for delayload purposes -- all the actctx functions.
  29. # Some delayload the entire .dll -- comctl32.dll.
  30. # Others activate around static links -- kernel32.dll, user32.dll, comdlg32.dll
  31. # some do not activate at all -- the actctx functions
  32. # winbase.inl gets an extra chunk of "less generated" / "relatively hardcoded"
  33. # code, that the stubs in the other files depend on.
  34. # winbase.inl exports two symbols to all the stubs, and one extra symbol
  35. # to two stubs in prsht.h
  36. # The two symbols are ActivateMyActCtx, g_fDownlevel.
  37. # The third symbol is g_hActCtx.
  38. # All symbols get "mangled".
  39. # Each header also gets a small function for calling GetProcAddress with an implied
  40. # HMODULE parameter. This function's name is also "mangled".
  41. # Besides "mangling", all external symbols are clearly "namespaced" with a relatively
  42. # long "namespace" -- IsolationAware or IsolationAwarePrivate.
  43. #
  44. # owner=JayKrell
  45. #
  46. #
  47. # $ scalar/string/number
  48. # @ list/array
  49. # $ hash
  50. # {} hash
  51. #
  52. $true = 1;
  53. $false = 0;
  54. $newline = "\n";
  55. $ErrorMessagePrefix = 'NMAKE : U1234: ' . $ENV{'SDXROOT'} . '\\tools\\shfusion2.bat ';
  56. sub ErrorExit
  57. {
  58. exit;
  59. }
  60. sub ErrorPrint
  61. {
  62. print(@_);
  63. }
  64. sub DebugPrint
  65. {
  66. print(@_);
  67. }
  68. sub DebugExit
  69. {
  70. exit;
  71. }
  72. sub EarlySuccessExit
  73. {
  74. exit;
  75. }
  76. sub MakeLower
  77. {
  78. my($x) = ($_[0]);
  79. return "\L$x";
  80. }
  81. sub MakeUpper
  82. {
  83. my($x) = ($_[0]);
  84. return "\U$x";
  85. }
  86. sub MakeTitlecase
  87. {
  88. # first character uppercase, the rest lowercase
  89. my($x) = ($_[0]);
  90. $x = "\L$x";
  91. $x = "\u$x";
  92. return $x;
  93. }
  94. sub ToIdentifier
  95. {
  96. # replace dots with underscores
  97. my($x) = ($_[0]);
  98. $x =~ s/\./_/g;
  99. return $x;
  100. }
  101. sub RemoveSpacesAroundStars
  102. {
  103. my($x) = ($_[0]);
  104. $x =~ s/ *\* */\*/g;
  105. return $x;
  106. }
  107. sub RemoveSpacesAroundCommas
  108. {
  109. my($x) = ($_[0]);
  110. $x =~ s/ *, */,/g;
  111. return $x;
  112. }
  113. sub RemoveTrailingComma
  114. {
  115. my($x) = ($_[0]);
  116. $x =~ s/, *$//g;
  117. return $x;
  118. }
  119. sub RemoveLeadingAndTrailingSpaces
  120. {
  121. my($x) = ($_[0]);
  122. $x =~ s/^ +//g;
  123. $x =~ s/ +$//g;
  124. return $x;
  125. }
  126. sub MakePublicCapitalizedSymbol
  127. {
  128. #
  129. # ISOLATION_AWARE_WORDWITHNOUNDERSCORES
  130. # ISOLATIONAWARE_MULTIPLE_UNDERSCORE_SEPERATED_WORDS
  131. #
  132. # not great, but consistent with existing symbols
  133. #
  134. my($name) = ($_[0]);
  135. if ($name !~ /[A-Z_0-9]/)
  136. {
  137. # warning..
  138. }
  139. if ($name =~ /_/)
  140. {
  141. return "ISOLATIONAWARE_" . $name;
  142. }
  143. else
  144. {
  145. return "ISOLATION_AWARE_" . $name;
  146. }
  147. }
  148. sub MakePublicPreprocessorSymbol
  149. {
  150. my($name) = ($_[0]);
  151. return MakePublicCapitalizedSymbol($name);
  152. }
  153. sub ComInterfaceParameterReplacementIdentifier
  154. {
  155. my($name) = ($_[0]);
  156. $header = BaseName($headerLeafName);
  157. if ($name =~ /^[A-Z_0-9]+$/)
  158. {
  159. $name = 'ISOLATIONAWARE' . MakeUpper($header) . '_' . $name;
  160. }
  161. elsif ($name =~ /^[A-Z0-9]+$/)
  162. {
  163. $name = 'ISOLATION_AWARE_' . MakeUpper($header) . '_' . $name;
  164. }
  165. else
  166. {
  167. $name = 'IsolationAware' . MakeTitlecase($header) . $name;
  168. }
  169. return $name;
  170. }
  171. $INLINE = MakePublicPreprocessorSymbol("INLINE");
  172. sub ObscurePrivateName
  173. {
  174. my ($namespace,$x) = ($_[0],$_[1]);
  175. $x =~ tr/0-9/a-j/;
  176. #
  177. # shift and sometimes invert case
  178. #
  179. $x =~ tr/a-zA-Z/N-Za-mn-zA-M/;
  180. return $namespace . $x;
  181. }
  182. sub MakeHeaderPrivateName
  183. {
  184. my($header, $name) = ($_[0], $_[1]);
  185. $header = MakeTitlecase(BaseName($header));
  186. return ObscurePrivateName($header . 'IsolationAwarePrivate', $name);
  187. }
  188. sub MakeMultiHeaderPrivateName
  189. {
  190. my($name) = ($_[0]);
  191. return ObscurePrivateName('IsolationAwarePrivate', $name);
  192. }
  193. sub MakePublicName
  194. {
  195. # IsolationAwareFoo
  196. my($name) = ($_[0]);
  197. return "IsolationAware" . $name;
  198. }
  199. # g_hActCtx is also used by prsht.h
  200. $g_hActCtx = MakeHeaderPrivateName('winbase.h', 'g_hActCtx');
  201. $g_fDownlevel = MakeMultiHeaderPrivateName('g_fDownlevel');
  202. $g_fCreatedActCtx = MakeHeaderPrivateName('winbase.h', 'g_fCreatedActCtx');
  203. $g_fCleanupCalled = MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled');
  204. $ActivateMyActCtx = MakeMultiHeaderPrivateName('ActivateMyActCtx');
  205. $GetMyActCtx = MakeHeaderPrivateName('winbase.h', 'GetMyActCtx');
  206. $QueryActCtxW = MakePublicName('QueryActCtxW');
  207. $FindActCtxSectionStringW = MakePublicName('FindActCtxSectionStringW');
  208. $ActivateActCtx = MakePublicName('ActivateActCtx');
  209. $DeactivateActCtx = MakePublicName('DeactivateActCtx');
  210. $Init = MakePublicName('Init');
  211. $Cleanup = MakePublicName('Cleanup');
  212. $CreateActCtxW = MakePublicName('CreateActCtxW');
  213. $MyGetProcAddress = MakeMultiHeaderPrivateName('MyGetProcAddress');
  214. $LoadA = MakeHeaderPrivateName('winbase.h', 'LoadA');
  215. $LoadW = MakeHeaderPrivateName('winbase.h', 'LoadW');
  216. $NameA = MakeHeaderPrivateName('winbase.h', 'NameA');
  217. $NameW = MakeHeaderPrivateName('winbase.h', 'NameW');
  218. $LoadedModule = MakeHeaderPrivateName('winbase.h', 'LoadedModule');
  219. $CONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('CONSTANT_MODULE_INFO');
  220. $_CONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('_CONSTANT_MODULE_INFO');
  221. $PCONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('PCONSTANT_MODULE_INFO');
  222. $MUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('MUTABLE_MODULE_INFO');
  223. $_MUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('_MUTABLE_MODULE_INFO');
  224. $PMUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('PMUTABLE_MODULE_INFO');
  225. $ENABLED = MakePublicPreprocessorSymbol('ENABLED');
  226. $MyLoadLibraryA = MakeMultiHeaderPrivateName('MyLoadLibraryA');
  227. $MyLoadLibraryW = MakeMultiHeaderPrivateName('MyLoadLibraryW');
  228. $MyGetModuleHandleA = MakeMultiHeaderPrivateName('MyGetModuleHandleA');
  229. $MyGetModuleHandleW = MakeMultiHeaderPrivateName('MyGetModuleHandleW');
  230. use Class::Struct;
  231. use IO::File;
  232. #
  233. # If ENV{_NTDRIVE} or ENV{_NTROOT} not defined, look here.
  234. #
  235. %NtDriveRootDefaults =
  236. (
  237. "jaykrell" =>
  238. {
  239. "_NTDRIVE" => "f:",
  240. "_NTROOT" => "\\jaykrell"
  241. },
  242. "default" =>
  243. {
  244. "_NTDRIVE" => "z:",
  245. "_NTROOT" => "\\nt"
  246. }
  247. );
  248. sub Indent
  249. {
  250. return $_[0] . " ";
  251. }
  252. sub Outdent
  253. {
  254. return substr($_[0], 4);
  255. }
  256. #
  257. # for Perl embedded in headers, stick data in global hashtables, but hide
  258. # the Perl syntax in what looks like C function calls.
  259. #
  260. sub DeclareFunctionErrorValue
  261. {
  262. my($function,$errorValue) = ($_[0], $_[1]);
  263. $FunctionErrorValue{$function} = MakeStringTrue($errorValue);
  264. #DebugPrint($function . " error value is " . $errorValue . "\n");
  265. }
  266. sub DelayLoad { $DelayLoad{$_[0]} = 1; }
  267. sub MapHeaderToDll { $MapHeaderToDll{MakeLower(BaseName($_[0]))} = MakeLower($_[1]); }
  268. sub ActivateAroundDelayLoad { DelayLoad($_[0]); $ActivateAroundDelayLoad{$_[0]} = 1; }
  269. sub ActivateAroundFunctionCall { $ActivateAroundFunctionCall{$_[0]} = 1; }
  270. sub NoActivateAroundFunctionCall {$NoActivateAroundFunctionCall{$_[0]} = 1;}
  271. sub ActivateNULLAroundFunctionCall { $ActivateNULLAroundFunctionCall{$_[0]} = 1; }
  272. sub PerHeaderMacroEnable { $PerHeaderMacroEnable{MakeLower(BaseName($_[0]))} = 1; }
  273. sub DeclareExportName32 { $ExportName32{$_[0]} = $_[1]; }
  274. sub DeclareExportName64 { $ExportName64{$_[0]} = $_[1]; }
  275. sub Undef { $Undef{$_[0]} = 1; }
  276. sub PoundIf { $PoundIfCondition{$_[0]} = $_[1]; }
  277. sub SetInsertionPoint { $InsertionPoint{MakeLower(BaseName($_[0]))} = $_[1]; }
  278. sub IgnoreFunction { $IgnoreFunction{$_[0]} = 1; }
  279. sub NeverFails { $NeverFails{$_[0]} = 1; $ActivateAroundFunctionCall{$_[0]} = 0; $ActivateAroundDelayLoad{$_[0]} = 0; }
  280. sub NoMacro { $NoMacro{$_[0]} = 1; }
  281. #
  282. # MFC #includes commctrl.h without __IStream_INTERFACE_DEFINED__ defined but
  283. # then later manually declares ImageList_Read/Write.
  284. #
  285. # Let ISOLATION_AWARE_ENABLED mean that ImageList_Read/Write/Ex declarations are really
  286. # desired even if __IStream_INTERFACE_DEFINED__ is not defined.
  287. #
  288. sub DeclareComInterface
  289. {
  290. #
  291. # for example: DeclareComInterface("IStream", "LPSTREAM", "typedef IStream *LPSTREAM;");
  292. #
  293. my($interface) = ($_[0]);
  294. my($parameter_type) = ($_[1]);
  295. my($typedef) = ($_[2]);
  296. $ComInterfaceParameterType{$parameter_type} = $interface;
  297. $ComInterfaceParameterTypedef{$parameter_type} = $typedef;
  298. }
  299. #
  300. # for Perl on the command line
  301. #
  302. sub SetStubsFile
  303. {
  304. $StubsFile = $_[0];
  305. #DebugPrint("StubsFile is " . $StubsFile . "\n");
  306. }
  307. sub LeafPath
  308. {
  309. my($x) = ($_[0]);
  310. my($y)= $x;
  311. if ($y =~ /\\/) # does it contain slashes?
  312. {
  313. ($y) = ($x =~ /.*\\(.+)/); # get everything after the last slash
  314. }
  315. #DebugPrint("leaf path of $x is $y\n");
  316. return $y;
  317. }
  318. sub BaseName
  319. {
  320. my($x) = ($_[0]);
  321. $x = LeafPath($x);
  322. if ($x =~ /\./)
  323. {
  324. $x =~ s/^(.*)\..*$/$1/;
  325. }
  326. return $x;
  327. }
  328. sub RemoveExtension { return BaseName($_[0]); }
  329. sub GetNtDriveOrRoot
  330. {
  331. my($name) = ($_[0]);
  332. my($x);
  333. $x = $ENV{$name};
  334. if ($x)
  335. {
  336. return $x;
  337. }
  338. $x = $NtDriveRootDefaults{MakeLower($ENV{"COMPUTERNAME"})}
  339. || $NtDriveRootDefaults{MakeLower($ENV{"USERNAME"})}
  340. || $NtDriveRootDefaults{$ENV{"default"}};
  341. return $x{$name};
  342. }
  343. sub GetNtDrive
  344. {
  345. return GetNtDriveOrRoot("_NTDRIVE");
  346. };
  347. sub GetNtRoot
  348. {
  349. return GetNtDriveOrRoot("_NTROOT");
  350. };
  351. struct Function => # I don't know what syntax is in play here, just following an example..
  352. {
  353. name => '$',
  354. ret => '$',
  355. retname => '$', # just for Hungarian purposes
  356. #
  357. # argsTypesNames and argNames are comma delimited strings,
  358. # wrapped in parentheses.
  359. #
  360. # argsTypeNames and argsNames are exactly the forms we need to
  361. # print a few times.
  362. #
  363. # For more sophisticated processing, these should be arrays or hashes,
  364. # and we would save away argsTypes too.
  365. #
  366. argsTypesNames => '$',
  367. argsNames => '$',
  368. error => '$', # eg NULL, 0, -1, FALSE
  369. dll => '$', # eg: kernel32.dll, comctl32.dll
  370. header => '$', # eg: winuser, commctrl
  371. delayload => '$', # boolean
  372. };
  373. #
  374. # Headers have versions of GetProcAddress where the .dll is implied.
  375. # This generates a call to such a GetProcAddress wrapper.
  376. #
  377. sub GenerateGetProcAddressCall
  378. {
  379. my($header, $dll, $function) = ($_[0], $_[1], $_[2]);
  380. my($x);
  381. $dll = MakeTitlecase($dll);
  382. $x .= MakeHeaderPrivateName($header, 'GetProcAddress_' . ToIdentifier($dll));
  383. $x .= '("' . $function . '")';
  384. return $x;
  385. }
  386. $code = '';
  387. $WinbaseSpecialCode1='
  388. /* These wrappers prevent warnings about taking the addresses of __declspec(dllimport) functions. */
  389. ' . $INLINE . ' HMODULE WINAPI '. $MyLoadLibraryA .'(LPCSTR s) { return LoadLibraryA(s); }
  390. ' . $INLINE . ' HMODULE WINAPI '. $MyLoadLibraryW .'(LPCWSTR s) { return LoadLibraryW(s); }
  391. ' . $INLINE . ' HMODULE WINAPI '. $MyGetModuleHandleA .'(LPCSTR s) { return GetModuleHandleA(s); }
  392. ' . $INLINE . ' HMODULE WINAPI '. $MyGetModuleHandleW .'(LPCWSTR s) { return GetModuleHandleW(s); }
  393. /* temporary support for out of sync headers */
  394. #define IsolationAwarePrivateG_FqbjaLEiEL ' . $g_fDownlevel . '
  395. #define IsolationAwarePrivatenCgIiAgEzlnCgpgk ' . $ActivateMyActCtx . '
  396. #define WinbaseIsolationAwarePrivateG_HnCgpgk ' . $g_hActCtx . '
  397. #define IsolationAwarePrivatezlybADyIBeAeln ' . $MyLoadLibraryA . '
  398. #define IsolationAwarePrivatezlybADyIBeAelJ ' . $MyLoadLibraryW . '
  399. #define IsolationAwarePrivatezltEgCebCnDDeEff ' . $MyGetProcAddress . '
  400. BOOL WINAPI ' . $ActivateMyActCtx . '(ULONG_PTR* pulpCookie);
  401. /*
  402. These are private.
  403. */
  404. __declspec(selectany) HANDLE ' . $g_hActCtx . ' = INVALID_HANDLE_VALUE;
  405. __declspec(selectany) BOOL ' . $g_fDownlevel . ' = FALSE;
  406. __declspec(selectany) BOOL ' . $g_fCreatedActCtx . ' = FALSE;
  407. __declspec(selectany) BOOL ' . $g_fCleanupCalled . ' = FALSE;
  408. ';
  409. $WinbaseSpecialCode2='
  410. #define WINBASE_NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
  411. typedef struct ' . $_CONSTANT_MODULE_INFO . ' {
  412. HMODULE (WINAPI * ' . $LoadA . ')(LPCSTR a);
  413. HMODULE (WINAPI * ' . $LoadW . ')(LPCWSTR w);
  414. PCSTR ' . $NameA . ';
  415. PCWSTR ' . $NameW . ';
  416. } ' . $CONSTANT_MODULE_INFO . ';
  417. typedef const ' . $CONSTANT_MODULE_INFO . ' *' . $PCONSTANT_MODULE_INFO . ';
  418. typedef struct ' . $_MUTABLE_MODULE_INFO . ' {
  419. HMODULE ' . $LoadedModule . ';
  420. } ' . $MUTABLE_MODULE_INFO . ', *' . $PMUTABLE_MODULE_INFO . ';
  421. ' . $INLINE . ' FARPROC WINAPI
  422. ' . $MyGetProcAddress . '(
  423. ' . $PCONSTANT_MODULE_INFO . ' c,
  424. ' . $PMUTABLE_MODULE_INFO . ' m,
  425. LPCSTR ProcName
  426. )
  427. {
  428. static HMODULE s_moduleUnicows;
  429. static BOOL s_fUnicowsInitialized;
  430. FARPROC Proc = NULL;
  431. HMODULE hModule;
  432. /*
  433. get unicows.dll loaded on-demand
  434. */
  435. if (!s_fUnicowsInitialized)
  436. {
  437. if ((GetVersion() & 0x80000000) != 0)
  438. {
  439. GetFileAttributesW(L"???.???");
  440. s_moduleUnicows = GetModuleHandleA("Unicows.dll");
  441. }
  442. s_fUnicowsInitialized = TRUE;
  443. }
  444. /*
  445. always call GetProcAddress(unicows) before the usual .dll
  446. */
  447. if (s_moduleUnicows != NULL)
  448. {
  449. Proc = GetProcAddress(s_moduleUnicows, ProcName);
  450. if (Proc != NULL)
  451. goto Exit;
  452. }
  453. hModule = m->' . $LoadedModule . ';
  454. if (hModule == NULL)
  455. {
  456. hModule = (((GetVersion() & 0x80000000) != 0) ? (*c->' . $LoadA . ')(c->' . $NameA . ') : (*c->' . $LoadW . ')(c->' . $NameW . '));
  457. if (hModule == NULL)
  458. goto Exit;
  459. m->' . $LoadedModule . ' = hModule;
  460. }
  461. Proc = GetProcAddress(hModule, ProcName);
  462. Exit:
  463. return Proc;
  464. }
  465. ' . $INLINE . ' BOOL WINAPI ' . $GetMyActCtx . '(void)
  466. /*
  467. The correctness of this function depends on it being statically
  468. linked into its clients.
  469. This function is private to functions present in this header.
  470. Do not use it.
  471. */
  472. {
  473. BOOL fResult = FALSE;
  474. ACTIVATION_CONTEXT_BASIC_INFORMATION actCtxBasicInfo;
  475. ULONG_PTR ulpCookie = 0;
  476. if (' . $g_fDownlevel . ')
  477. {
  478. fResult = TRUE;
  479. goto Exit;
  480. }
  481. if (' . $g_hActCtx . ' != INVALID_HANDLE_VALUE)
  482. {
  483. fResult = TRUE;
  484. goto Exit;
  485. }
  486. if (!' . $QueryActCtxW . '(
  487. QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS
  488. | QUERY_ACTCTX_FLAG_NO_ADDREF,
  489. &' . $g_hActCtx . ',
  490. NULL,
  491. ActivationContextBasicInformation,
  492. &actCtxBasicInfo,
  493. sizeof(actCtxBasicInfo),
  494. NULL
  495. ))
  496. goto Exit;
  497. /*
  498. If QueryActCtxW returns NULL, try CreateActCtx(3).
  499. */
  500. if (actCtxBasicInfo.hActCtx == NULL)
  501. {
  502. ACTCTXW actCtx;
  503. WCHAR rgchFullModulePath[MAX_PATH + 2];
  504. DWORD dw;
  505. HMODULE hmodSelf;
  506. PGET_MODULE_HANDLE_EXW pfnGetModuleHandleExW;
  507. pfnGetModuleHandleExW = (PGET_MODULE_HANDLE_EXW)' . GenerateGetProcAddressCall('winbase.h', 'kernel32.dll', 'GetModuleHandleExW') . ';
  508. if (pfnGetModuleHandleExW == NULL)
  509. goto Exit;
  510. if (!(*pfnGetModuleHandleExW)(
  511. GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
  512. | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
  513. (LPCWSTR)&' . $g_hActCtx . ',
  514. &hmodSelf
  515. ))
  516. goto Exit;
  517. rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 1] = 0;
  518. rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] = 0;
  519. dw = GetModuleFileNameW(hmodSelf, rgchFullModulePath, WINBASE_NUMBER_OF(rgchFullModulePath)-1);
  520. if (dw == 0)
  521. goto Exit;
  522. if (rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] != 0)
  523. {
  524. SetLastError(ERROR_BUFFER_OVERFLOW);
  525. goto Exit;
  526. }
  527. actCtx.cbSize = sizeof(actCtx);
  528. actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
  529. actCtx.lpSource = rgchFullModulePath;
  530. actCtx.lpResourceName = (LPCWSTR)(ULONG_PTR)3;
  531. actCtx.hModule = hmodSelf;
  532. actCtxBasicInfo.hActCtx = ' . $CreateActCtxW . '(&actCtx);
  533. if (actCtxBasicInfo.hActCtx == INVALID_HANDLE_VALUE)
  534. {
  535. const DWORD dwLastError = GetLastError();
  536. if ((dwLastError != ERROR_RESOURCE_DATA_NOT_FOUND) &&
  537. (dwLastError != ERROR_RESOURCE_TYPE_NOT_FOUND) &&
  538. (dwLastError != ERROR_RESOURCE_LANG_NOT_FOUND) &&
  539. (dwLastError != ERROR_RESOURCE_NAME_NOT_FOUND))
  540. goto Exit;
  541. actCtxBasicInfo.hActCtx = NULL;
  542. }
  543. ' . $g_fCreatedActCtx . ' = TRUE;
  544. }
  545. ' . $g_hActCtx . ' = actCtxBasicInfo.hActCtx;
  546. #define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2)
  547. if (' . $ActivateActCtx . '(actCtxBasicInfo.hActCtx, &ulpCookie))
  548. {
  549. __try
  550. {
  551. ACTCTX_SECTION_KEYED_DATA actCtxSectionKeyedData;
  552. actCtxSectionKeyedData.cbSize = sizeof(actCtxSectionKeyedData);
  553. if (' . $FindActCtxSectionStringW . '(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"Comctl32.dll", &actCtxSectionKeyedData))
  554. {
  555. /* get button, edit, etc. registered */
  556. LoadLibraryW(L"Comctl32.dll");
  557. }
  558. }
  559. __finally
  560. {
  561. ' . $DeactivateActCtx . '(0, ulpCookie);
  562. }
  563. }
  564. fResult = TRUE;
  565. Exit:
  566. return fResult;
  567. }
  568. ' . $INLINE . ' BOOL WINAPI ' . $Init . '(void)
  569. /*
  570. The correctness of this function depends on it being statically
  571. linked into its clients.
  572. Call this from DllMain(DLL_PROCESS_ATTACH) if you use id 3 and wish to avoid a race condition that
  573. can cause an hActCtx leak.
  574. Call this from your .exe\'s initialization if you use id 3 and wish to avoid a race condition that
  575. can cause an hActCtx leak.
  576. If you use id 2, this function fetches data from your .dll
  577. that you do not need to worry about cleaning up.
  578. */
  579. {
  580. return ' . $GetMyActCtx . '();
  581. }
  582. ' . $INLINE . ' void WINAPI ' . $Cleanup . '(void)
  583. /*
  584. Call this from DllMain(DLL_PROCESS_DETACH), if you use id 3, to avoid a leak.
  585. Call this from your .exe\'s cleanup to possibly avoid apparent (but not actual) leaks, if use id 3.
  586. This function does nothing, safely, if you use id 2.
  587. */
  588. {
  589. HANDLE hActCtx;
  590. if (' . $g_fCleanupCalled . ')
  591. return;
  592. /* IsolationAware* calls made from here on out will OutputDebugString
  593. and use the process default activation context instead of id 3 or will
  594. continue to successfully use id 2 (but still OutputDebugString).
  595. */
  596. ' . $g_fCleanupCalled . ' = TRUE;
  597. /* There is no cleanup to do if we did not CreateActCtx but only called QueryActCtx.
  598. */
  599. if (!' . $g_fCreatedActCtx . ')
  600. return;
  601. hActCtx = ' . $g_hActCtx . ';
  602. ' . $g_hActCtx . ' = NULL; /* process default */
  603. if (hActCtx == INVALID_HANDLE_VALUE)
  604. return;
  605. if (hActCtx == NULL)
  606. return;
  607. IsolationAwareReleaseActCtx(hActCtx);
  608. }
  609. ' . $INLINE . ' BOOL WINAPI ' . $ActivateMyActCtx . '(ULONG_PTR* pulpCookie)
  610. /*
  611. This function is private to functions present in this header and other headers.
  612. */
  613. {
  614. BOOL fResult = FALSE;
  615. if (' . $g_fCleanupCalled . ')
  616. {
  617. const static char debugString[] = "IsolationAware function called after ' . $Cleanup . '\\n";
  618. OutputDebugStringA(debugString);
  619. }
  620. if (' . $g_fDownlevel . ')
  621. {
  622. fResult = TRUE;
  623. goto Exit;
  624. }
  625. /* Do not call Init if Cleanup has been called. */
  626. if (!' . $g_fCleanupCalled . ')
  627. {
  628. if (!' . $GetMyActCtx . '())
  629. goto Exit;
  630. }
  631. /* If Cleanup has been called and id3 was in use, this will activate NULL. */
  632. if (!' . $ActivateActCtx . '(' . $g_hActCtx . ', pulpCookie))
  633. goto Exit;
  634. fResult = TRUE;
  635. Exit:
  636. if (!fResult)
  637. {
  638. const DWORD dwLastError = GetLastError();
  639. if (dwLastError == ERROR_PROC_NOT_FOUND
  640. || dwLastError == ERROR_CALL_NOT_IMPLEMENTED
  641. )
  642. {
  643. ' . $g_fDownlevel . ' = TRUE;
  644. fResult = TRUE;
  645. }
  646. }
  647. return fResult;
  648. }
  649. #undef WINBASE_NUMBER_OF
  650. '
  651. ;
  652. %MapHeaderToSpecialCode1 =
  653. (
  654. "winbase" => $WinbaseSpecialCode1,
  655. "winbase.h" => $WinbaseSpecialCode1,
  656. "Winbase" => $WinbaseSpecialCode1,
  657. "Winbase.h" => $WinbaseSpecialCode1,
  658. );
  659. %MapHeaderToSpecialCode2 =
  660. (
  661. "winbase" => $WinbaseSpecialCode2,
  662. "winbase.h" => $WinbaseSpecialCode2,
  663. "Winbase" => $WinbaseSpecialCode2,
  664. "Winbase.h" => $WinbaseSpecialCode2,
  665. );
  666. sub MakeStringTrue
  667. {
  668. ($_[0] eq "0") ? "0 " : $_[0];
  669. }
  670. %TypeErrorValue =
  671. (
  672. # Individual functions can override with a #!perl comment.
  673. # Functions that return an integer must specify. 0, -1, ~0 are too evenly split.
  674. # HANDLE must specify (NULL, INVALID_HANDLE..)
  675. "BOOL" => "FALSE",
  676. "bool" => "false",
  677. "PVOID" => "NULL",
  678. "HICON" => "NULL",
  679. "HIMAGELIST" => "NULL",
  680. "HWND" => "NULL",
  681. "COLORREF" => "RGB(0,0,0)",
  682. "HBITMAP" => "NULL",
  683. "LANGID" => "0",
  684. "ATOM" => "0",
  685. "HPROPSHEETPAGE" => "NULL",
  686. "HDSA" => "NULL",
  687. "HDPA" => "NULL",
  688. # HRESULTs are treated specially!
  689. "HRESULT" => "S_OK"
  690. );
  691. sub IndentMultiLineString
  692. {
  693. my ($indent, $string) = ($_[0], $_[1]);
  694. if ($string)
  695. {
  696. $string = $indent . join("\n" . $indent, split("\n", $string)). "\n";
  697. if ($string !~ /{/)
  698. {
  699. $string = ' ' . $string;
  700. }
  701. $string =~ s/ +\n/\n/gms;
  702. #$string =~ s/^(.)/$indent$1/gm;
  703. # unindent preprocessor directives
  704. $string =~ s/^$indent#/#/gms;
  705. }
  706. return $string;
  707. }
  708. %Hungarian =
  709. (
  710. # We default to empty.
  711. "BOOL" => "f",
  712. "int" => "n",
  713. "short" => "n",
  714. "long" => "n",
  715. "INT" => "n",
  716. "SHORT" => "n",
  717. "LONG" => "n",
  718. "UINT" => "n",
  719. "USHORT" => "n",
  720. "ULONG" => "n",
  721. "WORD" => "n",
  722. "DWORD" => "n",
  723. "INT_PTR" => "n",
  724. "LONG_PTR" => "n",
  725. "UINT_PTR" => "n",
  726. "ULONG_PTR" => "n",
  727. "DWORD_PTR" => "n",
  728. "HWND" => "window",
  729. "HRESULT" => "",
  730. "COLORREF" => "color",
  731. "HICON" => "icon",
  732. "PVOID" => "v",
  733. "HMODULE" => "module",
  734. "HINSTANCE" => "instance",
  735. "HBITMAP" => "bitmap",
  736. "LANGID" => "languageId",
  737. "HIMAGELIST" => "imagelist",
  738. );
  739. $headerName = MakeLower($ARGV[0]);
  740. #DebugPrint("ARGV is " . join(" ", @ARGV) . "\n");
  741. #DebugExit();
  742. @ARGV = reverse(@ARGV);
  743. pop(ARGV);
  744. @ARGV = reverse(@ARGV);
  745. #DebugPrint("ARGV is " . join(" ", @ARGV) . "\n");
  746. #
  747. # The command line should say 'SetStubsFile('foo.sxs-stubs');'
  748. #
  749. eval(join("\n", @ARGV));
  750. if ($headerName =~ /\\/)
  751. {
  752. ($headerLeafName) = ($headerName =~ /.+\\(.+)/);
  753. $headerFullPath = $headerName;
  754. }
  755. else
  756. {
  757. $headerLeafName = $headerName;
  758. $headerFullPath = GetNtDrive() . GetNtRoot() . "\\public\\sdk\\inc\\" . $headerName;
  759. }
  760. #DebugPrint($headerFullPath);
  761. open(headerFileHandle, "< " . $headerFullPath) || die;
  762. #
  763. # extract out the executable code
  764. # /* #!perl */
  765. #
  766. # $code .= "/* " . $headerFullPath . " */\n\n";
  767. # read all the lines into one string
  768. $file = join("", <headerFileHandle>);
  769. # if it doesn't contain any embedded Perl, then we are a no-op, just spit it out
  770. # This way we can run over all files, makes it easier to edit shell\published\makefile.inc.
  771. if ($file !~ /#!perl/ms)
  772. {
  773. print($file);
  774. EarlySuccessExit();
  775. }
  776. #
  777. # Change WINOLEAPI_(type) to just type.
  778. # This lets objbase.h/ole2.h work.
  779. #
  780. @types = qw(void HINSTANCE BOOL int LPVOID DWORD ULONG HOLEMENU HANDLE HGLOBAL);
  781. foreach $type (@types)
  782. {
  783. $file =~ s/\bWINOLEAPI_\($type\) +/$type\n/g;
  784. };
  785. $file =~ s/\bWINOLEAPI\b/HRESULT\n/g;
  786. #
  787. # Remove stuff that doesn't mean much.
  788. #
  789. $file =~ s/\bWINAPIV\b/ /g;
  790. $file =~ s/\bWINAPI\b/ /g;
  791. $file =~ s/\b__stdcall\b/ /g;
  792. $file =~ s/\b_stdcall\b/ /g;
  793. $file =~ s/\b__cdecl\b/ /g;
  794. $file =~ s/\b_cdecl\b/ /g;
  795. $file =~ s/\b__fastcall\b //g;
  796. $file =~ s/\b_fastcall\b/ /g;
  797. $file =~ s/\bCALLBACK\b/ /g;
  798. $file =~ s/\bPASCAL\b/ /g;
  799. $file =~ s/\bAPIENTRY\b/ /g;
  800. $file =~ s/\bFAR\b/ /g;
  801. $file =~ s/\bNEAR\b/ /g;
  802. $file =~ s/\bvolatile\b/ /g;
  803. $file =~ s/\bIN\b/ /g;
  804. $file =~ s/\bOUT\b/ /g;
  805. $file =~ s/\bDECLSPEC_NORETURN\b/ /g;
  806. $file =~ s/\bOPTIONAL\b/ /g;
  807. # honor backslash line continuations, before removing preprocessor directives
  808. $file =~ s/\\\n//gms;
  809. # execute perl code embedded in comments
  810. # quadratic behavior where we keep searching for the string, remove, search, remove..
  811. # without remembering where the previous find was
  812. while ($file =~ s/\/\* ?#!perl(.*?)\*\///ms)
  813. {
  814. $_ = $1;
  815. # C++ comments in the Perl comment are removed
  816. s/\/\/.*?$//gms; # support C++ comments within the #!perl C comment.
  817. # something resembling C comment close is restored
  818. # escape-o-rama..
  819. s/\* \//\*\//gms;
  820. eval;
  821. #DebugPrint;
  822. }
  823. #DebugPrint($file);
  824. #DebugExit();
  825. # remove comments, before removing preprocessor directives
  826. $file =~ s/\/\*.*?\*\//\n/gms;
  827. $file =~ s/\/\/.*?$//gms;
  828. #DebugPrint($file);
  829. #DebugExit();
  830. # remove preprocessor directives
  831. # must do this before we make one statement per line in pursuit
  832. # of an easy typedef/struct removal
  833. $file =~ s/^[ \t]*#.*$//gm;
  834. # remove FORCEINLINE functions, assuming they don't contain any braces..
  835. $file =~ s/FORCEINLINE.+?}//gms;
  836. # remove extern C open and close
  837. # must do this before we make one statement per line in pursuit
  838. # of an easy typedef/struct removal
  839. $file =~ s/\bextern\b \"C\" {$//gm;
  840. $file =~ s/^}$//gm;
  841. #
  842. # cleanup commdlg.h
  843. #
  844. # remove Afx blah
  845. $file =~ s/^.*Afx.*$//gm;
  846. # remove IID blah
  847. $file =~ s/^.*DEFINE_GUID.*$//gm;
  848. # remove IPrintDialogCallback
  849. $file =~ s/DECLARE_INTERFACE_.+?};//gs;
  850. #
  851. # cleanup ole2.h
  852. #
  853. $file =~ s/typedef struct _OLESTREAMVTBL.+}.+?;.+?;//gs;
  854. #
  855. # futz with whitespace (has to do with having removed comments from within structs)
  856. # we do this more later
  857. #
  858. $file =~ s/[ \t\n]+/ /g;
  859. # remove typedefs and structs, this is extremely sloppy and fragile
  860. # .. we fold statements to be single lines, and then only keep statements that have parens,
  861. # and then remove single line typedefs and structs as well
  862. # .. avoiding counting braces ..
  863. $file =~ s/\n/ /gms; # remove all newlines
  864. $file =~ s/;/;\n/gms; # each statement on its own line (also struct fields on their own line)
  865. $file =~ s/^[^()]+$//gm; # only keep statements with parens
  866. #
  867. # types with parens that don't have typedefs will defeat the above, for example:
  868. # struct foo {
  869. # void (*bar)(void);
  870. # };
  871. #
  872. # Still, just by requiring a leading "WIN" on function declarations, we can live with structs and
  873. # typedefs in the file.
  874. #
  875. $file =~ s/^ +//gm; # remove spaces at start of line
  876. $file =~ s/^typedef\b.+;$//gm; # remove typedefs (they're probably already gone)
  877. $file =~ s/^struct\b.+;$//gm; # remove structs (they're probably already gone)
  878. $file =~ s/\n+/\n/g; # remove empty lines
  879. #DebugPrint $file;
  880. $file =~ s/^.+\.\.\..+$//gm; # remove vararg functions
  881. # format as one function declaration per line, no empty lines (some of this is redundant
  882. # given how we now remove typedefs and structs)
  883. $file =~ s/[ \t\n]+/ /g;
  884. $file =~ s/;/;\n/g;
  885. $file =~ s/^.+?\bWinMain\b.+?$//gm; # WinMain looks wierd due to #ifdef _MAC. Remove it.
  886. $file =~ s/\n+/\n/g; # remove empty lines (again)
  887. $file =~ s/^ +//gm; # remove spaces at line starts (again)
  888. $file =~ s/\A\n+//g; # remove newline from very start of file
  889. # more simplications, more whitespace, fewer other characters
  890. $file =~ s/\);$//gm; # get rid of trailing semi and rparen
  891. #$file =~ s/\(/ \(/g; # make sure whitespace precedes lparens, to set them off from function name
  892. $file =~ s/\*/ \* /g; # make sure stars are whitespace delimited
  893. $file =~ s/\( +/\(/g; # remove whitespace after lparen
  894. $file =~ s/\bWINBASEAPI\b/ /g;
  895. $file =~ s/\bWINADVAPI\b/ /g;
  896. $file =~ s/\bWINUSERAPI\b/ /g;
  897. $file =~ s/\bWINCOMMCTRLAPI\b/ /g;
  898. $file =~ s/\bWINGDIAPI\b/ /g;
  899. $file =~ s/\bWINCOMMDLGAPI\b/ /g;
  900. $file =~ s/\bWIN[A-Z]+API\b/ /g;
  901. $file =~ s/^ +//gm; # remove whitespace at start of lines
  902. # normalize what empty parameter lists look like between (VOID) and (void)
  903. # leave PVOID and LPVOID alone (\b for word break)
  904. # lowercase others while we're at it
  905. $file =~ s/\b(VOID|CONST|INT|LONG|SHORT)\b/\L$1\E/g;
  906. $file =~ s/\($/\(void/gm; # change the occasional C++ form (this is broken if compiling for C) to the C form
  907. # yet more whitespace cleanup
  908. #$file =~ s/ *(,|\*) */$1/g; # remove whitespace around commas and stars
  909. $file =~ s/ *, */,/g; # remove whitespace around commas
  910. $file =~ s/^ +//gm; # remove spaces at start of line
  911. $file =~ s/ +$//gm; # remove spaces at end of line
  912. $file =~ s/ +/ /g; # runs of spaces to single spaces
  913. if (0)
  914. {
  915. DebugPrint $file;
  916. DebugExit();
  917. }
  918. foreach $line (split("\n", $file))
  919. {
  920. @argsTypes = ();
  921. $unnamed_counter = 1;
  922. # split off return type and name at first lparen
  923. #($retname, $args) = ($line =~ /WIN[A-Z]+ ([^(]+)\((.+)/);
  924. ($retname, $args) = ($line =~ /([^(]+)\((.+)/);
  925. # split off name as last space delimited from return type and name,
  926. # allowing return type to be multiple tokens
  927. ($ret, $name) = ($retname =~ /(.*) ([^ ]+)/);
  928. $args =~ s/^ +//g; # cleanup whitespace (again)
  929. $args =~ s/ +$//g; # cleanup whitespace (again!)
  930. $args =~ s/ +/ /g; # cleanup whitespace (again!!)
  931. #
  932. # now split up args, split their name from their type, and provide names for unnamed ones
  933. # and note if they are void
  934. # the key is to generate the two strings, argNamesAndTypes and argNames
  935. #
  936. # unnamed parameters are parameters that either
  937. # have only one token
  938. # or whose last token is a star
  939. # we don't handle C++ references or "untypedefed structs passed by value" like "void F(struct G);"
  940. # or inline defined structs "void F(struct G { int i; });"
  941. #
  942. $argNames = "";
  943. if ($args !~ /^void$/)
  944. {
  945. #
  946. # args2 is args with unnamed parameters inserted as needed.
  947. # args is replaced by args2 when we finish building args2.
  948. #
  949. $args2 = "";
  950. foreach $arg (split(/,/, $args))
  951. {
  952. #
  953. # If a parameter contains just one word, it is unnamed.
  954. # The word is the type and there is no name.
  955. #
  956. if ($arg =~ /^ *\w+ *$/)
  957. {
  958. $argName = "unnamed" . $unnamed_counter++;
  959. $argType = $arg; # The whole arg is the type since there's no name.
  960. }
  961. #
  962. # If a parameter ends with a star, it is unnamed.
  963. #
  964. elsif ($arg =~ /\* *$/)
  965. {
  966. $argName = "unnamed" . $unnamed_counter++;
  967. $argType = $arg; # The whole arg is the type since there's no name.
  968. }
  969. else
  970. {
  971. #
  972. # The last word is the name, whatever precedes it is the type.
  973. # This does not work with arrays and pointers to functions, unless
  974. # typedefs are used.
  975. #
  976. ($argType, $argName) = ($arg =~ /(.+?)(\w+)$/);
  977. }
  978. $argType = RemoveSpacesAroundStars($argType);
  979. $argType = RemoveSpacesAroundCommas($argType);
  980. $argType = RemoveTrailingComma($argType);
  981. $argType = RemoveLeadingAndTrailingSpaces($argType);
  982. $comType = $ComInterfaceParameterType{$argType};
  983. #DebugPrint($name . ' ' . $argType . " -> " . $comType . "\n");
  984. if ($comType)
  985. {
  986. $comData{$comType}{$argType} = 1;
  987. $argType = ComInterfaceParameterReplacementIdentifier($argType);
  988. }
  989. $argNames .= $argName . ',';
  990. $args2 .= $argType . ' ' . $argName . ',';
  991. push(@argsTypes, ($argType));
  992. }
  993. $args = $args2;
  994. }
  995. $dll = $MapHeaderToDll{RemoveExtension($headerLeafName)};
  996. if ( ($DelayLoad{$dll}
  997. || $DelayLoad{$name}
  998. || ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
  999. || $ActivateAroundFunctionCall{$name}
  1000. || $ActivateNULLAroundFunctionCall{$name})
  1001. && !$IgnoreFunction{$name}
  1002. )
  1003. {
  1004. $args = RemoveSpacesAroundStars($args);
  1005. $argNames = RemoveSpacesAroundStars($argNames);
  1006. $args = RemoveSpacesAroundCommas($args);
  1007. $argNames = RemoveSpacesAroundCommas($argNames);
  1008. $args = RemoveTrailingComma($args);
  1009. $argNames = RemoveTrailingComma($argNames);
  1010. $args = RemoveLeadingAndTrailingSpaces($args);
  1011. $argNames = RemoveLeadingAndTrailingSpaces($argNames);
  1012. $function = Function->new();
  1013. $function->ret($ret);
  1014. $function->name($name);
  1015. $function->argsTypesNames("(". $args . ")");
  1016. $function->argsNames("(". $argNames . ")");
  1017. $error = MakeStringTrue($FunctionErrorValue{$name});
  1018. if (!$error)
  1019. {
  1020. $error = MakeStringTrue($TypeErrorValue{$ret});
  1021. }
  1022. #DebugPrint("error for $ret:$name is $error\n");
  1023. if (!$error && $ret ne "void" && $ret ne "HRESULT" && !$NeverFails{$name})
  1024. {
  1025. ErrorPrint($ErrorMessagePrefix . "don't know know error value for $dll:$name:$ret:$args\n");
  1026. ErrorPrint($ErrorMessagePrefix . "line is '" . $line . "'\n");
  1027. ErrorExit();
  1028. #$error = "((" . $ret . ")0)";
  1029. }
  1030. $function->error($error);
  1031. $retname = $Hungarian{$ret};
  1032. if (!$retname)
  1033. {
  1034. $retname = "result";
  1035. }
  1036. else
  1037. {
  1038. $retname .= "Result";
  1039. }
  1040. $function->retname($retname);
  1041. $function->dll($dll);
  1042. $function->header(RemoveExtension(MakeLower($headerLeafName)) . ".h");
  1043. if ($DelayLoad{$dll} || $DelayLoad{$name})
  1044. {
  1045. $function->delayload($true);
  1046. }
  1047. push(@functions, ($function));
  1048. #DebugPrint("pushed " . $name . "\n");
  1049. }
  1050. else
  1051. {
  1052. #DebugPrint("didn't push " . $name . "(" . $dll . ")\n");
  1053. }
  1054. }
  1055. sub InsertCodeIntoFile
  1056. {
  1057. my($code, $filePath) = ($_[0], $_[1]);
  1058. my($fileContents, $fileHandle);
  1059. my($stubsFileHandle);
  1060. my($yearnow);
  1061. my($insertionPoint);
  1062. my($generateInclude);
  1063. #DebugPrint("/* InsertCodeIntoFile */");
  1064. $fileHandle = new IO::File($filePath, "r");
  1065. $fileContents = join("", $fileHandle->getlines());
  1066. #
  1067. # We have decided to sometimes use an #include in order to not be so large.
  1068. #
  1069. # Remove the executable perl code.
  1070. $fileContents =~ s/\/\* ?#!perl.*?\*\/\n+/\n/msg;
  1071. $fileContents =~ s/\/\* ?#!perl.*?\*\///msg;
  1072. $insertionPoint = $InsertionPoint{MakeLower(BaseName($filePath))};
  1073. #DebugPrint("LeafPath is " . LeafPath($filePath));
  1074. #DebugPrint("filePath is $filePath");
  1075. #DebugPrint("insertionPoint is $insertionPoint");
  1076. if ($insertionPoint || $StubsFile)
  1077. {
  1078. $code =
  1079. "#if defined(__cplusplus)\n"
  1080. . "extern \"C\" {\n"
  1081. . "#endif\n\n"
  1082. . $code
  1083. . "\n#if defined(__cplusplus)\n"
  1084. . "} /* __cplusplus */\n"
  1085. . "#endif\n"
  1086. ;
  1087. }
  1088. if ($StubsFile)
  1089. {
  1090. #DebugPrint("StubsFile is $StubsFile\n");
  1091. $stubsFileHandle = new IO::File($StubsFile, "w");
  1092. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
  1093. my ($firstyear) = 2001;
  1094. $year += 1900;
  1095. if ($year == $firstyear)
  1096. {
  1097. $stubsFileHandle->print("/* Copyright (c) " . $firstyear . " Microsoft Corp. All rights reserved. */\n");
  1098. }
  1099. else
  1100. {
  1101. $stubsFileHandle->print("/* Copyright (c) " . $firstyear . "-" . $year .", Microsoft Corp. All rights reserved. */\n");
  1102. }
  1103. #$stubsFileHandle->print("/* This file generated " . localtime() . " */\n");
  1104. $stubsFileHandle->print("\n");
  1105. $stubsFileHandle->print("#if _MSC_VER > 1000\n");
  1106. $stubsFileHandle->print("#pragma once\n");
  1107. $stubsFileHandle->print("#endif\n");
  1108. $stubsFileHandle->print("\n");
  1109. $stubsFileHandle->print($code);
  1110. $generateInclude = 1;
  1111. }
  1112. if ($generateInclude)
  1113. {
  1114. # generate the include, within #if
  1115. $code = "";
  1116. $code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
  1117. $code .= "#if defined($ENABLED) && ($ENABLED != 0)\n";
  1118. $code .= "#include \"" . LeafPath($StubsFile) . "\"\n";
  1119. $code .= "#endif /* $ENABLED */\n";
  1120. $code .= "#endif /* RC */";
  1121. }
  1122. if ($insertionPoint)
  1123. {
  1124. #DebugPrint("/* abc */");
  1125. $fileContents =~ s/$insertionPoint/\n$code\n/ms;
  1126. }
  1127. else
  1128. {
  1129. #
  1130. # put the #include or the code into the the file
  1131. #
  1132. # The #include or the code goes before the last
  1133. # occurence of #ifdef __cplusplus or #if defined(__cplusplus).
  1134. #
  1135. $fileContents =~ s/(.+)(#if[defined( \t]+__cplusplus.*?$})/$1\n\n$code\n\n$2/ms;
  1136. }
  1137. return $fileContents;
  1138. };
  1139. sub GenerateHeaderCommon1
  1140. {
  1141. my($function) = ($_[0]);
  1142. my($x, $dll, $dllid, $header);
  1143. #DebugPrint("2\n");
  1144. $dll = MakeLower($function->dll());
  1145. $dllid = MakeTitlecase(ToIdentifier($dll));
  1146. $header = MakeLower(BaseName($function->header())) . ".h";
  1147. $x .= '
  1148. #if !defined(ISOLATION_AWARE_USE_STATIC_LIBRARY)
  1149. #define ISOLATION_AWARE_USE_STATIC_LIBRARY 0
  1150. #endif
  1151. #if !defined(ISOLATION_AWARE_BUILD_STATIC_LIBRARY)
  1152. #define ISOLATION_AWARE_BUILD_STATIC_LIBRARY 0
  1153. #endif
  1154. #if !defined(' . $INLINE . ')
  1155. #if ISOLATION_AWARE_BUILD_STATIC_LIBRARY
  1156. #define ' . $INLINE . ' /* nothing */
  1157. #else
  1158. #if defined(__cplusplus)
  1159. #define ' . $INLINE . ' inline
  1160. #else
  1161. #define ' . $INLINE . ' __inline
  1162. #endif
  1163. #endif
  1164. #endif
  1165. ';
  1166. $x .= "#if !ISOLATION_AWARE_USE_STATIC_LIBRARY\n";
  1167. $x .= $MapHeaderToSpecialCode1{$header};
  1168. $x .= "FARPROC WINAPI ";
  1169. $x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
  1170. $x .= "(LPCSTR pszProcName);\n\n";
  1171. $x .= $SpecialChunksOfCode{$header};
  1172. $x .= "#endif /* ISOLATION_AWARE_USE_STATIC_LIBRARY */\n";
  1173. return $x;
  1174. }
  1175. sub GenerateHeaderCommon2
  1176. {
  1177. my($function) = ($_[0]);
  1178. my($x);
  1179. my($dll);
  1180. my($LoadLibrary);
  1181. my($indent);
  1182. my($dllid);
  1183. my($activate);
  1184. my($header);
  1185. my($exit);
  1186. my($exit_ret);
  1187. my($exit_leave);
  1188. $LoadLibA = $MyLoadLibraryA; # or GetModuleHandle
  1189. $LoadLibW = $MyLoadLibraryW; # or GetModuleHandle
  1190. $dll = MakeLower($function->dll());
  1191. $dllid = ToIdentifier(MakeTitlecase($dll));
  1192. $indent = "";
  1193. $activate = $ActivateAroundDelayLoad{$dll};
  1194. $header = MakeLower(LeafPath($function->header()));
  1195. #DebugPrint("header is " . $header . "\n");
  1196. $x .= $MapHeaderToSpecialCode2{$header};
  1197. $x .= $INLINE . " FARPROC WINAPI ";
  1198. $x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
  1199. $x .= "(LPCSTR pszProcName)\n";
  1200. $x .= "/* This function is shared by the other stubs in this header. */\n";
  1201. $x .= "{\n";
  1202. $indent = Indent($indent);
  1203. if ($activate)
  1204. {
  1205. $x .= $indent . "FARPROC proc = NULL;\n";
  1206. }
  1207. $x .= $indent . "static HMODULE s_module;\n";
  1208. $exit_ret = "return proc;\n";
  1209. $exit_leave = "__leave;\n";
  1210. $exit = $exit_ret;
  1211. if ($activate)
  1212. {
  1213. $x .= $indent . "BOOL fActivateActCtxSuccess = FALSE;\n";
  1214. $x .= $indent . "ULONG_PTR ulpCookie = 0;\n";
  1215. }
  1216. $Dll = MakeTitlecase($function->dll());
  1217. if ($Dll eq "Kernel32.dll")
  1218. {
  1219. $x .= $indent . "/* Use GetModuleHandle instead of LoadLibrary on kernel32.dll because */\n";
  1220. $x .= $indent . "/* we already necessarily have a reference on kernel32.dll. */\n";
  1221. $LoadLibA = $MyGetModuleHandleA;
  1222. $LoadLibW = $MyGetModuleHandleW;
  1223. }
  1224. else
  1225. {
  1226. $LoadLibrary = "LoadLibrary";
  1227. }
  1228. $x .= $indent . "const static $CONSTANT_MODULE_INFO\n";
  1229. $x .= $indent . " c = { $LoadLibA, $LoadLibW, \"$Dll\", L\"$Dll\" };\n";
  1230. $x .= $indent . "static $MUTABLE_MODULE_INFO m;\n\n";
  1231. if ($activate)
  1232. {
  1233. $x .= $indent . "__try\n";
  1234. $x .= $indent . "{\n";
  1235. $indent = Indent($indent);
  1236. $exit = $exit_leave;
  1237. $x .= $indent . "if (!" . $g_fDownlevel . ")\n";
  1238. $x .= $indent . "{\n";
  1239. $indent = Indent($indent);
  1240. $x .= $indent . "fActivateActCtxSuccess = ";
  1241. $x .= $ActivateMyActCtx;
  1242. $x .= "(&ulpCookie);\n";
  1243. $x .= $indent . "if (!fActivateActCtxSuccess)\n";
  1244. $x .= IndentMultiLineString($indent, $exit);
  1245. $indent = Outdent($indent);
  1246. $x .= $indent . "}\n";
  1247. $x .= $indent . "proc = $MyGetProcAddress(&c, &m, pszProcName);\n";
  1248. $indent = Outdent($indent);
  1249. $x .= $indent . "}\n";
  1250. $x .= $indent . "__finally\n";
  1251. $x .= $indent . "{\n";
  1252. $indent = Indent($indent);
  1253. $x .= $indent . "if (!" . $g_fDownlevel . " && fActivateActCtxSuccess)\n";
  1254. $x .= $indent . "{\n";
  1255. $indent = Indent($indent);
  1256. $x .= $indent . "const DWORD dwLastError = (proc == NULL) ? GetLastError() : NO_ERROR;\n";
  1257. $x .= $indent . "(void)" . $DeactivateActCtx . "(0, ulpCookie);\n";
  1258. $x .= $indent . "if (proc == NULL)\n";
  1259. $x .= $indent . " SetLastError(dwLastError);\n";
  1260. $indent = Outdent($indent);
  1261. $x .= $indent . "}\n";
  1262. $indent = Outdent($indent);
  1263. $x .= $indent . "}\n";
  1264. $x .= $indent . "return proc;\n";
  1265. }
  1266. else
  1267. {
  1268. $x .= $indent . "return $MyGetProcAddress(&c, &m, pszProcName);\n";
  1269. }
  1270. $x .= "}\n\n";
  1271. return $x;
  1272. }
  1273. sub GeneratePrototype
  1274. {
  1275. my($function) = ($_[0]);
  1276. my($proto);
  1277. $proto .= $function->ret() . " WINAPI ";
  1278. $proto .= MakePublicName($function->name());
  1279. $proto .= $function->argsTypesNames() . ";\n";
  1280. return $proto;
  1281. }
  1282. sub DelayLoadOrActivateAroundFunction
  1283. {
  1284. my($function) = ($_[0]);
  1285. my($dll);
  1286. my($name);
  1287. my($activate);
  1288. my($delayload);
  1289. $dll = $function->dll();
  1290. $name = $function->name();
  1291. $activate = $ActivateAroundFunctionCall{$name} || ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
  1292. || $ActivateNULLAroundFunctionCall{$name};
  1293. $delayload = $DelayLoad{$name} || $DelayLoad{$dll};
  1294. return ($activate || $delayload);
  1295. }
  1296. sub DoesHeaderNeedWin32ToHresult
  1297. {
  1298. my($function);
  1299. foreach $function (@functions)
  1300. {
  1301. if ($function->ret() eq "HRESULT" && DelayLoadOrActivateAroundFunction($function))
  1302. {
  1303. return 1;
  1304. }
  1305. }
  1306. return 0;
  1307. }
  1308. sub GenerateStub
  1309. {
  1310. my($function) = ($_[0]);
  1311. my($activate);
  1312. my($delayload);
  1313. my($stub);
  1314. my($indent);
  1315. my($name);
  1316. my($dll);
  1317. my($ret);
  1318. my($retname);
  1319. my($exit);
  1320. my($exit_ret);
  1321. my($exit_leave);
  1322. $name = $function->name();
  1323. $dll = $function->dll();
  1324. $dllid = MakeTitlecase(ToIdentifier($dll));
  1325. $ret = $function->ret();
  1326. $retname = $function->retname();
  1327. $indent = "";
  1328. $stub = "";
  1329. $activate = $ActivateAroundFunctionCall{$name} || $ActivateAroundFunctionCall{$dll}
  1330. || $ActivateNULLAroundFunctionCall{$name};
  1331. $delayload = $DelayLoad{$name} || $DelayLoad{$dll};
  1332. if ($function->ret() eq "HRESULT")
  1333. {
  1334. $exit_ret = "return $Win32ToHresult();\n";
  1335. $exit_leave = "{\n $retname = $Win32ToHresult();\n __leave;\n}";
  1336. }
  1337. elsif ($ret eq "void")
  1338. {
  1339. $exit_ret = "return;\n";
  1340. $exit_leave = "__leave;\n";
  1341. }
  1342. else
  1343. {
  1344. $exit_ret = "return " . $function->retname() . ";\n";
  1345. $exit_leave = "__leave;\n";
  1346. }
  1347. $exit = $exit_ret;
  1348. # "prototype"
  1349. $stub .= $INLINE . " " . $ret . " WINAPI ";
  1350. $stub .= MakePublicName($function->name());
  1351. $stub .= $function->argsTypesNames() . "\n";
  1352. $stub .= $indent . "{\n";
  1353. $indent = Indent($indent);
  1354. # locals
  1355. if ($ret ne "void")
  1356. {
  1357. $stub .= $indent . $ret . " " . $function->retname() . " = " . $function->error() . ";\n";
  1358. }
  1359. if ($delayload)
  1360. {
  1361. $stub .= $indent . "typedef " . $ret . " (WINAPI* PFN)" . $function->argsTypesNames() . ";\n";
  1362. $stub .= $indent . "static PFN s_pfn;\n";
  1363. }
  1364. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"locals"});
  1365. if ($activate)
  1366. {
  1367. $stub .= $indent . "ULONG_PTR ulpCookie = 0;\n";
  1368. $stub .= $indent . "const BOOL fActivateActCtxSuccess = " . $g_fDownlevel . " || ";
  1369. }
  1370. # code (partly merged with local sometimes ("initialization" in the strict C++ terminology sense)
  1371. if ($activate)
  1372. {
  1373. if ($ActivateNULLAroundFunctionCall{$function->name()})
  1374. {
  1375. $stub .= $ActivateActCtx;
  1376. $stub .= "(NULL, &ulpCookie);\n";
  1377. }
  1378. else
  1379. {
  1380. $stub .= $ActivateMyActCtx;
  1381. $stub .= "(&ulpCookie);\n";
  1382. }
  1383. $stub .= $indent . "if (!fActivateActCtxSuccess)\n";
  1384. $stub .= IndentMultiLineString($indent, $exit);
  1385. $stub .= $indent . "__try\n";
  1386. $stub .= $indent . "{\n";
  1387. $indent = Indent($indent);
  1388. $exit = $exit_leave;
  1389. }
  1390. if ($delayload)
  1391. {
  1392. $stub .= $indent . "if (s_pfn == NULL)\n";
  1393. $stub .= $indent . "{\n";
  1394. $indent = Indent($indent);
  1395. $stub .= $indent . "s_pfn = (PFN)";
  1396. $stub .= MakeHeaderPrivateName($function->header(), "GetProcAddress_$dllid");
  1397. $stub .= "(";
  1398. #
  1399. # Some functions are exported with different names
  1400. # on Win64 vs. Win32.
  1401. #
  1402. if ($ExportName32{$name} || $ExportName64{$name})
  1403. {
  1404. if (!$ExportName32{$name})
  1405. {
  1406. $ExportName32{$name} = $name;
  1407. }
  1408. if (!$ExportName64{$name})
  1409. {
  1410. $ExportName64{$name} = $name;
  1411. }
  1412. $stub .= "\n#if defined(_WIN64)\n";
  1413. $stub .= $indent . "\"" . $ExportName64{$name} . "\"\n";
  1414. $stub .= "#else\n";
  1415. $stub .= $indent . "\"" . $ExportName32{$name} . "\"\n";
  1416. $stub .= "#endif\n";
  1417. $stub .= $indent;
  1418. }
  1419. else
  1420. {
  1421. $stub .= "\"" . $name . "\"";
  1422. }
  1423. $stub .= ");\n";
  1424. $stub .= $indent . "if (s_pfn == NULL)\n";
  1425. $stub .= IndentMultiLineString($indent, $exit);
  1426. $indent = Outdent($indent);
  1427. $stub .= $indent . "}\n";
  1428. }
  1429. if ($SpecialChunksOfCode{$function->name()}{"body"})
  1430. {
  1431. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"body"});
  1432. }
  1433. else
  1434. {
  1435. $stub .= $indent;
  1436. if ($ret ne "void")
  1437. {
  1438. $stub .= $function->retname() . " = ";
  1439. }
  1440. if ($delayload)
  1441. {
  1442. $stub .= "s_pfn";
  1443. }
  1444. else
  1445. {
  1446. $stub .= $function->name();
  1447. }
  1448. $stub .= $function->argsNames();
  1449. $stub .= ";\n";
  1450. }
  1451. if ($activate)
  1452. {
  1453. #
  1454. # We cannot propagate the error from DeactivateActCtx.
  1455. # 1) DeactivateActCtx only fails with INVALID_PARAMETER.
  1456. # 2) How to generally cleanup the result, like of CreateWindow?
  1457. #
  1458. $indent = Outdent($indent);
  1459. $stub .= $indent . "}\n";
  1460. $stub .= $indent . "__finally\n";
  1461. $stub .= $indent . "{\n";
  1462. $indent = Indent($indent);
  1463. $stub .= $indent . "if (!" . $g_fDownlevel . ")\n";
  1464. $stub .= $indent . "{\n";
  1465. $indent = Indent($indent);
  1466. $maybePreserveError = 0;
  1467. if ($ret ne "void" && $ret ne "HRESULT")
  1468. {
  1469. $maybePreserveError = 1;
  1470. $stub .= $indent . "const BOOL fPreserveLastError = (" . $retname . " == " . $function->error() . ");\n";
  1471. $stub .= $indent . "const DWORD dwLastError = fPreserveLastError ? GetLastError() : NO_ERROR;\n";
  1472. }
  1473. else
  1474. {
  1475. # nothing;
  1476. }
  1477. $stub .= $indent . "(void)" . $DeactivateActCtx . "(0, ulpCookie);\n";
  1478. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"cleanup"});
  1479. if ($maybePreserveError)
  1480. {
  1481. $stub .= $indent . "if (fPreserveLastError)\n";
  1482. $stub .= $indent . " SetLastError(dwLastError);\n";
  1483. }
  1484. $indent = Outdent($indent);
  1485. $stub .= $indent . "}\n";
  1486. $indent = Outdent($indent);
  1487. $stub .= $indent . "}\n";
  1488. }
  1489. if ($activate)
  1490. {
  1491. #$stub .= "Exit:\n";
  1492. }
  1493. if ($ret ne "void")
  1494. {
  1495. $stub .= $indent . "return " . $function->retname() . ";\n";
  1496. }
  1497. else
  1498. {
  1499. $stub .= $indent . "return;\n";
  1500. }
  1501. $indent = Outdent($indent);
  1502. $stub .= $indent . "}\n\n";
  1503. return $stub;
  1504. };
  1505. foreach $function (@functions)
  1506. {
  1507. if (0)
  1508. {
  1509. DebugPrint(
  1510. "ret:" . $function->ret()
  1511. . " name:" . $function->name()
  1512. . " argsTypesNames:" . $function->argsTypesNames()
  1513. . " argsNames:" . $function->argsNames()
  1514. . "\n"
  1515. );
  1516. }
  1517. }
  1518. $code .= "\n";
  1519. $code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
  1520. $code .= "#if defined($ENABLED) && ($ENABLED != 0)\n";
  1521. $code .= GenerateHeaderCommon1($functions[0]);
  1522. sub AppendNewlineIfNotEmpty
  1523. {
  1524. return $_[0] ? $_[0] . "\n" : $_[0];
  1525. }
  1526. sub GeneratePoundIf
  1527. {
  1528. #
  1529. # note: nesting does not work
  1530. #
  1531. #DebugPrint "GeneratePoundIf\n";
  1532. my($function) = ($_[0]);
  1533. my($name) = $function->name();
  1534. my($condition) = $PoundIfCondition{$name};
  1535. my($state) = $PoundIfState{$condition};
  1536. my($code) = "";
  1537. if ($condition)
  1538. {
  1539. #$code .= "/* GeneratePoundIf:function=$name;condition=$condition;state=$state */\n";
  1540. }
  1541. if ($condition)
  1542. {
  1543. if (!$state)
  1544. {
  1545. $code .= GeneratePoundEndif();
  1546. $PoundIfState{$condition} = 1;
  1547. $code .= "#if $condition\n";
  1548. }
  1549. }
  1550. else
  1551. {
  1552. $code .= GeneratePoundEndif();
  1553. }
  1554. return $code;
  1555. }
  1556. sub GeneratePoundEndif
  1557. {
  1558. #
  1559. # note: nesting does not work
  1560. #
  1561. my ($code) = "";
  1562. my($condition);
  1563. foreach $condition (keys(%PoundIfState))
  1564. {
  1565. $code .= "#endif /* $condition */\n";
  1566. }
  1567. undef %PoundIfState; # empty it
  1568. return $code;
  1569. }
  1570. sub ComInterfaceType_IfdefSymbol
  1571. {
  1572. my($x) = ($_[0]);
  1573. #
  1574. # produced by Midl
  1575. #
  1576. return '__' . $x . '_INTERFACE_DEFINED__';
  1577. }
  1578. #
  1579. # comData is a two level hash table.
  1580. # the first key is the COM interface, like IStream
  1581. # the second key is the actual parameter type, like LPSTREAM
  1582. # the value is just 1, the second level hash table is for automatic uniquing.
  1583. #
  1584. # Multiple parameter types may map to the same COM interface, like for a bogus example:
  1585. #
  1586. # typedef IStream *LPSTREAM;
  1587. # typedef IStream *LPSTREAM2;
  1588. #
  1589. # Foo(LPSTREAM);
  1590. # Foo2(LPSTREAM2);
  1591. #
  1592. # The generated code is generalized to support that.
  1593. #
  1594. foreach $comInterface (sort(keys(%comData)))
  1595. {
  1596. $code .= $newline;
  1597. $code .= '#if ';
  1598. $or = '';
  1599. #
  1600. # First see if we need to define the COM interface.
  1601. #
  1602. # eg:
  1603. # #if !defined(REPLACEMENT_LPSTREAM) || \
  1604. # !defined(REPLACEMENT_LPSTREAM2)
  1605. #
  1606. foreach $comInterfaceParameterType (sort(keys(%{$comData{$comInterface}})))
  1607. {
  1608. $code .=
  1609. $or . '!defined(' . ComInterfaceParameterReplacementIdentifier($comInterfaceParameterType) . ')';
  1610. $or = ' || \\' . $newline . ' ';
  1611. }
  1612. $code .= $newline;
  1613. #
  1614. # Now see if we have the "real" COM interface definition from Midl.
  1615. # If not, generate it.
  1616. #
  1617. # eg:
  1618. # #if !defined(_IStream_INTERFACE_DEFINED)
  1619. # #if defined(interface)
  1620. # interface IStream; typedef interface IStream IStream;
  1621. # #else
  1622. # struct IStream; typedef struct IStream IStream;
  1623. # #endif
  1624. # #endif
  1625. #
  1626. $code .= '#if !defined(' . ComInterfaceType_IfdefSymbol($comInterface) . ')' . $newline;
  1627. $code .= ' #if defined(interface)' . $newline;
  1628. $code .= ' interface ' . $comInterface . '; typedef interface ' . $comInterface . ' ' . $comInterface . ';' . $newline;
  1629. $code .= ' #else' . $newline;
  1630. $code .= ' struct ' . $comInterface . '; typedef struct ' . $comInterface . ' ' . $comInterface . ';' . $newline;
  1631. $code .= ' #endif' . $newline;
  1632. $code .= '#endif' . $newline;
  1633. #
  1634. # Now for each parameter type, generate the typedefs if needed.
  1635. # eg:
  1636. #
  1637. # #if !defined(REPLACEMENT_LPSTREAM)
  1638. # typedef IStream *REPLACEMENT_LPSTREAM;
  1639. # #define REPLACEMENT_LPSTREAM REPLACEMENT_LPSTREAM
  1640. # #endif
  1641. # #if !defined(REPLACEMENT_LPSTREAM2)
  1642. # typedef IStream *REPLACEMENT_LPSTREAM2;
  1643. # #define REPLACEMENT_LPSTREAM2 REPLACEMENT_LPSTREAM2
  1644. # #endif
  1645. #
  1646. if (scalar(keys(%{$comData{$comInterface}})) > 1)
  1647. {
  1648. $needIndividualPoundIf = 1;
  1649. $typedefIndent = ' ';
  1650. }
  1651. else
  1652. {
  1653. $needIndividualPoundIf = 0;
  1654. $typedefIndent = '';
  1655. }
  1656. foreach $comInterfaceParameterType (sort(keys(%{$comData{$comInterface}})))
  1657. {
  1658. $replacement = ComInterfaceParameterReplacementIdentifier($comInterfaceParameterType);
  1659. if ($needIndividualPoundIf)
  1660. {
  1661. $code .= '#if !defined(' . $replacement . ')' . $newline;
  1662. }
  1663. $typedef = $ComInterfaceParameterTypedef{$comInterfaceParameterType};
  1664. $typedef =~ s/$comInterfaceParameterType/$replacement/g;
  1665. $code .= $typedefIndent . $typedef . $newline;
  1666. $code .= $typedefIndent . '#define ' . $replacement . ' ' . $replacement . $newline;
  1667. if ($needIndividualPoundIf)
  1668. {
  1669. $code .= '#endif' . $newline;
  1670. }
  1671. }
  1672. $code .= '#endif' . $newline;
  1673. }
  1674. #DebugPrint($code);
  1675. #DebugExit;
  1676. foreach $function (@functions)
  1677. {
  1678. $code .= GeneratePoundIf($function);
  1679. $code .= GeneratePrototype($function);
  1680. }
  1681. $code .= GeneratePoundEndif();
  1682. $headerBasename = BaseName($headerFullPath);
  1683. $upperBasename = MakeUpper($headerBasename);
  1684. $lowerBasename = MakeLower($headerBasename);
  1685. $Win32ToHresult = MakeHeaderPrivateName($headerBasename, 'Win32ToHresult');
  1686. if (DoesHeaderNeedWin32ToHresult())
  1687. {
  1688. $code .= $newline . $INLINE . ' HRESULT ' . $Win32ToHresult . '(void)';
  1689. $code .= '
  1690. {
  1691. DWORD dwLastError = GetLastError();
  1692. if (dwLastError == NO_ERROR)
  1693. dwLastError = ERROR_INTERNAL_ERROR;
  1694. return HRESULT_FROM_WIN32(dwLastError);
  1695. }
  1696. ';
  1697. }
  1698. # hash so we can look for FooA and FooW
  1699. foreach $function (@functions)
  1700. {
  1701. #DebugPrint($function->name() . "\n");
  1702. $hashFunctionNames{$function->name()} = $function;
  1703. }
  1704. $anyStringFunctions = 0; # objbase has no A/W string functions
  1705. foreach $function (sort(keys(%hashFunctionNames)))
  1706. {
  1707. #DebugPrint($function . "\n");
  1708. # if there exists FooA and FooW, then Foo is a string function
  1709. if ($function =~ /(.+)A$/ && $hashFunctionNames{$1 . "W"})
  1710. {
  1711. $anyStringFunctions = 1;
  1712. $stringFunctionsHash{$1} = 1;
  1713. #DebugPrint($1 . " is a string function\n");
  1714. }
  1715. }
  1716. if ($anyStringFunctions)
  1717. {
  1718. $code .= "\n#if defined(UNICODE)\n\n";
  1719. foreach $function (sort(keys(%stringFunctionsHash)))
  1720. {
  1721. $code .= "#define " . MakePublicName($function);
  1722. $code .= " " . MakePublicName($function . "W") . "\n";
  1723. }
  1724. $code .= "\n#else /* UNICODE */\n\n";
  1725. foreach $function (sort(keys(%stringFunctionsHash)))
  1726. {
  1727. $code .= "#define " . MakePublicName($function);
  1728. $code .= " " . MakePublicName($function . "A") . "\n";
  1729. }
  1730. $code .= "\n#endif /* UNICODE */\n\n";
  1731. }
  1732. else
  1733. {
  1734. $code .= "\n";
  1735. }
  1736. $code .= "#if !ISOLATION_AWARE_USE_STATIC_LIBRARY\n";
  1737. foreach $function (@functions)
  1738. {
  1739. $code .= AppendNewlineIfNotEmpty(GeneratePoundIf($function));
  1740. $code .= GenerateStub($function);
  1741. }
  1742. $code .= AppendNewlineIfNotEmpty(GeneratePoundEndif());
  1743. $code .= GenerateHeaderCommon2($functions[0]);
  1744. $code .= "#endif /* ISOLATION_AWARE_USE_STATIC_LIBRARY */\n\n";
  1745. # This was for objbase.h/ole2.h, but they don't use it.
  1746. $ifPerHeaderMacroEnable = $PerHeaderMacroEnable{$lowerBasename};
  1747. $perHeaderMacroSymbol = $ENABLED . '_' . $upperBasename;
  1748. if ($ifPerHeaderMacroEnable)
  1749. {
  1750. $code .= '#if defined(' . $perHeaderMacroSymbol . ')' . $newline;
  1751. }
  1752. foreach $function (sort(keys(%hashFunctionNames)))
  1753. {
  1754. if ($NoMacro{$function})
  1755. {
  1756. $code .= " /* " . $function . " skipped, as it is a popular C++ member function name. */\n";
  1757. }
  1758. else
  1759. {
  1760. if ($Undef{$function})
  1761. {
  1762. $code .= "#if defined(" . $function . ")\n";
  1763. $code .= "#undef " . $function . "\n";
  1764. $code .= "#endif\n";
  1765. }
  1766. $code .= "#define " . $function . " " . MakePublicName($function) . "\n";
  1767. }
  1768. }
  1769. if ($PerHeaderMacroEnable{MakeLower(BaseName($headerFullPath))})
  1770. {
  1771. $code .= '#endif /* defined(' . $perHeaderMacroSymbol . ') */' . $newline;
  1772. }
  1773. #$code .= "\n#endif\n\n";
  1774. $code .= "\n#endif /* " . $ENABLED . " */\n";
  1775. $code .= "#endif /* RC */\n\n";
  1776. $code = InsertCodeIntoFile($code, $headerFullPath);
  1777. print($code);
  1778. __END__
  1779. :endofperl