如何创建不终止的控制台应用程序?

时间:2010-04-07 10:57:13

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

在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服务器。

我的问题:如何实现这一目标?

4 个答案:

答案 0 :(得分:8)

我不确定我明白你需要做什么,但也许是这样的

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 :(得分:1)

永远不会终止的程序所需要的只是无限(或无限)循环。您的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毫秒长,如果你只是在做主线程正在接收消息并将其交给其他线程,除非你处于非常重负载下,否则这应该是足够的。

答案 2 :(得分:0)

您可以使用SyncObj单元及其类似TEvent来保持等待并打开,直到从Indy线程发出Event对象的信号。

答案 3 :(得分:0)

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.