DllImport和char Marshaling

时间:2012-09-10 11:48:36

标签: c# c marshalling dllimport

我是C#和Marshaling的新手。我需要在C#中使用我的C函数,但是我的C语句返回值不正确(或者我不知道如何将它转换为正确的答案)。

C来源:

#include "main.h"

char *Ololo(char *arg, int &n3)
{
    char *szRet;
    szRet=(char*)malloc(strlen(arg)+1);
    strcpy(szRet,arg);
    n3 = strlen(szRet);
    return szRet;
}

C标题:

extern "C" __declspec(dllexport) char *Ololo(char *arg, int &n3);

C#来源:

class Program
{
    [DllImport(@"F:\Projects\service\dll\testDLL2.DLL", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
    public static extern IntPtr Ololo([In] char[] arg, ref Int32 n3);

    static void Main(string[] args)
    {
        string n1 = "ololo";
        char[] chars = new char[n1.Length];
        chars = n1.ToCharArray();
        Int32 n3 = 0;
        IntPtr result;
        result = Ololo(chars, ref n3);
        string n4 = Marshal.PtrToStringUni(result,n3);
        Console.WriteLine(n4);
    }
}

我得到了像“o ??”这样的东西。

抱歉英文不好

----------------------解决----------------------- < / p>

class Program
    {
        [DllImport(@"F:\Projects\service\dll\testDLL2.DLL", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
        public static extern IntPtr Ololo([MarshalAs(UnmanagedType.LPStr)]string arg, ref Int32 n3);

        static void Main(string[] args)
        {
            string n1 = "ololo";
            Int32 n3 = 0;
            int n2 = n1.Length;
            IntPtr result;
            result = Ololo(n1, ref n3);
            string n4 = Marshal.PtrToStringAnsi(result, n3);
            Console.WriteLine(n4);
        }
    }

工作正常。在n3我有5和n4 ololo!谢谢你的快速解答!

2 个答案:

答案 0 :(得分:3)

public static extern IntPtr Ololo([In] char[] arg, ref Int32 n3);

IntPtr是错误的返回类型,因为本质上你想要返回字符串,而不是指向字符串的指针。在C中,您可以使用char*指向字符串的指针,.NET中的等价物将使用此函数:[MarshalAs(UnmanagedType.LPStr)]string。这应该正确地将char*编组为string

IntPtr表示指针类型,用于获取实际字符串是无用的。

看起来您应该将StringBuilder带入Marshalled功能,而不是char[]。那么至少你应该得到正确的C函数字符串。

答案 1 :(得分:0)

marshaller没有NULL终止char数组以进行测试。它会这样做,因为你告诉它 - 如果你告诉它。你是幸运的,因为.NET中的char是UTF-16,这是16位宽 - 第二个字节将为零,因为它是UTF-16中的'o',因此给出了一个strlen 1.将托管字符串作为以null结尾的C字符串传递的实际工作量比您似乎高兴得多。因此,让编组人员完成所有工作 - 它已经知道如何完成这项工作。

public static extern [MarshalAs(UnmanagedType.LPStr)]string Ololo(
    [MarshalAs(UnmanagedType.LPStr)]string arg,
    ref int n3
);
static void Main(string[] args)
{
    string n1 = "ololo";
    Int32 n3 = 0;
    string n4 = Ololo(chars, ref n3);
    Console.WriteLine(n4);
}