我有一个函数允许我启动一个子进程,等到它终止,然后返回一个退出代码。子进程是安装 MSI 包的 Windows Installer(仅显示其安装的当前进度)。从后台线程中调用此函数。
我已经像这样包装了这个函数:
function ShellExec(const Verb, Cmd, Params, Dir: WideString;
const Visible: Bool): Integer;
var
FN: String;
SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
begin
Result:= 1;
FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(TShellExecuteInfo);
with SEInfo do begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(Cmd);
lpParameters := PChar(Params);
lpDirectory := PChar(Dir);
if Visible then
nShow := SW_SHOWNORMAL
else
nShow := SW_HIDE;
end;
if ShellExecuteEx(@SEInfo) then begin
repeat
GetExitCodeProcess(SEInfo.hProcess, ExitCode);
until (ExitCode <> STILL_ACTIVE) or
Application.Terminated;
end else begin
ExitCode:= 1;
end;
Result:= ExitCode;
end;
然后我像这样使用它:
function InstallNodeJs(const Config: TInstConfig): Integer;
var
FN: String;
Params: string;
begin
Result:= 1;
if Config.Is64 then
FN := 'NodeInstall_x64.msi'
else
FN := 'NodeInstall_x86.msi';
FN:= Config.TmpDir + FN;
Params:= '/i "'+FN+'" /norestart /passive';
Result:= ShellExec('', 'msiexec.exe', Params, '', True);
end;
这工作正常,但是它不会暂停来自我的调用应用程序的输入——尽管上述函数中有循环,用户仍然可以点击我的应用程序——然后我的应用程序会进入子进程的顶部。我需要子流程来控制我的应用程序。
该进程从主窗体后面的工作线程中启动。线程使用事件来通知主窗体它的进度。主窗体有几个动画,我仍想继续,但我不希望用户能够在此子应用程序仍在运行时单击返回应用程序。我希望它看起来像一个模态状态。本质上,MSI 进度应该始终在我的应用程序之上。
如何运行此子进程并防止用户返回主应用程序并防止主应用程序在子应用程序之上运行?这是从 Inno Setup 执行相同操作时的默认行为,但我不知道如何在 Delphi 应用程序中执行此操作。