在c#中未能使用control.drawtobitmap之后,我的第二个选择是获取桌面的屏幕截图并裁剪出所需的部分。 一旦我切换用户帐户,我的打嗝就出现了,虽然程序没有崩溃,一旦用户切换,程序只生成纯黑色图像。
我使用此代码作为参考: WebBrowser.DrawToBitmap() or other methods?
我认为这在逻辑上是有道理的,因为这可以帮助Windows节省资源。
在我的情况下,我有哪些选择/解决方案?
修改1 对测试代码进行了修改:
int c = 0;
while (true)
{
try
{
c++;
Rectangle formBounds = this.Bounds;
Bitmap bmp = new Bitmap(formBounds.Width, formBounds.Height);
using (Graphics g = Graphics.FromImage(bmp))
g.CopyFromScreen(formBounds.Location, Point.Empty, formBounds.Size);
bmp.Save("picture" + c.ToString() + ".jpg");
Thread.Sleep(5000);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
这在用户帐户上完美运行,但是一旦切换用户,它就会返回异常:句柄无效。
有什么想法吗?
编辑2:
DrawToBitmap中的错误不是完全随机的...... 如果我使用你提供的代码:
Bitmap bmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
this.DrawToBitmap(bmp, this.ClientRectangle);
bmp.Save(".\\picture.jpg");
效果很好,例如:http://oi61.tinypic.com/1z23ynp.jpg
但是,当我右键单击Web浏览器控件时,DrawToBitmap将返回一个空白图像。
示例:http://oi60.tinypic.com/9ay0yc.jpg
所以我可以通过添加
轻松克服这个错误((Control)webbrowser1).Enabled = false;
这使得在网络浏览器上无法点击任何内容,但不幸的是,停用它会使我的项目无用,因为它的主要功能是模仿网页浏览器控件上的鼠标点击。 虽然如果隐藏窗口,这也可能是个问题。
目前正在查看这篇文章,其中提供了代码以提供窗口句柄。
Simulate click into a hidden window 看来它可能有一些价值......看看吧。
答案 0 :(得分:4)
您使用DrawToBitmap遇到了什么问题? 它在这里工作正常,(W8.1,VS2013)即使使用Webcontrol也可以在切换用户之后。 (但最后请看条件的编辑!)
Bitmap bmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
this.DrawToBitmap(bmp, this.ClientRectangle);
// Clipboard.SetImage(bmp); for testing only
bmp.Dispose();
以下是获取窗口截图的代码:
Rectangle formBounds = this.Bounds;
Bitmap bmp = new Bitmap(formBounds.Width, formBounds.Height );
using (Graphics g = Graphics.FromImage(bmp))
g.CopyFromScreen(formBounds.Location, Point.Empty, formBounds.Size);
//Clipboard.SetImage(bmp); for testing only
bmp.Dispose();
我可以像我想的那样切换用户,程序继续工作。
顺便说一下,你发布的链接真的很旧,很多东西可能都有所改进。修改强>
随着更新的问题,事情会更加清晰。
因此,即使用户已更改,您也希望不断获取程序的屏幕截图,对吧? 并且你想显示一个WebControl,对吧?
用户可以有三种类型的桌面:登录/注销屏幕,屏幕保护程序屏幕和一个或多个普通桌面屏幕。但是当用户注销时,他根本没有桌面屏幕。
因此,如果用户没有活动桌面,则屏幕截图方法将不起作用,g.CopyFromScreen
也不会导致GDI错误,也不会像在网络上的各种解决方案中那样使用窗口句柄,包括你的链接导致。所有这些最多只会显示一个空白或黑屏。
所以DrawToBitmap方法是唯一有效的方法。
您写道它有随机错误。那不是我所看到的。
当用户以任意方式与WebBrowser
进行交互时,问题会出现可预测。这包括滚动或点击带或不带导航。在这些互动之后,WebBrowser
会将自己绘制为一个空框,直到重新加载其网址 - 不仅刷新 - 而且真正由webBrowser1.Uri = new Uri(uriPath)
重新加载。可以这样做,请参阅我的other post
执行WebBrowser
时DrawToBitmap
还有另一个问题:对于包含<input type="text"
元素的任何网页,它都会失败(使用所述空框)。我不确定解决此问题的最佳方法是什么,更不用说为什么它首先发生了..截图方法没有特定的问题。
编辑2:
OP挖出代码的代码,通过调用PrintWindow
,似乎解决了我们遇到的所有问题:它在注销时有效,即使点击{{1}后也可以使用Refeshing并擦除所有页面,包括那些带有文本输入字段的页面。 Hoorah!
在减少松弛之后,这个版本可以创建WebBrowser
或仅Form
(或任何其他WebBroser
)的副本,包含或不包含边框:
Control
答案 1 :(得分:2)
最后,即使我切换了用户,这段代码似乎也能正常工作。
获取任何未保存的记事本进程的屏幕截图的代码(“无标题 - 记事本”)
private void Form1_Load(object sender, EventArgs e)
{
//loop for debugging
int c = 0;
while(true)
{
c++;
System.Drawing.Bitmap image = CaptureWindow(FindWindow(null, "Untitled - Notepad"));
image.Save(".\\picture"+c.ToString()+".jpg");
Thread.Sleep(5000);
}
}
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public System.Drawing.Bitmap CaptureWindow(IntPtr hWnd)
{
System.Drawing.Rectangle rctForm = System.Drawing.Rectangle.Empty;
using (System.Drawing.Graphics grfx = System.Drawing.Graphics.FromHdc(GetWindowDC(hWnd)))
{
rctForm = System.Drawing.Rectangle.Round(grfx.VisibleClipBounds);
}
System.Drawing.Bitmap pImage = new System.Drawing.Bitmap(rctForm.Width, rctForm.Height);
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(pImage);
IntPtr hDC = graphics.GetHdc();
try
{
PrintWindow(hWnd, hDC, (uint)0);
}
finally
{
graphics.ReleaseHdc(hDC);
}
return pImage;
}
请注意,该窗口可能已隐藏,但仍必须在用户帐户中最大化才能获得完整的屏幕截图。
答案 2 :(得分:1)
数字版权管理可能会阻止这种情况,因为Windows会增加对数字媒体的保护。
例如,如果您尝试使用Microsoft的图形渲染在Media Player或Media Center中创建某些内容的屏幕截图 - 是的,Microsoft将“保护您免受任何潜在的诉讼。”
试一试:点击键盘上的“Print Screen”,然后进入Microsoft Paint并尝试将屏幕截图粘贴到其中。有什么吗?
答案 3 :(得分:0)
我遇到了同样的问题,我无法使用CopyFromScreen方法,因为带有WebBrowser的表单可能会被隐藏。 PrintWindow方法也无法很好地生成带有黑色区域的图像,尤其是当我的MDI表单被MDI父表单部分覆盖时。
最后,我在SO上的this topic中使用了OleDraw方法,但将其集成到了从WebBrowser派生的类中。基本上,它只是覆盖对WM_PRINT消息的标准控制响应。这样,不仅可以对WebBrowser进行正常的Control.DrawToBitmap映射,还可以对其中包含WebBrowser的表单进行正常的Control.DrawToBitmap映射。如果该表单是隐藏的(也被其他表单(包括MDI父表单)覆盖),它也可以使用,并且在用户锁定与Win + L的会话(我尚未对其进行测试)时也可以使用。
public class WebBrowserEx : WebBrowser
{
private const uint DVASPECT_CONTENT = 1;
[DllImport("ole32.dll", PreserveSig = false)]
private static extern void OleDraw([MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwAspect,
IntPtr hdcDraw,
[In] ref System.Drawing.Rectangle lprcBounds
);
protected override void WndProc(ref Message m)
{
const int WM_PRINT = 0x0317;
switch (m.Msg)
{
case WM_PRINT:
Rectangle browserRect = new Rectangle(0, 0, this.Width, this.Height);
// Don't know why, but drawing with OleDraw directly on HDC from m.WParam.
// results in badly scaled (stretched) image of the browser.
// So, drawing to an intermediate bitmap first.
using (Bitmap browserBitmap = new Bitmap(browserRect.Width, browserRect.Height))
{
using (var graphics = Graphics.FromImage(browserBitmap))
{
var hdc = graphics.GetHdc();
OleDraw(this.ActiveXInstance, DVASPECT_CONTENT, hdc, ref browserRect);
graphics.ReleaseHdc(hdc);
}
using (var graphics = Graphics.FromHdc(m.WParam))
{
graphics.DrawImage(browserBitmap, Point.Empty);
}
}
// ignore default WndProc
return;
}
base.WndProc(ref m);
}
}