Passing String from Native C++ DLL to C# App

15,946

Solution 1

Use a StringBuilder to pass a character array that native code can fill in (see Fixed-Length String Buffers).

Declare the function:

[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
public static extern int xmain(int argc, string argv, StringBuilder argv2);

Use it:

// allocate a StringBuilder with enough space; if it is too small,
// the native code will corrupt memory
StringBuilder sb = new StringBuilder(4096);
xmain(2, @"C:\hhh.bmp", sb);
string argv2 = sb.ToString();

Solution 2

Give some other information to the DLLImport call. Look at the following example of my own:

[DllImport("tcpipNexIbnk.dll", EntryPoint = "SendData", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);

Notice two things, the CallingConvention parameter: CallingConvention = CallingConvention.Cdecl)

Use that as it is.

And then just behind the c# string type, you can play with the different Unmanaged types using the MarshalAS instruction, that will cast your C# string parameter to the native string type you have in your c++ program:

public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);

Hope it helps.

Share:
15,946
Jacob Quisenberry
Author by

Jacob Quisenberry

I am a Software Engineer at ACT Litigation Services.

Updated on June 04, 2022

Comments

  • Jacob Quisenberry
    Jacob Quisenberry almost 2 years

    I have written a DLL in C++. One of the functions writes to a character array.

    C++ Function

    EXPORT int xmain(int argc, char argv[], char argv2[])
    {
        char  pTypeName[4096];
        ...
        //Other pTypeName ends up populated with "Portable Network Graphics"
        //This code verifies that pTypeName is populated with what I think it is:
        char szBuff[64];
        sprintf(szBuff, pTypeName, 0);
        MessageBoxA(NULL, szBuff, szBuff, MB_OK);
        //The caption and title are "Portable Network Graphics"
    
        ...
        //Here, I attempt to copy the value in pTypeName to parameter 3.
        sprintf(argv2, szBuff, 0);
    
        return ret;
    }
    

    C# Import

        //I believe I have to use CharSet.Ansi because by the C++ code uses char[],
        [DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
        public static extern int xmain(int argc, string argv, ref string zzz);
    

    C# Function

    private void button2_Click(object sender, EventArgs e)
    {
        string zzz = ""; 
        int xxx = xmain(2, @"C:\hhh.bmp", ref zzz);
        MessageBox.Show(zzz);
    
        //The message box displays
        //MessageBox.Show displays "IstuÈst¼ÓstÄstlÄstwÄstiÑstõÖstwÍst\
        // aÖst[ÖstÃÏst¯ÄstÐstòÄstŽÐstÅstpÅstOleMainThreadWndClass"
    
    }
    

    I have attempted to pass a parameter from C# by reference and have the C++ DLL populate the parameter. Even though I have verified that the value is correct in the DLL, gibberish gets passed to the C# application.

    What can I do to write the correct string value to the C# string?