How to create a console application that does not

2019-04-13 00:53发布

问题:

In C++,a console application can have a message handler in its Winmain procedure.Like this:

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;
}

This makes the process not close until the console window has received WM_QUIT message. I don't know how to do something similar in delphi.

My need is not for exactly a message handler, but a lightweight "trick" to make the console application work like a GUI application using threads. So that, for example, two Indy TCP servers could be handled without the console application terminating the process.

My question: How could this be accomplished?

回答1:

I'm not sure I understand what you need to do, but maybe something like this

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.

gets you started? It is a console application, which will terminate when the console is closed. You could use the Indy components in the data module.

Edit:

The alternative without the Forms unit is:

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.

I think however that this won't work with most Delphi components - I don't know about Indy, but if one of its units brings the Forms unit in anyway, then the first version is IMO preferable.



回答2:

All you need for a program that never terminates is an infinite (or indefinite) loop. Your C++ program contains an indefinite loop: the while(msg.message != WM_QUIT) block. Delphi's TApplication contains a very similar indefinite loop. If you're using a console app instead of TApplication, all you have to do is write your own indefinite loop and put it in a procedure at the bottom of the call stack.

Determine a termination condition and create a while loop that says while not condition do. Or if you truly don't want it to ever terminate, say while true do. And then put your TCP server logic inside the loop body.

EDIT: An implementation that doesn't peg the CPU at 100:

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

The Sleep(0) call hands the CPU back off to Windows for the rest of the timeslice, which keeps it from pegging the CPU at 100. Each timeslice is about 16 milliseconds long, and if all you're doing in the main thread is receiving messages and handing them off to other threads, this should be more than adequate unless you're under a very heavy load.



回答3:

You could use the SyncObjs Unit and their classes like TEvent to keept it waiting and be open until the Event object(s) gets signaled from your Indy threads.



回答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.