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://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();
}
Теперь я могу перемещаться почти свободно, и соскоб экрана продолжает работать - за исключением страниц с текстовыми полями ввода, например, например.пользователей илиТеги страницы.
Интересно, может ли кто-нибудь воспроизвести ..?
Или объяснить ??
Или я все-таки просто «охота на призраков», а дело просто ненадежное ???
Окончательное редактирование:
Хотя было бы неплохо получить объяснение, получение рабочего решения, вероятно, должно быть достаточно хорошим. ОП нашел код, который использует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;
}
Это может захватить форму или элемент управления с границами или без них.