C#のwinformsでアクティブウィンドウをキャプチャ

コンピュータ
ブログ記事にウィンドウをキャプチャした画像を張り付けることが多いので、Windows11で標準でインストールされている「Snipping Tool」を使ってキャプチャをしています。お気に入りのツールなのですが、ブログ記事にキャプチャ画像をアップロードする場合一度ファイルに保存に必要があります。できればキャプチャ画像をブラウザへ直接ドラッグアンドドロップでアップロードできると便利そうなのでC#で作成できないかと調べてみました。
以下のサイト様でズバリの記事が見つかりました。
C#での画面キャプチャの取得方法を徹底解説! | .NETコラム
C#で画面キャプチャの取得方法をご存知でしょうか。ここでは、スクリーン全体、アクティブウィンドウ、矩形領域などのキャプチャ方法について紹介します。C#での画面キャプチャについて整理しましたので、興味のある方はぜひご覧ください。

アクティブウィンドウをキャプチャするコードをありがたく使わせてもらいます。
ただ、実際動かしてみるとキャプチャボタンを押すとアクティブウィンドウがC#で作成したフォーム自身になってしまうので、任意のウィンドウをキャプチャすることは出来ませんでした。

そうなると、現在実行中のプロセスの一覧から目的のウィンドウを選びフォーカスを移動するルーチンを組むのが良いかと思いましたが、UIを含めて作るのが面倒です。ということでキャプチャ用のボタンを押してから3秒ほど非同期にTask.Delay()することで、その間にキャプチャしたいウィンドウを選択するようにしてみました。

using System.Runtime.InteropServices;

namespace WindowCapture;

public partial class Form1 : Form
{
    [StructLayout(LayoutKind.Sequential)]
    struct Rect
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
    [DllImport("user32.dll")]
    static extern int GetWindowRect(IntPtr hWnd, out Rect rect);
    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

    readonly int _sec = 3;
    FlowLayoutPanel _basePanel = new()
    {
        Dock = DockStyle.Fill,
    };
    PictureBox _picbox = new()
    {
        SizeMode = PictureBoxSizeMode.Zoom,
        Size = new Size(720, 360),
    };
    Button _captureButton = new()
    {
        AutoSize = true,
    };

    public Form1()
    {
        InitializeComponent();
        
        _captureButton.Text = $"{_sec}秒後キャプチャ";

        this.Load += Form1_Load;
    }
    void Form1_Load(Object? s, EventArgs e)
    {
        _basePanel.Controls.AddRange(new Control[]
        {
            _picbox,
            _captureButton,
        });
        _basePanel.SetFlowBreak(_picbox, true);
        this.Controls.Add(_basePanel);

        _captureButton.Click += async (s, e) =>
        {
            
            await Task.Delay(_sec * 1000);

            Rect rect;
            IntPtr window = GetForegroundWindow();
            GetWindowRect(window, out rect);
            var rectangle = new Rectangle(rect.left, rect.top, (rect.right - rect.left), (rect.bottom-rect.top));
            var bitmap = new Bitmap(rectangle.Width, rectangle.Height);
            using var graphics = Graphics.FromImage(bitmap);

            graphics.CopyFromScreen(new Point(rectangle.X, rectangle.Y), new Point(0, 0), rectangle.Size);

            _picbox.Image?.Dispose();
            _picbox.Image = bitmap;
        };
        _picbox.MouseDown += (s, e) =>
        {
            if (_picbox.Image == null) return;

            var bitmap = (Bitmap)_picbox.Image;
            var path = Path.GetTempFileName() + ".png";
            bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);

            var effect = DragDropEffects.Copy | DragDropEffects.Move;
            string[] files = {path};
            var data = new DataObject(DataFormats.FileDrop, files);
            var result = _picbox.DoDragDrop(data, effect);
        };
    }
}

コメント