是否可以检测到Windows上的注销已中止?

时间:2018-11-20 23:25:31

标签: winapi windows-vista shutdown

我想知道是否有可能在关机开始时以编程方式重新启动已被终止的应用程序,该应用程序稍后将被取消
在Windows上,如果应用程序在关机时调用ShutdownBlockReasonCreate,则可以通过检查ENDSESSION_CRITICAL是否知道用户是否已取消了没有 lParam中已设置该位。
就我而言,我不想阻止任何关闭。

这可能吗?感谢您的任何建议。

1 个答案:

答案 0 :(得分:0)

我想我找到了解决方案

我使用CreateWindowEx创建了一个隐藏窗口来处理WM_QUERYENDSESSIONWM_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将仅等待几秒钟,然后关闭。

在循环中,我从here中得到了这个想法。我不知道是否有更好的选择。

就是这样。

请对其进行测试,如果我错了,请纠正我。 谢谢。

[编辑] 这是准备就绪的测试程序的主要部分:

#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;
}