I am trying to call a C# lib from a C++ program. C# and this interop is pretty new for me. Some of the communications have been easy until I had to face strings inside structures. I have been reading a lot and saw several examples, but I am unable to replicate them and make them work.
I extracted the code with the example of sending a string, and retriving the string which works (_string_exchange). And the method _return_struct which returns a struct with a string that doesnt works. Debugger fails when I try to use the variable for std::cout, with an unhandled exception from 0x00007FFFEA98A388 (KernelBase.dll). The Console.WriteLine havent wrote anything during the call.
I assume this is a problem matching the scrutures. Both are compiled in release x64, using .NET Framework 4.6.1. Also I have been checking with sizeof() and Marshal.SizeOf() to check that both have the same byte length. Also tried to change c++ project character from unicode to multibyte without success.
I saw examples like this that were pretty good explaning everything, but I dont know what I am missing: Passing strings/arrays within structures between C++/C#
C++ program:
struct myStruct
{
int myInt;
double myDouble;
bool myBool;
char myString[64];
};
int main() {
const TCHAR* pemodule = _T("F:\\PATH\\TO\\DLLsi\\LibCSharp.dll");
HMODULE lib = LoadLibrary(pemodule);
typedef LPCSTR(_cdecl *_string_exchange)(LPCSTR s);
auto pString_exchange = (_string_exchange)GetProcAddress(lib, "_string_exchange");
LPCSTR test = pString_exchange("LPCSTR test works fine");
std::cout << test << std::endl;
typedef myStruct(_cdecl *_return_struct)();
auto pReturn_struct = (_return_struct)GetProcAddress(lib, "_return_struct");
myStruct aStruct = pReturn_struct();
std::cout << aStruct.myString << aStruct.myBool << " " << aStruct.myDouble << " " << aStruct.myInt << std::endl;
return 0;
}
C# library:
namespace LibCSharp
{
public class Class1
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct myStruct
{
public int myInt;
public double myDouble;
[MarshalAs(UnmanagedType.U1)]
public byte myBool;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string myString;
}
[DllExport]
public static myStruct _return_struct()
{
Console.WriteLine("test");
myStruct a;
a.myInt = 3;
a.myDouble = 2;
a.myBool = 1;
Console.WriteLine(a.myBool);
a.myString = "Hello world! My values are: ";//28
Console.WriteLine(a.myString);
return a;
}
[DllExport]
public static string _string_exchange(string s)
{
Console.WriteLine(s);
return s;
}
}
}
I am also aiming in a future to make this structure an array, I hope once this is solved I wont face much problems, but any comment in advance is also wellcome.
Thank you in advance
__stdcall. Returning a structure as a function return value requires it to be "blittable", an expensive word that means that the managed layout must be the same as the native layout. Both the bool and the string make it non-blittable, replace with byte and a fixed-size buffer. Returning strings from a C or C++ function is always risky, hard to release the memory correctly. BSTR is better.