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

📄 uninstall.pas

📁 源代码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
    { Hide the application window so that we don't end up with two taskbar
      buttons once the second phase starts }
    SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
      SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);

    { Execute the copy of itself ("second phase") }
    ProcessHandle := Exec(TempFile, Format('/SECONDPHASE="%s" /FIRSTPHASEWND=$%x ',
      [NewParamStr(0), Wnd]) + GetCmdTail);

    { Wait till the second phase process unexpectedly dies or is ready
      for the first phase to terminate. }
    repeat until ProcessMsgs or (MsgWaitForMultipleObjects(1,
      ProcessHandle, False, INFINITE, QS_ALLINPUT) <> WAIT_OBJECT_0+1);
    CloseHandle(ProcessHandle);
  finally
    DestroyWindow(Wnd);
  end;
end;

procedure RunSecondPhase;
const
  RemovedMsgs: array[Boolean] of TSetupMessageID =
    (msgUninstalledMost, msgUninstalledAll);
var
  RestartSystem: Boolean;
  Wnd: HWND;
  CompiledCodeData: array[0..5] of String;
  Res, RemovedAll, UninstallNeedsRestart: Boolean;
begin
  RestartSystem := False;

  { Create second phase window }
  Wnd := CreateWindowEx(0, 'STATIC', '', 0, 0, 0, 0, 0, HWND_DESKTOP, 0,
    HInstance, nil);
  Longint(OldWindowProc) := SetWindowLong(Wnd, GWL_WNDPROC,
    Longint(@SecondPhaseWindowProc));

  try
    if DebugWnd <> 0 then
      SetDebugWnd(DebugWnd, True);

    if EnableLogging then begin
      try
        if LogFilename = '' then
          StartLogging('Uninstall')
        else
          StartLoggingWithFixedFilename(LogFilename);
      except
        on E: Exception do begin
          E.Message := 'Error creating log file:' + SNewLine2 + E.Message;
          raise;
        end;
      end;
    end;
    Log('Setup version: ' + SetupTitle + ' version ' + SetupVersion);
    Log('Original Uninstall EXE: ' + UninstExeFile);
    Log('Uninstall DAT: ' + UninstDataFile);
    if UninstMsgFile <> '' then
      Log('Detached uninstall MSG: ' + UninstMsgFile);
    Log('Uninstall command line: ' + GetCmdTail);
    LogFmt('Windows version: %u.%.2u.%u  (NT platform: %s)', [WindowsVersion shr 24,
      (WindowsVersion shr 16) and $FF, WindowsVersion and $FFFF, SYesNo[IsNT]]);

    { Open the .dat file for read access }
    try
      UninstLogFile := TFile.Create(UninstDataFile, fdOpenExisting, faRead, fsNone);
    except
      on E: EFileError do begin
        SetLastError(E.ErrorCode);
        RaiseLastError(FmtSetupMessage1(msgUninstallOpenError,
          UninstDataFile));
      end;
    end;

    { Load contents of the .dat file }
    UninstLog := TExtUninstallLog.Create;
    UninstLog.Load(UninstLogFile, UninstDataFile);
    Title := FmtSetupMessage1(msgUninstallAppFullTitle, UninstLog.AppName);

    { Check if admin privileges are needed to uninstall }
    if (ufAdminInstalled in UninstLog.Flags) and not IsAdminLoggedOn then begin
      AppMessageBox(PChar(SetupMessages[msgOnlyAdminCanUninstall]), PChar(Title),
        MB_OK or MB_ICONEXCLAMATION);
      Abort;
    end;

    { Reopen the .dat file for exclusive, read/write access and keep it
      open for the duration of the uninstall process to prevent a second
      instance of the same uninstaller from running. }
    FreeAndNil(UninstLogFile);
    try
      UninstLogFile := TFile.Create(UninstDataFile, fdOpenExisting, faReadWrite, fsNone);
    except
      on E: EFileError do begin
        SetLastError(E.ErrorCode);
        RaiseLastError(FmtSetupMessage1(msgUninstallOpenError,
          UninstDataFile));
      end;
    end;

    if not UninstLog.ExtractLatestRecData(utCompiledCode, SetupBinVersion, CompiledCodeData) then
      InternalError('Cannot find utCompiledCode record for this version of the uninstaller');
    if DebugWnd <> 0 then
      CompiledCodeData[0] := DebugClientCompiledCodeText;

    { Initialize ConstLeadBytes }
    if Length(CompiledCodeData[1]) <> SizeOf(UninstLeadBytes) then
      InternalError('utCompiledCodeText record is invalid');
    Move(Pointer(CompiledCodeData[1])^, UninstLeadBytes, SizeOf(UninstLeadBytes));
    ConstLeadBytes := @UninstLeadBytes;

    if CompiledCodeData[0] <> '' then begin
      { Setup some global variables which are accessible to [Code] }

      InitMainNonSHFolderConsts;
      TempInstallDir := CreateTempDir;
      Log('Created temporary directory: ' + TempInstallDir);
      if Debugging then
        DebugNotifyTempDir(TempInstallDir);
      LoadSHFolderDLL;

      UninstallExeFilename := UninstExeFile;
      UninstallExpandedAppId := UninstLog.AppId;
      UninstallSilent := InitSilent or InitVerySilent;

      UninstallExpandedApp := CompiledCodeData[2];
      UninstallExpandedGroup := CompiledCodeData[3];
      UninstallExpandedGroupName := CompiledCodeData[4];
      UninstallExpandedLanguage := CompiledCodeData[5];

      CodeRunner := TScriptRunner.Create();
      CodeRunner.OnDllImport := CodeRunnerOnDllImport;
      CodeRunner.OnDebug := CodeRunnerOnDebug;
      CodeRunner.OnDebugIntermediate := CodeRunnerOnDebugIntermediate;
      CodeRunner.OnException := CodeRunnerOnException;
      CodeRunner.LoadScript(CompiledCodeData[0], DebugClientCompiledCodeDebugInfo);
    end;
    try
      try
        if CodeRunner <> nil then begin
          try
            Res := CodeRunner.RunBooleanFunction('InitializeUninstall', [''], False, True);
          except
            Log('InitializeUninstall raised an exception (fatal).');
            raise;
          end;
          if not Res then begin
            Log('InitializeUninstall returned False; aborting.');
            Abort;
          end;
        end;

        { Confirm uninstall }
        if not Silent and not VerySilent then begin
          if MessageBoxFmt1(msgConfirmUninstall, UninstLog.AppName, PChar(Title),
             MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON2) <> ID_YES then
            Abort;
        end;

        CurUninstallStepChanged(usAppMutexCheck, False);

        { Is the app running? }
        while UninstLog.CheckMutexes do
          { Yes, tell user to close it }
          if MessageBoxFmt1(msgUninstallAppRunningError, UninstLog.AppName, PChar(Title),
             MB_OKCANCEL or MB_ICONEXCLAMATION) <> IDOK then
            Abort;

        CurUninstallStepChanged(usUninstall, False);

        { Start the actual uninstall process }
        RemovedAll := UninstLog.PerformUninstall(True, DeleteUninstallDataFiles);

        LogFmt('Removed all? %s', [SYesNo[RemovedAll]]);

        UninstallNeedsRestart := UninstLog.NeedRestart or (ufAlwaysRestart in UninstLog.Flags);
        if (CodeRunner <> nil) and CodeRunner.FunctionExists('UninstallNeedRestart') then begin
          if not UninstallNeedsRestart then begin
            try
              if CodeRunner.RunBooleanFunction('UninstallNeedRestart', [''], False, False) then begin
                UninstallNeedsRestart := True;
                Log('Will restart because UninstallNeedRestart returned True.');
              end;
            except
              Log('UninstallNeedRestart raised an exception.');
              ShowExceptionMsg;
            end;
          end
          else
            Log('Not calling UninstallNeedRestart because a restart has already been deemed necessary.');
        end;

        LogFmt('Need to restart Windows? %s', [SYesNo[UninstallNeedsRestart]]);

        { Wait for the "close timer" on ProgressForm to expire, then
          destroy the window }
        if Assigned(ProgressForm) then begin
          while not ProgressForm.CloseTimerExpired do
            Application.HandleMessage;
          FreeAndNil(ProgressForm);
        end;

        CurUninstallStepChanged(usPostUninstall, True);

        if not UninstallNeedsRestart then begin
          if not Silent and not VerySilent then
            MessageBoxFmt1(RemovedMsgs[RemovedAll], UninstLog.AppName,
              Title, MB_ICONINFORMATION or MB_OK or MB_SETFOREGROUND);
        end
        else begin
          if not NoRestart then begin
            if VerySilent or
               (MessageBoxFmt1(msgUninstalledAndNeedsRestart, UninstLog.AppName,
                  Title, MB_ICONINFORMATION or MB_YESNO or MB_SETFOREGROUND) = ID_YES) then
              RestartSystem := True;
          end;
          if not RestartSystem then
            Log('Will not restart Windows automatically.');
        end;

        CurUninstallStepChanged(usDone, True);
      except
        { Show any pending exception here *before* DeinitializeUninstall
          is called, which could display an exception message of its own }
        ShowExceptionMsg;
        Abort;
      end;
    finally
      if CodeRunner <> nil then begin
        try
          CodeRunner.RunProcedure('DeinitializeUninstall', [''], False);
        except
          Log('DeinitializeUninstall raised an exception.');
          ShowExceptionMsg;
        end;
      end;
    end;
  finally
    CodeRunner.Free;
    UnloadSHFolderDLL;
    if TempInstallDir <> '' then begin
      if Debugging then
        DebugNotifyTempDir('');
      if not DelTree(TempInstallDir, True, True, True, nil, nil, nil) then
        Log('Failed to remove temporary directory: ' + TempInstallDir);
    end;
    EndDebug;
    UninstLog.Free;
    FreeAndNil(UninstLogFile);
    DestroyWindow(Wnd);
  end;

  if RestartSystem then begin
    Log('Restarting Windows.');
    RestartComputer;
  end;
end;

procedure RunUninstaller;
var
  F: TFile;
  UninstallerMsgTail: TUninstallerMsgTail;
begin
  { Set default title; it's set again below after the messages are read }
  Application.Title := 'Uninstall';
  { This is needed for D3+: Must force the application window visible since
    we aren't displaying any forms }
  ShowWindow(Application.Handle, SW_SHOW);

  try
    InitializeCommonVars;

    SetCurrentDir(GetSystemDir);

    UninstExeFile := NewParamStr(0);
    ProcessCommandLine;

    { Initialize messages }
    F := TFile.Create(UninstExeFile, fdOpenExisting, faRead, fsRead);
    try
      F.Seek(F.Size.Lo - SizeOf(UninstallerMsgTail));
      F.ReadBuffer(UninstallerMsgTail, SizeOf(UninstallerMsgTail));
      if UninstallerMsgTail.ID <> UninstallerMsgTailID then begin
        { No valid UninstallerMsgTail record found at the end of the EXE;
          load messages from an external .msg file. }
        UninstMsgFile := PathChangeExt(UninstExeFile, '.msg');
        LoadSetupMessagesAndOptions(UninstMsgFile, 0);
      end
      else
        LoadSetupMessagesAndOptions(UninstExeFile, UninstallerMsgTail.Offset);
    finally
      F.Free;
    end;
    SetMessageBoxCaption(mbInformation, PChar(SetupMessages[msgInformationTitle]));
    SetMessageBoxCaption(mbConfirmation, PChar(SetupMessages[msgConfirmTitle]));
    SetMessageBoxCaption(mbError, PChar(SetupMessages[msgErrorTitle]));
    SetMessageBoxCaption(mbCriticalError, PChar(SetupMessages[msgErrorTitle]));
    Application.Title := SetupMessages[msgUninstallAppTitle];

    { Initialize dialog font name & size it will use }
    InitializeDialogFont;

    { Verify that uninstall data file exists }
    UninstDataFile := PathChangeExt(UninstExeFile, '.dat');
    if not NewFileExists(UninstDataFile) then begin
      MessageBoxFmt1(msgUninstallNotFound, UninstDataFile,
        SetupMessages[msgUninstallAppTitle], MB_ICONSTOP or MB_OK);
      Abort;
    end;

    if not SecondPhase then
      RunFirstPhase
    else
      RunSecondPhase;
  except
    ShowExceptionMsg;
  end;

  Halt(ExitCode);
end;

end.

⌨️ 快捷键说明

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