Мне кажется, я нашел решение :
Я создал скрытое окно, используя CreateWindowEx
для обработки сообщений WM_QUERYENDSESSION
и WM_ENDSESSION
:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_QUERYENDSESSION:
{
//clean up ...
ShutdownBlockReasonCreate(hwnd, L" ");
// What ? You said you don't want to block the shutdown ?
// Yes I do. It seems to work different with a hidden window.
return 1;
}
case WM_ENDSESSION:
{
// GetSystemMetrics(SM_SHUTTINGDOWN) return Nonzero if the current session is shutting down
// This loop waits for the user to cancel the shutdown
while(GetSystemMetrics(SM_SHUTTINGDOWN) != 0)
Sleep(100);
// The user has cancelled the shutdown here
// I can run the process again using CreateProcess or what ever...
// Once this line is executed this instance will be terminated
return 0;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
Значения return
очень важны (см. this ).
Как я и не ожидал, процесс без видимого окна верхнего уровня, даже если он вызывает ShutdownBlockReasonCreate
(сскрытый дескриптор окна), он не будет отображаться в списке приложений, блокирующих выключение.И если нет другого приложения, блокирующего отключение, Windows будет ждать только несколько секунд, а затем завершать работу.
Для цикла я взял идею из здесь .Я не знаю, есть ли лучшая альтернатива.
Вот и все.
Пожалуйста, проверьте это и исправьте меня, если я ошибаюсь.Спасибо.
[EDIT] Вот основная программа для готового теста:
#include <string>
#include <Windows.h>
using namespace std;
string getExePath()
{
TCHAR wpath[MAX_PATH];
GetModuleFileName (NULL, wpath, MAX_PATH);
size_t i;
char path[MAX_PATH];
wcstombs_s(&i, path, MAX_PATH, wpath, MAX_PATH);
return path;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_QUERYENDSESSION:
{
// A shutdown has been initiated
ShutdownBlockReasonCreate(hwnd, L" ");
return 1;
}
case WM_ENDSESSION:
{
// GetSystemMetrics(SM_SHUTTINGDOWN) return Nonzero if the current session is shutting down
// This loop waits for the user to cancel the shutdown
while(GetSystemMetrics(SM_SHUTTINGDOWN) != 0)
Sleep(100);
// The user has cancelled the shutdown here
// I can run the process again
WinExec(string("\"" + getExePath() + "\"").c_str(), SW_HIDE);
TerminateProcess(OpenProcess(PROCESS_TERMINATE, FALSE, GetCurrentProcessId()), 0);
return 0;
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
WNDCLASSEXA wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "TestShutDownAbortClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if( RegisterClassExA(&wc) == 0 )
return 1;
hwnd = CreateWindowExA(0,"TestShutDownAbortClass", "", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
return 1;
MSG msg;
while(GetMessageA(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
return 0;
}