如何在没有NativeMethods的情况下找到hWnd窗口的位置/位置?

Rob*_*t P 14 .net c# winapi watin screenshot

我目前正在与WatiN合作,并发现它是一个伟大的网页浏览自动化工具.但是,截至上一版本,它的屏幕捕获功能似乎缺乏.除了Charles Petzold的一些代码之外,我还提出了一个可行的解决方案,用于从屏幕捕获屏幕截图(独立生成类似于此StackOverflow问题的代码).不幸的是,缺少一个组件:实际窗口在哪里

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);
}
Run Code Online (Sandbox Code Playgroud)

成功!我们得到截图,但是存在这个问题:hWndX并且hWndY总是指向屏幕的左上角,而不是我们要复制的窗口的位置.

然后我调查了一下Control.FromHandle,但这似乎只适用于您创建的表单; 如果传入此方法,则此方法返回空指针hWnd.

然后,进一步阅读引导我切换我的搜索条件......当大多数人真正想要窗口的"位置"时,我一直在寻找"窗口的位置".这导致另一个SO问题,谈论这个,但他们的答案是使用本机方法.

那么,是否存在一种寻找窗口位置的原生C#方式,只有hWnd(最好只有.NET 2.0时代的库)?

Mar*_*ark 34

我刚刚在一个项目中完成了这个,并且无法找到任何托管的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;
  }
Run Code Online (Sandbox Code Playgroud)

称之为:

  RECT rct = new RECT();
  GetWindowRect(hWnd, ref rct);
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 6

否 - 如果您没有创建表单,则必须使用P/Invoke GetWindowRect.我不相信有管理的等价物.


Rob*_*t P 5

答案正如其他人所说,可能是“不,如果没有本机方法,您无法从 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;
    }   
}
Run Code Online (Sandbox Code Playgroud)