• 沒有找到結果。

變動畫面偵測 變動畫面偵測 變動畫面偵測 變動畫面偵測

3.3 vncClientThread

3.4.3 變動畫面偵測 變動畫面偵測 變動畫面偵測 變動畫面偵測

在上一小節中,說明了 VNC Server 偵測變動範圍的整個詳細過程,在這一 節以實際例子說明讓大家能有更深刻了解。這小節用兩個例子來說明,一、訊息 佇列的管理機制:說明當使用者操控鍵盤、滑鼠時,Windows 會得知這些動作 消息並做出對應回應,而我們在 4.3.1 節中啟動的三種 Hook,就是截取伴隨著這 些動作所產生的訊息,當此訊息是和畫面相關,則對應 Hook 的前處理函數會將 變動區塊的座標大小,Post 隱形程式的訊息佇列裡,接著 vncDesktopThread 再 從佇列中取出加以記錄。二、Extra Update Region 管理:由訊息佇列管理機制 中取得初步範圍後,為了確保所有變動區域都有取得,VNC 額外加入三種機制,

Pull FullScreen、Poll Foreground Window、Poll Window Under Cursor,以這 三種機制再額外將重要的範圍加進來判斷處理。

●訊息佇列的管理機制 訊息佇列的管理機制 訊息佇列的管理機制 訊息佇列的管理機制: : : :

下圖為一開始的狀態,接著使用者操控滑鼠點選小算盤的圖示,將他還原顯示在 桌面上,如圖。

圖 3-18.初始狀態

圖 3-19.還原小算盤

當使用者欲操控滑鼠將小算盤還原時,OS 內部能夠計算出小算盤應該在哪個地 方被還原出來,並以 WM_PAIT 的訊息送給小算盤的 WndProc 訊息處理函數,

此時 Server 所啟用的 Hook-WH_CALLWNDPROC 會先動作,它會偵測到 OS 發送 WM_PAINT 訊息給小算盤程式,請它重畫在螢幕上,此時對應的前處理函 數 CallWndProc()會先處理 WM_PAINT 訊息,處理後會將小算盤的視窗大小以 訊 息 方 式 (RFB_SCREEN_ UPDATE) , Post 到 隱 形 程 式 的 訊 息 佇 列 。 當 vncDesktopThread 進入迴圈後會先判斷訊息佇列中是否有新訊息,當它發現有 訊息時,會取出此訊息,接著由此消息的副消息參數得到應用程式的大小,並將 它記錄到 rgncache (Window 的 Region 類別)中。因此,rgncache 裡面會記載著 此應用程式的座標和大小,接著 vncDesktopThread 再回到迴圈開頭判斷是否還 有未處理的消息,若沒有,就會繼續後面的流程。在這個 case 中,前半部分已先 由 Windows 的訊息和 Hook 的搭配,取得完整應用程式的視窗範圍,在後面的 Add extra region 中只是再增加範圍進去,以上即是訊息佇列的管理機制。後續 會再接著呼叫 SendUpdate 去做其他的處理。

圖 3-20.rgncache 記錄的座標大小

●Extra Update Region 管理 管理 管理 管理: : : :

接著用另一個較複雜的例子來說明,當 VNC Server 遇到其他狀況時,它要 如何應對。假設 Client 連入時 Server 已在播放視訊檔案,如下圖。

圖 3-21.Server 初始狀況

一般而言,此時,4.3.1 節中啟用的三種 Hook,應該有能力偵測到整個 mplayer 的視窗大小,再進行後續的處理,但此時的訊息佇列中卻只會有兩種訊息和此播 放器有關的,如下圖紅框。

圖 3-22.mplayer 的變動訊息

因為拖曳區和時間都有獨立的 handle,所以 Server 初始化時所啟用的 Hook- WH_CALLWNDPROC 能偵測到發給他們的 WM_PAINT 訊息,因此處理後,

隱形程式的訊息佇列中會有上圖畫紅框的範圍大小,但為何 vncDesktopThread 無法獲得播放區域的範圍呢?常理來講,應該要可以偵測到畫面變動(工作區 域)、拖曳區、時間這三個地方,但是,播放器的原理是它取得視訊檔案後,在內 部解碼後直接呼叫 DirectDraw,將圖片資料送到顯示卡的記憶體秀出,或由 Windows GDI 在指定區域將解碼後的圖片畫上去,並不是以訊息的方式通知 mplayer 請它重畫,因為若是以訊息的方式通知重畫,可能造成播放的延遲,影 響觀看的品質。這部分就是應用程式內部工作區,不一定會以訊息方式處理,因 此,我們必須要在 Add extra region 中再加入必要範圍。

假設一開始訊息佇列中有兩個訊息,一個是拖曳區,另一個是時間,迴圈起始處 判斷佇列中有訊息,會先記錄第一個訊息中的範圍到 rgncache。

圖 3-23.rgncache 狀態 1

回到迴圈後發現訊息佇列中還有訊息,Thread 會再記錄到 rgncache,並移

除掉第二個訊息,等所有訊息都記錄完畢,就會進入迴圈下一個部分。因此,Hook 得到初步可能的變動範圍只有如圖所示。

圖 3-24.Hook 偵測到的初步變動範圍

在 vncDesktopThread 處理訊息佇列中的訊息後,取得了初步的範圍,可能 因為許多不同狀況中,如上圖,mplayer 在播放影片時,因為畫面更新的來源並 不是透過訊息,因此 Hook 對最重要的畫面區域沒辦法偵測到,因此,VNC Server 在 Update Flag 設為 True 後,接著後續的 Add extra region 這部分額外加入三個 選項:Poll FullScreen、Poll Foreground Window、Poll window under cursor,

針對不同狀況加入額外的範圍,確保雙方工作正常,接著為這三種狀況詳細說明。

●若勾選了 若勾選了 若勾選了 若勾選了 Poll Full Screen

若勾選 Poll FullScreen 了,則是要確保所有部分都要更新到,Thread 每次 會將螢幕四分之一等分大小範圍加進去,當第一次觸發時,會加上 1 的區塊,第 二次則換加 2 的區塊…以此類推,四個為一個循環。

圖 3-25.螢幕四等分

圖 3-26.第一、二次觸發的範圍

圖 3-27.第三、四次觸發的範圍

●若勾選了 若勾選了 若勾選了 若勾選了 Poll Foreground Window

如果使用者勾選了 Poll Foreground Window 選項,表示他要將目前前景的 應用程式視窗範圍加進去。假設延續上個例子,目前的前景程式是 mplayer,

Server 便會將整個 mplayer 的視窗大小累加到 rgncache 中,因此整個播放器的 區域範圍就是在這樣子加進來的。

圖 3-28.Poll foreground window 累加範圍

●若勾選了 若勾選了 若勾選了 若勾選了 Poll Window Under Cursor

如果勾選了 Poll Window Under Cursor 後,且游標位置是在後方的小算盤,

此時額外加進來的區域則會是小算盤的視窗大小,最後範圍如圖。

圖 3-29.原始圖

圖 3-30.Poll Window Under Cursor 累加範圍

以上就是當使用者用 mplayer 播放視訊檔案時,每當 Server 清空佇列後,在 Add extra region 一次的累計範圍。獲得上述範圍後,會呼叫 SendUpdate 函數做後 續處理。

PS:若同時間有許多 Client 連線進來,則 vncDesktopThread 取得初步範圍後,

在 Update Flag、Add extra region、SendUpdate 這些程序,依照幾個 Client 就 會重覆幾次,但是否要更新,端由各自的 vncClientThread 是否有將 Update Flag 設為 True,因此,同時有愈多 Client 存在,更新速度可能變慢。