tags:

views:

128

answers:

2

Using this function in my C# exe, I try to pass a Unicode string to my C++ DLL:

    [DllImport("Test.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
    public static extern int xSetTestString(StringBuilder xmlSettings);

This is the function on the C++ DLL side:

__declspec(dllexport) int xSetTestString(char* pSettingsXML);

Before calling the function in C#, I do a MessageBox.Show(string) and it displays all characters properly. On the C++ side, I do: OutputDebugStringW((wchar_t*)pString);, but that shows that the non-ASCII characters were replaced by '?'.

A: 

Try:

[DllImport("Test.dll")]
[return : MarshalAs(UnmanagedType.I4)]
private static extern int externalTestString(
    [MarshalAs(UnmanagedType. // The string type the C uses ansi/unicode/...) ] String st
    );

public int TestString(String st // or string builder here)
{
     // Perform input/output checks here + exception handling
}

Make sure the C++ functions are visible outside the DLL (using __declspec dllexport). Check using depends (comes with VS2005) if you can see the functions and what there name is.

If your C++ functions are NOT within classes, then you can use unmangled names if you use extern "C", if they are in classes, you will need to specify an entry point with the mangled names from depends.

Danny Varod
I tried this but same problem: [DllImport("Test.dll")] [return: MarshalAs(UnmanagedType.I4)] public static extern int xSetTestString( [MarshalAs(UnmanagedType.LPWStr)] String xmlSettings);
Martin
What type is your C++ string? char* wchar_t*, std::string,... ?
Danny Varod
+3  A: 

Just change your export in native DLL to:

extern "C" __declspec(dllexport) int xSetTestString(wchar_t* pSettingsXML);

This will do the trick.

BTW - You cant simply do char* str1 = (wchar_t*)pSettingsXML; because it does not convert the string. You need to use wcstombs_s to convert from wchar_t* to char*. But in your case you don't have to do it.

Notes: Best practice IMO is to use TCHAR* instead of wchar_t* directly, and set your native dll project General option Character Set to Use Unicode Character Set. This defines TCHAR* as wchar_t*.

Mirosoft natively uses two sets of functions: ANSI, using 1-byte chracter, marked as FunctionNameA and Unicode, using 2-bytes character, marked as FunctionNameW. This Unicode is in fact UTF-16.

UTF-8 is a multi-byte string that uses 1-byte for standard character and 2-bytes for non-standard characters. To convert UTF-8 to UTF-16 you can use MultiByteToWideChar function.

AOI Karasu
Why bother with the `TCHAR` stuff? That's just a macro which was introduced decades ago to facilitate the transition to Unicode. New code, even in C++, should start with Unicode.
MSalters
AOI Karasu