Setup.RedirFunc.pas 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. unit Setup.RedirFunc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2026 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. Used only by the Setup and SetupLdr projects.
  9. The *Redir functions are counterparts to common functions that offer
  10. built-in support for disabling FS redirection.
  11. }
  12. interface
  13. uses
  14. Windows;
  15. type
  16. TPreviousFsRedirectionState = record
  17. {$IFNDEF WIN64}
  18. DidDisable: Boolean;
  19. OldValue: Pointer;
  20. {$ENDIF}
  21. end;
  22. {$IFNDEF WIN64}
  23. function AreFsRedirectionFunctionsAvailable: Boolean;
  24. {$ENDIF}
  25. function DisableFsRedirectionIf(const Disable: Boolean;
  26. var PreviousState: TPreviousFsRedirectionState): Boolean;
  27. procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
  28. function CreateProcessRedir(const DisableFsRedir: Boolean;
  29. const lpApplicationName: PChar; const lpCommandLine: PChar;
  30. const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  31. const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
  32. const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
  33. const lpStartupInfo: TStartupInfo;
  34. var lpProcessInformation: TProcessInformation): BOOL;
  35. implementation
  36. uses
  37. Shared.CommonFunc;
  38. {$IFNDEF WIN64}
  39. var
  40. Wow64DisableWow64FsRedirectionFunc: function(var OldValue: Pointer): BOOL; stdcall;
  41. Wow64RevertWow64FsRedirectionFunc: function(OldValue: Pointer): BOOL; stdcall;
  42. FsRedirectionFunctionsAvailable: Boolean;
  43. function AreFsRedirectionFunctionsAvailable: Boolean;
  44. begin
  45. Result := FsRedirectionFunctionsAvailable;
  46. end;
  47. {$ENDIF}
  48. function DisableFsRedirectionIf(const Disable: Boolean;
  49. var PreviousState: TPreviousFsRedirectionState): Boolean;
  50. { If Disable is False, the function does not change the redirection state and
  51. always returns True.
  52. If Disable is True, the function attempts to disable WOW64 file system
  53. redirection, so that c:\windows\system32 goes to the 64-bit System directory
  54. instead of the 32-bit one.
  55. Returns True if successful, False if not. For extended error information when
  56. False is returned, call GetLastError. }
  57. begin
  58. {$IFNDEF WIN64}
  59. PreviousState.DidDisable := False;
  60. if not Disable then
  61. Result := True
  62. else begin
  63. if FsRedirectionFunctionsAvailable then begin
  64. { Note: Disassembling Wow64DisableWow64FsRedirection and the Rtl function
  65. it calls, it doesn't appear as if it can ever actually fail on 64-bit
  66. Windows. But it always fails on the 32-bit version of Windows Server
  67. 2003 SP1 (with error code 1 - ERROR_INVALID_FUNCTION). }
  68. Result := Wow64DisableWow64FsRedirectionFunc(PreviousState.OldValue);
  69. if Result then
  70. PreviousState.DidDisable := True;
  71. end
  72. else begin
  73. { Should never happen }
  74. SetLastError(ERROR_INVALID_FUNCTION);
  75. Result := False;
  76. end;
  77. end;
  78. {$ELSE}
  79. Result := True;
  80. {$ENDIF}
  81. end;
  82. procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
  83. { Restores the previous WOW64 file system redirection state after a call to
  84. DisableFsRedirectionIf. There is no indication of failure (which is
  85. extremely unlikely). }
  86. begin
  87. {$IFNDEF WIN64}
  88. if PreviousState.DidDisable then
  89. Wow64RevertWow64FsRedirectionFunc(PreviousState.OldValue);
  90. {$ENDIF}
  91. end;
  92. { *Redir functions }
  93. function CreateProcessRedir(const DisableFsRedir: Boolean;
  94. const lpApplicationName: PChar; const lpCommandLine: PChar;
  95. const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
  96. const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
  97. const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
  98. const lpStartupInfo: TStartupInfo;
  99. var lpProcessInformation: TProcessInformation): BOOL;
  100. var
  101. PrevState: TPreviousFsRedirectionState;
  102. ErrorCode: DWORD;
  103. begin
  104. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  105. Result := False;
  106. Exit;
  107. end;
  108. try
  109. Result := CreateProcess(lpApplicationName, lpCommandLine,
  110. lpProcessAttributes, lpThreadAttributes,
  111. bInheritHandles, dwCreationFlags, lpEnvironment,
  112. lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
  113. ErrorCode := GetLastError;
  114. finally
  115. RestoreFsRedirection(PrevState);
  116. end;
  117. SetLastError(ErrorCode);
  118. end;
  119. function DeleteFileRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
  120. var
  121. PrevState: TPreviousFsRedirectionState;
  122. ErrorCode: DWORD;
  123. begin
  124. if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
  125. Result := False;
  126. Exit;
  127. end;
  128. try
  129. Result := Windows.DeleteFile(PChar(Filename));
  130. ErrorCode := GetLastError;
  131. finally
  132. RestoreFsRedirection(PrevState);
  133. end;
  134. SetLastError(ErrorCode);
  135. end;
  136. initialization
  137. {$IFNDEF WIN64}
  138. Wow64DisableWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
  139. 'Wow64DisableWow64FsRedirection');
  140. Wow64RevertWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
  141. 'Wow64RevertWow64FsRedirection');
  142. FsRedirectionFunctionsAvailable := Assigned(Wow64DisableWow64FsRedirectionFunc) and
  143. Assigned(Wow64RevertWow64FsRedirectionFunc);
  144. {$ENDIF}
  145. { FormatMessage might be called with FS redirection disabled, so ensure
  146. that all the DLLs FormatMessage searches in for messages (e.g. netmsg.dll,
  147. ws03res.dll) are pre-loaded by calling it now with a randomly-chosen
  148. message ID -- one that won't result in a match and cause the function to
  149. return early.
  150. (Note: Presently, FormatMessage loads the DLLs as "data files" so it
  151. actually may not matter whether it gets 32- or 64-bit versions. But let's
  152. be on the safe side.) }
  153. Win32ErrorString($4C783AFB);
  154. end.