I am having an issue passing a simple string from my .NET app, compiled as 64-bit, to my native DLL, also compiled as 64-bit.
C++ signature:
DllExport void SetFoo(LPWSTR foo);
C# signature:
[DllImport(Library, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
internal static extern void SetFoo(
[In][MarshalAs(UnmanagedType.LPWStr)] string foo);
Then I run the following code in C#:
X.SetFoo("some string");
When it reaches the debugger in the DLL, the value is swearing at me in Chinese: Ⴐ虘翺
When I change both the .NET and native code to 32-bit, the value I get in the debugger is the correct string. Where am I being stupid?
Minimal reproduction as a Visual Studio 2015 Solution: download here
To reproduce:
- Create a new Visual Studio solution with a WinForms project.
- Add a Win32 Project, of type DLL to the solution
- Add the following files:
Foo.h:
extern "C" {
__declspec( dllexport ) void SetFoo(LPWSTR);
}
Foo.cpp:
#include "stdafx.h"
#include "Foo.h"
DllExport void SetFoo(LPWSTR foo)
{
}
- Set a breakpoint on the opening brace in
SetFoo - Add a button to the winforms form
- Double click it, and call
SetFoo("abc123"). - Implement
SetFoo:
Form1.cs:
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void SetFoo(string text);
- Change the apps to build in 64-bit mode by opening Configuration Manager.
- Set Win32Project1 to build as x64
- Set WindowsFormApplication1 to build as x64, by picking platform new, pick x64, OK.
- Change the output directory of WindowsFormsApplication1 to match the output directory of the other app.
- Start without debugging.
- Attach debugger (Ctrl+Alt+P) by setting
Attach totoManaged (v4.5, v4.0) code, Native codeand finding the process. - Observe value at breakpoint.