
proper way to use LPVOID's
Eric
Quote:
> I'm been doing some development using the COM facilityies in Dolphin.
> I've let Dolphin import the type libraries and in many cases it
> generates LPVOID's as the parameter type in the vtable for the
> interface...Obviously this means that when the implementor class
> receives a message the type for one of these parameters will be LPVOID.
Dolphin's type-library analyzer should only generate LPVOID parms for
doubly-indirected (typically [output]) arguments. This is where the caller
is expecting to receive a pointer as the result of the method call and
because COM uses the actual function return value for an error/success code,
this can only be achieved using a double indirection.
Quote:
> What I've been struggling with, is how to set the value of the LPVOID
> object so that when the COM interface gets this parameter back filled
> with goodies, he can use them.
> On the interface side I want to send an array of HRESULTS. Therefore I
> created:
> var := StructureArray length: numberOfElements elementClass: HRESULT.
Fine so far. But do watch out for the lifetime of that object.
Quote:
> which ultimately will call (on the imp side):
> DoSomething: var
> Then that comes through on the implementation side as:
> a LPVOID(an ExternalAddress(NULL))
> I thought I could change the value of the the LPVOID (on the imp side)
> to point at a new array by doing something like:
> DoSomething: anLPVOID
> arr := Array new: numberOfElements withAll: S_OK.
> arr at: 1 put: S_FALSE.
> anLPVOID value: arr yourAddress asExternalAddress detach.
If you are actually using Array, then that will fail. Array is an array of
Smalltalk object pointers. Also they cannot be detached, so the Array will
be garbage collected. Also you need to 'detach' the right thing to prevent
the memory being GC'd. Furthermore if the caller is really expecting you to
return an array of HRESULT codes that you are expected to allocate (an
unusual COM interface, but possible), then according to the rules of COM you
must allocate that memory from the COM task memory heap (the caller is
expected to take ownership of it, and so has to know which heap to free it
back to when it has finished with it). What you can't do in this case is to
return a pointer into a Dolphin object, even a ByteArray, because that
memory is still owned by Dolphin and will be GC'd when no further references
to it exist. So taking that all together what you would actually have to do
is:
buffer := COMTaskMemory new: numberOfElements*HRESULT byteSize.
array := StructureArray fromAddress: buffer length: numberOfElements
elementClass: HRESULT.
<...set the values of the elements in the array...>
anLPVOID value: buffer detach.
In this case the StructureArray is only being used as a convenient way to
set the data in the array (though you could also use DWORDArray in this
case). You could also create the StructureArray in Dolphin memory and then
send it #copyToCOMTaskMemory to get a block of memory that you can pass
back.
Even so I would look carefully at the documentation for that COM interface
to see if this is what is really wanted. Array output parameters like this
are quite unusual.
Quote:
> but what comes back on the interface side is:
> a HRESULT(0x871FBC4 - Unrecognised HRESULT - 16r871FBC4)
> What's interesting is that when I use the same technique with a class I
> defined (OPCITEMDEF) instead of HRESULT, this appears to work.
> I'm really pretty baffled. And I feel I've tried virtually every
> possible way to coerce that LPVOID's value (such as trying value value:,
> bytes:... and on and on)
I don't think the problem is your use of LPVOID, so much as confusion over
object lifetimes and the ownership of memory between COM clients and
servers. If the interface one is trying to use is a complicated one (most
COM objects are designed for use by automation clients, and this sort of
complexity does not arise there) then one really can't avoid the need to
read up on the rules of memory management in one of the COM texts.
Regards
Blair