Hi everyone.
I'm having trouble trying to call a c++ virtual function on a dll from Dolphin, and can't see what am i doing wrong. The function is beeing called, but what should be the first parameter, it's a 32bit constant value (i think it's not *this* pointer, though). i've tried changing the calling convention in both Dolphin and the dll, but didnt work ... any tips ? The example is pretty simple. this is my dolphin wrapper: ExternalStructure subclass: #IExperimenting IExperimenting>>inc: i "virtual int Inc(int i)" <virtual cdecl: sdword 2 sdword> ^self invalidCall and i'm obtaining an instance with ExperimentingLibrary>>makeInstanceOfIExperimenting "__declspec(dllexport) IExperimenting* MakeInstanceOfIExperimenting();" <cdecl: IExperimenting* '?MakeInstanceOfIExperimenting@@YAPAVIExperimenting@@XZ'> ^self invalidCall and this is my c++ class in the dll: __declspec(dllexport) IExperimenting* MakeInstanceOfIExperimenting(); class IExperimenting { public: IExperimenting(); virtual ~IExperimenting(); virtual int Inc(int i); }; thanks in advance Martin |
Martin,
I won't try to fumble for an answer to your problem. Dolphin can call some types of vtable functions (COM interfaces come to mind), though I've never done it directly. Since you seem to have control over the DLL, can you create some extern "C" functions for Dolphin to call? Then it becomes easy (by comparison). Note that you can use all the C++ you want inside the C-callable function; you simply cannot pass C++ specific types (references, etc.) to it, but that won't bother you, because Dolphin does not much deal in those. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by Martin Rubi
Martin wrote:
> I'm having trouble trying to call a c++ virtual function on a dll from > Dolphin, and can't see what am i doing wrong. > __declspec(dllexport) IExperimenting* MakeInstanceOfIExperimenting(); > class IExperimenting > { > public: > IExperimenting(); > virtual ~IExperimenting(); > virtual int Inc(int i); > }; I think the problem is that MSVC++ defaults to the 'thiscall' argument passing convention for virtual methods (which passes 'this' in a register, and then handles the rest of the arguments the same as __stdcall). Dolphin, according to the docs, cannot (yet) handle 'thiscall' -- you can only use stdcall or cdecl -- so the C++ program sees garbage where it expects to find the address of 'this' and 'this' where it expects to find the integer argument. If you change your example class to: ... virtual int __stdcall Inc(int i); ... or: ... virtual int __cdecl Inc(int i); ... and set the definition of IExperimenting>>inc: to: <virtual stdcall: sdword 2 sdword> or: <virtual cdecl: sdword 2 sdword> respectively, then you should be OK. BTW, apparently you can't use __cdecl for a virtual destuctor; I don't know why. BTW2. (I know this is only an example, but just in case) don't forget to include a DestroyInstance() function to parallel MakeInstance(). BTW3. If you declare your MakeInstance()/DestroyInstance() functions inside an extern "C" { ... } block, then you won't suffer from the name mangling. If they are declared __cdecl then there won't be any mangling at all, if they are __stdcall then there will be very little. Alternatively/additionally you could use a .DEF file to control the name exported by the DLL (which is what I do). -- chris |
Bill, Chris
> so the C++ program sees garbage where it expects to find the address > of 'this' and 'this' where it expects to find the integer argument. Indeed. After you pointed this out, i discovered that my actual parameter was pushed as if it was the second one. > If you change your example class to: > ... > virtual int __stdcall Inc(int i); > ... > respectively, then you should be OK. I am, works like a charme now. > BTW2. (I know this is only an example, but just in case) don't forget to > include a DestroyInstance() function to parallel MakeInstance(). Thanks for the tip. I've made instances of IExperimenting finalizable, redefined IExperimenting>>needsFree to answer true and call DestroyInstance() from IExperimenting>>basicFree. This calls c++ destructor when IExperimenting instances are garbage collected ... it's working, but could be something wrong in anything of what i've done ? > Alternatively/additionally you could > use a .DEF file to control the name exported by the DLL (which is what I do). Thanks for the tip2. I've followed this advice too. Thanks again. Best regards. Martin. PD: I think the tutorial on vitual calls from http://www.object-arts.com/Lib/EducationCentre4/htm/virtualcalls.c...olecominterface..htm may have a little error. Where it says "<virtual cdecl: lpstr 1>", should it say "<virtual cdecl: lpstr 2>" ? Because in the example, the first virtual function is the destructor, and the vt index seems to be 1-based. I think the example is clear enough, anyway. |
Martin wrote:
> Thanks for the tip. I've made instances of IExperimenting finalizable, > redefined IExperimenting>>needsFree to answer true and call > DestroyInstance() from IExperimenting>>basicFree. This calls c++ > destructor > when IExperimenting instances are garbage collected ... it's working, but > could be something wrong in anything of what i've done ? I can't think of anything special. You'd need to be a bit careful about ensuring that your finaliser didn't do anything (or wasn't called at all) for instances that had already been released (including instances that persist over an image save/restore). You also want to make sure that you don't release instances that haven't been created by #MakeInstance -- but that applies whether or not you use finalisation. You also need to ensure that the instances that are created implicitly by the MakeInstance() wrapper method do actually become finalisable. All that's straightforward. One other point to check is that your application (that uses these objects) is such that the finaliser thread will actually get a chance to run reasonably often. My guess is that that won't be a problem for you, but it can be sometimes. (E.g. if a program is in a tight loop doing Database stuff, then the finaliser may not get a chance to clean up old queries, etc -- which can impact the system significantly.) > PD: I think the tutorial on vitual calls from > http://www.object-arts.com/Lib/EducationCentre4/htm/virtualcalls.c...olecominterface..htm > may have a little error. > Where it says "<virtual cdecl: lpstr 1>", should it say "<virtual cdecl: > lpstr 2>" ? It looks that way to me too. -- chris |
Free forum by Nabble | Edit this page |