天天看點

模态視窗其實就是在目前視窗調用系統的消息循環,響應使用者的操作,将相關的消息發送到對應的視窗(轉)

上周準備在公司内部轉崗,面了3個部門windows用戶端相關的工作,最終拿到3個Offer,主要涉及C++和Windows兩大塊内容,C++的題目基本都答上了,Windows一直都是我的弱項,在這裡記錄一下Windows相關的題目。有些答不上的問題就沒列出來,還有些問題忘了,下面的答案有些大部分是我自己的了解,有些是直接從網上copy的,有問題大家可以讨論。

1:GetMessage和PeekMessage的差別?

GetMessage:擷取消息隊列中的一個消息,存入MSG中,并從消息隊列中移除,如果消息隊列中沒有消息就會阻塞;

PeekMessage:檢視消息,有消息,就将資料存入MSG結構中,沒有消息就傳回FALSE,不會阻塞,但如果沒有更新區,可以移除WM_PAINT消息,還可以通過最後一個參數來決定是否從隊列中移除檢視的消息;

2:SendMessage和PostMessage的差別?怎麼跨線程發消息?怎麼跨程序發消息?SendMessage在程序間發消息要注意什麼?SendMessage能将消息發送到消息隊列嗎?PostMessage可以在程序間發消息嗎?兩個線程互相SendMessage會出問題嗎?

SendMessage:将一個消息發送到指定視窗的視窗過程中,等視窗過程執行完了再傳回;

PostMessage:将消息發送到指定視窗所線上程的消息隊列中,直接傳回,消息是否被處理完全不知道;

SendMessage直接調用視窗過程,那它是否可以将消息發送到發送到線程的消息隊列中呢?

可以啊,比如發送一個WM_PAINT消息,這是一個隊列消息,隻有存在無效區域的情況下,才會處理WM_PAINT消息;

線程間SendMessage,由于它基本就是調用指定視窗的視窗過程,當跨線程發消息的時候,無法調用指定視窗的視窗過程,在跨線程發送;

消息的時候,發送線程會先挂起,由系統線程将消息發送到接收線程的另一個隊列中,并設定QS_SENDMESSAGE标志,當系統檢測到這個标志後,就會處理這個隊列的消息,當這個消息被處理之後,調用SendMessage的線程就會被喚醒,就繼續執行。

SendMessage是可以跨程序發消息的,通過FindWindow找到對方程序的視窗句柄,發一個消息過去就行了,由于兩個程序間的記憶體是完全獨立的,不能發指針,如果要發資料,就用WM_COPYDATA。

PostMessage可以在程序間發消息,但不能結合WM_COPYDATA使用,WM_COPYDATA通過記憶體映射在程序間傳遞資料,PostMessage後映射檔案的句柄就無效了。

兩個線程互相SendMessage可能會導緻死鎖,A線程鎖住一個資源,向B線程發一個消息,A線程挂起,這時如果B線程在處理A線程的消息需要A線程鎖住的資源,A由于發給B的消息還沒有處理完就一直不能傳回,鎖也沒有打開,B線程又用不了,消息也就處理不完,結果就死鎖了。

3:Windows是怎麼實作視窗重新整理的?怎麼實作視窗的立即重新整理?

Update Region不為空時,系統就會自動産生WM_PAINT消息,通過InvalidateRect和InvalidateRgn可把指定的區域加到視窗的Update Region中,通過處理WM_PAINT消息來實作視窗的重新整理。 系統為什麼不在調用Invalidate時發送WM_PAINT消息呢?又為什麼非要等應用消息隊列為空時才發送WM_PAINT消息呢?這是因為系統把在視窗中的繪制操作當作一種低優先級的操作,于是盡可能地推後做。不過這樣也有利于提高繪制的效率:兩個WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,然後在一個WM_PAINT消息中一次得到更新,不僅能避免多次重複地更新同一區域,也優化了應用的更新操作。

WM_PAINT一般在消息隊列中沒有消息的時候才處理,有時候我們需要立即重新整理視窗,那麼就需要UpdateWindow函數了,直接繞過消息循環,隻要更新區域不為空,将WM_PAINT消息直接發送到指定視窗過程即可。

Invalidate(hwnd); //将視窗設為不可用,導緻更新區域不為空

UpdateWindow(hwnd); //立即重新整理視窗 

4:Windows消息循環有哪幾個函數,各自的作用是什麼?消息循環是怎麼退出的?

while(GetMessage(&msg, NULL, 0, 0)) //擷取一個消息,成功後會放在msg中。

{      

 TranslateMessage(&msg); //消息進行必要的處理轉換。     

 DispatchMessage(&msg); //調用WinProc,将msg的各項資訊傳遞給WinProc

}

當GetMessage擷取到的消息是WM_QUIT,傳回的就是FALSE,while循環就退出了,消息循環也就終止了。

5:句柄是什麼?

句柄就是一個整數,Windows為每一個控件指定了一個唯一的整數,通過這個整數和相關函數操作控件。

6:Windows實作線程間同步有哪些方法?實作程序間同步又有哪些方法?讀寫鎖的實作原理是什麼?

1:volatile

2:關鍵段

3:旋轉鎖

4:讀寫鎖

5:事件對象

6:信号量

7:互斥量

隻要是核心對象,就能用于程序間的同步,核心對象不屬于任何程序,由系統管理。

讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的通路者劃分成讀者和寫者,讀者隻對共享資源進行讀通路,寫者則需要對共享資源進行寫操作。這種鎖相對于自旋鎖而言,能提高并發性,因為在多處理器系統中,它允許同時有多個讀者來通路共享資源,最大可能的讀者數為實際的邏輯CPU數。寫者是排他性的,一個讀寫鎖同時隻能有一個寫者或多個讀者(與CPU數相關),但不能同時既有讀者又有寫者。我覺得他其實就是對關鍵段和核心事件對象的封裝。寫的時候獨占,讀的時候共享。

7:模态視窗的實作原理?模态視窗會導緻崩潰嗎?

模态視窗其實就是在目前視窗調用系統的消息循環,響應使用者的操作,将相關的消息發送到對應的視窗。将父視窗設為不可用,即不能響應使用者的操作,在關閉目前視窗的時候,将父視窗設為可用,并退出消息循環。

可能導緻視窗崩潰,模态視窗顯示的時候,除了父視窗不可用之外,其他的視窗都是可用的,如果需要的一個資源在别的地方被釋放了,而在模态視窗中使用的時候,沒有判斷可能就會導緻崩潰。

8:你了解沙箱,UAC相關的知識嗎?

不了解

9:怎麼實作線程間發消息?線程的消息隊列預設會建立嗎?

SendMessage可以再線程間發消息,PostThreadMessage通過線程ID可以線上程間發消息,将消息發送到指定線程的消息隊列中。線程的消息隊列預設是不會建立的,因為線程的消息隊列并不是必須的。通過ResumeThread(threadHwnd);可以建立線程的消息隊列。

10:說說Windows的記憶體管理,怎麼實作記憶體共享?

FileMapping用于将存在于磁盤的檔案放進一個程序的虛拟位址空間,并在該程序的虛拟位址空間中産生一個區域用于“存放”該檔案,這個空間就叫做 File View,系統并同時産生一個File Mapping Object(存放于實體記憶體中)用于維持這種映射關系,這樣當多個程序需要讀寫那個檔案的資料時,它們的File View其實對應的都是同一個File  Mapping  Object,這樣做可節省記憶體和保持資料的同步性,并達到資料共享的目的。

<a href="http://www.cnblogs.com/hlxs/p/4091623.html">http://www.cnblogs.com/hlxs/p/4091623.html</a>