C#(WPF)中使用WinAPI函数进行截屏

在C#中,没有关于截屏的相关函数,这就需要使用Win32 API函数在C#代码中完成截屏。

一、基础知识介绍:

gdi32.dll:
系统文件gdi32.dll是存放在Windows系统文件夹中的重要文件,通常情况下是在安装操作系统过程中自动创建的,对于系统正常运行来说至关重要。除非用户电脑被木马病毒、或是流氓软件篡改导致出现gdi32.dll丢失、缺失损坏等弹窗现象,否则不建议用户对该类文件(gdi32.dll)进行随意的修改。
gdi32.dll是,包含的函数用来绘制图像和显示文字。

DeleteDC:该函数删除指定的设备上下文环境
Bool DeleteDC(HDC hdc);

DeleteObject:该函数删除一个逻辑笔、画笔、字体、位图、区域或者调色板,释放所有与该对象有关的系统资源,在对象被删除之后,指定的句柄也就失效了。
BOOL DeleteObject(HGDIOBJ hObject);

BitBlt:该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境
BOOL BitBlt(
HDC hdcDest, // 指向目标设备环境的句柄
int nXDest, // 指定目标矩形区域左上角的X轴逻辑坐标。
int nYDest, // 指定目标矩形区域左上角的Y轴逻辑坐标。
int nWidth, // 指定源在目标矩形区域的逻辑宽度。
int nHeight, // 指定源在目标矩形区域的逻辑高度
HDC hdcSrc, // 指向源设备环境的句柄。
int nXSrc, // 指定源矩形区域左上角的X轴逻辑坐标
int nYSrc, // 指定源矩形区域左上角的Y轴逻辑坐标。
DWORD dwRop // 指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
);

CreateCompatibleBitmap:该函数创建与指定的设备环境相关的设备兼容的位图。
HBITMAP CreateCompatibleBitmap(
HDC hdc, // 设备环境句柄
int nWidth, // 指定位图的宽度,单位为像素
int nHeight // 指定位图的高度,单位为像素
);

CreateCompatibleDC:该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。通过GetDc()获取的HDC直接与相关设备沟通,而本函数创建的DC,则是与内存中的一个表面相关联。
HDC CreateCompatibleDC(
HDC hdc // 现有设备上下文环境的句柄
);

SelectObject:计算机编程语言函数,该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
HGDIOBJ SelectObject(
HDC hdc, // 设备上下文环境的句柄。
HGDIOBJ hgdiobj // 被选择的对象的句柄,该指定对象必须由如下的函数创建
);


user32.dll:
user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。

GetDesktopWindow:该函数返回桌面窗口的句柄。桌面窗口覆盖整个屏幕。桌面窗口是一个要在其上绘制所有的图标和其他窗口的区域。
HWND GetDesktopWindow(VOID);

GetDC:该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
HDC GetDC(
HWND hWnd // handle to window
);

GetSystemMetrics:用于得到被定义的系统数据或者系统配置信息
int GetSystemMetrics(
int nIndex // system metric or configuration setting
);

GetWindowDC:返回hWnd参数所指定的窗口的设备环境。
HDC GetWindowDC(
HWND hWnd // handle to window
);

ReleaseDC:函数释放设备上下文环境(DC)供其他应用程序使用。函数的效果与设备上下文环境类型有关。它只释放公用的和设备上下文环境,对于类或私有的则无效。

int ReleaseDC(
HWND hWnd, // handle to window
HDC hDC // handle to DC
);


C#导入dll时类型对应关系:
C++中:
HWND:
h 是类型描述,表示句柄(handle), Wnd 是变量对象描述,表示窗口,所以hWnd 表示窗口句柄。通俗地说,如果把一个到处跑的人当作指针的话,那么HWND就是该人的身份证—-我想应该是身份证号码。
HDC:
HDC设备上下文是一种包含有关某个设备(如显示器或打印机)的绘制属性信息的 Windows 数据结构。所有绘制调用都通过设备上下文对象进行,这些对象封装了用于绘制线条、形状和文本的 Windows API。

HGDIOBJ:
指向一个GDI对象。
HBITMAP:
指向一个bitmap。

C#中:
IntPtr:
IntPtr 类型被设计成整数,其大小适用于特定平台。 即是说,此类型的实例在 32 位硬件和操作系统中将是 32 位,在 64 位硬件和操作系统上将是 64 位。
IntPtr 类型可以由支持指针的语言使用,并可作为在支持与不支持指针的语言间引用数据的一种通用方式。
IntPtr 对象也可用于保持句柄。 例如,IntPtr 的实例广泛地用在 System.IO.FileStream 类中来保持文件句柄。
IntPtr 类型符合 CLS,而 UIntPtr 类型却不符合。 只有 IntPtr 类型可用在公共语言运行时中。 UIntPtr 类型大多数是提供来维护与 IntPtr 类型之间的体系结构上的对称性。
因此,在导入dll时:
HWND类型对应IntPtr
HDC类型对应IntPtr
HGDIOBJ类型对应IntPtr
HBITMAP类型对应IntPtr

二、编码实现

创建工程:
1.创建一个WPF工程,在xmal中加入一个Image控件用于显示截屏的图片;添加一个Button,其Click事件中执行截屏函数;
2.添加一个类名为CaptureScreen.cs,用于编写截屏函数;
3.添加一个类名为PlatformInvokeGDI32.cs,用于存放导入gdi32.dll中的函数;
4.添加一个类名为PlatformInvokeUSER32.cs,用于存放导入user32.dll中的函数。

编写函数和类:
1.编写PlatformInvokeGDI32.cs类
DllImport需要引入命名空间:System.Runtime.InteropServices

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace WPF_CaptureScreen
{
    class PlatformInvokeGDI32
    {
        public const int SRCCOPY = 13369376;

        [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);
        public PlatformInvokeGDI32()
        {
            //
            // TODO: Add constructor logic here
            //
        }
    }
}

2.编写PlatformInvokeUSER32.cs类
DllImport需要引入命名空间:System.Runtime.InteropServices;
定义一个结构体SIZE用于保存截屏的尺寸;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace WPF_CaptureScreen
{ 
    class PlatformInvokeUSER32
    {
        public const int SM_CXSCREEN = 0;
        public const int SM_CYSCREEN = 1;
        [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);

    public PlatformInvokeUSER32()
    {
        //
        // TODO: Add constructor logic here
        //
    }
}
    //This structure shall be used to keep the size of the screen.
    public struct SIZE
    {
        public int cx;
        public int cy;
    }
}

3.编写CaptureScreen.cs类
为了使用Bitmap,需要添加引用System.Drawing,添加using System.Drawing空间
定义截屏函数:

public static Bitmap GetDesktopImage()
{
        //保存截屏的尺寸
        SIZE size;
        //指向bitmap的句柄
        IntPtr hBitmap;
        //通过GetDC函数获得指向桌面设备上下文的句柄
        IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());
        //在内存中创建一个兼容的设备上下文
        IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);
        //传递一个常数到GetSystemMetrics,并返回屏幕的x坐标
        size.cx = PlatformInvokeUSER32.GetSystemMetrics(0);
        //传递一个常数到GetSystemMetrics,并返回屏幕的y坐标
        size.cy = PlatformInvokeUSER32.GetSystemMetrics(1);
        //创建与指定的设备环境相关的设备兼容的位图。
        hBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);
        //As hBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
        if (hBitmap!=IntPtr.Zero)
        {
            //Here we select the compatible bitmap in memeory device context and keeps the refrence to 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 for compatible bitmap.
            PlatformInvokeGDI32.DeleteObject(hBitmap);
            //This statement runs the garbage collector manually.
            GC.Collect();
            //Return the bitmap
            return bmp;
    }
    //If hBitmap is null retunrn null.
return null;
}

4.编写MainWindow.xaml.cs

private void button1_Click(object sender, RoutedEventArgs e)
{
    Bitmap bitmap = CaptureScreen.GetDesktopImage();
    IntPtr ip = bitmap.GetHbitmap();//从GDI+ Bitmap创建GDI位图对象
    //Imaging.CreateBitmapSourceFromHBitmap方法,基于所提供的非托管位图和调色板信息的指针,返回一个托管的BitmapSource
    BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ip, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
    image1.Source = bitmapSource;
}

截图显示

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一苇渡江694

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值