名词解释
PostMessage 是 Windows API(应用程序接口) 中的一个常用函数,用于将一条消息放入到消息队列中。并且不会等待响应的线程处理消息,而是直接返回。(简单的理解就是异步)。
而 SendMessage 作用一样,但是会等待结果返回(同步)
我们先来看 PostMessag 函数的原型:
hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
HWND_BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、 被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口
NULL:此函数的操作和调用参数 dwThread 设置为当前线程的标识符 PostThreadMessage 函数一样
Msg:指定被寄送的消息。
wParam:指定附加的消息特定的信息。
LParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零,否则函数调用返回值为零
接收的时候,使用 QT5 中的方法是 在接收的类中,重新实现 nativeEvent()
(Qt4的时候使用的是 winEvent()
,从 Qt5 开始,就使用 nativeEvent()
),这个方法既可以拦截系统消息,也可以拦截通过 postMessage
和 sendMessage
发送的自定义消息。
例子
需求:要求程序 A 以 tab 标签形式嵌套到程序 B 中
部分核心代码
嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| auto window = QWindow::fromWinId((WId)hwnd); if (window) { qDebug() << "createWindowContainer............."; window->setFlags(window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); QWidget *containerWidget = new QWidget; containerWidget->setObjectName("containerWidget"); containerWidget->setProperty("processID", processID); containerWidget->setProperty("winID", jsObj.value("winId").toString()); QHBoxLayout *layout = new QHBoxLayout(containerWidget); layout->setMargin(0); if (auto w = QWidget::createWindowContainer(window, containerWidget, Qt::Widget)) layout->addWidget(w); containerWidget->setLayout(layout); mw->addTabPage(QIcon(":/resource/images/xx.ico"), title, containerWidget);
::MoveWindow(hwnd, mw->stackedWidget()->x(), mw->stackedWidget()->y(), mw->stackedWidget()->width(), mw->stackedWidget()->height(), true); mw->raise();
QApplication::processEvents(); }
...... int MainWindow::addTabPage(const QIcon &icon, const QString &text, QWidget *w) { return insertTabPage(ui->tabBar->count(), icon, text, w); }
int MainWindow::insertTabPage(int index, const QIcon &icon, const QString &text, QWidget *w) { ui->stackedWidget->insertWidget(index, w); int ret = ui->tabBar->insertTab(index, text); ui->tabBar->setTabIcon(index, icon); ui->tabBar->setCurrentIndex(index); ui->stackedWidget->setCurrentIndex(index);
m_flh->addExcludeItem(ui->tabBar->tabButton(ret, QTabBar::ButtonPosition::RightSide));
return ret; }
|
程序 A 发送 Windows 消息给程序 B
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| bool ok = false; auto strWinId = winID.toULongLong(&ok); if (!ok) { qDebug() << __FUNCTION__ << "winid error!"; return false; }
HWND hwnd = reinterpret_cast<HWND>(strWinId); if (hwnd == nullptr) { std::cout << GetLastErrorAsString1() << std::endl; return false; }
if (::IsWindow(hwnd)) { std::thread thread([=](){ COPYDATASTRUCT copyData; copyData.dwData = CUSTOM_TYPE_YDPLATFORM; copyData.lpData = (PVOID)msgData.data(); copyData.cbData = (DWORD)msgData.size();
HWND sender = (HWND)effectiveWinId(); LRESULT result = ::SendMessageW(hwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(sender), reinterpret_cast<LPARAM>(©Data)); qDebug() << __FUNCTION__ << "result: " << result; }); thread.detach();
return true; } else { qDebug() << "findwindow failed!"; }
return false;
|
接收 Windows 消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(eventType);
#ifdef Q_OS_WIN MSG *msg = static_cast<MSG *>(message); switch (msg->message) { case WM_COPYDATA: { COPYDATASTRUCT *copyData = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam); if (copyData->dwData == CUSTOM_TYPE_YDPLATFORM) {
QString structMsg = QString::fromUtf8(reinterpret_cast<char *>(copyData->lpData), copyData->cbData);
parseCustomMsgCommand(structMsg);
*result = 1; return true; } } break; } #endif
return false; }
|