How to create a console application that does not terminate?
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 a开发者_开发技巧pplication 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?
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.
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.
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.
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.
精彩评论