{
  Author  : Michael Puff - http://www.michael-puff.de
  Date    : 2006-02-11
  License : PUBLIC DOMAIN
}

unit MpuShutdownCls;

interface

uses
  Windows;

///////////////////////////////////////////////////////////////////////////////
//  FFlags: Shutdown type
//
//  Possible values:
//
//  EWX_LOGOFF                  Shuts down all processes running in the logon
//  0                           session of the process that called the
//                              ExitWindowsEx function. Then it logs the user
//                              off.
//                              This flag can be used only by processes
//                              running in an interactive user's logon session.
//  EWX_POWEROFF                Shuts down the system and turns off the power.
//  $00000008                   The system must support the power-off feature.
//                              The calling process must have the
//                              SE_SHUTDOWN_NAME privilege. For more
//                              information, see the following Remarks section.
//  EWX_REBOOT                  Shuts down the system and then restarts the
//  $00000002                   system.
//                              The calling process must have the
//                              SE_SHUTDOWN_NAME privilege. For more
//                              information, see the following Remarks section.
//  EWX_SHUTDOWN                Shuts down the system to a point at which it
//  $00000001                   is safe to turn off the power. All file buffers
//                              have been flushed to disk, and all running
//                              processes have stopped.
//                              The calling process must have the
//                              SE_SHUTDOWN_NAME privilege. For more information,
//                              see the following Remarks section.
//                              Specifying this flag will not turn off the power
//                              even if the system supports the power-off feature.
//                              You must specify EWX_POWEROFF to do this.
//                              Windows XP SP1:  If the system supports the
//                              power-off feature, specifying this flag turns
//                              off the power.
//
//
//  FForce: Forces processes to terminate
//
//  Possible value:
//
//  EWX_FORCE                   Windows 2000/NT:  Forces processes to terminate.
//  $00000004                   When this flag is set, the system does not send
//                              the WM_QUERYENDSESSION and WM_ENDSESSION messages.
//                              This can cause the applications to lose data.
//                              Therefore, you should only use this flag in an
//                              emergency.
//                              Starting with Windows XP, these messages will
//                              always be sent.




type
  TShutdown = class(TObject)
    private
      FFlags: DWORD;
      function EnablePrivilege(const Privilege: string; fEnable: Boolean; out PreviousState: Boolean): DWORD;
      procedure SetFlags(AFlags: DWORD);
      procedure SetForce(AForce: Boolean);
    public
      constructor Create;
      function Execute: Boolean;
      property Flags: DWORD write SetFlags;
      property Force: Boolean write SetForce;
  end;

implementation

constructor TShutdown.Create;
begin
  FFlags := 0;
end;

function TShutdown.EnablePrivilege(const Privilege: string; fEnable: Boolean; out PreviousState: Boolean): DWORD;
var
  Token             : THandle;
  NewState          : TTokenPrivileges;
  Luid              : TLargeInteger;
  PrevState         : TTokenPrivileges;
  Return            : DWORD;
begin
  SetLastError(0);  // Clear last system error state
  PreviousState := True;
  if (GetVersion() > $80000000) then // Win9x
    Result := ERROR_SUCCESS
  else // WinNT
  begin
    if OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, Token) then
    begin
      try
        if LookupPrivilegeValue(nil, PChar(Privilege), Luid) then
        begin
          NewState.PrivilegeCount := 1;
          NewState.Privileges[0].Luid := Luid;
          if fEnable then
            NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
          else
            NewState.Privileges[0].Attributes := 0;
          if AdjustTokenPrivileges(Token, False, NewState, SizeOf(TTokenPrivileges), PrevState, Return) then
          begin
            PreviousState := (PrevState.Privileges[0].Attributes and SE_PRIVILEGE_ENABLED <> 0);
          end;
        end;
      finally
        CloseHandle(Token);
      end;
    end;
    Result := GetLastError;
  end;
end;

procedure TShutdown.SetFlags(AFlags: DWORD);
begin
  FFlags := FFlags or AFlags;
end;

procedure TShutdown.SetForce(AForce: Boolean);
begin
  FFlags := FFlags or EWX_FORCE;
end;

function TShutdown.Execute;
var
  err: DWORD;
  PrevStat: Boolean;
begin
  err := EnablePrivilege('SeShutDownPrivilege', True, PrevStat);
  if err = 0 then
  begin
    if not ExitWindowsEx(FFlags, 0) then
      err := GetLastError;
  end
  else
    EnablePrivilege('SeShutDownPrivilge', PrevStat, PrevStat);
  result := err = 0;
end;

end.

