Delphi - 优雅地关闭服务中创建的进程。 (使用 tprocess / createProcess)
Posted
技术标签:
【中文标题】Delphi - 优雅地关闭服务中创建的进程。 (使用 tprocess / createProcess)【英文标题】:Delphi - Gracefully Closing Created Process in Service. (using tprocess / createProcess) 【发布时间】:2008-11-06 10:19:53 【问题描述】:我有一个用 Delphi 编写的 Windows 服务,它运行许多程序。
在停止服务时,我还想关闭这些程序。最初编写服务时,它工作得很好,但我想我已经更新了 tProcess 组件,现在 - 下级程序没有被关闭。
in tProcess - 这是启动新进程的代码。
if CreateProcess( nil , PChar( FProcess.Command ) , nil , nil , False ,
NORMAL_PRIORITY_CLASS , nil , Directory ,
StartupInfo , ProcessInfo ) then
begin
if FProcess.Wait then
begin
WaitForSingleObject( ProcessInfo.hProcess , Infinite );
GetExitCodeProcess( ProcessInfo.hProcess , ExitCode );
if Assigned( FProcess.FOnFinished ) then
FProcess.FOnFinished( FProcess , ExitCode );
end;
CloseHandle( ProcessInfo.hProcess );
CloseHandle( ProcessInfo.hThread );
end;
由此调用的每个可执行文件都是 Windows GUI 程序(顶部有一个关闭按钮)。
当我停止服务时,我还想停止(而不是杀死)我通过 createProcess 过程启动的程序。
你会怎么做?
【问题讨论】:
启动不是问题吧?那么你或 TProcess 会做些什么来关闭这些程序呢? 【参考方案1】:我会使用JVCL 的TJvCreateProcess 组件,它以优雅的方式包装了win32 的任何与进程相关的功能。这个答案来自 Dont-touch-winapi-unless-really-required 部门:-)
【讨论】:
【参考方案2】:您想枚举与您启动的 ProcessId 匹配的打开窗口并告诉这些窗口关闭。下面是一些示例代码:
uses Windows;
interface
function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; stdcall;
implementation
function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean;
var
vID:DWORD;
begin
GetWindowThreadProcessID(hHwnd, @vID);
if vID = dwData then
begin
PostMessage(hHwnd, WM_CLOSE, 0, 0); //tell window to close gracefully
Result := False; //can stop enumerating
end
else
begin
Result := TRUE; //keep enumerating until you find your id
end;
end;
然后,当您想要关闭已启动的应用程序时,您需要在代码中使用它:
Procedure TerminateMe(YourSavedProcessInfo:TProcessInformation);
var
vExitCode:UINT;
begin
GetExitCodeProcess(YourSavedProcessInfo.hProcess, vExitCode);
if (vExitCode = STILL_ACTIVE) then //launched app still running..
begin
//tell it to close
EnumWindows(@MyTerminateAppEnum, YourSavedProcessInfo.dwProcessId);
if WaitForSingleObject(YourSavedProcessInfo.hProcess, TIMEOUT_VAL) <> WAIT_OBJECT_0 then
begin
if not TerminateProcess(YourSavedProcessInfo.hProcess, 0) then //didn't close, try to terminate
begin
//uh-oh Didn't close, didn't terminate..
end;
end;
end;
CloseHandle(YourSavedProcessInfo.hProcess);
CloseHandle(YourSavedProcessInfo.hThread);
end;
【讨论】:
【参考方案3】:停止进程的唯一通用方法是使用TerminateProcess。但这远非你所能得到的优雅。要优雅地关闭一个进程,您需要告诉该进程您希望它停止,然后希望它服从。不过,一般来说没有办法做到这一点。
对于 GUI 程序,告诉它您希望它停止运行的常用方法是关闭其主窗口。但是,没有“主窗口”的正式概念。一个程序可以有零个或多个窗口,并且无法从外部知道您应该关闭哪个窗口以使程序停止工作。
您可以使用EnumWindows 循环浏览所有窗口并选择属于您的进程的窗口。 (GetWindowThreadProcessId 提供的进程 ID 与 CreateProcess 提供的进程 ID 相同。)
关闭一个窗口可能还不够。该程序可能会显示一个对话框(提示确认,或要求保存更改等)。您需要提前知道如何关闭该对话框。
非 GUI 程序也可能有类似的问题。模拟 Ctrl+C 击键可能就足够了。不过,它可能会以不同的方式捕捉和处理该击键。它可能有一个菜单系统,要求您键入“Q”来退出程序。
简而言之,除非您事先知道该程序期望如何关闭,否则您无法优雅地关闭该程序。
【讨论】:
以上是关于Delphi - 优雅地关闭服务中创建的进程。 (使用 tprocess / createProcess)的主要内容,如果未能解决你的问题,请参考以下文章
k8s 如何利用terminationGracePeriodSeconds 优雅地关闭你的服务?