从 D 调用 C# 程序

Calling C# programs from D

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

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

Derelict Mono 方法适用于 Hello World 程序,但是更大的 DLL(引用许多其他程序集,每个程序集可能会或可能不会使用真正的 Windows API 调用)由于 DLL 未正确加载而失败。

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

基于以下文章,我有一个从 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(参见可视化 C/C++ 项目集成)

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

尝试以下操作。首先是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 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);
}

最后是 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 shim 的方法。

此代码的编写方式使您可以使用 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();

你首先需要pin你要发回的东西,然后把地址发回D。在C++部分,你的D没有乏味的封送处理代码只需要能够处理指针后面的任何内容。

请务必在完成后释放固定指针。注释掉 D 代码中的 freeMe 行,观察 VS 中内存使用量的增长(和增长)。

就我个人而言,我发现 pin 过程有点善变,因为 GCHandle.Alloc 仅在其第一个参数(字节数组或结构)包含 blittable 项。

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

您可以使用 Unmanaged Exports 从 D 调用 C#。我已经成功完成了。

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

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

请务必仔细阅读说明,最重要的是确保您构建的是 x86 或 x64,而不是 "any CPU"。整理数据将是另一个挑战。