{$UNSAFECODE ON}
unit ZamknijSystem;

interface

uses Windows,  //funkcje i stałe WinAPI
     SysUtils, //zmienna Win32Platform
     {$IF DEFINED(CLR)} //.NET
     System.Text, //klasa StringBuilder
     {$IFEND}
     Dialogs;  //funkcja ShowMessage



function ZamknijSystem1(Action :Integer) :Boolean;
function ZamknijSystem2(InicjujLubPrzerwij :Boolean; a_nazwa_komputera,a_komunikat :String; opoznienie :Integer; force,reboot :Boolean) :Boolean;
function UspijSystem(fSuspend,fForce :Boolean) :Boolean;

implementation

{ -------- ZAMKNIJ SYSTEM 1 -------- }
function ZamknijSystem1(Action :Integer) :Boolean;
var
  hToken :THandle; //uchwyt do tokenu procesu
  Luid :Int64; //zmienna 64-bitowa, w której przechowywany bedzie kod LUID uprawnienia
  tkp :TTokenPrivileges; //struktura tokenu
  rl :Cardinal;
  fResult :Boolean;
begin
//Jezeli tylko logoff (do niego nie trzeba uprawnien) to robi i wychodzi
if ((Action=EWX_LOGOFF) or (Action=(EWX_LOGOFF or EWX_FORCE)) or (Action=(EWX_LOGOFF or EWX_FORCEIFHUNG))) then
   begin
   Result:=ExitWindowsEx(Action,0);
   Exit;
   end;

//Jezeli nie NT, to robi od razu (funkcje pytajace o uprawnienia sa nieobecne w Win95/98/ME)
if (not (Win32Platform=VER_PLATFORM_WIN32_NT)) then
   begin
   Result:=ExitWindowsEx(Action,0);
   Exit;
   end;

//Jezeli jednak NT to pyta o uprawnienia

//Aby uzyskac uprawnienie dla biezacego procesu musimy wpierw pobrac uchwyt (handle) do tego procesu
//Otwarcie znaku procesu dla biezacego procesu (1 arg), prosimy o mozliwosc modyfikacji uprawnien procesu i pytanie (2 arg)
//Jezeli sie nie uda (wartosc) wyswietla komunikat
//Uwaga! W Delphi podaje sie zmienna tam, gdzie w C++ podawalo sie adres zmiennej
if (not OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,hToken)) then
        begin
        ShowMessage('Nie udało się otworzyć tokenu procesu');
        Result:=False;
        Exit;
        end;

//Pobranie LUID dla uprawnienia zamykania systemu (SE_SHUTDOWN_NAME)
LookupPrivilegeValue(nil, 'SeShutdownPrivilege', Luid);

//Ustalenie wartosci dla uprawnienia
tkp.PrivilegeCount:=1; //ile uprawnien do ustalenia
tkp.Privileges[0].Luid:=Luid;
tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED; //uaktywanienie uprawnienia (nadanie wartosci elementowi Attributes)

//Modyfikacja uprawnienia do zamkniecia systemu dla biezacego procesu (shutdown privilege)
//nie pobieramy informacji o stanie uprawnien sprzed modyfikacji
//ustalamy wartosc uprawnienia dla hToken na ustalona w &tkp
//AdjustTokenPrivileges(hToken, False, tkp, 0, nil, Cardinal(nil^));
AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl);

//Jezeli uruchomienie AdjustTokenPrivileges nie powidiodlo sie (np. system nie jest NT) wyswietlany jest komunikat
if (GetLastError() <> ERROR_SUCCESS) then ShowMessage('Przyznanie uprawnienia nie powiodlo sie.');

//Uruchomienie funkcji ExitWindowsEx (zadziala w NT tylko jezeli posiadamy (dokladniej jezeli proces posiada) uprawnienia do zamykania systemu)
fResult := ExitWindowsEx(Action,0);	//w fResult bedzie przechowywany wynik uruchomienia ExitWindowsEx (ewentualny kod bledu)
if (not fResult) then ShowMessage('Zamknięcie systemu nie jest możliwe - być może nie posiadasz odpowiednich uprawnień.');

//Odbieranie procesowi uprawnienia do zamykania systemu (dla elegancji i bezpieczenstwa)
tkp.Privileges[0].Attributes := 0; //rownoznaczne z NOT_ENABLED
//AdjustTokenPrivileges(hToken, False, tkp, 0, nil, Cardinal(nil^)); //modyfikacja uprawnienia bez pobrania informacji, korzystamy z poprzednio pobranego LUID
AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl); //modyfikacja uprawnienia bez pobrania informacji, korzystamy z poprzednio pobranego LUID

if (GetLastError() <> ERROR_SUCCESS) then ShowMessage('Odebranie uprawnienia nie powiodlo sie.'); //informacja jeżeli odbieranie uprawnienia nie powiodło się

Result:=fResult;
end;


{ -------- ZAMKNIJ SYSTEM 2 -------- }
function ZamknijSystem2(InicjujLubPrzerwij :Boolean; a_nazwa_komputera,a_komunikat :String; opoznienie :Integer; force,reboot :Boolean) :Boolean;
type
  {$IF NOT DEFINED(CLR)} //Win32
  PortableString=PChar;
  {$ELSE} //.NET
  PortableString=String;
  {$IFEND}
var
   hToken :THandle;
   Luid :TLargeInteger;
   tkp :TTokenPrivileges;
   rl :Cardinal;

   nazwa_komputera :PortableString;
   komunikat :PortableString;
   nazwa_uprawnienia :PortableString;

   //{$IF NOT DEFINED(CLR)} //Win32
   //nazwa_lokalnego_komputera :array[0..MAX_COMPUTERNAME_LENGTH+3] of Char;
   //{$ELSE} //.NET
   //nazwa_lokalnego_komputera :StringBuilder;
   //{$IFEND}

   dlugosc_nlk :Cardinal;
begin
//Zob. komentarze w ZamknijSystem1

if (not (Win32Platform=VER_PLATFORM_WIN32_NT)) then
    begin
    ShowMessage('Funkcja ZamknijSystem2 obsługuje jedynie systemy oparte na technologii NT');
    Result:=False;
    Exit;
    end;

nazwa_komputera:=PortableString(a_nazwa_komputera);
//Jezeli nazwa komputera nie jest wpisana to system lokalny
if (a_nazwa_komputera='') then nazwa_komputera:=nil;

komunikat:=PortableString(a_komunikat);

{$IF NOT DEFINED(CLR)} //Win32
//Jezeli wpisana nazwa identyfikuje lokalny komputer, to zmiana na nil
//dlugosc_nlk:=MAX_COMPUTERNAME_LENGTH+3;
//FillChar(nazwa_lokalnego_komputera,dlugosc_nlk,'0');
//GetComputerName(nazwa_lokalnego_komputera,dlugosc_nlk);
//if (UpperCase(a_nazwa_komputera)=UpperCase(nazwa_lokalnego_komputera)) then nazwa_komputera:=nil;
{$ELSE} //.NET
//Jezeli wpisana nazwa identyfikuje lokalny komputer, to zmiana na nil
//GetComputerName(nazwa_lokalnego_komputera,dlugosc_nlk);
//if (a_nazwa_komputera.ToUpper=nazwa_lokalnego_komputera.ToString.ToUpper) then nazwa_komputera:=nil;
{$IFEND}

if (not OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken)) then
  begin
	ShowMessage('Nie udało się otworzyć tokenu procesu');
  Result:=False;
  Exit;
  end;

//Teraz podawana jest tu nazwa komputera pobierana przez glowe funkcji ExitWindowsEx3
//Jezeli zamykamy lokalny komputer pobieramy LUID uprawnienia SE_SHUTDOWN_NAME na lokalnym komputerze, jezeli zdalny to SE_REMOTE_SHUTDOWN_NAME na zdalnym komputerze
nazwa_uprawnienia:='SeRemoteShutdownPrivilege';
if (nazwa_komputera=nil) then nazwa_uprawnienia:='SeShutdownPrivilege';
//LookupPrivilegeValue(p_nazwa_komputera,p_nazwa_uprawnienia,Luid);
if not LookupPrivilegeValue(nazwa_komputera,nazwa_uprawnienia,Luid) then
  begin
  ShowMessage('Odnalezienie kodu LUID uprawnienia nie powiodlo sie.');
  Result:=False;
  Exit;
  end;

tkp.PrivilegeCount:=1;
tkp.Privileges[0].Luid:=Luid;
tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;

if not AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl) then
  begin
  ShowMessage('Przyznanie uprawnienia nie powiodlo sie.');
  Result:=False;
  Exit;
  end;

if (InicjujLubPrzerwij) then
  begin
	if (not InitiateSystemShutdown(nazwa_komputera,komunikat,opoznienie,force,reboot)) then
    begin
    ShowMessage('Zamknięcie systemu nie jest możliwe - być może nie posiadasz odpowiednich uprawnień.');
    Result:=False;
    Exit;
    end;
  end
  else
  begin
	if (not AbortSystemShutdown(nazwa_komputera)) then
    begin
    ShowMessage('Odwołanie zamknięcia zdalnego systemu nie jest możliwe - być może nie posiadasz odpowiednich uprawnień.');
    Result:=False;
    Exit;
    end;
  end;


tkp.Privileges[0].Attributes := 0;
AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl);
if (GetLastError() <> ERROR_SUCCESS) then
  begin
  ShowMessage('Odebranie uprawnienia nie powiodlo sie.');
  Result:=False;
  Exit;
  end;

Result:=True;
end;

{ -------- USPIJ SYSTEM -------- }
function UspijSystem(fSuspend,fForce :Boolean) :Boolean;
var
   hToken :THandle;
   Luid :TLargeInteger;
   tkp :TTokenPrivileges;
   fResult :Boolean;
begin
//Komentarze zob. w ExitWindowsEx1

//Jezeli nie NT, to robi od razu (funkcje pytajace o uprawnienia sa nieobecne w Win95/98/ME)
if (not (Win32Platform=VER_PLATFORM_WIN32_NT)) then
        begin
	Result:=SetSystemPowerState(fSuspend,fForce);
        Exit;
        end;

//Jezeli jednak NT to pyta o uprawnienia
if (not OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken)) then
	ShowMessage('Nie udało się otworzyć tokenu procesu');

LookupPrivilegeValue(nil, 'SeShutdownPrivilege', Luid);

tkp.PrivilegeCount:=1;
tkp.Privileges[0].Luid:=Luid;
tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(hToken, False, tkp, 0, PTokenPrivileges(nil)^, Cardinal(nil^));
if (GetLastError() <> ERROR_SUCCESS) then ShowMessage('Przyznanie uprawnienia nie powiodło się.');


fResult := SetSystemPowerState(fSuspend,fForce);
if (not fResult) then ShowMessage('Wstrzymanie systemu nie powiodło się');


tkp.Privileges[0].Attributes := 0;
AdjustTokenPrivileges(hToken, False, tkp, 0, PTokenPrivileges(nil)^, Cardinal(nil^));
if (GetLastError() <> ERROR_SUCCESS) then ShowMessage('Odebranie uprawnienia nie powiodło się.');

Result:=fResult;
end;

end.

