问题
my c++ dll:
int test2::CallMe(int y) {
return y;
}
c# code:
[DllImport("test2.dll",CharSet = CharSet.Anci)]
private static extern int CallMe(int y);
Console.WriteLine(CallMe(7));
if the dll and the test program are compiled in x86 i get a print: 7 but if i compile them at X64 for c++ and X64 or any CPU for c# the print is: 0
Any suggestion?
edit: the problem is the call, because in debugger i see that the CPP receives 0 , or null in case of struct.
edit 2: the functions are exported using a def file. if i export a function using extern "C" it works fine but i cant export a function of a calss, or i dont know how
edit 3: apparently the arguments are not actually zero, only the last argument is zero, all arguments are shifted, the second param is set to the first one and so on
回答1:
Calling a C++ function from C# isn't exactly/completely/transparently supported. You can try using the CallingConvention = CallingConvention.ThisCall
in the DllImport
, but it isn't an exact science. Let's say that it should work for simple cases...
[DllImport("test2.dll", CallingConvention = CallingConvention.ThisCall)]
private static extern int CallMe(IntPtr obj, int y);
where obj
is a reference to the C++ object (what in C++ is called this
). The difference you get between 32 and 64 bits happens because the place where the this
pointer is placed changes between 32 and 64 bits.
For very simple cases, when in truth the this
isn't used by the C++ method (and it doesn't use virtual functions), you can pass IntPtr.Zero
as the pointer. Normally you would have an extern C
method that creates the C++ object "C++ side" and returns an IntPtr
(a void*
) to C#, and then C# calls the C++ methods passing this IntPtr
.
The "brittle" point is that the C++ compiler mangles the name of C++ methods (methods that aren't in an extern "C"
block), so you have to "manually" discover them (for example using the DUMPBIN /exports
)... And to make things "easier", the mangled names change between 32 and 64 bits :-)
An example:
C++-side:
class Store
{
private:
int value;
public:
__declspec(dllexport) void Put(int value)
{
this->value = value;
}
__declspec(dllexport) int Get()
{
return this->value;
}
__declspec(dllexport) void Increment()
{
this->value++;
}
};
extern "C"
{
__declspec(dllexport) int PlusOne(int x)
{
return x + 1;
}
__declspec(dllexport) Store* NewStore()
{
return new Store;
}
__declspec(dllexport) void DeleteStore(Store* store)
{
delete store;
}
}
class Program
{
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static int PlusOne(int x);
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr NewStore();
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static void DeleteStore(IntPtr store);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Put@Store@@QAEXH@Z")]
extern static void Put32(IntPtr store, int value);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Get@Store@@QAEHXZ")]
extern static int Get32(IntPtr store);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Increment@Store@@QAEXXZ")]
extern static void Increment32(IntPtr store);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Put@Store@@QEAAXH@Z")]
extern static void Put64(IntPtr store, int value);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Get@Store@@QEAAHXZ")]
extern static int Get64(IntPtr store);
// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Increment@Store@@QEAAXXZ")]
extern static void Increment64(IntPtr store);
static void Main(string[] args)
{
int x = PlusOne(1);
Console.WriteLine(x);
IntPtr store = NewStore();
int ret;
if (IntPtr.Size == 8)
{
Put64(store, 5);
Increment64(store);
ret = Get64(store);
}
else
{
Put32(store, 5);
Increment32(store);
ret = Get32(store);
}
Console.WriteLine(ret);
DeleteStore(store);
}
}
来源:https://stackoverflow.com/questions/42483796/calling-a-c-code-from-c-sharp-in-x64-all-arguments-shift-by-one