Reputation: 635
I am working on a C++ DLL with a C wrapper to be able to use it on different langages. For now, I am developing too a plugin in C# which call my DLL.
What I want is to pass as argument of my DLL a string (the path of a file) to be able to use it on my DLL.
C#
[DllImport(DllName, CallingConvention = DllCallingConvention)]
public static extern IntPtr AllocateHandle(string filename);
C wrapper
LPVOID SAMPLEDLL_API CALLCONV_API AllocateHandle(char* filename);
C++ class constructor
CustomData::CustomData(char* filename)
{
_filename = filename; // string _filename;
}
When I save _filename on a file (because I didn't find the way to debug using breakpoints on the DLL), I have something like ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ0à×
. I tried different solutions to convert a char* to a string but the result is still the same.
Thank you in advance for your help.
Upvotes: 5
Views: 1487
Reputation: 2902
It looks like you are storing the string that is passed from managed code in a member field in the unmanaged class. That won't work, because the Garbage Collector will move or dispose of the managed string at some point, which will render the string useless on the unmanaged side. If you want to keep the string for later use, you have to make a copy of it on the unmanaged side (allocated on the unmanaged heap).
CustomData::CustomData(char *filename)
{
// _filename will need to be freed at some point; might
// want to think about using std::string instead
// like _filename = new std::string (filename);
_filename = strdup(filename);
}
Now the unmanaged code has its own (unmanaged) copy of the string, so when the GC disposes of the managed string, it won't matter. This is the simplest way to deal with the situation, since you are also writing the unmanaged code. There are other measures to prevent the GC from interfering with unmanaged interop, but those are tricky and time-consuming, and are necessary only if you can't modify the unmanaged code.
Upvotes: 1
Reputation: 2125
The problem is that strings in C# are in Unicode. String in cpp is ansi string. You have to tell C# that the string must be ansi:
[DllImport(DllName.dll, CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
static extern IntPtr AllocateHandle(string filename);
You could also pass string length as the second argument, so you could know what is the length of the string on cpp side.
[edit]
According to some comments you could also try to change [char *] to [wchar_t *] which is unicode. Then you should of course use approperiate attribute on C# side: CharSet=CharSet.Unicode
Upvotes: 2