编辑:最初的问题是一个很长的问题,有很多疯狂的猜测。我已经把它减少到剩下的奥秘了。

我整天都在挣扎和困惑,我想应该向社区提出我的问题。

它源自名为Screenshot method generates black images的帖子。原始发布者希望每n秒连续拍摄其程序的屏幕截图,其中包括WebBrowser,即使用户注销也是如此。

当用户注销时,他不再有屏幕。因此,任何尝试读取屏幕的操作都会失败。如果使用窗口句柄,则结果为黑框,而在使用CopyFromScreen时,将出现GDI错误。

但是程序窗口仍然存在,并且即使用户注销,使用DrawToBitmap也可以正常工作。

这里是条件和其余问题:


用户不得以任何方式触摸/单击WebBrowser。如果他这样做,例如滚动,单击,导航子DrawToBitmap调用,则会产生一个空框。
WebBrowser保持不变的情况下,在下一个DrawToBitmap调用之前执行Refresh就足够了。
触摸后,有必要通过执行webBrowser1.Url = new Uri(URLpath);重新加载URL。
导航时,必须存储新的URL。我在“导航”事件中这样做。
无论如何,如果网页包含DrawToBitmap<input type="text" ..> field都会失败(带有空白框)。
通过用DocumentText破坏Replace("<input", "<in_put");可以治愈,但是如果没有其他技巧,这将丢失CSS工作表。


为了测试它,抛出两个Buttons, a Label, a Timer, a Combobox and a WebBrowser on a Form并复制代码;将文件路径更改为适合您的设置和监视的文件夹..:

public Form1()
{
    InitializeComponent();
    this.button1.Click += new System.EventHandler(this.button1_Click);
    this.button2.Click += new System.EventHandler(this.button2_Click);
    this.button1.Text = "Start";
    this.button2.Text = "Stop";
    this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
    this.comboBox1.Items.AddRange(new object[] {
        "https://stackoverflow.com/questions",
        "http://webcam.zirndorf.de/marktplatz/gross.jpg"});
    scapeRect = this.ClientRectangle;
    webBrowser1.Url = new Uri("https://stackoverflow.com/questions");
    this.comboBox1.SelectedIndexChanged +=
                   new System.EventHandler(this.comboBox1_SelectedIndexChanged);

}

Rectangle scapeRect = Rectangle.Empty;
int imgIndex = 0;
int urlIndex = 0;

private void button1_Click(object sender, EventArgs e)
{
    timer1.Interval = 10 * 1000;  // every 10 seconds
    timer1.Start();
}

private void button2_Click(object sender, EventArgs e)
{
    timer1.Stop();
}


private void timer1_Tick(object sender, EventArgs e)
{
    imgIndex ++;
    label1.Text = imgIndex .ToString();
    webBrowser1.Url = new Uri(comboBox1.Text); // this works almost always
    //webBrowser1.Refresh();                   // this works only if the WB is 'untouched'
    string filename = "d:\\scrape\\AB_sos_Screen" + imgIndex .ToString("000") + ".png";
    Bitmap bmp = new Bitmap(scapeRect.Width, scapeRect.Height);
    this.DrawToBitmap(bmp, scapeRect);
    bmp.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
    bmp.Dispose();
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    if (comboBox1.Text != "") webBrowser1.Url = new Uri(comboBox1.Text);
}




private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
    if (!comboBox1.Items.Contains(e.Url.ToString()))
        urlIndex = comboBox1.Items.Add(e.Url.ToString());
    else
        urlIndex = comboBox1.Items.IndexOf(e.Url.ToString());
    if (urlIndex >= 0) comboBox1.SelectedIndex = urlIndex;
    button1.Focus();
}


现在,我几乎可以自由导航了,并且屏幕抓取功能仍然有效-带有文本输入字段(例如用户或标签页面。

我想知道是否有人能繁殖..?

还是解释一下?

还是我毕竟只是在“寻鬼”而已,事情简直就是不可靠???

最终编辑:

尽管可能会得到很好的解释,但获得可行的解决方案可能必须足够好。OP已找到使用PrintWindow调用user32.dll的代码并解决了所有问题。它可以在注销时工作,甚至可以在Refreshing中单击后与WebBrowser一起工作,并刮擦所有页面,包括带有文本输入字段的页面。这是我的版本:

using System.Runtime.InteropServices;
//...
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

public Bitmap CaptureControl(Control ctl)
{
    //Bitmap bmp = new Bitmap(ctl.Width, ctl.Height);  // includes borders
    Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height);  // content only
    using (Graphics graphics = Graphics.FromImage(bmp))
    {
        IntPtr hDC = graphics.GetHdc();
        try      { PrintWindow(ctl.Handle, hDC, (uint)0);   }
        finally  { graphics.ReleaseHdc(hDC);                }
    }
    return bmp;
}


这可以捕获带有或不带有边框的窗体或控件。

最佳答案

经过一整天的努力之后,我只是想增加我的经验。

上面的基于PrintWindow的方法只是在大多数WebBrowser控件上绘制了一个黑色矩形,尽管奇怪的是,显示的文本的最后几行似乎通过了。因此,即使黑色矩形也不一致!但是我能够使DrawToBitmap()工作。

但是,存在各种隐藏的要求。


首先,您的表单中只能有一个WebBrowser控件
-当我尝试添加第二个时,它会显示正常,但是
当绘制到位图时它将变成空白。
其次,WebBrowser必须是表单中最顶层的控件,
并且不能应用任何顶部/底部边距。违反
这往往导致我显示的HTML的底部被剪切
关闭,并且足够大的顶部/底部页边距往往会导致页面的
内容绘制到位图时会垂直拉伸。
第三,为避免触碰WebBrowser,请创建一个
禁用Control来包装它,并将WebBrowser放在其中
该控件(DockFill)。你要处理
显示整个HTML文档的内容,其中大部分是
涵盖here(即设置您的网络浏览器,并包含
控件的大小与Web浏览器的Document.Body.ScrollRectangle
DocumentCompleted事件处理程序中)。


但是到目前为止,这种方法对我来说一直有效。

关于c# - Web浏览器疯狂,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24343393/

10-13 07:35