17

私は現在、WatiN を使用していますが、これが優れた Web ブラウジング自動化ツールであることがわかりました。ただし、前回のリリースの時点では、スクリーン キャプチャ機能が不足しているようです。Charles Petzold によるいくつかのコードに加えて、画面からスクリーンショットをキャプチャするための実行可能なソリューション (この StackOverflow questionに似たコードを個別に生成する) を思いつきました。残念ながら、欠落しているコンポーネントがあります:実際のウィンドウはどこにありますか?

WatiN は便利にブラウザーを提供するhWndので、(この簡略化された例で) 画面から画像をコピーするように設定できます。次のようにします。

// browser is either an WatiN.Core.IE or a WatiN.Core.FireFox...
IntPtr hWnd = browser.hWnd;
string filename = "my_file.bmp";
using (Graphics browser = Graphics.FromHwnd(browser.hWnd) )
using (Bitmap screenshot = new Bitmap((int)browser.VisibleClipBounds.Width,
                                      (int)browser.VisibleClipBounds.Height,
                                      browser))
using (Graphics screenGraphics = Graphics.FromImage(screenshot))
{
    int hWndX = 0; // Upper left of graphics?  Nope, 
    int hWndY = 0; // this is upper left of the entire desktop!

    screenGraphics.CopyFromScreen(hWndX, hWndY, 0, 0, 
                          new Size((int)browser.VisibileClipBounds.Width,
                                   (int)browser.VisibileClipBounds.Height));
    screenshot.Save(filename, ImageFormat.Bmp);
}

成功!スクリーンショットを取得しますが、問題があります。コピー元のウィンドウの場所ではなくhWndXhWndY常に画面の左上隅をポイントします。

次に を調べましたがControl.FromHandle、これは作成したフォームでのみ機能するようです。このメソッドに を渡すと、このメソッドは null ポインターを返しますhWnd

次に、さらに読んで、検索条件を変更することにしました...ほとんどの人がウィンドウの「位置」を本当に必要としているときに、「ウィンドウの場所」を検索していました。これは、これについて話している別のSOの質問につながりましたが、彼らの答えはネイティブメソッドを使用することでした.

では、ウィンドウの位置を見つけるためのネイティブ C# の方法はありますか?

4

3 に答える 3

37

プロジェクトでこれを実行したところ、マネージ C# の方法が見つかりませんでした。

Reed の回答に追加するには、P/Invoke コードは次のとおりです。

 [DllImport("user32.dll", SetLastError = true)]
 [return: MarshalAs(UnmanagedType.Bool)]
 static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
 [StructLayout(LayoutKind.Sequential)]
 private struct RECT
 {
     public int Left;
     public int Top;
     public int Right;
     public int Bottom;
  }

次のように呼び出します。

  RECT rct = new RECT();
  GetWindowRect(hWnd, ref rct);
于 2009-09-16T18:03:46.583 に答える
6

いいえ - フォームを作成していない場合は、 P/Invoke GetWindowRectする必要があります。管理された同等物があるとは思いません。

于 2009-09-16T17:54:07.440 に答える
4

答えは、他の人が述べているように、おそらく「いいえ、ネイティブメソッドなしでは hwnd からランダムウィンドウのスクリーンショットを撮ることはできません.」です。表示する前にいくつかの注意事項があります。

予告:

このコードを使用する場合は、VisibleClipBounds から指定されたサイズはウィンドウのみであり、境界線やタイトル バーは含まれないことに注意してください。描画領域です。それがあれば、p/invoke なしでこれを実行できるかもしれません。

(ブラウザ ウィンドウの境界線を計算できる場合は、VisibleClipBounds を使用できます。必要に応じて、SystemInformationオブジェクトを使用して のような重要な情報を取得Border3DSizeしたり、ダミー フォームを作成して境界線とタイトルバーの高さはそれからですが、それはすべて、バグが作られている黒魔術のように聞こえます.)

これは、ウィンドウの Ctrl+Printscreen に相当します。これは、ブラウザーをスクロールしてページ全体の画像を取得するなど、WatiN スクリーンショット機能が行う細かな機能も行いません。これは私のプロジェクトには適していますが、あなたのプロジェクトには適していない可能性があります。

機能強化:

.NET 3 およびアップランドを使用している場合は、これを拡張メソッドに変更できます。また、イメージ タイプのオプションを簡単に追加できます (ImageFormat.Bmpこの例では、デフォルトで を使用しています)。

コード:

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public class Screenshot
{
    class NativeMethods
    {
        // http://msdn.microsoft.com/en-us/library/ms633519(VS.85).aspx
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        // http://msdn.microsoft.com/en-us/library/a5ch4fda(VS.80).aspx
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
    }
    /// <summary>
    /// Takes a screenshot of the browser.
    /// </summary>
    /// <param name="b">The browser object.</param>
    /// <param name="filename">The path to store the file.</param>
    /// <returns></returns>
    public static bool SaveScreenshot(Browser b, string filename)
    {
        bool success = false;
        IntPtr hWnd = b.hWnd;
        NativeMethods.RECT rect = new NativeMethods.RECT();
        if (NativeMethods.GetWindowRect(hWnd, ref rect))
        {
            Size size = new Size(rect.Right - rect.Left,
                                 rect.Bottom - rect.Top);
            // Get information about the screen
            using (Graphics browserGraphics = Graphics.FromHwnd(hWnd))
            // apply that info to a bitmap...
            using (Bitmap screenshot = new Bitmap(size.Width, size.Height, 
                                                  browserGraphics))
            // and create an Graphics to manipulate that bitmap.
            using (Graphics imageGraphics = Graphics.FromImage(screenshot))
            {
                int hWndX = rect.Left;
                int hWndY = rect.Top;
                imageGraphics.CopyFromScreen(hWndX, hWndY, 0, 0, size);
                screenshot.Save(filename, ImageFormat.Bmp);
                success = true;
            }
        }
        // otherwise, fails.
        return success;
    }   
}
于 2009-09-22T17:05:27.107 に答える