截屏方法:C#中 3种截屏方式及解决思路方法来源: 发布时间:星期五, 2009年2月20日 浏览:0次 评论:0
昨天写自动化测试CASE时候碰到个疑难杂症截图去截取个Popup窗口但是总是把背景给截下来Popup窗口就跟看不到样本来以为是同步问题也就是以为先截图再点击弹出Popup窗口了后来加了N个Thread.Sleep来测试发现根本不是这个原因而是截图截不下来这个窗口 这个为啥呢只好把截图代码翻出来看以前是用这种方式: view plaincopy to clipboardpr? BitBlt(dcImage, 0, 0, ()(rect.Width), ()(rect.Height), dcScreen, ()(rect.Left), ()(rect.Top), TernaryRasterOperations.SRCCOPY); BitBlt(dcImage, 0, 0, ()(rect.Width), ()(rect.Height), dcScreen, ()(rect.Left), ()(rect.Top), TernaryRasterOperations.SRCCOPY); 凭直觉感觉应该是这种通过DC方式对WPF支持有问题但是又觉得奇怪就是截取其它WPF组件和窗口都没有问题偏偏Popup窗口不行 前些天听说另外种截屏思路方法这种思路方法连被遮挡窗口都可以截于是就Google大把找打了PrWindow于是就有了第 2种解决方案代码如下: view plaincopy to clipboardpr? IntPtr hdc = Native.GetWindowDC(this.Handle); (hdc != IntPtr.Zero) { IntPtr hdcMem = Native.CreateCompatibleDC(hdc); (hdcMem != IntPtr.Zero) { IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, ()(Rect.Width), ()(Rect.Height)); (hbitmap != IntPtr.Zero) { Native.SelectObject(hdcMem, hbitmap); Native.PrWindow(this.Handle, hdcMem, 0); Native.DeleteObject(hbitmap); Bitmap bmp = Bitmap.FromHbitmap(hbitmap); bmp.Save(sPath); } Native.DeleteObject(hdcMem); } Native.ReleaseDC(this.Handle, hdc); } IntPtr hdc = Native.GetWindowDC(this.Handle); (hdc != IntPtr.Zero) { IntPtr hdcMem = Native.CreateCompatibleDC(hdc); (hdcMem != IntPtr.Zero) { IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, ()(Rect.Width), ()(Rect.Height)); (hbitmap != IntPtr.Zero) { Native.SelectObject(hdcMem, hbitmap); Native.PrWindow(this.Handle, hdcMem, 0); Native.DeleteObject(hbitmap); Bitmap bmp = Bitmap.FromHbitmap(hbitmap); bmp.Save(sPath); } Native.DeleteObject(hdcMem); } Native.ReleaseDC(this.Handle, hdc); } 就是拿到窗口句柄通过PrWindow API来截取窗口 但是更让人气愤事情出现了截出来窗口中只要是用到WPF组件地方全部是黑块儿只有MFC窗口框架和按钮可以正常被截取 于是乎就无奈继续分析这个问题我记得WPF是没有走GDI而是通过Directx渲染那就是说DC方式和PrWindow方式都不靠谱但是截Directx貌似还比较复杂 突然想起来平常报bug时候都是按PrScreen然后再处理下那应该PrScreen按键是管用看来只能曲线救国了但是那样就得走剪切板了貌似会破坏剪切板数据不过如果我在截取前保存下数据在截取后再恢复下剪切板数据那就没有问题了 于是就有了第 3种解决方案(暂时还没有加恢复剪切板数据代码): view plaincopy to clipboardpr? const u KEYEVENTF_EXTENDEDKEY = 0x1; const u KEYEVENTF_KEYUP = 0x2; const 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; (iObj.GetDataPresent(DataFormats.Bitmap, true)) { Bitmap bmpScreen = iObj.GetData(DataFormats.Bitmap, true) as Bitmap; Bitmap bmpOutput = Bitmap(()this.Rect.Width, ()this.Rect.Height, .Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bmpOutput); Rectangle destRectangle = Rectangle(0, 0, ()this.Rect.Width, ()this.Rect.Height); g.DrawImage(bmpScreen,destRectangle, ()this.Rect.X, ()this.Rect.Y, ()this.Rect.Width, ()this.Rect.Height, GraphicsUnit.Pixel); bmpOutput.Save(sPath, .Drawing.Imaging.ImageFormat.Bmp); } const u KEYEVENTF_EXTENDEDKEY = 0x1; const u KEYEVENTF_KEYUP = 0x2; const 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; (iObj.GetDataPresent(DataFormats.Bitmap, true)) { Bitmap bmpScreen = iObj.GetData(DataFormats.Bitmap, true) as Bitmap; Bitmap bmpOutput = Bitmap(()this.Rect.Width, ()this.Rect.Height, .Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bmpOutput); Rectangle destRectangle = Rectangle(0, 0, ()this.Rect.Width, ()this.Rect.Height); g.DrawImage(bmpScreen,destRectangle, ()this.Rect.X, ()this.Rect.Y, ()this.Rect.Width, ()this.Rect.Height, GraphicsUnit.Pixel); bmpOutput.Save(sPath, .Drawing.Imaging.ImageFormat.Bmp); } 测试可用只好先用着了 不过还有几个问题先写下来留待以后解决: 1. 针对第 3种方案既然可以按PrScreen键截图那对应API是什么总觉得发键盘消息没有直接调API稳定 2. 针对WPF截图有没有更好解决方案 0
相关文章读者评论发表评论 |