将Windows事件(WM_)重定向到隐藏窗口

时间:2012-06-18 15:44:25

标签: c# wpf windows winapi hook

我目前正在开展一个涉及大量挂钩的项目,旨在以与“Steam Overlay”相同的方式作为交互式产品的叠加层。

挂钩部分实际上是完整的。我们有一个“隐形”WPF应用程序,它执行DLL注入,挂钩DirectX,将自身呈现为纹理,然后在被挂钩的应用程序上呈现该纹理。

Program structure

我们遇到的困难是后一部分;获取用于叠加层的输入信息。正如您在图中看到的那样,简单的示例是一个被按下的按钮。我想要做的是,实际上将所有输入消息(WM_x)捕获到DirectX应用程序,然后让WPF应用程序决定哪些消息与覆盖相关,哪些不是。

我设法使用...

挂钩了DirectX应用程序的WNDPROC
IntPtr _oldWindProc = GetWindowLong(MainWindowHandle, Win32Helper.GWL_WNDPROC);
WndProcDelegate _myProc = new Win32Helper.WndProc(WndProc);
SetWindowLong(MainWindowHandle, Win32Helper.GWL_WNDPROC, _myProc );

......这似乎运作良好。此时,我可以将所有WM_x消息传递回WPF应用程序。但那就是我陷入困境的地方。我试过PostMessage并且Spy ++显示接收消息的WPF窗口(实际上在WPF窗口内设置一个钩子显示相同的内容)但这似乎没有按预期工作。那么,我错过了什么?我应该回复某些Windows消息吗?我天真地认为它就像让WPF应用程序在正确的位置接收“WM_LBUTTONDOWN”一样简单,而按钮会压低。

非常感谢任何指导。

更新:我可能稍微掩饰了实际问题。我想将消息重定向到WPF,就像它是他们的预期目的地一样。我已经将这些消息挂钩并阻止它们进入DirectX应用程序。问题是如何将它们无缝地传递给WPF应用程序。

2 个答案:

答案 0 :(得分:1)

我会使用带有SetWindowsHookEx的dll挂钩directx应用程序并将其消息传递回主应用程序的子类窗口。我在C ++中完成了这个,你应该能够使用pinvoke或其他东西在C#中完成它。这是C ++中的代码:

__declspec(dllexport) int _stdcall InstallHook(DWORD dwThreadId, HWND ExtrnHandle, HWND Apphandle)
{
    if (hHook==0)
            hWndApp = Apphandle;
            hWndHooked = ExtrnHandle;
            hHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC) GetMsgProc, (HINSTANCE) hInstance, dwThreadId);
        if (hHook==0) return GetLastError();
    return 0;
}

用此来取消挂钩:

 __declspec(dllexport) int UnInstallHook(void)
{
    LRESULT result;
    if (hHook != 0){
        result = UnhookWindowsHookEx(hHook);
        if (result == 0) return GetLastError();
        hHook = 0;
    }
    return 0;
}

然后在你的dll中使用此回调将消息传递回应用程序:

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    MSG *lpMsg;

    if (nCode==HC_ACTION){
        lpMsg = (MSG *) lParam;
        //see if this is the window we are monitoring
        if (lpMsg->hwnd == hWndHooked){
            //forward the message to App
            ChangeMessage=false;
            SendMessage(hWndApp, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
            if (ChangeMessage==true){//Did App make changes to the data?
                lpMsg->message = Shared_uMsg;
                lpMsg->wParam = Shared_wParam;
                lpMsg->lParam = Shared_lParam;

            }//end if change message

        }//end if correct hWnd
    }//end if nCode==Action     
    return(CallNextHookEx(hHook, nCode, wParam, lParam));
}

另外,fyi,这里是dll .cpp文件顶部的代码,声明,设置共享数据的函数等:

#include "afxdisp.h" //this does #include <windows.h>
#include <shellapi.h>
#include "WINUSER.H"    
#include <fstream>
#include <iostream>
using namespace std;

#define WM_MOUSEWHEEL 0x020A 
#define COPY2CLIPBOARD 1 //for copying data from msflexgrid
#define COPY2FILE      2

/*---------------------------------------------
          Shared Variables
This data is shared between both prcesses.  The
VB App has access to these variables through the
function SetSharedData
---------------------------------------------*/
#pragma data_seg(".shared")
    bool ChangeMessage = false;
    int Shared_uMsg = 0;
    int Shared_wParam = 0;
    int Shared_lParam = 0;
    int CopyMode = COPY2FILE;
    HWND hWndApp = 0; //handle to subclassed Window
    HWND hWndHooked = 0;//handle to the hooked window
    HHOOK   hHook = 0;      // Hook handle for WH_GETMESSAGE

#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

//---------------------------------------------
// Global Variables, specific to each process
//---------------------------------------------
    HINSTANCE   hInstance;  // Global instance handle for DLL



//--------------------------------------------
//        DLL entry-point
//--------------------------------------------
BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            hInstance = hinstDLL;//save dll handle for each process
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);

__declspec(dllexport) void _stdcall SetSharedData(int uMsg, WPARAM wParam, LPARAM lParam)
{
        Shared_uMsg = uMsg;
        Shared_wParam = wParam;
        Shared_lParam = lParam;
        ChangeMessage = true;
}

答案 1 :(得分:0)

为什么这不能按预期工作有太多边缘原因所以我采用手动修补我想要的特定事件(基本上是鼠标事件)。