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

1608 lines
46 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. $ErrorMessagePrefix = 'NMAKE : U1234: ' . $ENV{'SDXROOT'} . '\\tools\\ShFusion2.bat ';
  55. sub MakeLower
  56. {
  57. my($x) = ($_[0]);
  58. return "\L$x";
  59. }
  60. sub MakeTitlecase
  61. {
  62. # first character uppercase, the rest lowercase
  63. my($x) = ($_[0]);
  64. $x = "\L$x";
  65. $x = "\u$x";
  66. return $x;
  67. }
  68. sub ToIdentifier
  69. {
  70. # replace dots with underscores
  71. my($x) = ($_[0]);
  72. $x =~ s/\./_/g;
  73. return $x;
  74. }
  75. sub MakePublicPreprocessorSymbol
  76. {
  77. #
  78. # ISOLATION_AWARE_WORDWITHNOUNDERSCORES
  79. # ISOLATIONAWARE_MULTIPLE_UNDERSCORE_SEPERATED_WORDS
  80. #
  81. # not great, but consistent with existing symbols
  82. #
  83. my($name) = ($_[0]);
  84. if ($name !~ /[A-Z_0-9]/)
  85. {
  86. # warning..
  87. }
  88. if ($name =~ /_/)
  89. {
  90. return "ISOLATIONAWARE_" . $name;
  91. }
  92. else
  93. {
  94. return "ISOLATION_AWARE_" . $name;
  95. }
  96. }
  97. $INLINE = MakePublicPreprocessorSymbol("INLINE");
  98. sub ObscurePrivateName
  99. {
  100. #my ($hungarian, $namespace,$x) = ($_[0],$_[1]);
  101. my ($namespace,$x) = ($_[0],$_[1]);
  102. $readable = $x;
  103. $x =~ tr/0-9/a-j/;
  104. # shift 13, and sometimes invert case
  105. $x =~ tr/a-m/N-Z/;
  106. $x =~ tr/n-z/a-m/;
  107. $x =~ tr/A-M/n-z/;
  108. $x =~ tr/N-Z/A-M/;
  109. #if ($hungarian)
  110. #{
  111. # $hungarian = $hungarian . '_';
  112. #}
  113. #return $PRIVATE . '(' . $hungarian . $readable . ',' . $namespace . $x . ')';
  114. #return $PRIVATE . '(' . $readable . ',' . $namespace . $x . ')';
  115. return $namespace . $x;
  116. }
  117. sub MakeHeaderPrivateName
  118. {
  119. my($header, $name) = ($_[0], $_[1]);
  120. $header = MakeTitlecase(BaseName($header));
  121. return ObscurePrivateName($header . 'IsolationAwarePrivate', $name);
  122. }
  123. sub MakeMultiHeaderPrivateName
  124. {
  125. my($name) = ($_[0]);
  126. return ObscurePrivateName('IsolationAwarePrivate', $name);
  127. }
  128. sub MakePublicName
  129. {
  130. # IsolationAwareFoo
  131. my($name) = ($_[0]);
  132. return "IsolationAware" . $name;
  133. }
  134. use Class::Struct;
  135. use IO::File;
  136. #
  137. # If ENV{_NTDRIVE} or ENV{_NTROOT} not defined, look here.
  138. #
  139. %NtDriveRootDefaults =
  140. (
  141. "jaykrell" =>
  142. {
  143. "_NTDRIVE" => "f:",
  144. "_NTROOT" => "\\jaykrell"
  145. },
  146. "default" =>
  147. {
  148. "_NTDRIVE" => "z:",
  149. "_NTROOT" => "\\nt"
  150. }
  151. );
  152. sub Indent
  153. {
  154. return $_[0] . " ";
  155. }
  156. sub Outdent
  157. {
  158. return substr($_[0], 4);
  159. }
  160. #
  161. # for Perl embedded in headers, stick data in global hashtables, but hide
  162. # the Perl syntax in what looks like C function calls.
  163. #
  164. sub DeclareFunctionErrorValue
  165. {
  166. my($function,$errorValue) = ($_[0], $_[1]);
  167. $FunctionErrorValue{$function} = MakeStringTrue($errorValue);
  168. #print($function . " error value is " . $errorValue . "\n");
  169. }
  170. sub DelayLoad { $DelayLoad{$_[0]} = 1; }
  171. sub MapHeaderToDll { $MapHeaderToDll{RemoveExtension(MakeLower($_[0]))} = MakeLower($_[1]); }
  172. sub ActivateAroundDelayLoad { DelayLoad($_[0], $_[1]); $ActivateAroundDelayLoad{$_[0]} = 1; }
  173. sub ActivateAroundFunctionCall { $ActivateAroundFunctionCall{$_[0]} = 1; }
  174. sub NoActivateAroundFunctionCall {$NoActivateAroundFunctionCall{$_[0]} = 1;}
  175. sub ActivateNULLAroundFunctionCall { $ActivateNULLAroundFunctionCall{$_[0]} = 1; }
  176. sub NoMacro { $NoMacro{$_[0]} = 1; }
  177. sub DeclareExportName32 { $ExportName32{$_[0]} = $_[1]; }
  178. sub DeclareExportName64 { $ExportName64{$_[0]} = $_[1]; }
  179. sub Undef { $Undef{$_[0]} = 1; }
  180. sub PoundIf { $PoundIfCondition{$_[0]} = $_[1]; }
  181. #
  182. # for Perl on the command line
  183. #
  184. sub SetStubsFile
  185. {
  186. $StubsFile = $_[0];
  187. #print("StubsFile is " . $StubsFile . "\n");
  188. }
  189. sub LeafPath
  190. {
  191. my($x) = ($_[0]);
  192. my($y)= $x;
  193. if ($y =~ /\\/)
  194. {
  195. ($y) = ($x =~ /.*\\(.+)/);
  196. }
  197. #print("leaf path of $x is $y\n");
  198. return $y;
  199. }
  200. sub BaseName
  201. {
  202. my($x) = ($_[0]);
  203. $x = LeafPath($x);
  204. if ($x =~ /\./)
  205. {
  206. $x =~ s/^(.*)\..*$/$1/;
  207. }
  208. return $x;
  209. }
  210. sub RemoveExtension { return BaseName($_[0]); }
  211. sub GetNtDriveOrRoot
  212. {
  213. my($name) = ($_[0]);
  214. my($x);
  215. $x = $ENV{$name};
  216. if ($x)
  217. {
  218. return $x;
  219. }
  220. $x = $NtDriveRootDefaults{MakeLower($ENV{"COMPUTERNAME"})}
  221. || $NtDriveRootDefaults{MakeLower($ENV{"USERNAME"})}
  222. || $NtDriveRootDefaults{$ENV{"default"}};
  223. return $x{$name};
  224. }
  225. sub GetNtDrive
  226. {
  227. return GetNtDriveOrRoot("_NTDRIVE");
  228. };
  229. sub GetNtRoot
  230. {
  231. return GetNtDriveOrRoot("_NTROOT");
  232. };
  233. struct Function => # I don't know what syntax is in play here, just following an example..
  234. {
  235. name => '$',
  236. ret => '$',
  237. retname => '$', # just for Hungarian purposes
  238. # for more sophisticated processing, these should be arrays or hashes, and we wouldn't have
  239. # both, but all we ever do is print these flat strings
  240. argsTypesNames => '$',
  241. argsNames => '$',
  242. error => '$', # eg NULL, 0, -1, FALSE
  243. dll => '$', # eg: kernel32.dll, comctl32.dll
  244. header => '$', # eg: winuser, commctrl
  245. delayload => '$', # boolean
  246. };
  247. #
  248. # Headers have versions of GetProcAddress where the .dll is implied.
  249. # This generates a call to such a GetProcAddress wrapper.
  250. #
  251. sub GenerateGetProcAddressCall
  252. {
  253. my($header, $dll, $function) = ($_[0], $_[1], $_[2]);
  254. my($x);
  255. $dll = MakeTitlecase($dll);
  256. $x .= MakeHeaderPrivateName($header, 'GetProcAddress_' . ToIdentifier($dll));
  257. $x .= '("' . $function . '")';
  258. return $x;
  259. }
  260. $code = '';
  261. $WinbaseSpecialCode1='
  262. BOOL WINAPI ' . MakeMultiHeaderPrivateName("ActivateMyActCtx") . '(ULONG_PTR* pulpCookie);
  263. /*
  264. These are private.
  265. */
  266. __declspec(selectany) HANDLE ' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ' = INVALID_HANDLE_VALUE;
  267. __declspec(selectany) BOOL ' . MakeMultiHeaderPrivateName('g_fDownlevel') . ' = FALSE;
  268. __declspec(selectany) BOOL ' . MakeHeaderPrivateName('winbase.h', 'g_fCreatedActCtx') . ' = FALSE;
  269. __declspec(selectany) BOOL ' . MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled') . ' = FALSE;
  270. ';
  271. $WinbaseSpecialCode2='
  272. FORCEINLINE
  273. HMODULE
  274. WINAPI
  275. ' . MakeHeaderPrivateName("winbase.h", 'GetModuleHandle_Kernel32_dll') . '(
  276. )
  277. {
  278. HMODULE hKernel32 = GetModuleHandleW(L"Kernel32.dll");
  279. if (hKernel32 == NULL
  280. && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
  281. )
  282. hKernel32 = GetModuleHandleA("Kernel32.dll");
  283. return hKernel32;
  284. }
  285. #define WINBASE_NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
  286. '
  287. . '
  288. ' . $INLINE . ' BOOL WINAPI ' . MakeHeaderPrivateName("winbase.h", "GetMyActCtx") . ' (void)
  289. /*
  290. The correctness of this function depends on it being statically
  291. linked into its clients.
  292. This function is private to functions present in this header.
  293. Do not use it.
  294. */
  295. {
  296. BOOL fResult = FALSE;
  297. ACTIVATION_CONTEXT_BASIC_INFORMATION actCtxBasicInfo;
  298. ULONG_PTR ulpCookie = 0;
  299. if (' . MakeMultiHeaderPrivateName('g_fDownlevel') . ')
  300. {
  301. fResult = TRUE;
  302. goto Exit;
  303. }
  304. if (' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ' != INVALID_HANDLE_VALUE)
  305. {
  306. fResult = TRUE;
  307. goto Exit;
  308. }
  309. if (!' . MakePublicName('QueryActCtxW') . '(
  310. QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS
  311. | QUERY_ACTCTX_FLAG_NO_ADDREF,
  312. &' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ',
  313. NULL,
  314. ActivationContextBasicInformation,
  315. &actCtxBasicInfo,
  316. sizeof(actCtxBasicInfo),
  317. NULL
  318. ))
  319. goto Exit;
  320. /*
  321. If QueryActCtxW returns NULL, try CreateActCtx(3).
  322. */
  323. if (actCtxBasicInfo.hActCtx == NULL)
  324. {
  325. ACTCTXW actCtx;
  326. WCHAR rgchFullModulePath[MAX_PATH + 2];
  327. DWORD dw;
  328. HMODULE hmodSelf;
  329. PGET_MODULE_HANDLE_EXW pfnGetModuleHandleExW;
  330. pfnGetModuleHandleExW = (PGET_MODULE_HANDLE_EXW)' . GenerateGetProcAddressCall('winbase.h', 'kernel32.dll', 'GetModuleHandleExW') . ';
  331. if (pfnGetModuleHandleExW == NULL)
  332. goto Exit;
  333. if (!(*pfnGetModuleHandleExW)(
  334. GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
  335. | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
  336. (LPCWSTR)&' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ',
  337. &hmodSelf
  338. ))
  339. goto Exit;
  340. rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 1] = 0;
  341. rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] = 0;
  342. dw = GetModuleFileNameW(hmodSelf, rgchFullModulePath, WINBASE_NUMBER_OF(rgchFullModulePath));
  343. if (dw == 0)
  344. goto Exit;
  345. if (rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] != 0)
  346. {
  347. SetLastError(ERROR_BUFFER_OVERFLOW);
  348. goto Exit;
  349. }
  350. actCtx.cbSize = sizeof(actCtx);
  351. actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
  352. actCtx.lpSource = rgchFullModulePath;
  353. actCtx.lpResourceName = (LPCWSTR)(ULONG_PTR)3;
  354. actCtx.hModule = hmodSelf;
  355. actCtxBasicInfo.hActCtx = ' . MakePublicName('CreateActCtxW') . '(&actCtx);
  356. if (actCtxBasicInfo.hActCtx == INVALID_HANDLE_VALUE)
  357. {
  358. const DWORD dwLastError = GetLastError();
  359. if ((dwLastError != ERROR_RESOURCE_DATA_NOT_FOUND) &&
  360. (dwLastError != ERROR_RESOURCE_TYPE_NOT_FOUND) &&
  361. (dwLastError != ERROR_RESOURCE_LANG_NOT_FOUND) &&
  362. (dwLastError != ERROR_RESOURCE_NAME_NOT_FOUND))
  363. goto Exit;
  364. actCtxBasicInfo.hActCtx = NULL;
  365. }
  366. ' . MakeHeaderPrivateName('winbase.h', 'g_fCreatedActCtx') . ' = TRUE;
  367. }
  368. ' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ' = actCtxBasicInfo.hActCtx;
  369. #define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2)
  370. if (' . MakePublicName('ActivateActCtx') . '(actCtxBasicInfo.hActCtx, &ulpCookie))
  371. {
  372. __try
  373. {
  374. ACTCTX_SECTION_KEYED_DATA actCtxSectionKeyedData;
  375. actCtxSectionKeyedData.cbSize = sizeof(actCtxSectionKeyedData);
  376. if (' . MakePublicName("FindActCtxSectionStringW") . '(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"Comctl32.dll", &actCtxSectionKeyedData))
  377. {
  378. /* get button, edit, etc. registered */
  379. LoadLibraryW(L"Comctl32.dll");
  380. }
  381. }
  382. __finally
  383. {
  384. ' . MakePublicName('DeactivateActCtx') . '(0, ulpCookie);
  385. }
  386. }
  387. fResult = TRUE;
  388. Exit:
  389. return fResult;
  390. }
  391. ' . $INLINE . ' BOOL WINAPI ' . MakePublicName('Init') . '(void)
  392. /*
  393. The correctness of this function depends on it being statically
  394. linked into its clients.
  395. Call this from DllMain(DLL_PROCESS_ATTACH) if you use id 3 and wish to avoid a race condition that
  396. can cause an hActCtx leak.
  397. Call this from your .exe\'s initialization if you use id 3 and wish to avoid a race condition that
  398. can cause an hActCtx leak.
  399. If you use id 2, this function fetches data from your .dll
  400. that you do not need to worry about cleaning up.
  401. */
  402. {
  403. return ' . MakeHeaderPrivateName("winbase.h", "GetMyActCtx") . '();
  404. }
  405. ' . $INLINE . ' void WINAPI ' . MakePublicName('Cleanup') . '(void)
  406. /*
  407. Call this from DllMain(DLL_PROCESS_DETACH), if you use id 3, to avoid a leak.
  408. Call this from your .exe\'s cleanup to possibly avoid apparent (but not actual) leaks, if use id 3.
  409. This function does nothing, safely, if you use id 2.
  410. */
  411. {
  412. HANDLE hActCtx;
  413. if (' . MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled') . ')
  414. return;
  415. /* IsolationAware* calls made from here on out will OutputDebugString
  416. and use the process default activation context instead of id 3 or will
  417. continue to successfully use id 2 (but still OutputDebugString).
  418. */
  419. ' . MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled') . ' = TRUE;
  420. /* There is no cleanup to do if we did not CreateActCtx but only called QueryActCtx.
  421. */
  422. if (!' . MakeHeaderPrivateName('winbase.h', 'g_fCreatedActCtx') . ')
  423. return;
  424. hActCtx = ' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ';
  425. ' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ' = NULL; /* process default */
  426. if (hActCtx == INVALID_HANDLE_VALUE)
  427. return;
  428. if (hActCtx == NULL)
  429. return;
  430. IsolationAwareReleaseActCtx(hActCtx);
  431. }
  432. ' . $INLINE . ' BOOL WINAPI '
  433. . MakeMultiHeaderPrivateName("ActivateMyActCtx")
  434. . '(ULONG_PTR* pulpCookie)
  435. /*
  436. This function is private to functions present in this header and other headers.
  437. */
  438. {
  439. BOOL fResult = FALSE;
  440. if (' . MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled') . ')
  441. {
  442. const static char debugString[] = "IsolationAware function called after ' . MakePublicName('Cleanup') . '\\n";
  443. OutputDebugStringA(debugString);
  444. }
  445. if (' . MakeMultiHeaderPrivateName('g_fDownlevel') . ')
  446. {
  447. fResult = TRUE;
  448. goto Exit;
  449. }
  450. /* Do not call Init if Cleanup has been called. */
  451. if (!' . MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled') . ')
  452. {
  453. if (!' . MakeHeaderPrivateName('winbase.h', 'GetMyActCtx') . '())
  454. goto Exit;
  455. }
  456. /* If Cleanup has been called and id3 was in use, this will activate NULL. */
  457. if (!' . MakePublicName('ActivateActCtx') . '(' . MakeHeaderPrivateName('winbase.h', 'g_hActCtx') . ', pulpCookie))
  458. goto Exit;
  459. fResult = TRUE;
  460. Exit:
  461. if (!fResult)
  462. {
  463. const DWORD dwLastError = GetLastError();
  464. if (dwLastError == ERROR_PROC_NOT_FOUND
  465. || dwLastError == ERROR_CALL_NOT_IMPLEMENTED
  466. )
  467. {
  468. ' . MakeMultiHeaderPrivateName('g_fDownlevel') . ' = TRUE;
  469. fResult = TRUE;
  470. }
  471. }
  472. return fResult;
  473. }
  474. #undef WINBASE_NUMBER_OF
  475. '
  476. ;
  477. %MapHeaderToSpecialCode1 =
  478. (
  479. "winbase" => $WinbaseSpecialCode1,
  480. "winbase.h" => $WinbaseSpecialCode1,
  481. "Winbase" => $WinbaseSpecialCode1,
  482. "Winbase.h" => $WinbaseSpecialCode1,
  483. );
  484. %MapHeaderToSpecialCode2 =
  485. (
  486. "winbase" => $WinbaseSpecialCode2,
  487. "winbase.h" => $WinbaseSpecialCode2,
  488. "Winbase" => $WinbaseSpecialCode2,
  489. "Winbase.h" => $WinbaseSpecialCode2,
  490. );
  491. sub MakeStringTrue
  492. {
  493. ($_[0] eq "0") ? "0 " : $_[0];
  494. }
  495. %TypeErrorValue =
  496. (
  497. # Individual functions can override with a #!perl comment.
  498. # Functions that return an integer must specify. 0, -1, ~0 are too evenly split.
  499. # HANDLE must specify (NULL, INVALID_HANDLE..)
  500. "BOOL" => "FALSE",
  501. "bool" => "false",
  502. "PVOID" => "NULL",
  503. "HICON" => "NULL",
  504. "HIMAGELIST" => "NULL",
  505. "HWND" => "NULL",
  506. "COLORREF" => "RGB(0,0,0)",
  507. "HBITMAP" => "NULL",
  508. "LANGID" => "0",
  509. "ATOM" => "0",
  510. "HPROPSHEETPAGE" => "NULL",
  511. "HDSA" => "NULL",
  512. "HDPA" => "NULL",
  513. # HRESULTs are treated specially!
  514. "HRESULT" => "S_OK"
  515. );
  516. sub IndentMultiLineString
  517. {
  518. my ($indent, $string) = ($_[0], $_[1]);
  519. if ($string)
  520. {
  521. $string = join("\n" . $indent, split("\n", $string)). "\n";
  522. #$string =~ s/^(.)/$indent$1/gm;
  523. # unindent preprocessor directives
  524. $string =~ s/^$indent#/#/gms;
  525. }
  526. return $string;
  527. }
  528. # hack hack
  529. $ExitWin32ToHresult ='
  530. ExitWin32ToHresult:
  531. {
  532. DWORD dwLastError = GetLastError();
  533. if (dwLastError == NO_ERROR)
  534. dwLastError = ERROR_INTERNAL_ERROR;
  535. result = HRESULT_FROM_WIN32(dwLastError);
  536. return result;
  537. }
  538. ';
  539. %Hungarian =
  540. (
  541. # We default to empty.
  542. "BOOL" => "f",
  543. "int" => "n",
  544. "short" => "n",
  545. "long" => "n",
  546. "INT" => "n",
  547. "SHORT" => "n",
  548. "LONG" => "n",
  549. "UINT" => "n",
  550. "USHORT" => "n",
  551. "ULONG" => "n",
  552. "WORD" => "n",
  553. "DWORD" => "n",
  554. "INT_PTR" => "n",
  555. "LONG_PTR" => "n",
  556. "UINT_PTR" => "n",
  557. "ULONG_PTR" => "n",
  558. "DWORD_PTR" => "n",
  559. "HWND" => "window",
  560. "HRESULT" => "",
  561. "COLORREF" => "color",
  562. "HICON" => "icon",
  563. "PVOID" => "v",
  564. "HMODULE" => "module",
  565. "HINSTANCE" => "instance",
  566. "HBITMAP" => "bitmap",
  567. "LANGID" => "languageId",
  568. "HIMAGELIST" => "imagelist",
  569. );
  570. $headerName = MakeLower($ARGV[0]);
  571. #print("ARGV is " . join(" ", @ARGV) . "\n");
  572. @ARGV = reverse(@ARGV);
  573. pop(ARGV);
  574. @ARGV = reverse(@ARGV);
  575. #print("ARGV is " . join(" ", @ARGV) . "\n");
  576. #
  577. # The command line should say 'SetStubsFile('foo.sxs-stubs');'
  578. #
  579. eval(join("\n", @ARGV));
  580. if ($headerName =~ /\\/)
  581. {
  582. ($headerLeafName) = ($headerName =~ /.+\\(.+)/);
  583. $headerFullPath = $headerName;
  584. }
  585. else
  586. {
  587. $headerLeafName = $headerName;
  588. $headerFullPath = GetNtDrive() . GetNtRoot() . "\\public\\sdk\\inc\\" . $headerName;
  589. }
  590. #print($headerFullPath);
  591. open(headerFileHandle, "< " . $headerFullPath) || die;
  592. #
  593. # extract out the executable code
  594. # @ single line @
  595. #
  596. # $code .= "/* " . $headerFullPath . " */\n\n";
  597. # read all the lines into one string
  598. $file = join("", <headerFileHandle>);
  599. # if it doesn't contain any embedded Perl, then we are a no-op, just spit it out
  600. # This way we can run over all files, makes it easier to edit shell\published\makefile.inc.
  601. if ($file !~ /#!perl/ms)
  602. {
  603. print($file);
  604. exit;
  605. }
  606. # remove stuff that doesn't mean much
  607. $file =~ s/\bWINAPIV\b/ /g;
  608. $file =~ s/\bWINAPI\b/ /g;
  609. $file =~ s/\b__stdcall\b/ /g;
  610. $file =~ s/\b_stdcall\b/ /g;
  611. $file =~ s/\b__cdecl\b/ /g;
  612. $file =~ s/\b_cdecl\b/ /g;
  613. $file =~ s/\b__fastcall\b //g;
  614. $file =~ s/\b_fastcall\b/ /g;
  615. $file =~ s/\bCALLBACK\b/ /g;
  616. $file =~ s/\bPASCAL\b/ /g;
  617. $file =~ s/\bAPIENTRY\b/ /g;
  618. $file =~ s/\bFAR\b/ /g;
  619. $file =~ s/\bNEAR\b/ /g;
  620. $file =~ s/\bvolatile\b/ /g;
  621. $file =~ s/\bIN\b/ /g;
  622. $file =~ s/\bOUT\b/ /g;
  623. $file =~ s/\bDECLSPEC_NORETURN\b/ /g;
  624. $file =~ s/\bOPTIONAL\b/ /g;
  625. # honor backslash line continuations, before removing preprocessor directives
  626. $file =~ s/\\\n//gms;
  627. # execute perl code embedded in comments
  628. # quadratic behavior where we keep searching for the string, remove, search, remove..
  629. # without remembering where the previous find was
  630. while ($file =~ s/\/\* ?#!perl(.*?)\*\///ms)
  631. {
  632. $_ = $1;
  633. # C++ comments in the Perl comment are removed
  634. s/\/\/.*?$//gms; # support C++ comments within the #!perl C comment.
  635. # something resembling C comment close is restored
  636. # escape-o-rama..
  637. s/\* \//\*\//gms;
  638. eval;
  639. #print;
  640. }
  641. #print($file);
  642. #exit();
  643. # remove comments, before removing preprocessor directives
  644. $file =~ s/\/\*.*?\*\//\n/gms;
  645. $file =~ s/\/\/.*?$//gms;
  646. #print($file);
  647. #exit();
  648. # remove preprocessor directives
  649. # must do this before we make one statement per line in pursuit
  650. # of an easy typedef/struct removal
  651. $file =~ s/^[ \t]*#.*$//gm;
  652. # remove FORCEINLINE functions, assuming they don't contain any braces..
  653. $file =~ s/FORCEINLINE.+?}//gms;
  654. # remove extern C open and close
  655. # must do this before we make one statement per line in pursuit
  656. # of an easy typedef/struct removal
  657. $file =~ s/\bextern\b \"C\" {$//gm;
  658. $file =~ s/^}$//gm;
  659. #
  660. # cleanup commdlg.h
  661. #
  662. # remove Afx blah
  663. $file =~ s/^.*Afx.*$//gm;
  664. # remove IID blah
  665. $file =~ s/^.*DEFINE_GUID.*$//gm;
  666. # remove IPrintDialogCallback
  667. $file =~ s/DECLARE_INTERFACE_.+?};//gs;
  668. #
  669. # futz with whitespace (has to do with having removed comments from within structs)
  670. # we do this more later
  671. #
  672. $file =~ s/[ \t\n]+/ /g;
  673. # remove typedefs and structs, this is extremely sloppy and fragile
  674. # .. we fold statements to be single lines, and then only keep statements that have parens,
  675. # and then remove single line typedefs and structs as well
  676. # .. avoiding counting braces ..
  677. $file =~ s/\n/ /gms; # remove all newlines
  678. $file =~ s/;/;\n/gms; # each statement on its own line (also struct fields on their own line)
  679. $file =~ s/^[^()]+$//gm; # only keep statements with parens
  680. #
  681. # types with parens that don't have typedefs will defeat the above, for example:
  682. # struct foo {
  683. # void (*bar)(void);
  684. # };
  685. #
  686. # Still, just by requiring a leading "WIN" on function declarations, we can live with structs and
  687. # typedefs in the file.
  688. #
  689. $file =~ s/^ +//gm; # remove spaces at start of line
  690. $file =~ s/^typedef\b.+;$//gm; # remove typedefs (they're probably already gone)
  691. $file =~ s/^struct\b.+;$//gm; # remove structs (they're probably already gone)
  692. $file =~ s/\n+/\n/g; # remove empty lines
  693. #print $file;
  694. #exit;
  695. $file =~ s/^.+\.\.\..+$//gm; # remove vararg functions
  696. # format as one function declaration per line, no empty lines (some of this is redundant
  697. # given how we now remove typedefs and structs)
  698. $file =~ s/[ \t\n]+/ /g;
  699. $file =~ s/;/;\n/g;
  700. $file =~ s/^.+?\bWinMain\b.+?$//gm; # WinMain looks wierd due to #ifdef _MAC. Remove it.
  701. $file =~ s/\n+/\n/g; # remove empty lines (again)
  702. $file =~ s/^ +//gm; # remove spaces at line starts (again)
  703. $file =~ s/\A\n+//g; # remove newline from very start of file
  704. # more simplications, more whitespace, fewer other characters
  705. $file =~ s/\);$//gm; # get rid of trailing semi and rparen
  706. #$file =~ s/\(/ \(/g; # make sure whitespace precedes lparens, to set them off from function name
  707. $file =~ s/\*/ \* /g; # make sure stars are whitespace delimited
  708. $file =~ s/\( +/\(/g; # remove whitespace after lparen
  709. $file =~ s/\bWINBASEAPI\b/ /g;
  710. $file =~ s/\bWINADVAPI\b/ /g;
  711. $file =~ s/\bWINUSERAPI\b/ /g;
  712. $file =~ s/\bWINCOMMCTRLAPI\b/ /g;
  713. $file =~ s/\bWINGDIAPI\b/ /g;
  714. $file =~ s/\bWINCOMMDLGAPI\b/ /g;
  715. $file =~ s/\bWIN[A-Z]+API\b/ /g;
  716. $file =~ s/^ +//gm; # remove whitespace at start of lines
  717. # normalize what empty parameter lists look like between (VOID) and (void)
  718. # leave PVOID and LPVOID alone (\b for word break)
  719. # lowercase others while we're at it
  720. $file =~ s/\b(VOID|CONST|INT|LONG|SHORT)\b/\L$1\E/g;
  721. $file =~ s/\($/\(void/gm; # change the occasional C++ form (this is broken if compiling for C) to the C form
  722. # yet more whitespace cleanup
  723. #$file =~ s/ *(,|\*) */$1/g; # remove whitespace around commas and stars
  724. $file =~ s/ *, */,/g; # remove whitespace around commas
  725. $file =~ s/^ +//gm; # remove spaces at start of line
  726. $file =~ s/ +$//gm; # remove spaces at end of line
  727. $file =~ s/ +/ /g; # runs of spaces to single spaces
  728. if (0)
  729. {
  730. print $file;
  731. exit;
  732. }
  733. foreach $line (split("\n", $file))
  734. {
  735. $unnamed_counter = 1;
  736. # split off return type and name at first lparen
  737. #($retname, $args) = ($line =~ /WIN[A-Z]+ ([^(]+)\((.+)/);
  738. ($retname, $args) = ($line =~ /([^(]+)\((.+)/);
  739. # split off name as last space delimited from return type and name,
  740. # allowing return type to be multiple tokens
  741. ($ret, $name) = ($retname =~ /(.*) ([^ ]+)/);
  742. $args =~ s/^ +//g; # cleanup whitespace (again)
  743. $args =~ s/ +$//g; # cleanup whitespace (again!)
  744. $args =~ s/ +/ /g; # cleanup whitespace (again!!)
  745. #
  746. # now split up args, split their name from their type, and provide names for unnamed ones
  747. # and note if they are void
  748. # the key is to generate the two strings, argNamesAndTypes and argNames
  749. #
  750. # unnamed parameters are parameters that either
  751. # have only one token
  752. # or whose last token is a star
  753. # we don't handle C++ references or "untypedefed structs passed by value" like "void F(struct G);"
  754. # or inline defined structs "void F(struct G { int i; });"
  755. #
  756. $argNames = "";
  757. if ($args !~ /^void$/)
  758. {
  759. $args2 = "";
  760. foreach $arg (split(/,/, $args))
  761. {
  762. $args2 .= $arg;
  763. if ($arg =~ /^ *\w+ *$/)
  764. {
  765. $argName = "unnamed" . $unnamed_counter++;
  766. $argNames .= $argName;
  767. $args2 .= " " . $argName;
  768. }
  769. # If a parameter ends with a star, it is unnamed.
  770. elsif ($arg =~ /\* *$/)
  771. {
  772. $argName = "unnamed" . $unnamed_counter++;
  773. $argNames .= $argName;
  774. $args2 .= " " . $argName;
  775. }
  776. else
  777. {
  778. ($argName) = ($arg =~ /(\w+)$/);
  779. $argNames .= $argName;
  780. }
  781. $args2 .= ",";
  782. $argNames .= ",";
  783. }
  784. $args = $args2;
  785. }
  786. $args =~ s/ *\* */\*/g;
  787. $args =~ s/, *$//g;
  788. $argNames =~ s/, *$//g;
  789. $args =~ s/ *, */,/g;
  790. $argNames =~ s/ *, */,/g;
  791. $dll = $MapHeaderToDll{RemoveExtension($headerLeafName)};
  792. if ( $DelayLoad{$dll}
  793. || $DelayLoad{$name}
  794. || ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
  795. || $ActivateAroundFunctionCall{$name}
  796. || $ActivateNULLAroundFunctionCall{$name}
  797. )
  798. {
  799. $function = Function->new();
  800. $function->ret($ret);
  801. $function->name($name);
  802. $function->argsTypesNames("(". $args . ")");
  803. $function->argsNames("(". $argNames . ")");
  804. $error = MakeStringTrue($FunctionErrorValue{$name});
  805. if (!$error)
  806. {
  807. $error = MakeStringTrue($TypeErrorValue{$ret});
  808. }
  809. if (!$error && $ret ne "void")
  810. {
  811. print($ErrorMessagePrefix . "don't know know error value for " . $ret . " " . $name . "\n");
  812. exit;
  813. #$error = "((" . $ret . ")0)";
  814. }
  815. $function->error($error);
  816. $retname = $Hungarian{$ret};
  817. if (!$retname)
  818. {
  819. $retname = "result";
  820. }
  821. else
  822. {
  823. $retname .= "Result";
  824. }
  825. $function->retname($retname);
  826. $function->dll($dll);
  827. $function->header(RemoveExtension(MakeLower($headerLeafName)) . ".h");
  828. if ($DelayLoad{$dll} || $DelayLoad{$name})
  829. {
  830. $function->delayload($true);
  831. }
  832. push(@functions, ($function));
  833. #print("pushed " . $name . "\n");
  834. }
  835. else
  836. {
  837. #print("didn"t push " . $name . "(" . $dll . ")\n");
  838. }
  839. }
  840. sub InsertCodeIntoFile
  841. {
  842. my($code, $filePath) = ($_[0], $_[1]);
  843. my($fileContents, $fileHandle);
  844. my($stubsFileHandle);
  845. my($yearnow);
  846. $fileHandle = new IO::File($filePath, "r");
  847. $fileContents = join("", $fileHandle->getlines());
  848. #
  849. # We have decided to sometimes use an #include in order to not be so large.
  850. #
  851. # Remove the executable perl code.
  852. $fileContents =~ s/\/\* ?#!perl.*?\*\///msg;
  853. if ($StubsFile)
  854. {
  855. #print("StubsFile is $StubsFile\n");
  856. $stubsFileHandle = new IO::File($StubsFile, "w");
  857. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
  858. my ($firstyear) = 2001;
  859. $year += 1900;
  860. if ($year == $firstyear)
  861. {
  862. $stubsFileHandle->print("/* Copyright (c) " . $firstyear . " Microsoft Corp. All rights reserved. */\n");
  863. }
  864. else
  865. {
  866. $stubsFileHandle->print("/* Copyright (c) " . $firstyear . "-" . $year .", Microsoft Corp. All rights reserved. */\n");
  867. }
  868. #$stubsFileHandle->print("/* This file generated " . localtime() . " */\n");
  869. $stubsFileHandle->print("\n");
  870. $stubsFileHandle->print("#if _MSC_VER > 1000\n");
  871. $stubsFileHandle->print("#pragma once\n");
  872. $stubsFileHandle->print("#endif\n");
  873. $stubsFileHandle->print("\n");
  874. $stubsFileHandle->print("#if defined(__cplusplus)\n");
  875. $stubsFileHandle->print("extern \"C\" {\n");
  876. $stubsFileHandle->print("#endif\n\n");
  877. $stubsFileHandle->print($code);
  878. $stubsFileHandle->print("\n#if defined(__cplusplus)\n");
  879. $stubsFileHandle->print("} /* __cplusplus */\n");
  880. $stubsFileHandle->print("#endif\n");
  881. # generate the include, within #if
  882. $code = "";
  883. $code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
  884. $code .= "#if " . MakePublicPreprocessorSymbol("ENABLED") . "\n";
  885. $code .= "#include \"" . LeafPath($StubsFile) . "\"\n";
  886. $code .= "#endif /* " . MakePublicPreprocessorSymbol("ENABLED") . " */\n";
  887. $code .= "#endif /* RC */";
  888. }
  889. #
  890. # put the #include or the code into the the file
  891. #
  892. # The #include or the code goes before the last
  893. # occurence of #ifdef __cplusplus or #if defined(__cplusplus.
  894. #
  895. $fileContents =~ s/(.+)(#if[defined( \t]+__cplusplus.*?$})/$1\n\n$code\n\n$2/ms;
  896. return $fileContents;
  897. };
  898. sub GenerateHeaderCommon1
  899. {
  900. my($function) = ($_[0]);
  901. my($x, $dll, $dllid, $header);
  902. #print("2\n");
  903. $dll = MakeLower($function->dll());
  904. $dllid = MakeTitlecase(ToIdentifier($dll));
  905. $header = MakeLower(BaseName($function->header())) . ".h";
  906. $x .= '
  907. #if !defined(' . $INLINE . ')
  908. #if defined(__cplusplus)
  909. #define ' . $INLINE . ' inline
  910. #else
  911. #define ' . $INLINE . ' __inline
  912. #endif
  913. #endif
  914. ';
  915. $x .= $MapHeaderToSpecialCode1{$header};
  916. $x .= "FARPROC WINAPI ";
  917. $x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
  918. $x .= "(LPCSTR pszProcName);\n\n";
  919. $x .= $SpecialChunksOfCode{$header};
  920. return $x;
  921. }
  922. sub GenerateHeaderCommon2
  923. {
  924. my($function) = ($_[0]);
  925. my($x);
  926. my($dll);
  927. my($LoadLibrary);
  928. my($indent);
  929. my($exit);
  930. my($dllid);
  931. my($activate);
  932. my($header);
  933. $LoadLibrary = "LoadLibrary"; # or GetModuleHandle
  934. $dll = MakeLower($function->dll());
  935. $dllid = ToIdentifier(MakeTitlecase($dll));
  936. $indent = "";
  937. $activate = $ActivateAroundDelayLoad{$dll};
  938. $header = MakeLower(LeafPath($function->header()));
  939. #print("header is " . $header . "\n");
  940. $x .= $MapHeaderToSpecialCode2{$header};
  941. $x .= $INLINE . " FARPROC WINAPI ";
  942. $x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
  943. $x .= "(LPCSTR pszProcName)\n";
  944. $x .= "/* This function is shared by the other stubs in this header. */\n";
  945. $x .= "{\n";
  946. $indent = Indent($indent);
  947. $x .= $indent . "FARPROC proc = NULL;\n";
  948. $x .= $indent . "static HMODULE s_module;\n";
  949. $exit = "return proc;\n";
  950. if ($activate)
  951. {
  952. $x .= $indent . "BOOL fActivateActCtxSuccess = FALSE;\n";
  953. $x .= $indent . "ULONG_PTR ulpCookie = 0;\n";
  954. }
  955. if ($activate)
  956. {
  957. $x .= $indent . "__try\n";
  958. $x .= $indent . "{\n";
  959. $indent = Indent($indent);
  960. $exit = "__leave;\n";
  961. }
  962. $x .= $indent . "if (s_module == NULL)\n";
  963. $x .= $indent . "{\n";
  964. $indent = Indent($indent);
  965. if ($activate)
  966. {
  967. $x .= $indent . "if (!" . MakeMultiHeaderPrivateName('g_fDownlevel') . ")\n";
  968. $x .= $indent . "{\n";
  969. $indent = Indent($indent);
  970. $x .= $indent . "fActivateActCtxSuccess = ";
  971. $x .= MakeMultiHeaderPrivateName("ActivateMyActCtx");
  972. $x .= "(&ulpCookie);\n";
  973. $x .= $indent . "if (!fActivateActCtxSuccess)\n";
  974. $x .= $indent . " $exit";
  975. $indent = Outdent($indent);
  976. $x .= $indent . "}\n";
  977. }
  978. #
  979. # Depending on other factors, we might have a static ref to user32.dll,
  980. # in which case a GetModuleHandle is ok, but to be safe, LoadLibrary it.
  981. #
  982. if ($dll eq "kernel32.dll")
  983. {
  984. $x .= $indent . "s_module = " . MakeHeaderPrivateName("winbase.h", "GetModuleHandle_Kernel32_dll") . "();\n";
  985. $x .= $indent . "if (s_module == NULL)\n";
  986. $x .= $indent . " " . $exit;
  987. }
  988. else
  989. {
  990. $x .= $indent . "s_module = " . $LoadLibrary . "W(L\"" . MakeTitlecase($function->dll()) . "\");\n";
  991. $x .= $indent . "if (s_module == NULL)\n";
  992. $x .= $indent . "{\n";
  993. $indent = Indent($indent);
  994. $x .= $indent . "if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)\n";
  995. $x .= $indent . " " . $exit;
  996. $x .= $indent . "s_module = " . $LoadLibrary . "A(\"" . MakeTitlecase($function->dll()) . "\");\n";
  997. $x .= $indent . "if (s_module == NULL)\n";
  998. $x .= $indent . " " . $exit;
  999. $indent = Outdent($indent);
  1000. $x .= $indent . "}\n";
  1001. }
  1002. $indent = Outdent($indent);
  1003. $x .= $indent . "}\n";
  1004. $x .= $indent . "proc = GetProcAddress(s_module, pszProcName);\n";
  1005. if ($activate)
  1006. {
  1007. $indent = Outdent($indent);
  1008. $x .= $indent . "}\n";
  1009. $x .= $indent . "__finally\n";
  1010. $x .= $indent . "{\n";
  1011. $indent = Indent($indent);
  1012. $x .= $indent . "if (!" . MakeMultiHeaderPrivateName('g_fDownlevel') . " && fActivateActCtxSuccess)\n";
  1013. $x .= $indent . "{\n";
  1014. $indent = Indent($indent);
  1015. $x .= $indent . "const DWORD dwLastError = (proc == NULL) ? GetLastError() : NO_ERROR;\n";
  1016. $x .= $indent . "(void)" . MakePublicName("DeactivateActCtx") . "(0, ulpCookie);\n";
  1017. $x .= $indent . "if (proc == NULL)\n";
  1018. $x .= $indent . " SetLastError(dwLastError);\n";
  1019. $indent = Outdent($indent);
  1020. $x .= $indent . "}\n";
  1021. $indent = Outdent($indent);
  1022. $x .= $indent . "}\n";
  1023. }
  1024. $x .= $indent . "return proc;\n";
  1025. $indent = Outdent($indent);
  1026. $x .= "}\n\n";
  1027. return $x;
  1028. }
  1029. sub GeneratePrototype
  1030. {
  1031. my($function) = ($_[0]);
  1032. my($proto);
  1033. $proto .= $function->ret() . " WINAPI ";
  1034. $proto .= MakePublicName($function->name());
  1035. $proto .= $function->argsTypesNames() . ";\n";
  1036. return $proto;
  1037. }
  1038. sub GenerateStub
  1039. {
  1040. my($function) = ($_[0]);
  1041. my($activate);
  1042. my($delayload);
  1043. my($stub);
  1044. my($exit);
  1045. my($indent);
  1046. my($name);
  1047. my($dll);
  1048. my($ret);
  1049. my($retname);
  1050. $name = $function->name();
  1051. $dll = $function->dll();
  1052. $dllid = MakeTitlecase(ToIdentifier($dll));
  1053. $ret = $function->ret();
  1054. $retname = $function->retname();
  1055. $indent = "";
  1056. $stub = "";
  1057. $activate = $ActivateAroundFunctionCall{$name} || ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
  1058. || $ActivateNULLAroundFunctionCall{$name};
  1059. $delayload = $DelayLoad{$name} || $DelayLoad{$dll};
  1060. if ($function->ret() eq "HRESULT")
  1061. {
  1062. $exit = "goto ExitWin32ToHresult;\n";
  1063. }
  1064. elsif ($ret eq "void")
  1065. {
  1066. $exit = "return;\n";
  1067. }
  1068. else
  1069. {
  1070. $exit = "return " . $function->retname() . ";\n";
  1071. }
  1072. # "prototype"
  1073. $stub .= $INLINE . " " . $ret . " WINAPI ";
  1074. $stub .= MakePublicName($function->name());
  1075. $stub .= $function->argsTypesNames() . "\n";
  1076. $stub .= $indent . "{\n";
  1077. $indent = Indent($indent);
  1078. # locals
  1079. if ($ret ne "void")
  1080. {
  1081. $stub .= $indent . $ret . " " . $function->retname() . " = " . $function->error() . ";\n";
  1082. }
  1083. if ($delayload)
  1084. {
  1085. $stub .= $indent . "typedef " . $ret . " (WINAPI* PFN)" . $function->argsTypesNames() . ";\n";
  1086. $stub .= $indent . "static PFN s_pfn;\n";
  1087. }
  1088. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"locals"});
  1089. if ($activate)
  1090. {
  1091. $stub .= $indent . "ULONG_PTR ulpCookie = 0;\n";
  1092. $stub .= $indent . "const BOOL fActivateActCtxSuccess = " . MakeMultiHeaderPrivateName('g_fDownlevel') . " || ";
  1093. }
  1094. # code (partly merged with local sometimes ("initialization" in the strict C++ terminology sense)
  1095. if ($activate)
  1096. {
  1097. if ($ActivateNULLAroundFunctionCall{$function->name()})
  1098. {
  1099. $stub .= MakePublicName("ActivateActCtx");
  1100. $stub .= "(NULL, &ulpCookie);\n";
  1101. }
  1102. else
  1103. {
  1104. $stub .= MakeMultiHeaderPrivateName("ActivateMyActCtx");
  1105. $stub .= "(&ulpCookie);\n";
  1106. }
  1107. $stub .= $indent . "if (!fActivateActCtxSuccess)\n";
  1108. $stub .= $indent . " $exit";
  1109. $stub .= $indent . "__try\n";
  1110. $stub .= $indent . "{\n";
  1111. $indent = Indent($indent);
  1112. if ($ret ne "HRESULT")
  1113. {
  1114. $exit = "__leave;\n";
  1115. }
  1116. }
  1117. if ($delayload)
  1118. {
  1119. $stub .= $indent . "if (s_pfn == NULL)\n";
  1120. $stub .= $indent . "{\n";
  1121. $indent = Indent($indent);
  1122. $stub .= $indent . "s_pfn = (PFN)";
  1123. $stub .= MakeHeaderPrivateName($function->header(), "GetProcAddress_$dllid");
  1124. $stub .= "(";
  1125. if ($ExportName32{$name} || $ExportName64{$name})
  1126. {
  1127. if (!$ExportName32{$name})
  1128. {
  1129. $ExportName32{$name} = $name;
  1130. }
  1131. if (!$ExportName64{$name})
  1132. {
  1133. $ExportName64{$name} = $name;
  1134. }
  1135. $stub .= "\n#if defined(_WIN64)\n";
  1136. $stub .= $indent . "\"" . $ExportName64{$name} . "\"\n";
  1137. $stub .= "#else\n";
  1138. $stub .= $indent . "\"" . $ExportName32{$name} . "\"\n";
  1139. $stub .= "#endif\n";
  1140. $stub .= $indent;
  1141. }
  1142. else
  1143. {
  1144. $stub .= "\"" . $name . "\"";
  1145. }
  1146. $stub .= ");\n";
  1147. $stub .= $indent . "if (s_pfn == NULL)\n";
  1148. $stub .= $indent . " $exit";
  1149. $indent = Outdent($indent);
  1150. $stub .= $indent . "}\n";
  1151. }
  1152. if ($SpecialChunksOfCode{$function->name()}{"body"})
  1153. {
  1154. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"body"});
  1155. }
  1156. else
  1157. {
  1158. $stub .= $indent;
  1159. if ($ret ne "void")
  1160. {
  1161. $stub .= $function->retname() . " = ";
  1162. }
  1163. if ($delayload)
  1164. {
  1165. $stub .= "s_pfn";
  1166. }
  1167. else
  1168. {
  1169. $stub .= $function->name();
  1170. }
  1171. $stub .= $function->argsNames();
  1172. $stub .= ";\n";
  1173. }
  1174. if ($activate)
  1175. {
  1176. #
  1177. # We cannot propagate the error from DeactivateActCtx.
  1178. # 1) DeactivateActCtx only fails with INVALID_PARAMETER.
  1179. # 2) How to generally cleanup the result, like of CreateWindow?
  1180. #
  1181. $indent = Outdent($indent);
  1182. $stub .= $indent . "}\n";
  1183. $stub .= $indent . "__finally\n";
  1184. $stub .= $indent . "{\n";
  1185. $indent = Indent($indent);
  1186. $stub .= $indent . "if (!" . MakeMultiHeaderPrivateName('g_fDownlevel') . ")\n";
  1187. $stub .= $indent . "{\n";
  1188. $indent = Indent($indent);
  1189. $maybePreserveError = 0;
  1190. if ($ret ne "void" && $ret ne "HRESULT")
  1191. {
  1192. $maybePreserveError = 1;
  1193. $stub .= $indent . "const BOOL fPreserveLastError = (" . $retname . " == " . $function->error() . ");\n";
  1194. $stub .= $indent . "const DWORD dwLastError = fPreserveLastError ? GetLastError() : NO_ERROR;\n";
  1195. }
  1196. else
  1197. {
  1198. # nothing;
  1199. }
  1200. $stub .= $indent . "(void)" . MakePublicName("DeactivateActCtx") . "(0, ulpCookie);\n";
  1201. $stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"cleanup"});
  1202. if ($maybePreserveError)
  1203. {
  1204. $stub .= $indent . "if (fPreserveLastError)\n";
  1205. $stub .= $indent . " SetLastError(dwLastError);\n";
  1206. }
  1207. $indent = Outdent($indent);
  1208. $stub .= $indent . "}\n";
  1209. $indent = Outdent($indent);
  1210. $stub .= $indent . "}\n";
  1211. }
  1212. if ($activate)
  1213. {
  1214. #$stub .= "Exit:\n";
  1215. }
  1216. if ($ret ne "void")
  1217. {
  1218. $stub .= $indent . "return " . $function->retname() . ";\n";
  1219. }
  1220. else
  1221. {
  1222. $stub .= $indent . "return;\n";
  1223. }
  1224. if ($ret eq "HRESULT")
  1225. {
  1226. $stub .= $ExitWin32ToHresult;
  1227. }
  1228. $indent = Outdent($indent);
  1229. $stub .= $indent . "}\n\n";
  1230. return $stub;
  1231. };
  1232. foreach $function (@functions)
  1233. {
  1234. if (0)
  1235. {
  1236. print(
  1237. "ret:" . $function->ret()
  1238. . " name:" . $function->name()
  1239. . " argsTypesNames:" . $function->argsTypesNames()
  1240. . " argsNames:" . $function->argsNames()
  1241. . "\n"
  1242. );
  1243. }
  1244. }
  1245. $code .= "\n";
  1246. $code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
  1247. $code .= "#if " . MakePublicPreprocessorSymbol("ENABLED") . "\n\n";
  1248. $code .= GenerateHeaderCommon1($functions[0]);
  1249. #$ifSubClassProc = 0;
  1250. #$ifStream = 0;
  1251. #$ifPrintDialogEx = 0;
  1252. sub AppendNewlineIfNotEmpty
  1253. {
  1254. return $_[0] ? $_[0] . "\n" : $_[0];
  1255. }
  1256. sub GeneratePoundIf
  1257. {
  1258. #
  1259. # note: nesting does not work
  1260. #
  1261. #print "GeneratePoundIf\n";
  1262. my($function) = ($_[0]);
  1263. my($name) = $function->name();
  1264. my($condition) = $PoundIfCondition{$name};
  1265. my($state) = $PoundIfState{$condition};
  1266. my($code) = "";
  1267. if ($condition)
  1268. {
  1269. #$code .= "/* GeneratePoundIf:function=$name;condition=$condition;state=$state */\n";
  1270. }
  1271. if ($condition && !$state)
  1272. {
  1273. $PoundIfState{$condition} = 1;
  1274. $code .= "#if $condition\n";
  1275. }
  1276. elsif (!$condition)
  1277. {
  1278. $code .= GeneratePoundEndif($function);
  1279. }
  1280. return $code;
  1281. }
  1282. sub GeneratePoundEndif
  1283. {
  1284. #
  1285. # note: nesting does not work
  1286. #
  1287. my ($code) = "";
  1288. foreach $condition (keys(%PoundIfState))
  1289. {
  1290. $code .= "#endif /* $condition */\n";
  1291. }
  1292. undef %PoundIfState; # empty it
  1293. return $code;
  1294. }
  1295. foreach $function (@functions)
  1296. {
  1297. $code .= GeneratePoundIf($function);
  1298. $code .= GeneratePrototype($function);
  1299. }
  1300. $code .= GeneratePoundEndif($function);
  1301. # hash so we can look for fooA and fooW
  1302. foreach $function (@functions)
  1303. {
  1304. #print($function->name() . "\n");
  1305. $hashFunctionNames{$function->name()} = $function;
  1306. }
  1307. foreach $function (sort(keys(%hashFunctionNames)))
  1308. {
  1309. #print($function . "\n");
  1310. if ($function =~ /(.+)A$/ && $hashFunctionNames{$1 . "W"})
  1311. {
  1312. $stringFunctionsHash{$1} = 1;
  1313. #print($1 . " is a string function\n");
  1314. }
  1315. }
  1316. $code .= "\n#if defined(UNICODE)\n\n";
  1317. foreach $function (sort(keys(%stringFunctionsHash)))
  1318. {
  1319. $code .= "#define " . MakePublicName($function);
  1320. $code .= " " . MakePublicName($function . "W") . "\n";
  1321. }
  1322. $code .= "\n#else /* UNICODE */\n\n";
  1323. foreach $function (sort(keys(%stringFunctionsHash)))
  1324. {
  1325. $code .= "#define " . MakePublicName($function);
  1326. $code .= " " . MakePublicName($function . "A") . "\n";
  1327. }
  1328. $code .= "\n#endif /* UNICODE */\n\n";
  1329. ## PUBLIC here means "real Win32 documented name
  1330. ## Public in elsewhere means user callable function, even if macro renamed
  1331. #$code .= "\n#if defined(" . MakePublicPreprocessorSymbol("WRAPPER_NAMES_ARE_PUBLIC_NAMES") . ")\n\n";
  1332. #
  1333. #$code .= '/*
  1334. # THIS IS NOT THE DEFAULT.
  1335. #
  1336. # UNDONE If we really support this, then we need to do something about __declspec(dllimport).
  1337. # It is a warning to say:
  1338. # __declspec(dllimport) void Foo();
  1339. # inline void Foo() { }
  1340. #
  1341. # Either support the warning or remove the __declspec(dllimport) (a slight deoptimization for
  1342. # users that directly statically link).
  1343. #
  1344. # UNDONE This also probably does not work for the kernel32 and user32 functions, but is in fact
  1345. # what old shfusion.lib does for comctl and comdlg. The Perl code can tell these apart by
  1346. # checking if "delayload dll" vs. individsual "delayload functions".
  1347. #
  1348. # Note that some functions like LoadLibrary do not appear in this list of macros.
  1349. # That is deliberate. Nondelayloaded functions cannot be here, that\'d result in
  1350. # infinite recursion, where the wrapper calls itself.
  1351. #*/
  1352. #';
  1353. #foreach $function (sort(keys(%hashFunctionNames)))
  1354. #{
  1355. # #
  1356. # # This is only possible for delayloaded functions.
  1357. # # In particular, LoadLibrary cannot be this way, otherwise our stubs end up
  1358. # # calling our stubs.
  1359. # #
  1360. # if ($hashFunctionNames{$function}->delayload())
  1361. # {
  1362. # $code .= "#define " . MakePublicName($function) . " " . $function . "\n";
  1363. # }
  1364. #}
  1365. #$code .= "\n#endif\n\n";
  1366. foreach $function (@functions)
  1367. {
  1368. $code .= AppendNewlineIfNotEmpty(GeneratePoundIf($function));
  1369. $code .= GenerateStub($function);
  1370. }
  1371. $code .= AppendNewlineIfNotEmpty(GeneratePoundEndif($function));
  1372. $code .= GenerateHeaderCommon2($functions[0]);
  1373. #
  1374. # The mapping must come after the WinbaseSpecialCode2.
  1375. #
  1376. #$code .= "\n#if !defined(" . MakePublicPreprocessorSymbol("WRAPPER_NAMES_ARE_PUBLIC_NAMES") . ") \\\n";
  1377. #$code .= " && !defined(" . MakePublicPreprocessorSymbol("DO_NOT_MAP_PUBLIC_NAMES_TO_WRAPPER_NAMES") . ")\n\n";
  1378. #$code .= '/*
  1379. # THIS IS IN FACT THE USUAL CASE.
  1380. #
  1381. # All functions appear here, even if they don\'t all appear in the earlier macro list.
  1382. #*/
  1383. #';
  1384. foreach $function (sort(keys(%hashFunctionNames)))
  1385. {
  1386. if ($NoMacro{$function})
  1387. {
  1388. $code .= " /* " . $function . " skipped, as it is a popular C++ member function name. */\n";
  1389. }
  1390. else
  1391. {
  1392. if ($Undef{$function})
  1393. {
  1394. $code .= "#if defined(" . $function . ")\n";
  1395. $code .= "#undef " . $function . "\n";
  1396. $code .= "#endif\n";
  1397. }
  1398. $code .= "#define " . $function . " " . MakePublicName($function) . "\n";
  1399. }
  1400. }
  1401. #$code .= "\n#endif\n\n";
  1402. $code .= "\n#endif /* " . MakePublicPreprocessorSymbol("ENABLED") . " */\n";
  1403. $code .= "#endif /* RC */\n\n";
  1404. $code = InsertCodeIntoFile($code, $headerFullPath);
  1405. print($code);
  1406. __END__
  1407. :endofperl