Newbie COM question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Newbie COM question

John Whittaker
I am having trouble with COM in general, and in particular, it seems, the
IWebDocument interface.  This interface is wrappered by a more abstract
class provided to me by Steve Waring.  If I enter basically the same
sequence of statements as the below method into a workspace, it works.
Specifically, the tables assignment yields a non-nil collection for the URL
I'm loading.  This is what I expect.  But when I execute the method below,
as a method, it fails.  What happens is that when the commented out line is
run, the method seems to hang forever, i.e., the document is never "ready".
The "isReady" message never returns a True result.   If I ctl-break into the
computation and execute the very same statement, "webDoc isReady", it
returns True.  The "isReady" message wraps the "isReady" message of
IWebBrowser2.   This behavior has me stumped.  I thought maybe the Dolphin
process needed to yield some time to the Explorer process, so I added the
Delay you see in the code.  That hasn't done the trick.

What am I missing?


GrabData: aURL

  | webDoc tables delayer |

   delayer  := Delay forMilliseconds: 2000.
   self setURL: aURL.
   webDoc := (SWWebDocument new) initialize.
   webDoc gotoURL: self url.
   delayer wait.
  " [webDoc isReady]  whileFalse: [ ]."   <----------------
   tables := webDoc allTABLEElementsOC.
   self halt.
   tables do: [ :eachTable | | rows |
                        rows :=   eachTable rowsAsElementOC.
                        "rest of code that doesn't work anyway removed" ].


Reply | Threaded
Open this post in threaded view
|

Re: Newbie COM question

Steve Waring-2
Hi John,

#waitForURL: should do what you want, in both a workspace/method.

The control works asynchronously, so if possible, this is the best way to
use the control. For example;
========
webDoc when: #IsReady send: #onIsReady to: self.
webDoc gotoURL: aURL.

and;
onIsReady

MyHTMLStripper strip: webDoc
========

This isnt appropriate all the time; unit testing comes to mind!. Converting
the code you posted to something that just uses base classes/methods;

controlSite := AXControlSite progId: 'Shell.Explorer.2'.
control := controlSite controlUnknown queryInterface: IWebBrowser2.

delayer  := Delay forMilliseconds: 2000.
control navigate: url.
delayer wait.
[control readyState = READYSTATE_COMPLETE "4"]  whileFalse: [ ]."
<----------------
......
self halt.
.......

I believe that the reason you are finding inconsistencies when you evaluate
code in a workspace vs a method is that the workspace code will always be
running in the main GUI process, and when you lock that tight, you also lock
the windows message loop.

I have used the DeferredValue class in my #waitForURL: method. The class has
a good comment, and as you can see, it is designed for a Smalltalk process
to wait syncronously on an asynchronously operation. My waitForURL: method
using only base classes/methods is;

Processor forkMainIfMain.

deferredValue := DeferredValue
    evaluate: [
        control navigate: url.
        [control readyState = 4 "READYSTATE_COMPLETE" ] whileFalse.
        control readyState = 4]
    at: Processor userBackgroundPriority.

deferredValue value.

If you dont use, Processor forkMainIfMain, then evaluating the rest of the
code from the main GUI process will still mean that the main GUI process
will wait on the deferredValue value, which stops the control from
delivering a value. You should find that "deferredValue value" will return
true in both a workspace and a method. As for why blocking the main GUI
process stops the control from responding ... thats one for Blair :)


Hope this helps,
Steve