Board index » delphi » Detect Windows Shutdown

Detect Windows Shutdown

Hi

I have a formless application which scans specific files on a user's
hard drive, is it possible to trap WM_QUERYENDSESSION in an
application that does not have a main form?

I just need to detect if Windows is being shut down.

Thanks

DGJ

 

Re:Detect Windows Shutdown


Quote
In article <gqlmn1dk4r30bi4mdj9q8po3ur3l5fd...@4ax.com>, Dgj wrote:
> I have a formless application which scans specific files on a user's
> hard drive, is it possible to trap WM_QUERYENDSESSION in an
> application that does not have a main form?

Yes, in principle. You could create a helper window via AllocateHwnd,
but if your application does not have a message loop but works away in
a work loop the helper window would not be able to receive the message.

Try to use SetConsoleCtrlhandler to install a callback that gets
notified when the system goes down. The handler needs to set a boolean
flag somewhere that your work loop has to check frequently.

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be

Re:Detect Windows Shutdown


Thanks Peter

Quote
>Try to use SetConsoleCtrlhandler to install a callback that gets
>notified when the system goes down. The handler needs to set a boolean
>flag somewhere that your work loop has to check frequently.

I have tried the following code but cant get the handler to fire when
logging off or shutting down Windows 95, does this look about right to
you?

Regards
DGJ

****************
function Handler(dwCtrlType: DWORD): BOOL; stdcall;
begin
  Result := True;
  case dwCtrlType of
    CTRL_LOGOFF_EVENT: ShowMessage('Logoff');
    CTRL_SHUTDOWN_EVENT: ShowMessage('Shutdown');
    else MessageBeep(0)
  end
end;

begin
  Num1:=1;
  SetConsoleCtrlHandler(@Handler, True);

  while Num1 <= 60 do
  begin
    Delay(1000);
    //Processing ...
    Inc(Num1);
    Application.ProcessMessages;
  end;

end.

Re:Detect Windows Shutdown


Quote
In article <c5aon1h9i38u2s80l9a1hpq6r62496e...@4ax.com>, Dgj wrote:
> >Try to use SetConsoleCtrlhandler to install a callback that gets
> >notified when the system goes down. The handler needs to set a boolean
> >flag somewhere that your work loop has to check frequently.

> I have tried the following code but cant get the handler to fire when
> logging off or shutting down Windows 95, does this look about right to
> you?

> Regards
> DGJ

> ****************
> function Handler(dwCtrlType: DWORD): BOOL; stdcall;

This is OK.

Quote
> begin
>   Result := True;
>   case dwCtrlType of
>     CTRL_LOGOFF_EVENT: ShowMessage('Logoff');
>     CTRL_SHUTDOWN_EVENT: ShowMessage('Shutdown');

Don't use Showmessage, write a log statement to a file instead.

Quote
>     else MessageBeep(0)
>   end
> end;

> begin
>   Num1:=1;
>   SetConsoleCtrlHandler(@Handler, True);

Tsk, tsk, another blind optimist <g>. Check the return value of
SetConsoleCtrlHandler. It may fail in a windowed application, you know ...

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be

Re:Detect Windows Shutdown


Quote
>>   SetConsoleCtrlHandler(@Handler, True);

>Tsk, tsk, another blind optimist <g>. Check the return value of
>SetConsoleCtrlHandler. It may fail in a windowed application, you know ...

  if not SetConsoleCtrlHandler(@Handler, True) then
  begin
    ShowMessage(Format('SetConsoleCtrlHandler failed to install
console handler:%d',
     [GetLastError]));

  end;

Instead of a show message I have got the handler to write to a file,
and it still will not fire, but thanks again Peter

Regards

DGJ

Re:Detect Windows Shutdown


Quote
In article <l9tpn1lo8kgotneu6cidko466u7dur8...@4ax.com>, Dgj wrote:
>   if not SetConsoleCtrlHandler(@Handler, True) then
>   begin
>     ShowMessage(Format('SetConsoleCtrlHandler failed to install
> console handler:%d',
>      [GetLastError]));
>   end;

OK, and that succeeds, so does not show the message, i take it?

Quote
> Instead of a show message I have got the handler to write to a file,
> and it still will not fire, but thanks again Peter

Mh, pity. In a console application the handler is called in a separate thread
(the one owning the console window, which is not the same your own code
executes in). In a non-console app that seems not to be the case.

OK, back to the drawing board. Let's try a helper window managed by a
secondary thread. That seems to work, see test code below...

program Shutdownwatch;

uses
  Classes, Windows,
  ShutdownWatcherThreadU in 'ShutdownWatcherThreadU.pas';

{$R *.res}

procedure SaveStringToFile(const S, filename: string);
var
  fs: TFilestream;
begin
  fs := TFileStream.Create(filename, fmCreate);
  try
    if Length(S) > 0 then
      fs.WriteBuffer(S[1], Length(S));
    FlushFileBuffers(fs.Handle);  
  finally
    fs.free
  end;
end; { SaveStringToFile }

var
  ShutdownPending: Boolean = false;
  WorkIsDone: Boolean = false;
  Counter: int64 = 0;
  Watcherthread : TShutdownwatcherThread = nil;
begin
  WatcherThread := TShutdownwatcherThread.Create(ShutdownPending);
  while not (ShutdownPending or WorkIsDone) do begin
    Inc(Counter);
    Sleep(10);
    WorkIsDone := Counter > 10000;
  end;
  if WorkIsDone then begin
    WatcherThread.Quit;
    MessageBox(0, 'Done', nil, MB_OK or MB_ICONINFORMATION);
  end
  else
    SaveStringToFile('Closed by shutdown', 'C:\temp\Shutdownwatch.txt');
end.

unit ShutdownWatcherThreadU;

interface

uses
  Classes,Windows, Messages;

type
  TShutdownwatcherThread = class(TThread)
  private
    FHelperWindow: HWND;
    FWndProc: Pointer;
    PShutdownflag: ^Boolean;
    procedure CreateHelperWindow;
    procedure DestroyHelperWindow;
    procedure WndProc(var Message: TMessage);
  protected
    procedure Execute; override;
  public
    constructor Create(Var ShutdownFlag: Boolean);
    destructor Destroy; override;
    procedure Quit;
  end;

implementation

uses SysUtils;

{== ShutdownwatcherThread =============================================}

constructor TShutdownwatcherThread.Create(Var ShutdownFlag: Boolean);
begin
  inherited Create(true);
  PShutdownflag := @Shutdownflag;
  FreeOnTerminate:= true;
  FWndProc := MakeObjectInstance(WndProc);
  Resume;
end;

destructor TShutdownwatcherThread.Destroy;
begin
  FreeObjectInstance(FWndProc);
  inherited;
end;

procedure TShutdownwatcherThread.DestroyHelperWindow;
begin
  DestroyWindow(FHelperWindow);
end;

procedure TShutdownwatcherThread.CreateHelperWindow;
const
  TemplateClass: TWndClass = (
    style: 0;
    lpfnWndProc: nil;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: 0;
    lpszMenuName: nil;
    lpszClassName: 'TShutdownwatcherThreadWindow');
var
  UtilWindowClass, TempClass: TWndClass;
  ClassRegistered: Boolean;
begin
  UtilWindowClass := TemplateClass;
  UtilWindowClass.lpfnWndProc := @DefWindowProc;
  UtilWindowClass.hInstance := HInstance;
  ClassRegistered :=
    GetClassInfo(HInstance, UtilWindowClass.lpszClassName,
    TempClass);
  if ClassRegistered then
    Windows.UnregisterClass(UtilWindowClass.lpszClassName, HInstance);
  Windows.RegisterClass(UtilWindowClass);
  FHelperWindow :=
    CreateWindowEx(WS_EX_TOOLWINDOW,
    UtilWindowClass.lpszClassName,
    '', WS_POPUP, 0, 0, 0, 0, 0, 0, HInstance, nil);
  if FHelperWindow = 0 then
    RaiseLastOSError;
  SetWindowLong(FHelperWindow, GWL_WNDPROC, Longint(FWndProc));
end;

procedure TShutdownwatcherThread.Execute;
var
  Msg: TMsg;
begin
  CreateHelperWindow;
  try
    while GetMessage(Msg, 0, 0, 0) do
      DispatchMessage(Msg);
  finally
    DestroyHelperWindow;
  end; { finally }
end;

procedure TShutdownwatcherThread.Quit;
begin
  PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
end;

procedure TShutdownwatcherThread.WndProc(var Message: TMessage);
begin
  Message.Result := DefWindowProc(FHelperWindow,
    Message.Msg, Message.WParam, Message.LParam);
  if Message.Msg = WM_QUERYENDSESSION then begin
    PShutdownflag^ := true;
    PostQuitMessage(0);
  end;
end;

end.

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be

Re:Detect Windows Shutdown


I dont quite know what to say Peter, except, thank you most kindly. It
works just fine now ...

Best regards

DGJ

Quote

>OK, back to the drawing board. Let's try a helper window managed by a
>secondary thread. That seems to work, see test code below...

>program Shutdownwatch;

>uses
>  Classes, Windows,
>  ShutdownWatcherThreadU in 'ShutdownWatcherThreadU.pas';

Other Threads