⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 install.pas

📁 源代码
💻 PAS
📖 第 1 页 / 共 5 页
字号:
                    { Skip the file or fall back to time stamp comparison }
                    if not(foCompareTimeStamp in CurFile^.Options) then begin
                      Log('Same version. Skipping.');
                      goto Skip;
                    end;
                    AllowTimeStampComparison := True;
                  end;
                end;
              end;
            end
            else begin
              Log('Version of existing file: (none)');
              { If neither the existing file nor our file have version info,
                allow time stamp comparison }
              if not CurFileVersionInfoValid then
                AllowTimeStampComparison := True;
            end;
          end
          else begin
            { When foIgnoreVersion is in Options, always allow time stamp
              comparison }
            AllowTimeStampComparison := True;
          end;

          { Fall back to comparing time stamps if needed }
          if AllowTimeStampComparison and
             (foCompareTimeStamp in CurFile^.Options) then begin
            if not CurFileDateValid or not ExistingFileDateValid then begin
              { If we failed to read one of the time stamps, do the safe thing
                and just skip the file }
              Log('Couldn''t read time stamp. Skipping.');
              goto Skip;
            end;
            if CompareFileTime(ExistingFileDate, CurFileDate) = 0 then begin
              { Same time stamp }
              Log('Same time stamp. Skipping.');
              goto Skip;
            end;
            if CompareFileTime(ExistingFileDate, CurFileDate) > 0 then begin
              { Existing file has a later time stamp }
              if not(foPromptIfOlder in CurFile^.Options) or
                 (MsgBox(DestFile + SNewLine2 + SetupMessages[msgExistingFileNewer],
                  '', mbError, MB_YESNO) <> ID_NO) then begin
                Log('Existing file has a later time stamp. Skipping.');
                goto Skip;
              end;
            end;
          end;

          LastOperation := '';

          { If file already exists and foConfirmOverwrite is in Options, ask
            the user if it's OK to overwrite }
          if (foConfirmOverwrite in CurFile^.Options) and
             (MsgBox(DestFile + SNewLine2 + SetupMessages[msgFileExists],
              '', mbConfirmation, MB_YESNO) <> ID_YES) then begin
            Log('User opted not to overwrite the existing file. Skipping.');
            goto Skip;
          end;

          { Check if existing file is read-only }
          while True do begin
            ExistingFileAttr := GetFileAttributes(PChar(DestFile));
            if (ExistingFileAttr <> -1) and
               (ExistingFileAttr and FILE_ATTRIBUTE_READONLY <> 0) then begin
              if not(foOverwriteReadOnly in CurFile^.Options) and
                 AbortRetryIgnoreMsgBox(DestFile, SetupMessages[msgExistingFileReadOnly]) then begin
                Log('User opted not to strip the existing file''s read-only attribute. Skipping.');
                goto Skip;
              end;
              LastOperation := SetupMessages[msgErrorChangingAttr];
              if SetFileAttributes(PChar(DestFile),
                 ExistingFileAttr and not FILE_ATTRIBUTE_READONLY) then
                Log('Stripped read-only attribute.')
              else
                Log('Failed to strip read-only attribute.');
              if foOverwriteReadOnly in CurFile^.Options then
                Break;  { don't retry }
            end
            else
              Break;
          end;
        end
        else begin
          if (foOnlyIfDestFileExists in CurFile^.Options) and not DestFileExistedBefore then begin
            Log('Skipping due to "onlyifdestfileexists" flag.');
            goto Skip;
          end;
        end;

        Log('Installing the file.');

        { Locate source file }
        SourceFile := ASourceFile;
        { If the file is compressed in the setup package, has the same file
          already been copied somewhere else? If so, just make a duplicate of
          that file instead of extracting it over again. }
        if (SourceFile = '') and
           (FileLocationFilenames[CurFile^.LocationEntry] <> '') and
           NewFileExists(FileLocationFilenames[CurFile^.LocationEntry]) then
          SourceFile := FileLocationFilenames[CurFile^.LocationEntry];
        AllowFileToBeDuplicated := (SourceFile = '');

        { Extract or copy the file to a temporary file. Create the destination
          file's directory if it didn't already exist. }
        LastOperation := SetupMessages[msgErrorCreatingTemp];
        TempFile := GenerateUniqueName(PathExtractPath(PathExpand(DestFile)), '.tmp');
        MakeDir(PathExtractPath(TempFile), []);
        DestF := TFile.Create(TempFile, fdCreateAlways, faWrite, fsNone);
        try
          TempFileLeftOver := True;
          try
            ProgressUpdated := True;
            LastOperation := SetupMessages[msgErrorReadingSource];
            if SourceFile = '' then begin
              { Decompress a file }
              FileExtractor.SeekTo(CurFileLocation^, ExtractorProgressProc);
              LastOperation := SetupMessages[msgErrorCopying];
              FileExtractor.DecompressFile(CurFileLocation^, DestF, ExtractorProgressProc,
                not (foDontVerifyChecksum in CurFile^.Options));
            end
            else begin
              { Copy an external file, or a duplicated non-external file }
              SourceF := TFile.Create(SourceFile, fdOpenExisting, faRead, fsRead);
              try
                LastOperation := SetupMessages[msgErrorCopying];
                if Assigned(CurFileLocation) then
                  CopySourceFileToDestFile(SourceF, DestF, CurFileLocation^.OriginalSize)
                else
                  CopySourceFileToDestFile(SourceF, DestF, AExternalSize);
              finally
                SourceF.Free;
              end;
            end;
          except
            { If an exception occurred, put progress meter back to where it was }
            ProgressUpdated := False;
            SetProgress(PreviousProgress);
            raise;
          end;
          { Set time/date stamp }
          SetFileTime(DestF.Handle, nil, nil, @CurFileDate);
          { If it's the uninstall program, bind the messages }
          if CurFile^.FileType = ftUninstExe then begin
            AllowFileToBeDuplicated := False;
            MarkExeHeader(DestF, SetupExeModeUninstaller);
            if not DetachedUninstMsgFile then
              BindUninstallMsgDataToExe(DestF);
          end;
        finally
          DestF.Free;
        end;

        { If it's a font, unregister the existing one to ensure that Windows
          'notices' the file is being replaced, and to increase the chances
          of the file being unlocked/closed before we replace it. }
        if CurFile^.InstallFontName <> '' then begin
          LastOperation := '';
          FontFilename := ShortenOrExpandFontFilename(DestFile);
          if DestFileExistedBefore then
            RemoveFontResource(PChar(FontFilename));
        end;

        { Delete existing version of file, if any. If it can't be deleted
          because it's in use and the "restartreplace" flag was specified
          on the entry, register it to be replaced when the system is
          restarted. }
        if DestFileExists and (CurFile^.FileType <> ftUninstExe) then begin
          LastOperation := SetupMessages[msgErrorReplacingExistingFile];
          RetriesLeft := 4;
          while not DeleteFile(DestFile) do begin
            { Couldn't delete the existing file... }
            LastError := GetLastError;
            { If the file inexplicably vanished, it's not a problem }
            if LastError = ERROR_FILE_NOT_FOUND then
              Break;
            { Does the error code indicate that it is possibly in use? }
            if (LastError = ERROR_ACCESS_DENIED) or
               (LastError = ERROR_SHARING_VIOLATION) then begin
              if foRestartReplace in CurFile^.Options then begin
                LogFmt('The existing file appears to be in use (%d). ' +
                  'Will replace on restart.', [LastError]);
                LastOperation := SetupMessages[msgErrorRestartReplace];
                NeedsRestart := True;
                RestartReplace(TempFile, DestFile);
                ReplaceOnRestart := True;
                Break;
              end;
              { Automatically retry }
              if RetriesLeft > 0 then begin
                LogFmt('The existing file appears to be in use (%d). ' +
                  'Retrying.', [LastError]);
                Dec(RetriesLeft);
                Sleep(1000);
                ProcessEvents;
                Continue;
              end;
            end;
            { Some other error occurred, or we ran out of tries }
            SetLastError(LastError); 
            Win32ErrorMsg('DeleteFile');
          end;
        end;

        { Rename the temporary file to the new name now, unless the file is
          to be replaced when the system is restarted, or if the file is the
          uninstall program and an existing uninstall program already exists.
          Then set any file attributes. }
        if ReplaceOnRestart or
           ((CurFile^.FileType = ftUninstExe) and DestFileExistedBefore) then begin
          if CurFile^.FileType = ftUninstExe then
            UninstallTempExeFilename := TempFile;
          TempFileLeftOver := False;
          LastOperation := '';
          Log('Leaving temporary file in place for now.');
          if AllowFileToBeDuplicated then
            SetFileLocationFilename(CurFile^.LocationEntry, TempFile);
          AddAttributesToFile(TempFile, CurFile^.Attribs);
        end
        else begin
          LastOperation := SetupMessages[msgErrorRenamingTemp];
          if not MoveFile(PChar(TempFile), PChar(DestFile)) then
            Win32ErrorMsg('MoveFile');
          TempFileLeftOver := False;
          TempFile := '';
          LastOperation := '';
          Log('Successfully installed the file.');
          if AllowFileToBeDuplicated then
            SetFileLocationFilename(CurFile^.LocationEntry, DestFile);
          if foDeleteAfterInstall in CurFile^.Options then
            DeleteFilesAfterInstallList.Add(DestFile);
          { Set file attributes *after* renaming the file since Novell
            reportedly can't rename read-only files. }
          AddAttributesToFile(DestFile, CurFile^.Attribs);
        end;

        { If it's a font, register it }
        if CurFile^.InstallFontName <> '' then begin
          LastOperation := '';
          LogFmt('Registering file as a font ("%s")', [CurFile^.InstallFontName]);
          InstallFont(FontFilename, CurFile^.InstallFontName, not ReplaceOnRestart);
          DeleteFlags := DeleteFlags or utDeleteFile_IsFont;
        end;

        { There were no errors ... }
        LastOperation := '';
        if CurFile^.FileType <> ftUninstExe then begin
          { ... so add to undo list, unless it's the uninstall program. But
            don't add foSharedFile files to the undo list yet. }
          if not(foUninsNeverUninstall in CurFile^.Options) and
             not(foSharedFile in CurFile^.Options) then begin
            UninstLog.Add(utDeleteFile, [DestFile, TempFile,
              CurFile^.InstallFontName, FontFilename], DeleteFlags);
          end;
        end
        else begin
          if UninstallTempExeFilename = '' then
            UninstallExeCreated := ueNew
          else
            UninstallExeCreated := ueReplaced;
        end;

      Skip:
        { If foRegisterServer or foRegisterTypeLib is in Options, add the
          file to RegisterFilesList for registering later.
          Don't attempt to register if the file doesn't exist (which can
          happen if the foOnlyIfDestFileExists flag is used). }
        if ((foRegisterServer in CurFile^.Options) or
            (foRegisterTypeLib in CurFile^.Options)) and
           NewFileExists(DestFile) then begin
          LastOperation := '';
          if foRegisterTypeLib in CurFile^.Options then
            Log('Will register the file (a type library) later.')
          else
            Log('Will register the file (a DLL/OCX) later.');
          New(RegisterRec);
          RegisterRec^.Filename := DestFile;
          RegisterRec^.TypeLib := foRegisterTypeLib in CurFile^.Options;
          RegisterRec^.NoErrorMessages := foNoRegError in CurFile^.Options;
          RegisterFilesList.Add(RegisterRec);
        end;

        { If foSharedFile is in Options, increment the reference count in the
          registry for the file }
        if foSharedFile in CurFile^.Options then begin
          LastOperation := '';
          Log('Incrementing shared file count.');
          IncrementSharedCount(DestFile, DestFileExistedBefore);
          if not(foUninsNeverUninstall in CurFile^.Options) then begin
            DeleteFlags := DeleteFlags or utDeleteFile_SharedFile;
            if foUninsNoSharedFilePrompt in CurFile^.Options then
              DeleteFlags := DeleteFlags or utDeleteFile_NoSharedFilePrompt;
            UninstLog.Add(utDeleteFile, [DestFile, TempFile,
              CurFile^.InstallFontName, FontFilename], DeleteFlags);
          end
          else
            UninstLog.Add(utDecrementSharedCount, [DestFile], 0);
        end;

        { Apply permissions (even if the file wasn't replaced) }
        LastOperation := '';
        if TempFile <> '' then
          ApplyPermissions(TempFile, CurFile^.PermissionsEntry)
        else
          ApplyPermissions(DestFile, CurFile^.PermissionsEntry);
      except
        if ExceptObject is EAbort then
          raise;
        Failed := GetExceptMessage;
      end;
    finally
      { If an exception occurred before TempFile was cleaned up, delete it now }
      if TempFileLeftOver then
        DeleteFile(TempFile);
    end;

    { Was there an exception? Display error message and offer to retry }
    if Failed <> '' then begin
      if (CurFile^.FileType = ftUninstExe) and (UninstallTempExeFilename <> '') then begin
        DeleteFile(UninstallTempExeFilename);
        UninstallTempExeFilename := '';
        UninstallExeCreated := ueNone;
      end;

      if LastOperation <> '' then
        LastOperation := LastOperation + SNewLine;
      if not AbortRetryIgnoreMsgBox(DestFile + SNewLine2 + LastOperation + Failed,
         SetupMessages[msgFileAbortRetryIgnore]) then begin
        if ProgressUpdated then

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -