如何在不运行Win32 GUI应用程序时获取Windows电源状态消息(WM_POWERBROADCAST)?

时间:2009-07-22 14:21:26

标签: c++ winapi

所以基本上我有一个由GUI-Application加载的插件dll。在这个DLL中我需要检测Windows何时进入休眠状态。我无法修改GUI-App。 GetMessage仅在调用线程与UI-Thread相同的线程时才有效,而不是。有什么想法吗?

3 个答案:

答案 0 :(得分:8)

您可以在DLL代码的单独线程中创建隐藏窗口。并处理如下所示的消息。

您可以使用此Window类。

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

还要确保包含退出条件。

答案 1 :(得分:1)

您可以让DLL的用户传入他们的HWND。一旦你有了这个句柄,你可以GetWindowLongPtr窗口proc(GWL_WNDPROC),然后SetWindowLongPtr你自己的窗口proc将处理WM_POWERBROADCAST并将所有消息传递给你从初始GetWindowLongPtr存储的旧窗口过程。

当DLL退出时,你可以将SetWindowLongPtr设置为它自己的窗口proc,即使你的DLL被卸载,早期的thinigs也会继续很好地运行。

答案 2 :(得分:1)

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

我不确定你是否必须修改我的解决方案才能在DLL中运行。我相信所有具有消息队列的线程(以及线程在创建窗口时都会这样做)都会收到WM_POWERBROADCAST消息,因此即使您被Windows应用程序加载,也可以使用自己的一个线程。

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