views:

480

answers:

3

Hello,

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?

+4  A: 

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.

mghie
+1 This works very well! I only will wait for better answers as I don't want to include 'Forms',because it makes the exe too big.But I promise to Accept your answer if there is no such solution by somebody else.Thank you!
John
Accepted,Thank you!
John
+1  A: 

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.

Mason Wheeler
I'm not sure if I understand everything correct.I tried this: "While(true) do;" ,but the CPU gets at 100%.Could you explain in details or perhaps show me how it would look like? I will appreciate it! +1 for the answer from now. :)
John
@John: OK, updated my answer.
Mason Wheeler
Sorry for the time wasted,Mason.I still had CPU at 90% with your updated code.But I thank you for trying to help me.Wish I could + more than once.
John
`Sleep(0)` does not help at all - if there is no other runnable thread with at least the same priority it will return immediately and just burn more cycles. CPU load will hit 100% in any case, from the context switches alone if no other thread can run. You need at least `Sleep(1)` to suspend thread execution.
mghie
A: 

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.

bassfriend