3
votes

I'm newbie at C# and Marshaling. I need to use my C func in C#, but i have an incorrect return value from C func (or I don't know how to convert it to correct answer).

C source:

#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 header:

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

C# source:

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

I've got return something like "o?? ?"

Sorry for bad English

----------------------Solved-----------------------

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

That works fine. In n3 i ve got 5 and in n4 ololo! Thank s for quick answers!

2
btw 'int &n3' is not C, its C++ notation.AndersK
You haven't solved anything, the code leaks the memory for the string.Hans Passant
possible duplicate of Char * marshalling in C#Hans Passant
@Hans Passant There is one difference: On your link func which return char * was rewrited to void func. In my question the first was how to catch return(char ). And if there is memory leak, how to free return(char) in c#?Treno1

2 Answers

3
votes

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

IntPtr is the wrong return type, as essentially you want to return the string, not a pointer to the string. In C you can use a pointer to your string by using char*, the equivalent in .NET would be to use use this: [MarshalAs(UnmanagedType.LPStr)]string. This should marshall the char* to a string correctly.

IntPtr represents a pointer type, which to get your actual string is useless.

Also looks like you should be taking a StringBuilder into your Marshalled function, and not a char[]. Then at least you should be getting the correct string to your C function.

-1
votes

The marshaller does not NULL terminate char arrays for funsies. It will do it because you told it to- if you told it to. You are fortunate because a char in .NET is UTF-16, and this is 16 bits wide- and the second byte will be zero because that is 'o' in UTF-16, thus giving a strlen of 1. The actual effort to pass in a managed string as a null-terminated C string is a tad higher than you seem to appreciate. So let the marshaller do all the work- it already knows how to do this job.

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