Qt主界面使用QComboBox时,无法接收nativeEvent事件导致无法接收WM_COPYDATA消息的问题处理

11 篇文章 0 订阅
5 篇文章 1 订阅

Qt主界面使用QComboBox时,无法接收nativeEvent事件导致无法接收WM_COPYDATA消息的问题处理

Qt主界面使用QComboBox时,无法接收nativeEvent事件导致无法接收WM_COPYDATA消息的问题处理

问题描述

给需要接收消息的mainwindow窗体发送windows消息,mainwindow的nativeEvent方法无响应。

背景:mainwindow.ui文件中包含了一个QComboBox控件

1.给mainwindow窗体发送一次WM_COPYDATA消息

​ mainwindow窗体可正确收到WM_COPYDATA消息,进入nativeEvent方法

// 这里多发送几次,均可正确进入

3.单击mainwindow窗体上的QComboBox下拉框,弹出下拉列表,随意选取或不选取新的选项均可,只需要执行弹出下拉列表的操作

4.给mainwindow窗体发送一次WM_COPYDATA消息

​ mainwindow窗体无法收到WM_COPYDATA消息,无法进入nativeEvent方法

//这里无论发多少次,均无法进入

经过多次实验,得出结论:在ui的QComboBox的下拉列表被弹出后,mainwindow窗体均无法响应WM_COPYDATA消息

问题排查

测试环境

消息发送进程名称:TestMsgSender.exe

消息接收进程名称:mainwindow.exe

WM_COPYDATA消息中的窗体名称: mainwindow

FindWindowW传参: mainwindow

继承QAbstractNativeEventFilter,并实现nativeEventFilter方法,截获nativeEvent消息.

class mainwindow : public QMainWindow,  public QAbstractNativeEventFilter
{
    Q_OBJECT
public:
    mainwindow(QWidget *parent = Q_NULLPTR);
	~mainwindow();
protected:
    virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override;

public slots:
	bool nativeEvent(const QByteArray &eventType, void *message, long *result);
private:
    Ui::mainwindowClass ui;
};

bool mainwindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
	MSG* msg = (MSG*)message;
	switch (msg->message)
	{
		case WM_COPYDATA:
		{
			printf("receive mainwindow::nativeEvent: WM_COPYDATA\n");
			break;
		}
		default:
			break;
	}
	return QMainWindow::nativeEvent(eventType, message, result);
}
bool mainwindow::nativeEventFilter(const QByteArray &eventType, void *message, long *ll)
{
    if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
    {
        MSG* pMsg = reinterpret_cast<MSG*>(message);
        if (pMsg->message == WM_COPYDATA)
        {
            printf("MainWindow windows system message WM_COPYDATA\n");
        }
    }
    return false;
}

在“printf(“MainWindow windows system message WM_COPYDATA\n”)”处设置断点

  • 测试结果

首次进入的数据截图
首次进入nativeEventFilter.png

首次进入时,hwnd的值为0x200942

弹出ComboBox的下拉框后的数据截图
弹出ComboBox后的nativeEventFilter记录.png

可以看到,此时hwnd的值变成了0x3c1892

由上述可知,在弹出QComboBox的下拉框后,Qt根据窗口名称“mainwindow”获得的窗口hwnd发生了变化,最终导致nativeEvent事件无法进入mainwindow类的重写方法

bool mainwindow::nativeEvent(const QByteArray &eventType, void *message, long *result)

根据前述过程,怀疑时因为弹出QComboBox的下拉列表时导致Qt根据消息中的窗体名称获取对应窗体的hwnd时出错。

因为windows系统下发送WM_COPYDATA消息需要使用::FindWindowW()方法获取程序句柄,因此在测试代码中插入以下代码打印窗口句柄查看句柄是否发生了变化。

std::wstring  str = CharToWchar("mainwindow", CP_ACP);
HWND server = ::FindWindowW(nullptr, str.c_str());    // 打印窗口句柄
if (!IsWindow(server))
{
    qDebug() << "can't find server :" << server << "end";
}
else
{
    qDebug() << "find window :" << server << "end";
}

结论

再次进行了几个验证性试验后,我认为当消息接收进程名称和WM_COPYDATA消息中要查找的窗体名称一致时是存在bug的,打开QComboBox下拉列表后会提前触发这个bug。

类似这种情况均会出发这个bug:

消息接收进程名称:mainwindow.exe

WM_COPYDATA消息中的窗体名称: mainwindow

所以,最终的建议是,在使用windows的WM_COPYDATA消息和Qt的nativeEvent事件进行进程间通讯时,WM_COPYDATA消息名称不要和消息接收者的进程名称相同。

建议如下

消息接收进程名称:mainwindow.exe

WM_COPYDATA消息中的窗体名称: mainwindowServer (名字与exe文件名称不一样即可)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值