c#

位置:IT落伍者 >> c# >> 浏览文章

C#中三种截屏方式小结


发布日期:2024年09月01日
 
C#中三种截屏方式小结

昨天写自动化测试的CASE的时候碰到一个疑难杂症调用截图的函数去截取一个Popup窗口但是总是把背景程序给截下来Popup窗口就跟看不到一样本来以为是同步的问题也就是以为先截图再点击弹出Popup窗口了后来加了N个ThreadSleep来测试发现根本不是因为这个原因而是截图的函数截不下来这个窗口

这个为啥呢只好把截图的函数代码翻出来看以前是用这种方式的BitBlt(dcImage (int)(rectWidth) (int)(rectHeight) dcScreen (int)(rectLeft) (int)(rectTop) TernaryRasterOperationsSRCCOPY)凭直觉感觉应该是因为这种通过DC的方式对WPF程序支持有问题但是又觉得奇怪就是截取其它的WPF组件和窗口都没有问题偏偏Popup窗口不行

前些天听说另外一种截屏的方法这种方法连被遮挡的窗口都可以截于是就Google一大把找打了PrintWindow函数于是就有了第二种解决方案代码如下

IntPtr hdc = NativeGetWindowDC(thisHandle);

if (hdc != IntPtrZero)

{

IntPtr hdcMem = NativeCreateCompatibleDC(hdc);

if (hdcMem != IntPtrZero)

{

IntPtr hbitmap = NativeCreateCompatibleBitmap(hdc (int)(RectWidth) (int)(RectHeight));

if (hbitmap != IntPtrZero)

{

NativeSelectObject(hdcMem hbitmap);

NativePrintWindow(thisHandle hdcMem );

NativeDeleteObject(hbitmap);

Bitmap bmp = BitmapFromHbitmap(hbitmap);

bmpSave(sPath);

}

NativeDeleteObject(hdcMem);

}

NativeReleaseDC(thisHandle hdc);

}

就是拿到窗口的句柄通过PrintWindow API来截取窗口

但是更让人气愤的事情出现了截出来的窗口中只要是用到WPF组件的地方全部是黑块儿只有MFC的窗口框架和按钮可以正常被截取

于是乎就无奈的继续分析这个问题我记得WPF是没有走GDI而是通过Directx渲染的那就是说DC的方式和PrintWindow的方式都不靠谱但是截Directx的貌似还比较复杂

突然想起来平常报bug的时候都是按PrintScreen然后再处理一下的那应该PrintScreen按键是管用的看来只能曲线救国了但是那样就得走剪切板了貌似会破坏剪切板的数据不过如果我在截取前保存一下数据在截取后再恢复一下剪切板数据那就没有问题了

于是就有了第三种解决方案(暂时还没有加恢复剪切板数据的代码)

const uint KEYEVENTF_EXTENDEDKEY = x;

const uint KEYEVENTF_KEYUP = x;

const byte VK_SNAPSHOT = xC;

Nativekeybd_event(VK_SNAPSHOT x KEYEVENTF_EXTENDEDKEY UIntPtrZero);

Nativekeybd_event(VK_SNAPSHOT x KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP UIntPtrZero);

IDataObject iObj = ClipboardGetDataObject();

if (iObjGetDataPresent(DataFormatsBitmap true))

{

Bitmap bmpScreen = iObjGetData(DataFormatsBitmap true) as Bitmap;

Bitmap bmpOutput = new Bitmap((int)thisRectWidth (int)thisRectHeight SystemDrawingImagingPixelFormatFormatbppRgb);

Graphics g = GraphicsFromImage(bmpOutput);

Rectangle destRectangle = new Rectangle( (int)thisRectWidth (int)thisRectHeight);

gDrawImage(bmpScreendestRectangle (int)thisRectX (int)thisRectY (int)thisRectWidth

(int)thisRectHeight GraphicsUnitPixel);

bmpOutputSave(sPath SystemDrawingImagingImageFormatBmp);

}

测试可用只好先用着了

不过还有几个问题先写下来留待以后解决

针对第三种方案既然可以按PrintScreen键截图那对应的API是什么总觉得发键盘消息没有直接调API稳定

针对WPF截图有没有更好的解决方案

上一篇:使用C#构建带事件的签名ActiveX组件

下一篇:C#判断素数的算法