Фоновый процесс без форм и не сервис
От: leonidvp Россия  
Дата: 18.07.06 10:26
Оценка:
Здравствуйте

У меня есть такая задача: нужно написать процесс, который будет работать в фоновом режиме, незаметно для пользователя. Казалось бы все просто, но я столкнулся с такой трудностью: как процессу узнать, что ему нужно завершиться, например при выключении компьютера? Сервис не подходит, должно работать под win9x.
Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.
Re: Фоновый процесс без форм и не сервис
От: ekamaloff Великобритания  
Дата: 18.07.06 10:35
Оценка: 2 (1)
Здравствуйте, 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
Re[2]: Фоновый процесс без форм и не сервис
От: leonidvp Россия  
Дата: 18.07.06 10:39
Оценка:
Здравствуйте, ekamaloff, Вы писали:

E>Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx.

E>Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT
Приложение не консольное, SetConsoleCtrlHandler я пробовал — для неконсольного не работает, а жалко.
А CreateWindowEx и TOOLWINDOW это хорошая идея, сейчас попробую, спасибо!
Re[2]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 18.07.06 11:21
Оценка:
Здравствуйте, ekamaloff, Вы писали:

E>Здравствуйте, leonidvp, Вы писали:


L>>Сейчас я делаю скрытую форму, которая принимает сообщения и благодаря этому может узнать о необходимости завершения. Но это как-то неизящно, да и в списке приложений по Alt-Tab моя программа появляется, а это лишнее.


E>Просто в расширенных стилях у окна дожно быть WS_EX_TOOLWINDOW, тогда оно не будет появляться в списке по Alt+Tab. И форма это по-моему перебор, хватило и бы CreateWindowEx.


E>Если приложение у тебя консольное, см. в сторону SetConsoleCtrlHandler, CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT


Думаю человеку придется прятать Application. Именно оно висит в таск баре.
ShowWindow (Application.Handle, SW_HIDE)
Re: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 18.07.06 11:45
Оценка:
Здравствуйте, 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.
Re[3]: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 18.07.06 11:47
Оценка:
Здравствуйте, 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 вообще создавать? Только зря размер проги увеличивать
Re[4]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 18.07.06 11:58
Оценка:
Здравствуйте, FDSC, Вы писали:

[Skip]

FDS>А нафига ему Application вообще создавать? Только зря размер проги увеличивать


Да не нафига, а он уже ее создал.
Я щас напишу, а нафига ваще диалог создавать? Если можна обойтись AllocateHWnd и DeallocateHWnd и простым Message Loop
Re[5]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 18.07.06 12:21
Оценка: 5 (1)
[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
  // nothing
end;

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 appear
end;

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.
Re[6]: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 18.07.06 13:50
Оценка:
Здравствуйте, 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.


Спасибо за приведённое решение.
Re[7]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 18.07.06 14:17
Оценка: 3 (1)
Здравствуйте, FDSC, Вы писали:

[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 exceptions
    end;
  until False;
  
  // terminate all that you need

end.
Re[8]: Фоновый процесс без форм и не сервис
От: leonidvp Россия  
Дата: 19.07.06 07:24
Оценка:
Здравствуйте, Danchik, Вы писали:


D>Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать.

D>Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.
Вот это как раз то что нужно, спасибо!
Re[3]: Фоновый процесс без форм и не сервис
От: leonidvp Россия  
Дата: 19.07.06 07:34
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Думаю человеку придется прятать Application. Именно оно висит в таск баре.

D>
D>ShowWindow (Application.Handle, SW_HIDE)
D>


точно, так я сейчас и делаю
+ к этому мне подсказали стиль окна ToolWindow, так что программу не видно по Alt-Tab
и еще + к этому RegisterServiceProcess скрывает программу от Ctrl-Alt-Del в Win9x
Re: А можно ли сделать это без оконных сообщений?
От: leonidvp Россия  
Дата: 19.07.06 07:37
Оценка:
Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений?
Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?
Re[2]: А можно ли сделать это без оконных сообщений?
От: FDSC Россия consp11.github.io блог
Дата: 19.07.06 09:48
Оценка:
Здравствуйте, leonidvp, Вы писали:

L>Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений?

L>Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?

В принципе можно взять handle системного процесса (если получится по безопасности), который завершается при завершении системы. Например, explorer (хотя он иногда завершается, а система остаётся работать ). И ждать с пом. WaitforSingleObject сигнального состояния этого процесса. Когда будет сигнальное состояние — процесс завершается, а, значит, скорее всего и система.
Re[8]: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 19.07.06 09:49
Оценка:
Здравствуйте, 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>



М-да-а-а. Никогда не думал, что так можно.
Re[9]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 19.07.06 11:43
Оценка:
Здравствуйте, FDSC, Вы писали:

[Skip]

D>>Вообще то все можна написать намного проще, просто без окна я не вижу смысла в этой программе. Не понятно как она будет работать.

D>>Тоесть мы запустим программу, которая только то и умеет что выходить Разве что запустить работающий поток, который прибивать при выходе.

FDS>Почему. У меня диалог в моём приложении то же ничего не делает. Он сразу скрывается. Приложение через иконку в systray общается с пользователем (ну и запускает иногда iexplorer )


Вот видите, вам нужна была интерактивная работа, а тут, кажется, прсто нужен фоновый процесс. И все равно, Вам хватило бы создать окно Tray и использовать приведенный мною пример.

[Skip]

FDS>М-да-а-а. Никогда не думал, что так можно.


Это стандартная реализация WinMain. Все просто, цикл выгребающий очередь сообщений и передающий их в созданные окна (в том же потоке). Кстати, диалог именно этим и занимается. В Delphi диалог делает так:
function TCustomForm.ShowModal: Integer;
...
      repeat
        Application.HandleMessage; // PeekMessage->TranslateMessage->DispatchMessage
        if Application.FTerminate then ModalResult := mrCancel else
          if ModalResult <> 0 then CloseModal;
      until ModalResult <> 0;
...

Поверьте в Windows это не слишком отличается
Re[2]: А можно ли сделать это без оконных сообщений?
От: Danchik Украина  
Дата: 19.07.06 11:46
Оценка:
Здравствуйте, leonidvp, Вы писали:

L>Может ли процесс узнать о том, что windows выключается без обработки оконных сообщений?

L>Может быть есть какой-нибудь именованный Event, на котором можно ждать завершения системы, или что-то вроде этого?

WM_ENDSESSION ?
Re[10]: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 19.07.06 11:48
Оценка:
Здравствуйте, 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 делал )
Re[11]: Фоновый процесс без форм и не сервис
От: Danchik Украина  
Дата: 19.07.06 11:52
Оценка:
Здравствуйте, FDSC, Вы писали:

[Skip]

FDS>Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна

FDS>Так-то цикл сообщений я знаю и в Delphi и в VC.
FDS>(Сам когда-то на asm делал )

А помоему, это логично. Это же граничное условие: будет ли алгоритм работать в начале, пока ниодно окно не создано
Re[12]: Фоновый процесс без форм и не сервис
От: FDSC Россия consp11.github.io блог
Дата: 19.07.06 14:27
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, FDSC, Вы писали:


D>[Skip]


FDS>>Да, нет. Я про то, что никогда не думал, что это можно сделать вообще без окна

FDS>>Так-то цикл сообщений я знаю и в Delphi и в VC.
FDS>>(Сам когда-то на asm делал )

D> А помоему, это логично. Это же граничное условие: будет ли алгоритм работать в начале, пока ниодно окно не создано


Работать то будет, только вот сообщения кто принимать будет?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.