Web浏览器疯狂

时间:2014-06-21 16:05:13

标签: c# winforms webbrowser-control uri drawtobitmap

编辑:最初的问题很长,有很多猜测。我已经把它切回到剩下的奥秘......

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

它起源于名为Screenshot method generates black images的帖子。原始海报希望连续拍摄他的节目的截图,其中包括一个WebBrowser,每隔n秒,即使用户已经注销

当用户退出时,他不再有屏幕了。因此,任何读取屏幕的尝试都将失败。如果使用窗口句柄,则结果是黑盒子,当使用CopyFromScreen时出现GDI错误异常。

但程序窗口仍然存在,即使用户退出,使用DrawToBitmap也能正常工作。

以下是条件和剩余问题:

  • 用户不得以任何方式触碰/点击WebBrowser。如果他这样做,比如滚动,点击,导航下面的DrawToBitmap次调用会产生一个空框。

  • 虽然WebBrowser保持不变,但在下一次DrawToBitmap调用之前完成Refresh就足够了。

  • 触摸后,需要通过执行webBrowser1.Url = new Uri(URLpath);

  • 再次加载网址
  • 导航新网址时必须存储以执行此操作。我在Navigated活动中这样做。

  • 无论如何,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();
}

我现在可以几乎自由地导航并且屏幕抓取工作仍然有效 - 除了具有文本输入字段的页面,例如用户标签页面。

我想知道是否可以重现..?

或解释??

或者我只是一直在寻找幽灵&#39;毕竟,事情根本不可靠???

最终修改:

虽然获得解释本来不错,但获得一个可行的解决方案可能必须足够好...... 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;
}

这可以使用或不使用边框捕获表单或控件。

1 个答案:

答案 0 :(得分:0)

在经过漫长的一天打击这个问题之后,我想加上自己的经验。

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

然而,有各种各样的隐藏要求。

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

但到目前为止,这种方法对我来说始终如一。