dll 导出 vcl 类???

w88529593 2008-10-16 11:17:34
如题,谁做过这样的测试例子,可以讲讲如何实现吗?就是新建个Dll工程,选择支持Vcl,然后 新建个From1,在类前声明为导出类: __declspec(dllexport) __stdcall class TForm1 : public TForm ,但是再新建个Exe程序,如何使用DLL中的这个导出类TForm1呢?
...全文
129 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
你先尝试一下,这样可以验证我们的想法是否正确
w88529593 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 yuanreid 的回复:]
建议手工释放Frame,即dll中再提供一个释放资源的接口,同时将它从Page上抹去,不要让Page再找到它。最后再FreeLibrary(hDLL)。
我怀疑资源释放的顺序上有问题。
[/Quote]


“将它从Page上抹去,不要让Page再找到它”
你的意思是如果动态创建一个Frame,那么我就要把他存起来,然后在关闭时,遍历这个保存所有动态创建的Frame列表,把动态创建的这些Frame的Parent设置为NULL?
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
建议手工释放Frame,即dll中再提供一个释放资源的接口,同时将它从Page上抹去,不要让Page再找到它。最后再FreeLibrary(hDLL)。
我怀疑资源释放的顺序上有问题。
w88529593 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 yuanreid 的回复:]
析构函数中,你是手工释放Frame的吗?
[/Quote]
没有手工释放,就是默认的,然后出错后,我给TFrame3类添加了一个析构:~TFrame3(){};但是还是不行
w88529593 2008-10-19
  • 打赏
  • 举报
回复
不是OnDestroy(),是FormDestroy这个事件,发帖时没细看代码,还以为和VC里面一样
w88529593 2008-10-19
  • 打赏
  • 举报
回复
如果我在MDI的OnDestry()事件中不调用 FreeLibrary(hDLL),不释放DLL的话,居然不会再抛异常,估计还是内存释放的问题,哪位指点一下,怎么能不发生异常呢?
MDI中的代码如下:
TTabSheet pPage=new TTabSheet(PageControl1);
pPage->PageControl =PageControl1;
pPage->Caption="Frame1";
framePage(pPage,0);
这个是动态创建一个Page然后加入到PageControl中,framePage是个函数指针,是这样framePage=(TFramePage)GetProcAddress(hDLL,"TestFramePage");得到的。
然后DLL中导出的函数是这样的:
extern "C" __declspec(dllexport) __stdcall void TestFramePage(
TCustomControl *ParentCtrl)
{
TFrame3*frame=new TFrame3(ParentCtrl);
frame->Parent=ParentCtrl;
}
伙计们看看,这个是怎么回事导致的FreeLibrary时,抛非法访问内存的异常
  • 打赏
  • 举报
回复
做包
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
析构函数中,你是手工释放Frame的吗?
w88529593 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 yuanreid 的回复:]
我们公司的一的一套软件架构就是MIDI主框架+DLL中的Child窗口,不过不是导出类
[/Quote]


这个我测试成功了,把MDI的Application指针传进去,可以把里面新建的ChildForm窗体显示在MDI里面,
不过如果我把Frame写进DLL中,然后在MDI中有个PageControl,然后动态创建一个Page,然后把Page的指针传进,想把Frame显示到动态创建的这个Page,也可以测试成功,但是在关闭MDI时,抛出异常,我看了是运行到~Form(){}时抛异常的,非法访问内存了,会不会是控件的析构的先后顺序有问题呢?
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
呵呵,我也刚写了一个。已经通过了。


void __fastcall TForm1::Button1Click(TObject *Sender)
{
//说明Delphi Dll文件内函数的指针
HANDLE __stdcall (*NewButton)(HANDLE handle);



//取得此Dll文件函数地址
(FARPROC &) NewButton=GetProcAddress(hInst,"NewButton");

//调用Dll文件函数
btn = NewButton(this);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
//说明Delphi Dll文件内函数的指针
int __stdcall (*DeleteButton)(HANDLE handle);



//取得此Dll文件函数地址
(FARPROC &) DeleteButton=GetProcAddress(hInst,"DeleteButton");

DeleteButton(btn);

FreeLibrary(hInst);
}


DLL:

HANDLE __stdcall NewButton(HANDLE parent)
{
TWinControl* ctl = (TWinControl*)(parent);
TButton* btn = new TButton(ctl);
btn->Parent = ctl;
btn->Top = 100;
btn->Left = 100;
btn->Caption = "test";

return (HANDLE)btn;
}

int __stdcall DeleteButton(HANDLE button)
{
TButton* btn = (TButton*) button;
delete btn;
return 0;
}
w88529593 2008-10-19
  • 打赏
  • 举报
回复
结贴送分了
w88529593 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 yuanreid 的回复:]
TFrame3*frame=new TFrame3(ParentCtrl);

最好还是delete掉。

delete (TFrame3*)pIter->second;
FrameMap.erase(pIter);
[/Quote]

伙计,你是高手,佩服,搞定了
w88529593 2008-10-19
  • 打赏
  • 举报
回复
而这个PageControl是在Exe程序里面的MDI主界面里面存放着的
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
TFrame3*frame=new TFrame3(ParentCtrl);

最好还是delete掉。

delete (TFrame3*)pIter->second;
FrameMap.erase(pIter);
w88529593 2008-10-19
  • 打赏
  • 举报
回复
Form的应该没什么问题,它是没有加载在其他的容器里面的,而Frame我是把它新建后放进了PageControl的Page里面了,然后这个释放就有问题
w88529593 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 yuanreid 的回复:]
我担心的一个问题是,你的同一个DLL内的Frame被用了多次,再你释放第一个Frame后就FreeLibrary的话,其他的Frame就无法再释放了,不知道这种怀疑存在否。
[/Quote]
不是的,我的代码是这样的:

在DLL中定义个map <TCustomControl*,TFrame*> FrameMap;

extern "C" __declspec(dllexport) __stdcall void TestFramePage(
TCustomControl *ParentCtrl)
{
TFrame3*frame=new TFrame3(ParentCtrl);
frame->Parent=ParentCtrl;
FrameMap.insert(make_pair(ParentCtrl,frame));
}


frame是每次动态new的。

释放的函数我这样写的:

extern "C" __declspec(dllexport) __stdcall void FreeFramePage(
TCustomControl *ParentCtrl)
{
map <TCustomControl*,TFrame*>::iterator pIter;
for(pIter=FrameMap.begin();pIter!=FrameMap.end();pIter++)
{
if(pIter->first ==ParentCtrl)
{
pIter->second->Parent=NULL;
FrameMap.erase(pIter);
}
}
}

我并没有手动释放那个Frame,我只是把他的Parent设置为NULL,按你说的意思将它从Page上面抹去,

然后在FreeLibrary(hDLL)前,我调用freeFramePage(pPage),freeFramePage是用GetProcAddress得到的函数指针
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
另外的办法就是将所有的DLL,LoadLibrary后存入map,复用就行了。但是每次创建的Frame有可能要你自己释放,比如通过Dll内提供的释放接口,传递参数为Frame实例的地址,Dll内负责释放。这样就不要做FreeLibrary操作了,进程退出时让系统回收吧。
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
我担心的一个问题是,你的同一个DLL内的Frame被用了多次,再你释放第一个Frame后就FreeLibrary的话,其他的Frame就无法再释放了,不知道这种怀疑存在否。
w88529593 2008-10-19
  • 打赏
  • 举报
回复
我看他的异常是指向这个类:class PASCALIMPLEMENTATION TForm : public TCustomForm 的inline __fastcall virtual ~TForm(void) { },这个函数,看来是比较郁闷的事情哦
yuanreid 2008-10-19
  • 打赏
  • 举报
回复
你写一个最简单的测试例子试试,dll中创建最简单的frame,主程序加载放入窗口内,然后是否资源,再FreeLibrary。
如果没有问题,再跟踪你现有的工程代码。

这个是在Dll中显示窗口,

//说明Delphi Dll文件内函数的指针
int __stdcall (*FormShow)(HWND handle);

//将Delphi编写的Dll文件载入
HINSTANCE hInst = LoadLibrary("..\\DLLFormDemo.dll");

//取得此Dll文件函数地址
(FARPROC &) FormShow=GetProcAddress(hInst,"FormShow");

//调用Dll文件函数
FormShow(this->Handle);

//释放Dll文件
FreeLibrary(hInst);



DLL中的代码,由于是ShowModal,所以后面直接就释放了。但原理同你在Dll中公布一个释放接口一样的,不知道你的释放代码是如何做的。

int __stdcall FormShow(HWND handle)
{
Dynamic_Form = new TDynamic_Form(NULL);
Dynamic_Form->ShowModal();
delete Dynamic_Form;
return 0;
}
加载更多回复(14)

604

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder VCL组件使用和开发
社区管理员
  • VCL组件使用和开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧