• 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);
    }
  • 相关阅读:
    cxgrid显示行号
    编写服务端程序的要点
    创建自己的数据库
    cxgrid动态创建footer
    build with runtime package
    TQueue,TStack
    能用图形分析
    Laravel任务调度
    PHP 判断点是否在多边形内
    判断一个点是否在某个区域内。百度,高德,腾讯都能用。(php版)
  • 原文地址:https://www.cnblogs.com/Xavierr/p/2146000.html
Copyright © 2020-2023  润新知