WebBrowser Madness

Редактировать: оригинальный вопрос был длинным со многими дикими догадками. Я сократил это до оставшихся тайн..

Я боролся и ломал голову весь день и думаю, что должен представить свою проблему сообществу.

Он возник из поста под названием Скриншот метод генерирует черные изображения. Оригинальный постер хочет постоянно делать скриншоты своей программы, включая веб-браузер, каждые n секунд, даже если пользователь вышел из системы.

Когда пользователь вышел из системы, у него больше нет экрана. Поэтому любая попытка прочитать экран потерпит неудачу. Если используется дескриптор окна, результатом является черный ящик, а при использовании CopyFromScreen исключение GDI-ошибки.

Но окно программы все еще там и использует DrawToBitmap работает нормально, даже когда пользователь вышел из системы.

Вот условия и остающиеся проблемы:

  • Пользователь не должен касаться / нажимать WebBrowser в любом случае. Если он делает это, скажем, прокрутка, щелчок, навигация по подкатегории DrawToBitmap звонки приводят к пустому полю.

  • В то время как WebBrowser остается нетронутым, достаточно сделать Refresh до следующего вызова DrawToBitmap.

  • После прикосновения к нему необходимо снова загрузить URL, выполнив webBrowser1.Url = new Uri(URLpath);

  • При навигации новый URL должен быть сохранен для этого. Я делаю это в событии 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://stackru.com/questions",
        "http://webcam.zirndorf.de/marktplatz/gross.jpg"});
    scapeRect = this.ClientRectangle;
    webBrowser1.Url = new Uri("https://stackru.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();
}

Теперь я могу перемещаться почти свободно, и соскоб экрана продолжает работать - за исключением страниц с текстовыми полями ввода, например, страницы " Пользователи" или " Теги".

Интересно, может ли кто-нибудь воспроизвести..?

Или объяснить??

Или я все-таки просто "охота за призраками", а дело просто ненадежное???

Окончательное редактирование:

Хотя было бы неплохо получить объяснение, получение рабочего решения, вероятно, должно быть достаточно хорошим. ОП нашел код, который использует 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 ответ

Просто хотел добавить свой опыт после долгого дня, когда я бился головой об этой проблеме.

Выше PrintWindowна основе метода просто нарисовал черный прямоугольник над большей частью WebBrowser контроль, хотя, как ни странно, последние несколько строк отображаемого текста, казалось, прошли. Так что даже черный прямоугольник несовместим! Но я смог получить DrawToBitmap() работать.

Однако существуют всевозможные скрытые требования.

  • Во-первых, вы можете иметь только один WebBrowser контроль в вашей форме - когда я попытался добавить второй, он будет отображаться нормально, но он будет пустым, когда обращается к растровому изображению.
  • Во-вторых, WebBrowser должен быть верхним элементом управления в вашей форме, и к нему не должно быть применено никаких верхних / нижних полей. Нарушение этого приводило к обрезанию нижней части моего отображаемого HTML-кода, а достаточно большие верхние / нижние поля имели тенденцию приводить к вертикальному растяжению содержимого страницы при обращении к растровому изображению.
  • В-третьих, чтобы сохранить WebBrowser от прикосновения создать инвалида Control обернуть его и положить WebBrowser внутри этого элемента управления (с Dock из Fill). Вам придется иметь дело с отображением содержимого всего HTML-документа, большая часть которого описана здесь (т. Е. Настроить ваш веб-браузер и содержать размер элемента управления в соответствии с веб-браузером Document.Body.ScrollRectangleв DocumentCompleted обработчик события).

Но пока этот метод работает последовательно для меня.

Другие вопросы по тегам