Каким образом запустить процесс завершения работы операционной
системы (функция ExitWindows) из кода моей программы? Мне необходимо
перезапустить операционную систему без перезапуска компьютера.
Ok, приводим обе функции для перезапуска операционной системы:
|
|
procedure TMainForm.RestartWindowsBtnClick(Sender:
TObject);
begin
if not ExitWindows(EW_RestartWindows, 0) then
ShowMessage('Приложение не может завершить
работу');
end; |
|
|
procedure TMainForm.RebootSystemBtnClick(Sender:
TObject);
begin
if not ExitWindows(EW_RebootSystem, 0) then
ShowMessage('Приложение не может завершить
работу');
end; |
Функция ExitWindows не была правильно задокументирована Microsoft'ом и не
содержит описания возвращаемого значения. Более того, информация о этой функции
практически не встречается в других источниках. Вот правильное определение этой
функции:
|
|
function ExitWindows (dwReturnCode: Longint;
Reserved: Word): Bool; |
Улучшения
Изменить данный совет мне помог Дмитрий
Слабко, приславший письмо следующего содержания:
Хотелось бы внести некоторые дополнения с Ваш FAQ, которые касаются вопроса о
завершении/перезагрузки Windows. Указанный код не даст результата для Windows NT
(и даже, наверное, для Win2000). Ниже - корректно работающий код для Win9x и
WinNT. Проверено под D4.
|
|
uses
Windows;
procedure RebootSystem; var
handle, ph: THandle;
pid, n: DWORD;
luid: TLargeInteger;
priv: TOKEN_PRIVILEGES;
dummy: PTokenPrivileges;
ver: TOSVERSIONINFO; begin
ver.dwOSVersionInfoSize := Sizeof(ver);
GetVersionEx(ver);
if ver.dwPlatformId=VER_PLATFORM_WIN32_NT then
begin
pid := GetCurrentProcessId;
if OpenProcessToken(ph, TOKEN_ADJUST_PRIVILEGES, handle)
then
if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', luid) then begin
priv.PrivilegeCount := 1;
priv.Privileges[0].Attributes :=
SE_PRIVILEGE_ENABLED;
priv.Privileges[0].Luid := luid;
dummy := nil;
AdjustTokenPrivileges(handle, false, priv, 0, dummy^, n);
end;
end;
ExitWindowsEx(EWX_REBOOT, 0); end; |
К сожалению, 32-битная функция ExitWindowsEx не позволяет выполнить простой
перезапуск Windows 95/98.
Тем не менее есть 16-битная функция ExitWindows, которая позволяет выполнить
перезапуск, будучи вызванной с параметром EW_RESTARTWINDOWS.
Соответственно, в 32-битном приложении Вам либо нужно использовать Thunks,
либо запускать дочернее 16-битное приложение, вызывающее данную функцию.
Даже если ты работаешь под Администратором, твоя программка должна запросить
дополнительные привилегии. Вот как это делается (на языке Си):void Reboot (void)
{
HANDLE hToken;
TOKEN_PRIVILEGES* NewState;
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&OSVersionInfo);
if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES,
&hToken);
NewState = (TOKEN_PRIVILEGES*) malloc (sizeof
(TOKEN_PRIVILEGES) + sizeof (LUID_AND_ATTRIBUTES));
NewState->PrivilegeCount = 1;
LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME,
&NewState->Privileges[0].Luid);
NewState->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges (hToken, FALSE, NewState, NULL, NULL, NULL);
free (NewState);
CloseHandle (hToken);
}
ExitWindowsEx (EWX_REBOOT, 0);
}
Здесь иная редакция этой процедуры (на Паскале, без проверки версии ОС) -
|
|
Procedure
Shutdown(Name:String; // Имя машины
(\\SERVER)
Message:String; //
Сообщение
Delay:Integer; // Задержка перед
рестартом
Restart,CloseAll:Boolean); var
ph:THandle;
tp,prevst:TTokenPrivileges;
rl:DWORD; begin
OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES
or TOKEN_QUERY,ph);
LookupPrivilegeValue(Nil,'SeShutdownPrivilege',tp.Privileges[0].Luid);
tp.PrivilegeCount:=1;
tp.Privileges[0].Attributes:=2;
AdjustTokenPrivileges(ph,FALSE,tp,SizeOf(prevst),prevst,rl);
InitiateSystemShutdown(PChar(name),PChar(Message),Delay,Restart,CloseAll);
ShowMessage(SysErrorMessage(GetLastError)); //
Результат end; | |