C#如何截屏

最近用到截屏功能,有点小波折,写下心得。

1. CopyFromScreen

最开始使用的方法,如下,还附带了如何截取鼠标形状。但是很快发现了问题,有些窗口的控件不能截取图像。找了很久原因也不清楚,猜测可能是WPF程序。

public static void CaptureEx(string fileName, bool withCursor = false)
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;

using (Bitmap bitmap = new Bitmap(width, height))
{
using(Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(
0, 0, 0, 0, bitmap.Size);

if (withCursor)
DrawCursor(graphics);

try
{
bitmap.Save(fileName, ImageFormat.Jpeg);
}
catch
{}

graphics.ReleaseHdc(graphics.GetHdc());
}
}
}

private static void DrawCursor(Graphics graphics)
{
CURSORINFO pci
= new CURSORINFO();
pci.cbSize
= Marshal.SizeOf(pci);
API.GetCursorInfo(
ref pci);

if (pci.hCursor == IntPtr.Zero)
return;

Cursor cursor
=new Cursor(pci.hCursor);
Point point
=new Point(pci.ptScreenPos.X -10, pci.ptScreenPos.Y -10);
cursor.Draw(graphics,
new Rectangle(point, cursor.Size));
}
[StructLayout(LayoutKind.Sequential)]
public struct CURSORINFO
{
public int cbSize;
public int flags;
public IntPtr hCursor;
public Point ptScreenPos;
}

2. SendKeys.SendWait("{PRTSC}")
试了试手工截图,可以解决方法一中的问题,于是想模拟键盘操作。
public static void Capture(string fileName)
{
System.Windows.Forms.SendKeys.SendWait(
"{PRTSC}");

Image image
= Clipboard.GetImage();
if (image == null)
return;

image.Save(fileName, ImageFormat.Jpeg);
}

 开始以为可以了,后经测试发现SendKeys.SendWait("{PRTSC}")的效果和SendKeys.SendWait("%{PRTSC}")一样,也就是"Alt"+"PrtSc"。郁闷了,原来Sendkeys还不支持截屏键的使用。Google搜索后发现如下说明,虽然说得不太清楚,或者已经过时了,但是不能用SendKeys截取全屏是事实。

注意 不能用SendKeys将按键消息发送到这样一个应用程序,这个应用程序并没有被设计成在 Microsoft Windows 中运行。Sendkeys 也无法将 PRINT SCREEN 按键 {PRTSC} 发送到任何应用程序。

3. keybd_event

终于解决了问题。注意一定要加上Application.DoEvents(),否则截图总是会出问题。

Application.DoEvents()表示交出CPU控制权,让系统可以处理队列中的所有Windows消息。比如在大运算量循环内,加Application.DoEvents可以防止界面停止响应。

因为winform的消息循环是一个线程来处理,那么假如你的某个操作比较耗时,那么消息处理得等你这个耗时操作做完了才能继续,而Application.DoEvents方法就是允许你在耗时操作的内部调用它,而去处理消息队列中的消息。 

像鼠标移动鼠标点击都是windows消息,如果耗时操作一直进行,那么界面就像死锁一样。

[DllImport("user32.dll", EntryPoint = "keybd_event")]
public static extern void keybd_event(int bVk, int bScan, int dwFlags, int dwExtraInfo);

public const int KEYEVENTF_KEYUP = 0x0002;
public const int KEYEVENTF_KEYDOWN = 0x0000;
public static void Capture(string fileName)
{
keybd_event((
int)Keys.PrintScreen, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event((
int)Keys.PrintScreen, 0, KEYEVENTF_KEYUP, 0);
Application.DoEvents();


Image image
= Clipboard.GetImage();
if (image == null)
return;

image.Save(fileName, ImageFormat.Jpeg);
}
原文地址:https://www.cnblogs.com/Xavierr/p/2146000.html