• Welcome to Theos PowerBasic Museum 2017.

IWebBrowser2 / IDispatch -> I<Other>, why must I do so?

Started by Petr Schreiber, July 07, 2009, 02:58:09 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Petr Schreiber

Dear José,

today, thanks to your IE Automation tutorial, I finally managed to write program to reboot my router. Thanks a lot :)

But there is one thing I do not get in COM programming with IWebBrowser2, maybe you could explain more on this topic.

To retrieve IHTMLDocument2, I have to do this:

Code #1

LOCAL pDispatch       AS IDispatch
LOCAL pIHTMLDocument2 AS IHTMLDocument2

pDisp = pIWebBrowser2.Document
IF ISNOTHING(pDisp) THEN EXIT FUNCTION
 
pIHTMLDocument2 = pDispatch
IF ISNOTHING(pIHTMLDocument2) THEN EXIT FUNCTION


What is the exact reason I cannot do directly:
Code #2

LOCAL pIHTMLDocument2 AS IHTMLDocument2

pIHTMLDocument2 = pIWebBrowser2.Document
IF ISNOTHING(pIHTMLDocument2) THEN EXIT FUNCTION


What does the following line in original code actually change?:

pIHTMLDocument2 = pDispatch


In Code #1 I retrieve IDispatch reference, then assign it to IHTMLDocument2 object variable. Why do you think this is not possible directly?

To me assigning the reference to dispatch variable and then to IHTMLDocument2 seems just longer way to direct assignment.
Is it like that to make possible compiler check that I am retrieving value to variable of correct type? I would guess this is good for "safe code", but why I am then allowed to assign to IHTMLDocument2 variable?

I am used from OOP programming in other languages, that I can assign object of inherited class to parent class object variable, but not the opposite.

That is:
- IHTMLDocument2( inheriting IDispatch ) to IDispatch -> OK
- IDispatch to IHTMLDocument2( inheriting IDispatch ) -> NO

PB seems to support the second way, which is cool, but I am not sure why it works and how it works :)
Any info on this topic would be highly appreciated!


Thanks,
Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Petr Schreiber

In your IE automation thread I found:
Quote
With PowerBASIC, the following assignment performs a call to IUnknown.QueryInterface. It is equivalent to pIHTMLDocument2.QueryInterface (IID_IHTMLDocument3, BYVAL VARPTR(pIHTMLDocument3))

I guess this is the thing PB does during the assignment in my case above too?


Thanks,
Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

José Roca

Quote
What is the exact reason I cannot do directly:

LOCAL pIHTMLDocument2 AS IHTMLDocument2

pIHTMLDocument2 = pIWebBrowser2.Document
IF ISNOTHING(pIHTMLDocument2) THEN EXIT FUNCTION

You can. I'm doing that in many of the examples that I have posted.

Quote
What does the following line in original code actually change?:

pIHTMLDocument2 = pDispatch

It calls QueryInterface asking for the IHTMLDocument2 interface.

Petr Schreiber

#3
Hi José,

thanks for the information ... but then I do not understand why does this code GPF with %WANTGPF set to 1:

#COMPILE EXE
#DIM ALL
#INCLUDE "exdisp.inc"
#INCLUDE "mshtml.inc"

%WANTGPF = 1  ' -- Change to 0 for no error

FUNCTION PBMAIN () AS LONG

  LOCAL pIWebBrowser2            AS IWebBrowser2
  LOCAL pIHTMLDocument2          AS IHTMLDocument2
  LOCAL pIHTMLElementCollection  AS IHTMLElementCollection

  ' Create a new instance of Internet Explorer
  pIWebBrowser2 = NEWCOM "InternetExplorer.Application"
  IF ISNOTHING(pIWebBrowser2) THEN EXIT FUNCTION

  ' Make it visible
  pIWebBrowser2.Visible = 1
  ' Navigate to Google
  pIWebBrowser2.Navigate UCODE$("http://www.google.com")
  ' Wait until the page is ready
  WHILE (pIWebBrowser2.ReadyState <> %READYSTATE_COMPLETE)
     apiSleep 3
  WEND

  #IF %WANTGPF
    pIHTMLDocument2 =  pIWebBrowser2.Document
    IF ISNOTHING(pIHTMLDocument2) THEN EXIT FUNCTION
   
  #ELSE
    local pDispatch as IDispatch
    pDispatch = pIWebBrowser2.Document
    IF ISNOTHING(pDispatch) THEN EXIT FUNCTION
   
    pIHTMLDocument2 =  pDispatch
    IF ISNOTHING(pIHTMLDocument2) THEN EXIT FUNCTION
 
  #ENDIF

  msgbox "Is pIHTMLDocument2 object?: "+iif$(isobject(pIHTMLDocument2), "YES", "NOPE")
  '  Get all forms
  pIHTMLElementCollection  = pIHTMLDocument2.Forms         ' <- here it will fail if %WANTGPF = 1
  IF ISNOTHING(pIHTMLElementCollection ) THEN EXIT FUNCTION
 
  msgbox "All went fine..."
           
  ' ... here would follow other code ...

END FUNCTION


Can you confirm problem with the code above or is my PC ill? :) Maybe I overlooked something.
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

José Roca

It GPFs, but it works when the WebBrowser Control is embedded.

Who knows what the WebBrowser Controls is doing when we use "InternetExplorer.Application" instead of "Shell.Explorer", used for embedding?

Apparently, it is returning a pointer to the IHTMLDocument interface instead of the IHTMLDocument2 interface, and it GPFs because the Forms property isn't available in IHTMLDocument.

Petr Schreiber

That is odd,

but good to know.

Thank you very much again for explanation :)
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com