1

我目前正在从事一个涉及大量挂钩的项目,该项目旨在以与“ Steam Overlay ”相同的方式作为交互式产品的覆盖层运行。

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

程序结构

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

我已经设法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 应用程序。

4

2 回答 2

1

我会使用一个 dllSetWindowsHookEx来挂钩 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));
}

另外,仅供参考,这里是 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;
}
于 2012-06-18T16:28:10.157 回答
0

有太多的边缘原因导致这不能按预期工作,所以我求助于手动修补我想要的特定事件(基本上是鼠标事件)。

于 2012-06-28T10:49:23.977 回答