您的当前位置:首页正文

阻止windows关机时自动结束进程,导致数据丢失或异常

2024-11-06 来源:个人技术集锦
windows在结束对话或者一个系统关机的时候,系统会发送WM_QUERYENDSESSION消息给尚未终止的所有窗口。当程序在处理这个消息的时候,如果返回了false,那么系统将不结束对话或者关机(注销)。
需要注意在XP里面,我们直接返回false,可以做到阻止关机的作用,但是在Windows Vista及在这之后的操作系统,直接返回false无法达到阻止关机的效果。需要借助两个函数ShutdownBlockReasonCreate和ShutdownBlockReasonDestroy
XP里面处理比较简单,所以这里主要说Vista之后的操作系统
可以把整个处理分成几个部分:

1.当我们的程序收到系统的WM_QUERYENDSESSION函数时,返回false,并且使用ShutdownBlockReasonCreate弹提示说明关机被打断的原因
2.向系统安装钩子处理控制台消息(初始化的时候)
3.过滤控制台消息,如果用户强制关机,发送WM_CLOSE给我们的程序
4.这时候我们调用ShutdownBlockReasonDestroy让关机继续进行

这种代码网上很多,这里附上我整理的相关函数,全部代码和别的代码混在一起,太乱

这是处理控制台的钩子函数

BOOL WINAPI 
ConsoleCtrlHandler(DWORD dwCtrlType)
{
    // 用户按下CTRL+BREAK, 或者由GenerateConsoleCtrlEvent API发出,当试图关闭控制台程序,系统发送关闭消息。
    if (dwCtrlType == CTRL_C_EVENT ||
        dwCtrlType == CTRL_BREAK_EVENT || 
        dwCtrlType == CTRL_CLOSE_EVENT) {
            SendMessage(hWnd, WM_CLOSE, 0, 0);
        return TRUE;
    }
    return FALSE;
}

注册窗口类

void 
register (HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = (WNDPROC)procWndMsg;    //回调函数
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"TestClass";
    wcex.hIconSm = NULL;
    // 安装钩子处理控制台消息
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleCtrlHandler, TRUE);

创建窗口类

BOOL creatWindow(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance;
    RECT sz = {0, 0, 512, 512};
    AdjustWindowRect(&sz, WS_OVERLAPPEDWINDOW, TRUE);
    hWnd = CreateWindow(L"TestClass", L"Test Window", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, sz.right - sz.left, sz.bottom - sz.top,
        NULL, NULL, hInstance, NULL);
    if(!hWnd)
    {
        return FALSE;
    }
}

处理信息回调函数

LRESULT CALLBACK procWndMsg(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    switch(message)
    {
        case WM_QUERYENDSESSION:
          if (ncOSUtil::IsWinXPFamily ()){
                    static BOOL bFlag = FALSE;
                    if (bFlag) {
                        return TRUE;
                    }
                    //这里建议弹出个等待窗口来提示,因为XP没有还有进程未关闭那个界面
                    bFlag = TRUE;

                    return FALSE;   
                }
                else {
                    return FALSE;
                }
            break;
        case WM_CREATE:
           if (!ncOSUtil::IsWinXPFamily ()) {
           //这里使用函数指针来调用,否则在XP下,USER32里面没有这两个函数,会无法找到入口
           //即使用if不进入这里也会报错,亲测
                typedef BOOL (WINAPI* SHUTDOWNBLOCKREASONCREATE) (__in HWND hWnd, __in LPCWSTR pwszReason);
                HMODULE hUser32Dll = GetModuleHandle (_T("User32"));
                SHUTDOWNBLOCKREASONCREATE pShutdownBlockReasonCreate = (SHUTDOWNBLOCKREASONCREATE)GetProcAddress (hUser32Dll, "ShutdownBlockReasonCreate");
                if (pShutdownBlockReasonCreate) {
                    pShutdownBlockReasonCreate (hwnd, L"程序正在运行,建议手动关闭后在关机或注销,以免引起数据丢失。");  //弹提示,阻止关机
                }
            }
            break;
        case WM_DESTROY:
            if (!ncOSUtil::IsWinXPFamily ()) {
                typedef BOOL (WINAPI* SHUTDOWNBLOCKREASONDESTROY) (__in HWND hWnd);
                HMODULE hUser32Dll = GetModuleHandle (_T("User32"));
                SHUTDOWNBLOCKREASONDESTROY pShutdownBlockReasonDestroy = (SHUTDOWNBLOCKREASONDESTROY)GetProcAddress (hUser32Dll, "ShutdownBlockReasonDestroy");

                if (pShutdownBlockReasonDestroy) {
                    pShutdownBlockReasonDestroy (hwnd);   //继续关机
                }
                PostQuitMessage (0);                            //退出消息循环
                }
                break;
        default:
           break;
    }
    return TRUE;
}
当然了,如果你是单独做一个这个小程序,完全可以不向系统安装钩子,直接循环获取消息,类似于这样
   MSG msg;
    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;

经过我的测试,发现如果电脑上用优化软件优化了系统性能,会杀掉我的软件,无法阻止关机,解决办法和这个分开写

Top