简体   繁体   中英

Calling C++ DLL with a callback function that contains a char* from C#

I have a C++ DLL ( SimpleDLL.dll ), with a exposed function ( DllFunctionPoibnterGetName ) that has a function pointer ( getNameFP ). The function pointer takes a char * as a parameter (*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 ); 
}

I have a C# application that would like to use this C++ DLL.

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

Currently I can set the length with out any problems, but I can't seem to find a way to set the name correctly.

My Question is

  • How do I set the char * name to a value correctly.

Cast the char* as a char[]. That should do the trick.

Casting the char will not do. The char * data is 'unmanaged', native data. And C# uses 'managed', .NET data.

You need to make a wrapper for your call and use marschall to convert the data from 'unmanaged' to 'managed'.

You don't need to use unsafe code. You can do it like this:

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

Although this interface design is just asking for a buffer overrun. How are you supposed to know how big the unmanaged buffer is? It would make more sense for the length parameter to be passed by ref . On input it would tell you how big the buffer is. On output you would have recorded how many bytes you copied into the buffer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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