将包含StringBuilder的类从c#传递给ada

本文关键字:ada 包含 StringBuilder | 更新日期: 2023-09-27 18:07:36

我正在Unity c#中工作,试图与ada编写的dll集成。我需要将一个包含字符串和双精度的类传递给dll,以便修改和返回,但我得到以下错误:传递给非托管代码的System.Text.StringBuilder类型必须有一个StructLayout属性。

现在,这些类已经有一个StructLayoutAttribute。我不能把StructLayout属性放在Stringbuilder上,Unity告诉我它只适用于类和结构。这让我对错误信息感到困惑,因为它似乎要求我做一些不可能的事情?

public class controller : MonoBehavior{
    myClass student = new myClass();
    [DllImport ("my_dll", EntryPoint="myFunction@12")]
    public static extern void myFunction(myClass c);
    void Start(){
        myFunction (student);
    }
}
[StructLayoutAttribute(LayoutKind.Sequential, size=2)]
public class myClass {
    public double height = 0.0;
    public System.Text.StringBuilder name = new System.Text.StringBuilder(16);
}

将包含StringBuilder的类从c#传递给ada

c#在使用platformminvoke特性时默认将StringBuilder封送为char*。这对于与C调用约定dll进行接口非常方便。一些Ada编译器(尤其是GCC编译器)可能允许针对C调用约定对Ada库进行优化。这种"近乎神奇"的本质实际上可能是真的。:)

我的建议:用一个不安全的{}块和固定()你的char数组包围你对Ada函数的c#调用,然后将它传递给你的Ada函数,然后在它返回后再次退出固定块。

我没有Visual Studio的工作副本,所以我无法验证这一点。

(修改了不正确的术语)

这肯定让人感觉不对劲。如果您的Ada DLL知道如何处理System.Text.StringBuilder,那么这似乎很神奇。在处理本机库时,通常需要传递基本类型。此外,这个Ada DLL可能不是一个本机DLL,这是Mono期望使用的。有关封送数据的更多信息,请参阅与本机库的互操作。

现在让我们假设您的Ada DLL实际上是一个本机DLL。它知道如何处理StringBuilder。你可以通过IntPtr传递一个指向内存地址的空指针。但我非常怀疑这能否奏效。最有可能你想做的是传递实际的字符串:

public class controller : MonoBehavior{
    myClass student = new myClass();
    [DllImport ("my_dll", EntryPoint="myFunction@12")]
    public static extern void myFunction(myClass c);
    void Start(){
        student.name = "John Doe";
        myFunction (student);
    }
}
[StructLayoutAttribute(LayoutKind.Sequential, size=2)]
public class myClass {
    //The following MarshalAs may be unnecessary.
    [MarshalAs (UnmanagedType.LPStr)]
    public string name;
    public double height = 0.0;
}

LPStr是"指向字符串的长指针"。假设您的Ada DLL知道如何处理它。如果这不起作用,那么您可以删除MarshalAs,看看它是否更喜欢这样。

这个C函数将接受一个必须小于~250个字符的输入str,并返回一个修改后的字符串。你会看到它malloc一个字符串的大小等于sprintf修改后的字符串的大小,然后strcopy它。没有相应的free(),因为它会被mono释放。

  char* myFunction(char* input, double height)
  {
    char buffer[256];
    int n = sprintf(buffer, "%s -- %f", input, height);
    char* ret = (char*)malloc(n+1); // +1 for the newline
    strcopy(ret, buffer);
    return ret;
  }