使用包含来自C#的char *的回调函数调用C ++ DLL

时间:2012-11-09 18:09:38

标签: c# pinvoke

我有一个C ++ DLL( SimpleDLL.dll ),带有一个具有函数指针( getNameFP )的公开函数( DllFunctionPoibnterGetName ) 。函数指针将char *作为参数(* char * name *)。

// C++ 
DllExport void DllFunctionPoibnterGetName( void (*getNameFP) (char * name, unsigned short * length ) ) {

    char name[1024];
    unsigned short length = 0 ; 
    getNameFP( name, &length ); 

    printf( "length=[%d] name=[%s]\n", length, name ); 
}

我有一个想要使用这个C ++ DLL的C#应用​​程序。

// C# 
public unsafe delegate void GetName( System.Char* name, System.UInt16* length); 
unsafe class Program
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void delegateGetName(System.Char* name, System.UInt16* length);

    [DllImport("SimpleDLL.dll", CharSet = CharSet.Ansi )]
    public static extern void DllFunctionPoibnterGetName([MarshalAs(UnmanagedType.FunctionPtr)] delegateGetName getName);

    static void Main(string[] args)
    {   
        DllFunctionPoibnterGetName(GetName); 
    }

    static void GetName(System.Char* name, System.UInt16* length)
    {
        // name = "one two three";
        *length = 10; 
    }   
}

目前我可以设置长度没有任何问题,但我似乎找不到正确设置名称的方法。

我的问题是

  • 如何正确设置 char * 名称。

3 个答案:

答案 0 :(得分:1)

将char *转换为char []。这应该可以解决问题。

答案 1 :(得分:1)

投射char不会。 char *数据是“非托管”的本机数据。 C#使用'托管',.NET数据。

您需要为您的调用创建一个包装器,并使用marschall将数据从“非托管”转换为“托管”。

答案 2 :(得分:1)

您不需要使用不安全的代码。你可以这样做:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void delegateGetName(IntPtr name, out ushort length);
....
static void GetName(IntPtr name, out ushort length)
{
    byte[] buffer = Encoding.Default.GetBytes("one two three");
    length = (ushort)buffer.Length;
    Marshal.Copy(buffer, 0, name, buffer.Length);
}   

虽然这种界面设计只是要求缓冲区溢出。你怎么知道非托管缓冲区有多大? length传递ref参数会更有意义。在输入时它会告诉你缓冲区有多大。在输出时,您将记录您复制到缓冲区的字节数。