无法升级的程序启动升级更新程序,更新程序应等待程序完成

Bjo*_*nHH 8 delphi createprocess handle waitforsingleobject shellexecuteex

我有2个应用程序,program.exe和updater.exe,都是用Delphi5编写的.程序在没有admin-rights(并且没有manifest)的情况下运行,updater有一个带有"requireAdministrator"的清单,因为他必须能够在Program-Folder中写入以更新program.exe.

问题是启动更新程序,让他等到程序关闭.我在网上找到了不同的方式,但都没有用(大多数情况下,第一个应用程序启动第二个应用程序并等待第二个应用程序的结束,在我的情况下,第二个应用程序应该等待第一个应用程序的结束).

更新程序应该等待,这很容易
updater.exe

{$R manifest.res}
label.caption:='Wait for program.exe closing';
repeat
    sleep(1000);
until File is not open
ProgramHandle := Read Handle from File
WaitForSingleObject(ProgramHandle,INFINITE);
label.caption:='program.exe CLOSED';
Do updates
Run Code Online (Sandbox Code Playgroud)

方法1
使用CreateProcess启动更新程序:
program.exe

FillChar(siInfo, SizeOf(siInfo), 0);
siInfo.cb := SizeOf(siInfo);

saProcessAttributes.nLength := SizeOf(saProcessAttributes);
saProcessAttributes.lpSecurityDescriptor := nil;
saProcessAttributes.bInheritHandle := TRUE;

saThreadAttributes.nLength := SizeOf(saThreadAttributes);
saThreadAttributes.lpSecurityDescriptor := nil;
saThreadAttributes.bInheritHandle := True;

if CreateProcess(nil,
           PChar('updater.exe'),
           @saProcessAttributes,
           @saThreadAttributes,
           TRUE, NORMAL_PRIORITY_CLASS, nil,
           PChar(ExtractFilePath(Application.ExeName)),
           siInfo, piInfo) then
begin
DuplicateHandle(GetCurrentProcess, GetCurrentProcess,
                piInfo.hProcess, @MyHandle,
                PROCESS_QUERY_INFORMATION, TRUE,
                DUPLICATE_SAME_ACCESS) then
Write MyHandle in a File
end;
Close program
Run Code Online (Sandbox Code Playgroud)

什么都不做,只有当updater没有带有requireAdministrator的清单时才有效.如果我使用explizit admin-rights运行程序,它也可以.

方法2使用ShellExecuteEx启动更新程序:
program.exe

  FillChar(Info, SizeOf(Info), Chr(0));
  Info.cbSize := SizeOf(Info);
  Info.fMask := SEE_MASK_NOCLOSEPROCESS;
  Info.lpVerb := PChar('runas');
  Info.lpFile := PChar('update.exe');
  Info.lpDirectory := nil;
  Info.nShow := SW_RESTORE;
  ShellExecuteEx(@Info);

  MyHandle:=OpenProcess(PROCESS_ALL_ACCESS, False, GetCurrentProcessId())));
  Write MyHandle in a File
  Close program
Run Code Online (Sandbox Code Playgroud)

不行,MyHandle每次运行此程序时都有不同的值(不重新启动程序),因此更新程序无法使用它.

所以我不知道如何启动updater.exe并在文件中写入program.exe的句柄.

我对编程的这些部分不是很熟悉......有人对我的问题有所了解吗?

EPr*_*und 7

您的代码无法正常工作,因为句柄表是每个进程,这意味着第二个进程可能具有指向另一个内核对象的相同句柄.下面是许多可能的解决方案之一:

创建进程2时,将进程1的PID作为参数传递:

procedure CreateUpdater;
var
  Info: TShellExecuteInfo;
begin  
  FillChar(Info, SizeOf(TShellExecuteInfo), 0);
  Info.cbSize := SizeOf(TShellExecuteInfo);
  Info.fMask  := SEE_MASK_NOCLOSEPROCESS;
  Info.lpVerb := PChar('runas');
  Info.lpFile := PChar('Update.exe');
  Info.lpParameters := PChar(IntToStr(GetCurrentProcessId));
  Info.lpDirectory := nil;
  Info.nShow := SW_RESTORE;
  ShellExecuteEx(@Info);
  //NOTE: MISSING ERROR CHECKING!
end;
Run Code Online (Sandbox Code Playgroud)

在Updater中,等待process1终止:

procedure WaitForAndClose;
var
  PID: String;
  AHandle: Cardinal;
  Ret: longbool;
  ExitNumber: DWORD;
begin
  PID:= ParamStr(1);
  if PID <> '' then
  begin
    AHandle:= OpenProcess(PROCESS_QUERY_INFORMATION, False, StrToInt(PID));  
    //NOTE: MISSING ERROR CHECKING!
    try
      repeat
        Ret:= GetExitCodeProcess(AHandle, ExitNumber);
        //NOTE: MISSING ERROR CHECKING!
        Sleep(1000); //define a time to poolling
      until (ExitNumber <> STILL_ACTIVE);
    finally
      CloseHandle(AHandle);
    end;
    //Terminate the process;
    Application.Terminate;        
  end;
end;
Run Code Online (Sandbox Code Playgroud)

您还可以使用WaitForSingleObject以避免轮询:

WaitForSingleObject(AHandle, INFINITE);
//NOTE: MISSING ERROR CHECKING!
Run Code Online (Sandbox Code Playgroud)

但是您需要SYNCHRONIZE访问才能打开进程:

AHandle:= OpenProcess(SYNCHRONIZE, False, StrToInt(PID));
//NOTE: MISSING ERROR CHECKING!
Run Code Online (Sandbox Code Playgroud)

注意:此处没有错误检查.您应该阅读文档并正确检查错误.

注2:我想请你注意你正在泄漏手柄的事实.当你使用SEE_MASK_NOCLOSEPROCESS调用者负责关闭calee的句柄.在你的情况下,我认为你根本不需要那个面具.我会删除它.