65.9K
CodeProject 正在变化。 阅读更多。
Home

在C#中捕获屏幕图像

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (33投票s)

2002年10月12日

1分钟阅读

viewsIcon

363710

downloadIcon

13984

一篇关于使用Win32 API在C#中捕获屏幕的文章。

引言

我正在使用 C# 开发一个桌面共享类型的应用程序。我遇到的第一个问题是 C# 中没有太多工具可以截取桌面图像。经过一番研究,我了解到我需要使用 Win32 API 来为我的应用程序提供此功能。我创建了以下三个类来完成这项工作。

  1. PlatformInvokeGDI32: 此类包含此应用程序中使用的所有 GDI32.dll API。
  2. PlatformInvokeUSER32: 此类包含所有 User32.dll API。
  3. CaptureScreen: 在这个类中,我提供了一个简单的静态函数 GetDesktopImage,它使用 PlatformInvokeGDI32PlatformInvokeUSER32 中提供的 API 截取屏幕图像,并将其作为位图返回。

您可以很容易地将这些类放置在您的 C# 应用程序中。只需将以下代码复制并粘贴到您的 C# 项目中,无需进行任何更改。如果您想使用附带的源文件,您可以将 CaptureScreen 命名空间添加到您的项目中,或者只需将这些类中的 CaptureScreen 命名空间更改为您的项目命名空间即可,就完成了。

美丽的源代码

/// <summary>
/// This class shall keep the GDI32 APIs used in our program.
/// </summary>
public class PlatformInvokeGDI32
{
#region Class Variables
    public const int SRCCOPY = 13369376;
#endregion
#region Class Functions<br>
    [DllImport("gdi32.dll",EntryPoint="DeleteDC")]
    public static extern IntPtr DeleteDC(IntPtr hDc);

    [DllImport("gdi32.dll",EntryPoint="DeleteObject")]
    public static extern IntPtr DeleteObject(IntPtr hDc);

    [DllImport("gdi32.dll",EntryPoint="BitBlt")]
    public static extern bool BitBlt(IntPtr hdcDest,int xDest,
        int yDest,int wDest,int hDest,IntPtr hdcSource,
        int xSrc,int ySrc,int RasterOp);

    [DllImport ("gdi32.dll",EntryPoint="CreateCompatibleBitmap")]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,
        int nWidth, int nHeight);

    [DllImport ("gdi32.dll",EntryPoint="CreateCompatibleDC")]
    public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

    [DllImport ("gdi32.dll",EntryPoint="SelectObject")]
    public static extern IntPtr SelectObject(IntPtr hdc,IntPtr bmp);
#endregion

#region Public Constructor
}

/// <summary>
/// This class shall keep the User32 APIs used in our program.
/// </summary>
public class PlatformInvokeUSER32
{
#region Class Variables
    public const int SM_CXSCREEN=0;
    public const int SM_CYSCREEN=1;
#endregion 

#region Class Functions
    [DllImport("user32.dll", EntryPoint="GetDesktopWindow")]
    public static extern IntPtr GetDesktopWindow();

    [DllImport("user32.dll",EntryPoint="GetDC")]
    public static extern IntPtr GetDC(IntPtr ptr);

    [DllImport("user32.dll",EntryPoint="GetSystemMetrics")]
    public static extern int GetSystemMetrics(int abc);

    [DllImport("user32.dll",EntryPoint="GetWindowDC")]
    public static extern IntPtr GetWindowDC(Int32 ptr);

    [DllImport("user32.dll",EntryPoint="ReleaseDC")]
    public static extern IntPtr ReleaseDC(IntPtr hWnd,IntPtr hDc);

#endregion
}

/// <summary>
/// This class shall keep all the functionality 
/// for capturing the desktop.
/// </summary>
public class CaptureScreen
{
#region Class Variable Declaration
    protected static IntPtr m_HBitmap;
#endregion

///
/// This class shall keep all the functionality for capturing
/// the desktop.
///
public class CaptureScreen
{
  #region Public Class Functions
  public static Bitmap GetDesktopImage()
  {
    //In size variable we shall keep the size of the screen.
    SIZE size;

    //Variable to keep the handle to bitmap.
    IntPtr hBitmap;

    //Here we get the handle to the desktop device context.
    IntPtr  hDC = PlatformInvokeUSER32.GetDC
                  (PlatformInvokeUSER32.GetDesktopWindow());

    //Here we make a compatible device context in memory for screen
    //device context.
    IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);

    //We pass SM_CXSCREEN constant to GetSystemMetrics to get the
    //X coordinates of the screen.
    size.cx = PlatformInvokeUSER32.GetSystemMetrics
              (PlatformInvokeUSER32.SM_CXSCREEN);

    //We pass SM_CYSCREEN constant to GetSystemMetrics to get the
    //Y coordinates of the screen.
    size.cy = PlatformInvokeUSER32.GetSystemMetrics
              (PlatformInvokeUSER32.SM_CYSCREEN);

    //We create a compatible bitmap of the screen size and using
    //the screen device context.
    hBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap
                (hDC, size.cx, size.cy);

    //As hBitmap is IntPtr, we cannot check it against null.
    //For this purpose, IntPtr.Zero is used.
    if (hBitmap!=IntPtr.Zero)
    {
      //Here we select the compatible bitmap in the memeory device
      //context and keep the refrence to the old bitmap.
      IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject
                             (hMemDC, hBitmap);
      //We copy the Bitmap to the memory device context.
      PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC,
                                 0, 0,PlatformInvokeGDI32.SRCCOPY);
      //We select the old bitmap back to the memory device context.
      PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
      //We delete the memory device context.
      PlatformInvokeGDI32.DeleteDC(hMemDC);
      //We release the screen device context.
      PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.
                                     GetDesktopWindow(), hDC);
      //Image is created by Image bitmap handle and stored in
      //local variable.
      Bitmap bmp = System.Drawing.Image.FromHbitmap(hBitmap); 
      //Release the memory to avoid memory leaks.
      PlatformInvokeGDI32.DeleteObject(hBitmap);
      //This statement runs the garbage collector manually.
      GC.Collect();
      //Return the bitmap 
      return bmp;
    }
    //If hBitmap is null, retun null.
    return null;
  }
  #endregion
}

//This structure shall be used to keep the size of the screen.
public struct SIZE
{
    public int cx;
    public int cy;
}

结论

包含此代码的演示应用程序展示了这些类的用法。它是一个非常简单的 Windows 应用程序,其中包含一个简单的表单,该表单具有一个菜单和一个PictureBox控件。菜单的“Capture Screen”菜单项用于截取屏幕并将其分配给PictureBox控件的图像属性。我希望您喜欢这段代码。我已经对这段代码的每一行都进行了注释,使其易于理解。如果仍然有任何不清楚的地方,请告诉我。祝你好运!

© . All rights reserved.