从D调用C#程序

时间:2019-01-30 13:08:24

标签: d unmanaged

如何从D调用C#函数(DLL)?

我尝试过或正在查看以下内容:

Derelict Mono方法对于Hello World程序效果很好,但是由于未正确加载DLL,因此较大的DLL(引用了很多其他程序集,其中每个程序集可能使用也可能不使用正版Windows API调用)失败。 / p>

使用非托管导出的初始实验会导致MSBUILD错误。

3 个答案:

答案 0 :(得分:1)

基于以下文章,我有一个初步的字符串传递解决方案,从D到(少量)C ++到C#:(我放弃了Robert Giesecke的非托管输出)

C# "Unmanaged Exports"(Hans Passant的教程)

Calling C# function from C++/CLI - Convert Return C# string to C String

D到C ++与Visual D的集成就可以了。

https://rainers.github.io/visuald/visuald/vcxproject.html(请参阅Visual C / C ++项目集成)

https://dlang.org/spec/cpp_interface.html

答案 1 :(得分:1)

尝试以下方法。首先是D代码:

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);
}

然后是C ++ / CLI填充程序:

#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);
}

最后一个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;
        }
    }
}

我仍在寻找摆脱C ++ / CLI填充程序的方法。

此代码的编写方式使您可以使用VS调试器进行调试。

这在Visual Studio中设置和测试非常简单。安装Visual D后,首先设置一个C ++ / CLI项目(不是Visual D项目),然后将D和C ++代码停在那里。然后在D项目下设置一个C#DLL项目。

从D调用C#代码是一回事,而另一回事情是取回数据,除非您仅使用int之类的简单标量类型。 C#的关键行是

gcbuf = GCHandle.Alloc(buffer, GCHandleType.Pinned);
ulong l = (ulong)gcbuf.AddrOfPinnedObject();

首先需要固定发送回的东西,然后再将地址发送回D。在C ++部分中,处理封送没有繁琐的事情,您的D代码只需要能够处理指针后面的任何东西。

完成操作后,还请确保释放固定的指针。注释掉D代码中的freeMe行,并观察VS中的内存使用量增长(和增长)。

我个人认为 pin 进程有些变幻,因为GCHandle.Alloc仅在其第一个参数(字节数组或结构)包含 blittable时才有效 项。

另请参阅https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types

答案 2 :(得分:1)

您可以使用非托管导出从D调用C#。我已经做到了,没有问题。

请参见https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports

但是,当我尝试使用Visual Studio 2017进行非托管导出时,我也无法使其正常工作。非托管导出与VS2015配合良好。考虑到链接是从2009年7月开始的,其他方面可能已经过时。

请务必仔细阅读说明,最重要的是,请确保您要针对x86或x64而不是“任何CPU”进行编译。整理数据将是另一个挑战。