I am trying to create a simple COM server for the following method in
a subclass of AXDualImp named 'SampleApplication' where I want to return an instance of 'SampleUnit' (also a subclass of AXDualImp). The following method works (but is it correct?), but when the client releases the Interface (the referenceCount = 0), the server instance of SampleUnit's interface still has a referenceCount = 1 and therefore is hanging around in the image (COMObjectStub registry) (even though it should have (I believe) a referenceCount of 0). Unit: unitFloat unitString: unitString Unit: unit "Private - Invoke the Unit() method of the COM object. Helpstring: 'Return aUnit' HRESULT __stdcall Unit( [in] VARIANT unitFloat, [in] VARIANT unitString, [out, retval] VARIANT* Unit);" | newValue | newValue := SampleUnit unitValue: unitFloat asObject unitType: unitString asObject. unit value: newValue interface asVariant. ^S_OK I have created a zip file that has IDL and PAC file (Interface classes generated, AXDualImp subclasses implemented, and a Test Class that demonstrates the recreats the problem using Dolphin 5.01. Here is the revelant portion of the IDL. [ object, uuid(51895187-3D52-4474-8E33-62F4A344E300), dual, helpstring("COM Server ActiveX Interface"), pointer_default(unique), oleautomation, nonextensible ] interface _Application : IDispatch { [id(1), helpstring("Return aUnit")] HRESULT Unit( [in] VARIANT unitFloat, [in] VARIANT unitString, [out, retval] VARIANT* unit); }; [ object, uuid(765540BC-2729-4103-8A07-B75DEE31E220), dual, helpstring("Unit"), pointer_default(unique), oleautomation, nonextensible ] interface _Unit : IDispatch { [id(1), propget] HRESULT unitValue( [out, retval] VARIANT* unitFloat); [id(2), propget] HRESULT unitType( [out, retval] VARIANT* unitString); [id(4), helpstring("Add Units")] HRESULT add( [in] VARIANT addUnit, [out, retval] VARIANT* unit); }; Thanks, Scott |
Scott,
> Unit: unitFloat unitString: unitString Unit: unit > "Private - Invoke the Unit() method of the COM object. > Helpstring: 'Return aUnit' > > HRESULT __stdcall Unit( > [in] VARIANT unitFloat, > [in] VARIANT unitString, > [out, retval] VARIANT* Unit);" > > | newValue | > newValue := SampleUnit unitValue: unitFloat asObject unitType: > unitString asObject. > unit value: newValue interface asVariant. > ^S_OK **If** I'm reading this correctly, it looks like you are trying to make COM return an object by value rather than allowing the interface pointer to act as a proxy in one process for the object/server in another. My advice would be to leave the functionality in SampleUnit and expose just enough via IDL to allow a client in another process to access the behavior via an interface pointer. Is that helpful, or am I missing your point? Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
How would you define the IDL and the Smalltalk server method to return
the interface. That sounds like what I am trying to do. Any help would be great, Scott "Bill Schwab" <[hidden email]> wrote in message news:<ajjath$1b1e7f$[hidden email]>... > Scott, > > > Unit: unitFloat unitString: unitString Unit: unit > > "Private - Invoke the Unit() method of the COM object. > > Helpstring: 'Return aUnit' > > > > HRESULT __stdcall Unit( > > [in] VARIANT unitFloat, > > [in] VARIANT unitString, > > [out, retval] VARIANT* Unit);" > > > > | newValue | > > newValue := SampleUnit unitValue: unitFloat asObject unitType: > > unitString asObject. > > unit value: newValue interface asVariant. > > ^S_OK > > **If** I'm reading this correctly, it looks like you are trying to make COM > return an object by value rather than allowing the interface pointer to act > as a proxy in one process for the object/server in another. My advice would > be to leave the functionality in SampleUnit and expose just enough via IDL > to allow a client in another process to access the behavior via an interface > pointer. Is that helpful, or am I missing your point? > > Have a good one, > > Bill |
Scott,
> > **If** I'm reading this correctly, it looks like you are trying to make COM > > return an object by value rather than allowing the interface pointer to act > > as a proxy in one process for the object/server in another. My advice would > > be to leave the functionality in SampleUnit and expose just enough via IDL > > to allow a client in another process to access the behavior via an interface > > pointer. Is that helpful, or am I missing your point? > How would you define the IDL and the Smalltalk server method to return > the interface. That sounds like what I am trying to do. My mission is now to talk you out of it :) If you have a Smaltalk app on the client side, then it can do the work for itself. If you don't, then it won't know how to make sense of the object you "return" to it. Instead, you should focus on defining enough behavior in your interface(s) to allow the caller to request the services with the server object "remaining in place". COM is a very nice technology (though beware of DCOM and its temporal tantrums) for crossing boundaries between binary executables. As such, design for it is different than for traditional OO systems. Generally (if not always) you will find that objects with behavior do not get returned by value; instead, one passes interface pointers to them and the objects themselves don't move. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
>
> My mission is now to talk you out of it :) If you have a Smaltalk app on > the client side, then it can do the work for itself. If you don't, then it > won't know how to make sense of the object you "return" to it. Instead, you > should focus on defining enough behavior in your interface(s) to allow the > caller to request the services with the server object "remaining in place". Most of core objects do "remain in place", just this one class of object get a new instance for each method sent to it, (which can be then used as an input to another method). So I believe I need the object to remain temporilly until released by the client. > COM is a very nice technology (though beware of DCOM and its temporal > tantrums) for crossing boundaries between binary executables. As such, > design for it is different than for traditional OO systems. Generally (if > not always) you will find that objects with behavior do not get returned by > value; instead, one passes interface pointers to them and the objects > themselves don't move. So can you provide me with a sample of IDL returning an interface pointer as well as the smalltalk com server method on how to pass that interface pointer out? Thanks, Scott |
Looking at Microsoft Office typelib as an example of how to define IDL
that returns an Interface. The following is an example of how I am defining my IDL. I believe that the IDL is correct and compiles. interface _Application : IDispatch { [id(1), helpstring("Return aUnit")] HRESULT Unit( [in] VARIANT unitFloat, [in] BSTR unitString, [out, retval] _Unit** unit); }; So I have SampleApplication (implements _Application) and SampleUnit (implements _Unit) as subclasses of AXDualImp. Following is my current implementation: SampleApplication Unit: unitFloat unitString: unitString unit: unit "Private - Invoke the unit() method of the COM object. Helpstring: 'Return aUnit' HRESULT __stdcall unit( [in] VARIANT unitFloat, [in] BSTR unitString, [out, retval] _Unit** unit);" | newValue | newValue := SampleUnit unitValue: unitFloat asObject unitType: unitString. unit value: newValue interface. ^S_OK This method raises an error "_Unit does not understand #asInteger. 'unit' is an instance of LPVOID, but the sender method defined that parm to be "_Unit newPointer". How do I return the interface for an instance of SampleUnit? Please help, Scott |
Scott,
> as an example of how to define IDL > that returns an Interface. Take a look at Rogerson's Inside COM, Chapter 10 in the "Structures in IDL section" - it's page 259 in my copy, and not far after the discussion of size_is. In that general area, you'll find a description of iid_is, which is a nicer way to return an interface. Sadly, I don't remember whether it allows you to be "Automation compatible", but using a pointer to your own interface certainly will not be Automation compatible. Making a long story short, Automation compatible interfaces can be marshaled by simply registering an associated type library; otherwise, you'll have to compile a custom marshaling DLL. The latter isn't too difficult, and Rogerson describes how to get started. Have a good one, Bill --- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by Scott
"Scott" <[hidden email]> wrote in message
news:[hidden email]... >... > Following is my current implementation: > > SampleApplication > Unit: unitFloat unitString: unitString unit: unit > "Private - Invoke the unit() method of the COM object. > Helpstring: 'Return aUnit' > > HRESULT __stdcall unit( > [in] VARIANT unitFloat, > [in] BSTR unitString, > [out, retval] _Unit** unit);" > > | newValue | > newValue := SampleUnit unitValue: unitFloat asObject unitType: > unitString. > unit value: newValue interface. > ^S_OK > > This method raises an error "_Unit does not understand #asInteger. > 'unit' is an instance of LPVOID, but the sender method defined that > parm to be "_Unit newPointer". How do I return the interface for an > instance of SampleUnit? > See the example package 'EnumRECT', specifically the method EnumRECT>>clone:. The general pattern is also evident in the base COM support framework (see for example COMObjectStub>>innerQueryInterface:ppvObject: and COMClassFactory>>CreateInstance:riid:ppvObject:). Passing out an interface pointer is relatively simple, but you must respect COMs reference counting rules, which is basically that you return an interface with a elevated ref. count, in anticipation of the client assuming responsibility for that reference. This is why you will see the interface being #detach'd. Alternatively you can explicitly #addRef and set the #yourAddress of the interface into the output parameter. Regards Blair |
In reply to this post by Bill Schwab-2
I can find IDL examples of how to return an Interface, but I would
like to know what the correct way writing Smalltalk code to return the Interface. I would like to write an ActiveX component. I will be also interested in how to raise events as Bill has metioned in another thread. Maybe Blair or Andy can give us an example of how to accomplish these items. Thanks, Scott |
Free forum by Nabble | Edit this page |