【问题标题】:Calling method inside of mouse hook code causes access violation在鼠标钩子代码中调用方法会导致访问冲突
【发布时间】:2015-10-09 15:59:01
【问题描述】:

我有一个低级鼠标钩子,我试图用它来处理全局左键单击事件。我在一个基本的主窗体类中定义了钩子,如下所示:

class TMainForm : public TForm
{
private:
    HHOOK hMouseHook;
    static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam);
    void __fastcall MouseHook(int nCode, WPARAM wParam, LPARAM lParam);
};
extern PACKAGE TMainForm *MainForm;


LRESULT CALLBACK TMainForm::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    MainForm->MouseHook(nCode, wParam, lParam);
    return CallNextHookEx(0, nCode, wParam, lParam);
}

void TMainForm::MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0 && wParam == WM_LBUTTONDOWN)
    {

        HWND__ * handle = Platform::Win::WindowHandleToPlatform(this->Handle)->Wnd;

        RECT Rect;
        GetWindowRect(handle, &Rect);
    }
}

我的鼠标钩子可以很好地检测到左键单击,但是当我尝试获取 MainForm 的句柄时,我遇到了访问冲突。

我最初认为这可能是因为我试图在 TMainForm 类中检索句柄,而实际上在运行时,继承自 TMainForm 的表单将处于活动状态。为此,我编写了一个名为GetHandle() 的虚拟方法。

此函数在TMainForm 标头中定义如下:

virtual HWND__ * __fastcall GetHandle();

在继承类中是这样的:

HWND__ * __fastcall TMainFormPass::GetHandle()
{
   return Platform::Win::WindowHandleToPlatform(this->Handle)->Wnd;
}

但是,当我在 TMainForm 中调用 GetHandle() 时,我仍然遇到访问冲突。此外,在尝试了更多的事情之后,我意识到从MouseHook 内部调用任何虚函数都会导致访问冲突。

为什么我无法在MouseHook 内部使用Platform::Win::WindowHandleToPlatform(this->Handle)->Wnd; 检索我的表单句柄?为什么在MouseHook 内部调用虚函数会导致访问冲突?

编辑:

为了测试 Remy 提出的 MainForm 指针无效的答案,我在 TMainForm 构造函数中添加了一段代码来测试指针是否有效。此外,我向继承自TMainForm 并在启动我的应用程序时加载的类的构造函数添加了一段代码,以测试其全局指针。我的TMainForm 类中的全局MainForm 指针实际上是无效的。但是,继承类的全局指针是有效的,因为它是实际被实例化的类。

【问题讨论】:

    标签: c++ firemonkey mouse-hook c++builder-xe8


    【解决方案1】:

    您的描述表明您的全局 MainForm 指针在调用钩子时未指向有效的 Form 对象。因此,任何对表单方法的调用,例如MouseHook(),都会有一个无效的this 指针。您必须确保您正在分配该指针。

    您正在使用我在回答another question 时提供给您的SetWindowsHookEx() 示例。在同一个答案中,我还为您提供了不涉及SetWindowsHookEx() 的替代解决方案 - 处理来自RAW Input APIWM_INPUT 消息。您的问题没有提到您使用的是 FireMonkey 而不是 VCL。我给你的例子是VCL。我现在已经更新了该答案以包含一个 FireMonkey 示例。

    【讨论】:

    • @RemyLebau 非常感谢您不遗余力地编辑您对我其他问题的回答!我一定会考虑使用 RawInput。我只是想看看我是否可以了解在这种情况下出了什么问题,因为我已经把所有的东西都输入了。在MouseHook()方法的情况下,当你说它会有一个无效的this指针时,是指隐藏的this指针吗?
    • 如果MainForm->MouseHook(...)调用中使用的MainForm指针无效,则MouseHook()内部的this指针同样无效,所以this->Handlethis->的其他访问将失败。 MainForm 必须在应用程序启动时由Application->CreateForm() 分配,或者在代码中的某处由MainForm = new TMainForm(...) 分配。此外,如果您继续使用SetWindowsHookEx(),请在销毁表单时调用UnhookWindowsHookEx()。即便如此,仍然可以再次调用该钩子,因此将 MainForm 设置为 NULL 并让 MouseHookProc() 在调用 MouseHook() 之前检查它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多