画面をキャプチャ(ハードコピー)し、イメージをBitmapオブジェクトとして取得する方法を幾つか紹介します。
.NET Framework 2.0から追加されたGraphics.CopyFromScreenメソッドを使用すれば、画面上の指定された範囲をキャプチャすることができます。
画面全体をキャプチャしてPictureBox1に表示する例を以下に示します。
'Imports System.Drawing 'Imports System.Windows.Forms 'Bitmapの作成 Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, _ Screen.PrimaryScreen.Bounds.Height) 'Graphicsの作成 Dim g As Graphics = Graphics.FromImage(bmp) '画面全体をコピーする g.CopyFromScreen(New Point(0, 0), New Point(0, 0), bmp.Size) '解放 g.Dispose() '表示 PictureBox1.Image = bmp
//using System.Drawing; //using System.Windows.Forms; //Bitmapの作成 Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); //Graphicsの作成 Graphics g = Graphics.FromImage(bmp); //画面全体をコピーする g.CopyFromScreen(new Point(0, 0), new Point(0, 0), bmp.Size); //解放 g.Dispose(); //表示 PictureBox1.Image = bmp;
注意:.NET Framework 3.5以下のCopyFromScreenメソッドには、ハンドルリークのバグがあります(「System.ArgumentException: Parameter is not valid. at System.Drawing.Graphics.GetHdc()」によると、.NET Framework 2.0 SP1と3.5にバグがあるということです)。詳しくは、「Need help confirming possible bug in Graphics.CopyFromScreen regarding leakage of Gdi object handle」をご覧ください。
CopyFromScreenメソッドにはもう1つバグがあります。それは、CopyFromScreenメソッドの最後に指定できるCopyPixelOperation構造体のパラメータに、CopyPixelOperation値の1つしか指定できない点です。例えばここに「CopyPixelOperation.SourceCopy Or CopyPixelOperation.CaptureBlt」を指定すると、例外InvalidEnumArgumentExceptionが発生します。そのため、Opacityプロパティで半透明にしたフォームや、TransparencyKeyプロパティで一部を透明にしたフォームを正しくキャプチャすることができません。下で紹介するWin32 APIの方法では、BitBltの最後のパラメータを「SRCCOPY Or CAPTUREBLT」(C#では「SRCCOPY | CAPTUREBLT」)とすることで、これらのフォームも正常にキャプチャできます。詳しくは、「copyFromScreen - no alpha window captured」をご覧ください。
Print ScreenキーストロークをSendKeys.SendWaitメソッド(またはSendKeys.Sendメソッド)で送信し、クリップボードにコピーされたイメージを取得する方法も考えられます。Ctrl+PrintScreenキーストローク("^{PRTSC}")で画面全体がキャプチャされ、Alt+PrintScreenキーストローク("%{PRTSC}")でアクティブなウィンドウがキャプチャされます(PrintScreenキーストロークのみでもアクティブなウィンドウがキャプチャされるようです)。
ただしこの方法では確実に画面のイメージを取得できる保障はありません。
補足:MSDNの「SendKeys.Send メソッド」には、「{PRTSC} (今後使用するために予約されている)」と書かれています。
SendKeysに関しては、「VB6のSendKeysと同じ事を行うには?」でも説明しています。また、クリップボードの画像を取得する方法は、「クリップボードの画像を表示する」で説明しています。
この方法により画面全体のイメージを取得し、PictureBox(PictureBox1)に表示するサンプルを以下に示します。
'Imports System.Drawing 'Imports System.Windows.Forms '画面全体のイメージをクリップボードにコピー SendKeys.SendWait("^{PRTSC}") '次のようにすると、アクティブなウィンドウのイメージをコピー 'SendKeys.SendWait("%{PRTSC}") 'SendKeys.SendWait("{PRTSC}") 'DoEventsを呼び出したほうがよい場合があるらしい 'Application.DoEvents() 'クリップボードにあるデータの取得 Dim d As IDataObject = Clipboard.GetDataObject() 'クリップボードにデータがあったか確認 If d IsNot Nothing Then 'ビットマップデータ形式に関連付けられているデータを取得 Dim img As Image = DirectCast(d.GetData(DataFormats.Bitmap), Image) If img IsNot Nothing Then 'データが取得できたときはPictureBoxに表示する PictureBox1.Image = img '画面のイメージデータは大きいため、 '用がなくなればクリップボードから削除した方がいいかもしれない Clipboard.SetDataObject(New DataObject()) End If End If
//using System.Drawing; //using System.Windows.Forms; //画面全体のイメージをクリップボードにコピー SendKeys.SendWait("^{PRTSC}"); //次のようにすると、アクティブなウィンドウのイメージをコピー //SendKeys.SendWait("%{PRTSC}"); //SendKeys.SendWait("{PRTSC}"); //DoEventsを呼び出したほうがよい場合があるらしい //Application.DoEvents(); //クリップボードにあるデータの取得 IDataObject d = Clipboard.GetDataObject(); //クリップボードにデータがあったか確認 if (d != null) { //ビットマップデータ形式に関連付けられているデータを取得 Image img = (Image)d.GetData(DataFormats.Bitmap); if (img != null) { //データが取得できたときはPictureBoxに表示する PictureBox1.Image = img; //画面のイメージデータは大きいため、 //用がなくなればクリップボードから削除した方がいいかもしれない Clipboard.SetDataObject(new DataObject()); } }
最後に、Win32 APIを使う方法を紹介します。この方法関しては、ウェブ上で優れたサンプルがいくつも公開されています。その一部を紹介します。
以下はC#のサンプルです。
以下はVB.NETのサンプルです。
以下に画面全体をキャプチャするメソッド(CaptureScreen)と、アクティブなウィンドウをキャプチャするメソッド(CaptureActiveWindow)のごく簡単なサンプルを紹介します。
'Imports System.Drawing 'Imports System.Windows.Forms 'Imports System.Runtime.InteropServices Const SRCCOPY As Integer = 13369376 Const CAPTUREBLT As Integer = 1073741824 <DllImport("user32.dll")> _ Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr End Function <DllImport("gdi32.dll")> _ Private Shared Function BitBlt(ByVal hDestDC As IntPtr, _ ByVal x As Integer, ByVal y As Integer, _ ByVal nWidth As Integer, ByVal nHeight As Integer, _ ByVal hSrcDC As IntPtr, _ ByVal xSrc As Integer, ByVal ySrc As Integer, _ ByVal dwRop As Integer) As Integer End Function <DllImport("user32.dll")> _ Private Shared Function ReleaseDC(ByVal hwnd As IntPtr, _ ByVal hdc As IntPtr) As IntPtr End Function ''' <summary> ''' プライマリスクリーンの画像を取得する ''' </summary> ''' <returns>プライマリスクリーンの画像</returns> Public Shared Function CaptureScreen() As Bitmap 'プライマリモニタのデバイスコンテキストを取得 Dim disDC As IntPtr = GetDC(IntPtr.Zero) 'Bitmapの作成 Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, _ Screen.PrimaryScreen.Bounds.Height) 'Graphicsの作成 Dim g As Graphics = Graphics.FromImage(bmp) 'Graphicsのデバイスコンテキストを取得 Dim hDC As IntPtr = g.GetHdc() 'Bitmapに画像をコピーする BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, disDC, 0, 0, SRCCOPY) '解放 g.ReleaseHdc(hDC) g.Dispose() ReleaseDC(IntPtr.Zero, disDC) Return bmp End Function <StructLayout(LayoutKind.Sequential)> _ Private Structure RECT Public left As Integer Public top As Integer Public right As Integer Public bottom As Integer End Structure <DllImport("user32.dll")> _ Private Shared Function GetWindowDC(ByVal hwnd As IntPtr) As IntPtr End Function <DllImport("user32.dll")> _ Private Shared Function GetForegroundWindow() As IntPtr End Function <DllImport("user32.dll")> _ Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, _ ByRef lpRect As RECT) As Integer End Function ''' <summary> ''' アクティブなウィンドウの画像を取得する ''' </summary> ''' <returns>アクティブなウィンドウの画像</returns> Public Shared Function CaptureActiveWindow() As Bitmap 'アクティブなウィンドウのデバイスコンテキストを取得 Dim hWnd As IntPtr = GetForegroundWindow() Dim winDC As IntPtr = GetWindowDC(hWnd) 'ウィンドウの大きさを取得 Dim winRect As New RECT GetWindowRect(hWnd, winRect) 'Bitmapの作成 Dim bmp As New Bitmap(winRect.right - winRect.left, _ winRect.bottom - winRect.top) 'Graphicsの作成 Dim g As Graphics = Graphics.FromImage(bmp) 'Graphicsのデバイスコンテキストを取得 Dim hDC As IntPtr = g.GetHdc() 'Bitmapに画像をコピーする BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, winDC, 0, 0, SRCCOPY) '解放 g.ReleaseHdc(hDC) g.Dispose() ReleaseDC(hWnd, winDC) Return bmp End Function
//using System.Drawing; //using System.Windows.Forms; //using System.Runtime.InteropServices; private const int SRCCOPY = 13369376; private const int CAPTUREBLT = 1073741824; [DllImport("user32.dll")] private static extern IntPtr GetDC(IntPtr hwnd); [DllImport("gdi32.dll")] private static extern int BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop); [DllImport("user32.dll")] private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc); /// <summary> /// プライマリスクリーンの画像を取得する /// </summary> /// <returns>プライマリスクリーンの画像</returns> public static Bitmap CaptureScreen() { //プライマリモニタのデバイスコンテキストを取得 IntPtr disDC = GetDC(IntPtr.Zero); //Bitmapの作成 Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); //Graphicsの作成 Graphics g = Graphics.FromImage(bmp); //Graphicsのデバイスコンテキストを取得 IntPtr hDC = g.GetHdc(); //Bitmapに画像をコピーする BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, disDC, 0, 0, SRCCOPY); //解放 g.ReleaseHdc(hDC); g.Dispose(); ReleaseDC(IntPtr.Zero, disDC); return bmp; } [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] private static extern IntPtr GetWindowDC(IntPtr hwnd); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern int GetWindowRect(IntPtr hwnd, ref RECT lpRect); /// <summary> /// アクティブなウィンドウの画像を取得する /// </summary> /// <returns>アクティブなウィンドウの画像</returns> public static Bitmap CaptureActiveWindow() { //アクティブなウィンドウのデバイスコンテキストを取得 IntPtr hWnd = GetForegroundWindow(); IntPtr winDC = GetWindowDC(hWnd); //ウィンドウの大きさを取得 RECT winRect = new RECT(); GetWindowRect(hWnd, ref winRect); //Bitmapの作成 Bitmap bmp = new Bitmap(winRect.right - winRect.left, winRect.bottom - winRect.top); //Graphicsの作成 Graphics g = Graphics.FromImage(bmp); //Graphicsのデバイスコンテキストを取得 IntPtr hDC = g.GetHdc(); //Bitmapに画像をコピーする BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, winDC, 0, 0, SRCCOPY); //解放 g.ReleaseHdc(hDC); g.Dispose(); ReleaseDC(hWnd, winDC); return bmp; }
(この記事は、「.NETプログラミング研究 第53号」で紹介したものを基にしています。)