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

时间:2015-08-12 14:54:24

标签: c# dll unity3d stringbuilder ada

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

现在,这些类已经有了一个StructLayoutAttribute。而且我不能在Stringbuilder上放置StructLayout属性,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);
}

2 个答案:

答案 0 :(得分:0)

关于这一点肯定感觉不到。如果您的Ada DLL知道如何处理System.Text.StringBuilder那么这看起来几乎是神奇的。在处理本机库时,通常需要传递原始类型。此外,这个Ada DLL可能不是本机dll,这是Mono期望使用的。有关封送数据的详细信息,请参阅Interop With Native Libraries

现在假设您的Ada DLL实际上是本机DLL。它以某种方式知道如何处理StringBuilder。您可以通过IntPtr将void指针传递给内存地址。但我非常怀疑这会奏效。你很可能想要做的是传递实际的字符串:

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并返回修改后的字符串。你会看到它mallocs一个字符串大小为sprintf的修改后的字符串,然后strcopy就是它。没有相应的free()因为它将被mono as mentioned here.

释放
  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;
  }

答案 1 :(得分:0)

IIRC C#默认使用PlatformInvoke功能时将StringBuilder编组为char *。这对于与C调用约定DLL的接口很方便。一些Ada编译器(尤其是GCC编译器)可能允许Ada库针对C调用约定进行优化。事实上,“几乎神奇”的本质可能是真实的。 :)

我的建议:用一个不安全的{}块围绕你的C#调用Ada函数并修复你的char数组,然后将它传递给你的Ada函数,然后在它返回后再次退出固定块。

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

(编辑用于修正错误的术语)