Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem
From: Ken Hanson (khanson_at_capstonetechnology.com)
Date: 03/17/04
- Next message: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Previous message: Michael Tissington: "Re: Quit event not fireing"
- In reply to: Charles Law: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Next in thread: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Reply: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Messages sorted by: [ date ] [ thread ]
Date: Tue, 16 Mar 2004 17:59:21 -0800
Charles,
Actually I had chopped off the top of the Form Load script which correctly
did the navigate. As it turns out the problem does not seem to have
anything to do with loading from a stream. If I navigate to a file
containing the html directly instead of loading from a stream I get the same
behaivour.
Basically I can call into the DHTML only after the first navigate, if the
web control is disposed and the form is released (but the app still runs of
course) and the the form and webbrowser is re-instantiated and navigates to
the same html I cannot call into the same dhtml script function. Something
must be left hanging around but I can't figure out what it is.
If you have any thoughts please let me know. I may play around with a
simpler dhtml sample to see if it has something to do with my script,
however in vb6 calling the same dhtml function gives me no problems. I am
beginning to suspect there is something broken in the interop regarding
support for this type script calling.
Thanks for all your help.
- Ken
Call WebBrowser1.Script.PopupDrawXYPlot(strXMLData, lngCurveFitStyles)
Works once on first instance, after second time the WebBrowser is
instantiated it fails, saying it is unable to find PopupDrawXYPlot, even
though the innerHTML of the document shows it has loaded correctly.
"Charles Law" <blank@nowhere.com> wrote in message
news:utl18A7CEHA.2888@TK2MSFTNGP09.phx.gbl...
> Ken
>
> Although probably not the problem, it looks like you might be caching the
> document object. It is best to retrieve it from the control each time you
> need a reference.
>
> When you talk about 'dialog form unload', do you mean that you close the
> form that hosts the browser control and then re-open it? The browser
control
> needs to be disposed explicitly, so you should have a call to Dispose when
> you close the form.
>
> You say that objects are not available on subsequent occasions. Do you get
> an error? When you load the form, I do not see a Navigate("about:blank").
> This is required to initialise the control before you do anything else,
and
> then you must wait for DocumentComplete (readyState = "complete") before
you
> continue.
>
> HTH
>
> Charles
>
>
> "Ken Hanson" <khanson@capstonetechnology.com> wrote in message
> news:eTyO2t6CEHA.2800@tk2msftngp13.phx.gbl...
> > Charles,
> >
> > Thanks for the advice. Per your suggestion I moved the load from stream
> > logic to the form load event and it worked great. After looking a
little
> > closer I saw that the C++ example that Microsoft shows avoids the infite
> > event firing loop by checking the interface pointer of the document to
> make
> > sure it is the one you want, this is difficult to do in .NET and not
worth
> > the effort since it works as seen below.
> >
> > Unfortantely I Now I have a new problem. It appears that I can only
load
> > once from the stream. If I let the dialog form unload and release
object
> > accordingly a second attempt at loading the document seems to succeed
but
> > objects in the document are not available as they were the first time.
> >
> > Are you familiar with any thing I need to explicity clean up to avoid
> > confusing COM/WebBrowser interface?
> >
> > Thanks much for your help.
> >
> > - Ken
> >
> > In Form load:
> >
> > objDocument = WebBrowser1.Document
> >
> > strHTML = objSR.ReadToEnd()
> >
> > hGlobal = Marshal.StringToHGlobalAnsi(strHTML)
> >
> > CreateStreamOnHGlobal(hGlobal, True, strm)
> >
> > objPersistStreamInit = DirectCast(objDocument, IPersistStreamInit)
> >
> > objPersistStreamInit.InitNew()
> >
> > objPersistStreamInit.Load(strm)
> >
> > Do While WebBrowser1.ReadyState <> tagREADYSTATE.READYSTATE_COMPLETE
> >
> > Application.DoEvents()
> >
> > Loop
> >
> > objDocument = WebBrowser1.Document
> >
> > ...
> >
> > Subsequent call to vbscript function in document, works once, does not
> work
> > on subsequent doucment loads?
> >
> > Call objDocument.Script.PopupDrawXYPlot(strXMLData, lngCurveFitStyles)
> >
> >
> > "Charles Law" <blank@nowhere.com> wrote in message
> > news:OWLSze6CEHA.2628@TK2MSFTNGP11.phx.gbl...
> > > Hi Ken
> > >
> > > It looks to me that your technique is correct. The problem, I suspect,
> is
> > > where you load the document from the stream. Since documents are
loaded
> > > asynchronously, the logic of the load process is
> > >
> > > 1. Put html into stream
> > > 2. Load document from stream
> > > 3. Wait for operation to complete
> > > 4. Continue ...
> > >
> > > Step 3 means waiting for the readyState to become 'complete', and when
> > that
> > > happens the DocumentComplete event fires. As you are loading the
> document
> > in
> > > the DocumentComplete event, you will get into a continuous loop.
> > >
> > > I would suggest that you either load the document outside the
> > > DocumentComplete event (preferred), or set a flag in the event, before
> you
> > > load, to say that you are currently loading. This way you can avoid
> > > reloading the document.
> > >
> > > The preferred way would be to wait for the browser initialisation to
> > > complete (that is, it finishes navigating to about:blank, which you
must
> > > instruct it to do), and then load the document, waiting for readyState
> > > before continuing
> > >
> > > HTH
> > >
> > > Charles
> > >
> > >
> > > "Ken Hanson" <khanson@capstonetechnology.com> wrote in message
> > > news:%23cYb7l4CEHA.1604@TK2MSFTNGP11.phx.gbl...
> > > > Charels,
> > > >
> > > > I have seen several threads where it appears you have been sucesfull
> > > loading
> > > > the WebBrowser control from a stream in the DocumentComplete event
> from
> > > > vb.net. I have been struggeling with this myself and was hoping you
> > might
> > > > illuminate me.
> > > >
> > > > Bottom line is that when I try to load from a stream, no error is
> thrown
> > > but
> > > > I seem to go into a infinite event loop where DocumentComplete keeps
> > being
> > > > fired.
> > > >
> > > > Any help would be appreciated.
> > > >
> > > > Thanks,
> > > >
> > > > Ken
> > > >
> > > > Here are the bits that appear to be important:
> > > >
> > > > Dim TrendHTML As Stream =
> > > >
> > >
> >
>
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(
> > > > "CTCTrend.TrendGraphics.htm")
> > > >
> > > > ...
> > > >
> > > > Private Sub WebBrowser1_DocumentComplete(ByVal eventSender As
> > > System.Object,
> > > > ByVal eventArgs As
AxSHDocVw.DWebBrowserEvents2_DocumentCompleteEvent)
> > > > Handles WebBrowser1.DocumentComplete
> > > >
> > > > Dim bResult As Boolean
> > > >
> > > > Dim strm As UCOMIStream
> > > >
> > > > Dim objPersistStreamInit As IPersistStreamInit
> > > >
> > > > Dim hGlobal As IntPtr
> > > >
> > > > Dim strHTML As String
> > > >
> > > > Dim objSR As New StreamReader(TrendHTML)
> > > >
> > > > Try
> > > >
> > > > objDocument = WebBrowser1.Document
> > > >
> > > > strHTML = objSR.ReadToEnd() 'objSR is a stream reader initialized
> > durring
> > > > form load
> > > >
> > > > hGlobal = Marshal.StringToHGlobalAnsi(strHTML)
> > > >
> > > > CreateStreamOnHGlobal(hGlobal, True, strm)
> > > >
> > > > objPersistStreamInit = DirectCast(objDocument, IPersistStreamInit)
> > > >
> > > > objPersistStreamInit.InitNew()
> > > >
> > > > objPersistStreamInit.Load(strm)
> > > >
> > > > Catch ex As Exception
> > > >
> > > > msgbox ex.Mesage
> > > >
> > > > End Try
> > > >
> > > > End Sub
> > > >
> > > > "Charles Law" <blank@nowhere.com> wrote in message
> > > > news:efMqFaW%23DHA.3812@TK2MSFTNGP09.phx.gbl...
> > > > > Sorry for the cross post, but I'm not sure who is best placed to
> > answer
> > > > this
> > > > > one.
> > > > >
> > > > > This is the most bizarre behaviour of MSHTML and streams.
> > > > >
> > > > > I have a WebBrowser control that contains nothing but some default
> > HTML.
> > > I
> > > > > want to copy the document and modify it before saving it to disk.
> > > > >
> > > > > So, I clone the document like this:
> > > > >
> > > > > <code>
> > > > > Private Function CloneDocument(ByVal doc As
> mshtml.IHTMLDocument2)
> > > As
> > > > > mshtml.IHTMLDocument2
> > > > >
> > > > > Dim newdoc2 As mshtml.IHTMLDocument2
> > > > > Dim ips As IPersistStreamInit
> > > > >
> > > > > Dim strm As UCOMIStream
> > > > >
> > > > > Dim source As String
> > > > >
> > > > > ' Create and initialise a new document object
> > > > > newdoc2 = New mshtml.HTMLDocument
> > > > >
> > > > > ips = DirectCast(newdoc2, IPersistStreamInit)
> > > > >
> > > > > ips.InitNew()
> > > > >
> > > > > Do Until newdoc2.readyState = "complete"
> > > > > Application.DoEvents()
> > > > > Loop
> > > > >
> > > > > ' Get the current document HTML as a stream
> > > > > source = GetDocumentSource(AxWebBrowser1.Document) ' see
> below
> > > > > strm = GetStream(source) ' see below
> > > > >
> > > > > ' Load the new document from the stream
> > > > > ips.Load(strm)
> > > > >
> > > > > ' Wait until the new document has settled
> > > > > Do Until newdoc2.readyState = "complete"
> > > > > Application.DoEvents()
> > > > > Loop
> > > > >
> > > > > Return newdoc2
> > > > >
> > > > > End Function
> > > > >
> > > > > Private Function GetStream(ByVal s As String) As UCOMIStream
> > > > >
> > > > > Dim iptr As IntPtr
> > > > > Dim istrm As UCOMIStream
> > > > >
> > > > > ' Get a pointer to the string
> > > > > iptr = Marshal.StringToHGlobalAuto(s)
> > > > >
> > > > > ' Create the stream from the pointer
> > > > > CreateStreamOnHGlobal(iptr, True, istrm)
> > > > >
> > > > > Return istrm
> > > > >
> > > > > End Function
> > > > > Private Function GetStream(ByVal size As Integer) As
UCOMIStream
> > > > >
> > > > > Dim iptr As IntPtr
> > > > > Dim strm As UCOMIStream
> > > > >
> > > > > ' Create a pointer to a block of the required size
> > > > > iptr = Marshal.AllocHGlobal(size)
> > > > >
> > > > > ' Create the stream from the pointer
> > > > > CreateStreamOnHGlobal(iptr, True, strm)
> > > > >
> > > > > Return strm
> > > > >
> > > > > End Function
> > > > >
> > > > > Private Function GetDocumentSource(ByVal doc As
> > > mshtml.IHTMLDocument2,
> > > > > ByVal resetIsDirty As Boolean) As String
> > > > >
> > > > > Dim stream As UCOMIStream
> > > > >
> > > > > Dim ips As IPersistStreamInit
> > > > >
> > > > > Dim s As String
> > > > >
> > > > > ips = DirectCast(doc, IPersistStreamInit)
> > > > >
> > > > > If ips Is Nothing Then
> > > > > s = Nothing
> > > > > Else
> > > > > stream = GetStream(2048)
> > > > >
> > > > > ' Save the document into the comstream, without
clearing
> > the
> > > > > IsDirty flag
> > > > > ips.Save(stream, resetIsDirty)
> > > > >
> > > > > s = StreamToString(stream)
> > > > > End If
> > > > >
> > > > > Return s
> > > > >
> > > > > End Function
> > > > >
> > > > > Private Function StreamToString(ByVal strm As UCOMIStream) As
> > String
> > > > >
> > > > > Dim iptr As IntPtr
> > > > >
> > > > > Dim s As String
> > > > >
> > > > > GetHGlobalFromStream(strm, iptr)
> > > > >
> > > > > ' *** THIS IS ODD TOO ***
> > > > > ' If the source is the WebBrowser control then Ansi must
be
> > used
> > > > ***
> > > > > s = Marshal.PtrToStringAnsi(iptr)
> > > > >
> > > > > ' If the source is the cloned and modified document then
> Auto
> > > must
> > > > > be used ***
> > > > > s = Marshal.PtrToStringAuto(iptr)
> > > > >
> > > > > ' ***
> > > > >
> > > > > Return s
> > > > >
> > > > > End Function
> > > > > </code>
> > > > >
> > > > > Having cloned the document, I modify it by inserting some tags
into
> > the
> > > > body
> > > > > element. I then call GetDocumentSource() to get the HTML from the
> > cloned
> > > > > document.
> > > > >
> > > > > However, the HTML that is returned is the original HTML, from the
> > > > WebBrowser
> > > > > control, and not from the cloned document. I know that the cloned
> > > document
> > > > > contains the correct HTML because if I execute the following for
the
> > > > cloned
> > > > > document
> > > > >
> > > > > ?doc.all.tags("html").Item(0).outerhtml
> > > > >
> > > > > in the command window, I get what I expect in the body element.
> > > > >
> > > > > Can anyone suggest why this is happening?
> > > > >
> > > > > I have also highlighted an oddity in function StreamToString(),
> which
> > I
> > > do
> > > > > not understand. Why would the encoding of the HTML change between
> the
> > > > > browser and a cloned document?
> > > > >
> > > > > TIA
> > > > >
> > > > > Charles
> > > > >
> > > > >
> > > >
> > > >
> > >
> > >
> >
> >
>
>
- Next message: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Previous message: Michael Tissington: "Re: Quit event not fireing"
- In reply to: Charles Law: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Next in thread: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Reply: Ken Hanson: "Re: UCOMIStream, MSHTML and WebBrowser control Persistence Problem"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|