Как найти положение/расположение окна с учетом hWnd без NativeMethods?

В настоящее время я работаю с WatiN и считаю, что это отличный инструмент для автоматического просмотра веб-страниц. Однако, как и в последнем выпуске, функции захвата экрана, похоже, отсутствуют. Я придумал подходящее решение для захвата скриншотов с экрана (независимо от генерации кода, подобного qaru.site/info/390030/...) в дополнение к некоторым код Чарльза Петцольда. К сожалению, отсутствует недостающий компонент: Где находится фактическое окно?

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);
}

Успех! Мы получаем скриншоты, но есть проблема: hWndX и hWndY всегда указывают на верхний левый угол экрана, а не на местоположение окна, из которого мы хотим скопировать.

Затем я просмотрел Control.FromHandle, но, похоже, это работает только с созданными вами формами; этот метод возвращает нулевой указатель, если вы передаете hWnd в него.

Затем, дальнейшее чтение приведет меня к переключению критериев поиска... Я искал "местоположение окна", когда большинство людей действительно хотят "положение" окна. Это привело к другому вопросу SO, в котором говорилось об этом, но их ответ заключался в использовании собственных методов.

Итак, Есть ли собственный С# способ нахождения положения окна, только с учетом hWnd (желательно только с библиотеками эпох .NET 2.0)?

Ответы

Ответ 1

Я просто просмотрел это в проекте и не смог найти какой-либо управляемый способ С#.

Чтобы добавить к 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);

Ответ 2

Нет - если вы не создали форму, вы должны P/Invoke GetWindowRect. Я не верю, что есть управляемый эквивалент.

Ответ 3

Ответ, как утверждают другие, вероятно, "Нет, вы не можете сделать снимок экрана из случайного окна из 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;
    }   
}