Theos PowerBasic Museum 2017

Archive => Discussion - Legacy Software (PBWIN 9.0+/PBCC 5.0+) => Topic started by: Petr Schreiber on July 07, 2009, 02:58:09 PM

Title: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: Petr Schreiber on July 07, 2009, 02:58:09 PM
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
Title: Re: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: Petr Schreiber on July 07, 2009, 04:14:35 PM
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
Title: Re: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: José Roca on July 07, 2009, 04:18:42 PM
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.
Title: Re: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: Petr Schreiber on July 07, 2009, 06:00:58 PM
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.
Title: Re: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: José Roca on July 07, 2009, 07:24:06 PM
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.
Title: Re: IWebBrowser2 / IDispatch -> I<Other>, why must I do so?
Post by: Petr Schreiber on July 07, 2009, 08:20:16 PM
That is odd,

but good to know.

Thank you very much again for explanation :)