Community discussion forum

Generate an Image of a Web Page

This is a comment thread discussing Generate an Image of a Web Page
  • 9 years ago

    This thread is for discussions of Generate an Image of a Web Page.

  • Advertisement

    Simply the fastest line-level profiler for .NET ever

    “The low overhead means it has minimal impact on the execution of my program”
    Mark Everest, Development Team Leader, Renault F1 Team Ltd.

    Try out the new ANTS Profiler 4 for yourself. Download your 14-day trial now

  • 3 years ago
    1. When i tryed this, i got the following results (after some struglings with interops and the like):


    a) With the web browser in the viewable part of the form i get the image of the site with scrollbars
    b) With the web browser outside of the viewable part of the form i get an empty image


    2. The image copyed is limited to the size of the web browser in the first place;


    3. What i tryed to archieve would be to point to a site, grab it's content, render it in a "out-of-screen" object and copy it's "image" to a graphic, at the size that the content requires... Is there a way of doing it?



  • 3 years ago

    This is the code i'm using for the test (in a standard form/windows desktop project):


    Imports System.Runtime.InteropServices
    Imports mshtml
    Imports System.Drawing
    Imports System.Drawing.Imaging
    Imports System


    <Guid("3050f669-98b5-11cf-bb82-00aa00bdce0b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(True), ComImport()> _
    Interface IHTMLElementRender


       Sub DrawToDC(<In> _
     ByVal hDC As IntPtr)


       Sub SetDocumentPrinter(<In, MarshalAs(UnmanagedType.BStr)> _
     ByVal bstrPrinterName As String, <In> _
     ByVal hDC As IntPtr)
    End Interface


    Public Class Form1
       Inherits System.Windows.Forms.Form


       Private Class GDI32
           Public Const SRCCOPY As Integer = 13369376


           <DllImport("gdi32.dll")> _
           Public Shared Function BitBlt(ByVal hObject As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hObjectSource As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As Integer) As Boolean
           End Function


           <DllImport("gdi32.dll")> _
           Public Shared Function CreateCompatibleBitmap(ByVal hDC As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr
           End Function


           <DllImport("gdi32.dll")> _
           Public Shared Function CreateCompatibleDC(ByVal hDC As IntPtr) As IntPtr
           End Function


           <DllImport("gdi32.dll")> _
           Public Shared Function DeleteDC(ByVal hDC As IntPtr) As Boolean
           End Function


           <DllImport("gdi32.dll")> _
           Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
           End Function


           <DllImport("gdi32.dll")> _
           Public Shared Function SelectObject(ByVal hDC As IntPtr, ByVal hObject As IntPtr) As IntPtr
           End Function
       End Class



    Region " Windows Form Designer generated code "



       Public Sub New()
           MyBase.New()


           'This call is required by the Windows Form Designer.
           InitializeComponent()


           'Add any initialization after the InitializeComponent() call


       End Sub


       'Form overrides dispose to clean up the component list.
       Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
           If disposing Then
               If Not (components Is Nothing) Then
                   components.Dispose()
               End If
           End If
           MyBase.Dispose(disposing)
       End Sub


       'Required by the Windows Form Designer
       Private components As System.ComponentModel.IContainer


       'NOTE: The following procedure is required by the Windows Form Designer
       'It can be modified using the Windows Form Designer.  
       'Do not modify it using the code editor.
       Friend WithEvents PictureBox1 As System.Windows.Forms.PictureBox
       Friend WithEvents AxWebBrowser1 As AxSHDocVw.AxWebBrowser
       <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
           Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
           Me.PictureBox1 = New System.Windows.Forms.PictureBox
           Me.AxWebBrowser1 = New AxSHDocVw.AxWebBrowser
           CType(Me.AxWebBrowser1, System.ComponentModel.ISupportInitialize).BeginInit()
           Me.SuspendLayout()
           '
           'PictureBox1
           '
           Me.PictureBox1.Location = New System.Drawing.Point(8, 8)
           Me.PictureBox1.Name = "PictureBox1"
           Me.PictureBox1.Size = New System.Drawing.Size(488, 312)
           Me.PictureBox1.TabIndex = 1
           Me.PictureBox1.TabStop = False
           '
           'AxWebBrowser1
           '
           Me.AxWebBrowser1.Enabled = True
           Me.AxWebBrowser1.Location = New System.Drawing.Point(8, 336)
           Me.AxWebBrowser1.OcxState = CType(resources.GetObject("AxWebBrowser1.OcxState"), System.Windows.Forms.AxHost.State)
           Me.AxWebBrowser1.Size = New System.Drawing.Size(488, 208)
           Me.AxWebBrowser1.TabIndex = 2
           '
           'Form1
           '
           Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
           Me.ClientSize = New System.Drawing.Size(504, 549)
           Me.Controls.Add(Me.AxWebBrowser1)
           Me.Controls.Add(Me.PictureBox1)
           Me.Name = "Form1"
           Me.Text = "Form1"
           CType(Me.AxWebBrowser1, System.ComponentModel.ISupportInitialize).EndInit()
           Me.ResumeLayout(False)


       End Sub


    End Region



       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
           AxWebBrowser1.Navigate("http://www.teladigital.pt")
       End Sub


       Private Sub AxWebBrowser1DocumentComplete(ByVal sender As System.Object, ByVal e As AxSHDocVw.DWebBrowserEvents2DocumentCompleteEvent) Handles AxWebBrowser1.DocumentComplete
           Dim document As IHTMLDocument2 = CType(Me.AxWebBrowser1.Document, IHTMLDocument2)
           Dim graphics1 As Graphics = Me.PictureBox1.CreateGraphics
           If Not (document Is Nothing) Then
               Dim element As IHTMLElement = CType(document.body, IHTMLElement)
               If Not (element Is Nothing) Then
                   Dim render As IHTMLElementRender = CType(element, IHTMLElementRender)
                   If Not (render Is Nothing) Then
                       ' Using
                       Try
                           Dim hdcDestination As IntPtr = graphics1.GetHdc
                           render.DrawToD

  • 2 years ago

    Code:

    render = (IHTMLElementRender)element;

    this statement throw an exception: Specified cast is not valid.
    How it happen? Did you met this problem?

  • 2 years ago

    My code is written by C# but it's exactly as yours. I got the same result as you described. Have you resolved this problem? I am really want to know. Thanks very much.

  • 2 years ago

    Has anyone been able to get the code in this article to work in VB Express.  I have tried the following VB code to no avail. I think I have followed the article code pretty close.  I have added references to msHTML,GDI32, and ax shdocVw so I do not think that is the problem.  The render.DrawTo DC() does not seem to work.  I think it may have something to do with the way I have set up the IHTMLElementRender interface. I may be missing a subtle step in setting up the interface.  I have tried it both inside and outside the form1 class but the results do not change. The picturebox does not change at all.  The code not shown navigates to a webpage and waits for completion, then a call to mapcopy() to generate an image of the HTML in a picturebox, and then a call to me.Invalidate() to cause the picturebox to to be refreshed.  Can anyone point me in the right direction or tell me a better way to accomplish the same thing I would appreciate it.  

    Option Explicit On
    Imports System.Runtime.InteropServices
    Imports mshtml
    Imports System.Xml
    Imports System.IO
    Imports System.Net
    Imports System
    Imports System.Text
    Imports System.Text.RegularExpressions
    Imports System.Threading








     

    Public Class Form1
        <Guid("3050f669-98b5-11cf-bb82-00aa00bdce0b"), System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown),

    System.Runtime.InteropServices.ComVisible(True), System.Runtime.InteropServices.ComImport()> _
        Interface IHTMLElementRender

            Sub DrawToDC(<System.Runtime.InteropServices.In()> ByVal hDC As IntPtr)

            Sub SetDocumentPrinter(<System.Runtime.InteropServices.In(), System.Runtime.InteropServices.MarshalAs(UnmanagedType.BStr)> _
            ByVal bstrPrinterName As String, <System.Runtime.InteropServices.In()> _
            ByVal hDC As IntPtr)
        End Interface


    Private Sub mapcopy()
            'This sub copies a web page as image to picturebox as bitmap. It uses msHTML.dll, GDI32.dll, and axSHDocVw.dll

            Dim document As IHTMLDocument2 = CType(Me.AxWebBrowser1.Document, IHTMLDocument2)
            If Not (document Is Nothing) Then
                Dim element As IHTMLElement = CType(document.body, IHTMLElement)
                If Not (element Is Nothing) Then
                    Dim render As IHTMLElementRender = CType(element, IHTMLElementRender)
                    If Not (render Is Nothing) Then
                        ' Using
                        Dim graphics As Drawing.Graphics = Me.PictureBox2.CreateGraphics
                        Try
                            Dim PointerToGraphics As IntPtr = graphics.GetHdc 'Set the graphics pointer
                            render.DrawToDC(PointerToGraphics) 'draw to the picturebox2
                            Dim PointerToDC As IntPtr = gdi32.CreateCompatibleDC(PointerToGraphics) 'Set the DC pointer
                            Dim PointerToBitmap As IntPtr = gdi32.CreateCompatibleBitmap(PointerToGraphics, Me.AxWebBrowser1.ClientRectangle.Width, Me.WebBrowser1.ClientRectangle.Height) 'Set the











    bitmap pointer

                            If Not (PointerToBitmap = IntPtr.Zero) Then
                                Dim hOld As IntPtr = CType(gdi32.SelectObject(PointerToDC, PointerToBitmap), IntPtr)

                                gdi32.BitBlt(PointerToDC, 0, 0, Me.AxWebBrowser1.ClientRectangle.Width, Me.AxWebBrowser1.ClientRectangle.Height, PointerToGraphics, 0, 0,

    CType(gdi32.TernaryRasterOperations.SRCCOPY, Integer))
                                gdi32.SelectObject(PointerToDC, hOld)
                                gdi32.DeleteDC(PointerToDC)
                                graphics.ReleaseHdc(PointerToGraphics)
                                Me.PictureBox2.Image = Drawing.Image.FromHbitmap(PointerToBitmap) 'Copy Bitmap to Picturebox2
                                Me.PictureBox2.Image.Save("c:\temp\map.bmp")
                            End If
                        Finally
                            CType(graphics, IDisposable).Dispose()
                        End Try
                    End If
                End If
            End If
        End Sub












    End Class

    Public Class gdi32
        'This class is used by Sub Mapcopy
        Public Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As IntPtr) As Boolean
        Public Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As IntPtr, ByVal hgdiobj As IntPtr) As IntPtr
        Public Declare Function CreateCompatibleDC _
         Lib "gdi32" (ByVal hDC As IntPtr) As IntPtr
        Public Declare Function _
         CreateCompatibleBitmap Lib "gdi32" (ByVal hDC As IntPtr, _
         ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr
        Public Declare Function BitBlt Lib "gdi32" _
         (ByVal hDestDC As IntPtr, ByVal x As Integer, _
         ByVal y As Integer, ByVal nWidth As Integer, _
         ByVal nHeight As Integer, ByVal hSrcDC As _
         IntPtr, ByVal xSrc As Integer, ByVal ySrc As _
         Integer, ByVal dwRop As Integer) As Integer
        Enum TernaryRasterOperations As Integer
            'This Enum is used by Mapcopy sub
            SRCCOPY = 13369376     'dest = source
            SRCPAINT = 15597702    'dest = source OR dest
            SRCAND = 8913094       'dest = source AND dest
            SRCINVERT = 6684742    'dest = source XOR dest
            SRCERASE = 4457256     'dest = source AND (NOT dest )
            NOTSRCCOPY = 3342344   'dest = (NOT source)
            NOTSRCERASE = 1114278  'dest = (NOT src) AND (NOT dest)
            MERGECOPY = 12583114   'dest = (source AND pattern)
            MERGEPAINT = 12255782  'dest = (NOT source) OR dest
            PATCOPY = 15728673     'dest = pattern
            PATPAINT = 16452105    'dest = DPSnoo
            PATINVERT = 5898313    'dest = pattern XOR dest
            DSTINVERT = 5570569    'dest = (NOT dest)
            BLACKNESS = 66     'dest = BLACK
            WHITENESS = 16711778   'dest = WHITE
        End Enum
    End Class
































     

  • 2 years ago

    I was also doing some poking around with this, only using the wrapped web browser object that is now part of the .Net Form Controls that is part of .Net 2.0

    What I had was essentially a standard .Net webform, with a WebBrowser  control on it (called webBrowserNavigate)....

    slight modification of the code leads to:

    HtmlDocument document = this.webBrowserNavigate.Document;
    if (document != null)
    {
      HtmlElement element = document.Body;
      if (element != null)
      {
        IHTMLElementRender render= (IHTMLElementRender)element.DomElement;
        if (render != null)
        {
          using (Bitmap B = new Bitmap(
            this.webBrowserNavigate.ClientRectangle.Width,
    this.webBrowserNavigate.ClientRectangle.Height)) { //Code as normal from here } } } }

  • 2 years ago

    Arthur,

    How can I add this webbrowsernavigate control to the toolbox? I can only find microsoft web browser under com componets and webbrowser under .net framework comopents(in System.windows.forms namespace). I am using visual studio 2005. thanks

  • 1 year ago

    Update if you use a .NET 2.0 WebBrowser component instead of activex.

    .NET 2.0 has a WebBrowser component that is a wrapper around the ActiveX control. It has the advantage of a DrawToBitmap method. Below is an event handler that for the Webbrowser.DocumentComplete event.

    private void OnDocumentComplete(object sender, EventArgs e)
            {       
                WebBrowser browser = (WebBrowser) sender;
               
                browser.DrawToBitmap
                    (((Bitmap)pictureBox1.Image),
                     new Rectangle(0,0, pictureBox1.Width, pictureBox1.Height));
                pictureBox1.Refresh();           
                /* http://www.developerfusion.co.uk/show/4712/ */
            }














  • 1 year ago

    I have been moving my old entries across from dotnetjunkies to my new domain (this article on developfusion was culled from a blog entry).

    As part of that process, I have been reworking some of the content, where it was worth keeping. The "Generate an image of a web page" has been extensively rewritten and I have also made a Visual Studio 2005 solution available for download as well.

    See http://thoughtpad.net/alan-dean/web-page-image-thumbnail.html

  • 1 year ago

    zippy1981 wrote the following post at 03-07-2007 7:23 PM:

    ".NET 2.0 has a WebBrowser component that is a wrapper around the ActiveX control. It has the advantage of a DrawToBitmap method."

    If only our life was that simple! Sadly, this is a bum steer.

    See the MSDN docs:

    http://msdn2.microsoft.com/en-us/library/system.windows.forms.webbrowser_members.aspx

    they clearly state that "This method is not supported by this control." (I suspect that it was supported during beta, but then dropped)

    However, I have good news ... see my previous forum post: http://www.developerfusion.co.uk/forums/thread/152827/#152827

  • 1 year ago

    Here's my thoughts about modifications of code for achieving better results:

    First possible solution:
    The main problem still exists. when you're trying to get content of rendered page, you use BitBlt function which clips content and if your source window is not shown on desktop then you will not get image. I'll explain how I think this problem should be solved.

    Question: where BitBlt function gets information about clipping?
    Answer: from Graphics object, which contains property with name "Clip". I'm currently investigating how to set correct clipping...

    Second possible solution:
    Solution goes around same function. In order to avoid clipping, we should avoid BitBlt and replace it with GetDIBBits or something like that. in this case I think we will get full image without clipping...

    I'm currently working on implementing both of solutions but if anyone has solution already, please let me know...

    Best Regards,
           Levan Jgharkava















  • 1 year ago

    levaniko wrote:
    Here's my thoughts about modifications of code for achieving better results:

    First possible solution:
    The main problem still exists. when you're trying to get content of rendered page, you use BitBlt function which clips content and if your source window is not shown on desktop then you will not get image. I'll explain how I think this problem should be solved.

    Question: where BitBlt function gets information about clipping?
    Answer: from Graphics object, which contains property with name "Clip". I'm currently investigating how to set correct clipping...

    Second possible solution:
    Solution goes around same function. In order to avoid clipping, we should avoid BitBlt and replace it with GetDIBBits or something like that. in this case I think we will get full image without clipping...

    I'm currently working on implementing both of solutions but if anyone has solution already, please let me know...

    Best Regards,
           Levan Jgharkava

















    Here's solution:
    Everything related to clipping comes from System.Drawing.Graphics object and we need to turn off clipping in Graphics object. To do this we should not create Graphics object from our picturebox and not from any window. I noticed Graphics object can be created from Image object which is base class for Bitmap object. So we can create Graphics object and write directly to Bitmap which has no clipping initially. in order to create bitmap, compatible to contents of webbrowser we can write code like this:
                bmp = new Bitmap(1, 1, webBrowser.CreateGraphics());
                PixelFormat pfmt = bmp.PixelFormat;
                bmp = new Bitmap(webBrowser.ClientRectangle.Width, webBrowser.ClientRectangle.Height, pfmt);

    and code for creating Graphics object is following:
    Graphics graphics = Graphics.FromImage(bmp);

    So, after this, clipping issues are fixed and we have bitmap of size of webbrowser control window.

    But... here's another problem:

    DrawToDC method of IHTMLElementRender interface is not rendering correctly all pages, especially with dynamic content and styling. for example, if we try to render http://www microsoft.com then it gives just some gradient on top and empty space after that. YouTube.com is not rendered at all! http://video.google.com has problems with rendering some background spaces e.t.c...
    so next goal is to use something else than DrawToDC.
    I did some investigation on drawing related functions in MSHTML object and found some functions which I'm trying right now. Any help will be appreciated...

    Best Regards,
           Levan Jgharkava

































  • 10 months ago

    [quote user="alan.dean"]

    zippy1981 wrote the following post at 03-07-2007 7:23 PM:

    ".NET 2.0 has a WebBrowser component that is a wrapper around the ActiveX control. It has the advantage of a DrawToBitmap method."

    If only our life was that simple! Sadly, this is a bum steer.

    See the MSDN docs:

    http://msdn2.microsoft.com/en-us/library/system.windows.forms.webbrowser_members.aspx

    they clearly state that "This method is not supported by this control." (I suspect that it was supported during beta, but then dropped)

    However, I have good news ... see my previous forum post: http://www.developerfusion.co.uk/forums/thread/152827/#152827

    [/quote]

    WebBrowser component itself doesn't have DrawToBitmap method, but it is derived from base-class Control that has this method - witch allows to cast the object into Control and use the method on that:

    void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
          WebBrowser wbCurrent = (WebBrowser)sender;
          wbCurrent.Width = wbCurrent.Document.Body.ScrollRectangle.Width;
          wbCurrent.Height = wbCurrent.Document.Body.ScrollRectangle.Height;
          Bitmap myBitmap = new Bitmap(wbCurrent.Width, wbCurrent.Height);
          ((Control)(wbCurrent)).DrawToBitmap(myBitmap, new Rectangle(0, 0, wbCurrent.Width, wbCurrent.Height));
          MemoryStream rawImage = new MemoryStream();
          myBitmap.Save(rawImage, ImageFormat.Png);
          pbViewer.Image = Image.FromStream(rawImage); //put image to PictureBox in the form
        }

    Not sure if this solution raises some additional problems or not, but it seemed to work quite fine. I also set WebBrowser initial Height and Width to 1 - to allow content to be exactly as large it must be.

    However, I have another question regarding it - I needed to use this solution (or ability to create images of specified web-pages) in web-server environment. The problem is however, that WebBrowser control can only work in Single-threaded apartment, whereas aspx calls run in Multi-threaded apartment - I managed to bypass this by encapsulating the task into dll where I create separate thread and set it's apartment-state to Single-threaded apartment. The solution actually works, but it has some undetectable bugs - like crashing the IIS application-thread from time-to-time (and IIS has default setting of disabling the application in an event of specified number of fatal crashes), and loosing the ability to navigate to given address after a while. For example after some amount of hits to one address - probably from aspx files running on different application-pool threads - this address becomes unreachable. The application-pool recycling resolves that problem, but it doesn't explain why this is happening in the first place. Also, the overall memory usage of IIS rises drastically over time and as more calls are coming against the component, the slower it gets. What I want to find out, is, if these problems are caused by the usage of WebBrowser control itself (that shouldn't work in MTA anyway) or because of the way I get the image (casting to Control) or because of the way I bypass the STA limitation (creating new STA thread from MTA thread)?

  • 8 months ago

     Well if the code you have above is exactly what you have in your application then you probably need to dispose of some resources! Which is easy and will probably help a lot try this:

    using(Bitmap myBitmap = new Bitmap(wbCurrent.Width, wbCurrent.Height)

    {

      //...

      using(MemoryStream rawImage = new MemoryStream())

      {

        //....

      }

    }

     

    The question is how are you creating your WebBrowser and calling navigate? WHen I do it I get no exceptions, no errors and no calls to my event handlers. I will actually get Navigating to fire but never DocumentCompelted or ProgressChanged or anything else. Any hints?
     

  • 8 months ago

    Actually I have tried to specifically dispose all objects where and whenever possible (even though they are destroyed anyway as soon as the scope they are in is completed) but it makes no difference. The WebBrowser object is created within code and it works fine for me:

    WebBrowser x = new WebBrowser();
    x.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
    x.Navigate("http://www.somesite.com");

     

    Anyways, I have concluded my quest for solution with the conclusion that multiple WebBrowser objects running simultaneously simply create some problems in the underlying framework (IE) that, and at some point (too many simultaneous WebBrowser objects/requests as it's possible in web-server environment), can result in unexpected results. And, that this issue can't be solved from within the calling code.

  • 8 months ago

    I managed to get the WebBrowser to work off screen too, I'm not sure what fixed it though. I totally buy that multiple WebBrowser controls will cause problems too, makes sense.

    However, calling Dispose() explicitly is actually very important. Simply going out of scope isn't good enough, calling dispose will clear up any unmanaged resources and simply going out of scope will cause the GC to only clean up managed resources. It is VERY important to always call dispose on an object implementing IDisposable. Wrap it in a using(IDisposable d = ...) { ... } to make your life easier (so dispose will still get called if there is an exception).

  • 8 months ago

    As I said, I tried disposing all possible objects - but with no difference to the outcome. Disposing gets rid of the no-longer-used objects, but in my case the problem lies in objects working at the same time in different threads - that somehow results with a conflict in the underlying framework level (odd as it may be).

  • 8 months ago

    That's unfortunate but doesn't surprise me. I suppose the logical conclusion would be to have a single WebBrowser control that does all of the rendering then queue the requests and asynchronously render the images and pass them back to the requestors. A lot more work but it's worth it if it fixes bugs that take down the system. 

  • 5 months ago

    Have used this Code for a long time with multiple weBrowser controls without problems but recently I've noticed that FLASH, SIlverlight and other stuff are not being thumbnailed.  While most of the standard HTML shows up the newer stuff shows as black spots in the case of FLASH and Styler-sheets with xml, Sliverlight just ends up showing the background color.  Standard HTML works fine!
    Does the DOM/IHTMLELEMENT not carry these nodes or items?  Are they carried somewhere else?
    ANY HELP GREATLY APPRECIATED!

    MY VERSION of CODE BELOW     VS2005/Net 2.0 - VB.net

    Public Enum TernaryRasterOperations
        SRCCOPY = &HCC0020       ' dest = source
        SRCPAINT = &HEE0086      ' dest = source OR dest
        SRCAND = &H8800C6        ' dest = source AND dest
        SRCINVERT = &H660046     ' dest = source XOR dest
        SRCERASE = &H440328      ' dest = source AND (NOT dest )
        NOTSRCCOPY = &H330008    ' dest = (NOT source)
        NOTSRCERASE = &H1100A6   ' dest = (NOT src) AND (NOT dest)
        MERGECOPY = &HC000CA     ' dest = (source AND pattern)
        MERGEPAINT = &HBB0226    ' dest = (NOT source) OR dest
        PATCOPY = &HF00021       ' dest = pattern
        PATPAINT = &HFB0A09      ' dest = DPSnoo
        PATINVERT = &H5A0049     ' dest = pattern XOR dest
        DSTINVERT = &H550009     ' dest = (NOT dest)
        BLACKNESS = &H42         ' dest = BLACK
        WHITENESS = &HFF0062     ' dest = WHITE
    End Enum

    <Guid("3050f669-98b5-11cf-bb82-00aa00bdce0b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(True), ComImport()> _
    Interface IHTMLElementRender
    Sub DrawToDC(<[In]()> ByVal hDC As IntPtr)

    Sub SetDocumentPrinter(<[In](), MarshalAs(UnmanagedType.BStr)> _
      ByVal bstrPrinterName As String, <[In]()> _
      ByVal hDC As IntPtr)
    End Interface

    Public Sub Thumb()
            'Console.WriteLine("Public Class BrowserThumbnail-Public Sub Thumb|E-- ")
            Try
                Dim document As mshtml.IHTMLDocument2 = DirectCast(Myform2.Ax15Form2Browser.Document.DomDocument, mshtml.IHTMLDocument2)
                Dim element As mshtml.IHTMLElement2 = DirectCast(document.body, mshtml.IHTMLElement2)
                Dim render As IHTMLElementRender = DirectCast(element, IHTMLElementRender)
                Dim GraphicsObject As Graphics = Myform2.thumbScr15.CreateGraphics
                Dim PointerToGraphics As IntPtr = GraphicsObject.GetHdc
                Dim PointerToDC As IntPtr = CreateCompatibleDC(PointerToDC)
                Dim PointerToBitmap As IntPtr = CreateCompatibleBitmap(PointerToGraphics, ThumbCopyFromWT, ThumbCopyFromHT)
                SelectObject(PointerToDC, PointerToBitmap)
                render.DrawToDC(PointerToDC)
                GraphicsObject.ReleaseHdc(PointerToGraphics)
                Dim dummyCallBack As System.Drawing.Image.GetThumbnailImageAbort
                dummyCallBack = New System.Drawing.Image.GetThumbnailImageAbort(AddressOf ThumbnailCallback)
                Dim fullSizeImg As System.Drawing.Image
                fullSizeImg = System.Drawing.Image.FromHbitmap(PointerToBitmap)
                Dim URLfullSizeImg As System.Drawing.Image
                URLfullSizeImg = System.Drawing.Image.FromHbitmap(PointerToBitmap)
                Myform2.thumbScr15.Image = fullSizeImg.GetThumbnailImage(ThumbWidth, ThumbSizeHT, dummyCallBack, IntPtr.Zero)
                URLHistThumbImage15 = URLfullSizeImg.GetThumbnailImage(URLHistImageWD, URLHistImageHT, dummyCallBack, IntPtr.Zero)
                'Cleanup
                CType(GraphicsObject, IDisposable).Dispose()
                DeleteDC(PointerToDC)
                DeleteObject(PointerToBitmap)
                T15Done = True
            Catch ex As System.NullReferenceException
                Console.WriteLine("--- NullReferenceException ---" & "  " & _
                vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
                ' Code reacting to NullReferenceException
            Catch ex As Exception
                ' Code reacting to any exception
                Console.WriteLine(vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
            End Try

     

  • 5 months ago

    Greg,

     Unfortunately, the code is unable to capture Flash or Silverlight and I am not aware of any way around this.

    Sorry, Alan

  • 5 months ago

     

    Hi Alan,

     

    I’ve looked around a bit and no one has a solution.   I certainly can do a screen capture and thumbnail it that way; unfortunately this is a display and capture mechanism and I lose the benefit of thumb-nailing multiple browsers under the cover. 

     

    Do you think it’s possible (under the cover) to navigate to a site, then somehow device context it upon browser completion and thumbnail it from a DC?

     

    Well… maybe not.  If I find a way to do this I will certainly post it here.

     

    Thanks Alan,

     

    Greg

     

  • 5 months ago

    Hi Alan,

    Found a timing bug in my project (browser completion was occurring before FLASH was completed) so FLASH now does work, but SilverLight and xsl/parser/xml HTML generated images do not. 

    It was suggested via MSDN that IHTMLElementRender has problems (misses’ stuff) that could be resolved by using IViewObject’s Draw Function.  What I need is a VB.net example of the parameters required by IViewObject:Draw to draw [BELOW--- (DIM) Drawrender to a DC (device Context)].   I been searching all over to find an example but have had no luck…  Do you have a VB.net example?

    Thanks Alan,  Greg

     

    Imports Microsoft.VisualStudio.OLE.Interop

    <Guid("0000010D-0000-0000-C000-000000000046")> <InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), ComVisible(True), ComImport()> _
    Interface IViewObject

        Sub Draw(ByVal dwDrawAspect As UInteger, _
        ByVal lindex As Integer, _
        ByVal pvAspect As UInteger, _
        ByVal ptd() As Microsoft.VisualStudio.OLE.Interop.DVTARGETDEVICE, _
        ByVal hdcTargetDev As UInteger, ByVal hdcDraw As UInteger, _
        ByVal lprcBounds() As Microsoft.VisualStudio.OLE.Interop.RECTL, _
        ByVal lprcWBounds() As Microsoft.VisualStudio.OLE.Interop.RECTL, _
        ByVal pContinue As Microsoft.VisualStudio.OLE.Interop.IContinue)

    End Interface


    Try
    Dim document As mshtml.IHTMLDocument2 = DirectCast(Me.WebBrowser1.Document.DomDocument, mshtml.IHTMLDocument2)
    Dim element As mshtml.IHTMLElement2 = DirectCast(document.body, mshtml.IHTMLElement2)
    'Dim render As IHTMLElementRender = DirectCast(element, IHTMLElementRender)
    Dim Drawrender As IViewObject = DirectCast(element, IViewObject)

    Dim GraphicsObject As Graphics = Me.PictureBox1.CreateGraphics
    Dim PointerToGraphics As IntPtr = GraphicsObject.GetHdc
    Dim PointerToDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)
    Dim PointerToBitmap As IntPtr = CreateCompatibleBitmap(PointerToGraphics, Me.WebBrowser1.Width, Me.WebBrowser1.Height)

    SelectObject(PointerToDC, PointerToBitmap)

    DrawRender.Draw(?????...
    'render.DrawToDC(PointerToDC)

  • 5 months ago

    I'd love to know the solution, as I'm in the same boat.  So if you do figure it out, please post back here to this thread!

    The code I came up with is below.  However, it faults inside of the Draw call.  I'm really not sure if passing an "array of one RECTL" is the right way to handle this interface, which wants a pointer to a RECTL when you're writing it natively.

    public Image GetHtmlThumbnail(Size size)

    {

    Image imgThumb = new Bitmap(size.Width, size.Height, PixelFormat.Format24bppRgb);

    Rectangle rectDest = new Rectangle(new Point(0, 0), size);

    _browser.Navigate("about:blank;");

    while (_browser.ReadyState != WebBrowserReadyState.Complete)

    Application.DoEvents();

    _browser.DocumentText = aobjData[DataFormats.Html] as string;

    Size sizeDocument = Utilities.GetHTMLDocumentSize(_browser.Document);

    IViewObjectEx viewObjectEx = _browser.Document.DomDocument as IViewObjectEx;

    IOleObject oleObject = viewObjectEx as IOleObject;

    double xScale = (double)size.Width / (double)sizeDocument.Width;

    int iPadding = (int)(xScale * System.Windows.Forms.SystemInformation.VerticalScrollBarWidth);

    SIZEL sizel;

    sizel.cx = Utilities.PixelsToHIMETRICX(sizeDocument.Width);sizel.cy = Utilities.PixelsToHIMETRICY(sizeDocument.Height);

     

    // Save away the old size so we can restore it

    SIZEL [] sizelOld = new SIZEL[1];

    oleObject.GetExtent(1, sizelOld); // DVASPECT_CONTENT == 1

     

    using (Graphics g = Graphics.FromImage(imgThumb))

    {

    RECTL [] rectl = new RECTL[1];

    rectl[0].top = 0;

    rectl[0].left = 0;

    rectl[0].right = size.Width + iPadding; // Extra padding so scrollbar renders outside thumbnail

    rectl[0].bottom = size.Height;

    IntPtr hdc = g.GetHdc();viewObjectEx.Draw(1, -1, 0, null, 0, (uint) hdc, rectl, null, null);

    g.ReleaseHdc(hdc);

    }

    oleObject.SetExtent(1, sizelOld);

    return null;

    }

  • 5 months ago

    Hi Dave I’m working on it.

    I have a variation of the code that gets the WebBrowser control from its rendered address passed to the context of the rendered desktop window.  This means It works only if the WebBrowser control is displayed on the desktop in a form (Code Below) and it does not matter where the webBrowser control is on the desktop or what is in it XSL/XML, Silverlight whatever.  I am trying to figure out how the rendered desktop window gets passed the rendered HTML.

    From code below:
    BitBlt(AddrCreateCompatibleDC, 0, 0, WinWidth, WinHeight, GetWindowDC(Me.WebBrowser1.Handle), 0, 0, SRCCOPY)

    StretchBlt(AddrOfPB1, 0, 0, 100, 100, AddrCreateCompatibleDC, 0, 0, Me.WebBrowser1.Width, Me.WebBrowser1.Height, TernaryRasterOperations.SRCCOPY)

    Of course this is not what I want and for whatever reason I cannot figure out where the rendered HTML is being stored.  So now I am using WinDBG to go through the assembly to find out what address (buffer) all HTML for display are being rendered to before being posted to the screens context!   Once I figure this out I’ll write a callable assembler or C++ routine from any .Net language. 

    I tried to go another route to see what the value of Webbrowse1.handle would be outside of NET so I Marshaled it from the outside back to NET – got the same result.  I’ve included the code if you want to play around with it.  To use the mshtml._RemotableHandle, a BitBlt call which I have commented out getRHandle(Me.WebBrowser1.Handle) You’ll need the following sub to grap it from outside of NET

    -------
    Public remotableHandle As mshtml._RemotableHandle

    'This essentially stores the IntPtr into unmanaged memory and then marshalls it again into a new structure, in this case a _RemotableHandle. Can be used as follows:

        Public Function getRHandle(ByVal windowHandle As IntPtr)
            'Allocate unmanaged memory to store this IntPtr0
            Dim address As IntPtr = Marshal.AllocHGlobal(IntPtr.Size)

            'Write the IntPtr into unmanaged memory
            Marshal.WriteIntPtr(address, windowHandle)

            'Return the RemotableHandle by marshalling it from unmanaged memory
            Return Marshal.PtrToStructure(address, GetType(mshtml._RemotableHandle))
        End Function

    --------------

        Private Structure RECT
            Dim Left As Integer
            Dim Top As Integer
            Dim Right As Integer
            Dim Bottom As Integer
        End Structure

    Try
                'Handle for the desktop window
                Dim AddrDesktopWindow As IntPtr
                If AddrDesktopWindow = 0 Then AddrDesktopWindow = GetDesktopWindow

                'getWindow Size
                Dim rcWindow As RECT
                GetWindowRect(AddrDesktopWindow, rcWindow)
                Dim WinHeight As Integer = rcWindow.Right - rcWindow.Left
                Dim WinWidth As Integer = rcWindow.Bottom - rcWindow.Top

                Dim PB1 As Graphics = Me.PictureBox1.CreateGraphics
                Dim AddrOfPB1 As IntPtr = PB1.GetHdc

                Dim AddrOfPictureBox1 As IntPtr = Me.PictureBox1.Handle

                'create a compatible DC
                Dim AddrCreateCompatibleDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)

                'create a memory bitmap in the DC just created, the size of the window we're capturing
                Dim AddrCreateCompatibleBitmap As IntPtr = CreateCompatibleBitmap(AddrOfPB1, WinWidth, WinHeight)

                'Prepare DC as a Bitmap using selectObject to configure the DC
                SelectObject(AddrCreateCompatibleDC, AddrCreateCompatibleBitmap)

                'copy the screen image into the DC
                'BitBlt(AddrCreateCompatibleDC, 0, 0, WinWidth, WinHeight, GetWindowDC(AddrDesktopWindow), 0, 0, SRCCOPY)
                BitBlt(AddrCreateCompatibleDC, 0, 0, WinWidth, WinHeight, GetWindowDC(Me.WebBrowser1.Handle), 0, 0, SRCCOPY)
                'BitBlt(AddrCreateCompatibleDC, 0, 0, WinWidth, WinHeight, getRHandle(Me.WebBrowser1.Handle), 0, 0, SRCCOPY)


                'Clone image of PictureBox1 to Picturebox2 when the IMAGE is in the Device Context
                '#### BitBlt(AddrOfPB1, 0, 0, WinWidth, WinHeight, AddrCreateCompatibleDC, 0, 0, SRCCOPY)
                StretchBlt(AddrOfPB1, 0, 0, 100, 100, AddrCreateCompatibleDC, 0, 0, Me.WebBrowser1.Width, Me.WebBrowser1.Height, TernaryRasterOperations.SRCCOPY)

                PB1.ReleaseHdc(AddrOfPB1)
                CType(PB1, IDisposable).Dispose()
                DeleteDC(AddrCreateCompatibleDC)
                DeleteObject(AddrCreateCompatibleBitmap)

            Catch ex As System.NullReferenceException
                MsgBox("--- NullReferenceException ---" & "  " & _
                vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
                ' Code reacting to NullReferenceException
            Catch ex As Exception
                ' Code reacting to any exception
                MsgBox(vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
            End Try
        End Sub

  • 5 months ago

    Thanks!  For my appliction the web browser control needs to be offscreen (not on a form), so it won't work for me.  I did find one thing interesting, though, which is the the interface definition for IViewObjectEx::Draw that ships in microsoft.visualstudio.ole.interop is wrong.  It's missing the last parameter (the DWORD value passed to the continuation function) from the definition of Draw.  So when you call it, its going to pop extra bytes off the stack before returning, and will crash.  Which it did, so I had to create my own interface definition (with the same guid) and that got it working.  That interface is below, in case it helps anyone.

    I'm still having a problem that its not drawing anything into my DC, and that's where I'm at right now, debugging the Draw() implementation in mshtml to figure out why...

    [Guid("3AF24292-0C96-11CE-A0CF-00AA00600AB8")]
    [
    ComConversionLoss]
    [
    InterfaceType(1)]
    public interface IViewObjectExDave
    {
    void Draw(uint dwDrawAspect, int lindex, uint pvAspect, DVTARGETDEVICE[] ptd, uint hdcTargetDev, uint hdcDraw, RECTL[] lprcBounds, RECTL[] lprcWBounds, IContinue pContinue, uint x);
     

    // etc, rest of methods
     

    }

  • 5 months ago


    OK, I FINALLY GOT IT TO WORK…..OFFSCREEN with SilverLight and XSL/XML EXCEPT SHOCKWAVE FLASH!

    At least I have a way to call Alan's routine when I detect a non-Flash HTML screen and now use IViewObject Draw when I have a Silverlight or xml/xsl css gened screen.  AGAIN all this works off Screen!

    Unfortunately as far as I can tell IViewObject is incompatible with trying to DirectCast it down to the element as in Alan's code so, while I now have a dual solution (with some upfront HTML parsing) I will keep looking into a single step solution.

    After looking at WinDbg and screwing around with memory addresses.  I finally got it to write off screen using IViewObject Draw function to a DC and then to a thumbnail.  What a pain this was!

    I had to use StretchBlt to grab it from the DC to shrink it down to a 100 by 100 thumbnail.  I do not like the way StretchBlt renders it.  The thumbnail is grainy and not as clear as Alan’s original FromBitmap code.  BUT for NOW ENOUGH IS ENOUGH!  I’ll screw with that later… ( I now have replace StretchBlt see my next reply)

    The Following CODE will write the rendered HTML screen from its memory location (not the form on the Desktop) and post it to a DEVICE COINTEXT.  It works WITH SILVERLIGHT and XSL/XML.  From the DC I use StretchBlt (will change that) to shrink it to the Picturebox 100 by 100 thumb.

     

    <ComImport(), _
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
    Guid("00000127-0000-0000-C000-000000000046")> _
    Public Interface IViewObject
        Function Draw(ByVal dwDrawAspect As Int32, _
        ByVal lindex As Int32, _
        ByVal pvAspect As IntPtr, _
        ByVal ptd As IntPtr, _
        ByVal hicTargetDev As Int32, _
        ByVal hdcDraw As IntPtr, _
        ByVal prcBounds As IntPtr, _
        ByVal prcWBounds As RectangleF, _
        ByVal fnContinue As IntPtr, _
        ByVal dwContinue As Int32) As Int32
    End Interface

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Try

                Dim ViewObject As IViewObject = DirectCast(Me.WebBrowser1.Document.DomDocument, IViewObject)

                Dim PB1 As Graphics = Me.PictureBox1.CreateGraphics
                Dim AddrOfPB1 As IntPtr = PB1.GetHdc

                'create a compatible DC
                Dim AddrCreateCompatibleDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)

                'create a memory bitmap in the DC just created, the size of the window we're capturing
                Dim AddrCreateCompatibleBitmap As IntPtr = CreateCompatibleBitmap(AddrOfPB1, Me.WebBrowser1.Width, Me.WebBrowser1.Height)

                'Prepare DC as a Bitmap using selectObject to configure the DC
                SelectObject(AddrCreateCompatibleDC, AddrCreateCompatibleBitmap)

                'Draw the Rendered DomDocument to the Device Context
                ViewObject.Draw(1, 1, Nothing, Nothing, 0, AddrCreateCompatibleDC, Nothing, Nothing, Nothing, 0)

                'Use StretchBlt to shrink it down to the Theubnail
                StretchBlt(AddrOfPB1, 0, 0, 100, 100, AddrCreateCompatibleDC, 0, 0, Me.WebBrowser1.Width, Me.WebBrowser1.Height, TernaryRasterOperations.SRCCOPY)


                'Dim fullSizeImg As System.Drawing.Image
                'fullSizeImg = System.Drawing.Image.FromHbitmap(AddrCreateCompatibleBitmap)

                PB1.ReleaseHdc(AddrOfPB1)
                CType(PB1, IDisposable).Dispose()
                DeleteDC(AddrCreateCompatibleDC)
                DeleteObject(AddrCreateCompatibleBitmap)

            Catch ex As System.NullReferenceException
                MsgBox("--- NullReferenceException ---" & "  " & _
                vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
                ' Code reacting to NullReferenceException
            Catch ex As Exception
                ' Code reacting to any exception
                MsgBox(vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
            End Try
      


    End Sub

  • 5 months ago

    Ok just replace StretchBlt with.  Not sure why this was not working before?  other than I was up very late and just couldn't see straight..

    Dim fullSizeImg As System.Drawing.Image

    fullSizeImg = System.Drawing.Image.FromHbitmap(AddrCreateCompatibleBitmap)

    Me.PictureBox1.Image = fullSizeImg.GetThumbnailImage(100, 100, Nothing, IntPtr.Zero)

  • 4 months ago

    Ok, this is the final version – and final comments.

     

    IViewObjectDraw is now my standard.  When the HTML text is converted into a rendered image sitting in memory and available to be moved to the desktop form’s screen buffer for display, … for whatever reason IVewObject.Draw will do a better job of picking up all of the pieces at whatever addresses they are stored at giving me an off-screen image (using the screen’s device context) to thumbnail from. 

     

    I now use the original  IHTMLElement.DrawToDc to pickup the only item (so far) the “Adobe Shockwave embedded player” the rest can be handled by IViewObject.Draw – flash, xsl/css, silverlight, etc.  It’s now a simple matter of searching the HTML document text looking for Adobe Shockwave and calling the original  IHTMLElement.DrawToDc.

     

    It is kind of a pain to do it this way because I must pre-check for Shcokwave, but the overhead with some reduced instruction tricks is reasonable… Also IViewObject code seems faster

     

    Greg

    Public Sub IviewDrawStyleThumb1()
            Try
                Dim ViewObject As IViewObject = DirectCast(Myform2.Ax1Form2Browser.Document.DomDocument, IViewObject)

                Dim PB1 As Graphics = Myform2.thumbScr1.CreateGraphics
                Dim AddrOfPB1 As IntPtr = PB1.GetHdc

                'create a compatible DC
                Dim AddrCreateCompatibleDC As IntPtr = CreateCompatibleDC(IntPtr.Zero)

                'create a memory bitmap in the DC just created, the size of the window we're capturing
                Dim AddrCreateCompatibleBitmap As IntPtr = CreateCompatibleBitmap(AddrOfPB1, ThumbCopyFromWT, ThumbCopyFromHT)

                'Prepare DC as a Bitmap using selectObject to configure the DC
                SelectObject(AddrCreateCompatibleDC, AddrCreateCompatibleBitmap)

                'Draw the Rendered DomDocument to the Device Context
                ViewObject.Draw(1, 1, Nothing, Nothing, 0, AddrCreateCompatibleDC, Nothing, Nothing, Nothing, 0)

                Dim fullSizeImg1 As System.Drawing.Image
                fullSizeImg1 = System.Drawing.Image.FromHbitmap(AddrCreateCompatibleBitmap)
                Myform2.thumbScr1.Image = fullSizeImg1.GetThumbnailImage(ThumbWidth, ThumbSizeHT, Nothing, IntPtr.Zero)

                Dim URLfullSizeImg As System.Drawing.Image
                URLfullSizeImg = System.Drawing.Image.FromHbitmap(AddrCreateCompatibleBitmap)
                URLHistThumbImage1 = URLfullSizeImg.GetThumbnailImage(URLHistImageWD, URLHistImageHT, Nothing, IntPtr.Zero)

                PB1.ReleaseHdc(AddrOfPB1)
                CType(PB1, IDisposable).Dispose()
                DeleteDC(AddrCreateCompatibleDC)
                DeleteObject(AddrCreateCompatibleBitmap)

                T1Done = True

            Catch ex As System.NullReferenceException
                MsgBox("--- NullReferenceException ---" & "  " & _
                vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
                ' Code reacting to NullReferenceException
            Catch ex As Exception
                ' Code reacting to any exception
                MsgBox(vbCrLf & "Message --- " & ex.Message & "  " & _
                vbCrLf & "Source --- " & ex.Source & "  " & _
                vbCrLf & "StackTrace --- " & ex.StackTrace & "  " & _
                vbCrLf & "TargetSite --- " & ex.TargetSite.ToString)
            End Try

        End Sub

Post a reply

Enter your message below

Sign in or Join us (it's free).