BCB2009编写MDI Application,框架程序定义标准的__stdcall调用标准;
Delphi7和BCB6分别编写Dll_X.dll,插件包括接口函数和MDIChild Form。 //--------------------------------------------------------------------------
//Dll_c.dll的接口标准:
extern "C" __declspec(dllexport) char* __stdcall GetCaption(void);
extern "C" __declspec(dllexport) bool __stdcall ShowDllForm(void*,char*); //Dll_c.dll的函数内容:
void* hSave = NULL;//临时保存DllForm父指针 //标准的Dll函数入口
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if((reason==DLL_PROCESS_DETACH) && hSave)
Application=(TApplication*)hSave ; //恢复Application
return 1;
} //输出函数定义:获取主窗体标题
char* __stdcall GetCaption(void)
{
static char lpCaption[128];
strcpy(lpCaption,"Dll_c.dll插件演示");
return lpCaption;
} //输出函数定义:打开DLL主窗体
bool __stdcall ShowDllForm(void* hHandle,char* lpCaption)
{
if(NULL==hSave) //保存Application,传递Application
{
hSave=Application;
Application=(TApplication*)hHandle;
}
TDllForm *DllForm=new TDllForm(Application);
DllForm->Caption=lpCaption;
DllForm->Show();
return true;
} //--------------------------------------------------------------------------
//Dll_d.dll的接口标准:
function GetCaption: Pchar; stdcall;
function ShowDllForm(hHandle: THandle; lpCaption: Pchar): Boolean; stdcall; //Dll_d.dll的函数内容:
//标准的Dll函数入口
MDIChild Form返回,这里怎么恢复Application??? //输出函数定义:获取主窗体标题
function GetCaption: Pchar; stdcall;
var
lpCaption:array[0..100] of char;
begin
lpCaption:='Dll_d.dll插件演示';
Result:=lpCaption;
end; //输出函数定义:打开DLL主窗体
function ShowDllForm(hHandle: THandle; lpCaption: Pchar): Boolean; stdcall;
var
hSave: THandle;//这个变量是用来临时保存DllForm父指针的
begin
hSave:=Application.Handle;
Application.Handle:=hHandle;
DllForm.Create(Application);
DllForm.Caption:=lpCaption;
DllForm.Show;
Application.Handle:=hSave;
Result:=true;
end; //--------------------------------------------------------------------------
//BCB 编写的MDI结构部分代码 //MDIApplication.h
HINSTANCE DllInst;//Dll句柄全局变量声明
char* (__stdcall *GetCaption)();//获取DllForm的标题
bool (__stdcall *ShowDllForm)(void*,char*);//显示DllForm的界面 //MDIApplication.cpp
void __fastcall TMainForm::FormCreate(TObject *Sender)
{//框架启动时初始化Dll模块,这里以Dll_d.dll为例
if(NULL==DllInst)
DllInst=LoadLibrary("Library\\Dll_d.dll");
if (DllInst)
{
GetCaption=(char* (__stdcall*)())GetProcAddress(DllInst,"GetCaption");
ShowDllForm=(bool (__stdcall*)(void*,char*))GetProcAddress(DllInst,"ShowDllForm");
ShowDllForm(Application,GetCaption());//在MDI区域显示子窗体
}
} //-------------------------------------------------------------------------
问题1:为什么Dll_c.dll中的GetCaption()能返回正确的字符串,而Dll_d.dll的GetCaption()只能返回第一个字符,乱码。(使用__cdecl和__pascal等等都测试过。反过来,用Delphi写MDIApp,则Dll_c.dll传递乱码,何解?)
问题2:Dll_d.dll如何传递参数才能正确调用ShowDllForm?(两个dll中的Form都已经设置成MDIChild模式,且编写了退出释放代码。)
问题3:为什么D5程序员指南中指出Dll中使用过多的VCL控件将造成越界,如何理解?能否在Dll中实现MIS系统,包括ACCESS和SQL连接,读写操作,XML文件操作,Flash交互,D3D交互等? 这几个问题已经烦了我一个多星期了,差不多把Google翻遍了,做了十几个Demo,但是还不能确定,各位达达,高手,牛人,ccrun类,帮忙看看啦,这种结构好好麻烦啊~~~~
Delphi7和BCB6分别编写Dll_X.dll,插件包括接口函数和MDIChild Form。 //--------------------------------------------------------------------------
//Dll_c.dll的接口标准:
extern "C" __declspec(dllexport) char* __stdcall GetCaption(void);
extern "C" __declspec(dllexport) bool __stdcall ShowDllForm(void*,char*); //Dll_c.dll的函数内容:
void* hSave = NULL;//临时保存DllForm父指针 //标准的Dll函数入口
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
if((reason==DLL_PROCESS_DETACH) && hSave)
Application=(TApplication*)hSave ; //恢复Application
return 1;
} //输出函数定义:获取主窗体标题
char* __stdcall GetCaption(void)
{
static char lpCaption[128];
strcpy(lpCaption,"Dll_c.dll插件演示");
return lpCaption;
} //输出函数定义:打开DLL主窗体
bool __stdcall ShowDllForm(void* hHandle,char* lpCaption)
{
if(NULL==hSave) //保存Application,传递Application
{
hSave=Application;
Application=(TApplication*)hHandle;
}
TDllForm *DllForm=new TDllForm(Application);
DllForm->Caption=lpCaption;
DllForm->Show();
return true;
} //--------------------------------------------------------------------------
//Dll_d.dll的接口标准:
function GetCaption: Pchar; stdcall;
function ShowDllForm(hHandle: THandle; lpCaption: Pchar): Boolean; stdcall; //Dll_d.dll的函数内容:
//标准的Dll函数入口
MDIChild Form返回,这里怎么恢复Application??? //输出函数定义:获取主窗体标题
function GetCaption: Pchar; stdcall;
var
lpCaption:array[0..100] of char;
begin
lpCaption:='Dll_d.dll插件演示';
Result:=lpCaption;
end; //输出函数定义:打开DLL主窗体
function ShowDllForm(hHandle: THandle; lpCaption: Pchar): Boolean; stdcall;
var
hSave: THandle;//这个变量是用来临时保存DllForm父指针的
begin
hSave:=Application.Handle;
Application.Handle:=hHandle;
DllForm.Create(Application);
DllForm.Caption:=lpCaption;
DllForm.Show;
Application.Handle:=hSave;
Result:=true;
end; //--------------------------------------------------------------------------
//BCB 编写的MDI结构部分代码 //MDIApplication.h
HINSTANCE DllInst;//Dll句柄全局变量声明
char* (__stdcall *GetCaption)();//获取DllForm的标题
bool (__stdcall *ShowDllForm)(void*,char*);//显示DllForm的界面 //MDIApplication.cpp
void __fastcall TMainForm::FormCreate(TObject *Sender)
{//框架启动时初始化Dll模块,这里以Dll_d.dll为例
if(NULL==DllInst)
DllInst=LoadLibrary("Library\\Dll_d.dll");
if (DllInst)
{
GetCaption=(char* (__stdcall*)())GetProcAddress(DllInst,"GetCaption");
ShowDllForm=(bool (__stdcall*)(void*,char*))GetProcAddress(DllInst,"ShowDllForm");
ShowDllForm(Application,GetCaption());//在MDI区域显示子窗体
}
} //-------------------------------------------------------------------------
问题1:为什么Dll_c.dll中的GetCaption()能返回正确的字符串,而Dll_d.dll的GetCaption()只能返回第一个字符,乱码。(使用__cdecl和__pascal等等都测试过。反过来,用Delphi写MDIApp,则Dll_c.dll传递乱码,何解?)
问题2:Dll_d.dll如何传递参数才能正确调用ShowDllForm?(两个dll中的Form都已经设置成MDIChild模式,且编写了退出释放代码。)
问题3:为什么D5程序员指南中指出Dll中使用过多的VCL控件将造成越界,如何理解?能否在Dll中实现MIS系统,包括ACCESS和SQL连接,读写操作,XML文件操作,Flash交互,D3D交互等? 这几个问题已经烦了我一个多星期了,差不多把Google翻遍了,做了十几个Demo,但是还不能确定,各位达达,高手,牛人,ccrun类,帮忙看看啦,这种结构好好麻烦啊~~~~
外部只保留最低限度的参数或指针传递.对于问题1,我用静态和一般变量都尝试过,如果MDIApplication程序是用BCB2009
编写,则不论Dll_c.dll定义静态或一般,都可以正确传递,Dll_d.dll乱码;如果
MDIApplication程序用D7/D2009编写,则Dll_d.dll可以正确传递,而Dll_c.dll
定义静态或一般,都是乱码。ShowDllForm()传递窗体指针也是这种情况,我怀疑是
同一种问题造成。 另外,Dll所包含的Form有何要求,有何限制?不论是Win32 Form,VCL Form,
MFC Form,VB Form还是.Net Form。
唉,这种做法是无可奈何之举,类似DLL交换字符串数据典型的方式--主动管理内存,
在 Windows API 中广泛使用,就是编码非常麻烦,比如 GetWindowText 函数:
int GetWindowText(
HWND hWnd, //父窗体句柄
LPTSTR lpString, //主调者调用之前先申请足够的内存
int nMaxCount //把这块内存大小通知 DLL
);
这样 DLL函数就只需要向缓冲区直接填写就可以了,这样写API就非常透明。 有没有高人支一招呢?热切期待中...