tags:

views:

373

answers:

2

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. GetMessage only works if the calling thread is the same thread as the UI-Thread, which it is not. Any ideas?

+1  A: 

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.

Indeera
Thanks, that works perfectly!
Simon H.
+1  A: 

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.

Goz
This could work as well but I don't have a direct way to get the HWND handle. I'd have to use something like FindWindow() to get the handle.
Simon H.