• 沒有找到結果。

vncDesktopThread 畫面處理流程 畫面處理流程 畫面處理流程 畫面處理流程

3.3 vncClientThread

3.4.2 vncDesktopThread 畫面處理流程 畫面處理流程 畫面處理流程 畫面處理流程

vncDesktopThread 一開始的初始化完成後,就會進入處理畫面的無窮迴圈 裡,總共有三大部分,一、取得 Hook 偵測可能的範圍,二、進一步增加額外判 斷範圍,三、將最後可能變動範圍進行比對並傳送真正變動區塊。下圖為此 Thread 的流程圖。

圖 3-13.vncDesktopThread 流程圖 這個迴圈相當繁瑣, 大致上是由三個部分所組成。

一 一 一

一、 、 、 、取得 取得 取得 取得 Hook 偵測 偵測 偵測到 偵測 到 到可能的範圍 到 可能的範圍 可能的範圍 可能的範圍

1. vncDesktopThread 初始化後,剛進入迴圈時,可能尚未有如 4.3.1 節中 啟用的三種 Hook 動作發生,因此,他們對應的前處理函數不會送來任何可

能變動的訊息到隱形程式的訊息佇列,因此佇列中沒有任何訊息。接著繼續 判斷 region 中是否有記錄任何可能的變動區塊大小,若沒有,代表目前沒 有任何需要更新的區域,隨即再回到迴圈中,等待訊息並加以處理。

2. 一切開始正常運作後,當一產生 4.3.1 節中啟用三種 Hook 對應的動作後,

對應 Hook 的前處理函數會處理可能和畫面變動相關的訊息,處理完後會再 以訊息方式(RFB_SCREEN_UPDATE), Post 到 Initialization 時啟動的隱 形程式的訊息佇列。vncDesktopThread 進入迴圈後會先判斷訊息佇列中是 否 有 新 訊 息 , 當 它 發 現 有 訊 息 時 , 會 取 出 此 訊 息 判 斷 , 如 果 訊 息 是 RFB_SCREEN_ UPDATE 就表示是由對應動作 Hook 的前處理函數處理過 後傳過來的,接著 vncDesktopThread 由此 RFB_SCREEN_ UPDATE 消息 的副消息參數,可以得到可能變動的大小,並將它記錄到 rgncache(Window 的 Region 類別)中,如下圖。接著再回到佇列中看是否有新的訊息,若有,

則再取出並和剛剛記錄的做聯集,直到訊息佇列中都沒訊息為止。

圖 3-14.GetMessage and Record

3. 訊息佇列清空後,代表現階段沒有任何新的畫面變動,Thread 會趁此空 檔趕緊去做後續處理,因此再判斷 region 不為空後,會再判斷旗標 Update Flag 是否被設為 TRUE,它代表 Client 有要求畫面更新,若有要求才會 進一步處理。若 Client 沒有要求,則 Flag 為 False,因此 Thread 會將剛 記錄的 region 保留著,直接返回剛剛 vncDesktopThread 訊息處理迴圈,

等待下次記錄完並清空訊息佇列後再一起處理。這是因為 VNC 的整個架

構是 Client Pull,Update Flag 是由 vncClientThread 所控制,在它收到 Client 的畫面更新要求後,才會將 Update Flag 設為 TRUE,因此主動權 在 Client 端,只有在 Client 有要求後,Server 才能做後續的處理。

二 二 二

二、 、 、 、增加額外判斷範圍 增加額外判斷範圍 增加額外判斷範圍 增加額外判斷範圍

在 region 不為空且 Update Flag 被設為 TRUE 時,表示剛剛 vncDesktop- Thread 已發現可能有畫面變動,並記錄著這些區塊的座標大小在 region 中,而 且當 Client 也要求要更新畫面時,Thread 就要接著後續的處理。為了避免一些 應用程式,可能不是透過 Windows 以畫面重畫的訊息機制更新畫面,而是自行 處理內部工作區域的變動,因此在 4.3.1 節中啟用的三種 Hook 無從取得可能變 動範圍。VNC Server 在這部分,是以自行增加額外範圍來應對,它總共提供三 種方式:Poll FullScreen、Poll Foreground Window、Poll Window Under Cursor。

圖 3-15.Add extra region 流程圖

●Poll Full Screen

當使用者勾選了這個選項,代表為了確保整個螢幕都要更新到,不希望失去 某些畫面,此時 VNC Server 會將螢幕範圍拆成四等分,每觸發一次都會額外再 加入一個等分,如下圖。因此,採取這樣的方式會稍稍增加資料的處理量。VNC Server 也可以每次都加入全螢幕的大小範圍,但為了克服網路頻寬和 Computing Power 的問題,它採取的是經過四次的觸發流程,才會更新完整個畫面。

圖 3-16.Poll Full Screen

因為每一次清空訊息佇列中的訊息得到初步範圍後,再進到 Add extra region 時,只會加上螢幕的四分之一,加入的方式如下圖程式碼,用 m_pollingcycle 記住狀態,然後以 m_pollingcycle 計算這次要加入的是哪一塊範圍,並記錄在矩 形結構 rect 中,再將這個座標大小與 vncDesktopThread 前端取得的初始範圍做 聯集,接著送去 SendUpdate()函數處理後再回到迴圈,再等下次清空佇列裡的 訊息,才有機會再進 Add extra region 加上另一塊四分之一的畫面,因此要重覆 四次才能更新完成。

圖 3-17.Pollingcycle 狀態

假設在更新一塊後,後續可能因為都沒有任何變動,因此 vncDesktopThread 會一直卡在等待佇列中新的訊息產生,那剩下三塊的資料,有可能會延遲相當長 的時間才能完成,因此,Poll FullScreen 是種定量卻不定時的機制,對於這點,

我們可以設一個類似計時器的功能,在一定時間內觸發一次,讓他能夠持續的更 新完整的畫面,這是值得我們改進的地方。

●Poll Foreground Window

如果使用者勾選了 Poll Foreground Window 選項,表示他要目前使用中的 前景應用程式視窗範圍,也加進去剛取得的初步範圍,避免應用程式內部工作區 的漏掉。它會先以 hwnd = GetForegroundWindow()取得前景程式的 HWND,

再以 GetWindowRect(hwnd, &rect)將前景程式的視窗座標大小存入矩形的結構 rect,接著將此大小加入到 vncDesktopThread 得到的初步範圍。

●Poll Window Under Cursor

至於 Poll Window Under Cursor 這個選項,和上面的類似,這個則是要加入 目前游標下方,應用程式視窗大小的範圍。它會先以 GetCursorPos(&mousepos) 取得滑鼠的位置存在 mousepos 中,再以 hwnd= WindowFromPoint(mousepos) 取得滑鼠位置下方的視窗程式座標和大小,接著也是加入到 vncDesktopThread 函數,在最新資料的 mainbuff 和前一狀態的 backbuff 兩個 buffer 中,詳細比 對這些可能範圍,取得真正有變動的區域資料並壓縮,再進一步傳送給 Client,

這部分比較直觀,在 3.4.4 小節會詳細介紹。