SetWindowsHookEx不能在另一个进程线程ID上与WH_CBT一起使用但可以在自己的线程ID上使用 定义回调的DLLinject.dll:用于设置CBT挂钩DLLwrapper.dll的DLL:

如何解决SetWindowsHookEx不能在另一个进程线程ID上与WH_CBT一起使用但可以在自己的线程ID上使用 定义回调的DLLinject.dll:用于设置CBT挂钩DLLwrapper.dll的DLL:

几天来,我一直在绞尽脑汁,可以使用一些帮助!将SetwindowsHookEx钩到WPF应用程序的线程ID时,我能够使用它检测到CBT钩子,但是当该窗口成为前台应用程序时,我无法使其钩接到另一个进程窗口的Thread ID。

图片1:表明我可以使用CBT钩子来检测主应用程序的线程ID最大化的窗口

Image 1: Shows that I CAN get the CBT hook for detecting window maximize on the main app's Thread ID

图像2:表明在侦听另一个应用程序的线程ID时我无法获得CBT钩子,它将使该应用程序崩溃!

Image 2: Shows that I CANNOT get the CBT hook when listening to another app's Thread ID,and it will crash the app!

我想避免发送ThreadId = 0并使其成为完整的全局钩子,因为我知道我只想听前台应用程序,而不是桌面上的所有应用程序。我希望能够在当前具有前景焦点的任何窗口发生之前,先监听一些窗口事件(根据我的理解,WH_CBT会这样做)。

同样,以下代码在当前WPF应用成为前台应用时起作用,但在另一个应用的窗口成为前台(例如记事本,Internet Explorer,文件浏览器,Chrome等)时失败。

完整代码(link to github zip file)

以下是一些代码片段,以显示我的工作:

定义回调的DLL(inject.dll):

inject.h:摘要
typedef void(__stdcall* MYFUNCPTR)(int code,WParaM wparam,LParaM lparam);
extern "C" __declspec(dllexport) void Init(MYFUNCPTR funcPtr);
extern "C" __declspec(dllexport) LRESULT CALLBACK CbtProcCallback(int code,LParaM lparam);
WParaM wparam,LParaM lparam);
MYFUNCPTR _handler = 0;
inject.cpp:代码
void Init(MYFUNCPTR funcPtr)
{
    _handler = funcPtr;
}
LRESULT CALLBACK CbtProcCallback(int code,LParaM lparam)
{
    if (code >= 0)
    {
        // Only send the code if you are about to MAXIMIZE
        if (code == HCBT_MINMAX)
        {
            if (lparam == SW_MAXIMIZE)
            {
                _handler(0,wparam,lparam);
            }
        }
    }

    return CallNextHookEx(NULL,code,lparam);
}

用于设置CBT挂钩(DLLwrapper.dll)的DLL:

dllwrapper.cpp:代码
    // Load library in which we'll be hooking our functions.
    HMODULE dll = LoadLibrary(L"inject.dll");
    if (dll == NULL) {
        char errorMessage[100];
        sprintf_s(errorMessage,"ERR-LoadLibrary Failed! ErrorCode=%d",GetLastError());
        SendManagedMessage(errorMessage);
        return false;
    }
    SendManagedMessage("LoadLibrary passed!");

    // Get the address of the function inside the DLL.
    MYPROC iaddr = (MYPROC)GetProcAddress(dll,"Init");
    if (iaddr == NULL) {
        char errorMessage[100];
        sprintf_s(errorMessage,"ERR-GetProcAddress for Init Failed! ErrorCode=%d",GetLastError());
        SendManagedMessage(errorMessage);
        return false;
    }
    SendManagedMessage("GetProcAddress for Init passed!");
    iaddr(OnInjectionCallback);

    // Get the address of the function inside the DLL.
    HOOKPROC cbtProcAddress = (HOOKPROC)GetProcAddress(dll,"CbtProcCallback");
    if (cbtProcAddress == NULL) {
        char errorMessage[100];
        sprintf_s(errorMessage,"ERR-GetProcAddress for CbtProcCallback Failed! ErrorCode=%d",GetLastError());
        SendManagedMessage(errorMessage);
        return false;
    }
    SendManagedMessage("GetProcAddress for CbtProcCallback passed!");

    // Hook the function
    cbtProcHook = SetwindowsHookEx(WH_CBT,cbtProcAddress,dll,_threadId);
    if (cbtProcHook == NULL) {
        char errorMessage[100];
        sprintf_s(errorMessage,"ERR-SetwindowsHookEx cbtProcAddress Failed! ErrorCode=%d",GetLastError());
        SendManagedMessage(errorMessage);
        return false;
    }
    SendManagedMessage("SetwindowsHookEx for cbtProcAddress passed!");
片段导出到C#
typedef void(__stdcall* CodeCallback)(int code,LParaM lparam);
typedef void(__stdcall* MessageCallback)(const char* message);
#ifdef __cplusplus
extern "C" {  // only need to export C interface if
              // used by C++ source code
#endif

    __declspec(dllexport) bool StartHooks(unsigned int threadId,MessageCallback messageCallback,CodeCallback codeCallback);
    __declspec(dllexport) void StopHooks();

#ifdef __cplusplus
}
#endif
NativeMethods.cs:C#dll的片段导入到WPF应用程序
public delegate void MessageCallback(string message);
public delegate void CodeCallback(int code,IntPtr wParam,IntPtr lParam);
[DllImport("dllwrapper.dll")]
public extern static bool StartHooks(uint threadId,MessageCallback messageHandler,CodeCallback codeHandler);
[DllImport("dllwrapper.dll")]
public extern static void StopHooks();

从WPF应用程序窗口中的消息中可以看到,挂钩正在传递并且未返回任何Win32错误,但是当另一个窗口具有焦点(即使使用调试器)时,它只是不执行回调。

任何帮助将不胜感激!

开发环境:

  • Windows 10 1909
  • VS2019 16.7.4
  • C#.NET Framework 4.7.2,C ++

解决方法

当主应用程序调用{​​{1}}时,它正在调用自己的DLL实例,因此也设置了自己的Init()副本。

将挂钩DLL注入另一个进程后,该进程将获得其自己的DLL副本,并因此获得其自己的_handler副本。但是_handler从未在该DLL实例上被调用,因此当您在该进程内调用hook函数时,其Init()的副本仍为0。这就是进程崩溃的原因,因为该钩子没有检查该条件。

您在另一个进程中的DLL无法跨进程边界调用主应用程序中的函数。当_handler为0时,您将不得不更改钩子函数以改为使用您选择的IPC机制与主应用程序进程进行通信。可以将窗口消息,管道,邮槽,套接字等用于该过程。交流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?