Мне нужно выключить компьютер так, чтобы пользователь не смог отменить выключение, но и чтобы не потерять несохранённые данные. Решил сделать так: выключить компьютер API функцией ExitWindowsEx(EWX_SHUTDOWN) (т.е. не завершать приложения, которые ответили отказом на WM_QUERYENDSESSION), если компьютер не выключится через 30 секунд, сгибернировать его (спящий режим с сохранением RAM на HDD).
Теперь проблема. Если какое-то приложение имеет несохранённые данные, оно выдаёт запрос на сохранение. Если ничего не нажимать, то появится диалоговое окно снятия процесса (в Windows XP, по крайней мере). Если пользователь нажмёт "Отмена" в первом запросе, или "Отмена" или "Снять процесс" во втором запросе, то всё сработает. Но вот если пользователь просто проигнорирует предложение снять процесс, свернёт его и продолжит работать, то моя программа повиснет при попытки сгибернировать компьютер.
Вот код функций выключения и гибернации (скачал из интернета):
| Код | function LinkAPI(const module, functionname: string): Pointer; forward; function SetSuspendState(Hibernate, ForceCritical,DisableWakeEvent: Boolean): Boolean;forward; function MyExitWindows(RebootParam: Longword): Boolean;forward;
function MyExitWindows; var TTokenHd: THandle; TTokenPvg: TTokenPrivileges; cbtpPrevious: DWORD; rTTokenPvg: TTokenPrivileges; pcbtpPreviousRequired: DWORD; tpResult: Boolean; const SE_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, SE_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;
{ The SetSuspendState function suspends the system by shutting power down. Depending on the Hibernate parameter, the system either enters a suspend (sleep) state or hibernation.
Syntax: } { function SetSuspendState( Hibernate: Boolean; ForceCritical: Boolean; DisableWakeEvent: Boolean); }
{ Parameters:
Hibernate: If this parameter is TRUE, the system hibernates. If the parameter is FALSE, the system is suspended. ForceCritical: If this parameter is TRUE, the system suspends operation immediately; if it is FALSE, the system broadcasts a PBT_APMQUERYSUSPEND event to each application to request permission to suspend operation. DisableWakeEvent: If this parameter is TRUE, the system disables all wake events. If the parameter is FALSE, any system wake events remain enabled.
Windows NT/2000/XP: Included in Windows 2000 and later. Windows 95/98/Me: Included in Windows 98 and later. }
{var _SetSuspendState: function (Hibernate, ForceCritical, DisableWakeEvent: BOOL): BOOL stdcall = nil; }
function SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent: Boolean): Boolean; var _SetSuspendState: function (Hibernate, ForceCritical, DisableWakeEvent: BOOL): BOOL stdcall ;
begin _SetSuspendState:=nil; if not Assigned(_SetSuspendState) then @_SetSuspendState := LinkAPI('POWRPROF.dll', 'SetSuspendState'); if Assigned(_SetSuspendState) then Result := _SetSuspendState(Hibernate, ForceCritical, DisableWakeEvent) else Result := False; end;
function LinkAPI(const module, functionname: string): Pointer; var hLib: HMODULE; begin hLib := GetModulehandle(PChar(module)); if hLib = 0 then hLib := LoadLibrary(PChar(module)); if hLib <> 0 then Result := getProcAddress(hLib, PChar(functionname)) else Result := nil; end;
// Я вызываю так MyExitWindows(EWX_SHUTDOWN); // Потом SetSuspendState(true,true,false);
|
Я так понимаю, что Windows не даёт инициировать новое завершение работы, пока активно старое. Если перед тем, как гибернировать, отменить выключение, то, наверное, должно сработать.
Подскажите, как сделать? |