2
4

2 回答 2

3

我建议使用 @konan.internal.CName("topLevelFunctionName") 注释将您的函数导出为顶级 C 函数,并像往常一样使用它,因此对于如下代码: @konan.internal.CName("topLevelFunctionVoidFromC") fun topLevelFunctionVoid(x1: Int): Int 将生成以下 C 代码: int topLevelFunctionVoid(int x1); 请参阅https:// github.com/JetBrains/kotlin-native/blob/master/backend.native/tests/produce_dynamic/simple

于 2018-03-23T13:01:28.623 回答
2

首先,我不熟悉 Kotlin/Native,但是如果有任何方法可以指定它应该为 C 代码生成一个平面 API,那么你绝对应该使用它。就目前而言,生成的 API 太复杂了;该bar_ExportedSymbols结构只不过是一袋函数——它根本不需要被定义为一个结构。

但是,继续使用我们的代码,您需要定义与本机函数指针相对应的委托。

public class NativeMethods
{
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  public delegate void DisposeStablePointer(IntPtr ptr);

  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  public delegate void DisposeString([MarshalAs(UnmanagedType.LPStr)] string str);

  // this assumes that bar_KBoolean is defined as an int
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  [return: MarshalAs(UnmanagedType.Bool)]
  public delegate bool IsInstance(IntPtr pRef, IntPtr type);

  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  public delegate void Foo([MarshalAs(UnmanagedType.LPStr)] string str);

  [DllImport("KONAN_bar.dll", EntryPoint = "bar_symbols")]
  public static extern IntPtr BarSymbols();
}

接下来要做的是定义一个托管结构来保存函数委托。本机结构不必要地包含嵌套rootkotlin结构,它们没有做任何有用的事情。此定义应该有效,除非存在特定于您的编译器/平台的结构填充问题,您必须自己解决这些问题。

[StructLayout(LayoutKind.Sequential)]
public struct ExportedSymbols
{
  public NativeMethods.DisposeStablePointer FuncPointerDispose;
  public NativeMethods.DisposeString FuncStringDispose;
  public NativeMethods.IsInstance FuncIsInstance;
  public NativeMethods.Foo FuncFoo;
}

一个简单的程序来测试对该foo函数的访问:

class Program
{
  static void Main(string[] args)
  {
    IntPtr p = NativeMethods.BarSymbols();
    ExportedSymbols es = (ExportedSymbols)Marshal.PtrToStructure(p, typeof(ExportedSymbols));
    es.FuncFoo("Testing");
  }
}

由于该结构只不过是一组函数指针,因此您可能会将其存储在某个静态变量中,该变量将持续应用程序的生命周期。如果这涉及具有已分配数据成员并且需要在某个时候释放的结构,您将存储指针p,以便您可以将其传递给将释放分配的内存的库函数。

于 2018-03-22T04:57:02.900 回答