今天跟同事聯調一段**,被乙個問題鬱悶了很久。
呼叫過程其實並不複雜,就是他提供乙個dll,並輸出乙個函式(姑且叫做foo()吧),我呼叫他的函式foo,其內部產生乙個視窗。但是,我每次呼叫,視窗總是一閃而過!我們於是懷疑,是不是因為主程式是console,不支援mfc的緣故?要不然一定是因為不是在主線程裡呼叫的緣故?!又是多執行緒,真是麻煩!
反覆測試,結果如下
mfc對話方塊win32 mfc console
多執行緒 失敗 失敗
單執行緒 成功 失敗
為什麼?難道就不能在普通執行緒裡建立視窗嗎?什麼是主線程(ui執行緒),什麼又是工作執行緒?以前認為理所當然的事情,現在突然變得很模糊!
開始把目光鎖定到訊息佇列上!是不是因為主線程有訊息佇列?比如mfc對話方塊程式就有訊息佇列,而console沒有。但是,同樣是執行緒,為什麼你有而我沒有?難道是winmain函式和普通的main函式不一樣?到底訊息佇列是什麼時候產生的?
帶著這個鬱悶回到了家,開啟那本windows程式設計寶典,翻到訊息佇列一章。原來,每個視窗歸屬於建立它的執行緒。一旦執行緒退出,視窗也將自行銷毀!另外,執行緒還要進行訊息迴圈,以分發視窗的訊息!注意,訊息迴圈是由執行緒負責的!執行緒剛開始建立的時候是不帶訊息佇列的,當執行緒第一次呼叫視窗相關的函式時,作業系統自動為其建立訊息佇列!原來,視窗的訊息佇列是歸屬於執行緒的!
問題終於搞清楚了,在普通的工作執行緒裡,我們沒有訊息迴圈,所以建立出來的視窗還沒有沒有機會顯示出來,執行緒就結束退出了!即使在console程式裡,通過cin.get()讓程式等待,視窗還是沒有機會重新整理(依賴訊息迴圈分發並呼叫訊息處理函式)而一直處於忙碌等待狀態!而前面的foo函式,恰恰要依賴於訊息迴圈!
知道問題的真正原因後,就很容易解決了!在呼叫同事的函式產生視窗後(函式返回了),在同乙個執行緒裡進行訊息迴圈!如下
...in a working thread...
foo(); //call some function
while (getmessage(&msg, null, 0, 0))
}...working thread exit...
問題迎刃而解!你看不是mfc的問題,也不是不能在工作執行緒裡建立視窗。本來,我一開始就懷疑,這麼依賴mfc,總不能讓主程式都是mfc程式吧!作為乙個dll元件,不能對呼叫者有太多的限制!而多執行緒,太尋常了,如果都在主線程裡做,那也太難模組化了吧!當然了,現在說這些都是馬後炮,當時鬱悶的時候,什麼古怪的理由都用上了!
其實,這個問題本來可以解決得更快點的。如果同事事先說明他的foo函式何時返回(我一直以為它要一直阻塞到其產生的視窗關閉才返回的,結果並不是這樣的,視窗一產生它就返回了),以及是否需要依賴外部的訊息迴圈(他是有提過,但也很模糊,搞不清具體為什麼)。當然,最大的原因還是因為大家對windows的訊息迴圈機制理解得不是很深入!
現在你搞明白windows的訊息迴圈到底是如何進行的了麼?
Windows的訊息佇列和訊息迴圈
一 windows中有乙個系統訊息佇列,對於每乙個正在執行的windows應用程式,系統為其建立乙個 訊息佇列 即應用程式佇列,用來存放該程式可能建立的各種視窗的訊息。應用程式中含有一段稱作 訊息迴圈 的 用來從訊息佇列中檢索這些訊息並把它們分發到相應的視窗函式中。二 windows為當前執行的每個...
譯 理解Windows訊息迴圈
出處 理解訊息迴圈和整個訊息傳送機制對windows程式設計來說非常重要。如果對訊息處理的整個過程不了解,在windows程式設計中會遇到很多令人困惑的地方。什麼是訊息 message define wm initdialog 0x0110 define wm command 0x0111 defi...
詳談Windows訊息迴圈機制
一直對windows訊息迴圈不太清楚,今天做個詳細的總結,有說錯的地方,請務必指出。程式入口 intwinapi winmain 定義視窗類 typedef struct tagwndclassa 註冊視窗類 registerclass wndclass 生成視窗 createwindow 更新視窗...