代码之家  ›  专栏  ›  技术社区  ›  Simon H.

当不运行win32 gui应用程序时,如何获取Windows电源状态消息(wm_powerbroadcast)?

  •  3
  • Simon H.  · 技术社区  · 15 年前

    所以基本上我有一个插件DLL,它由一个GUI应用程序加载。在这个dll中,我需要检测Windows何时进入休眠状态。我无法修改GUI应用程序。只有当调用线程与UI线程是同一线程时,getMessage才起作用,而UI线程不是。有什么想法吗?

    3 回复  |  直到 13 年前
        1
  •  8
  •   Indy9000    15 年前

    你可以在一个独立的线程中从你的DLL代码创建一个隐藏窗口。处理消息,如下所示。

    你可以用这个窗口类来实现。

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

    还要确保包含退出条件。

        2
  •  1
  •   Goz    15 年前

    您可以让您的dll用户传递其Hwnd。一旦你有了这个句柄,你就可以获取windowlongptr的window proc(gwl_wndproc),然后设置windowlongptr你自己的window proc,它将处理wm_powerbroadcast,并将所有消息传递给你从初始getwindowlongptr存储的旧window过程。

    当dll退出时,您可以将windowlongptr设置为它自己的window proc,即使您的dll被卸载,早期的thinigs也会继续很好地运行。

        3
  •  1
  •   Zach Burlingame    13 年前

    我在Windows控制台应用程序中遇到了类似的问题。我写了一篇关于问题是什么、隐藏窗口是如何成为唯一的解决方案以及如何做到这一点的博客文章。这个职位空缺 here 源代码可用 here . 我使用的基本原理几乎与Indeera的答案相同。

    我不确定您是否需要修改我的解决方案才能在DLL中运行。我相信所有有消息队列的线程(当线程创建一个窗口时,它会接收wm_powerbroadcast消息),因此即使Windows应用程序加载了您自己的线程,也可以对其进行假脱机。

    顺便说一句,值得注意的是,在系统进入休眠状态(如电池电量严重不足)或任何其他睡眠状态之前,您不能保证收到通知。但您将收到 PBT_APMRESUMEAUTOMATIC 事件(或) PBT_APMRESUMECRITICAL 在Vista之前的系统上)当系统在此类事件发生后重新联机时。