1. BitBlt
我想做Windows開(kāi)發(fā)應(yīng)該都知道這個(gè)API, 它能實(shí)現(xiàn)DC間的內(nèi)容拷貝, 如果我們把源DC指定成Monitor DC或是桌面DC, 它就能實(shí)現(xiàn)抓屏功能。
對(duì)于通過(guò)這種方式的抓屏, 有2點(diǎn)需要特別提醒:
a. 在XP下我們可以通過(guò)最后的拷貝標(biāo)志來(lái)控制是否拷貝layered window, 只有SRCCPY表示拷貝內(nèi)容不包含layered window, 如果是SRCCPY | CAPTUREBLT表示拷貝包括Layered window在內(nèi)的所有窗口。 這個(gè)標(biāo)志在Vista之后的系統(tǒng)(win7/win8),開(kāi)啟DWM的情況下, 已經(jīng)失效, 因?yàn)檫@種情況下所有的窗口都是layered window.
b. 這種方式的抓屏在 Vista之后, 開(kāi)啟DWM的情況下, 抓屏速度非常慢(30ms +), 具體原因不知道是因?yàn)橄到y(tǒng)沒(méi)有緩存整個(gè)屏幕的數(shù)據(jù)還是GPU向內(nèi)存拷貝數(shù)據(jù)太慢了, 有知道的朋友可以提示下。
2. Mirror driver
這種方法應(yīng)該是Win8之前最高效的抓屏方法, 也是微軟推薦的遠(yuǎn)程桌面共享方案,它通過(guò)創(chuàng)建虛擬鏡像驅(qū)動(dòng), 直接獲取最終屏幕變化數(shù)據(jù)。
該方法也有一些缺點(diǎn):
a. 涉及到驅(qū)動(dòng)安裝, 技術(shù)難度大, 系統(tǒng)權(quán)限要求也高
3. GDI hook
這種方法應(yīng)該說(shuō)是XP時(shí)代比較流行的抓屏方法, 因?yàn)樗械睦L制都是通過(guò)GDI32.dll中的繪圖函數(shù)來(lái)實(shí)現(xiàn)的, 所以我們只要攔截了這些函數(shù), 系統(tǒng)的所有繪制就都讓我們控制了。這種方法應(yīng)該來(lái)說(shuō)也是一種挺高效的抓屏方法,屏幕的變化也都能讓我們攔截到, 同時(shí)因?yàn)楹枚嗬L圖函數(shù)是以矢量方式實(shí)現(xiàn)的,所有抓到的數(shù)據(jù)包非常小, 即使在低帶寬下也效果挺好。
下面是該方法的一些缺點(diǎn):
a. Hook技術(shù)本身就有其復(fù)雜性和不穩(wěn)定性, 尤其是Hook所有進(jìn)程
b. Vista只有越來(lái)越多程序采用D2D/D3D繪制, GDI Hook對(duì)這些繪制無(wú)能為力。
c. Vista之后UAC打開(kāi)的情況下, 如果我們的程序權(quán)限不夠高, Hook不到更高權(quán)限的程序。
4. Windows Media API
Windows Media 9.0 支持用Windows Media Encoder 9 API來(lái)抓屏。它有一個(gè)編碼器叫Windows Media Video 9 Screen codec,特別為抓屏優(yōu)化過(guò)。Windows Media Encoder API提供了一個(gè)IWMEncoder2接口可以用來(lái)高效地捕捉屏幕圖像。
5. DirectX
每個(gè)DirectX程序都包含一個(gè)被我們稱作緩沖的內(nèi)存區(qū)域,其中保存了和該程序有關(guān)的顯存內(nèi)容,這在程序中被稱作后臺(tái)緩沖(Back Buffer),有些程序有不止一個(gè)的后臺(tái)緩沖。還有一個(gè)緩沖,在默認(rèn)情況下每個(gè)程序都可以訪問(wèn)-前臺(tái)緩沖。前臺(tái)緩沖保存了和桌面相關(guān)的顯存內(nèi)容,實(shí)質(zhì)上就是屏幕圖像。 我們的程序通過(guò)訪問(wèn)前臺(tái)緩沖就可以捕捉到當(dāng)前屏幕的內(nèi)容。上面的列子中也包含該方法的實(shí)現(xiàn), 是基于DirectX9的,我們可以參考下, 據(jù)我測(cè)試該方法在DWM打開(kāi)的情況下抓整屏也要30ms左右。Vista之后的DirectX 10/11相對(duì)于DirectX 9 已經(jīng)發(fā)生非常大的變化, 直接用新的接口上面的代碼未必能正常工作。
6. PrintWindow
該方法本身不能直接做為一種抓屏方法, 但是有時(shí)候我們要獲取某個(gè)窗口的內(nèi)容, 即使他被其他窗口覆蓋著, 這時(shí)候這個(gè)函數(shù)就很有用。該方該調(diào)用法的原理是通過(guò)給目標(biāo)窗口發(fā)送WM_PRINT或是WM_PRINTCLIENT消息, 所以如果目標(biāo)窗口沒(méi)有響應(yīng), 該調(diào)用可能會(huì)阻塞抓屏線程, 這種情況下抓屏前最好先用SendMessageTimeout檢測(cè)目標(biāo)窗口是否有響應(yīng)。另外該方法也抓不到D3D窗口的內(nèi)容。
7. DWM/Dxgi hook
Vista之后微軟放棄了XP時(shí)代的XPDM, 采用了全新的WDDM視屏驅(qū)動(dòng)模型, 現(xiàn)在Win8.1上已經(jīng)是WDDM1.3.
Vista之后底層所有的渲染都是基于D3D技術(shù), 另外我們也知道系統(tǒng)在DWM.exe里進(jìn)行窗口邊框的繪畫(huà)和合成, 所以理論上我們可以通過(guò)HOOK DWM/D3D/DXGI,攔截到整個(gè)系統(tǒng)的屏幕內(nèi)容。當(dāng)然作為一種Hook技術(shù), 它也有上面GDI Hook類似的問(wèn)題。
8. Magnification
這組API是微軟Vista之后開(kāi)放給我們開(kāi)發(fā)放大鏡程序的, 它里面提供了一個(gè)API讓我們攔截到顯示的內(nèi)容, 可惜的是這個(gè)關(guān)鍵的API MagSetImageScalingCallback 微軟已經(jīng)宣布作廢。另外該方式的抓屏效率也不高, 整屏需要60 ms 左右。
9. Desktop Duplication
這是微軟Win8 上宣布放棄Mirror driver之后推薦采用的抓屏技術(shù), 全部基于D3D/DXGI技術(shù), 效率非常高, 并且包含變化區(qū)域和屏幕鼠標(biāo)光標(biāo)。它的缺點(diǎn)是沒(méi)法抓取某個(gè)窗口的內(nèi)容 。
10. GetWindowDC
該方法和PrintWindow類似,但是它沒(méi)有PrintWindow的權(quán)限問(wèn)題, 也沒(méi)有超時(shí)問(wèn)題。
這種抓屏方法在Win7/Win8 DWM打開(kāi)的情況下抓屏,結(jié)果會(huì)顛覆我們XP時(shí)代的知識(shí), 因?yàn)榧词勾翱诒桓采w, 它也可以正確抓取到被覆蓋窗口下的內(nèi)容, WebRTC正是用這種方式來(lái)Share Application的。
它的主要問(wèn)題是有些窗口抓到的內(nèi)容不包含非客戶區(qū),有些窗口比如任務(wù)欄的Thumbnail窗口會(huì)抓不到內(nèi)容。
最后簡(jiǎn)單總結(jié)下 , 我們可以看到Windows系統(tǒng)上基本沒(méi)有一種通用的抓屏技術(shù)可以高效的抓取所有的系統(tǒng)(XP/Win7/Win8), 很大一部原因是操作系統(tǒng)的顯示驅(qū)動(dòng)模型在從XPDM向WDDM轉(zhuǎn)變, 應(yīng)用層的API也在從GDI向D3D轉(zhuǎn)變 。 相對(duì)于Linux的穩(wěn)定, Window的不斷發(fā)展和進(jìn)步, 對(duì)開(kāi)發(fā)人員究竟是喜是悲?
posted on 2013-12-01 22:04
Richard Wei 閱讀(38813)
評(píng)論(16) 編輯 收藏 引用 所屬分類:
windows desktop