我正在使用以下代码从我的应用程序中打开另一个应用程序。
type TShellState = class
SEInfo: TShellExecuteInfo;
AppName: String;
Constructor Create(pSEInfo: TShellExecuteInfo; pAppName: String);
end;
Var
ShellStates: TObjectStack<TShellState>;
Constructor TShellstate.Create(pSEInfo: TShellExecuteInfo; pAppName: string);
begin
inherited Create;
SEInfo := pSEInfo;
AppName := pAppName;
end;
//In Form Create
ShellStates := TObjectStack<TShellState>.create;
ShellStates.OwnsObjects := true;
function DoExecute(Const ExecuteFile: string;
Const ParamString: string;
Modal: Boolean;
UseLocalDir: Boolean = false;
NoCloseProc: Boolean = true): Boolean;
Var SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
begin
FillChar(SEInfo, SizeOf(SEInfo), 0) ;
SEInfo.cbSize := SizeOf(TShellExecuteInfo) ;
with SEInfo do begin
fMask := SEE_MASK_DEFAULT;
Wnd := Application.Handle;
lpFile := PChar(ExecuteFile) ;
lpParameters := PChar(ParamString) ;
if UseLocalDir then
lpDirectory := PChar(ExtractFilePath(ExecuteFile));
nShow := SW_SHOWNORMAL;
end;
Result := ShellExecuteEx(@SEInfo);
if result then begin
if Modal then begin
if SEInfo.hProcess <> 0 then begin
WaitForSingleObject(SEInfo.hProcess, INFINITE);
CloseHandle(SEInfo.hProcess);
end;
Result := true;
end
else if NoCloseProc then
ShellStates.Push(TShellState.Create(SEInfo, ExecuteFile));
end;
end;
如果NoCloseProc为真,我将SEInfo记录放入堆栈。
当我关闭主程序时,我希望能够使用SEInfo中的字段来标识接收WM_CLOSE消息的窗口。
while ShellStates.Count > 0 do begin
ShellState := ShellStates.Peek;
SendMessage(ShellState.SEInfo.Wnd, WM_CLOSE,0,0);
ShellStates.Pop;
end
但是hProcess和Wnd都是0,所以看起来我必须使用文件名来定位窗口。有没有更直接的方法?我尝试使用FindWindow API调用SEInfo.lpFile,但是返回0。
1条答案
按热度按时间xwmevbvl1#
当我关闭主程序时,我希望能够使用SEInfo中的字段来标识接收WM_CLOSE消息的窗口。
ShellExecuteEx()
没有为此目的提供单个字段,因此您必须查找要与之交互的窗口。还要注意的是,如果你试图退出一个派生的程序,发送
WM_CLOSE
可能并不总是能成功,想象一下一个文本编辑器,它提示用户保存挂起的更改,如果用户取消提示,编辑器会继续运行,所以,如果你想强制关闭,考虑发送WM_QUIT
而不是WM_CLOSE
。StackOverflow有几个与关闭外部进程相关的问题,例如:How to gracefully terminate a process?
Win32 API For Shutting Down Another Process Elegantly?
How do I gracefully close another application?
仅举几例。
但是hProcess和Wnd都是0
Wnd
字段是仅输入字段,它指定ShellExecute()
在设置/执行指定操作时可能显示的任何UI对话框的所有者窗口。该字段不接收属于正在启动的进程的任何窗口。温德
类型:HWND
可选。所有者窗口的句柄,用于显示和定位系统在执行此函数时可能生成的任何UI。
hProcess
字段为0,因为您没有在fMask
字段中指定SEE_MASK_NOCLOSEPROCESS
标志:f屏蔽
类型:ULONG
下列一个或多个值的组合,指示其他结构成员的内容和有效性:
| 价值|意义|
| - ------|- ------|
| 参见面罩关闭过程(0x00000040)|用于指示hProcess成员接收进程句柄。此句柄通常用于允许应用程序查明用ShellExecuteEx创建的进程何时终止。在某些情况下,例如通过DDE对话满足执行要求时,将不返回句柄。调用应用程序负责在不再需要句柄时将其关闭。|
所以看起来我必须用文件名来定位窗口。有没有更直接的方法?
使用
SEE_MASK_NOCLOSEPROCESS
标志时,可以使用EnumWindows()
查找属于返回的hProcess
字段所表示的进程的窗口。可以使用GetProcessId()
从hProcess
字段获取ProcessID,然后让enumeration callback使用GetWindowThreadProcessId()
比较窗口ProcessID。我尝试对SEInfo.lpFile使用API调用,但返回0。
当然,因为大多数应用程序一开始都不会在窗口标题中显示文件名,而显示文件名的应用程序往往也会显示其他信息,比如应用程序名称。