Как вызвать строковую функцию в Do tNet Core с ImportDll в nim-lang - PullRequest
0 голосов
/ 01 марта 2020

Я хотел использовать Nim внутри моего C# кода, и я использовал этот https://www.euantorano.co.uk/posts/nim-with-c-sharp-net/ пример без проблем. Хорошо, я сказал, давайте получим строку pro c, работающую.

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

Это не ошибка, но она не распечатывает Строка либо. Lorks. Что пошло не так?

1 Ответ

1 голос
/ 02 марта 2020

Что здесь не так, так это то, что C# думает, что возвращает управляемую строку, и пытается ее освободить. Но полученная строка находится не в своем фрагменте памяти, как она была выделена DLL-библиотекой Nim, поэтому она вылетает (если вы посмотрите на код выхода do tnet, это должно быть 139, что означает SIGSEGV, по крайней мере на Linux). Чтобы избежать этого, вы можете определить процедуру как возвращающую IntPtr, а затем упорядочить ее в C# строку, используя Marshal.PtrToStringUTF8(returnValue) Еще одна вещь, на которую стоит обратить внимание, - это для строк (или всего, что использует G C в Nim и для инициализации глобальных переменных) для работы вам нужно вызвать 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, поэтому каждый раз, когда вы вызываете что-то из DLL-библиотеки Nim, есть вероятность, что это произойдет быть G C 'ред. Если вы хотите сохранить его в своем C# коде, вы должны немедленно скопировать его (не уверен, делает ли это Маршалл).

...