Ok, приводим обе функции для перезапуска операционной системы:
procedure TMainForm.RestartWindowsBtnClick(Sender: TObject);beginif not ExitWindows(EW_RestartWindows, 0) thenShowMessage('Приложение не может завершить работу');end; |
procedure TMainForm.RebootSystemBtnClick(Sender: TObject);beginif not ExitWindows(EW_RebootSystem, 0) thenShowMessage('Приложение не может завершить работу');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 beginpid := GetCurrentProcessId;if OpenProcessToken(ph, TOKEN_ADJUST_PRIVILEGES, handle) thenif LookupPrivilegeValue(nil, 'SeShutdownPrivilege', luid) then beginpriv.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; |