views:

60

answers:

2

I have two communicating components - one managed, the other unmanaged. The managed needs to retrieve a character string from the unmanaged implementation (the same string or just a copy). I tried the following code.

// Unmanaged code
const char* GetTestName(Test* test)
{
    return test->getName();
}

// Managed wrapper
[DllImport(DllName, EntryPoint = "GetTestName")]
public static extern IntPtr GetTestName(IntPtr testObj);

// API Invocation
IntPtr testName = GetTestName(test);
string testStr = Marshal.PtrToStringAuto(testName);

But, the value of testStr is not what is expected. Does anyone know what I'm doing wrong here? Any suggestions would be really helpful.

+2  A: 

You're close but you have to use PtrToStringAnsi(). Auto uses the system default which will be Unicode.

Hans Passant
I tried that. Didn't work. I actually tried all PtrToStringX() methods available. Am I doing something wrong in marshalling the data? The unmanaged unit is responsible for the character string memory.
Elroy
No, your pinvoke declaration is correct. I'd focus on making sure the *test* argument is correct. Just debug this, turn on unmanaged debugging and set a breakpoint on test->getName().
Hans Passant
Yup, got it. getName() is buggy. Thanks Hans.
Elroy
+1  A: 

I'd suggest this, instead:

[DllImport(DllName, EntryPoint = "EntryPoint")]
[MarshalAs(UnmanagedType.LPStr)]
public static extern StringBuilder GetTestName(IntPtr testObj);

UnmanagedType.LPStr works with strings and System.Text.StringBuilder, and perhaps others (I only ever used those two). I've found StringBuilder to work more consistantly, though.

See this MSDN article for further information on the various string marshalling options.

Moudis
Hah, and I added this as soon as you picked an answer. Glad you got it figured out :)
Moudis
@Moudis I appreciate the suggestion. Will check it out.
Elroy