我目前正在与WatiN合作,并发现它是一款出色的网页浏览自动化工具。但是,截至上一版本,它的屏幕捕获功能似乎缺乏。除了一些this StackOverflow question之外,我还提出了一个可行的解决方案,用于从屏幕捕获屏幕截图(独立生成类似于code by Charles Petzold的代码)。不幸的是,缺少一个组件:实际窗口在哪里?
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
传递给它,则此方法返回空指针。
然后,进一步阅读引导我切换我的搜索条件......当大多数人真正想要窗口的“位置”时,我一直在寻找“窗口的位置”。这导致another SO question谈到了这一点,但他们的答案是使用原生方法。
那么,是否有一种本地C#查找窗口位置的方式,只有hWnd(最好只有.NET 2.0时代库)?
答案 0 :(得分:33)
我刚刚在一个项目中完成了这个,但无法找到任何托管的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);
答案 1 :(得分:6)
否 - 如果您没有创建表单,则必须进行P / Invoke GetWindowRect。我不相信有管理的等价物。
答案 2 :(得分:4)
答案正如其他人所说的那样,可能是“不,你不能在没有本地方法的情况下从hwnd中截取随机窗口的截图。”在我展示之前几点警告:
<强>预警:强>
对于想要使用此代码的任何人,请注意,VisibleClipBounds提供的大小仅在内窗口中,并且不包含边框或标题栏。这是可绘制的区域。如果你有这个,你可以在没有p / invoke的情况下做到这一点。
(如果您可以计算浏览器窗口的边框,可以使用VisibleClipBounds。如果您愿意,可以使用SystemInformation
对象获取Border3DSize
等重要信息,或者您可以尝试通过创建一个虚拟形式和deriving the border and title bar height from that计算它,但所有听起来都像是由错误组成的黑魔法。)
这相当于窗口的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;
}
}