Reputation: 209
How can I call C# functions (a DLL) from D?
I have tried or am looking at the following:
Using the Derelict Mono package (https://github.com/kubasz/derelict-mono)
Using Unmanaged Exports (See
Calling C# from C), D
to C to C#, eventually maybe eliminating the C.
The Derelict Mono approach works well for Hello World programs, however a larger DLL (with references to lots of other assemblies, each of which may or may not use genuine Windows API calls) fails as the DLL is not properly loaded.
Initial experiments with Unmanaged Exports result in errors with MSBUILD.
Upvotes: 2
Views: 262
Reputation: 26
Try the following. First the D code:
module main;
import std.stdio;
import std.conv;
extern (C++) ulong receiveMe(ulong i);
extern (C++) ulong freeMe(ulong i);
void main() {
ulong l = receiveMe(0);
char* p = cast(char*)l;
char[] s = to!(char[])(p);
byte[] b = cast(byte[])(s.dup);
writeln("The answer is " ~ to!string(s));
ulong m = freeMe(0);
}
Then a C++/CLI shim:
#include "stdafx.h"
#using "...\CS-Interop\bin\x64\Debug\netstandard2.0\CS-Interop.dll"
using namespace System;
UInt64 sendMe(UInt64 arg) {
return CS_Interop::Test::receiveMe(42);
}
UInt64 freeMe(UInt64 arg) {
return CS_Interop::Test::freeMe(42);
}
Lastly the C#:
using System.Runtime.InteropServices;
using System.Text;
namespace CS_Interop {
public class Test {
public static byte[] buffer;
public static GCHandle gcbuf;
public static ulong receiveMe(ulong arg) {
string s = "I was a string " + arg;
s = (s.Length + 2) + s;
buffer = Encoding.ASCII.GetBytes(s);
gcbuf = GCHandle.Alloc(buffer, GCHandleType.Pinned);
ulong l = (ulong)gcbuf.AddrOfPinnedObject();
return l;
}
public static ulong freeMe(ulong arg) {
gcbuf.Free();
return 42;
}
}
}
I'm still looking at ways to get rid of that C++/CLI shim.
This code is written in such a way that you can poke around with the VS debugger.
This is very simple to set up and test in Visual Studio. With Visual D installed, first set up a C++/CLI project (NOT a Visual D project) and park the D and C++ code there. Then setup a C# DLL project under the D project.
It is one thing to call C# code from D, but another thing to get data back unless you are using only simple scalar types like int. The key lines of C# are
gcbuf = GCHandle.Alloc(buffer, GCHandleType.Pinned);
ulong l = (ulong)gcbuf.AddrOfPinnedObject();
where you first need to pin the thing you are sending back then send the address back to D. There is no tedious mucking about with marshaling in the C++ part, your D code just needs to be able to deal with whatever sits behind the pointer.
Be sure also to free the pinned pointer once you're done with it. Comment out the freeMe line in the D code and watch the memory usage grow (and grow) in VS.
Personally, I find the pin process a bit fickle as GCHandle.Alloc
will only work when its first argument, be it a byte array or structure, contains blittable items.
See also https://learn.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types
Upvotes: 1
Reputation: 11
You can use Unmanaged Exports to call C# from D. I've done it without problems.
See https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports
However, when I tried Unmanaged Exports with Visual Studio 2017, I also could not get it to work. Unmanaged Exports worked well with VS2015. Considering the link is from July 2009, other aspects could have become stale.
Be sure to read the instructions carefully, and most importantly make sure you are building for x86 or x64, and not "any CPU". Marshalling the data will be another challenge.
Upvotes: 1
Reputation: 209
I have a preliminary string passing solution from D to (a small amount of) C++ to C# based on the following articles: (I gave up on unmanaged exports from Robert Giesecke)
C# "Unmanaged Exports" (tutorial from Hans Passant)
Calling C# function from C++/CLI - Convert Return C# string to C String
The D to C++ integration with Visual D just works.
https://rainers.github.io/visuald/visuald/vcxproject.html (See Visual C/C++ Project Integration)
https://dlang.org/spec/cpp_interface.html
Upvotes: 1