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

C++ 当不运行Win32 GUI应用程序时,如何获取Windows电源状态消息(WM_POWERBROADCAST)?,c++,winapi,C++,Winapi,所以基本上我有一个插件dll,由GUI应用程序加载。在这个dll中,我需要检测Windows何时进入休眠状态。我无法修改GUI应用程序。GetMessage仅在调用线程与UI线程是同一个线程时有效,而UI线程不是。有什么想法吗?您可以在DLL代码的单独线程中创建一个隐藏窗口。并按如下所示处理消息 您可以使用这个窗口类来实现这一点 #pragma once #include <windows.h> #include <process.h> #include <ios

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

您可以在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);
    }
};
#pragma一次
#包括
#包括
#包括
使用名称空间std;
静态常量char*g_AppName=“Test”;
CMyWindow类
{
HWND HWND;
内部宽度;
内部高度;
公众:
CMyWindow(常量整型宽度,常量整型高度):\u-hWnd(NULL),\u-width(宽度),\u-height(高度)
{
_beginthread(&CMyWindow::thread\u条目,0,this);
}
~CMyWindow(无效)
{
SendMessage(_hWnd,WM_CLOSE,NULL,NULL);
}
私人:
静态void thread_条目(void*p_userdata)
{
CMyWindow*p_win=静态_cast(p_userdata);
p_win->创建_窗口();
p_win->message_loop();
}
void创建_窗口()
{
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(空,IDI_应用程序);
wcex.hCursor=LoadCursor(空,IDC_箭头);
wcex.hbrBackground=(HBRUSH)(彩色窗口+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=g_AppName;
wcex.hIconSm=LoadIcon(空,IDI_应用程序);
注册类别(&wcex);
_hWnd=CreateWindow(g_AppName,g_AppName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,GetModuleHandle(NULL),NULL);
显示窗口(显示默认值);
更新域(_hWnd);
}
无效消息_循环()
{
MSG={0};
while(GetMessage(&msg,NULL,0,0))
{
如果(msg.message==WM\u退出)
{
打破
}
翻译信息(&msg);
发送消息(&msg);
}
}
静态LRESULT WINAPI WindowProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg)
{
案例WM_销毁:
PostQuitMessage(0);
返回0;
案例WM_POWERBROADCAST:
{
//这里是电源管理代码
}
}
返回DefWindowProc(hWnd、uMsg、wParam、lParam);
}
};

还要确保包含退出条件。

您可以让DLL的用户传入其HWND。拥有此句柄后,您可以获取WindowLongptr窗口进程(GWL_WNDPROC),然后设置WindowLongptr您自己的窗口进程,该进程将处理WM_POWERBROADCAST,并将所有消息传递到从初始GetWindowLongPtr存储的旧窗口进程


当DLL退出时,您可以将WindowLongPtr设置为它自己的窗口进程,即使您的DLL被卸载,早期的东西也会继续很好地发挥作用。

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

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


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

这也可以工作,但我没有直接的方法获取HWND句柄。我必须使用类似FindWindow()的东西来获得句柄。子类化(更改wndproc)您不拥有的hwnd应该被视为最后的手段;如果有两段代码要执行,那么它可能会特别脆弱。更糟糕的情况是,在卸载DLL后,另一段代码将wndproc“还原”到DLL的wndproc,从而导致崩溃。在Raymond Chen的博客上查看这篇文章:。最低限度,你应该在API文档中明确说明传入的hwnd将以这种方式进行子类化。非常好的示例..我可以知道如何在应用程序中使用此DLL吗?@Zach..很好的博客..但是我可以知道当前的源代码链接吗?Cf:代码不再可用不幸的是,我忘记了在恢复时这里有交叉链接不新鲜的我会看看是否可以把它放在GitHub上,然后更新链接。