如何使用 nim-lang 中的 ImportDll 在 DotNet Core 中调用字符串函数

How to call string function in DotNet Core with ImportDll in nim-lang

我想在我的 C# 代码中使用 Nim,我使用这个 https://www.euantorano.co.uk/posts/nim-with-c-sharp-net/ 示例没有问题。好吧,我说了,让字符串 proc 工作。

proc HelloNim*(a, b: cint): cstring {.cdecl, exportc, dynlib.} =
  return "bob".cstring

然后在 C# 中

using System;
using System.Runtime.InteropServices;

namespace Miasma
{
    class Program
    {
        static void Main(string[] args)
        {
            string b = ""+HelloNim(1,2);
            Console.WriteLine(b);
        }

        [DllImport("HelloNim.dll")]
        public static extern void NimMain();

        [DllImport("HelloNim.dll")]
        public static extern string HelloNim(int a, int b);
    }
}

这没有错误,但也没有打印出任何字符串。乐克斯。出了什么问题?

这里出问题的是 C# 认为它正在取回托管字符串,并试图释放它。但是它得到的字符串不在它的内存块中,因为它是由 Nim DLL 分配的,所以它崩溃了(如果你查看 dotnet 的退出代码,它应该是 139,这意味着 SIGSEGV,至少在 Linux ).为避免这种情况,您可以将过程定义为返回 IntPtr,然后使用 Marshal.PtrToStringUTF8(returnValue) 将其编组为 C# 字符串 另一件需要注意的事情是,对于字符串(或任何其他在 Nim 中使用 GC 的东西,并初始化全局变量)才能工作,你需要先调用 NimMain() 。结合这个你的代码可以重写为:

using System;
using System.Runtime.InteropServices;

namespace Miasma
{
    class Program
    {
        static void Main(string[] args)
        {
            NimMain();
            IntPtr strPtr = HelloNim(1,2);
            var str = Marshal.PtrToStringUTF8(strPtr);
            Console.WriteLine(str);
        }

        [DllImport("HelloNim.dll")]
        public static extern void NimMain();

        [DllImport("HelloNim.dll")]
        public static extern IntPtr HelloNim(int a, int b);
    }
}

另外请记住,您收到的指针指向 Nim 管理的内存,因此每次您从 Nim DLL 调用某些内容时,它都有可能被 GC 处理。如果您想将它保留在您的 C# 代码中,您应该立即将其复制过来(不确定 Marshall 是否这样做)。