// (1) 创建一个lib项目:Tlib.lib
// 定义一个类CT,继承CObject
class CT : public CObject
{
private:
int a;
public:
void set(int na) { a = na; }
int get() { return a; }
CT() { a = 0; }
~CT() {}
};
// (2)定义一个类CTA, CT类为CTA的一个属性
#include "T.h"
class CTA
{
private:
CT *m_pT;
public:
CT* CreateNewT();
void SetT(CT* pT);
CTA();
~CTA();
};
CTA::CTA()
{
m_pT = NULL;
}
CTA::~CTA()
{
if (m_pT)
{
delete m_pT; m_pT = NULL;
}
}
CT* CTA::CreateNewT()
{
m_pT = new CT();
return m_pT;
}
// (3) 创建一个dll调用CTA类
// 在stdafx.h中加入:
#pragma comment(lib, "Tlib.lib")
#define TLIB_EXPORT
#ifdef TLIB_EXPORT
#define TLIB_API extern "C" __declspec(dllexport)
#else
#define TLIB_API extern "C" __declspec(dllimport)
#endif
TLIB_API int DoAlib(CTA *pTA)
{
if (pTA)
{
pTA->CreateNewT();
}
return 0;
}
// (4)创建一个MFC对话框程序,m_pTA在头文件中定义,并在对话框构造函数中初始化:m_pTA = new CTA();
// 对话框上放置一个Button按钮,按钮事件:
void CCexeDlg::OnBnClickedButton1()
{
typedef void(*DoTA) (CTA *);
HMODULE hLibrary = LoadLibrary(L"bdll.dll");
if (hLibrary)
{
DoTA lpFunc = (DoTA)GetProcAddress(hLibrary, "DoAlib");
if (lpFunc) (*lpFunc)(m_pTA);
FreeLibrary(hLibrary);
}
}
//重载对话框DestroyWindow()
{
if (m_pTA)
{
delete m_pTA; m_pTA = NULL;
}
}
// (5) 点击Button按钮,无异常,但关闭对话框会显示异常:
// 0x00007FF72CE92E0A 处有未经处理的异常(在 Cexe.exe 中): 0xC0000005: 读取位置 0x00007FFF42FE3360 时发生访问冲突。
// 异常定位在delete m_pTA; m_pTA = NULL;语句。
// 如果把class CT : public CObject修改为class CT,不再继承CObject类,则不会产生异常。
// 请问是何种原因?如何解决?
当CObject的派生类中使用delete时,如果对象正在被跟踪,则将调用CObject::InternalRelease。如果对象是通过new分配的,则该对象的内存被释放,并且内存跟踪信息被删除。如果对象是从非MFC内存分配函数分配的,则只会删除内存跟踪信息。
在你的代码中,CTA的析构函数中调用了delete m_pT,但是m_pT是通过new分配的内存,在释放内存前会调用CObject的InternalRelease函数。如果在DLL中的CT对象已被加载并在调用DLL中的函数时被锁定,则InternalRelease函数将导致访问冲突。
为了解决此问题,可以使用下列方法之一:
在DLL中重载CObject::InternalRelease函数,并确保在调用之前解锁对象。
使用动态分配的内存(使用malloc和free)来实例化CT对象,从而避免调用InternalRelease。
不使用CObject的派生类,而是使用基本的C++类。