WebBrowser.DrawToBitmap () or other methods?

I am trying to capture the contents of a WebBrowser control. DrawToBitmap() will work fine, but it is not supported in the documentation for the WebBrowser control. I am trying to find another way to capture the contents of a WebBrowser control and save it in a local image file.

Does anyone have any workarounds or other methods for storing the contents of a WebBrowser control in a local image file?

+22
html c # webbrowser-control
Mar 12 '10 at 16:31
source share
4 answers

Control.DrawToBitmap does not always work, so I resorted to the following API calls, which provide more consistent results:

Utility Class. Call Utilities.CaptureWindow (Control.Handle) to capture a specific control:

 public static class Utilities { public static Image CaptureScreen() { return CaptureWindow(User32.GetDesktopWindow()); } public static Image CaptureWindow(IntPtr handle) { IntPtr hdcSrc = User32.GetWindowDC(handle); RECT windowRect = new RECT(); User32.GetWindowRect(handle, ref windowRect); int width = windowRect.right - windowRect.left; int height = windowRect.bottom - windowRect.top; IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc); IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height); IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap); Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, ApiConstants.SRCCOPY); Gdi32.SelectObject(hdcDest, hOld); Gdi32.DeleteDC(hdcDest); User32.ReleaseDC(handle, hdcSrc); Image image = Image.FromHbitmap(hBitmap); Gdi32.DeleteObject(hBitmap); return image; } } 

Gdi32 Class:

 public class Gdi32 { [DllImport("gdi32.dll")] public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop); [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight); [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hDC); [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hDC); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); } 

User32 class:

 public static class User32 { [DllImport("user32.dll")] public static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll")] public static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("user32.dll")] public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect); [DllImport("user32.dll")] public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC); } 

Constants Used:

  public const int SRCCOPY = 13369376; 

Used structures:

 [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left; public int top; public int right; public int bottom; } 

Friendly extension method:

 public static class ControlExtensions { public static Image DrawToImage(this Control control) { return Utilities.CaptureWindow(control.Handle); } } 

This is a code snippet from my CC.Utilities project, and I specifically wrote it to take screenshots from the WebBrowser control.

+37
Mar 12
source share

The following method can capture the entire image of the window, even if the window is larger than the screen size. It can then capture an image of the page content if the window is resized to webBrowser.Document.OffsetRectangle.Size

 class NativeMethods { [ComImport] [Guid("0000010D-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IViewObject { void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect, int lindex, IntPtr pvAspect, [In] IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [MarshalAs(UnmanagedType.Struct)] ref RECT lprcBounds, [In] IntPtr lprcWBounds, IntPtr pfnContinue, [MarshalAs(UnmanagedType.U4)] uint dwContinue); } [StructLayout(LayoutKind.Sequential, Pack = 4)] struct RECT { public int Left; public int Top; public int Right; public int Bottom; } public static void GetImage(object obj, Image destination, Color backgroundColor) { using(Graphics graphics = Graphics.FromImage(destination)) { IntPtr deviceContextHandle = IntPtr.Zero; RECT rectangle = new RECT(); rectangle.Right = destination.Width; rectangle.Bottom = destination.Height; graphics.Clear(backgroundColor); try { deviceContextHandle = graphics.GetHdc(); IViewObject viewObject = obj as IViewObject; viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, deviceContextHandle, ref rectangle, IntPtr.Zero, IntPtr.Zero, 0); } finally { if(deviceContextHandle != IntPtr.Zero) { graphics.ReleaseHdc(deviceContextHandle); } } } } } 

Using:

 Bitmap screenshot = new Bitmap(1024, 768); NativeMethods.GetImage(webBrowser.ActiveXInstance, screenshot, Color.White); 
+3
Dec 21 '14 at 14:11
source share

I am using DrawToBitmap (Visual Studio 2008 C #) to capture large images (custom invoices, off-screen content). Mostly it works well, but I get blank images. About 100 employees use this software, approximately every 2 weeks I see one blank image.

I did a lot of testing, and one fun thing I found was: I created a button to create an image from a web browser. This is usually normal, but if I click on the web browser first and then click the Create button, a blank image will appear.

0
May 17 '10 at 5:49 a.m.
source share

I used the OleDraw method, as in this section on SO, but integrated it into a class derived from WebBrowser. This allows you to create a regular Control.DrawToBitmap not only for WebBrowser, but also for a form with WebBrowser. This also works if the form is hidden (covered by another form, including the parent MDI form) and should work when the user has blocked the session with Win + L (I did not check it).

 public class WebBrowserEx : WebBrowser { private const uint DVASPECT_CONTENT = 1; [DllImport("ole32.dll", PreserveSig = false)] private static extern void OleDraw([MarshalAs(UnmanagedType.IUnknown)] object pUnk, uint dwAspect, IntPtr hdcDraw, [In] ref System.Drawing.Rectangle lprcBounds ); protected override void WndProc(ref Message m) { const int WM_PRINT = 0x0317; switch (m.Msg) { case WM_PRINT: Rectangle browserRect = new Rectangle(0, 0, this.Width, this.Height); // Don't know why, but drawing with OleDraw directly on HDC from m.WParam. // results in badly scaled (stretched) image of the browser. // So, drawing to an intermediate bitmap first. using (Bitmap browserBitmap = new Bitmap(browserRect.Width, browserRect.Height)) { using (var graphics = Graphics.FromImage(browserBitmap)) { var hdc = graphics.GetHdc(); OleDraw(this.ActiveXInstance, DVASPECT_CONTENT, hdc, ref browserRect); graphics.ReleaseHdc(hdc); } using (var graphics = Graphics.FromHdc(m.WParam)) { graphics.DrawImage(browserBitmap, Point.Empty); } } // ignore default WndProc return; } base.WndProc(ref m); } } 
0
Apr 09 '19 at 13:29
source share



All Articles