【问题标题】:Is it possible to detect that a log-off has been aborted on windows?是否可以检测到 Windows 上的注销已中止?
【发布时间】:2019-04-23 11:53:21
【问题描述】:

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

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

【问题讨论】:

  • 为什么是c++ 标签?
  • 有点笨拙,但您可以使用任务计划程序创建一个特定时间触发的任务(例如)未来 20 秒。
  • @abhishek_naik,我使用了 C++ 标签,因此没有针对 C#、VB 的解决方案
  • @JonathanPotter,在任务计划程序中创建任务需要管理员权限,我没有,也不想要求。
  • @perrahmaouy 不,任何用户都可以安排任务以自己的身份运行。

标签: winapi windows-vista shutdown


【解决方案1】:

我想我找到了解决方案

我使用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;
}

【讨论】:

  • 如果用户不取消关机,还是强制关机?您的WM_ENDSESSION 将由于您对ShutdownBlockReasonCreate() 的调用而无限期循环,因为系统不会自动终止应用程序,因为它正在等待它调用ShutdownBlockReasonDestroy() 来表示终止/关闭可以安全继续,但您不这样做不要那样做。 "应用程序在开始无法中断的操作时应调用 [ShutdownBlockReasonCreate()],例如刻录 CD 或 DVD。"
  • 我测试过了,即使我不调用ShutdownBlockReasonDestroy,Windows 也会不强制关闭计算机,因为我不是 b> 从顶级可见窗口调用ShutdownBlockReasonCreate。所以 Windows 给了它大约 30 秒,我认为可能更短,然后它就关闭了。
猜你喜欢
  • 2010-10-27
  • 1970-01-01
  • 2020-12-26
  • 2016-08-31
  • 2012-01-13
  • 2018-10-23
  • 1970-01-01
  • 2013-12-04
  • 2014-08-08
相关资源
最近更新 更多