The calling convention describes to the compiler and linker how parameters, the stack and registers are to be handled. So if these don't match things won't work or memory can be corrupted. For instance, if the caller thinks the first parameter should be passed in the register eax, but the callee thinks it's on the stack. Things will obviously not work. For more info on calling conventions Wikipedia has a good description here. The calling convention you choose isn't very important, unless the compiler forces one on you. For instance for 64 bit programs Microsoft only uses one to my knowledge. So, I suggest adding __cdecl
in front of the functions you have written. And using CallingConvention.Cdecl
on the DLLImport
lines.
Also, all the data types must exactly match. For instance:
[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern string GetStringKey();
This says it is returning a string, however despite our using the term string to represent a series of characters followed by a null. In this case string is a formal type. Which is they type std::string. Which is not what is being returned by the C code. The C code is returning a pointer to a char.
Generally passing complex types based on a library is kinda iffy. That's because it requires both languages to use the exact data structure to represent the type. So when crossing language boundaries it's often useful to stay with your own custom structures and very primitive types.
So I recommend your C function be this instead:
__cdecl bool GetStringKey(char *buffer, int maximumLength)
{
// Write code here to copy all the characters from your "My String"
// to the buffer or use a standard library function for copying char * strings (often called C strings) when copying make sure to copy the null character at the end. It's definitely needed.
return true; // Yes it fit
}
You will need to change your DllImport to match. Once that is working you can add code to never go over the maximum buffer length (to prevent memory corruption) and maybe change the bool to the length of the string or -1 for failure.
I suggested this particular function prototype because it doesn't pass memory between languages. Instead the C code fills in a buffer from the C++ code. Which is the safest way to do something. Passing memory between unrelated modules (in this case C and C++ doesn't always work). Though I suspect in this case your C and C++ compiler and libraries are enough alike. That you could just switch to returning a std::string. As long as both sides match perfectly.