C# 在没有 NativeMethods 的情况下,如何在给定 hWnd 的情况下找到窗口的位置/位置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1434524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 16:29:37  来源:igfitidea点击:

How do I find the position / location of a window given a hWnd without NativeMethods?

c#.netwinapiwatinscreenshot

提问by Robert P

I'm currently working with WatiN, and finding it to be a great web browsing automation tool. However, as of the last release, it's screen capturing functionality seems to be lacking. I've come up with a workable solution for capturing screenshots from the screen (independently generating code similar to this StackOverflow question) in addition to some code by Charles Petzold. Unfortunately, there is a missing component: Where is the actual window?

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

WatiN conveniently provides the browser's hWndto you, so we can (with this simplified example) get set to copy an image from the screen, like so:

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

Success! We get screenshots, but there's that problem: hWndXand hWndYalways point to the upper left most corner of the screen, not the location of the window we want to copy from.

成功!我们得到了屏幕截图,但存在一个问题:hWndX并且hWndY始终指向屏幕的最左上角,而不是我们要从中复制的窗口的位置。

I then looked into Control.FromHandle, however this seems to only work with forms you created; this method returns a null pointer if you pass the hWndinto it.

然后我查看了Control.FromHandle,但是这似乎只适用于您创建的表单;如果您将 传递给该方法,则该方法将返回一个空指针hWnd

Then, further reading lead me to switch my search criteria...I had been searching for 'location of window' when most people really want the 'position' of the window. This lead to another SO questionthat talked about this, but their answer was to use native methods.

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

So, Is there a native C# way of finding the position of a window, only given the hWnd (preferably with only .NET 2.0 era libraries)?

那么,是否有一种本机 C# 方式来查找窗口的位置,仅给定 hWnd(最好仅使用 .NET 2.0 时代的库)?

采纳答案by Mark

I just went through this on a project and was unable to find any managed C# way.

我刚刚在一个项目中经历了这个并且无法找到任何托管的 C# 方式。

To add to Reed's answer the P/Invoke code is:

要添加到 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;
  }

Call it as:

称之为:

  RECT rct = new RECT();
  GetWindowRect(hWnd, ref rct);

回答by Reed Copsey

No - if you didn't create the form, you have to P/Invoke GetWindowRect. I don't believe there is a managed equivalent.

否 - 如果您没有创建表单,则必须 P/Invoke GetWindowRect。我不相信有一个托管的等价物。

回答by Robert P

The answer is as others have stated, probably "No, you cannot take a screenshot of a random window from an hwnd without native methods.". Couple of caveats before I show it:

答案就像其他人所说的那样,可能“不,如果没有本机方法,您无法从 hwnd 中截取随机窗口的屏幕截图。”。在我展示之前,有几个警告:

Forewarning:

预警:

For anyone who wants to use this code, note that the size given from the VisibleClipBounds is only insidethe window, and does notinclude the border or title bar. It's the drawable area. If you had that, you might be able to do this without p/invoke.

对于任何想要使用此代码的人,请注意 VisibleClipBounds 给出的大小仅窗口内,包括边框或标题栏。这是可绘制区域。如果你有那个,你也许可以在没有 p/invoke 的情况下做到这一点。

(If you could calculate the border of the browser window, you could use the VisibleClipBounds. If you wanted, you could use the SystemInformationobject to get important info like Border3DSize, or you could try to calculate it by creating a dummy form and deriving the border and title bar height from that, but that all sounds like the black magic that bugs are made of.)

(如果您可以计算浏览器窗口的边框,您可以使用 VisibleClipBounds。如果您愿意,您可以使用该SystemInformation对象来获取重要信息,例如Border3DSize,或者您可以尝试通过创建一个虚拟表单并派生边框和标题栏的高度从那开始,但这一切听起来都像是制造错误的黑魔法。)

This is equivalent to Ctrl+Printscreen of the window. This also does not do the niceties that the WatiN screenshot capability does, such as scroll the browser and take an image of the whole page. This is suitable for my project, but may not be for yours.

这相当于窗口的 Ctrl+Printscreen。这也没有实现 WatiN 屏幕截图功能的优点,例如滚动浏览器并拍摄整个页面的图像。这适合我的项目,但可能不适合你的。

Enhancements:

增强功能:

This could be changed to be an extension method if you're in .NET 3 and up-land, and an option for the image type could be added pretty easily (I default to ImageFormat.Bmpfor this example).

如果您在 .NET 3 和高地,这可以更改为扩展方法,并且可以很容易地添加图像类型的选项(我默认ImageFormat.Bmp为这个示例)。

Code:

代码:

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