【问题标题】:winapi - GetMessage() crashing when is called from QObject derived classwinapi - 从 QObject 派生类调用时 GetMessage() 崩溃
【发布时间】:2017-04-05 12:07:33
【问题描述】:

我有一个取自 Registering for Device Notification 的代码示例,用于检测是否移除了 USB 设备。此代码使用 Win32 API,我已成功构建并测试它。

当我尝试将此功能集成到 QObject 派生类中时,我在 MessagePump() 方法中遇到了崩溃:

void QObjectDerivedClass::MessagePump() {
    MSG message;
    int retVal;

    if (!m_hWnd) {
        return;
    }

    qDebug() << Q_FUNC_INFO;

    // Get all messages for any window that belongs to this thread,
    // without any filtering. Potential optimization could be
    // obtained via use of filter values if desired.

    while ((retVal = GetMessage(&message, m_hWnd,
                             MSG_FILTER_MIN, MSG_FILTER_MAX)) != 0) {
        if (retVal == -1) {
            break;
        } else {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }
    }
}

如你所想,我必须修改示例中的WndProc() 回调,为此类使用静态成员并满足WNDCLASS 对象,如下所示:

BOOL QObjectDerivedClass::InitWindowClass() {
    WNDCLASSEX wndClass;/* = {0};*/

    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = 0;
    wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
    // WndProcThunk is an static member of QObjectDerivedClass
    wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WndProcThunk);
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hIcon = NULL;
    wndClass.hIconSm = NULL;
    wndClass.hbrBackground = NULL;
    wndClass.hCursor = NULL;
    wndClass.lpszClassName = WND_CLASS_NAME;
    wndClass.lpszMenuName = NULL;

    if (!RegisterClassEx(&wndClass)) {
        qDebug() << Q_FUNC_INFO << "Unable to register window class. Error:"
             << QString::number(GetLastError());

        return FALSE;
    }

    m_instance = wndClass.hInstance;

    return TRUE;
}

应用崩溃时的调用栈为:

1 0xd26128 2 设置操作输入目标 USER32 0x7709d2b3 3 DispatchMessageW USER32 0x7707e88a 4 DispatchMessageW USER32 0x7707e4c0 5 RealGetWindowClassW USER32 0x7708a64f 6 KiUserCallbackDispatcher ntdll 0x772e08c6 7 QObjectDerivedClass::MessagePump qobjectderived.cpp 165 0xa52e88 8 QObjectDerivedClass::开始 qobjectderived.cpp 346 0xa52bc2 9 wWinMain main.cpp 259 0xa525ff 10 invoke_main exe_common.inl 118 0xa5516e 11 __scrt_common_main_seh exe_common.inl 253 0xa54fd0 12 __scrt_common_main exe_common.inl 296 0xa54e6d 13 wWinMainCRTStartup exe_wwinmain.cpp 17 0xa55188 14 BaseThreadInitThunk 内核32 0x73d862c4 15 RtlSubscribeWnfStateChangeNotification ntdll 0x772d0fd9 16 RtlSubscribeWnfStateChangeNotification ntdll 0x772d0fa4

知道如何解决这个崩溃吗?


编辑:发布的标准输出:

int __stdcall wWinMain(struct HINSTANCE__ *,struct HINSTANCE__ *,wchar_t *,int) int __stdcall QObjectDerivedClass::WndProcThunk(struct HWND__ *,unsigned int,unsigned int,long) int __stdcall QObjectDerivedClass::WndProcThunk(struct HWND__ *,unsigned int,unsigned int,long) int __stdcall QObjectDerivedClass::WndProcThunk(struct HWND__ *,unsigned int,unsigned int,long) int __stdcall QObjectDerivedClass::WndProcThunk(struct HWND__ *,unsigned int,unsigned int,long) void __thiscall QObjectDerivedClass::MessagePump(void)

【问题讨论】:

  • 请发布标准
  • @Idgorman 不知道该怎么做,但发布了。
  • 这有一种独特的感觉,QObjectDerivedClass 实例被它自己触发的其他事件破坏,并在从MessagePump 返回时崩溃,第一次碰巧尝试访问任何它的领域。这是在将代码模式逻辑与非 UI 模式对话框混合时一直出现的一个经典问题,我希望这会是这个主题的一些变化。

标签: c++ qt winapi


【解决方案1】:

您不需要重新实现任何本机消息泵送:Qt 已经为您完成了。

相反,在具体的QAbstractNativeEventFilter 中重新实现nativeEventFilter 时对Windows 消息做出反应。重新实现还可以继承 QObject - 确保 QObject 是第一个基类,因为这是唯一支持的继承 QObject 的方式。

要使用过滤器,请使用qApp-&gt;installNativeEventFilter 安装它。

【讨论】:

  • 我很怀疑,我可以使用 QAbstractNativeEventFilter 获得 WM_DEVICECHANGE 吗?
  • @jgd 你可以得到任何windows消息。这就是本机事件过滤器的用途。 IIRC 这些消息被发送到所有顶级窗口。
  • 完美运行,非常感谢您为我指路。
【解决方案2】:

WinApi 天生不支持 C++。 QT 将抽象出将正确消息传递到正确窗口所涉及的所有艰苦工作。您似乎试图绕过所有这些事情并自己创建窗口和发送消息,这导致了您的问题。

为什么不关注simple QT example 并将您的更改插入其中,而不是重新发明轮子。

【讨论】:

  • 我已经尝试不从 QObject 扩展并且应用程序继续崩溃。
  • 它可能会。您需要创建一个基本的 QT 应用程序!
  • 也许我没有解释清楚,我已经尝试过,在调用 GetMessage 的类中,不是从 QObject 扩展,并且应用程序继续崩溃,因此我们可以从方程中删除 Qt。 ;)
  • @jgd:如果您可以在不涉及 QT 的情况下使用 minimal reproducible example 重现崩溃,那么请显示该代码。你显然还是做错了什么。
猜你喜欢
  • 1970-01-01
  • 2020-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
  • 1970-01-01
  • 2019-12-31
  • 2015-12-22
相关资源
最近更新 更多