1. 程式人生 > >QT c++ 中使用PostMessage/SendMessage

QT c++ 中使用PostMessage/SendMessage

PostMessage是Windows API(應用程式介面) 中的一個常用函式,用於將一條訊息放入到訊息佇列中。並且不會等待響應的執行緒處理訊息,而是直接返回。(簡單的理解就是非同步)。

SendMessage作用一樣,但是會等待結果返回(同步

我們先來看PostMessage函式的原型:

BOOL WINAPI PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

hWnd:其視窗程式接收訊息的視窗的控制代碼。可取有特定含義的兩個值:

HWND_BROADCAST:訊息被寄送到系統的所有頂層視窗,包括無效或不可見的非自身擁有的視窗、 被覆蓋的視窗和彈出式視窗。訊息不被寄送到子視窗

NULL:此函式的操作和呼叫引數dwThread設定為當前執行緒的識別符號PostThreadMessage函式一樣

Msg:指定被寄送的訊息。

wParam:指定附加的訊息特定的資訊。

LParam:指定附加的訊息特定的資訊。

返回值:如果函式呼叫成功,返回非零,否則函式呼叫返回值為零

接收的時候,使用QT5中的方法是 在接收的類中,重新實現 nativeEvent函式(Qt4的時候使用的是winEvent,從Qt5開始,就使用nativeEvent),這個方法既可以攔截系統訊息,也可以攔截通過postMessage,sendMessage傳送的自定義訊息。

[virtual protected] bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result);

其中:

eventType: windows平臺的值就是“windows_generic_MSG”;

message: 型別為MSG*, 儲存的就是PostMessage中的Msg。

Result:型別為LRESULT,返回的值。

如果返回ture:表示停止這個訊息。如果返回false:這個訊息就繼續傳遞給Qt,Qt會將這個訊息轉變為Qt event並將它傳送給響應的控制元件。

我們用Qt環境下來舉個栗子:

先是使用SendMessage來向頂層視窗傳送訊息

    HWND m_wnd = ::FindWindowA(("ClientMainWindow"), NULL);//通過主視窗類名尋找主視窗控制代碼
    WId wid = this->winId(); //這個視窗的winid
    if (NULL != m_wnd)
    {
        std::thread th([=](){ //單獨啟動一個執行緒進行資料傳遞
            QString command = QString("Command=ChangeCode=%1\r\n").arg(code);//傳遞的內容
            std::string param = command.toStdString();
            COPYDATASTRUCT data;    //使用COPYDATA的方式進行資料傳遞
            data.dwData = 0;
            data.cbData = param.length();
            data.lpData = &param[0];
            ::SendMessage(m_wnd, WM_COPYDATA, (WPARAM)wid, (LPARAM)&data);
        });

        th.detach();//傳遞結束後,進行關閉執行緒
    }

同時,在接收的頂層視窗中,重寫nativeEvent函式

bool EmbededWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
	if (eventType == "windows_generic_MSG") //windows平臺
	{
		MSG* msg = reinterpret_cast<MSG*>(message); //

		if(msg->message == WM_COPYDATA)//訊息型別
		{
			COPYDATASTRUCT *data = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
			QTextCodec *gbk = QTextCodec::codecForName("GB18030");
			QString recevice = gbk->toUnicode((char *)(data->lpData));//轉碼

			if(recevice.contains("Command="))
			{
			   return true;//訊息不再進行傳遞,不再處理
			}

			m_wnd = reinterpret_cast<HWND>(msg->wParam);//高地址的引數

		}
	}

	return QWidget::nativeEvent(eventType, message, result);//交給Qt處理
}