My problem is , i have some functions in a DLL some of these functions are for example :
#include <string>
using namespace std;
extern "C" __declspec(dllexport) string __cdecl encryption(string s)
{
return s;
}
Whenever i try to call this function from C# , here is the code im using :
[DllImport("Packer.dll", EntryPoint = "encryption")]
static extern string encryption(string s);
i get an error : A call to PInvoke function 'Packer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged sig开发者_高级运维nature.
im guessing i get this error because i dont have the right declarations for the function can anyone guide me how to fix that , thanks in advance
std::string
can not be used with PInvoke, because C++ does not have an ABI for its objects which is required to properly clean stack, copy objects, etc. This is one of the greatest pains of C++.
You have to use char*
pointers and plain C APIs. Simply put, PInvoke does not work with C++.
As I'm sure you already know, the C++ std::string
is actually a template. Only when the template is instantiated (as std::basic_string<char>
in this case), the exact layout of the objects of that type and signatures of the methods are determined by the C++ compiler.
Unfortunately, only the C++ compiler in question has the access to all the relevant information (such as template source code) to make these kinds of decisions. That's why non-C features such as templates are generally not "transferable" even between different C++ compilers, let alone C++ and C#.
Also, C++ names are typically "mangled" in a C++ compiler-specific manner.
You'll have to change the signature of your native method, so it is becomes a "pure" C function:
- Ensure there is no C++ name mangling by declaring the function as
extern "C"
(you are already doing that). - Use
char*
parameter instead ofstd::string
. - Return
char*
result instead ofstd::string
, but be very careful how you do it. - Ensure your
DllImportAttribute.CallingConvention
matches the__cdecl
,__stdcall
or__fastcall
in your C.
The problem here is, you're using the STL string
class which C# doesn't know how to marshal. You have two options here:
- refactor your C++ code to work with
char *
buffers. Or write a wrapper or an overload or something that useschar *
instead ofstring
. - Write a C++/CLI wrapper around your C++ functions that uses
System::String
and calls the STL string versions internally.
If memory serves, if you don't specify otherwise P/Invoke assumes the calling convention is __stdcall
. If so, changing your __cdecl
to __stdcall
should fix the first problem.
As @Adam Rosenfield points out, you probably also need to pass and return a char const *
, not a string
. C# and C++ almost certainly have somewhat different ideas of what constitutes a string.
精彩评论