导航
  • 主页
  • Windows SDK/API
  • 基础类
  • ActiveX
  • 数据库及相关技术
  • 网络及通讯开发
  • VCL组件使用和开发
  • 问答

问一个关于DLL的问题

Javpp 2005-09-01 12:08:47
我想在WINMAIN函数里直接动态连接DLL,DLL里打包了所有的窗体,但运行退出时出现了读内存错误,请大家帮帮忙!
代码如下:
EXE文件代码,我是将自动生成的工程去掉那个窗体,然后修改WINMAIN函数:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

//extern "C" __declspec (dllimport) HANDLE __stdcall LoadMainForm (TApplication *App);
HANDLE (__stdcall *LoadMainForm) (TApplication *App);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize ();
//Load dll
HINSTANCE HInst = LoadLibrary ("DTForm.dll");
if (HInst)
{
LoadMainForm = (HANDLE (__stdcall *) (TApplication *App)) GetProcAddress (HInst, "LoadMainForm");
if (LoadMainForm)
{
//Application->Handle = LoadMainForm (Application);
LoadMainForm (Application);
}
else
{
ShowMessage ("File Error!");
return 1;
}
}
else
{
ShowMessage ("Load dll Error!");
return 1;
}

Application->Run ();
FreeLibrary ("DTForm.dll");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------

DLL文件代码,只添加了一个窗口:
DLL文件:
//---------------------------------------------------------------------------

#include <vcl.h>
#include <windows.h>
#include <objbase.h>

#include "MainFrm.h"

#pragma hdrstop
//---------------------------------------------------------------------------
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be performing new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE's to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
//
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

//载入主窗体
extern "C" __declspec(dllexport) __stdcall HANDLE LoadMainForm (TApplication *App);

TApplication *dllApp;
void DllUnload (int reason);

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
//将EXE的句柄给DLL
dllApp = Application;
//Application = dllApp;
DllProc = &DllUnload;
return 1;
}
//---------------------------------------------------------------------------

HANDLE __stdcall LoadMainForm (TApplication *App)
{
Application = App;
Application->Title = "Gree AC Remote Control";
Application->Initialize ();
CoInitialize (NULL);
Application->CreateForm (__classid (TfrmMain), &frmMain);
Application->Run ();
return frmMain->Handle;
}
//---------------------------------------------------------------------------

void DllUnload (int reason)
{
if (reason == DLL_PROCESS_DETACH)
{
CoUninitialize ();

//将句柄交还给Application
Application = dllApp;
}
}
//---------------------------------------------------------------------------

DLL中窗口的代码:
CPP文件:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "MainFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::Exit1Click(TObject *Sender)
{
//这里不能使用Application->Terminate ();
//因为还没有将DLL的句柄交还给EXE,会出错
//不知道这样做对不对
Close ();
//Application->Terminate ();
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::FormDestroy(TObject *Sender)
{
DllProc (DLL_PROCESS_DETACH);
}
//---------------------------------------------------------------------------

头文件代码:
//---------------------------------------------------------------------------

#ifndef MainFrmH
#define MainFrmH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <Menus.hpp>
#include <ToolWin.hpp>
//---------------------------------------------------------------------------
class TfrmMain : public TForm
{
__published: // IDE-managed Components
TCoolBar *CoolBar1;
TToolBar *ToolBar1;
TToolBar *ToolBar2;
TToolButton *ToolButton1;
TToolButton *ToolButton2;
TToolButton *ToolButton3;
TMainMenu *MainMenu1;
TMenuItem *System1;
TMenuItem *Logout1;
TMenuItem *AddUser1;
TMenuItem *ConfigUser1;
TMenuItem *DeleteUser1;
TMenuItem *Setting1;
TMenuItem *N1;
TMenuItem *Logout2;
TMenuItem *Exit1;
TMenuItem *Edit1;
TMenuItem *Add1;
TMenuItem *Inner1;
TMenuItem *OutDoor1;
TMenuItem *Help1;
TMenuItem *Help2;
TMenuItem *About1;
TMenuItem *AboutGree1;
void __fastcall Exit1Click(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TfrmMain(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmMain *frmMain;
//---------------------------------------------------------------------------
#endif

请大家指点一下,代码中可能还有别的错误,请指点,谢谢!!!
...全文
309 点赞 收藏 23
写回复
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
sczyq 2005-09-06
Dll 窗口退出时,应当发放一条消息,通知主程序释放DLL,才是正解
回复
Javpp 2005-09-06
主窗体代码:
HPP文件:
//---------------------------------------------------------------------------

#ifndef MainFrmH
#define MainFrmH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <Menus.hpp>
#include <ToolWin.hpp>
//---------------------------------------------------------------------------
class TfrmMain : public TForm
{
__published: // IDE-managed Components
TCoolBar *CoolBar1;
TToolBar *ToolBar1;
TToolBar *ToolBar2;
TToolButton *ToolButton1;
TToolButton *ToolButton2;
TToolButton *ToolButton3;
TMainMenu *MainMenu1;
TMenuItem *System1;
TMenuItem *Logout1;
TMenuItem *AddUser1;
TMenuItem *ConfigUser1;
TMenuItem *DeleteUser1;
TMenuItem *Setting1;
TMenuItem *N1;
TMenuItem *Logout2;
TMenuItem *Exit1;
TMenuItem *Edit1;
TMenuItem *Add1;
TMenuItem *Inner1;
TMenuItem *OutDoor1;
TMenuItem *Help1;
TMenuItem *Help2;
TMenuItem *About1;
void __fastcall ToolButton1Click(TObject *Sender);
void __fastcall About1Click(TObject *Sender);
void __fastcall Exit1Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TfrmMain(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmMain *frmMain;
//---------------------------------------------------------------------------
#endif


CPP文件:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "MainFrm.h"
#include "AboutFrm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
this->Position = poDesktopCenter;
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::ToolButton1Click(TObject *Sender)
{
ShowMessage ("asdf");
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::About1Click(TObject *Sender)
{
TfrmAbout *frmAbout = new TfrmAbout (Application);
frmAbout->ShowModal ();
delete frmAbout;
frmAbout = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::Exit1Click(TObject *Sender)
{
Close ();
}
//---------------------------------------------------------------------------

回复
Javpp 2005-09-06
DLL的入口文件:
//---------------------------------------------------------------------------

#include <vcl.h>
#include <windows.h>
#include <objbase.h>

#include "MainFrm.h"

#pragma hdrstop
//---------------------------------------------------------------------------
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be performing new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE's to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
//
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

//载入主窗体
extern "C" __declspec(dllexport) __stdcall HANDLE LoadMainForm (TApplication *App);

TApplication *dllApp;

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
//根据DLL被调用还是被释放交换句柄
switch (reason)
{
case DLL_PROCESS_ATTACH: //调用DLL
{
CoInitialize (NULL);
dllApp = Application;
break;
}
case DLL_PROCESS_DETACH: //释放DLL
{
CoUninitialize ();
Application = dllApp;
break;
}
}

return 1;
}
//---------------------------------------------------------------------------

HANDLE __stdcall LoadMainForm (TApplication *App)
{
Application = App;
Application->Title = "Gree AC Remote Control";
Application->Initialize ();
Application->CreateForm (__classid (TfrmMain), &frmMain);
Application->Run ();
return frmMain->Handle;
}
//---------------------------------------------------------------------------
回复
Javpp 2005-09-06
偶重新写了下代码,如下,现在没问题了,起码表面上没有再出错,请各位指点:
EXE的WINMAIN函数
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

//extern "C" __declspec (dllimport) HANDLE __stdcall LoadMainForm (TApplication *App);
HANDLE (__stdcall *LoadMainForm) (TApplication *App);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
//Load dll
HINSTANCE HInst = LoadLibrary ("DTForm.dll");
if (HInst)
{
LoadMainForm = (HANDLE (__stdcall *) (TApplication *App)) GetProcAddress (HInst, "LoadMainForm");
if (LoadMainForm)
{
Application->Handle = LoadMainForm (Application);
}
else
{
ShowMessage ("File Error!");
return 1;
}
}
else
{
ShowMessage ("Load dll Error!");
return 1;
}

FreeLibrary ("DTForm.dll");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//---------------------------------------------------------------------------
回复
cczlp 2005-09-06
使用new而不是Application->CreateForm.
看看《避免C++Builder中的常见错误:来自TeamB的建议》就知道了。
pdf文档,文字复制不下来,楼主可在网上下载看看,很有帮助的。
回复
cygwolf 2005-09-06
主窗体应该非模态,用new创建,自动销毁,你用FreeLibrary ("DTForm.dll");销毁
是不对的,应该去掉。
回复
LLTing 2005-09-05
补充:你的那个DLL写的好像有问题--Dll.cpp,DllMain.h,DllMain.cpp(界面文件代码)
把extern "C" __declspec (dllimport) HANDLE __stdcall LoadMainForm
这句丢到DllMain.h中,Dll.cpp文件空着(切记),在DllMain.cpp中包含DllMain.h,
然后写处理函数就可以了。
"BCB5开发人员指南"说:当创建了一个VCL的DLL,所需VCL组件被连接到DLL,这将
导致一定量的越界(overhead),通过将几个组件结合进一个只需要一个VCL组件支持
的DLL中可以压缩这种越界。这种规范严格限制了在DLL中使用VCL组件的范围。开发
时一定要注意!
回复
Javpp 2005-09-05
LLTing(会飞的木鱼):
extern "C" __declspec (dllimport) HANDLE __stdcall LoadMainForm 放到DllMain.h中?
Dll.cpp才是Dll的入口啊,DllMain.h和DllMain.cpp是Dll中一个窗体的文件,怎么要把Dll的接口放到这个文件里 ?不懂。
回复
leonatcs 2005-09-05
Application = App;恐怕不能这样赋值!
为什么一定要把exe的application赋给dll的application呢?!

dllApplication->Handle = ExeApplication->MainForm->Handle;这样倒是可以。
既然不要主窗体,或者你可以新建一个console exe来加载你的dll。
回复
Javpp 2005-09-04
那在WINMAIN函数里使用下面哪个函数:
Application->Handle = LoadMainForm (Application);

LoadMainForm (Application);

后来我又把DLL的代码改了一下,明天帖过来,主要是更改了DLLENTRYPOINT函数里的
回复
jishiping 2005-09-04
经过实践,将 HANDLE __stdcall LoadMainForm (TApplication *App) 里面的 Application = App; 拿掉就可以了。
回复
LLTing 2005-09-04
好像你想保护整个程序包括界面似的,设计思路有点儿问题吧?!
具体不说了,我以前设计带界面的DLL也出现过类似的问题,你看
看"BCB5开发人员指南"就知道了,DLL是不能这样加载的!
回复
mdf2008 2005-09-04
>>>搞得好复杂,还没有见过BCB中这么写程序的,

我也不明白

回复
Javpp 2005-09-02
老大,那这个和出现错误有关系吗?

你有没有运行一下看看?
回复
jishiping 2005-09-02
发现Application的值在EXE和DLL中不同
----------------------------------------------------------
如果DLL使用静态连接,那么EXE和DLL中的Application就一样了。
回复
Javpp 2005-09-02
UP,今天设置断点跟踪了Application一下,发现Application的值在EXE和DLL中不同,期待高手给解释一下,正在看INSIDE VCL,但是看不明白
回复
tiegerium2 2005-09-02
这样搞是为了实验吗?真的想不通,要变换一个主窗口就要变换不同版本的DLL吗?
DLL中已经有了:
Application->Initialize ();
Application->Run ();

所以上面两句(WinMain)不要了.

是不是Application->Run ()在程序结束后才返回呢?
是不是应该把FreeLibrary ("DTForm.dll")放到别的地方呢?
回复
Javpp 2005-09-01
cczlp(不惑) ( )
好像和创建窗体的方法没关系吧
Application->Initialize ();

Application->Run ();
这两个函数EXE和DLL重复了,应该只要一个就可以了。
================================

今天我在公司运行,什么错误都没有了,晕了

还有,谁有比较深入一些的CB些DLL的资料啊,找到的都是查不多的
================================

jishiping(JSP 季世平) 老大,不知道你有没有调试,我每次退出时就出现读内存错误,调试窗口上显示内存地址的内容都是问号,但好像程序还要读那里的内容,可能就是你说的DLLENTRYPOINT中没有区分REASON的原因吧,我回去试一下。

还有,老大,我是想这样的,将所有的窗体按照功能块放到DLL中,一些公用的函数放到另外一个DLL中,然后调用,不知道这样做合理不合理。
回复
Javpp 2005-09-01
up,还是没解决,不知道问题在哪里
回复
jishiping 2005-09-01
DllEntryPoint 中不区分reason,每次都执行 dllApp = Application; 不知道会不会造成错误。
回复
发动态
发帖子
C++ Builder
创建于2007-08-02

1.3w+

社区成员

C++ Builder相关内容讨论区
申请成为版主
社区公告
暂无公告