如何使用重新启动管理器在Inno Setup卸载中关闭然后重新启动explorer.exe?

用户名

是否有人知道一个示例,或者可以提供一个示例,说明如何在Inno Setup的卸载过程开始时使用Windows内置的Restart Manager关闭explorer.exe,然后在删除文件后立即重新启动它?我有一些外壳程序项,即使取消注册后仍会分配它们,并且在explorer.exe关闭之前无法删除。

TIA!

用户名

这是一个如何做的例子:

{ Example how to use RestartManager and Offer Option to Delete App Data during Uninstall of Inno Setup }
{ Combined multiple open source ISS code found with some custom changes }
{ This could probably be cleaned up a bit, my goal was to get something to work. }
{ I also stripped it down a bit as I had multiple applications and data so hope }
{ everything removed without an issue, but I'm sure you can figure it out if so }

{-------------------------------------------------------------------------}

{ Copies a NULL-terminated array of characters to a string. }
function ArrayToString(Chars:array of Char):String;
var
    Len,i:Longint;
begin
    Len:=GetArrayLength(Chars);
    SetLength(Result,Len);
    i:=0;
    while (i<Len) and (Chars[i]<>#0) do begin
        Result[i+1]:=Chars[i];
        i:=i+1;
    end;
    SetLength(Result,i);
end;

{-------------------------------------------------------------------------}

type
    LONG      = Longint;
    ULONG     = Cardinal;
    IdList=array of DWORD;
    ProcessEntry=record
        ID:DWORD;
        Name:String;
        Restartable,ToTerminate:Boolean;
    end;
    ProcessList=array of ProcessEntry;

{
    Code for Windows Vista and above
}

const
    { Return codes. }
    ERROR_SUCCESS        = 0;
    ERROR_MORE_DATA      = 234;
    INVALID_HANDLE_VALUE = -1;

    CCH_RM_SESSION_KEY  = 32;
    CCH_RM_MAX_APP_NAME = 255;
    CCH_RM_MAX_SVC_NAME = 63;

    RmUnknownApp  = 0;    { The application cannot be classified as any other type. An application of this type can only be shut down by a forced shutdown. }
    RmMainWindow  = 1;    { A Windows application run as a stand-alone process that displays a top-level window. }
    RmOtherWindow = 2;    { A Windows application that does not run as a stand-alone process and does not display a top-level window. }
    RmService     = 3;    { The application is a Windows service. }
    RmExplorer    = 4;    { The application is Windows Explorer. }
    RmConsole     = 5;    { The application is a stand-alone console application. }
    RmCritical    = 1000; { A system restart is required to complete the installation because a process cannot be shut down. }

    RmStatusUnknown        = $0000;
    RmStatusRunning        = $0001;
    RmStatusStopped        = $0002;
    RmStatusStoppedOther   = $0004;
    RmStatusRestarted      = $0008;
    RmStatusErrorOnStop    = $0010;
    RmStatusErrorOnRestart = $0020;
    RmStatusShutdownMasked = $0040;
    RmStatusRestartMasked  = $0080;

    RmForceShutdown          = $0001;
    RmShutdownOnlyRegistered = $0010;

type
    SessionKey=array[1..CCH_RM_SESSION_KEY+1] of Char;

    FILETIME=record
        dwLowDateTime,dwHighDateTime:DWORD;
    end;
    RM_UNIQUE_PROCESS=record
        dwProcessId:DWORD;
        ProcessStartTime:FILETIME;
    end;
    RM_APP_TYPE=DWORD;
    RM_PROCESS_INFO=record
        Process:RM_UNIQUE_PROCESS;
        strAppName:array[1..CCH_RM_MAX_APP_NAME+1] of Char;
        strServiceShortName:array[1..CCH_RM_MAX_SVC_NAME+1] of Char;
        ApplicationType:RM_APP_TYPE;
        AppStatus:ULONG;
        TSSessionId:DWORD;
        bRestartable:BOOL;
    end;
    RM_WRITE_STATUS_CALLBACK=DWORD;

function RmStartSession(var pSessionHandle:DWORD;dwSessionFlags:DWORD;strSessionKey:SessionKey):DWORD;
external '[email protected] stdcall delayload';

function RmEndSession(dwSessionHandle:DWORD):DWORD;
external '[email protected] stdcall delayload';

function RmRegisterResources(dwSessionHandle:DWORD;hFiles:UINT;rgsFilenames:TArrayOfString;nApplications:UINT;rgApplications:array of RM_UNIQUE_PROCESS;nServices:UINT;rgsServiceNames:TArrayOfString):DWORD;
external '[email protected] stdcall delayload';

function RmGetList(dwSessionHandle:DWORD;var pnProcInfoNeeded,pnProcInfo:UINT;rgAffectedApps:array of RM_PROCESS_INFO;var lpdwRebootReasons:DWORD):DWORD;
external '[email protected] stdcall delayload';

function RmShutdown(dwSessionHandle:DWORD;lActionFlags:ULONG;fnStatus:RM_WRITE_STATUS_CALLBACK):DWORD;
external '[email protected] stdcall delayload';

function RmRestart(dwSessionHandle:DWORD;dwRestartFlags:DWORD;fnStatus:RM_WRITE_STATUS_CALLBACK):DWORD;
external '[email protected] stdcall delayload';


var

  Processes: ProcessList;
  RestartManagerHandle:DWORD;

{-------------------------------------------------------------------------}

{ Returns a list of running processes that currectly use one of the specified modules. }
{ Each module has to be a full path and filename to a DLL. }
function FindProcessesUsingModules(Modules:TArrayOfString;var Processes:ProcessList):DWORD;
var
    Handle:DWORD;
    Name:SessionKey;
    Apps:array of RM_UNIQUE_PROCESS;
    Services:TArrayOfString;
    Path:String;
    PathLength:DWORD;
    Needed,Have,i:UINT;
    AppList:array of RM_PROCESS_INFO;
    RebootReason:DWORD;
    Success:DWORD;
begin
    SetArrayLength(Processes,0);
    Result:=INVALID_HANDLE_VALUE;

    { NULL-terminate the array of chars. }
    Name[CCH_RM_SESSION_KEY+1]:=#0;
    if RmStartSession(Handle,0,Name)<>ERROR_SUCCESS then begin
        Exit;
    end;

    if RmRegisterResources(Handle,GetArrayLength(Modules),Modules,0,Apps,0,Services)=ERROR_SUCCESS then begin
        { Reallocate the arrays until they are large enough to hold the process information. }
        Needed:=1;
        repeat
            Have:=Needed;
            SetArrayLength(AppList,Have);
            Success:=RmGetList(Handle,Needed,Have,AppList,RebootReason);
        until (Success<>ERROR_MORE_DATA) or (Have>=Needed);

        if (Success=ERROR_SUCCESS) and (Needed>0) then begin
            for i:=0 to Needed-1 do begin
                { append to end of list }
                Have:=GetArrayLength(Processes);
                SetArrayLength(Processes,Have+1);
                { assign values to new entry }
                Processes[Have].ID:=AppList[i].Process.dwProcessId;
                Processes[Have].Name:=ArrayToString(AppList[i].strAppName);
                Processes[Have].Restartable:=AppList[i].bRestartable;
                Processes[Have].ToTerminate:=True;
            end;
            Result:=Handle;
        end;
    end;

    if (Result=INVALID_HANDLE_VALUE) then
      RmEndSession(Handle);

end;

{-------------------------------------------------------------------------}
{ Returns a list of running processes that currectly use the specified module. 
{ The module has to be a full path and filename to a DLL.  This starts the }
{ RestartManager and returns its handle or INVALID_HANDLE_VALUE if failed  }
{ or nothing has lock }
function FindProcessesUsingModule(Module:String;var Processes:ProcessList):DWORD;
var
    Modules:TArrayOfString;
begin
    SetArrayLength(Modules,1);
    Modules[0]:=Module;
    Result:=FindProcessesUsingModules(Modules,Processes);
end;


{-------------------------------------------------------------------------}

var
  UninstallDelDataPage: TNewNotebookPage;
  UninstallConfirmPage: TNewNotebookPage;
  UninstallProcessListPage: TNewNotebookPage;
  UninstallBackButton: TNewButton;
  UninstallNextButton: TNewButton;

  UninstallAutoCloseRB: TNewRadioButton;

  DeleteAppDataCheckBox: TNewCheckBox;
  AppData: String;

{-------------------------------------------------------------------------}

procedure UpdateUninstallWizard;
begin
  if UninstallProgressForm.InnerNotebook.ActivePage = UninstallDelDataPage then
  begin
    UninstallProgressForm.PageNameLabel.Caption := 'Select Data Uninstall Options';
    UninstallProgressForm.PageDescriptionLabel.Caption := 'What data, if any, should be deleted?';
  end
    else
  if UninstallProgressForm.InnerNotebook.ActivePage = UninstallConfirmPage then
  begin
    UninstallProgressForm.PageNameLabel.Caption := 'Confirm Uninstall';
    UninstallProgressForm.PageDescriptionLabel.Caption := 'Confirm the uninstall options below.';
  end
    else
  if UninstallProgressForm.InnerNotebook.ActivePage = UninstallProcessListPage then
  begin
    UninstallProgressForm.PageNameLabel.Caption := 'Preparing to Uninstall';
    UninstallProgressForm.PageDescriptionLabel.Caption := 'Uninstall is preparing to uninstall {#MyAppName} from your computer.'
  end;

  UninstallBackButton.Visible :=
    (UninstallProgressForm.InnerNotebook.ActivePage = UninstallConfirmPage) or 
    ((UninstallProgressForm.InnerNotebook.ActivePage = UninstallDelDataPage) and (UninstallProcessListPage<>nil));

  if (UninstallProgressForm.InnerNotebook.ActivePage = UninstallDelDataPage) or 
      ((UninstallProgressForm.InnerNotebook.ActivePage = UninstallProcessListPage) and (UninstallDelDataPage<>nil)) then
  begin
    UninstallNextButton.Caption := SetupMessage(msgButtonNext);
    UninstallNextButton.ModalResult := mrNone;
  end
    else
  begin
    UninstallNextButton.Caption := 'Uninstall';
    { Make the "Uninstall" button break the ShowModal loop }
    UninstallNextButton.ModalResult := mrOK;
  end;
end;  


{-------------------------------------------------------------------------}

procedure CreateUninstallConfirmPage();
var
  PageText: TNewStaticText;
begin

   { Create the second page }

    if (UninstallConfirmPage<>nil) then UninstallConfirmPage.Free();
    UninstallConfirmPage := TNewNotebookPage.Create(UninstallProgressForm);
    UninstallConfirmPage.Notebook := UninstallProgressForm.InnerNotebook;
    UninstallConfirmPage.Parent := UninstallProgressForm.InnerNotebook;
    UninstallConfirmPage.Align := alClient;

    PageText := TNewStaticText.Create(UninstallProgressForm);
    PageText.Parent := UninstallConfirmPage;
    PageText.Top := UninstallProgressForm.StatusLabel.Top;
    PageText.Left := UninstallProgressForm.StatusLabel.Left;
    PageText.Width := UninstallProgressForm.StatusLabel.Width;
    PageText.Height := UninstallProgressForm.StatusLabel.Height;
    PageText.AutoSize := True;
    PageText.Wordwrap := True;
    PageText.ShowAccelChar := False;
    PageText.Font.Size := 9;
    PageText.Caption := 'Click Uninstall to continue with removal of {#MyAppName}.';

    if DeleteAppDataCheckBox.Checked then
      PageText.Caption := PageText.Caption + #13#10#10 + 'WARNING: Application data will be deleted.';


end;


{-------------------------------------------------------------------------}

procedure UninstallNextButtonClick(Sender: TObject);
begin
  if UninstallProgressForm.InnerNotebook.ActivePage = UninstallConfirmPage then
  begin
    UninstallNextButton.Visible := False;
    UninstallBackButton.Visible := False;
  end
  else 
  begin
    if UninstallProgressForm.InnerNotebook.ActivePage = UninstallDelDataPage then
    begin
      CreateUninstallConfirmPage();
      UninstallProgressForm.InnerNotebook.ActivePage := UninstallConfirmPage;
    end
    else if UninstallDelDataPage<>nil then
    begin
      UninstallProgressForm.InnerNotebook.ActivePage := UninstallDelDataPage;
    end
    else
    begin
      UninstallNextButton.Visible := False;
      UninstallBackButton.Visible := False;
    end;
    UpdateUninstallWizard;
  end;
end;

{-------------------------------------------------------------------------}

procedure UninstallBackButtonClick(Sender: TObject);
begin
  if UninstallProgressForm.InnerNotebook.ActivePage = UninstallConfirmPage then
  begin
    UninstallProgressForm.InnerNotebook.ActivePage := UninstallDelDataPage;
  end
  else if (UninstallProgressForm.InnerNotebook.ActivePage = UninstallDelDataPage) and (UninstallProcessListPage<>Nil) then
  begin
    UninstallProgressForm.InnerNotebook.ActivePage := UninstallProcessListPage;
  end;
  UpdateUninstallWizard;
end;

{-------------------------------------------------------------------------}

procedure InitializeUninstallProgressForm();
var
  PageText: TNewStaticText;
  PageNameLabel: string;
  PageDescriptionLabel: string;
  CancelButtonEnabled: Boolean;
  CancelButtonModalResult: Integer;
  appinstalled: Boolean;
  top : Integer;
  ListBox : TNewListBox;
  i:Integer;
  UninstallNoCloseRB : TNewRadioButton;
begin

  RestartManagerHandle:=FindProcessesUsingModule(ExpandConstant('{app}\MyModule.dll'), Processes);


  if not UninstallSilent then
  begin

    { save labels / description }
    PageNameLabel := UninstallProgressForm.PageNameLabel.Caption;
    PageDescriptionLabel := UninstallProgressForm.PageDescriptionLabel.Caption;

    if RestartManagerHandle<>INVALID_HANDLE_VALUE then
    begin
      UninstallProcessListPage:=TNewNotebookPage.Create(UninstallProgressForm);
      UninstallProcessListPage.Notebook := UninstallProgressForm.InnerNotebook;
      UninstallProcessListPage.Parent := UninstallProgressForm.InnerNotebook;
      UninstallProcessListPage.Align := alClient;

      PageText := TNewStaticText.Create(UninstallProgressForm);
      PageText.Parent := UninstallProcessListPage;
      PageText.Top := UninstallProgressForm.StatusLabel.Top;
      PageText.Left := UninstallProgressForm.StatusLabel.Left;
      PageText.Width := UninstallProgressForm.StatusLabel.Width;
      PageText.Height := UninstallProgressForm.StatusLabel.Height;
      PageText.AutoSize := True;
      PageText.WordWrap := True;
      PageText.ShowAccelChar := False;
      PageText.Caption := 'The following applications are using files that need to be removed by the uninstaller.  It is recommended that you allow Uninstall to automatically close these applications.  After uninstall has completed, it will attempt to restart the applications.';

      ListBox := TNewListBox.Create(UninstallProgressForm);
      ListBox.Parent := UninstallProcessListPage;
      ListBox.Top := PageText.Top + PageText.Height + 16;
      ListBox.Left := PageText.Left;
      ListBox.Width := PageText.Width;
      ListBox.Height := ScaleY(97);
      ListBox.TabStop:=False;

      for i:=0 to GetArraylength(Processes)-1 do
      begin
        ListBox.Items.Add(Processes[i].Name);
      end;
      ListBox.ItemIndex:=-1;

      UninstallAutoCloseRB := TNewRadioButton.Create(UninstallProgressForm);
      UninstallAutoCloseRB .Parent := UninstallProcessListPage;
      UninstallAutoCloseRB .Checked := True;
      UninstallAutoCloseRB .Top := ListBox.Top+ListBox.Height+8;
      UninstallAutoCloseRB .Left := ListBox.Left;
      UninstallAutoCloseRB .Width := ListBox.Width;
      UninstallAutoCloseRB.Font.Size := 9;
      UninstallAutoCloseRB.Caption := '&Automatically close the applications';

      UninstallNoCloseRB := TNewRadioButton.Create(UninstallProgressForm);
      UninstallNoCloseRB .Parent := UninstallProcessListPage;
      UninstallNoCloseRB .Checked := False;
      UninstallNoCloseRB .Top := UninstallAutoCloseRB.Top+UninstallAutoCloseRB.Height+8;
      UninstallNoCloseRB .Left := UninstallAutoCloseRB.Left;
      UninstallNoCloseRB .Width := UninstallAutoCloseRB.Width;
      UninstallNoCloseRB .Font.Size := 9;
      UninstallNoCloseRB .Caption := '&Do not close the applications';



      { make page active }
      UninstallProgressForm.InnerNotebook.ActivePage := UninstallProcessListPage;
    end;

    { work around elevated uninstaller for single user}
    AppData:=GetEnv('AppData');
    Log('AppData reported as' + AppData);

    if AppData<>'' then 
    begin
      appinstalled:=FileExists(ExpandConstant('{app}/myapp.exe'));

      if appinstalled then
      begin

        { Create the first page and make it active }
        UninstallDelDataPage := TNewNotebookPage.Create(UninstallProgressForm);
        UninstallDelDataPage.Notebook := UninstallProgressForm.InnerNotebook;
        UninstallDelDataPage.Parent := UninstallProgressForm.InnerNotebook;
        UninstallDelDataPage.Align := alClient;

        PageText := TNewStaticText.Create(UninstallProgressForm);
        PageText.Parent := UninstallDelDataPage;
        PageText.Top := UninstallProgressForm.StatusLabel.Top;
        PageText.Left := UninstallProgressForm.StatusLabel.Left;
        PageText.Width := UninstallProgressForm.StatusLabel.Width;
        PageText.Height := UninstallProgressForm.StatusLabel.Height;
        PageText.AutoSize := True;
        PageText.WordWrap := True;
        PageText.ShowAccelChar := False;
        PageText.Caption := 'You have the option to delete the data assoicated with App Name';
        
        top:=PageText.Top + PageText.Height + 16;
        if appinstalled then
        begin 
          DeleteAppDataCheckBox := TNewCheckBox.Create(UninstallProgressForm);
          DeleteAppDataCheckBox.Parent := UninstallDelDataPage;
          DeleteAppDataCheckBox.Checked := False;
          DeleteAppDataCheckBox.Top := top;
          DeleteAppDataCheckBox.Left := PageText.Left+10;
          DeleteAppDataCheckBox.Width := PageText.Width - 10;
          DeleteAppDataCheckBox.Font.Size := 9;
          DeleteAppDataCheckBox.Caption := 'Delete all App Data';

          top:=DeleteAppDataCheckBox.Top + DeleteAppDataCheckBox.Height + 8;
        end;

        { set as first page if not already set }
        if UninstallProgressForm.InnerNotebook.ActivePage=UninstallProgressForm.InstallingPage then
          UninstallProgressForm.InnerNotebook.ActivePage:=UninstallDelDataPage;


        { next button }
        UninstallNextButton := TNewButton.Create(UninstallProgressForm);
        UninstallNextButton.Parent := UninstallProgressForm;
        UninstallNextButton.Left := UninstallProgressForm.CancelButton.Left - UninstallProgressForm.CancelButton.Width - ScaleX(10);
        UninstallNextButton.Top := UninstallProgressForm.CancelButton.Top;
        UninstallNextButton.Width := UninstallProgressForm.CancelButton.Width;
        UninstallNextButton.Height := UninstallProgressForm.CancelButton.Height;
        UninstallNextButton.OnClick := @UninstallNextButtonClick;

        { back button }
        UninstallBackButton := TNewButton.Create(UninstallProgressForm);
        UninstallBackButton.Parent := UninstallProgressForm;
        UninstallBackButton.Left := UninstallNextButton.Left - UninstallNextButton.Width - ScaleX(10);
        UninstallBackButton.Top := UninstallProgressForm.CancelButton.Top;
        UninstallBackButton.Width := UninstallProgressForm.CancelButton.Width;
        UninstallBackButton.Height := UninstallProgressForm.CancelButton.Height;
        UninstallBackButton.Caption := SetupMessage(msgButtonBack);
        UninstallBackButton.OnClick := @UninstallBackButtonClick;

        { setup tab order }
        UninstallBackButton.TabOrder := UninstallProgressForm.CancelButton.TabOrder;
        UninstallNextButton.TabOrder := UninstallBackButton.TabOrder + 1;
        UninstallProgressForm.CancelButton.TabOrder := UninstallNextButton.TabOrder + 1;

        { Run our wizard pages } 
        UpdateUninstallWizard;
        CancelButtonEnabled := UninstallProgressForm.CancelButton.Enabled
        UninstallProgressForm.CancelButton.Enabled := True;

        { save value }
        CancelButtonModalResult := UninstallProgressForm.CancelButton.ModalResult;

        { set value to use }
        UninstallProgressForm.CancelButton.ModalResult := mrCancel;

        if UninstallProgressForm.ShowModal = mrCancel then 
        begin
          if RestartManagerHandle<>INVALID_HANDLE_VALUE then
          begin
            RmEndSession(RestartManagerHandle);
            RestartManagerHandle:=INVALID_HANDLE_VALUE;
          end;
          Abort;
        end;

        { Restore the standard page payout }
        UninstallProgressForm.CancelButton.Enabled := CancelButtonEnabled;
        UninstallProgressForm.CancelButton.ModalResult := CancelButtonModalResult;

        UninstallProgressForm.PageNameLabel.Caption := PageNameLabel;
        UninstallProgressForm.PageDescriptionLabel.Caption := PageDescriptionLabel;

        UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage;
      end;
    end;
  end;
end;

{-------------------------------------------------------------------------}
function IsDeleteAppData: Boolean;
begin
  Result:=(DeleteAppDataCheckBox<>nil) and DeleteAppDataCheckBox.Checked;
end;

{-------------------------------------------------------------------------}


procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  ErrorCode: Integer;
  Res : Boolean;
begin
  if CurUninstallStep = usUninstall then
  begin
      if (RestartManagerHandle<>INVALID_HANDLE_VALUE) and (UninstallAutoCloseRB<>nil) and (UninstallAutoCloseRB.Checked) then
        RmShutdown(RestartManagerHandle, 0, 0);
  end
  else if CurUninstallStep = usPostUninstall then
  begin
    if IsDeleteAppData then
    begin
      Res:=DelTree(AppData+'\MyAppDataDir', true, true, true);
      Log('Delete '+AppData+'\MyAppDataDir result: '+IntToStr(Integer(Res)));
    end;

    if (RestartManagerHandle<>INVALID_HANDLE_VALUE) and (UninstallAutoCloseRB<>nil) and (UninstallAutoCloseRB.Checked) then
      RmRestart(RestartManagerHandle, 0, 0);

    if (RestartManagerHandle<>INVALID_HANDLE_VALUE) then
    begin
      RmEndSession(RestartManagerHandle);
      RestartManagerHandle:=INVALID_HANDLE_VALUE;
    end;
  end;
end;

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

无法在Windows XP中重新启动explorer.exe

WiX:如何立即重新启动explorer.exe?

使用Excel VBA重新启动explorer.exe

重新启动崩溃的exe?

在Windows 10中退出时如何重新启动exe?

重新启动网络管理器

如何使用批处理文件重新启动explorer.exe

如何使用批处理文件安全地重新启动explorer.exe

如何重新启动网络管理器小程序

如何重新启动窗口管理器?

登录时Explorer.exe重新启动循环

如何重新启动Rabbitmq中的erl.exe和epmd.exe?

重新启动explorer.exe时如何还原“丢失”的通知图标?

如何在不重新启动explorer.exe的情况下刷新桌面?

在进程启动时杀死explorer.exe,在进程结束时重新启动

冻结后重新启动更新管理器!

重新启动Pantheon文件管理器(elemenaryOS)的命令?

重新启动后重复警报管理器

Inno Setup:在卸载过程中重新启动后删除文件夹

任务栏冻结,无法重新启动explorer.exe

重新启动或关闭?

wix重新启动管理器成功关闭了应用程序,但说不能

如果我通过双击或cmd运行.exe,C#程序将关闭并重新启动

Iexplorer.exe作为自定义用户界面-如果关闭则重新启动?

explorer.exe崩溃后,如何在远程桌面连接上重新启动计算机?

Android在广播接收器中暂停并重新启动警报管理器

如何自动执行Excel的强制关闭,然后重新启动?

重新启动然后使用bash脚本关闭?

为什么apt-get不需要重新启动,而更新管理器却需要重新启动?