Windows抓屏技術

☆綠茶☆發表於2017-12-10
1. BitBlt
 
我想做Windows開發應該都知道這個API, 它能實現DC間的內容拷貝, 如果我們把源DC指定成Monitor DC或是桌面DC, 它就能實現抓屏功能。
對於通過這種方式的抓屏, 有2點需要特別提醒:
a. 在XP下我們可以通過最後的拷貝標誌來控制是否拷貝layered window, 只有SRCCPY表示拷貝內容不包含layered window, 如果是SRCCPY | CAPTUREBLT表示拷貝包括Layered window在內的所有視窗。 這個標誌在Vista之後的系統(win7/win8),開啟DWM的情況下, 已經失效, 因為這種情況下所有的視窗都是layered window.
b. 這種方式的抓屏在 Vista之後, 開啟DWM的情況下, 抓屏速度非常慢(30ms +), 具體原因不知道是因為系統沒有快取整個螢幕的資料還是GPU向記憶體拷貝資料太慢了, 有知道的朋友可以提示下。
2. Mirror driver
 
這種方法應該是Win8之前最高效的抓屏方法, 也是微軟推薦的遠端桌面共享方案,它通過建立虛擬映象驅動, 直接獲取最終螢幕變化資料。
該方法也有一些缺點:
a. 涉及到驅動安裝, 技術難度大, 系統許可權要求也高
b. Win8 上該方案已經失效, 但是還是有方法的, 參見 Remote Display Drivers


 
3. GDI hook
 
這種方法應該說是XP時代比較流行的抓屏方法, 因為所有的繪製都是通過GDI32.dll中的繪圖函式來實現的, 所以我們只要攔截了這些函式, 系統的所有繪製就都讓我們控制了。這種方法應該來說也是一種挺高效的抓屏方法,螢幕的變化也都能讓我們攔截到, 同時因為好多繪圖函式是以向量方式實現的,所有抓到的資料包非常小, 即使在低頻寬下也效果挺好。
下面是該方法的一些缺點:
a. Hook技術本身就有其複雜性和不穩定性, 尤其是Hook所有程式
b. Vista只有越來越多程式採用D2D/D3D繪製, GDI Hook對這些繪製無能為力。
c. Vista之後UAC開啟的情況下, 如果我們的程式許可權不夠高, Hook不到更高許可權的程式。

 
4. Windows Media API
 
Windows Media 9.0 支援用Windows Media Encoder 9 API來抓屏。它有一個編碼器叫Windows Media Video 9 Screen codec,特別為抓屏優化過。Windows Media Encoder API提供了一個IWMEncoder2介面可以用來高效地捕捉螢幕影象。
因為對這組API不熟, 這種抓屏方法我也沒嘗試過, 具體可見Various methods for capturing the screen, 感覺這種方法的最大缺點是使用者機器需要安裝Windows Media Encoder 9。

 
5. DirectX

每個DirectX程式都包含一個被我們稱作緩衝的記憶體區域,其中儲存了和該程式有關的視訊記憶體內容,這在程式中被稱作後臺緩衝(Back Buffer),有些程式有不止一個的後臺緩衝。還有一個緩衝,在預設情況下每個程式都可以訪問-前臺緩衝。前臺緩衝儲存了和桌面相關的視訊記憶體內容,實質上就是螢幕影象。 我們的程式通過訪問前臺緩衝就可以捕捉到當前螢幕的內容。上面的列子中也包含該方法的實現, 是基於DirectX9的,我們可以參考下, 據我測試該方法在DWM開啟的情況下抓整屏也要30ms左右。Vista之後的DirectX 10/11相對於DirectX 9 已經發生非常大的變化, 直接用新的介面上面的程式碼未必能正常工作。
 

6. PrintWindow
 
該方法本身不能直接做為一種抓屏方法, 但是有時候我們要獲取某個視窗的內容, 即使他被其他視窗覆蓋著, 這時候這個函式就很有用。該方該呼叫法的原理是通過給目標視窗傳送WM_PRINT或是WM_PRINTCLIENT訊息, 所以如果目標視窗沒有響應, 該呼叫可能會阻塞抓屏執行緒, 這種情況下抓屏前最好先用SendMessageTimeout檢測目標視窗是否有響應。另外該方法也抓不到D3D視窗的內容。
 

7. DWM/Dxgi hook
 
Vista之後微軟放棄了XP時代的XPDM, 採用了全新的WDDM視屏驅動模型, 現在Win8.1上已經是WDDM1.3.
Vista之後底層所有的渲染都是基於D3D技術, 另外我們也知道系統在DWM.exe裡進行視窗邊框的繪畫和合成, 所以理論上我們可以通過HOOK DWM/D3D/DXGI,攔截到整個系統的螢幕內容。當然作為一種Hook技術, 它也有上面GDI Hook類似的問題。

 
8. Magnification
 
這組API是微軟Vista之後開放給我們開發放大鏡程式的, 它裡面提供了一個API讓我們攔截到顯示的內容, 可惜的是這個關鍵的API  MagSetImageScalingCallback 微軟已經宣佈作廢。另外該方式的抓屏效率也不高, 整屏需要60 ms 左右。

 
9. Desktop Duplication  
 
這是微軟Win8 上宣佈放棄Mirror driver之後推薦採用的抓屏技術, 全部基於D3D/DXGI技術, 效率非常高, 並且包含變化區域和螢幕滑鼠游標。它的缺點是沒法抓取某個視窗的內容 。


10. GetWindowDC 

該方法和PrintWindow類似,但是它沒有PrintWindow的許可權問題, 也沒有超時問題。
這種抓屏方法在Win7/Win8  DWM開啟的情況下抓屏,結果會顛覆我們XP時代的知識, 因為即使視窗被覆蓋, 它也可以正確抓取到被覆蓋視窗下的內容, WebRTC正是用這種方式來Share  Application的。
它的主要問題是有些視窗抓到的內容不包含非客戶區,有些視窗比如工作列的Thumbnail視窗會抓不到內容。
 
http://www.cppblog.com/weiym/archive/2013/12/01/204536.html

相關文章