📄 install.pas
字号:
for CurDirNumber := 0 to Entries[seDir].Count-1 do
with PSetupDirEntry(Entries[seDir][CurDirNumber])^ do begin
if ShouldProcessEntry(WizardComponents, WizardTasks, Components, Tasks, Languages, Check) then begin
DebugNotifyEntry(seDir, CurDirNumber);
NotifyBeforeInstallEntry(BeforeInstall);
Flags := [];
if doUninsNeverUninstall in Options then Include(Flags, mdNoUninstall);
if doDeleteAfterInstall in Options then Include(Flags, mdDeleteAfterInstall);
if doUninsAlwaysUninstall in Options then Include(Flags, mdAlwaysUninstall);
N := RemoveBackslashUnlessRoot(ExpandConst(DirName));
MakeDir(N, Flags);
AddAttributesToFile(N, Attribs);
ApplyPermissions(N, PermissionsEntry);
NotifyAfterInstallEntry(AfterInstall);
end;
end;
end;
procedure WriteUninstallMsgData(const F: TFile);
var
UninstLangOpts: TUninstLangOptions;
LangEntry: PSetupLanguageEntry;
begin
FillChar(UninstLangOpts, SizeOf(UninstLangOpts), 0);
UninstLangOpts.ID := UninstLangOptionsID;
UninstLangOpts.DialogFontName := LangOptions.DialogFontName;
UninstLangOpts.DialogFontSize := LangOptions.DialogFontSize;
LangEntry := Entries[seLanguage][ActiveLanguage];
F.WriteBuffer(LangEntry.Data[1], Length(LangEntry.Data));
F.WriteBuffer(UninstLangOpts, SizeOf(UninstLangOpts));
end;
procedure MarkExeHeader(const F: TFile; const ModeID: Longint);
begin
F.Seek(SetupExeModeOffset);
F.WriteBuffer(ModeID, SizeOf(ModeID));
end;
procedure BindUninstallMsgDataToExe(const F: TFile);
var
UninstallerMsgTail: TUninstallerMsgTail;
begin
UninstallerMsgTail.ID := UninstallerMsgTailID;
UninstallerMsgTail.Offset := F.Size.Lo;
F.SeekToEnd;
WriteUninstallMsgData(F);
F.WriteBuffer(UninstallerMsgTail, SizeOf(UninstallerMsgTail));
end;
procedure ProcessFileEntry(const CurFile: PSetupFileEntry;
ASourceFile, ADestName: String; const FileLocationFilenames: TStringList;
const AExternalSize: Integer64);
procedure InstallFont(const Filename, FontName: String;
const AddToFontTableNow: Boolean);
var
K: HKEY;
LastError: DWORD;
begin
if IsNT then begin
if not SetIniString('Fonts', FontName, Filename, '') then
LogFmt('Failed to create [Fonts] entry in WIN.INI. (%d)', [GetLastError]);
end
else begin
if RegOpenKeyEx(HKEY_LOCAL_MACHINE, NEWREGSTR_PATH_SETUP + '\Fonts', 0,
KEY_SET_VALUE, K) = ERROR_SUCCESS then begin
if RegSetValueEx(K, PChar(FontName), 0, REG_SZ, PChar(Filename),
Length(Filename)+1) <> ERROR_SUCCESS then
Log('Failed to set value in Fonts registry key.');
RegCloseKey(K);
end
else
Log('Failed to open Fonts registry key.');
end;
if AddToFontTableNow then begin
LastError := 0;
repeat
SetLastError(0); { does AddFontResource set last error code? }
if AddFontResource(PChar(Filename)) <> 0 then begin
SendNotifyMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
Break;
end;
LastError := GetLastError;
until AbortRetryIgnoreMsgBox(FmtSetupMessage(msgErrorFunctionFailed,
['AddFontResource', IntToStr(LastError)]),
SetupMessages[msgEntryAbortRetryIgnore]);
end;
end;
procedure SetFileLocationFilename(const LocationEntry: Integer;
Filename: String);
var
LowercaseFilename: String;
Hash: Longint;
I: Integer;
begin
Filename := PathExpand(Filename);
LowercaseFilename := PathLowercase(Filename);
Hash := GetCRC32(LowercaseFilename[1], Length(LowercaseFilename));
{ If Filename was already associated with another LocationEntry,
disassociate it. If we *don't* do this, then this script won't
produce the expected result:
[Files]
Source: "fileA"; DestName: "file2"
Source: "fileB"; DestName: "file2"
Source: "fileA"; DestName: "file1"
1. It extracts fileA under the name "file2"
2. It extracts fileB under the name "file2"
3. It copies file2 to file1, thinking a copy of fileA was still
stored in file2.
}
for I := 0 to FileLocationFilenames.Count-1 do
if (Longint(FileLocationFilenames.Objects[I]) = Hash) and
(PathLowercase(FileLocationFilenames[I]) = LowercaseFilename) then begin
FileLocationFilenames[I] := '';
FileLocationFilenames.Objects[I] := nil;
Break;
end;
FileLocationFilenames[LocationEntry] := Filename;
FileLocationFilenames.Objects[LocationEntry] := Pointer(Hash);
end;
procedure ApplyPermissions(const Filename: String; const PermsEntry: Integer);
var
Attr: DWORD;
P: PSetupPermissionEntry;
begin
if PermsEntry <> -1 then begin
Attr := GetFileAttributes(PChar(Filename));
if (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0) then begin
LogFmt('Setting permissions on file: %s', [Filename]);
P := Entries[sePermission][PermsEntry];
if not GrantPermissionOnFile(Filename, TGrantPermissionEntry(Pointer(P.Permissions)^),
Length(P.Permissions) div SizeOf(TGrantPermissionEntry)) then
Log('Failed to set permissions on file.');
end;
end;
end;
var
ProgressUpdated: Boolean;
PreviousProgress: Integer64;
LastOperation: String;
CurFileLocation: PSetupFileLocationEntry;
SourceFile, DestFile, TempFile, FontFilename: String;
DestFileExists, DestFileExistedBefore, CheckedDestFileExistedBefore,
TempFileLeftOver, AllowFileToBeDuplicated, ReplaceOnRestart: Boolean;
ExistingFileAttr: Integer;
Failed: String;
CurFileVersionInfoValid: Boolean;
CurFileVersionInfo, ExistingVersionInfo: TFileVersionNumbers;
CurFileDateValid, ExistingFileDateValid: Boolean;
CurFileMD5, ExistingFileMD5: TMD5Digest;
AllowTimeStampComparison: Boolean;
DeleteFlags: Longint;
CurFileDate, ExistingFileDate: TFileTime;
RegisterRec: PRegisterFilesListRec;
RetriesLeft: Integer;
LastError: DWORD;
DestF, SourceF: TFile;
label Retry, Skip;
begin
Log('-- File entry --');
CheckedDestFileExistedBefore := False;
DestFileExistedBefore := False; { prevent warning }
if CurFile^.LocationEntry <> -1 then
CurFileLocation := PSetupFileLocationEntry(Entries[seFileLocation][CurFile^.LocationEntry])
else
CurFileLocation := nil;
Retry:
TempFile := '';
TempFileLeftOver := False;
ProgressUpdated := False;
PreviousProgress := CurProgress;
LastOperation := '';
Failed := '';
try
try
ReplaceOnRestart := False;
DeleteFlags := 0;
if foRegisterServer in CurFile^.Options then
DeleteFlags := DeleteFlags or utDeleteFile_RegisteredServer;
if foRegisterTypeLib in CurFile^.Options then
DeleteFlags := DeleteFlags or utDeleteFile_RegisteredTypeLib;
if foUninsRestartDelete in CurFile^.Options then
DeleteFlags := DeleteFlags or utDeleteFile_RestartDelete;
if foUninsRemoveReadOnly in CurFile^.Options then
DeleteFlags := DeleteFlags or utDeleteFile_RemoveReadOnly;
FontFilename := '';
{ Determine the destination filename }
case CurFile^.FileType of
ftUninstExe: DestFile := UninstallExeFilename;
else
if ADestName = '' then
DestFile := ExpandConst(CurFile^.DestName)
else
DestFile := ADestName;
end;
{ Update the filename label }
SetFilenameLabelText(DestFile, True);
LogFmt('Dest filename: %s', [DestFile]);
DestFileExists := NewFileExists(DestFile);
if not CheckedDestFileExistedBefore then begin
DestFileExistedBefore := DestFileExists;
CheckedDestFileExistedBefore := True;
end;
if DestFileExistedBefore then
DeleteFlags := DeleteFlags or utDeleteFile_ExistedBeforeInstall;
if Assigned(CurFileLocation) then begin
if foTimeStampInUTC in CurFileLocation^.Flags then
CurFileDate := CurFileLocation^.TimeStamp
else
LocalFileTimeToFileTime(CurFileLocation^.TimeStamp, CurFileDate);
CurFileDateValid := True;
end
else
CurFileDateValid := GetFileDateTime(ASourceFile, CurFileDate);
if CurFileDateValid then
LogFmt('Time stamp of our file: %s', [FileTimeToStr(CurFileDate)])
else
Log('Time stamp of our file: (failed to read)');
if foDontCopy in CurFile^.Options then begin
Log('Skipping due to "dontcopy" flag.');
goto Skip;
end;
if DestFileExists then begin
Log('Dest file exists.');
if foOnlyIfDoesntExist in CurFile^.Options then begin
Log('Skipping due to "onlyifdoesntexist" flag.');
goto Skip;
end;
LastOperation := SetupMessages[msgErrorReadingExistingDest];
ExistingFileDateValid := GetFileDateTime(DestFile, ExistingFileDate);
if ExistingFileDateValid then
LogFmt('Time stamp of existing file: %s', [FileTimeToStr(ExistingFileDate)])
else
Log('Time stamp of existing file: (failed to read)');
{ Skip if it's a protected system file.
Note: We don't call IsProtectedSystemFile anymore on Windows Me
even though it supports WFP. Two users reported that installs ran
very slowly on 4.2.1, and with the help of one of the users, the
cause was narrowed down to this call. For him, it was taking 6
seconds per call. I have no idea what would cause it to be so
slow; it only took a few milliseconds in my tests on Windows Me. }
if (CurFile^.FileType = ftUserFile) and IsNT then
if IsProtectedSystemFile(DestFile) then begin
Log('File is protected by Windows File Protection. Skipping.');
goto Skip;
end;
{ Compare version info }
if not(foIgnoreVersion in CurFile^.Options) then begin
AllowTimeStampComparison := False;
{ Read version info of file being installed }
if Assigned(CurFileLocation) then begin
CurFileVersionInfoValid := foVersionInfoValid in CurFileLocation^.Flags;
CurFileVersionInfo.MS := CurFileLocation^.FileVersionMS;
CurFileVersionInfo.LS := CurFileLocation^.FileVersionLS;
end
else
CurFileVersionInfoValid := GetVersionNumbers(PathExpand(ASourceFile),
CurFileVersionInfo);
if CurFileVersionInfoValid then
LogFmt('Version of our file: %u.%u.%u.%u',
[LongRec(CurFileVersionInfo.MS).Hi, LongRec(CurFileVersionInfo.MS).Lo,
LongRec(CurFileVersionInfo.LS).Hi, LongRec(CurFileVersionInfo.LS).Lo])
else
Log('Version of our file: (none)');
{ Does the existing file have version info? }
if GetVersionNumbers(PathExpand(DestFile), ExistingVersionInfo) then begin
{ If the file being installed has no version info, or the existing
file is a newer version... }
LogFmt('Version of existing file: %u.%u.%u.%u',
[LongRec(ExistingVersionInfo.MS).Hi, LongRec(ExistingVersionInfo.MS).Lo,
LongRec(ExistingVersionInfo.LS).Hi, LongRec(ExistingVersionInfo.LS).Lo]);
if not CurFileVersionInfoValid or
((ExistingVersionInfo.MS > CurFileVersionInfo.MS) or
((ExistingVersionInfo.MS = CurFileVersionInfo.MS) and
(ExistingVersionInfo.LS > CurFileVersionInfo.LS))) then begin
if not(foPromptIfOlder in CurFile^.Options) or
(MsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
'', mbError, MB_YESNO) <> ID_NO) then begin
Log('Existing file is a newer version. Skipping.');
goto Skip;
end;
end
else begin
{ If the existing file and the file being installed are the same
version... }
if (ExistingVersionInfo.MS = CurFileVersionInfo.MS) and
(ExistingVersionInfo.LS = CurFileVersionInfo.LS) and
not(foOverwriteSameVersion in CurFile^.Options) then begin
if foReplaceSameVersionIfContentsDiffer in CurFile^.Options then begin
{ Get the two files' MD5 sums and compare them }
if TryToGetMD5OfFile(DestFile, ExistingFileMD5) then begin
if Assigned(CurFileLocation) then
CurFileMD5 := CurFileLocation^.MD5Sum
else begin
LastOperation := SetupMessages[msgErrorReadingSource];
{ This GetMD5OfFile call could raise an exception, but
it's very unlikely since we were already able to
successfully read the file's version info. }
CurFileMD5 := GetMD5OfFile(ASourceFile);
LastOperation := SetupMessages[msgErrorReadingExistingDest];
end;
{ If the two files' MD5 sums are equal, skip the file }
if MD5DigestsEqual(ExistingFileMD5, CurFileMD5) then begin
Log('Existing file''s MD5 sum matches our file. Skipping.');
goto Skip;
end;
Log('Existing file''s MD5 sum is different from our file. Proceeding.');
end
else
Log('Failed to read existing file''s MD5 sum. Proceeding.');
end
else begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -