【问题标题】:How to get the screenshot of the form如何获取表单的屏幕截图
【发布时间】:2025-11-26 06:40:01
【问题描述】:

有什么方法可以输出活动表单的截图吗?

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    .NET 支持的更简单的答案:

    Control.DrawToBitmap.

    【讨论】:

    • 如果您想捕获当时可能打开的任何对话框怎么办?或重叠的表格。我认为您不会在用户屏幕上看到该应用程序。
    • 这个方法有一些限制(最明显的是子控件以相反的顺序绘制),我已经发布了一个没有这个问题的答案。
    【解决方案2】:

    使用 Control.DrawToBitmap() 方法。例如:

        private void timer1_Tick(object sender, EventArgs e) {
            var frm = Form.ActiveForm;
            using (var bmp = new Bitmap(frm.Width, frm.Height)) {
                frm.DrawToBitmap(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height));
                bmp.Save(@"c:\temp\screenshot.png");
            }
        }
    

    【讨论】:

      【解决方案3】:

      因为 Control.DrawToBitmap 有一些限制(最明显的是以相反的顺序绘制子控件),所以我做了这个替代方案。变量_control 是您要复制的 WinForms 控件/表单。

      using (Bitmap bitmap = new Bitmap(width, height)) {
          using (Graphics gb = Graphics.FromImage(bitmap))
          using (Graphics gc = Graphics.FromHwnd(_control.Handle)) {
      
                IntPtr hdcDest = IntPtr.Zero;
                IntPtr hdcSrc = IntPtr.Zero;
      
                try {
                    hdcDest = gb.GetHdc();
                    hdcSrc = gc.GetHdc();
      
                    BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRC_COPY);
                } finally {
                    if (hdcDest != IntPtr.Zero) gb.ReleaseHdc(hdcDest);
                    if (hdcSrc != IntPtr.Zero) gc.ReleaseHdc(hdcSrc);
                }
            }
      
            bitmap.Save(...);
      }
      
      [DllImport("gdi32.dll", EntryPoint = "BitBlt")]
      [return: MarshalAs(UnmanagedType.Bool)]
      public static extern bool BitBlt(
          [In()] System.IntPtr hdc, int x, int y, int cx, int cy,
          [In()] System.IntPtr hdcSrc, int x1, int y1, uint rop);
      
      private const int SRC_COPY = 0xCC0020;
      

      【讨论】:

        【解决方案4】:
        here is:
        
        
        
        
               public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
        
            [DllImport("gdi32.dll")]
            public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
                int nWidth, int nHeight, IntPtr hObjectSource,
                int nXSrc, int nYSrc, int dwRop);
        
            [DllImport("gdi32.dll")]
            public static extern bool StretchBlt(
                  IntPtr hdcDest,      // handle to destination DC
                  int nXOriginDest, // x-coord of destination upper-left corner
                  int nYOriginDest, // y-coord of destination upper-left corner
                  int nWidthDest,   // width of destination rectangle
                  int nHeightDest,  // height of destination rectangle
                  IntPtr hdcSrc,       // handle to source DC
                  int nXOriginSrc,  // x-coord of source upper-left corner
                  int nYOriginSrc,  // y-coord of source upper-left corner
                  int nWidthSrc,    // width of source rectangle
                  int nHeightSrc,   // height of source rectangle
                  int dwRop       // raster operation code
                );
        
        
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
                int nHeight);
            [DllImport("gdi32.dll")]
            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteDC(IntPtr hDC);
            [DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
            [DllImport("gdi32.dll")]
            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
        
        
        
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }
        
            [DllImport("user32.dll")]
            public static extern IntPtr GetDesktopWindow();
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll")]
            public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
            [DllImport("user32.dll")]
            public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
        
            private void run_test()
            {
        
                Rectangle rc = new Rectangle();
                Image img = ScreenToImage(ref rc, false);
                img.Save(@"C:\Users\ssaamm\Desktop\Capt44ure.JPG", System.Drawing.Imaging.ImageFormat.Jpeg);
                img.Dispose();
        
            }
        
        
            private Image ScreenToImage(ref Rectangle rcDest, bool IsPapaer)
            {
                IntPtr handle = this.Handle;
        
                //this.Handle
                // get te hDC of the target window
                IntPtr hdcSrc = GetWindowDC(handle);
                // get the size
                RECT windowRect = new RECT();
                GetWindowRect(handle, ref windowRect);
                int nWidth = windowRect.right - windowRect.left;
                int nHeight = windowRect.bottom - windowRect.top;
        
                if (IsPapaer)
                {
                    float fRate = (float)rcDest.Width / nWidth;
                    //float fHeight = nHeight * fRate;
                    //rcDest.Height = (int)(nHeight * fRate);
                    //rcDest.Width = (int)(rcDest.Width);// * fRate);
                    rcDest.X = 0;
                    rcDest.Y = 0;
                    rcDest.Height = (int)(nHeight * fRate);
                    //rcDest.Width = (int)(nWidth * fRate);
                }
                else
                {
                    rcDest.X = 0;
                    rcDest.Y = 0;
                    rcDest.Height = nHeight;
                    rcDest.Width = nWidth;
                }
        
                // create a device context we can copy to
                IntPtr hdcDest = CreateCompatibleDC(hdcSrc);
                // create a bitmap we can copy it to,
                // using GetDeviceCaps to get the width/height
                IntPtr hBitmap = CreateCompatibleBitmap(hdcSrc, rcDest.Width, rcDest.Height);
                // select the bitmap object
                IntPtr hOld = SelectObject(hdcDest, hBitmap);
                // bitblt over
                StretchBlt(hdcDest, rcDest.X, rcDest.Y, rcDest.Width, rcDest.Height, hdcSrc, 0, 0, nWidth, nHeight, SRCCOPY);
                // restore selection
                SelectObject(hdcDest, hOld);
                // clean up 
                DeleteDC(hdcDest);
                ReleaseDC(handle, hdcSrc);
        
                // get a .NET image object for it
                Image img = Image.FromHbitmap(hBitmap);
                // free up the Bitmap object
                DeleteObject(hBitmap);
                return img;
            }
        

        【讨论】:

          【解决方案5】:

          这会将活动窗口的屏幕截图保存到 C: 驱动器。

          SendKeys.Send("") 用于将按键发送到计算机。在这种情况下,% 用于按下 Alt{PRTSC} 显然是按下键盘上的 Print Screen 按钮。

          希望这对某人有所帮助!

          private void printScreenButton_Click(object sender, EventArgs e)
          {
              SendKeys.Send("%{PRTSC}");
              Image img = Clipboard.GetImage();
              img.Save(@"C:\\testprintscreen.jpg");
          }
          

          【讨论】:

          • 它还会破坏剪贴板上的任何内容,这可能会妨碍用户执行操作。
          【解决方案6】:

          试试这个:

          using System;
          using System.Collections.Generic;
          using System.ComponentModel;
          using System.Data;
          using System.Drawing;
          using System.Text;
          using System.Windows.Forms;
          using System.Drawing.Imaging;
          
          namespace ScreenshotCapturer
          {
              public partial class Form1 : Form
              {
                  private static Bitmap bmpScreenshot;
                  private static Graphics gfxScreenshot;
          
                  public Form1()
                  {
                      InitializeComponent();
                  }
          
                  private void btnCapture_Click(object sender, EventArgs e)
                  {
                      // If the user has choosed a path where to save the screenshot
                      if (saveScreenshot.ShowDialog() == DialogResult.OK)
                      {
                          // Hide the form so that it does not appear in the screenshot
                          this.Hide();
                          // Set the bitmap object to the size of the screen
                          bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
                          // Create a graphics object from the bitmap
                          gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                          // Take the screenshot from the upper left corner to the right bottom corner
                          gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
                          // Save the screenshot to the specified path that the user has chosen
                          bmpScreenshot.Save(saveScreenshot.FileName, ImageFormat.Png);
                          // Show the form again
                          this.Show();
                      }
                  }
              }
          }
          

          【讨论】:

          • 这个 ScreenCapture 类从何而来?它不是 .NET 框架的一部分...
          【解决方案7】:

          这是您可以使用的扩展方法:

              #region Interop
          
              [DllImport("user32.dll")]
              static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr hdc, PRF_FLAGS drawingOptions);
          
              const uint WM_PRINT = 0x317;
          
              [Flags]
              enum PRF_FLAGS : uint
              {
                  CHECKVISIBLE = 0x01,
                  CHILDREN = 0x02,
                  CLIENT = 0x04,
                  ERASEBKGND = 0x08,
                  NONCLIENT = 0x10,
                  OWNED = 0x20
              }
          
              #endregion
          
              public static Image CaptureImage(this Control control)
              {
                  Image img = new Bitmap(control.Width, control.Height);
                  using (Graphics g = Graphics.FromImage(img))
                  {
                      SendMessage(
                         control.Handle,
                         WM_PRINT,
                         g.GetHdc(),
                         PRF_FLAGS.CLIENT | PRF_FLAGS.NONCLIENT | PRF_FLAGS.ERASEBKGND);
                  }
                  return img;
              }
          

          Form 继承自 Control,因此您也可以在表单上使用它。

          【讨论】:

          • 这似乎与 Control.DrawToBitmap 的功能相同,但具有相同的限制(例如以相反的顺序绘制子控件)。
          【解决方案8】:
                   this.Opacity = 0;
                  Rectangle bounds = Screen.GetBounds(Point.Empty);
          
                  // create the bitmap to copy the screen shot to
                  Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
          
                  // now copy the screen image to the graphics device from the bitmap
                  using (Graphics gr = Graphics.FromImage(bitmap))
                  {
          
                      gr.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);          
                  }
                  this.Opacity = 100;
          

          现在就

                  gr.Save(@"c\pic.jpg",ImageFormat.jpg);
          

          【讨论】:

          • 我相信你已经错过了阅读这个问题。该问题指出“活动表单的屏幕截图”,而您的解决方案将捕获整个屏幕,而将活动表单排除在外。我相信您可以轻松地将其转换为问题所要求的内容。
          最近更新 更多