【问题标题】:How to create a console application that does not terminate?如何创建不终止的控制台应用程序?
【发布时间】:2010-04-07 10:57:12
【问题描述】:

在 C++ 中,控制台应用程序可以在其 Winmain 过程中包含消息处理程序。像这样:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;

    #ifdef _DEBUG
    CreateConsole("Title");
    #endif

    hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
    PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
    while(msg.message != WM_QUIT)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if(IsDialogMessage(hwnd, &msg))
                continue;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

    }

    return 0;
}

这使得进程在控制台窗口收到 WM_QUIT 消息之前不会关闭。我不知道如何在delphi中做类似的事情。

我需要的不只是一个消息处理程序,而是一个轻量级的“技巧”,可以让控制台应用程序像使用线程的 GUI 应用程序一样工作。因此,例如,可以在控制台应用程序不终止进程的情况下处理两个 Indy TCP 服务器。

我的问题:如何做到这一点?

【问题讨论】:

  • 不是一个控制台应用程序,它是一个标准的 GUI 应用程序,没有可见的顶级窗口。否则你不需要调用CreateConsole(),控制台应用程序总是有一个附加到它的控制台。还是您希望在应用运行时空的控制台窗口一直存在?
  • 我希望空的控制台窗口在应用程序运行时保持不变,但我不希望它终止。我必须将一个 gui 应用程序替换为两个 TCP 服务器和一个以相同方式运行的控制台作为两个 tcp 服务器的 gui(不终止)。
  • 如果你真的在写一个 TCP 服务器,那么它可能应该是一个服务,在这种情况下控制台与 gui 是无关紧要的,因为它的 UI 也永远不会被看到方式。

标签: delphi multithreading console delphi-2009 console-application


【解决方案1】:

我不确定我是否了解您需要做什么,但可能是这样的

program Project1;

{$APPTYPE CONSOLE}

uses
  Forms,
  Unit1 in 'Unit1.pas' {DataModule1: TDataModule};

begin
  Application.Initialize;
  Application.CreateForm(TDataModule1, DataModule1);
  while not Application.Terminated do
    Application.ProcessMessages;
end.

让你开始?它是一个控制台应用程序,将在控制台关闭时终止。您可以在数据模块中使用 Indy 组件。

编辑:

没有Forms 单位的替代方案是:

program Project1;

{$APPTYPE CONSOLE}

uses
  Windows;

var
  Msg: TMsg;
begin
  while integer(GetMessage(Msg, 0, 0, 0)) <> 0 do begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end.

但我认为这不适用于大多数 Delphi 组件 - 我不了解 Indy,但如果它的一个单元无论如何都带有 Forms 单元,那么第一个版本是 IMO 更可取的。

【讨论】:

  • +1 这很好用!我只会等待更好的答案,因为我不想包含“表格”,因为它会使 exe 太大。但如果其他人没有这样的解决方案,我保证接受你的答案。谢谢!
【解决方案2】:

一个永不终止的程序只需要一个无限(或无限)循环。您的 C++ 程序包含一个无限循环:while(msg.message != WM_QUIT) 块。 Delphi 的 TApplication 包含一个非常相似的无限循环。如果您使用的是控制台应用程序而不是 TApplication,您所要做的就是编写自己的无限循环并将​​其放入调用堆栈底部的过程中。

确定一个终止条件并创建一个表示while not condition do 的while 循环。或者,如果您真的不希望它终止,请说 while true do。然后将你的 TCP 服务器逻辑放入循环体中。

编辑:不将 CPU 固定在 100 的实现:

while true do
begin
  DoSomethingWithTCP;
  Sleep(0); 
end;

Sleep(0) 调用将 CPU 交给 Windows 处理剩余的时间片,这使它不会将 CPU 固定在 100。每个时间片大约 16 毫秒长,如果你在主线程正在接收消息并将它们传递给其他线程,这应该绰绰有余,除非您处于非常重负载之下。

【讨论】:

  • 我不确定我是否理解一切正确。我试过这个:“While(true) do;” ,但是 CPU 达到 100%。你能详细解释一下,或者告诉我它的样子吗?我会很感激的!从现在开始为答案+1。 :)
  • 抱歉浪费了时间,Mason。我仍然有 90% 的 CPU 与你更新的代码。但我感谢你试图帮助我。希望我能 + 不止一次。
  • Sleep(0) 根本没有帮助 - 如果没有其他至少具有相同优先级的可运行线程,它将立即返回并消耗更多周期。如果没有其他线程可以运行,CPU 负载将在任何情况下达到 100%,仅来自上下文切换。您至少需要Sleep(1) 才能暂停线程执行。
【解决方案3】:

您可以使用 SyncObjs 单元及其类(如 TEvent)使其等待并保持打开状态,直到 Event 对象从您的 Indy 线程发出信号。

【讨论】:

    【解决方案4】:
    program YourConsoleProgram;
    
    uses
      System.SysUtils,
      Winapi.Windows;
    
    var
      Msg: TMsg;
      bRet: LongBool;
    
    begin
      try
        { your program logic here }
        { start your own threads, tcp servers, etc. }
    
        // And this is Win32 Native Console Message Loop:
        repeat
          bRet := Winapi.Windows.GetMessage(Msg, 0, 0, 0);
    
          if Int32(bRet) = -1 then
          begin
            // Error
            Break;
          end
          else
          begin
            TranslateMessage(Msg);
            DispatchMessage(Msg);
         end;
       until not bRet;
     except
        on E: Exception do
        begin
          // do something with exception
          Writeln(E.Classname, ': ', E.Message);
        end;
      end;
    end.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多