代码之家  ›  专栏  ›  技术社区  ›  seanyboy

Delphi-优雅地关闭服务中创建的流程。(使用tprocess/createProcess)

  •  1
  • seanyboy  · 技术社区  · 17 年前

    我有一个用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过程启动的程序。

    你会怎么做?

    3 回复  |  直到 17 年前
        1
  •  4
  •   utku_karatas    17 年前

    我会用 TJvCreateProcess 组件 JVCL 它以优雅的方式包装了win32的任何与进程相关的功能。这个答案来自“除非真的需要,否则不要碰winapi”部门:-)

        2
  •  1
  •   Darian Miller    17 年前

    您想枚举与启动的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
  •  1
  •   Rob Kennedy    17 年前

    停止进程的唯一通用方法是使用 TerminateProcess 但这远远不够优雅。要优雅地关闭一个进程,您需要告诉该进程您希望它停止,然后希望它遵守。不过,一般来说,没有办法做到这一点。

    对于GUI程序,告诉它您希望它停止运行的通常方法是关闭其主窗口。不过,没有正式的“主窗口”概念。一个程序可以有零个或多个窗口,并且无法从外部知道应该关闭哪个窗口以使程序停止工作。

    你可以使用 EnumWindows 循环浏览所有窗口并选择属于您的进程的窗口。(他们将是那些 GetWindowThreadProcessId 给出与CreateProcess给您的进程ID相同的进程ID。)

    关闭一个窗口可能还不够。程序可能会显示一个对话框(提示确认,或要求保存更改等)。您需要提前知道如何关闭该对话框。

    非GUI程序也可能存在类似的问题。这可能足以模拟Ctrl+C按键。不过,它可能会以不同的方式捕捉和处理击键。它可能有一个菜单系统,要求您键入“Q”退出程序。

    简而言之,除非你事先知道程序预计如何关闭,否则你无法优雅地关闭程序。

    推荐文章