RedirFunc.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. unit RedirFunc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Functions for dealing with WOW64 file system redirection.
  8. The *Redir functions are counterparts to common functions that offer
  9. built-in support for disabling FS redirection.
  10. $jrsoftware: issrc/Projects/RedirFunc.pas,v 1.11 2007/09/10 11:59:14 mlaan Exp $
  11. }
  12. interface
  13. uses
  14. Windows, SysUtils, FileClass, VerInfo;
  15. type
  16. TPreviousFsRedirectionState = record
  17. DidDisable: Boolean;
  18. OldValue: Pointer;
  19. end;
  20. function AreFsRedirectionFunctionsAvailable: Boolean;
  21. function DisableFsRedirectionIf(const Disable: Boolean;
  22. var PreviousState: TPreviousFsRedirectionState): Boolean;
  23. procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
  24. function CreateDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  25. function CreateProcessRedir(const DisableFsRedir: Boolean;
  26. const lpApplicationName: PChar; const lpCommandLine: PChar;
  27. const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  28. const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
  29. const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
  30. const lpStartupInfo: TStartupInfo;
  31. var lpProcessInformation: TProcessInformation): BOOL;
  32. function CopyFileRedir(const DisableFsRedir: Boolean;
  33. const ExistingFilename, NewFilename: String; const FailIfExists: BOOL): BOOL;
  34. function DeleteFileRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  35. function DirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  36. function FileOrDirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  37. function FindFirstFileRedir(const DisableFsRedir: Boolean; const Filename: String;
  38. var FindData: TWin32FindData): THandle;
  39. function GetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String): DWORD;
  40. function GetShortNameRedir(const DisableFsRedir: Boolean; const Filename: String): String;
  41. function GetVersionNumbersRedir(const DisableFsRedir: Boolean; const Filename: String;
  42. var VersionNumbers: TFileVersionNumbers): Boolean;
  43. function IsDirectoryAndNotReparsePointRedir(const DisableFsRedir: Boolean;
  44. const Name: String): Boolean;
  45. function MoveFileRedir(const DisableFsRedir: Boolean;
  46. const ExistingFilename, NewFilename: String): BOOL;
  47. function MoveFileExRedir(const DisableFsRedir: Boolean;
  48. const ExistingFilename, NewFilename: String; const Flags: DWORD): BOOL;
  49. function NewFileExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  50. function RemoveDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  51. function SetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String;
  52. const Attrib: DWORD): BOOL;
  53. function SetNTFSCompressionRedir(const DisableFsRedir: Boolean; const FileOrDir: String; Compress: Boolean): Boolean;
  54. type
  55. TFileRedir = class(TFile)
  56. private
  57. FDisableFsRedir: Boolean;
  58. protected
  59. function CreateHandle(const AFilename: String;
  60. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  61. ASharing: TFileSharing): THandle; override;
  62. public
  63. constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
  64. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  65. ASharing: TFileSharing);
  66. end;
  67. TTextFileReaderRedir = class(TTextFileReader)
  68. private
  69. FDisableFsRedir: Boolean;
  70. protected
  71. function CreateHandle(const AFilename: String;
  72. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  73. ASharing: TFileSharing): THandle; override;
  74. public
  75. constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
  76. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  77. ASharing: TFileSharing);
  78. end;
  79. TTextFileWriterRedir = class(TTextFileWriter)
  80. private
  81. FDisableFsRedir: Boolean;
  82. protected
  83. function CreateHandle(const AFilename: String;
  84. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  85. ASharing: TFileSharing): THandle; override;
  86. public
  87. constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
  88. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  89. ASharing: TFileSharing);
  90. end;
  91. implementation
  92. uses
  93. CmnFunc2, PathFunc;
  94. var
  95. Wow64DisableWow64FsRedirectionFunc: function(var OldValue: Pointer): BOOL; stdcall;
  96. Wow64RevertWow64FsRedirectionFunc: function(OldValue: Pointer): BOOL; stdcall;
  97. FsRedirectionFunctionsAvailable: Boolean;
  98. function AreFsRedirectionFunctionsAvailable: Boolean;
  99. begin
  100. Result := FsRedirectionFunctionsAvailable;
  101. end;
  102. function DisableFsRedirectionIf(const Disable: Boolean;
  103. var PreviousState: TPreviousFsRedirectionState): Boolean;
  104. { If Disable is False, the function does not change the redirection state and
  105. always returns True.
  106. If Disable is True, the function attempts to disable WOW64 file system
  107. redirection, so that c:\windows\system32 goes to the 64-bit System directory
  108. instead of the 32-bit one.
  109. Returns True if successful, False if not. For extended error information when
  110. False is returned, call GetLastError. }
  111. begin
  112. PreviousState.DidDisable := False;
  113. if not Disable then
  114. Result := True
  115. else begin
  116. if FsRedirectionFunctionsAvailable then begin
  117. { Note: Disassembling Wow64DisableWow64FsRedirection and the Rtl function
  118. it calls, it doesn't appear as if it can ever actually fail on 64-bit
  119. Windows. But it always fails on the 32-bit version of Windows Server
  120. 2003 SP1 (with error code 1 - ERROR_INVALID_FUNCTION). }
  121. Result := Wow64DisableWow64FsRedirectionFunc(PreviousState.OldValue);
  122. if Result then
  123. PreviousState.DidDisable := True;
  124. end
  125. else begin
  126. { Should never happen }
  127. SetLastError(ERROR_INVALID_FUNCTION);
  128. Result := False;
  129. end;
  130. end;
  131. end;
  132. procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
  133. { Restores the previous WOW64 file system redirection state after a call to
  134. DisableFsRedirectionIf. There is no indication of failure (which is
  135. extremely unlikely). }
  136. begin
  137. if PreviousState.DidDisable then
  138. Wow64RevertWow64FsRedirectionFunc(PreviousState.OldValue);
  139. end;
  140. { *Redir functions }
  141. function CreateDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  142. var
  143. PrevState: TPreviousFsRedirectionState;
  144. ErrorCode: DWORD;
  145. begin
  146. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  147. Result := False;
  148. Exit;
  149. end;
  150. try
  151. Result := CreateDirectory(PChar(Filename), nil);
  152. ErrorCode := GetLastError;
  153. finally
  154. RestoreFsRedirection(PrevState);
  155. end;
  156. SetLastError(ErrorCode);
  157. end;
  158. function CreateProcessRedir(const DisableFsRedir: Boolean;
  159. const lpApplicationName: PChar; const lpCommandLine: PChar;
  160. const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  161. const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
  162. const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
  163. const lpStartupInfo: TStartupInfo;
  164. var lpProcessInformation: TProcessInformation): BOOL;
  165. var
  166. PrevState: TPreviousFsRedirectionState;
  167. ErrorCode: DWORD;
  168. begin
  169. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  170. Result := False;
  171. Exit;
  172. end;
  173. try
  174. Result := CreateProcess(lpApplicationName, lpCommandLine,
  175. lpProcessAttributes, lpThreadAttributes,
  176. bInheritHandles, dwCreationFlags, lpEnvironment,
  177. lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
  178. ErrorCode := GetLastError;
  179. finally
  180. RestoreFsRedirection(PrevState);
  181. end;
  182. SetLastError(ErrorCode);
  183. end;
  184. function CopyFileRedir(const DisableFsRedir: Boolean;
  185. const ExistingFilename, NewFilename: String; const FailIfExists: BOOL): BOOL;
  186. var
  187. PrevState: TPreviousFsRedirectionState;
  188. ErrorCode: DWORD;
  189. begin
  190. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  191. Result := False;
  192. Exit;
  193. end;
  194. try
  195. Result := CopyFile(PChar(ExistingFilename), PChar(NewFilename), FailIfExists);
  196. ErrorCode := GetLastError;
  197. finally
  198. RestoreFsRedirection(PrevState);
  199. end;
  200. SetLastError(ErrorCode);
  201. end;
  202. function DeleteFileRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  203. var
  204. PrevState: TPreviousFsRedirectionState;
  205. ErrorCode: DWORD;
  206. begin
  207. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  208. Result := False;
  209. Exit;
  210. end;
  211. try
  212. Result := Windows.DeleteFile(PChar(Filename));
  213. ErrorCode := GetLastError;
  214. finally
  215. RestoreFsRedirection(PrevState);
  216. end;
  217. SetLastError(ErrorCode);
  218. end;
  219. function DirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  220. var
  221. PrevState: TPreviousFsRedirectionState;
  222. ErrorCode: DWORD;
  223. begin
  224. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  225. Result := False;
  226. Exit;
  227. end;
  228. try
  229. Result := DirExists(Filename);
  230. ErrorCode := GetLastError;
  231. finally
  232. RestoreFsRedirection(PrevState);
  233. end;
  234. SetLastError(ErrorCode);
  235. end;
  236. function FileOrDirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  237. var
  238. PrevState: TPreviousFsRedirectionState;
  239. ErrorCode: DWORD;
  240. begin
  241. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  242. Result := False;
  243. Exit;
  244. end;
  245. try
  246. Result := FileOrDirExists(Filename);
  247. ErrorCode := GetLastError;
  248. finally
  249. RestoreFsRedirection(PrevState);
  250. end;
  251. SetLastError(ErrorCode);
  252. end;
  253. function FindFirstFileRedir(const DisableFsRedir: Boolean; const Filename: String;
  254. var FindData: TWin32FindData): THandle;
  255. var
  256. PrevState: TPreviousFsRedirectionState;
  257. ErrorCode: DWORD;
  258. begin
  259. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  260. Result := INVALID_HANDLE_VALUE;
  261. Exit;
  262. end;
  263. try
  264. Result := FindFirstFile(PChar(Filename), FindData);
  265. ErrorCode := GetLastError;
  266. finally
  267. RestoreFsRedirection(PrevState);
  268. end;
  269. SetLastError(ErrorCode);
  270. end;
  271. function GetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String): DWORD;
  272. var
  273. PrevState: TPreviousFsRedirectionState;
  274. ErrorCode: DWORD;
  275. begin
  276. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  277. Result := $FFFFFFFF;
  278. Exit;
  279. end;
  280. try
  281. Result := GetFileAttributes(PChar(Filename));
  282. ErrorCode := GetLastError;
  283. finally
  284. RestoreFsRedirection(PrevState);
  285. end;
  286. SetLastError(ErrorCode);
  287. end;
  288. function GetShortNameRedir(const DisableFsRedir: Boolean; const Filename: String): String;
  289. var
  290. PrevState: TPreviousFsRedirectionState;
  291. begin
  292. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  293. Result := Filename;
  294. Exit;
  295. end;
  296. try
  297. Result := GetShortName(Filename);
  298. finally
  299. RestoreFsRedirection(PrevState);
  300. end;
  301. end;
  302. function GetVersionNumbersRedir(const DisableFsRedir: Boolean; const Filename: String;
  303. var VersionNumbers: TFileVersionNumbers): Boolean;
  304. var
  305. PrevState: TPreviousFsRedirectionState;
  306. begin
  307. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  308. Result := False;
  309. Exit;
  310. end;
  311. try
  312. Result := GetVersionNumbers(Filename, VersionNumbers);
  313. finally
  314. RestoreFsRedirection(PrevState);
  315. end;
  316. end;
  317. function IsDirectoryAndNotReparsePointRedir(const DisableFsRedir: Boolean;
  318. const Name: String): Boolean;
  319. var
  320. PrevState: TPreviousFsRedirectionState;
  321. begin
  322. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  323. Result := False;
  324. Exit;
  325. end;
  326. try
  327. Result := IsDirectoryAndNotReparsePoint(Name);
  328. finally
  329. RestoreFsRedirection(PrevState);
  330. end;
  331. end;
  332. function MoveFileRedir(const DisableFsRedir: Boolean;
  333. const ExistingFilename, NewFilename: String): BOOL;
  334. var
  335. PrevState: TPreviousFsRedirectionState;
  336. ErrorCode: DWORD;
  337. begin
  338. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  339. Result := False;
  340. Exit;
  341. end;
  342. try
  343. Result := MoveFile(PChar(ExistingFilename), PChar(NewFilename));
  344. ErrorCode := GetLastError;
  345. finally
  346. RestoreFsRedirection(PrevState);
  347. end;
  348. SetLastError(ErrorCode);
  349. end;
  350. function MoveFileExRedir(const DisableFsRedir: Boolean;
  351. const ExistingFilename, NewFilename: String; const Flags: DWORD): BOOL;
  352. var
  353. NewFilenameP: PChar;
  354. PrevState: TPreviousFsRedirectionState;
  355. ErrorCode: DWORD;
  356. begin
  357. if (NewFilename = '') and (Flags and MOVEFILE_DELAY_UNTIL_REBOOT <> 0) then
  358. NewFilenameP := nil
  359. else
  360. NewFilenameP := PChar(NewFilename);
  361. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  362. Result := False;
  363. Exit;
  364. end;
  365. try
  366. Result := MoveFileEx(PChar(ExistingFilename), NewFilenameP, Flags);
  367. ErrorCode := GetLastError;
  368. finally
  369. RestoreFsRedirection(PrevState);
  370. end;
  371. SetLastError(ErrorCode);
  372. end;
  373. function NewFileExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
  374. var
  375. PrevState: TPreviousFsRedirectionState;
  376. ErrorCode: DWORD;
  377. begin
  378. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  379. Result := False;
  380. Exit;
  381. end;
  382. try
  383. Result := NewFileExists(Filename);
  384. ErrorCode := GetLastError;
  385. finally
  386. RestoreFsRedirection(PrevState);
  387. end;
  388. SetLastError(ErrorCode);
  389. end;
  390. function RemoveDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  391. var
  392. PrevState: TPreviousFsRedirectionState;
  393. ErrorCode: DWORD;
  394. begin
  395. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  396. Result := False;
  397. Exit;
  398. end;
  399. try
  400. Result := RemoveDirectory(PChar(Filename));
  401. ErrorCode := GetLastError;
  402. finally
  403. RestoreFsRedirection(PrevState);
  404. end;
  405. SetLastError(ErrorCode);
  406. end;
  407. function SetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String;
  408. const Attrib: DWORD): BOOL;
  409. var
  410. PrevState: TPreviousFsRedirectionState;
  411. ErrorCode: DWORD;
  412. begin
  413. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  414. Result := False;
  415. Exit;
  416. end;
  417. try
  418. Result := SetFileAttributes(PChar(Filename), Attrib);
  419. ErrorCode := GetLastError;
  420. finally
  421. RestoreFsRedirection(PrevState);
  422. end;
  423. SetLastError(ErrorCode);
  424. end;
  425. function SetNTFSCompressionRedir(const DisableFsRedir: Boolean; const FileOrDir: String; Compress: Boolean): Boolean;
  426. var
  427. PrevState: TPreviousFsRedirectionState;
  428. ErrorCode: DWORD;
  429. begin
  430. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  431. Result := False;
  432. Exit;
  433. end;
  434. try
  435. Result := SetNTFSCompression(FileOrDir, Compress);
  436. ErrorCode := GetLastError;
  437. finally
  438. RestoreFsRedirection(PrevState);
  439. end;
  440. SetLastError(ErrorCode);
  441. end;
  442. { TFileRedir }
  443. constructor TFileRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
  444. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  445. ASharing: TFileSharing);
  446. begin
  447. FDisableFsRedir := DisableFsRedir;
  448. inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
  449. end;
  450. function TFileRedir.CreateHandle(const AFilename: String;
  451. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  452. ASharing: TFileSharing): THandle;
  453. var
  454. PrevState: TPreviousFsRedirectionState;
  455. ErrorCode: DWORD;
  456. begin
  457. if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
  458. Result := INVALID_HANDLE_VALUE;
  459. Exit;
  460. end;
  461. try
  462. Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
  463. ASharing);
  464. ErrorCode := GetLastError;
  465. finally
  466. RestoreFsRedirection(PrevState);
  467. end;
  468. SetLastError(ErrorCode);
  469. end;
  470. { TTextFileReaderRedir }
  471. constructor TTextFileReaderRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
  472. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  473. ASharing: TFileSharing);
  474. begin
  475. FDisableFsRedir := DisableFsRedir;
  476. inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
  477. end;
  478. function TTextFileReaderRedir.CreateHandle(const AFilename: String;
  479. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  480. ASharing: TFileSharing): THandle;
  481. var
  482. PrevState: TPreviousFsRedirectionState;
  483. ErrorCode: DWORD;
  484. begin
  485. if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
  486. Result := INVALID_HANDLE_VALUE;
  487. Exit;
  488. end;
  489. try
  490. Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
  491. ASharing);
  492. ErrorCode := GetLastError;
  493. finally
  494. RestoreFsRedirection(PrevState);
  495. end;
  496. SetLastError(ErrorCode);
  497. end;
  498. { TTextFileWriterRedir }
  499. constructor TTextFileWriterRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
  500. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  501. ASharing: TFileSharing);
  502. begin
  503. FDisableFsRedir := DisableFsRedir;
  504. inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
  505. end;
  506. function TTextFileWriterRedir.CreateHandle(const AFilename: String;
  507. ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
  508. ASharing: TFileSharing): THandle;
  509. var
  510. PrevState: TPreviousFsRedirectionState;
  511. ErrorCode: DWORD;
  512. begin
  513. if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
  514. Result := INVALID_HANDLE_VALUE;
  515. Exit;
  516. end;
  517. try
  518. Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
  519. ASharing);
  520. ErrorCode := GetLastError;
  521. finally
  522. RestoreFsRedirection(PrevState);
  523. end;
  524. SetLastError(ErrorCode);
  525. end;
  526. initialization
  527. Wow64DisableWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
  528. 'Wow64DisableWow64FsRedirection');
  529. Wow64RevertWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
  530. 'Wow64RevertWow64FsRedirection');
  531. FsRedirectionFunctionsAvailable := Assigned(Wow64DisableWow64FsRedirectionFunc) and
  532. Assigned(Wow64RevertWow64FsRedirectionFunc);
  533. { For GetVersionNumbersRedir: Pre-load shell32.dll since GetFileVersionInfo
  534. and GetFileVersionInfoSize will try to load it when reading version info
  535. on 16-bit files. We can't allow the DLL be loaded for the first time while
  536. FS redirection is disabled. }
  537. SafeLoadLibrary(AddBackslash(GetSystemDir) + 'shell32.dll', SEM_NOOPENFILEERRORBOX);
  538. { FormatMessage might be called with FS redirection disabled, so ensure
  539. that all the DLLs FormatMessage searches in for messages (e.g. netmsg.dll,
  540. ws03res.dll) are pre-loaded by calling it now with a randomly-chosen
  541. message ID -- one that won't result in a match and cause the function to
  542. return early.
  543. (Note: Presently, FormatMessage loads the DLLs as "data files" so it
  544. actually may not matter whether it gets 32- or 64-bit versions. But let's
  545. be on the safe side.) }
  546. Win32ErrorString($4C783AFB);
  547. end.