How should one properly create a SAFEARRAY of IUnknowns having an array of
COM interfaces? When I try the most apparent solution such as: iface := IUnknown createObject: 'Scripting.FileSystemObject'. array := Array with: iface. safearray := array asSAFEARRAY the safearray gets the vartype VT_VARIANT, and I need it to be VT_UNKNOWN. The SAFEARRAY class has many other constructor methods, but none of them could create what I want (I know obviously not so much about the safearrays). I've found finally a working solution, but I'm afraid it works only accidentally. Could someone please comment on that: withAllComInterfaces: aSequenceableCollection | result | result := SAFEARRAY length: aSequenceableCollection size vt: IUnknown vt elementClass: IUnknown. 1 to: aSequenceableCollection size do: [:i | result elementAt: (Array with: i + result start - 1) "the normal #at:put: fails" put: ((aSequenceableCollection at: i) queryInterface: IUnknown)]. ^result |
Maxim
You wrote in message news:bbkfmj$a45qj$[hidden email]... > How should one properly create a SAFEARRAY of IUnknowns having an array of > COM interfaces? > When I try the most apparent solution such as: > > iface := IUnknown createObject: 'Scripting.FileSystemObject'. > array := Array with: iface. > safearray := array asSAFEARRAY > > the safearray gets the vartype VT_VARIANT, and I need it to be VT_UNKNOWN. Given that a Smalltalk Array may be of heterogenous content, the only comparable form of SAFEARRAY is an array of VARIANT, hence this is the default conversion. > The SAFEARRAY class has many other constructor methods, but none of them > could create what I want (I know obviously not so much about the > safearrays). > I've found finally a working solution, but I'm afraid it works only > accidentally. Could someone please comment on that: > > withAllComInterfaces: aSequenceableCollection > | result | > result := SAFEARRAY > length: aSequenceableCollection size > vt: IUnknown vt > elementClass: IUnknown. > 1 to: aSequenceableCollection size > do: > [:i | > result elementAt: (Array with: i + result start - 1) "the normal > #at:put: fails" > put: ((aSequenceableCollection at: i) queryInterface: IUnknown)]. > ^result This will actually work fine. I consider the failure of #at:put: when used with COM interface objects to be a bug, which I've recorded as #1285. A fix is below. With that fix installed a slightly simpler form would be: array := SAFEARRAY length: aSequenceableCollection size vt: IUnknown vt. aSequenceableCollection keysAndValuesDo: [:i :each | array at: i put: each]. However it is worth bearing in mind that SAFEARRAYs can actually be strongly typed to a particular interface (not just generic IUnknown or IDispatch). A SAFEARRAY of this form can (with the patch) be constructed as in the following example: randoms := (1 to: 10) collect: [:i | COMRandomStream new]. array := SAFEARRAY length: randoms size interfaceClass: IRandomStream. randoms keysAndValuesDo: [:i :each | each put_Seed: i*9973. array at: i put: each]. array collect: [:each | each next] Regards Blair ----------------- !ExternalStructure class methodsFor! fromObject: anObject "Answer an instance of the receiver whose value is the argument." ^(self newBuffer) value: anObject; yourself! ! !ExternalStructure class categoriesFor: #fromObject:!instance creation!public! ! !COMInterface class methodsFor! fromObject: anObject "Answer an instance of the receiver whose value is the argument." ^anObject queryInterface: self! ! !COMInterface class categoriesFor: #fromObject:!instance creation!public! ! !BSTR class methodsFor! fromObject: anObject ^self fromString: anObject! ! !BSTR class categoriesFor: #fromObject:!instance creation!public! ! !SAFEARRAY methodsFor! at: index put: value "Set the value of the element of the receiver at the specified <integer> index to the specified value, which must be representable by the element class of the receiver. Assumes that the receiver is a single-dimensioned array, if not an error will result. . Note: This isn't likely to be terribly fast!!" self elementAt: (Array with: index + self start - 1) put: (self elementClass fromObject: value). ^value! ! !SAFEARRAY categoriesFor: #at:put:!accessing!public! ! |
Free forum by Nabble | Edit this page |