I should start by admitting that I don't really know what I'm doing here, so it
is very likely that I /am/ doing something stupid... I've been trying to use the asynchronous notifications provided by IWinHttpRequest objects, but my attempts just crash Dolphin (D5 or D6). I've generated the wrappers for "Microsoft WinHTTP Services, version 5.1", thus creating classes IWinHttpRequest and IWinHttpRequestEvents (for more background see the "HTTP/S Post Get Head" thread). With them installed, I can download URLs provided I don't try to monitor the asynchronous progress events. This is what I'm trying: target := Object new. sink := AXEventSink target: target sourceTypeInfo: IWinHttpRequestEvents typeInfo. request := IWinHttpRequest new. sink connect: request. request open: 'GET' url: 'http://www.microsoft.com/' async: true. request send. That /seems/ to work up to the point where I invoke #send. At that point I get a sequence of invalid reads of addresses like 10, then a few invalid writes of arbitrary-looking addresses, and then the image crashes. (With a crash dump, but the info therein does not appear relevant). -- chris |
Chris Uppal wrote:
> I should start by admitting that I don't really know what I'm doing here, so it > is very likely that I /am/ doing something stupid... > > I've been trying to use the asynchronous notifications provided by > IWinHttpRequest objects, but my attempts just crash Dolphin (D5 or D6). > > I've generated the wrappers for "Microsoft WinHTTP Services, version 5.1", thus > creating classes IWinHttpRequest and IWinHttpRequestEvents (for more background > see the "HTTP/S Post Get Head" thread). With them installed, I can download > URLs provided I don't try to monitor the asynchronous progress events. > > This is what I'm trying: > > target := Object new. > sink := AXEventSink > target: target > sourceTypeInfo: IWinHttpRequestEvents typeInfo. > request := IWinHttpRequest new. > sink connect: request. > request open: 'GET' url: 'http://www.microsoft.com/' async: true. > request send. > > That /seems/ to work up to the point where I invoke #send. At that point I > get a sequence of invalid reads of addresses like 10, then a few invalid writes > of arbitrary-looking addresses, and then the image crashes. (With a crash > dump, but the info therein does not appear relevant). I have the same errors. I am pretty much clueless in this area - but reading the documention: AXEventSink implements the IDispatch interface (Dolphin class comment) but in MSDN ' IWinHttpRequestEvents interface inherits the methods of the IUnknown interface' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winhttp/http/iwinhttprequest_setcredentials.asp Edward Stow |
In reply to this post by Chris Uppal-3
I wrote:
> I've been trying to use the asynchronous notifications provided by > IWinHttpRequest objects, but my attempts just crash Dolphin (D5 or D6). I've made some progress, but I still don't know whether the problem was a mistake on my part, or a bug in either the Dolphin COM stuff or in the HTML component. Edward's suggestion (thanks Edward!), pushed me to try a different track. I created a normal COM implementation of IWinHttpRequestEvents, WinHttpWatcher, as a trivial subclass of COMInterfaceImp which traces the progress events to the Transcript (I'll post the code if anyone wants to see it). I didn't #register that class or #registerClassFactory since I don't think it's necessary (or even correct) for this application[*]. Maybe I'm wrong, if so then I hope someone will please point it out. With that created, I can do: watcher := WinHttpWatcher new queryInterface: IWinHttpRequestEvents. request := IWinHttpRequest new. container := request queryInterface: IConnectionPointContainer. connector := container findConnectionPoint: IWinHttpRequestEvents. cookie := connector advise: watcher. request open: 'GET' url: 'http://www.microsoft.com/' async: true. request send. --- pause for a bit --- connector unadvise: cookie. watcher free. request free. And that works! So I am, basically, happy -- but there are a few puzzles... The first thing that's puzzling is that the code for setting up the connection point is copied almost verbatim from AXEventSink, so why doesn't an AXEventSink work here ? One clue is that, if I stick a bit of tracing into WinHttpWatcher's #queryInterface, I can see that the HTML object doesn't QueryInterface() the handle that it is passed -- it seems to just assume that it is in fact a pointer to an IWinHttpRequestEvents. I assume that's a bug in the HTTP object. So maybe the crash is because AXEventSink passes an IDispatch ? So I tried moving WinHttpWatcher to be a subclass of AXDualImp (changing the code accordingly -- a remarkably trivial change, btw ;-), and tried the above example again, but changing the first line to: watcher := WinHttpWatcher new queryInterface: IDispatch. But that still worked. So it seems that the HTTP object is happy enough to get an IUnknown that is in fact the IDispatch part of a dual interface, but is not happy to get the one supplied by an AXEventSink. So, is this a flaw in AXEventSink which is being exposed by the bug in the HTTP object, or only a bug in the HTTP object, or am I daft expecting this to work ? -- chris [*] Actually, at one point I did have the class #registerClassFactory, in a D6 image, and then ran something like the above example in a D5 image, but changing it so that: watcher := IWinHttpRequestEvents new. And that also worked, but the tracing for the D5 operation was written to the D6 image's Transcript -- which is exactly what you'd expect, but it still looked very odd ;-) |
Chris,
Did you see this post - this seems to be a model for what may be needed? http://groups.google.com/group/comp.lang.smalltalk.dolphin/browse_thread/thread/951f2c38dcc38a/fb29b429b946d1ee?lnk=gst&q=iUnknown&rnum=1#fb29b429b946d1ee Edward Stow Chris Uppal wrote: > I wrote: > > > I've been trying to use the asynchronous notifications provided by > > IWinHttpRequest objects, but my attempts just crash Dolphin (D5 or D6). > > I've made some progress, but I still don't know whether the problem was a > mistake on my part, or a bug in either the Dolphin COM stuff or in the HTML > component. > > Edward's suggestion (thanks Edward!), pushed me to try a different track. I > created a normal COM implementation of IWinHttpRequestEvents, WinHttpWatcher, > as a trivial subclass of COMInterfaceImp which traces the progress events to > the Transcript (I'll post the code if anyone wants to see it). > > I didn't #register that class or #registerClassFactory since I don't think it's > necessary (or even correct) for this application[*]. Maybe I'm wrong, if so > then I hope someone will please point it out. > > With that created, I can do: > > watcher := WinHttpWatcher new queryInterface: IWinHttpRequestEvents. > request := IWinHttpRequest new. > > container := request queryInterface: IConnectionPointContainer. > connector := container findConnectionPoint: IWinHttpRequestEvents. > cookie := connector advise: watcher. > > request open: 'GET' url: 'http://www.microsoft.com/' async: true. > request send. > > --- pause for a bit --- > > connector unadvise: cookie. > watcher free. > request free. > > And that works! So I am, basically, happy -- but there are a few puzzles... > > The first thing that's puzzling is that the code for setting up the connection > point is copied almost verbatim from AXEventSink, so why doesn't an AXEventSink > work here ? > > One clue is that, if I stick a bit of tracing into WinHttpWatcher's > #queryInterface, I can see that the HTML object doesn't QueryInterface() the > handle that it is passed -- it seems to just assume that it is in fact a > pointer to an IWinHttpRequestEvents. I assume that's a bug in the HTTP object. > So maybe the crash is because AXEventSink passes an IDispatch ? So I tried > moving WinHttpWatcher to be a subclass of AXDualImp (changing the code > accordingly -- a remarkably trivial change, btw ;-), and tried the above > example again, but changing the first line to: > > watcher := WinHttpWatcher new queryInterface: IDispatch. > > But that still worked. So it seems that the HTTP object is happy enough to get > an IUnknown that is in fact the IDispatch part of a dual interface, but is not > happy to get the one supplied by an AXEventSink. > > So, is this a flaw in AXEventSink which is being exposed by the bug in the HTTP > object, or only a bug in the HTTP object, or am I daft expecting this to work ? > > -- chris > > > [*] Actually, at one point I did have the class #registerClassFactory, in a D6 > image, and then ran something like the above example in a D5 image, but > changing it so that: > watcher := IWinHttpRequestEvents new. > And that also worked, but the tracing for the D5 operation was written to the > D6 image's Transcript -- which is exactly what you'd expect, but it still > looked very odd ;-) |
Edward,
> Did you see this post - this seems to be a model for what may be > needed? > > http://groups.google.com/group/comp.lang.smalltalk.dolphin/browse_thread/thread/951f2c38dcc38a/fb29b429b946d1ee?lnk=gst&q=iUnknown&rnum=1#fb29b429b946d1ee No, I hadn't seen it (or had forgotten it). Thanks. It seems I had managed to reinvent something pretty close to that (nice to have the confirmation ;-) I guess that the reason the first version crashes is that ACEventSink /only/ implements IDispatch, and that the HTTP component doesn't bother to check what kind of IUnknown it is passed. -- chris |
Following is my final take on implementing an IUnknown event sink.Two
classes: AXIUnknownEventSink - implements #connect:, #disconnect IWinHttpRequestEventsSink implements the OnXXX methods. See IWinHttpRequestEventsSink class>>exampleRequest for sample usage. You must use disconnect on the sink object to break the circular references between the sink and the request object. "Filed out from Dolphin Smalltalk X6"! COMInterfaceImp subclass: #AXIUnknownEventSink instanceVariableNames: 'connector cookie' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! AXIUnknownEventSink guid: (GUID fromString: '{A329F9AE-B31E-4312-BEDA-512356EEBA61}')! AXIUnknownEventSink comment: ''! !AXIUnknownEventSink categoriesForClass!Unclassified! ! !AXIUnknownEventSink methodsFor! connect: anIUnknown | container | self disconnect. container := anIUnknown queryInterface: IConnectionPointContainer. connector := container findConnectionPoint: self interfaceClass. cookie := connector advise: (self server queryInterface: IUnknown). "Transcript nextPutAll: 'Connected '; print: self; cr." ^cookie! disconnect "Disconnect the receiver from the connection point to which it has previously been connected." connector notNull ifTrue: ["Transcript nextPutAll: 'Disconnecting '; print: self; cr." connector Unadvise: cookie. connector free. connector := nil]! interfaceClass ^self class interfaceClass! supportedInterfaces ^Array with: self interfaceClass! ! !AXIUnknownEventSink categoriesFor: #connect:!public! ! !AXIUnknownEventSink categoriesFor: #disconnect!public! ! !AXIUnknownEventSink categoriesFor: #interfaceClass!public! ! !AXIUnknownEventSink categoriesFor: #supportedInterfaces!public! ! !AXIUnknownEventSink class methodsFor! interfaceClass ^self subclassResponsibility! ! !AXIUnknownEventSink class categoriesFor: #interfaceClass!public! ! AXIUnknownEventSink subclass: #IWinHttpRequestEventsSink instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! IWinHttpRequestEventsSink guid: (GUID fromString: '{F1F9763B-FFA6-4426-ADDD-86DBE4FEE08B}')! IWinHttpRequestEventsSink comment: ''! !IWinHttpRequestEventsSink categoriesForClass!Unclassified! ! !IWinHttpRequestEventsSink methodsFor! OnError: errorNumber errorDescription: errorDescription "Invoke the OnResponseStart() method of the COM object." Transcript show: 'OnError called: errorNumber ' , errorNumber printString , ' errorDescription ' , errorDescription printString; cr! OnResponseDataAvailable: data Transcript show: 'OnResponseDataAvailable called ' , 'data: ' , data printString; cr.! OnResponseFinished "Invoke the OnResponseFinished() method of the COM object" Transcript show: 'OnResponseFinished called'; cr! OnResponseStart: status contentType: contentType "Invoke the OnResponseStart() method of the COM object." Transcript show: 'OnResponseStart called: status ' , status printString , ' contentType ' , contentType printString; cr! ! !IWinHttpRequestEventsSink categoriesFor: #OnError:errorDescription:!public! ! !IWinHttpRequestEventsSink categoriesFor: #OnResponseDataAvailable:!public! ! !IWinHttpRequestEventsSink categoriesFor: #OnResponseFinished!public! ! !IWinHttpRequestEventsSink categoriesFor: #OnResponseStart:contentType:!public! ! !IWinHttpRequestEventsSink class methodsFor! exampleRequest " self exampleRequest " | request sink | request := IWinHttpRequest new. sink := self new. sink connect: request. request open: 'GET' url: 'http://www.google.com/' async: true. request send. ! interfaceClass ^IWinHttpRequestEvents! ! !IWinHttpRequestEventsSink class categoriesFor: #exampleRequest!public! ! !IWinHttpRequestEventsSink class categoriesFor: #interfaceClass!public! ! |
Free forum by Nabble | Edit this page |