首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ Builder >

MDI Application共享Delphi和BCB DLL插件的有关问题

2012-04-07 
MDI Application共享Delphi和BCB DLL插件的问题 - C++ Builder / Windows SDK/APIBCB2009编写MDI Applicat

MDI Application共享Delphi和BCB DLL插件的问题 - C++ Builder / Windows SDK/API
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类,帮忙看看啦,这种结构好好麻烦啊~~~~

[解决办法]
问题1:为什么Dll_c.dll中的GetCaption()能返回正确的字符串,而Dll_d.dll的GetCaption()只能返回第一个字符,乱码
 這是变量的生命周期問題,並非函數接口問題。 Dll_c.dll中的GetCaption() 返回的是靜態变量的指針, 而 Dll_d.dll 中返回的卻是函數中的局部变量的指針,結果當然是不可知的。 



问题2:Dll_d.dll如何传递参数才能正确调用ShowDllForm?(两个dll中的Form都已经设置成MDIChild模式,且编写了退出释放代码。) 
這裡有使用了一個強制轉換Application=(TApplication*)hHandle; 那麼你必須保障所用的編譯器:B6 D7 D2009 ,其Application的內存布局是一樣的。而這個只有在同一VCL版本中,才有保障。強制轉換是一個魔鬼。

问题3:我一無所知。

最好使用同一VCL版本的編譯器。
DLL不是语言无关性的吗? 可是你用強制轉換來解析傳遞過來的參數....這是編譯器相關的。就如VB的datetime 與 Delphi的datetime無法相互識別一樣。
[解决办法]
做DLL,最重要的是清醒的内存管理,以及内存使用的生命周期,保证数据的有效性,防止野指针等问题的出现;其次是结构布局的同一性,或者至少是兼容性,保证内存访问不会越界。

对于使用MDI,如果不是完全按照API兼容模式来写,而是采用VCL的兼容模式,那么很难做到语言无关性,从而导致做出来的东西是不伦不类的。

不要每个时候都希望把东西做到完美,有些必须要考虑一个应用环境。

热点排行