Можно ли обнаружить, что выход из системы был прерван в Windows? - PullRequest
0 голосов
/ 21 ноября 2018

Мне интересно, возможно ли программно перезапустить приложение, которое было прекращено в начале завершения работы, которое будет отменено позже.
В Windows, еслиприложение вызывает ShutdownBlockReasonCreate при завершении работы, оно может знать, отменил ли пользователь его или , а не , проверяя, установлен ли бит ENDSESSION_CRITICAL в lParam.
В моем случае я не хочу блокировать любое отключение.

Возможно ли это?Спасибо за любое предложение.

1 Ответ

0 голосов
/ 21 ноября 2018

Мне кажется, я нашел решение :

Я создал скрытое окно, используя 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;
}
...