У меня есть такая задача: нужно написать процесс, который будет работать в фоновом режиме, незаметно для пользователя. Казалось бы все просто, но я столкнулся с такой трудностью: как процессу узнать, что ему нужно завершиться, например при выключении компьютера? Сервис не подходит, должно работать под win9x.
Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
Здравствуйте, leonidvp, Вы писали:
L>Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx.
Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, ekamaloff, Вы писали:
E>Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx. E>Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT
Приложение не консольное, SetConsoleCtrlHandler я пробовал — для неконсольного не работает, а жалко.
А CreateWindowEx и TOOLWINDOW это хорошая идея, сейчас попробую, спасибо!
Здравствуйте, ekamaloff, Вы писали:
E>Здравствуйте, leonidvp, Вы писали:
L>>Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
E>Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx.
E>Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT
Думаю человеку придется прятать Application. Именно оно висит в таск баре.
Здравствуйте, leonidvp, Вы писали:
L>Здравствуйте
L>У меня есть такая задача: нужно написать процесс, который будет работать в фоновом режиме, незаметно для пользователя. Казалось бы все просто, но я столкнулся с такой трудностью: как процессу узнать, что ему нужно завершиться, например при выключении компьютера? Сервис не подходит, должно работать под win9x. L>Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
Создавай диалог и прячь его
или просто прячь своё окно (см. ShowWindow(hwnd, SW_HIDE))
program FdscInformer;
... и много чего ещё
function HideWindow(hwnd: cardinal): boolean;
begin// if NOT ShowWindow(hwnd, SW_HIDE) then
// KillTimer(hwnd, 1);
ShowWindow(hwnd, SW_HIDE);
result := true;
end;
function Msg(hwnd: cardinal; msg: cardinal; wparam: cardinal; lparam: cardinal): boolean; stdcall;
begin
result := false;
if (msg > WM_USER) and (msg < WM_USER + 6) then result := true;
case msg of
WM_INITDIALOG : result := InitDialog(hwnd);
WM_DESTROY : result := InitializeShell(hwnd, NIM_DELETE);
WM_CLOSE : result := onClose (hwnd);
WM_TIMER : result := onTimer (hwnd, wparam, lparam);
WM_NOTIFYICON : result := onIcon (hwnd, wparam, lparam);
WM_COMMAND : result := onCommand(hwnd, wparam, lparam);
WM_USER+80 : result := OnTimer (hwnd, 3, lparam)
end;
end;
procedure CreateDialog;
begin
if windows.DialogBoxW(hInstance, pointer(101), 0, @Msg) = -1 then
begin
GetError(GetLastError, true);
exit;
end;
end;
begin
hInstance := windows.GetModuleHandle(nil);
SetLastError(0);
// MsgBox(0, GetFile('strings.ini'), 'caption');if SuccessInternalStringsLoading and NOT Terminated
then CreateDialog;
end.
Здравствуйте, Danchik, Вы писали:
D>Здравствуйте, ekamaloff, Вы писали:
E>>Здравствуйте, leonidvp, Вы писали:
L>>>Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
E>>Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx.
E>>Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT
D>Думаю человеку придется прятать Application. Именно оно висит в таск баре. D>
D>ShowWindow (Application.Handle, SW_HIDE)
D>
А нафига ему Application вообще создавать? Только зря размер проги увеличивать
[Skip]
FDS>А нафига ему Application вообще создавать? Только зря размер проги увеличивать
Да не нафига, а он уже ее создал.
Я щас напишу, а нафига ваще диалог создавать? Если можна обойтись AllocateHWnd и DeallocateHWnd и простым Message Loop
[Skip]
D>Да не нафига, а он уже ее создал. D>Я щас напишу, а нафига ваще диалог создавать? Если можна обойтись AllocateHWnd и DeallocateHWnd и простым Message Loop
Да вот, кстати, и оно
Unit DLiteProgram.pas
unit DLiteProgram;
interface
uses
Windows, Messages, Classes;
type
TDLiteProgram = class
private
FOnIdle: TNotifyEvent;
FRunning: Boolean;
FTerminated: Boolean;
FHandle: HWND;
function GetTerminated: Boolean;
function GetHandle: HWND;
function ProcessMessage(var Msg: TMsg): Boolean;
procedure SetTerminated(Value: Boolean);
protected
procedure Idle(const Msg: TMsg); virtual;
procedure WndMethod(var Message: TMessage); virtual;
public
constructor Create;
destructor Destroy; override;
procedure HandleException(Sender: TObject);
procedure HandleMessage;
procedure ProcessMessages;
procedure Run;
property Handle: HWND read GetHandle;
property Terminated: Boolean read GetTerminated write SetTerminated;
property OnIdle: TNotifyEvent read FOnIdle write FOnIdle;
property Running: Boolean read FRunning;
end;
implementation
constructor TDLiteProgram.Create;
begin
inherited Create;
FHandle := AllocateHWnd(WndMethod);
end;
destructor TDLiteProgram.Destroy;
begin
DeallocateHWnd(FHandle);
inherited;
end;
function TDLiteProgram.GetTerminated: Boolean;
begin
Result := FTerminated;
end;
function TDLiteProgram.GetHandle: HWND;
begin
Result := FHandle;
end;
procedure TDLiteProgram.HandleException(Sender: TObject);
begin// nothingend;
procedure TDLiteProgram.HandleMessage;
var
Msg: TMsg;
begin
if not ProcessMessage(Msg) then Idle(Msg);
end;
procedure TDLiteProgram.Idle(const Msg: TMsg);
begin
if Assigned (FOnIdle) then
FOnIdle (Self);
WaitMessage;
end;
function TDLiteProgram.ProcessMessage(var Msg: TMsg): Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
Result := True;
if Msg.Message <> WM_QUIT then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end
else
FTerminated := True;
end;
end;
procedure TDLiteProgram.ProcessMessages;
var
Msg: TMsg;
begin
while ProcessMessage(Msg) do{loop};
end;
procedure TDLiteProgram.Run;
begin
FRunning := True;
try
repeat
try
HandleMessage;
except
HandleException(Self);
end;
until Terminated;
finally
FRunning := False;
end;
end;
procedure TDLiteProgram.SetTerminated(Value: Boolean);
begin
if FTerminated = Value then
Exit;
FTerminated := Value;
end;
procedure TDLiteProgram.WndMethod(var Message: TMessage);
begin// do something if message appearend;
end.
И сама DPR
program Project1;
uses
DLiteProgram in'DLiteProgram.pas';
{$R *.res}var
aProgram : TDLiteProgram;
begin
aProgram := TDLiteProgram.Create;
try
aProgram.Run;
finally
aProgram.Free;
end;
end.
Здравствуйте, Danchik, Вы писали:
D>[Skip]
D>>Да не нафига, а он уже ее создал. D>>Я щас напишу, а нафига ваще диалог создавать? Если можна обойтись AllocateHWnd и DeallocateHWnd и простым Message Loop
D>Да вот, кстати, и оно
...
Ну, что-то много всего.
Всё-таки с диалогом проще: цикла не надо и проч. и проч.
function onClose(hwnd : cardinal): boolean;
begin
result := EndDlg(hwnd);
end;
function HideWindow(hwnd: cardinal): boolean;
begin
ShowWindow(hwnd, SW_HIDE);
result := true;
end;
function Msg(hwnd: cardinal; msg: cardinal; wparam: cardinal; lparam: cardinal): boolean; stdcall;
begin
result := false;
if (msg > WM_USER) and (msg < WM_USER + 6) then result := true;
case msg of
WM_INITDIALOG : result := InitDialog(hwnd); // если нужно
WM_DESTROY : // если нужно
WM_CLOSE : result := onClose (hwnd);
// ...
WM_PAINT : result := HideWindow(hwnd);
end;
end;
procedure CreateDialog;
begin
if windows.DialogBoxW(hInstance, pointer(101), 0, @Msg) = -1 then
begin
GetError(GetLastError, true);
exit;
end;
end;
begin
hInstance := windows.GetModuleHandle(nil);
SetLastError(0);
// MsgBox(0, GetFile('strings.ini'), 'caption');if SuccessInternalStringsLoading and NOT Terminated
then CreateDialog;
end.
[Skip]
FDS>Всё-таки с диалогом проще: цикла не надо и проч. и проч.
[Skip]
FDS>Спасибо за приведённое решение.
Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать.
Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.
Вот пример как MSDN учит:
program Project1;
uses
Windows,
Messages;
{$R *.res}var
aRet : BOOL;
aMessage : TMsg;
begin// start working thread here....repeat
aRet := GetMessage(aMessage, 0, 0, 0);
if not aRet then
Break; {WM_QUIT}if Integer (aRet) = -1 then
Break; {error}try
TranslateMessage(aMessage); // это даже лишнее
DispatchMessage(aMessage);
except// kill any exceptionsend;
until False;
// terminate all that you needend.
D>Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать. D>Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.
Вот это как раз то что нужно, спасибо!
Здравствуйте, Danchik, Вы писали:
D>Думаю человеку придется прятать Application. Именно оно висит в таск баре. D>
D>ShowWindow (Application.Handle, SW_HIDE)
D>
точно, так я сейчас и делаю
+ к этому мне подсказали стиль окна ToolWindow, так что программу не видно по Alt-Tab
и еще + к этому RegisterServiceProcess скрывает программу от Ctrl-Alt-Del в Win9x
Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений?
Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?
Re[2]: А можно ли сделать это без оконных сообщений?
Здравствуйте, leonidvp, Вы писали:
L>Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений? L>Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?
В принципе можно взять handle системного процесса (если получится по безопасности), который завершается при завершении системы. Например, explorer (хотя он иногда завершается, а система остаётся работать ). И ждать с пом. WaitforSingleObject сигнального состояния этого процесса. Когда будет сигнальное состояние — процесс завершается, а, значит, скорее всего и система.
Здравствуйте, Danchik, Вы писали:
D>Здравствуйте, FDSC, Вы писали:
D>[Skip]
FDS>>Всё-таки с диалогом проще: цикла не надо и проч. и проч.
D>[Skip]
FDS>>Спасибо за приведённое решение.
D>Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать. D>Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.
Почему. У меня диалог в моём приложении то же ничего не делает. Он сразу скрывается. Приложение через иконку в systray общается с пользователем (ну и запускает иногда iexplorer )
D>Вот пример как MSDN учит: D>
D>program Project1;
D>uses
D> Windows,
D> Messages;
D>{$R *.res}
D>var
D> aRet : BOOL;
D> aMessage : TMsg;
D>begin
D> // start working thread here....
D> repeat
D> aRet := GetMessage(aMessage, 0, 0, 0);
D> if not aRet then
D> Break; {WM_QUIT}
D> if Integer (aRet) = -1 then
D> Break; {error}
D> try
D> TranslateMessage(aMessage); // это даже лишнее
D> DispatchMessage(aMessage);
D> except
D> // kill any exceptions
D> end;
D> until False;
D> // terminate all that you need
D>end.
D>
[Skip]
D>>Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать. D>>Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.
FDS>Почему. У меня диалог в моём приложении то же ничего не делает. Он сразу скрывается. Приложение через иконку в systray общается с пользователем (ну и запускает иногда iexplorer )
Вот видите, вам нужна была интерактивная работа, а тут, кажется, прсто нужен фоновый процесс. И все равно, Вам хватило бы создать окно Tray и использовать приведенный мною пример.
[Skip]
FDS>М-да-а-а. Никогда не думал, что так можно.
Это стандартная реализация WinMain. Все просто, цикл выгребающий очередь сообщений и передающий их в созданные окна (в том же потоке). Кстати, диалог именно этим и занимается. В Delphi диалог делает так:
function TCustomForm.ShowModal: Integer;
...
repeat
Application.HandleMessage; // PeekMessage->TranslateMessage->DispatchMessageif Application.FTerminate then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
...
Поверьте в Windows это не слишком отличается
Re[2]: А можно ли сделать это без оконных сообщений?
Здравствуйте, leonidvp, Вы писали:
L>Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений? L>Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?
Здравствуйте, Danchik, Вы писали:
D>Это стандартная реализация WinMain. Все просто, цикл выгребающий очередь сообщений и передающий их в созданные окна (в том же потоке). Кстати, диалог именно этим и занимается. В Delphi диалог делает так: D>
D>function TCustomForm.ShowModal: Integer;
D>...
D> repeat
D> Application.HandleMessage; // PeekMessage->TranslateMessage->DispatchMessage
D> if Application.FTerminate then ModalResult := mrCancel else
D> if ModalResult <> 0 then CloseModal;
D> until ModalResult <> 0;
D>...
D>
D>Поверьте в Windows это не слишком отличается
Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна
Так-то цикл сообщений я знаю и в Delphi и в VC.
(Сам когда-то на asm делал )
[Skip]
FDS>Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна FDS>Так-то цикл сообщений я знаю и в Delphi и в VC. FDS>(Сам когда-то на asm делал )
А помоему, это логично. Это же граничное условие: будет ли алгоритм работать в начале, пока ниодно окно не создано
Здравствуйте, Danchik, Вы писали:
D>Здравствуйте, FDSC, Вы писали:
D>[Skip]
FDS>>Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна FDS>>Так-то цикл сообщений я знаю и в Delphi и в VC. FDS>>(Сам когда-то на asm делал )
D> А помоему, это логично. Это же граничное условие: будет ли алгоритм работать в начале, пока ниодно окно не создано
Работать то будет, только вот сообщения кто принимать будет?
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, Danchik, Вы писали:
D>>Здравствуйте, FDSC, Вы писали:
D>>[Skip]
FDS>>>Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна FDS>>>Так-то цикл сообщений я знаю и в Delphi и в VC. FDS>>>(Сам когда-то на asm делал )
D>> А помоему, это логично. Это же граничное условие: будет ли алгоритм работать в начале, пока ниодно окно не создано
FDS>Работать то будет, только вот сообщения кто принимать будет?
Да окошечко было бы не плохо AllocateHWnd — самое оно.
Я же и написал, толку от такой аппликухи, если не использовать потоки, маловато будет
Re[3]: А можно ли сделать это без оконных сообщений?