本人声明
1.本栏仅为归档自己看到的优秀文章;
2.文章版权归原作者所有;
3.因为个人水平有限,翻译难免有错误,请多多包涵。
原文地址
https://www.codeguru.com/csharp/.net/net_general/displaying-the-computer-screen-using-.net.html
文章正文
利用.NET显示当前屏幕内容
作者: Hannes DuPreez 发表于:2018.07.5
概述
在论坛上,有一个问题经常被人提出,那就是如何在窗体的PictureBox控件上显示当前计算机屏幕上的内容。今天,我将向您做出解答。现在就让我们开始吧!
实例
打开Visual Studio程序,并创建一个C#或Visual Basic.NET 的Windows窗体应用程序。按照1所示,设计你的窗体;按照图2所示,设置窗体的Timer控件的属性。
图1 窗体设计
这个窗体中包含一个占满整个窗体显示区域的PictureBox控件和一个定时器控件。
图2 定时器属性
增加一个名为clsGDI的类。并将如下所示的命名空间添加到clsGDI类中。
- C#
using System;
using System.Runtime.InteropServices;
- VB.NET
Imports System
Imports System.Runtime.InteropServices
这些命名空间能够让您以适当的方式调用Windows API函数。接下来完成clsGDI类的编写。
- C#
public class clsGDI
{
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);
}
- VB.NET
Public Const SRCCOPY As Integer = 13369376
<DllImport("gdi32.dll", EntryPoint:="DeleteDC")>
Public Shared Function DeleteDC(ByVal hDc As IntPtr) _
As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="DeleteObject")>
Public Shared Function DeleteObject(ByVal hDc As IntPtr) _
As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="BitBlt")>
Public Shared Function BitBlt(ByVal hdcDest As IntPtr, _
ByVal xDest As Integer, ByVal yDest As Integer, ByVal wDest _
As Integer, ByVal hDest As Integer, ByVal hdcSource As _
IntPtr, ByVal xSrc As Integer, ByVal ySrc As Integer, ByVal _
RasterOp As Integer) As Boolean
End Function
Public Shared Function CreateCompatibleBitmap(ByVal hdc As _
IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) _
As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="CreateCompatibleDC")>
Public Shared Function CreateCompatibleDC(ByVal hdc As IntPtr) _
As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="SelectObject")>
Public Shared Function SelectObject(ByVal hdc As IntPtr, _
ByVal bmp As IntPtr) As IntPtr
End Function
DeleteDC函数用于删除指定的设备上下文。 DeleteObject函数可以删除画笔,画刷,字体,位图,区域或调色板对象;在执行此操作时,它释放与该对象关联的所有系统资源。 BitBlt函数对指定的源设备环境区域中的像素进行位块转换,以传送到目标设备环境。 CreateCompatibleBitmap函数创建与设备兼容的位图对象。 CreateCompatibleDC函数创建与指定设备兼容的内存设备上下文。
添加一个名为clsUSER的类,并为该类添加必要的命名空间来引入Windows API函数。
- C#*
using System;
using System.Runtime.InteropServices;
- VB.NET
Imports System
Imports System.Runtime.InteropServices
添加clsUSER类的其余代码。
- C#
public class clsUSER
{
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 struct SIZE
{
public int x;
public int y;
}
- VB.NET
Public Class clsUSER
Public Const SM_CXSCREEN As Integer = 0
Public Const SM_CYSCREEN As Integer = 1
<DllImport("user32.dll", EntryPoint:="GetDesktopWindow")>
Public Shared Function GetDesktopWindow() As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="GetDC")>
Public Shared Function GetDC(ByVal ptr As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="GetSystemMetrics")>
Public Shared Function GetSystemMetrics(ByVal abc As Integer) _
As Integer
End Function
<DllImport("user32.dll", EntryPoint:="GetWindowDC")>
Public Shared Function GetWindowDC(ByVal ptr As Int32) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="ReleaseDC")>
Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, _
ByVal hDc As IntPtr) As IntPtr
End Function
End Class
Public Structure SIZE
Public x As Integer
Public y As Integer
End Structure
GetDesktopWindow函数获取桌面窗口的句柄,该窗口覆盖整个屏幕范围,并且是绘制其他窗口的顶部区域。 GetDC函数获取特定窗口的客户区域或整个屏幕的设备上下文的句柄。 GetSystemMetrics函数获取指定的系统单位或系统配置参数。 GetWindowDC函数获取整个窗口的设备上下文,包括菜单、滚动条和标题栏。
SIZE是一个包含x和y坐标的公共结构体。
添加一个新类,并将其命名为clsCapScreen。将以下命名空间添加到类中,让其可以使用绘图命名空间内的绘图功能。
- C#
using System;
using System.Drawing;
- VB.NET
Imports System
Imports System.Drawing
将GetDesktopImage函数添加到clsCapScreen类中。 clsCapScreen类仅包含该功能。
- C#
public static Bitmap GetDesktopImage()
{
SIZE ScreenSize;
IntPtr bitScreenBMP;
IntPtr iDC = clsUSER.GetDC(clsUSER.GetDesktopWindow());
IntPtr iMemDC = clsGDI.CreateCompatibleDC(iDC);
ScreenSize.x = clsUSER.GetSystemMetrics
(clsUSER.SM_CXSCREEN);
ScreenSize.y = clsUSER.GetSystemMetrics
(clsUSER.SM_CYSCREEN);
bitScreenBMP = clsGDI.CreateCompatibleBitmap(iDC,
ScreenSize.x, ScreenSize.y);
if (bitScreenBMP != IntPtr.Zero)
{
IntPtr hPrev = (IntPtr)clsGDI.SelectObject(iMemDC,
bitScreenBMP);
clsGDI.BitBlt(iMemDC, 0, 0, ScreenSize.x, ScreenSize.y,
iDC, 0, 0, clsGDI.SRCCOPY);
clsGDI.SelectObject(iMemDC, hPrev);
clsGDI.DeleteDC(iMemDC);
clsUSER.ReleaseDC(clsUSER.GetDesktopWindow(), iDC);
Bitmap bmpRes = Image.FromHbitmap(bitScreenBMP);
clsGDI.DeleteObject(bitScreenBMP);
GC.Collect();
return bmpRes;
}
return null;
}
- VB.NET
Public Shared Function GetDesktopImage() As Bitmap
Dim ScreenSize As SIZE
Dim bitScreenBMP As IntPtr
Dim iDC As IntPtr = clsUSER.GetDC(clsUSER.GetDesktopWindow())
Dim iMemDC As IntPtr = clsGDI.CreateCompatibleDC(iDC)
ScreenSize.x = clsUSER.GetSystemMetrics(clsUSER.SM_CXSCREEN)
ScreenSize.y = clsUSER.GetSystemMetrics(clsUSER.SM_CYSCREEN)
bitScreenBMP = clsGDI.CreateCompatibleBitmap(iDC, _
ScreenSize.x, ScreenSize.y)
If bitScreenBMP <> IntPtr.Zero Then
Dim hPrev As IntPtr = CType(clsGDI.SelectObject(iMemDC, _
bitScreenBMP), IntPtr)
clsGDI.BitBlt(iMemDC, 0, 0, ScreenSize.x, ScreenSize.y, _
iDC, 0, 0, clsGDI.SRCCOPY)
clsGDI.SelectObject(iMemDC, hPrev)
clsGDI.DeleteDC(iMemDC)
clsUSER.ReleaseDC(clsUSER.GetDesktopWindow(), iDC)
Dim bmpRes As Bitmap = Image.FromHbitmap(bitScreenBMP)
clsGDI.DeleteObject(bitScreenBMP)
GC.Collect()
Return bmpRes
End If
Return Nothing
End Function
GetDesktopImage函数的优点是它包含了clsGDI和clsUSER类的API。它首先创建一个要绘制的设备上下文。 在clsUSER类中,调用GetSystemMetrics来计算屏幕的尺寸。如果屏幕分辨率不为零,则该函数使用clsGDIclass中的BitBlt来复制屏幕的内容。在成功复制后,内存中的图形对象将会被删除。
在您的窗体中,为Timer控件的Tick事件添加以下代码:
- C#
private void tmrTime_Tick(object sender, EventArgs e)
{
picScreen.Image = clsCapScreen.GetDesktopImage();
}
- VB.NET
Private Sub tmrTime_Tick(sender As Object, e As EventArgs) _
Handles tmrTime.Tick
picScreen.Image = clsCapScreen.GetDesktopImage()
End Sub
在运行时,您的程序结果将如图3所示。请记住:此代码将每秒运行一次,或者根据您设置Timer的间隔来循环运行,因此如果您的运行结果看起来让人有点迷惑,请不要惊慌。
图3:运行结果
结论
使用Windows API的Graphic功能非常简单,只要您确保你能处理好正在使用的内存资源即可。您需要经常清理未使用的内存。使用计时器来复制屏幕并不是必须的;这只是一个例子。现在您知道如何在PictureBox中显示当前屏幕的内容了。希望在以后的文章中,我也可以给你介绍鼠标及其事件。
关于作者
Hannes DuPreez
Hannes du Preez是2008年-2017年度的Visual Basic的MVP。他热爱技术并喜欢Visual Basic和C#语言。他喜欢撰写文章,并证明了Visual Basic比大多数人认为的更加强大。欢迎与其交流:ojdupreez1978@gmail.com。
相关文章
Microsoft Officially Announces the Release of Visual Studio 2013
In-app File Management Changes in Windows 8.1 and Visual Studio 2013
Microsoft Visual Studio 2013 to Deliver 1080p Display Support
栏目导航
上一篇:技术文章翻译(四) – 现代C++避免产生BUG的相关技术
下一篇:技术文章翻译(六) – 基于GTK+创建一个GUI程序