【问题标题】:Calling C# programs from D从 D 调用 C# 程序
【发布时间】:2019-08-09 20:56:52
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: d unmanaged


    【解决方案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 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 em> 个项目。

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

    【讨论】:

    • 谢谢。通过一些更改,这对我来说效果很好。
    【解决方案2】:

    根据以下文章,我有一个从 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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-30
        • 1970-01-01
        • 1970-01-01
        • 2018-03-15
        • 1970-01-01
        相关资源
        最近更新 更多