Link to home
Start Free TrialLog in
Avatar of ruanlab123
ruanlab123Flag for South Africa

asked on

Determine Windows shutdown or reboot

Hi Experts

Is there a way that I could determine if Windows shutdown, if it is a shutdown or a reboot.
My Delphi app stops the windows shutdown if still busy, but if finished I want to either shutdown or
reboot the pc according to what the user have choosen.

I've used the follwing code to stop the shutdown

procedure TForm_Main.WMQueryEndSession(var M: TWMQueryEndSession);
begin
  if ClientBusy = False then
    M.Result := 1
  else
    M.Result := 0;
end;
   
Thanks
Avatar of FarajLY
FarajLY




WinExit(EWX_LOGOFF); // one of these 3 only :-)
WinExit(EWX_REBOOT);
WinExit(EWX_SHUTDOWN);

See the source for the flags EWX_POWEROFF and EWX_FORCE.
The function SetPrivilege() is a necessary helper function.
The other document referenced at the top in the See-Also section is a slight modification of this code snippet, but it works basically the same way.

   
 function SetPrivilege (sPrivilegeName: string; bEnabled: Boolean) : Boolean;
var
  TPPrev,
  TP       : TTokenPrivileges;
  Token    : THandle;
  dwRetLen : DWORD;
begin
  result := False;
 
  OpenProcessToken (GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, @Token);
 
  TP.PrivilegeCount := 1;
  if LookupPrivilegeValue (nil, PChar (sPrivilegeName), TP.Privileges[0].LUID) then
  begin
    if bEnabled then
      TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
    else
      TP.Privileges[0].Attributes := 0;
   
    dwRetLen := 0;
    result := AdjustTokenPrivileges (Token, False, TP, SizeOf (TPPrev), TPPrev,
      dwRetLen)
  end;
 
  CloseHandle (Token)
end;


//
// iFlags:
//
//  one of the following must be
//  specified
//
//   EWX_LOGOFF
//   EWX_REBOOT
//   EWX_SHUTDOWN
//
//  following attributes may be
//  combined with above flags
//
//   EWX_POWEROFF
//   EWX_FORCE    : terminate processes
//
function WinExit (iFlags: integer) : Boolean;
begin
  result := true;
  if SetPrivilege ('SeShutdownPrivilege', true) then
  begin
    if (not ExitWindowsEx (iFlags, 0)) then
    begin
      // handle errors...
      result := False
    end;
    SetPrivilege ('SeShutdownPrivilege', False)
  end
  else
  begin
    // handle errors...
    result := False
  end
end;  
as you can see in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shutdown/base/wm_queryendsession.asp
there is no way of detecting if it's a shutdown or a reboot using API.
however, as said in this PAQ https://www.experts-exchange.com/questions/21019028/How-to-detect-the-difference-in-a-Logoff-Reboot-or-Shutdown.html, you can use madhi's hook components and hook into the shutdown api's.
Avatar of ruanlab123

ASKER

Ok, I know about the madhi's hook components, I've use it before to not allow an process kill.
But what API must I hook, to determine if it was a shutdown or a reboot?
as it is mentioned in the PAQ I've told you about, it's the function ExitWindowsEx you should hook.
ok my dll looks like this :
var
  Reg : TRegistry;
  ExitWindowsExNext : function (uFlags, dwReserved : Cardinal) : LongBool; stdcall;

{$R *.res}
function ExitWindowsEx(uFlags, dwReserved : Cardinal) : LongBool; stdcall;
begin
  Reg := TRegistry.Create;
  Reg.RootKey := HKEY_LOCAL_MACHINE;
  if Reg.OpenKey(RegKey,True) then
  begin
    if (uFlags = EWX_SHUTDOWN) or (uFlags = EWX_POWEROFF) then
    try
      Reg.WriteString('ShutdownProc','Shutdown');
    except
    end;
    if uFlags = EWX_REBOOT then
    try
      Reg.WriteString('ShutdownProc','Reboot');
    except
    end;
  end;
  Result := False;
end;
begin
  HookAPI('kernel32.dll', 'ExitWindowsEx', @ExitWindowsEx,@ExitWindowsExNext); //hook the API
end.

and I've changed the code to stop the shutdown to this

procedure TForm_Main.WMQueryEndSession(var M: TWMQueryEndSession);
begin
  if ClientBusy = False then
    M.Result := 1
  else
  begin
    InjectLibrary(ALL_SESSIONS or SYSTEM_PROCESSES, 'C:\WINDOWS\system32\DigiCVSDN.dll');
    M.Result := 1;
  end;
end;

but now the shutdown is not stopped and no values in been written to the registy?
i would do some logging in the hook function just to make sure nothing is being lost.

as a "protocol" of mine, I always call the hooked function (if needed) to make sure that I don't accidentally "kill" functionality.

in you code, you also forgot to free the registry object.
plus that your hook function always return false. why? false has a "value" of zero, and you are hence signaling that an error occured.
Ok, I've tried everything this weekend, nothing works.
Looks like if the ExitWindowsEx function that I've hooked is never called, I've put in some showmessages but it never shows.
If I change M.Result = 0 in the WMQueryEndSession procedure the shutdown is stopped, but then according to me the ExitWindowsEx function will not be called, change it back to M.Result = 1, ExitWindowsEx function is still not called and windows reboot or shutdown without even showing my showmessages.
Any suggestions?
sorry for the blackout. been a little too busy. I'll try to do this myself though I never worked with these components :)

I'll let you know in a day or two of the results (I'm still a little busy ;) )
thanks, I will be waiting on your reply then.
ASKER CERTIFIED SOLUTION
Avatar of 2266180
2266180
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial