【问题标题】:How do I handle Ctrl+C in a Delphi console application?如何在 Delphi 控制台应用程序中处理 Ctrl+C?
【发布时间】:2009-06-16 08:39:46
【问题描述】:

是否有可用的最佳实践和代码 sn-ps 显示如何在 Delphi 控制台应用程序中处理 Ctrl+C?

我发现一些文章提供了一些关于调试器可能出现的问题的信息,包括异常处理、DLL 的卸载、标准输入的关闭和终结for example this CodeGear forums thread

【问题讨论】:

    标签: delphi console


    【解决方案1】:

    来自 Windows API (MSDN):

    BOOL WINAPI SetConsoleCtrlHandler(
        PHANDLER_ROUTINE HandlerRoutine,    // address of handler function  
        BOOL Add    // handler to add or remove 
       );   
    

    HandlerRoutine 函数是控制台进程指定用于处理进程接收到的控制信号的函数。该函数可以有任何名称。

    BOOL WINAPI HandlerRoutine(
        DWORD dwCtrlType    //  control signal type
       );   
    

    在 Delphi 中,处理程序例程应该是这样的:

    function console_handler( dwCtrlType: DWORD ): BOOL; stdcall;
    begin
      // Avoid terminating with Ctrl+C
      if (  CTRL_C_EVENT = dwCtrlType  ) then
        result := TRUE
      else
        result := FALSE;
    end;
    

    【讨论】:

    • 好的,这显示了我如何禁用 Ctrl+C - 我应该澄清我的问题:如何在检测到 Ctrl+C 后执行干净的应用程序关闭?
    • 哦,我明白了。如果您像我的示例一样捕获 Ctrl+C,您可以设置一种“标志”并随时终止正常
    • 我只记得“break := false;”我过去常常在我的 Turbo Pascal 程序中禁用 Ctrl-Break。啊,怀旧...
    • 要记住的重要一点是 HandlerRoutine 在单独的线程中运行。如果您不自己启动任何其他线程,请将 IsMultithread 全局变量设置为 True,以便您执行的任何内存操作都是安全的。
    • 调用约定也很重要。回调函数必须使用 stdcall 调用约定,否则你的程序会莫名其妙地崩溃。
    【解决方案2】:

    我编写了一个小程序来向您展示如何正确停止后台任务。 希望它更清楚。

    ThreadConsoleApplication.dpr 文件内容:

    program ThreadConsoleApplication;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      Windows,
      Classes;
    
    type
      { **
        * Classe TQueueReaderTestApplication
        * }
      TThreadConsoleApplication = class(TThread)
      public
        procedure Execute; override;
    
        constructor Create; virtual;
        destructor Destroy; override;
    
        class function getInstance: TThreadConsoleApplication;
      end;
    
    function TThreadConsoleApplication_consoleCtrlHandler(dwCtrlType: DWORD): BOOL;
      stdcall; forward;
    
    { **
      * Classe TQueueReaderTestApplication
      * }
    
    constructor TThreadConsoleApplication.Create;
    begin
      inherited Create(True { CreateSuspended } );
      Windows.setConsoleCtrlHandler(@TThreadConsoleApplication_consoleCtrlHandler,
        True { add } );
    end;
    
    var
      threadConsoleApplicationInstance: TThreadConsoleApplication = nil;
    
    destructor TThreadConsoleApplication.Destroy;
    begin
      threadConsoleApplicationInstance := nil;
      inherited;
    end;
    
    procedure TThreadConsoleApplication.Execute;
    begin
      System.Writeln('[TThreadConsoleApplication.Execute] begin');
      try
        while not Terminated do
        begin
          System.Writeln('[TThreadConsoleApplication.Execute] running ...');
          Windows.Sleep(1000 { dwMilliseconds } );
        end;
      finally
        System.Writeln('[TThreadConsoleApplication.Execute] end');
      end;
    end;
    
    class function TThreadConsoleApplication.getInstance: TThreadConsoleApplication;
    begin
      if nil = threadConsoleApplicationInstance then
      begin
        threadConsoleApplicationInstance := TThreadConsoleApplication.Create;
      end;
      Result := threadConsoleApplicationInstance;
    end;
    
    function TThreadConsoleApplication_consoleCtrlHandler(dwCtrlType: DWORD): BOOL;
    begin
      Result := False;
      if Windows.CTRL_C_EVENT = dwCtrlType then
      begin
        TThreadConsoleApplication.getInstance.Terminate;
        Result := True;
      end;
    end;
    
    var
      thread: TThread;
    
    begin
      System.Writeln('[program] begin');
      try
        thread := nil;
        try
          thread := TThreadConsoleApplication.getInstance;
          thread.Resume;
          System.Writeln('[program] press a CTRL+C to stop running');
          thread.WaitFor;
        finally
          thread.Free;
        end;
        System.Writeln('[program] end');
      except
        on E: Exception do
        begin
          System.Writeln(System.ErrOutput, '[program] end with error');
          System.Writeln(System.ErrOutput, E.ClassName, ': ', E.Message);
        end;
      end;
      System.Writeln('[program] press a key to quit');
      System.Readln;
    
    end.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      • 2012-03-17
      • 2010-10-20
      相关资源
      最近更新 更多