Calling D from C++

Johann MacDonagh johann.macdonagh.no at spam.gmail.com
Mon Jul 18 20:46:14 PDT 2011


On 7/18/2011 11:27 PM, Loopback wrote:
> On 2011-07-19 04:40, Andrej Mitrovic wrote:
>> You have several problems.
>>
>> extern(C++) only specifies the calling convention, not the visibility
>> of the symbol. To export the symbol, list it in a .def file or mark
>> the function with export in the module itself, ala:
>>
>> export extern(C++) void SetInt(int * foo) {}
>>
>> I don't know why, but if you use a .def file instead of `export` the
>> function will be exported as a C function with no name mangling.
>>
>> Anyway, use a .def file like the one below and pass it to DMD while
>> compiling the DLL, and it should be exported with that name (and
>> change the string "mydll.dll" of course):
>>
>> LIBRARY "mydll.dll"
>> DESCRIPTION 'My DLL written in D'
>> EXETYPE NT
>> SUBSYSTEM WINDOWS
>> CODE PRELOAD DISCARDABLE
>> DATA WRITE
>>
>> EXPORTS
>> SetInt
>>
>>
>> ATA.lib is probably the autogenerated import library which is useful
>> for implicit linking.
> Seems as if this fixed it, thank you!
>
> I want to ask though how I am supposed to go about to enable class
> communication. For example; if I define a interface, and inherit this
> interface in a class, C++ can use these class functions by defining
> a analogous class (instead of interface) with virtual functions.
>
> If I create a class dynamically on the heap (in my dll), and then
> make a function that c++ can call to receive this object, how should
> I proceed then?
>
> extern(C++) interface Base
> {
> int Test();
> }
>
> class Foo : Base
> {
> public:
> extern(C++) int Test() { return 5; }
> }
>
> export extern(C++) void GetObject(Base base)
> {
> Foo temp = new Foo;
> base = Foo;
> }
>
> This is just a example to explain what I want to accomplish. One problem
> with this code, is that a memory exception is thrown on the C++ side if
> this function is called, whenever I use the "new" operator. Is this
> because it's a export/extern function?
>
> // C++ Code
> class Base
> {
> public:
> virtual int Test(void);
> };
>
> What is the best method to accomplish this, and are there any
> limitations with this method (do I have to allocate the class with
> malloc instead etc.)?

Your C++ class "Base" is not compatible with your D "Foo" class. The 
v-tables are not guaranteed to be identical. I'm not even sure if D's 
thiscall is the same as C++'s thiscall. It's just not going to work. 
Most languages don't support this. This is why we use C bindings. 
Everyone supports C ;)

Now, you can do something like this:

struct Foo
{
	int x;
	float y;
}

extern(C) void* GetNewFoo()
{
	// Note: Don't use new here otherwise the GC may clean it up
	return cast(void*) core.memory.GC.malloc(Foo.sizeof);
}

extern(C) float Foo_DoSomething(Foo* foo)
{
	return foo.x + foo.y;
}

extern(C) void FreeFoo(Foo* foo)
{
	core.memory.GC.free(foo);
}

I haven't tried this, but something like this should work. Structs are 
inherently compatible between languages. Of course, you won't be able to 
do any kind of polymorphism.

Does this help?


More information about the Digitalmars-d-learn mailing list