简体   繁体   English

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

[英]Passing a class containing a StringBuilder from C# to ada

I'm working in Unity C#, trying to integrate with a dll written in ada. 我在Unity C#中工作,试图与以ada编写的dll集成。 I need to pass a class containing strings and doubles to the dll for it to modify and return, but I get the following error: "Type System.Text.StringBuilder which is passed to unmanaged code must have a StructLayout attribute." 我需要将包含字符串和双精度型的类传递给dll进行修改并返回,但出现以下错误:“传递给非托管代码的Type System.Text.StringBuilder必须具有StructLayout属性。”

Now, these classes already have a StructLayoutAttribute. 现在,这些类已经具有StructLayoutAttribute。 And I can't put a StructLayout attribute on a Stringbuilder, Unity tells me it only works on classes and structs. 而且我不能将StructLayout属性放在Stringbuilder上,Unity告诉我它仅适用于类和结构。 Which makes me really confused about the error message, because it seems like it's asking me for something that's impossible? 这使我对错误消息感到非常困惑,因为它似乎在问我一些不可能的事情?

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

Something about this definitely feels off. 有关此事肯定让人感到有些不适。 If your Ada DLL knows how to handle a System.Text.StringBuilder then that seems almost magical. 如果您的Ada DLL知道如何处理System.Text.StringBuilder,那么这似乎很神奇。 You generally need to pass primitive types around when dealing with native libraries. 处理本地库时,通常需要传递原始类型。 Also, this Ada DLL is possibly not a native dll, which is what Mono is expecting to work with. 另外,此Ada DLL可能不是本机dll,而Mono希望使用该dll。 See Interop With Native Libraries for more info on marshaling data. 有关封送数据的更多信息,请参见与本地库互操作

Now lets assume that your Ada DLL is actually a native DLL. 现在,假设您的Ada DLL实际上是本机DLL。 And it somehow knows what to do with a StringBuilder. 它以某种方式知道如何处理StringBuilder。 You can possibly pass a void pointer to the memory address via IntPtr. 您可以通过IntPtr将void指针传递到内存地址。 But I highly doubt this would work. 但我高度怀疑这是否行得通。 Most likely what you want to do is pass the actual string through: 您最想做的是通过以下方式传递实际的字符串:

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 is a 'long pointer to a string'. LPStr是“指向字符串的长指针”。 The assumption is your Ada DLL will know what to do with that. 假设您的Ada DLL将知道该怎么做。 If that doesn't work, then you can remove the MarshalAs and see if it likes it better that way. 如果那不起作用,那么您可以删除MarshalAs并查看它是否更喜欢这种方式。

This C function will take an input str that must be less than ~250 characters and returns a modified string. 此C函数将采用必须小于约250个字符的输入str,并返回修改后的字符串。 You'll see that it mallocs a string the size of sprintf's modified string and then strcopy's it. 您会看到它分配了一个与sprintf修改后的字符串大小相同的字符串,然后对其进行strcopy分配。 There is no corresponding free() because it will be freed by mono as mentioned here. 没有相应的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;
  }

IIRC C# marshals StringBuilder as char* by default when using PlatformInvoke features. 使用PlatformInvoke功能时,默认情况下,IIRC C#将StringBuilder封送为char *。 This is handy for interfacing with C call convention DLLs. 这很方便与C调用约定DLL进行接口。 Some Ada compilers (especially the GCC one) might allow Ada libraries to be optimised for C call conventions. 一些Ada编译器(尤其是GCC编译器)可能允许Ada库针对C调用约定进行优化。 The "almost magical" nature of this may in fact be true. 实际上,这种“几乎神奇的”本质是正确的。 :) :)

My suggestion: surround your C# call to the Ada functions with an unsafe{} block and fixed() your char array, then pass it to your Ada function, then drop out of the fixed block again after it returns. 我的建议是:用一个不安全的{}块对Ada函数进行C#调用,并用char()固定住char数组,然后将其传递给Ada函数,然后在返回后再退出固定块。

I don't have a working copy of Visual Studio so I can't verify this. 我没有Visual Studio的工作副本,因此无法验证这一点。

(Edited to fix incorrect terminology) (编辑以修复错误的术语)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM