WM_ENDSESSION - Shutdown type?

Hi.

I've got a backup application that runs at shutdown.  The program receives the WM_ENDSESSION message and stops it, therefore stopping the shutdown.  Then, the program does the backups it needs to do and starts a shutdown again.

The problem I have is that the shutdown that the backup program starts is always a shutdown.  I want to detect the type of shutdown that it's stopping so that I can do the same thing after the backup procedure.  In a nutshell, if I do a shutdown, it's great, but if I do a restart or logoff, it shuts down after the backup.

I need to know how to capture the shutdown type during WM_ENDSESSION.

Thanks in advance,

MoonCalf.
LVL 1
MoonCalfAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jase-CoderCommented:
there is consts like EWX_LOGOFF that enable to loggoff. Maybe, if you check to see if the program recieves that message (EWX_LOGOFF) it'll help
MoonCalfAuthor Commented:
That's what the question is.  How?
Jase-CoderCommented:
http://delphi.about.com/cs/adptips2000/a/bltip0500_4.htm <-- here is a link stating how to detect windows shutting down and here is what you need to look into:

The WM_ENDSESSION message is sent to an application after Windows processes the results of the WM_QUERYENDSESSION message. The WM_ENDSESSION message informs the application whether the Windows session is ending.

WM_ENDSESSION  
fEndSession = (BOOL) wParam;     // end-session flag
fLogOff =  lParam                // logoff flag
 

Parameters

fEndSession

Value of wParam. Specifies whether the session is being ended. If the session is being ended, this parameter is TRUE; otherwise, it is FALSE.

fLogOff

Value of lParam. Indicates whether the user is logging off or shutting down the system. Supported values include: ENDSESSION_LOGOFF.

 

Return Values

If an application processes this message, it should return zero.

Remarks

If the fEndSession parameter is TRUE, the Windows session can end any time after all applications have returned from processing this message. Therefore, an application should perform all tasks required for termination before returning from this message.
The application need not call the DestroyWindow or PostQuitMessage function when the session is ending.


WM_ENDSESSION  
fEndSession = (BOOL) wParam;     // end-session flag
fLogOff =  lParam                // logoff flag

WM_ENDSESSION has a field fLogOff that states whether you have logged off. Look at the link above that shows how to detect shutting down and then tweak it so it checks logginf off


===========================================================
also check out:

The WM_QUERYENDSESSION message is sent when the user chooses to end the Windows session or when an application calls the ExitWindows function. If any application returns zero, the Windows session is not ended. Windows stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.

After processing this message, Windows sends the WM_ENDSESSION message with the wParam parameter set to the results of the WM_QUERYENDSESSION message.

WM_QUERYENDSESSION  
nSource = (UINT) wParam;    // source of end-session request
fLogOff = lParam            // logoff flag
 

Parameters

nSource

Reserved for future use.

fLogOff

Value of lParam. Indicates whether the user is logging off or shutting down the system. Supported values include: ENDSESSION_LOGOFF.

 

Return Values

If an application can terminate conveniently, it should return TRUE; otherwise, it should return FALSE.

Remarks

By default, the DefWindowProc function returns TRUE for this message.
Windows NT: When an application returns TRUE for this message, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
Windows 95: After all applications return TRUE for this message, they receive the WM_ENDSESSION and they are terminated.

both those long definitiions where taken from the delphi/windows SDK help files
Expert Spotlight: Joe Anderson (DatabaseMX)

We’ve posted a new Expert Spotlight!  Joe Anderson (DatabaseMX) has been on Experts Exchange since 2006. Learn more about this database architect, guitar aficionado, and Microsoft MVP.

Ivanov_GCommented:

   TForm1 = class(TForm)
   private
     procedure OnQueryEndSession(var Msg : TMessage); message WM_QUERYENDSESSION;
   public
   end;

   procedure TForm1.OnQueryEndSession(var Msg: TMessage);
   begin
      // executed the the application receive WM_QUERYENDSESSION
      if (Msg.LParam and ENDSESSION_LOGOFF) then
          ShowMessage('Logging Off...')
      else
          ShowMessage('Shutdown');
      inherited;
   end;
Jase-CoderCommented:
shouldnt the above code be:

if (Msg.LParam = ENDSESSION_LOGOFF) then
          ShowMessage('Logging Off...')

????

i cant be a 100% sure since I cannot test it at the minute.

MoonCalfAuthor Commented:
What about restart?
MoonCalfAuthor Commented:
This is simple enough....

I know how to stop shutdown - I am currently trapping WM_ENDSESSION and setting Msg.EndSession:=False

I need to be able to take a value from within that procedure that relates directly to the type of shutdown, not just shutdown and logoff.  That value can then be either used directly, as is, or mapped to a shutdown type.

I also know how to do the shut down.

All I want is to detect the type of shutdown.
MoonCalfAuthor Commented:
I can see where I was going wrong earlier.  I was use TWMEndSession as the message type, not TMessage.  Now I have access to wParam and lParam so I can tell the difference between log off and shutdown.

I still need to know how to detect restart though.  Everything I've checked is the same as a shutdown request.

Any ideas?
MadshiCommented:
As far as I know Windows just doesn't tell you exactly what it does (shutdown / reboot / logoff). At least I don't know how you could get that information.

I'm solving this problem by hooking the shutdown APIs by using my madCodeHook package. It's quite a brute force approach, though...   :-(
MoonCalfAuthor Commented:
Okay.  I think the best approach would be to try an alternative solution.  I'm gonna ask for this question to be deleted, but ask another one about pausing shutdown, rather than cancel and restart.

Thanks everyone.
MadshiCommented:
Pausing is more or less simple: Just do your work in the WM_(QUERY)ENDSESSION handler before returning. The OS might not want to wait too long for you, though. So you need to hurry up doing whatever you need to do.
MoonCalfAuthor Commented:
That's my problem - it could take anything between 20 seconds and, well, hours.  It depends on the amount of backing-up to be done which depends on how much work has been done.

It's far too variable to allow the length of the process to affect the procedure.

Any more ideas?
MadshiCommented:
No other apart from what I mentioned in my first post in this thread (hooking the shutdown APIs).
MoonCalfAuthor Commented:
Okay, fair enough, and thanks for comments, everyone.

Madshi : Where can I get a copy of your "madCodeHook package"?  I'd like to give it a go.
MadshiCommented:
Download:
http://madshi.net/madCollection.exe

Online documentation:
http://help.madshi.net/madCodeHook.htm

It's free for non-commercial usage (only).

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MadshiCommented:
This is how my hook dll looks like (tested in winNT only, might work in win9x):

library ShutdownHooks;

{$IMAGEBASE $42800000}

uses Windows, madCodeHook;

// ***************************************************************

var
  ExitWindowsExNext             : function (flags, reserved: dword) : bool; stdcall;
  InitiateSystemShutdownWNext   : function (pc, msg: pwideChar; timeOut: dword; force, reboot: bool) : bool; stdcall;
  InitiateSystemShutdownExWNext : function (pc, msg: pwideChar; timeOut: dword; force, reboot, reason: bool) : bool; stdcall;

function IsShutdownAllowed(flags: dword) : boolean;
var b1 : boolean;
begin
  b1 := false;
  if SendIpcMessage('ShutdownIpcQueue', @flags, 4, @b1, 1, 5000, false) and (not b1) then begin
    result := false;
    SetLastError(ERROR_ACCESS_DENIED);
  end else
    result := true;
end;

function ExitWindowsExCallback(flags, reserved: dword) : bool; stdcall;
begin
  result := IsShutdownAllowed(flags) and
            ExitWindowsExNext(flags, reserved);
end;

function GetShutdownFlags(force, reboot: boolean) : dword;
begin
  if reboot then
       result := EWX_REBOOT
  else result := EWX_SHUTDOWN;
  if force then
    result := result or EWX_FORCE;
end;

function InitiateSystemShutdownWCallback(pc, msg: pwideChar; timeOut: dword; force, reboot: bool) : bool; stdcall;
begin
  result := IsShutdownAllowed(GetShutdownFlags(force, reboot)) and
            InitiateSystemShutdownWNext(pc, msg, timeOut, force, reboot);
end;

function InitiateSystemShutdownExWCallback(pc, msg: pwideChar; timeOut: dword; force, reboot, reason: bool) : bool; stdcall;
begin
  result := IsShutdownAllowed(GetShutdownFlags(force, reboot)) and
            InitiateSystemShutdownExWNext(pc, msg, timeOut, force, reboot, reason);
end;

// ***************************************************************

begin
  HookAPI(  user32,             'ExitWindowsEx',             @ExitWindowsExCallback,             @ExitWindowsExNext);
  HookAPI(advapi32,   'InitiateSystemShutdownW',   @InitiateSystemShutdownWCallback,   @InitiateSystemShutdownWNext);
  HookAPI(advapi32, 'InitiateSystemShutdownExW', @InitiateSystemShutdownExWCallback, @InitiateSystemShutdownExWNext);
end.
MadshiCommented:
Application:

procedure ShutdownIpcQueue(name       : pchar;
                           messageBuf : pointer;
                           messageLen : dword;
                           answerBuf  : pointer;
                           answerLen  : dword); stdcall;
var s1 : string;
begin
  boolean(answerBuf^) := MayShutdown;
  if not MayShutdown then begin
    if      dword(messageBuf^) and EWX_LOGOFF <> 0 then s1 := 'You''re not allowed to log off.'
    else if dword(messageBuf^) and EWX_REBOOT <> 0 then s1 := 'You''re not allowed to restart Windows.'
    else                                                s1 := 'You''re not allowed to shutdown Windows.';
    MessageBox(0, pchar(s1), 'Information...', 0);
  end;
end;

begin
  CreateIpcQueue('ShutdownIpcQueue', ShutdownIpcQueue);
  InjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'ShutdownHooks.dll');
  [...]
end.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.