C#导入C++类成员DLL时参数数量不符却正常,求原因解释
C++ DLL类成员函数导入C#的参数异常问题
问题背景
尝试将C++编写的DLL导入C#时遇到参数传递异常:
C++代码
.h文件
#define DllExport __declspec( dllexport ) extern "C" { class DllExport SomeClass { public: SomeClass(); virtual ~SomeClass(); private: BOOL SomeFunction(DWORD cCode, DWORD dwIn, LPDWORD lpdwOut); } }
.cpp文件
BOOL SomeClass::SomeFunction(DWORD cCode, DWORD dwIn, LPDWORD lpdwOut) { if (lpdwOut == NULL) return FALSE; //@006A BOOL Result = FALSE; some code... return Result ; }
初始C#调用代码
[DllImport(ConstVar.PMDDLLPATH, EntryPoint = "?SomeFunction@SomeClass@@AEAAHKKPEAK@Z", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SomeFunction([MarshalAs(UnmanagedType.U4)] uint cCode, [MarshalAs(UnmanagedType.U4)] uint dwIn, [MarshalAs(UnmanagedType.U4)] ref uint lpdwOut); uint res = 0; bool result = SomeFunction(222, 2, ref res);
调试时C端接收到的参数值不正确,但在C#函数中添加一个额外的前置参数后,C端能得到正确值:
[DllImport(ConstVar.PMDDLLPATH, EntryPoint = "?SomeFunction@SomeClass@@AEAAHKKPEAK@Z", CallingConvention = CallingConvention.Cdecl, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SomeFunction(uint param, [MarshalAs(UnmanagedType.U4)] uint cCode, [MarshalAs(UnmanagedType.U4)] uint dwIn, [MarshalAs(UnmanagedType.U4)] ref uint lpdwOut); uint res = 0; bool result = SomeFunction(0, 222, 2, ref res);
原因解释
这是C++非静态成员函数的底层调用机制导致的:
- C++的非静态成员函数隐含第一个参数
this指针,用来指向调用该函数的类实例对象。即使代码里没有显式声明,编译器编译时会自动把this作为第一个参数插入到函数参数列表中。 - 你导出的
SomeFunction是SomeClass的非静态成员函数,它的实际参数列表是(SomeClass* this, DWORD cCode, DWORD dwIn, LPDWORD lpdwOut),但初始C#声明中没有对应这个隐含的this参数,导致所有参数传递位置整体偏移:原本要传给cCode的值被当成this指针,后续参数全部错位,所以C++端接收到的值完全错误。 - 当你在C#函数声明中添加第一个参数
param时,这个参数就对应了C端的this指针(此处传0能运行是因为该private函数没有访问类成员变量,若函数内部访问类成员,传0会直接崩溃),后续参数和C端实际参数列表一一对应,因此C++端能接收到正确的参数值。
注意事项
- 这种直接调用类成员函数的方式并不规范,非静态成员函数依赖类实例,随意传
this指针存在崩溃风险。 - 更合理的做法:要么将成员函数改为
static(此时无this指针),要么在C++中导出C风格的包装函数,负责创建类实例、调用成员函数,再在C#中对应调用这些包装函数。
内容的提问来源于stack exchange,提问作者Hulyo
相关产品推荐
相关产品推荐

