Edit: The original question was long with lots of wild guesses. I reduced it to the remaining puzzles.
I have been struggling and perplexed all day and think that I should introduce my problem to the community.
It came from a message called Screenshot Method generates black images . The original poster wants to constantly take screenshots of its program, including WebBrowser, every n seconds , even when the user logs out .
When a user logs out, he no longer has a screen. Therefore, any attempt to read the screen will fail. When using a window descriptor, the result is a black box, when using CopyFromScreen, a GDI error is thrown.
But the program window still exists, and using DrawToBitmap works fine even when the user logs off.
Below are the conditions and remaining issues:
The user should not touch / WebBrowser any way. If it does, say, scroll, click, move calls, subsqeuent DrawToBitmap leads to an empty box.
As long as the WebBrowser remains untouched, it is enough to do a Refresh before the next call to DrawToBitmap.
After touching it, you need to download the URL again by doing webBrowser1.Url = new Uri(URLpath);
If you need to save the new URL for this, you must save it. I do this in the Navigated event.
No matter what DrawToBitmap fails (with an empty field), if the web page contains <input type="text" ..> field .
By vandalizing a DocumentText with Replace("<input", "<in_put"); it can be healed, but without further tricks it will lose CSS sheets.
To check this, skip the two Buttons, a Label, a Timer, a Combobox and a WebBrowser on a Form and copy the code; change the path to the folder that matches your setting and look ..:
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(); }
Now I can move almost freely, and the screen scraper continues to work - with the exception of pages with text input fields, for example, for example. Users or .
I wonder if any bda can reproduce ..?
Or explain
Or was I just a "ghost hunt" and the thing is just unreliable ???
Final Edit:
Although it would be nice to get an explanation, getting a working solution should probably be good enough. The OP found code that uses the PrintWindow call for user32.dll and solves all the problems. It works when you log out, works with Refreshing even after you click the WebBrowser button, and resets all pages, including text input fields. Here is my version:
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; }
This can capture a form or control with or without borders.