C++ DLL的类接口形参传递异常
情况一:形参中含有CString,参数栈内存异常
原因分析:形参中,字符串的传递,不要使用临时变量拷贝赋值,这样导致了形参的栈数据异常,导致形参中的ini类型的变量也出现了异常
解决方案:字符串的传递使用引用或者char*代替
class __declspec(dllimport) CInstrumentCtrlSample
{
public:
//该写法正常
bool Connect(const CString& resourceName, int tryTimes, CString& errMsg);
//该写法异常:如果写成下面这样会出现int参数异常,errMsg的内存也无法正常读取,具体原因未知。
bool Connect(CString resourceName, int tryTimes, CString& errMsg);
}
情况二:形参中含有STL类型数据,如std::map,std::list等
原因分析:DLL接口不能使用STL,具体参考:跨dll访问STL的map的问题 _followme163的博客-CSDN博客
解决方案:STL改为类的私有变量,暴露容器的操作函数,例如:
class DLL_API NeowayPrint
{
public:
void ClearBtwSubStringMap() {
m_BtwSubStringMap.clear();
}
void SetBtwSubString(const std::string& key, const std::string& value) {
m_BtwSubStringMap[key] = value;
}
private:
std::map <std::string, std::string> m_BtwSubStringMap;
};
情况三:形参中含有结构体,而结构体数据中含有string,这个是结构体数据存储原理导致的,此外结构体还有字节对齐等问题(参考:C/C++ struct字节对齐那些事儿 - 知乎 (zhihu.com))。
原因分析:string的内存是随内容变化的,这导致了结构体中的数据内存分布变更,导致在DLL接口的参数传递中找不到正确的数据指针,例如下面的代码,std::string变量放在了最前面,从而导致了这个结构体形参传入时,后面的int、bool等数据因为找不数据地址导致数据异常
typedef struct _PrintExecutionParameter_
{
std::string PrinterName; //打印机名称
int printCountMax; //连续打印最大数量(达到此数量后会提示)
int PrintNum; //打印数量(执行一次打印动作,打印多少张)
int SamebtPrintNum; //一张纸打印多少张模板
bool IsShowPrintDialog; //是否显示打印窗口
}PrintExecutionParameter, *pPrintExecutionParameter;
解决方案:将std::string变量放到最后
typedef struct _PrintExecutionParameter_
{
int printCountMax; //连续打印最大数量(达到此数量后会提示)
int PrintNum; //打印数量(执行一次打印动作,打印多少张)
int SamebtPrintNum; //一张纸打印多少张模板
bool IsShowPrintDialog; //是否显示打印窗口
std::string PrinterName; //打印机名称
}PrintExecutionParameter, *pPrintExecutionParameter;
情况四:从接口中返回string,无论是通过返回值返回,还是通过形参引用参数返回,都导致了数据崩溃
原因分析:string的内存在DLL接口函数中申请的,而在返回时,申请的内存被释放了,从而导致接口调用者在获取数据时出现了堆栈内存异常崩溃
#ifdef DLL_PRINT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
DLL_API std::string GetBtwFilePath() const;
DLL_API void GetBtwFilePath(std::string& strBtwFilePath) const;
解决方案:尽量都使用char*等指针来替代string,增强DLL接口的兼容性(情况一也建议此方案)
#ifdef DLL_PRINT
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
DLL_API void GetBtwFilePath(char* const _Destination, rsize_t const _DestinationSize) const;
情况五:接口调用时编译正常,Demo测试也正常,但是合入到实际工程中调用时奔溃,或是实际工程的其他函数在合入接口前正常,在合入后出现了异常
原因分析:接口中涉及的一些依赖DLL版本与实际工程中涉及的DLL版本冲突,例如:接口中用到了A.dll其版本3.1,实际工程中也用到了A.dll其版本是2.2
解决方案:令两者都使用相同版本的A.dll
待续...