Inno-Setup-issrc/Projects/Src/SetupLdrAndSetup.RedirFunc.pas

621 lines
20 KiB
ObjectPascal
Raw Permalink Normal View History

2024-08-06 13:54:25 +02:00
unit SetupLdrAndSetup.RedirFunc;
2011-10-06 20:53:09 +02:00
{
Inno Setup
Copyright (C) 1997-2025 Jordan Russell
2011-10-06 20:53:09 +02:00
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.
2011-10-06 20:53:09 +02:00
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;
2011-10-06 20:53:09 +02:00
type
TPreviousFsRedirectionState = record
DidDisable: Boolean;
OldValue: Pointer;
end;
function AreFsRedirectionFunctionsAvailable: Boolean;
2011-10-06 20:53:09 +02:00
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;
2011-10-06 20:53:09 +02:00
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
2024-08-04 19:59:25 +02:00
Shared.CommonFunc, PathFunc;
2011-10-06 20:53:09 +02:00
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.
2024-03-29 08:00:28 +01:00
Returns True if successful, False if not. For extended error information when
False is returned, call GetLastError. }
2011-10-06 20:53:09 +02:00
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
2024-03-29 08:00:28 +01:00
{ Should never happen }
2011-10-06 20:53:09 +02:00
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;
2011-10-06 20:53:09 +02:00
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);
2011-10-06 20:53:09 +02:00
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;
2011-10-06 20:53:09 +02:00
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);
2011-10-06 20:53:09 +02:00
{ 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.