Hi.
I'm trying to implement SQL-DMO wrapper classes. SQL-DMO has some event callback, but it derrived from IUnknown. Dolphin's EventSink mechanism is seems only focused on IDispatch interface, so, I'm troubled with that. Anybody suggest me! |
"handjive" <[hidden email]> wrote in message
news:[hidden email]... > Hi. > > I'm trying to implement SQL-DMO wrapper classes. > SQL-DMO has some event callback, but it derrived from IUnknown. > Dolphin's EventSink mechanism is seems only focused on IDispatch > interface, so, I'm troubled with that. > > Anybody suggest me! The class comment of AXEventSink does give a hint how to do this. Essentially it comes down to implementing a COM interface (the event interface) against an object in Dolphin. A custom interface event sink will be significantly less complicated than AXEventSink itself, but you'll have to implement the event interface methods to perform the actions you need, rather than having the inbound calls generically converted to Smalltalk events. Since the overhead of IDispatch will be avoided, however, the solution will have much higher performance. The easiest way to do this is to subclass COMInterfaceImp (see e.g. http://www.object-arts.co.uk/wiki/html/Dolphin/DefiningTheSmalltalkComponentClasses.htm, or much more detailed but as yet incomplete http://object-arts.com/Lib/Downloads/Misc/DevelopingCOMComponents.pdf), although you can implement COM interfaces on any Dolphin object with a little more effort. Assuming that the event interfaces are exposed as connection points, wiring up your implementation to the SQL-DMO object will follow the same pattern as in AXEventSink>>connect:, i.e. SQLDMOServerSinkImp>>connect: anIUnknown "Connect the receiver to appropriate connection point of the the COM object, anIUnknown. Answer the advise cookie. Note: If the Active-X object has been implemented using ATL, which is common, then one of these standard error codes may result: 0x80040200 - CONNECT_E_NOCONNECTION This indicates that there is no such connection point on the source. 0x80040202 This indicates that the source has queried back for the sink interface off the receiver and received an E_NOINTERFACE response. This should not occur because of the receiver's implementation of #supportedInterfaces. " | container iidSource | self disconnect. container := anIUnknown queryInterface: IConnectionPointContainer. connector := container findConnectionPoint: SQLDMOServerSink. cookie := connector advise: (self server queryInterface: SQLDMOServerSink). ^cookie Assuming that cookie is defined as an instance variable, and #disconnect has been copied from AXEventSink. I hope this gets you started. Regards Blair |
Blair
Thanks for your suggestion. I tryed, but can not breaking it. Let me ask you point me out the mistakes? *Make a class named "AXEventSinkDiscoverie" as subclass of COMInterfaceImp. *Imprement methods below: AXEventSinkDiscoverie class>>clsid "ID for BackupSink from typelib" ^CLSID fromString: '{10021F09-E260-11CF-AE68-00AA004A34D5}' AXEventSinkDiscoverie>>supportedInterfaces ^Array with: SQLDMOBackupSink AXEventSinkDiscoverie>>connect: anIUnknown |container| self disconnect. container := anIUnknown queryInterface: IConnectionPointContainer. connector := container findConnectionPoint: SQLDMOBackupSink. cookie := connector advise: (self server queryInterface: SQLDMOBackupSink). ^cookie *Create instance of "_Backup" and, try to connect. aBackup := IDispatch creteObject: 'SQLDMO.Backup'. sink := AXEventSinkDiscoverie new. sink connect: aBackup. Finaly, HRESULTError said, 'Interface does not supported'... |
In reply to this post by Blair McGlashan-3
Blair
Thanks for your suggestion. I tryed, but can not breaking it. Let me ask you point me out the mistakes? *Make a class named "AXEventSinkDiscoverie" as subclass of COMInterfaceImp. *Imprement methods below: AXEventSinkDiscoverie class>>clsid "ID for BackupSink from typelib" ^CLSID fromString: '{10021F09-E260-11CF-AE68-00AA004A34D5}' AXEventSinkDiscoverie>>supportedInterfaces ^Array with: SQLDMOBackupSink AXEventSinkDiscoverie>>connect: anIUnknown |container| self disconnect. container := anIUnknown queryInterface: IConnectionPointContainer. connector := container findConnectionPoint: SQLDMOBackupSink. cookie := connector advise: (self server queryInterface: SQLDMOBackupSink). ^cookie *Create instance of "_Backup" and, try to connect. aBackup := IDispatch creteObject: 'SQLDMO.Backup'. sink := AXEventSinkDiscoverie new. sink connect: aBackup. Finaly, HRESULTError said, 'Interface does not supported'... |
"handjive" <[hidden email]> wrote in message
news:[hidden email]... > Blair > > Thanks for your suggestion. I tryed, but can not breaking it. > Let me ask you point me out the mistakes? It was a good effort, and you're almost there. You were lucky I read your post at the start of my lunch break - see below (or download from ftp://object-arts.com/Lib/Downloads/Misc/SQLDMOEvents.zip). :-) Regards Blair P.S. In the attached I've implemented a slightly more generic solution that encapsulates the custom event subscription mechanism into a general class, which I've then used in another class where I've implemented stuff specific to this case. See SQLDMOBackupHost class>>example1. Note that it assumes you've generated an SQLDMO package using the AX Component Wizard ------------------------- | package | package := Package name: 'SQLDMO Events'. package paxVersion: 0; basicComment: 'Example of using SQL-DMO, including sinking events. Copyright (c) Object Arts Ltd, 2004'. package classNames add: #AXCustomEventSink; add: #SQLDMOBackupHost; yourself. package binaryGlobalNames: (Set new yourself). package globalAliases: (Set new yourself). package allResourceNames: (Set new yourself). package setPrerequisites: (IdentitySet new add: '..\..\..\Dolphin\ActiveX\Connection Points\ActiveX Connection Points'; add: '..\..\..\Dolphin\Base\Dolphin'; add: '..\..\..\Dolphin\ActiveX\COM\OLE COM'; add: '..\..\..\..\SQLDMO'; yourself). package! COMInterfaceImp subclass: #AXCustomEventSink instanceVariableNames: 'interfaceClass server connector cookie' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! COMInterfaceImp subclass: #SQLDMOBackupHost instanceVariableNames: 'backup backupSink' classVariableNames: '' poolDictionaries: 'SQLDMOConstants' classInstanceVariableNames: ''! AXCustomEventSink guid: (GUID fromString: '{F07D81A3-9BAE-45B6-805C-1F83C206C10E}')! AXCustomEventSink comment: 'AXCustomEventSink is a Smalltalk COM object that provides the basic mechanism for subscribing to Active-X events through a connection point where the event interface is not IDispatch based. You can use it in conjunction with another Smalltalk COM object that implements the actual interface methods (in which case the ''server'' should be set to reference that object), or subclass it and implement the interface in that subclass (in which case ''server'' should be initialized to reference ''self''). See also AXEventSink. Instance Variables: interfaceClass <Class> - IUnknown subclass that represents the event interface. server <COMObject>. The implementor of the interfaceClass, possibly this object (in a subclass) connector <IConnectionPoint>. Server''s connection point. cookie <integer>. Cookie supplied by server when subscribing, needed to unsubscribe. '! !AXCustomEventSink categoriesForClass!COM-Implementations! ! !AXCustomEventSink 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 ^interfaceClass! interfaceClass: anObject "Set the value of the receiver's ''interfaceClass'' instance variable to the argument, anObject." interfaceClass := anObject! server ^server! server: anObject "Set the server object on behalf of which the receiver is 'sinking' an interface. Any invocations of methods in the interface (i.e. arriving events) will be forwarded to this object, assuming the the server is set before the interface is queried." server := anObject! supportedInterfaces ^Array with: self interfaceClass! ! !AXCustomEventSink categoriesFor: #connect:!operations!public! ! !AXCustomEventSink categoriesFor: #disconnect!operations!public! ! !AXCustomEventSink categoriesFor: #interfaceClass!public! ! !AXCustomEventSink categoriesFor: #interfaceClass:!accessing!public! ! !AXCustomEventSink categoriesFor: #server!accessing!public! ! !AXCustomEventSink categoriesFor: #server:!accessing!public! ! !AXCustomEventSink categoriesFor: #supportedInterfaces!constants!public! ! SQLDMOBackupHost guid: (GUID fromString: '{2319F8E5-13B1-490A-9083-6FD1371BFD08}')! SQLDMOBackupHost comment: 'Hosts for SQLDMO backup service and also sinks events from that service. At present it doesn''t do anything useful with the events, but these could be translated to Smalltalk events, etc. N.B. Watch out for object lifetime issues. There is effectively a circular reference between any SQLDMO objects hosted by the receiver, and the receiver because the receiver is sinking events from those objects. i.e. it holds an interface pointer to the SQLDMO object, which in turn is holding an interface pointer to the receiver through which it passes back events. This circular reference cannot be cleared up by garbage collection (because COM uses plain reference counting), so it must be explicitly broken, e.g. by sending #free to this object.'! !SQLDMOBackupHost categoriesForClass!COM-Implementations! ! !SQLDMOBackupHost methodsFor! Complete: aString "Helpstring: Backup has completed." Transcript print: 'Backup Completed: '; display: aString; cr. ^S_OK! free backupSink notNil ifTrue: [backupSink disconnect. backupSink := nil]. backup notNull ifTrue: [backup free. backup := nil]! interface backup isNull ifTrue: [backup := SQLDMO_Backup new. backupSink := (AXCustomEventSink new) server: self; interfaceClass: SQLDMOBackupSink; yourself. backupSink connect: backup]. ^backup! NextMedia: aString "Helpstring: Request for next volume in backup" Transcript nextPutAll: 'Backup, Next Media: '; display: aString; cr. ^S_OK! PercentComplete: aString Percent: anInteger "Helpstring: Percent completion message during Backup process" Transcript nextPutAll: 'Backup Progress: '; display: aString; nextPut: $(; print: anInteger; nextPutAll: '%)'; cr. ^S_OK! supportedInterfaces ^Array with: SQLDMOBackupSink! ! !SQLDMOBackupHost categoriesFor: #Complete:!COM Interfaces-BackupSink!public! ! !SQLDMOBackupHost categoriesFor: #free!public!realizing/unrealizing! ! !SQLDMOBackupHost categoriesFor: #interface!accessing!public! ! !SQLDMOBackupHost categoriesFor: #NextMedia:!COM Interfaces-BackupSink!public! ! !SQLDMOBackupHost categoriesFor: #PercentComplete:Percent:!COM Interfaces-BackupSink!public! ! !SQLDMOBackupHost categoriesFor: #supportedInterfaces!constants!public! ! !SQLDMOBackupHost class methodsFor! example1 | backup dmo server | dmo := SQLDMOBackupHost new. backup := dmo interface. backup backupSetName: 'Dolphin Test'. backup database: 'Northwind'. backup action: SQLDMOBackup_Database. backup files: 'c:\TestSQLBackup'. server := SQLDMO_SQLServer new. server loginSecure: true. server connect. backup sqlBackup: server. server close. dmo free! ! !SQLDMOBackupHost class categoriesFor: #example1!examples!public! ! |
Blair
Thank you for your supports, and I apologize. Your first suggestion is sufficient for break my probrem, but I could't use that well. Because I touched and modified some around of COM classes, and falled into a confusion. At first, Your program did not work. But with fresh image, its work well :-( |
Free forum by Nabble | Edit this page |