Powerbasic Museum 2020-B

General Category => General Discussion => Topic started by: Edwin Knoppert on September 04, 2011, 05:56:23 PM

Title: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 05:56:23 PM
I am using an ATL window, how can i use your MSHTML/xml/html example over and over with new content.
The idea is that the control is created without progid or mshtml syntax.
I could initialize it first but my goal is not to do that.

Thanks,
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 06:23:14 PM
ATL is an AxtiveX container, not a web browser control. If you create an instance of it wihout nothing, you will get nothing.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 07:05:43 PM
My 2nd attempt is to load a dummy html fragment, this is shown fine.
Now i would like to access the document object but it fails.
My ATL code obtains the dispatch from the ATL control and usually i can obtain the document just fine.
I normally use late binding but since i could not get a reference i implemented the interfaces (for now).
Here is some test code:

    Local pIWebBrowser2 As IWebBrowser2
    Local pIHTMLDocument2 As IHTMLDocument2
    pIWebBrowser2 = oWB
    ? Str$( ObjPtr( pIWebBrowser2 ) ) 
    pIHTMLDocument2 = pIWebBrowser2.Document
    ? Str$( ObjPtr( pIHTMLDocument2 ) )


oWB is the dispatch and like i said i usually obtain the document via: Object Get oWB.Document To v
Any idea why pIWebBrowser2 remains empty?
I have seen your code which does nearly the same but via the document ready event.
I would not like to use that part this way.

The control is created and shows the MSHTML, i click a button to obtain the dispatch and then the document.
?

Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 07:19:34 PM
To get the dispatch interface of the instance of the Web Browser control hosted in an ATL window you have to use something like:


' ========================================================================================
FUNCTION AtlAxGetDispatch (BYVAL hWndControl AS DWORD) AS IDispatch

   LOCAL hr AS LONG
   LOCAL pUnk AS IUnknown
   LOCAL pDispatch AS IDispatch
   LOCAL IID_IDispatch AS GUID

   ' Get the IUnknown of the OCX hosted in the control
   hr = AtlAxGetControl(hWndControl, pUnk)
   IF hr <> 0 THEN EXIT FUNCTION

   ' Query for the IDispatch interface
   IID_IDispatch = GUID$("{00020400-0000-0000-C000-000000000046}")
   hr = pUnk.QueryInterface(IID_IDispatch, BYVAL VARPTR(pDispatch))
   IF hr = %S_OK THEN FUNCTION = pDispatch

END FUNCTION
' ========================================================================================

Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 07:33:20 PM
But i do have a reference to this dispatch (not shown in my code), obtaining the document fails when i use MSHTML, it's fine with ordinary html.
Combine your function with mine and that's all i do.

?
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 07:47:17 PM
Sorry, but if you don't show all the code I don't know what you're doing.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 08:25:50 PM

    Local oWB           As Dispatch 
    Local v             As Variant
    Local pIWebBrowser2 As IWebBrowser2
    Local pIHTMLDocument2 As IHTMLDocument2

    oWB = AtlAxGetDispatch( hWnd )
    If IsObject( oWB ) Then

        pIWebBrowser2 = oWB
        ? Str$( ObjPtr( pIWebBrowser2 ) ) 
        pIHTMLDocument2 = pIWebBrowser2.Document
        ? Str$( ObjPtr( pIHTMLDocument2 ) )

' Object Call oWB.document To v
' ? Str$( Variant#( v ) )

        End If

        oWB = Nothing

    End If


Where  ObjPtr( pIWebBrowser2 )  returns 0
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 08:58:38 PM
If the code not show is correct, it should work.

In the following example, this works:


   LOCAL pWB AS IWebBrowser2
   LOCAL oWB AS DISPATCH
   oWB = OC_GetDispatch(hCtl)
   pWB = oWB
   MSGBOX STR$(OBJPTR(pWB)) & STR$(OBJPTR(oWB))



#COMPILE EXE
#DIM ALL
%UNICODE = 1

' // Include files for external files
%USEWEBBROWSER = 1            ' // Use the WebBrowser control
#INCLUDE ONCE "CWindow.inc"   ' // CWindow class

' // Identifier
%IDC_WEBBROWSER = 101

' ########################################################################################
' Main
' ########################################################################################
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
'   SetProcessDPIAware

   ' // Create an instance of the class
   LOCAL pWindow AS IWindow
   pWindow = CLASS "CWindow"
   IF ISNOTHING(pWindow) THEN EXIT FUNCTION

   ' // Create the main window
   pWindow.CreateWindow(%NULL, "AddWebBrowser Template", 0, 0, 0, 0, 0, 0, CODEPTR(WindowProc))
   ' // Set the client siz
   pWindow.SetClientSize 600, 350
   ' // Center the window
   pWindow.CenterWindow

   ' // Add a WebBrowser control
   LOCAL hCtl AS DWORD
   LOCAL bstrURL AS WSTRING

   bstrURL = "http://www.jose.it-berater.org/smfforum/index.php"
   ' // Create the control
   hCtl = pWindow.AddWebBrowserControl(pWindow.hwnd, %IDC_WEBBROWSER, bstrURL, NOTHING, 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)

   LOCAL pWB AS IWebBrowser2
   LOCAL oWB AS DISPATCH
   oWB = OC_GetDispatch(hCtl)
   pWB = oWB
   MSGBOX STR$(OBJPTR(pWB)) & STR$(OBJPTR(oWB))
   

   ' // Default message pump (you can replace it with your own)
   pWindow.DoEvents(nCmdShow)

END FUNCTION
' ########################################################################################

' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   STATIC hInstance AS DWORD        ' // Instance handle
   STATIC lpc AS CREATESTRUCT PTR   ' // Pointer to the creation parameters
   STATIC pWindow AS IWindow        ' // Reference to the IWindow interface

   SELECT CASE uMsg

      CASE %WM_CREATE
         ' // Pointer to the creation parameters
         lpc = lParam
         ' // Instance handle
         hInstance = @lpc.hInstance
         ' // Get a reference to the IWindow interface from the CREATESTRUCT structure
         pWindow = CWindow_GetObjectFromCreateStruct(lParam)
         EXIT FUNCTION

      CASE %WM_SYSCOMMAND
         ' // Capture this message and send a WM_CLOSE message
         ' // Note: Needed with some OCXs, that otherwise remain in memory
         IF (wParam AND &HFFF0) = %SC_CLOSE THEN
            SendMessage hwnd, %WM_CLOSE, 0, 0
            EXIT FUNCTION
         END IF

      CASE %WM_COMMAND
         SELECT CASE LO(WORD, wParam)
            CASE %IDCANCEL
               ' // If the Escape key has been pressed...
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  ' // ... close the application by sending a WM_CLOSE message
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE %WM_SIZE
         IF wParam <> %SIZE_MINIMIZED THEN
            ' // Resize the control
            pWindow.MoveWindow GetDlgItem(hwnd, %IDC_WEBBROWSER), 0, 0, pWindow.ClientWidth, pWindow.ClientHeight, %TRUE
         END IF

      CASE %WM_DESTROY
         ' // End the application
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   ' // Pass unprocessed messages to Windows
   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 09:33:24 PM
I just tried your code and indeed it works fine.
Though i don't think you have an ATL example present.
Maybe we need a different interface first (i mean maybe there is a difference in dispatches here?)

Anyway one thing i wanted to test today was the immediate html replacement (remember we spoke about the 'doevents' stuff?)
MSHTML seems to be handy for direct writing without the need for waiting until a document is present like:


   [b]bstrURL = MyHTMLCode()[/b]
   ' // Create the control
   hCtl = pWindow.AddWebBrowserControl( _
          pWindow.hWnd _
        , %IDC_WEBBROWSER _
        , bstrURL _
        , Nothing _
        , 0 _
        , 0 _
        , pWindow.ClientWidth _
        , pWindow.ClientHeight _
    )

   LOCAL pWB AS IWebBrowser2
   Local oWB As Dispatch
   oWB = OC_GetDispatch(hCtl)
   pWB = oWB
   'MSGBOX STR$(OBJPTR(pWB)) & STR$(OBJPTR(oWB))
   Local oDoc As Dispatch
   oDoc = pWB.document()
   
    Local v As Variant
    Local vHtml As Variant
    [b]vHtml = MyHTMLCode2() [/b]   
   
    v = "about:blank"
    Object Call oDoc.Open( v ) 
    Object Call oDoc.Write( vHtml ) 
    Object Call oDoc.Close() 
    oDoc = Nothing


For testing i have two MSHTM html fragments, the 2nd seems to be loaded properly.
I still would like an atl solution or suggestion, it brings less code and project enhancements to me.

(At least i was 'forced' to do my first test using PwrDev 3 which is a unicode tool only, no issues found yet :) )
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 09:47:40 PM
Quote
For testing i have two MSHTM html fragments, the 2nd seems to be loaded properly.

But you don't show them... Remember that you have to prefix it with "MSHTML:".
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 09:50:57 PM
Another thing: "MSHTML:" only works when you pass it as the caption when you create an instance of the ATL control.
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 09:57:39 PM
Quote
    v = "about:blank"
    Object Call oDoc.Open( v ) 
    Object Call oDoc.Write( vHtml ) 
    Object Call oDoc.Close() 

What does this? You don't open a blank page; you navigate to it with Navigate2, and you have to retrieve the document reference to this new page.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 11:04:59 PM
But every thing works fine except i can't get a reference to the document interface via atl when i use MSHTML.
Via OLECON it works fine, looks like it can not find the IID or so but i copied it from your files, so i don't see why it should not get a reference to IWebbrowser2.

Code i used is here, i took it from a topic of yours somewhere:

Function MyHTMLCode() As String

   Local s As String

   S =  "MSHTML:<?xml version=""1.0""?>"
   s += "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">" & $CrLf
   s += "<html xmlns=""http://www.w3.org/1999/xhtml"">" & $CrLf
   s += "<head>" & $CrLf
   s += "<title>Image Test</title>" & $CrLf
   s += "</head>" & $CrLf
   s += "<body scroll=" & $Dq & "auto" & $Dq & " style=" & $Dq & "MARGIN: 0px 0px 0px 0px" & $Dq & " >" & $CrLf
   s += "Hello <b>world</b>" & $CrLf
   s += "</body>" & $CrLf
   s += "</html>" & $CrLf
   
   Function = s

End Function


The 2nd document is ordinary html:


Function MyHTMLCode2() As String

   Local s As String

   S =  ""
   s += "<!DOCTYPE HTML PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">" & $CrLf
   s += "<html xmlns=""http://www.w3.org/1999/xhtml"">" & $CrLf
   s += "<head>" & $CrLf
   s += "<title>Image Test</title>" & $CrLf
   s += "</head>" & $CrLf
   s += "<body scroll=" & $Dq & "show" & $Dq & " style=" & $Dq & "MARGIN: 100px 0px 0px 0px" & $Dq & " >" & $CrLf
   s += "AAAAAAAAAAAAAAAAAAAAAAAAaHello <b>world</b>" & $CrLf
   s += "</body>" & $CrLf
   s += "</html>" & $CrLf
   
   Function = s

End Function


Note that this actually works fine and even without the wait-for-ready and doevents stuff.

The ATL also shows the initial MSHTML part fine but the lack of a document handle is the problem to place a new html part.
(And yes, the MSHTML is passed as 'progid' part (the caption).


v = "about:blank"
    Object Call oDoc.Open( v ) 
    Object Call oDoc.Write( vHtml ) 
    Object Call oDoc.Close()


Read about this today on MSDN, it seems ok though.. (?)
The open is required when the first document is done loading.
The url is not optional and AB was suggested, it clears the existing document.

Edit:
Must have been wrong, this is ok as well:
Object Call oDoc.Open()

http://msdn.microsoft.com/en-us/library/aa752628(v=vs.85).aspx
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 11:18:48 PM
Quote
Object Call oDoc.Write( vHtml ) 

This is wrong. The parameter for the Write method must be a safe array of type VT_VARIANT.
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 04, 2011, 11:33:59 PM
Quote
The open is required when the first document is done loading.
The url is not optional and AB was suggested, it clears the existing document.

No, it does not. It opens a NEW WINDOW.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 04, 2011, 11:36:03 PM
When late bound it works fine but i let's forget that for a moment.
I really really tried everything via atl, even your includes and interfaces.
There really may be something different about the dispatch (oWB).
Can you please check with MSHTML code on ATL?
Like i said, using plain html it always worked fine.

Edit:
Goal is a reference to the document, i tried the interfaces because late binding also didn't work, i don't want the interfaces if not needed, just the document dispatch.
Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 05, 2011, 12:03:39 AM
I really don't understand what you mean with MSHTML code and plain html.

I don't have anything that uses ATL since I wrote my OLE container, and much less using OBJECT CALL, that I always have disliked deeply. Write a compilable example and I will look at it.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 07, 2011, 08:07:43 PM
I am using MSHTML to initialize the webcontrol *instead* of using about:blank.
AB requires 'doevents' to complete while MSHTML seems not.
While at first a document for these may not be the same, not sure, but i accomplished this fine using OLECON code but not with atl.
When the MSHTML initializes the webcontrol it was ready to obtain the document object right away and i could then write ordinary html to it (without the MSHTML/xml stuff up front).
So in fact i am trying to get me a document handle from the MSHTML container.
In ATL this keeps failing, i now have an ATL fragment of yours where i have made several kind of attempts to get me a document handle.
Maybe i should abandon this anyway, the document may not be of the same breed??

Anyway, i do have the atl project, i could pm it if you think it's still a valid attempt?

Title: Re: MSHTML - use it over and over?
Post by: José Roca on September 07, 2011, 09:10:20 PM
You can't get a reference to the document until it has been fully loaded. Attempting to do it will result in a null reference.

If you use my OLE container and the AddWebBrowserControl method of my CWindow class then you don't need to navigate to about:blank and pump windows events because the method does it for you, not because it is not needed.
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 07, 2011, 09:53:56 PM
Sigh..., now i see..
Title: Re: MSHTML - use it over and over?
Post by: Edwin Knoppert on September 07, 2011, 10:45:30 PM
Call me persistant..., i have the idea of handling the messages to the windows i have listed via the messagepump:

Internet Explorer_Hidden
Internet Explorer_Hidden
Shell Embedding
Button
Button
Shell DocObject View
Internet Explorer_Server


I mean that i could simply prevent the messages for other parts of the program by not handling these messages.
In fact that's what i wanted in the first place, no intervening during the load of a webcontrol.
I am not sure it's allowed to post pone certain messages and allow the WC's messages, maybe the messagepump get's mixed up.. (i don't think so)
Disabling a form is very bad.., later :)