本人聲明
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 = ;
[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 =
<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 = ;
public const int SM_CYSCREEN = ;
[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 =
Public Const SM_CYSCREEN As Integer =
<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, , , ScreenSize.x, ScreenSize.y,
iDC, , , 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, , , ScreenSize.x, ScreenSize.y, _
iDC, , , 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比大多數人認為的更加強大。歡迎與其交流:[email protected]。
相關文章
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程式