Как найти положение/расположение окна с учетом 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;
}
}