昨天寫(xiě)自動(dòng)化測(cè)試的CASE的時(shí)候,碰到一個(gè)疑難雜癥,調(diào)用截圖的函數(shù)去截取一個(gè)Popup窗口,但是總是把背景程序給截下來(lái),Popup窗口就跟看不到一樣。本來(lái)以為是同步的問(wèn)題,也就是以為先截圖再點(diǎn)擊彈出Popup窗口了。后來(lái)加了N個(gè)Thread.Sleep來(lái)測(cè)試,發(fā)現(xiàn)根本不是因?yàn)檫@個(gè)原因,而是截圖的函數(shù)截不下來(lái)這個(gè)窗口。
這個(gè)為啥呢,只好把截圖的函數(shù)代碼翻出來(lái)看,以前是用這種方式的:
BitBlt(dcImage, 0, 0, (int)(rect.Width), (int)(rect.Height), dcScreen, (int)(rect.Left), (int)(rect.Top), TernaryRasterOperations.SRCCOPY);
憑直覺(jué)感覺(jué)應(yīng)該是因?yàn)檫@種通過(guò)DC的方式對(duì)WPF程序支持有問(wèn)題,但是又覺(jué)得奇怪就是截取其它的WPF組件和窗口都沒(méi)有問(wèn)題,偏偏Popup窗口不行。
前些天聽(tīng)說(shuō)另外一種截屏的方法,這種方法連被遮擋的窗口都可以截,于是就Google一大把,找打了PRintWindow函數(shù),于是就有了第二種解決方案,代碼如下:
IntPtr hdc = Native.GetWindowDC(this.Handle);
if (hdc != IntPtr.Zero)
{
IntPtr hdcMem = Native.CreateCompatibleDC(hdc);
if (hdcMem != IntPtr.Zero)
{
IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, (int)(Rect.Width), (int)(Rect.Height));
if (hbitmap != IntPtr.Zero)
{
Native.SelectObject(hdcMem, hbitmap);
Native.PrintWindow(this.Handle, hdcMem, 0);
Native.DeleteObject(hbitmap);
Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
bmp.Save(sPath);
}
Native.DeleteObject(hdcMem);
}
Native.ReleaseDC(this.Handle, hdc);
}
就是拿到窗口的句柄,通過(guò)PrintWindow API來(lái)截取窗口。
但是更讓人氣憤的事情出現(xiàn)了,截出來(lái)的窗口中,只要是用到WPF組件的地方,全部是黑塊兒,只有MFC的窗口框架和按鈕可以正常被截取。
于是乎,就無(wú)奈的繼續(xù)分析這個(gè)問(wèn)題,我記得WPF是沒(méi)有走GDI,而是通過(guò)Directx渲染的,那就是說(shuō)DC的方式和PrintWindow的方式都不靠譜,但是截Directx的貌似還比較復(fù)雜。
突然想起來(lái),平常報(bào)bug的時(shí)候都是按PrintScreen,然后再處理一下的,那應(yīng)該P(yáng)rintScreen按鍵是管用的,看來(lái)只能曲線救國(guó)了。但是那樣就得走剪切板了,貌似會(huì)破壞剪切板的數(shù)據(jù),不過(guò)如果我在截取前保存一下數(shù)據(jù),在截取后再恢復(fù)一下剪切板數(shù)據(jù),那就沒(méi)有問(wèn)題了。
于是就有了第三種解決方案(暫時(shí)還沒(méi)有加恢復(fù)剪切板數(shù)據(jù)的代碼):
const uint KEYEVENTF_EXTENDEDKEY = 0x1;
const uint KEYEVENTF_KEYUP = 0x2;
const byte VK_SNAPSHOT = 0x2C;
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero);
IDataObject iObj = Clipboard.GetDataObject();
if (iObj.GetDataPresent(DataFormats.Bitmap, true))
{
Bitmap bmpScreen = iObj.GetData(DataFormats.Bitmap, true) as Bitmap;
Bitmap bmpOutput = new Bitmap((int)this.Rect.Width, (int)this.Rect.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(bmpOutput);
Rectangle destRectangle = new Rectangle(0, 0, (int)this.Rect.Width, (int)this.Rect.Height);
g.DrawImage(bmpScreen,destRectangle, (int)this.Rect.X, (int)this.Rect.Y, (int)this.Rect.Width, (int)this.Rect.Height, GraphicsUnit.Pixel);
bmpOutput.Save(sPath, System.Drawing.Imaging.ImageFormat.Bmp);
}
測(cè)試可用,只好先用著了
不過(guò)還有幾個(gè)問(wèn)題,先寫(xiě)下來(lái),留待以后解決:
1. 針對(duì)第三種方案,既然可以按PrintScreen鍵截圖,那對(duì)應(yīng)的API是什么,總覺(jué)得發(fā)鍵盤(pán)消息沒(méi)有直接調(diào)API穩(wěn)定
2. 針對(duì)WPF截圖有沒(méi)有更好的解決方案
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注