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" ]. |
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 |
Free forum by Nabble | Edit this page |