How to get the Windows Power State Message (WM_POWERBROADCAST) when not running a Win32 GUI app?

前端 未结 3 1225
余生分开走
余生分开走 2021-01-06 12:46

So basically I have a plugin dll that is loaded by a GUI-Application. In this dll I need to detect when Windows enters the Hibernate state. I cannot modify the GUI-App. GetM

相关标签:
3条回答
  • 2021-01-06 13:25

    You could create a hidden window in a seperate thread from your DLL code. And process messages as shown below.

    You could use this Window class for that.

    #pragma once
    
    #include <windows.h>
    #include <process.h>
    #include <iostream>
    
    using namespace std;
    
    static const char *g_AppName  = "Test";
    
    class CMyWindow
    {
        HWND  _hWnd;
        int _width;
        int _height;
    public:
        CMyWindow(const int width,const int height):_hWnd(NULL),_width(width),_height(height)
        {
            _beginthread( &CMyWindow::thread_entry, 0, this);
        }
    
        ~CMyWindow(void)
        {
            SendMessage(_hWnd, WM_CLOSE, NULL, NULL);
        }
    
    
    private:
        static void thread_entry(void * p_userdata)
        {
            CMyWindow * p_win = static_cast<CMyWindow*> (p_userdata);
            p_win->create_window();
            p_win->message_loop();
        }
    
        void create_window()
        {
            WNDCLASSEX wcex;
    
            wcex.cbSize         = sizeof(WNDCLASSEX);
            wcex.style          = CS_HREDRAW | CS_VREDRAW;
            wcex.lpfnWndProc    = &CMyWindow::WindowProc;
            wcex.cbClsExtra     = 0;
            wcex.cbWndExtra     = 0;
            wcex.hInstance      = GetModuleHandle(NULL);
            wcex.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
            wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
            wcex.lpszMenuName   = NULL;
            wcex.lpszClassName  = g_AppName;
            wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    
            RegisterClassEx(&wcex);
    
            _hWnd = CreateWindow(g_AppName, g_AppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
    
            ShowWindow(_hWnd, SW_SHOWDEFAULT);
            UpdateWindow(_hWnd);
        }
    
        void message_loop()
        {
            MSG msg = {0};
    
            while (GetMessage(&msg, NULL, 0, 0))
            {
                if(msg.message == WM_QUIT)
                {
                    break;
                }
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        static LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
            switch(uMsg)
            {
            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
            case WM_POWERBROADCAST:
                {
                    //power management code here
                }
    
            }
    
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        }
    };
    

    Also make sure to include an exit condition.

    0 讨论(0)
  • 2021-01-06 13:37

    You can get the user of your DLL to pass in their HWND . Once you have this handle you can GetWindowLongPtr the window proc (GWL_WNDPROC) and then SetWindowLongPtr your own window proc that will process the WM_POWERBROADCAST and pass all messages on to the old window procedure that you stored from the initial GetWindowLongPtr.

    When the DLL exits you can SetWindowLongPtr to its own window proc and even if your DLL is unloaded early thinigs will continue to play nicely.

    0 讨论(0)
  • 2021-01-06 13:37

    I ran into a similar problem with a Windows console application. I wrote up a blog post on what the issues are, how the hidden window seems like the only solution, and how to do it. The post is available here and the source code is available here. The basic principle I used is almost identical to Indeera's answer.

    I'm not sure if you would have to modify my solution at all to run in a DLL. I believe that ALL threads which have a message queue (and a thread does when it creates a window) receive WM_POWERBROADCAST messages, so spooling up one of your own even if you are loaded by a Windows application might work.

    It's worth noting by the way, that you aren't guaranteed to receive a notification prior to the system going into Hibernate (such as from a critical battery state) or any other sleep state for that matter. You will however receive a PBT_APMRESUMEAUTOMATIC event (or PBT_APMRESUMECRITICAL on systems prior to Vista) when the system comes back online after such an event has occurred.

    0 讨论(0)
提交回复
热议问题