天天看點

技術文章翻譯(五) -- 利用.NET顯示目前螢幕内容

本人聲明

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控件的屬性。

技術文章翻譯(五) -- 利用.NET顯示目前螢幕内容

圖1 窗體設計

這個窗體中包含一個占滿整個窗體顯示區域的PictureBox控件和一個定時器控件。

技術文章翻譯(五) -- 利用.NET顯示目前螢幕内容

圖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的間隔來循環運作,是以如果您的運作結果看起來讓人有點迷惑,請不要驚慌。

技術文章翻譯(五) -- 利用.NET顯示目前螢幕内容

圖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程式

繼續閱讀