123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- unit SetupLdrAndSetup.RedirFunc;
- {
- Inno Setup
- Copyright (C) 1997-2025 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- Functions for dealing with WOW64 file system redirection.
- Used only by the Setup and SetupLdr projects.
- The *Redir functions are counterparts to common functions that offer
- built-in support for disabling FS redirection.
- }
- interface
- uses
- Windows, SysUtils, Shared.FileClass, Shared.VerInfoFunc;
- type
- TPreviousFsRedirectionState = record
- DidDisable: Boolean;
- OldValue: Pointer;
- end;
- function AreFsRedirectionFunctionsAvailable: Boolean;
- function DisableFsRedirectionIf(const Disable: Boolean;
- var PreviousState: TPreviousFsRedirectionState): Boolean;
- procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
- function CreateFileRedir(const DisableFsRedir: Boolean; const FileName: String;
- const DesiredAccess, ShareMode: DWORD; const SecurityAttributes: PSecurityAttributes;
- const CreationDisposition, FlagsAndAttributes: DWORD; TemplateFile: THandle): THandle;
- function CreateDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String;
- const SecurityAttributes: PSecurityAttributes = nil): BOOL;
- function CreateProcessRedir(const DisableFsRedir: Boolean;
- const lpApplicationName: PChar; const lpCommandLine: PChar;
- const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
- const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
- const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
- const lpStartupInfo: TStartupInfo;
- var lpProcessInformation: TProcessInformation): BOOL;
- function CopyFileRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String; const FailIfExists: BOOL): BOOL;
- function DeleteFileRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
- function DirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- function FileOrDirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- function FindFirstFileRedir(const DisableFsRedir: Boolean; const Filename: String;
- var FindData: TWin32FindData): THandle;
- function GetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String): DWORD;
- function GetShortNameRedir(const DisableFsRedir: Boolean; const Filename: String): String;
- function GetVersionNumbersRedir(const DisableFsRedir: Boolean; const Filename: String;
- var VersionNumbers: TFileVersionNumbers): Boolean;
- function IsDirectoryAndNotReparsePointRedir(const DisableFsRedir: Boolean;
- const Name: String): Boolean;
- function MoveFileRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String): BOOL;
- function MoveFileExRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String; const Flags: DWORD): BOOL;
- function NewFileExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- function RemoveDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
- function SetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String;
- const Attrib: DWORD): BOOL;
- function SetNTFSCompressionRedir(const DisableFsRedir: Boolean; const FileOrDir: String; Compress: Boolean): Boolean;
- type
- TFileRedir = class(TFile)
- private
- FDisableFsRedir: Boolean;
- protected
- function CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle; override;
- public
- constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- end;
- TTextFileReaderRedir = class(TTextFileReader)
- private
- FDisableFsRedir: Boolean;
- protected
- function CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle; override;
- public
- constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- end;
- TTextFileWriterRedir = class(TTextFileWriter)
- private
- FDisableFsRedir: Boolean;
- protected
- function CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle; override;
- public
- constructor Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- end;
- implementation
- uses
- Shared.CommonFunc, PathFunc;
- var
- Wow64DisableWow64FsRedirectionFunc: function(var OldValue: Pointer): BOOL; stdcall;
- Wow64RevertWow64FsRedirectionFunc: function(OldValue: Pointer): BOOL; stdcall;
- FsRedirectionFunctionsAvailable: Boolean;
- function AreFsRedirectionFunctionsAvailable: Boolean;
- begin
- Result := FsRedirectionFunctionsAvailable;
- end;
- function DisableFsRedirectionIf(const Disable: Boolean;
- var PreviousState: TPreviousFsRedirectionState): Boolean;
- { If Disable is False, the function does not change the redirection state and
- always returns True.
- If Disable is True, the function attempts to disable WOW64 file system
- redirection, so that c:\windows\system32 goes to the 64-bit System directory
- instead of the 32-bit one.
- Returns True if successful, False if not. For extended error information when
- False is returned, call GetLastError. }
- begin
- PreviousState.DidDisable := False;
- if not Disable then
- Result := True
- else begin
- if FsRedirectionFunctionsAvailable then begin
- { Note: Disassembling Wow64DisableWow64FsRedirection and the Rtl function
- it calls, it doesn't appear as if it can ever actually fail on 64-bit
- Windows. But it always fails on the 32-bit version of Windows Server
- 2003 SP1 (with error code 1 - ERROR_INVALID_FUNCTION). }
- Result := Wow64DisableWow64FsRedirectionFunc(PreviousState.OldValue);
- if Result then
- PreviousState.DidDisable := True;
- end
- else begin
- { Should never happen }
- SetLastError(ERROR_INVALID_FUNCTION);
- Result := False;
- end;
- end;
- end;
- procedure RestoreFsRedirection(const PreviousState: TPreviousFsRedirectionState);
- { Restores the previous WOW64 file system redirection state after a call to
- DisableFsRedirectionIf. There is no indication of failure (which is
- extremely unlikely). }
- begin
- if PreviousState.DidDisable then
- Wow64RevertWow64FsRedirectionFunc(PreviousState.OldValue);
- end;
- { *Redir functions }
- function CreateFileRedir(const DisableFsRedir: Boolean; const FileName: String;
- const DesiredAccess, ShareMode: DWORD; const SecurityAttributes: PSecurityAttributes;
- const CreationDisposition, FlagsAndAttributes: DWORD; TemplateFile: THandle): THandle;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := INVALID_HANDLE_VALUE;
- Exit;
- end;
- try
- Result := CreateFile(PChar(Filename), DesiredAccess, ShareMode, SecurityAttributes,
- CreationDisposition, FlagsAndAttributes, TemplateFile);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function CreateDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String;
- const SecurityAttributes: PSecurityAttributes): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := CreateDirectory(PChar(Filename), SecurityAttributes);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function CreateProcessRedir(const DisableFsRedir: Boolean;
- const lpApplicationName: PChar; const lpCommandLine: PChar;
- const lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
- const bInheritHandles: BOOL; const dwCreationFlags: DWORD;
- const lpEnvironment: Pointer; const lpCurrentDirectory: PChar;
- const lpStartupInfo: TStartupInfo;
- var lpProcessInformation: TProcessInformation): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := CreateProcess(lpApplicationName, lpCommandLine,
- lpProcessAttributes, lpThreadAttributes,
- bInheritHandles, dwCreationFlags, lpEnvironment,
- lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function CopyFileRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String; const FailIfExists: BOOL): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := CopyFile(PChar(ExistingFilename), PChar(NewFilename), FailIfExists);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function DeleteFileRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := Windows.DeleteFile(PChar(Filename));
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function DirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := DirExists(Filename);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function FileOrDirExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := FileOrDirExists(Filename);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function FindFirstFileRedir(const DisableFsRedir: Boolean; const Filename: String;
- var FindData: TWin32FindData): THandle;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := INVALID_HANDLE_VALUE;
- Exit;
- end;
- try
- Result := FindFirstFile(PChar(Filename), FindData);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function GetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String): DWORD;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := INVALID_FILE_ATTRIBUTES;
- Exit;
- end;
- try
- Result := GetFileAttributes(PChar(Filename));
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function GetShortNameRedir(const DisableFsRedir: Boolean; const Filename: String): String;
- var
- PrevState: TPreviousFsRedirectionState;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := Filename;
- Exit;
- end;
- try
- Result := GetShortName(Filename);
- finally
- RestoreFsRedirection(PrevState);
- end;
- end;
- function GetVersionNumbersRedir(const DisableFsRedir: Boolean; const Filename: String;
- var VersionNumbers: TFileVersionNumbers): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := GetVersionNumbers(Filename, VersionNumbers);
- finally
- RestoreFsRedirection(PrevState);
- end;
- end;
- function IsDirectoryAndNotReparsePointRedir(const DisableFsRedir: Boolean;
- const Name: String): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := IsDirectoryAndNotReparsePoint(Name);
- finally
- RestoreFsRedirection(PrevState);
- end;
- end;
- function MoveFileRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := MoveFile(PChar(ExistingFilename), PChar(NewFilename));
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function MoveFileExRedir(const DisableFsRedir: Boolean;
- const ExistingFilename, NewFilename: String; const Flags: DWORD): BOOL;
- var
- NewFilenameP: PChar;
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if (NewFilename = '') and (Flags and MOVEFILE_DELAY_UNTIL_REBOOT <> 0) then
- NewFilenameP := nil
- else
- NewFilenameP := PChar(NewFilename);
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := MoveFileEx(PChar(ExistingFilename), NewFilenameP, Flags);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function NewFileExistsRedir(const DisableFsRedir: Boolean; const Filename: String): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := NewFileExists(Filename);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function RemoveDirectoryRedir(const DisableFsRedir: Boolean; const Filename: String): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := RemoveDirectory(PChar(Filename));
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function SetFileAttributesRedir(const DisableFsRedir: Boolean; const Filename: String;
- const Attrib: DWORD): BOOL;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := SetFileAttributes(PChar(Filename), Attrib);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- function SetNTFSCompressionRedir(const DisableFsRedir: Boolean; const FileOrDir: String; Compress: Boolean): Boolean;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(DisableFsRedir, PrevState) then begin
- Result := False;
- Exit;
- end;
- try
- Result := SetNTFSCompression(FileOrDir, Compress);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- { TFileRedir }
- constructor TFileRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- begin
- FDisableFsRedir := DisableFsRedir;
- inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
- end;
- function TFileRedir.CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
- Result := INVALID_HANDLE_VALUE;
- Exit;
- end;
- try
- Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
- ASharing);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- { TTextFileReaderRedir }
- constructor TTextFileReaderRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- begin
- FDisableFsRedir := DisableFsRedir;
- inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
- end;
- function TTextFileReaderRedir.CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
- Result := INVALID_HANDLE_VALUE;
- Exit;
- end;
- try
- Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
- ASharing);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- { TTextFileWriterRedir }
- constructor TTextFileWriterRedir.Create(const DisableFsRedir: Boolean; const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing);
- begin
- FDisableFsRedir := DisableFsRedir;
- inherited Create(AFilename, ACreateDisposition, AAccess, ASharing);
- end;
- function TTextFileWriterRedir.CreateHandle(const AFilename: String;
- ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
- ASharing: TFileSharing): THandle;
- var
- PrevState: TPreviousFsRedirectionState;
- ErrorCode: DWORD;
- begin
- if not DisableFsRedirectionIf(FDisableFsRedir, PrevState) then begin
- Result := INVALID_HANDLE_VALUE;
- Exit;
- end;
- try
- Result := inherited CreateHandle(AFilename, ACreateDisposition, AAccess,
- ASharing);
- ErrorCode := GetLastError;
- finally
- RestoreFsRedirection(PrevState);
- end;
- SetLastError(ErrorCode);
- end;
- initialization
- Wow64DisableWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
- 'Wow64DisableWow64FsRedirection');
- Wow64RevertWow64FsRedirectionFunc := GetProcAddress(GetModuleHandle(kernel32),
- 'Wow64RevertWow64FsRedirection');
- FsRedirectionFunctionsAvailable := Assigned(Wow64DisableWow64FsRedirectionFunc) and
- Assigned(Wow64RevertWow64FsRedirectionFunc);
- { For GetVersionNumbersRedir: Pre-load shell32.dll since GetFileVersionInfo
- and GetFileVersionInfoSize will try to load it when reading version info
- on 16-bit files. We can't allow the DLL be loaded for the first time while
- FS redirection is disabled. }
- SafeLoadLibrary(AddBackslash(GetSystemDir) + 'shell32.dll', SEM_NOOPENFILEERRORBOX);
- { FormatMessage might be called with FS redirection disabled, so ensure
- that all the DLLs FormatMessage searches in for messages (e.g. netmsg.dll,
- ws03res.dll) are pre-loaded by calling it now with a randomly-chosen
- message ID -- one that won't result in a match and cause the function to
- return early.
- (Note: Presently, FormatMessage loads the DLLs as "data files" so it
- actually may not matter whether it gets 32- or 64-bit versions. But let's
- be on the safe side.) }
- Win32ErrorString($4C783AFB);
- end.
|