2007. november 18., vasárnap

Reboot, log off, shut down or turn off the system


Problem/Question/Abstract:

How would I reboot the system and restart my program?

Answer:

Solve 1:

This will reboot, shutdown, etc. It's a wrapper function for the ExitWindowsEx API:

function ExitWin(ExitType: Integer): Boolean;
{ExitType can be any of these values:
EWX_FORCE, EWX_LOGOFF, EWX_POWEROFF, EWX_REBOOT, EWX_SHUTDOWN}

  function GetShutdownPrivilege: Boolean;
  var
    hToken: THandle;
    tkp: TTokenPrivileges;
    retlength: DWORD;
    Newt: TTokenPrivileges;
  begin
    Result := False;
    hToken := GetCurrentProcess();
    if OpenProcessToken(hToken, TOKEN_ADJUST_PRIVILEGES + TOKEN_QUERY, hToken) then
    begin
      {Get the LUID for shutdown privilege}
      if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', tkp.Privileges[0].Luid) then
      begin
        tkp.PrivilegeCount := 1; {One privilege to set}
        tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        {Get shutdown privilege for this process}
        Result := AdjustTokenPrivileges(hToken, FALSE, tkp, sizeof(TTokenPrivileges),
          Newt, retlength)
      end;
    end;
  end;

begin
  if Win32Platform = VER_PLATFORM_WIN32_NT then
    GetShutdownPrivilege;
  if ExitWindowsEx(ExitType, 0) then
  begin
    Result := True;
  end
  else
  begin
    Result := False;
  end;
end;


Solve 2:

procedure QuitWindows(uFlags: UINT; forced: boolean);
{uFlages can be: EWX_LOGOFF, EWX_REBOOT or EWX_SHUTDOWN}
var
  hProcess: THandle;
  hToken: THandle;
  tpAct, tpPrev: TTokenPrivileges;
  wDummy: DWORD;
begin
  hProcess := GetCurrentProcess;
  OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);
  LookupPrivilegeValue(nil, 'SeShutdownPrivilege', tpAct.Privileges[0].Luid);
  tpPrev := tpAct;
  tpAct.PrivilegeCount := 1;
  tpAct.Privileges[0].Attributes := 2;
  AdjustTokenPrivileges(hToken, false, tpAct, SizeOf(tpPrev), tpPrev, wDummy);
  if forced then
    uFLags := uFlags or EWX_FORCE;
  ExitWindowsEx(uFlags, 0);
end;


Solve 3:

function GetShutdownPrivilege: Boolean;
const
  SHN: PChar = 'SeShutdownPrivilege';
  EMP: PChar = '';
var
  hToken: THandle;
  tkp, p: TTokenPrivileges;
  RetLen: DWORD;
  Err: DWord;
begin
  {Get a token for this process.}
  if not OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or
    TOKEN_QUERY, hToken) then
  begin
    Result := False; // 'Error: OpenProcessToken:' + IntToStr(GetLastError)
    Exit;
  end;
  {Get the LUID for the shutdown privilege.}
  if not LookupPrivilegeValue(EMP, SHN, tkp.Privileges[0].Luid) then
  begin
    Result := False; // 'Error: LookupPrivilegeValue:' + IntToStr(GetLastError)
    Exit;
  end;
  tkp.PrivilegeCount := 1; {One privilege to set}
  tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
  {Get the shutdown privilege for this process}
  AdjustTokenPrivileges(hToken, False, tkp, SizeOf(TTokenPrivileges), p, RetLen);
  {Cannot test the return value of AdjustTokenPrivileges}
  Err := GetLastError;
  if Err <> ERROR_SUCCESS then
  begin
    { Err = 1300: 'You do not have the right to shut the system down'
    else
      'Error: AdjustTokenPrivileges: ' + IntToStr(Err); }
    Result := False;
    Exit;
  end;
  {Current user have privileges to shutdown the system}
  Result := True;
end;

Usage:

function MyExit(Param1, Param2: LongWord): Boolean;
if Win32Platform = VER_PLATFORM_WIN32_NT then
  GetShutdownPrivilege;
Result := ExitWindowsEx(Param1, Param2)
end;


Solve 4:

A quite common question I see often in discussion groups is how to shutdown/reboot Windows NT. The problem is that the usual API for the task, ExitWindowsEx, doesn't work right away with Windows NT. It's necessary to "ask for permission" before calling ExitWindows NT. This means that a process must have the SE_SHUTDOWN_NAME privilege for rebooting, powering off, or shutting the system, forced or not (using the EWX_FORCE flag).

For those who have taken a look at the Win32 Development Guide, a help file that comes with Delphi, there's a topic that explains how to shut down Windows NT, but that code is in C++. I've translated the code to Delphi, creating a function called ExitWindowsNT.

Calling ExitWindowsNT is just like calling ExitWindowsEx with only the uFlags paramter. The uFlags parameter specifies the type of shutdown. More about this is explained in the topic "ExitWindowsEx" in the Win32 SDK.

All that said, let's go the function itself:

procedure ExitWindowsNT(uFlags: integer);
var
  hToken: THANDLE;
  tkp, tkDumb: TTokenPrivileges;
  DumbInt: integer;
begin
  FillChar(tkp, sizeof(tkp), 0);
  // Get a token for this process
  if not (OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES
    or TOKEN_QUERY, hToken)) then
    raise Exception.create('OpenProcessToken failed with code '
      + inttostr(GetLastError));

  // Get the LUID for the Shutdown privilege
  LookupPrivilegeValue(nil, pchar('SeShutdownPrivilege'),
    tkp.Privileges[0].Luid);

  tkp.PrivilegeCount := 1; // one privilege to set
  tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;

  // Get the shutdown provolege for this process
  AdjustTokenPrivileges(hToken, false, tkp, sizeof(tkDumb), tkDumb, DumbInt);

  // Cannot test the return value of AdjustTokenPrivileges
  if GetLastError <> ERROR_SUCCESS then
    raise Exception.create('AdjustTokenPrivileges failed with code '
      + inttostr(GetLastError));

  // shut down the system and for all applications to close
  if not ExitWindowsEx(uFlags, 0) then
    raise Exception.create('ExitWindowsEx failed with code '
      + inttostr(GetLastError));
end;

A few examples on using the function above are:

ExitWindowsNT(EWX_SHUTDOWN or EWX_FORCE); ---- This will shutdown Windows NT without making questions. All opened applications will be closed and any unsaved data will be lost.

ExitWindowsNT(EWX_REBOOT); ---- This will reboot the system. Applications will be sent the WM_QUERYENDSESSION message so they can stop the process.

For other possible combinations of EWX_FORCE, EWX_REBOOT, EWX_POWEROFF, EWX_LOGOFF, EWX_SHUTDOWN, please refer to the Win32 Development Guide.


Solve 5:

Shut-down system under Win XP:

function DoExitWindows(RebootParam: Longword): boolean;
var
  TTokenHd: THandle;
  TTokenPvg: TTokenPrivileges;
  cbtpPrevious: DWORD;
  rTTokenPvg: TTokenPrivileges;
  pcbtpPreviousRequired: DWORD;
  tpResult: boolean;
const
  cSE_SHUTDOWN_NAME = 'SeShutdownPrivilege';
begin
  if (Win32Platform = VER_PLATFORM_WIN32_NT) then
  begin
    tpResult := OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES
      or TOKEN_QUERY, TTokenHd);
    if tpResult then
    begin
      tpResult := LookupPrivilegeValue(nil, cSE_SHUTDOWN_NAME,
        TTokenPvg.Privileges[0].Luid);
      TTokenPvg.PrivilegeCount := 1;
      TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      cbtpPrevious := SizeOf(rTTokenPvg);
      pcbtpPreviousRequired := 0;
      if tpResult then
        Windows.AdjustTokenPrivileges(TTokenHd, false, TTokenPvg, cbtpPrevious,
          rTTokenPvg, pcbtpPreviousRequired);
    end;
  end;
  Result := ExitWindowsEx(RebootParam, 0);
end;

Used like this:

DoExitWindows(EWX_SHUTDOWN or EWX_FORCE);

Nincsenek megjegyzések:

Megjegyzés küldése