C++ Builde 2010 MDI 调用 DLL 子窗体


MDI 封装DLL 子窗体,要注意的问题:

  1) 传递 TApplication

  2) 必须要将 Dynamic RTL,Build with runtime packags 勾选编译,否则主窗体无法获取子窗体信息。MDIChildCount 一直为0,不能响应排列等一系列功能。


DLL 方面:


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

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

#include "Main.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
//---------------------------------------------------------------------------

#pragma argsused

extern "C" {
	__declspec(dllexport) void __stdcall ShowMDIForm(TApplication *app);
	__declspec(dllexport) void __stdcall GetDescribe(char *szBuf, int len);
};


TApplication *dllApp = NULL;

//---------------------------------------------------------------------------
void __stdcall ShowMDIForm(TApplication *app)
{
	if (dllApp == NULL)
	{
		dllApp = Application;
		Application = app;
	}

	//TDllForm1 *frm = new TDllForm1(Application->MainForm);
	TDllForm1 *frm = new TDllForm1(Application);
	frm->Show();
}
//---------------------------------------------------------------------------

void __stdcall GetDescribe(char *szBuf, int len)
{
	strncpy(szBuf, "TDllForm1", len);
}
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
	switch (reason)
	{
	case DLL_PROCESS_ATTACH:
		//CoInitialize(NULL);
		break;

	case DLL_PROCESS_DETACH:
		//CoUninitialize();
		//Application = NULL;
		if (dllApp != NULL)
			Application = dllApp;
		break;
	}
	return 1;
}
//-------------------------------------------------------------------------


DLL  窗体:

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

#include <vcl.h>
#pragma hdrstop

#include "Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TDllForm1 *DllForm1;
//---------------------------------------------------------------------------
__fastcall TDllForm1::TDllForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TDllForm1::Button1Click(TObject *Sender)
{
	ShowMessage("Test mdi child dll");
}
//---------------------------------------------------------------------------
void __fastcall TDllForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
	Action = caFree;
}
//---------------------------------------------------------------------------


DLL 中的子窗体 要将 FormType 设置成 fsMDIChild, 在OnClose 事件中 要将 Action 设置成 caFree,保证窗体卸载不会出问题。


主函数部分:

新建个 MDI 工程,在上面搞俩测试按钮,一个建立唯一窗体,另外一个可以建立多个窗体。

声明一个 DLL 字典变量,用来保证 dll 加载一次,并且Close 的时候 卸载掉。

protected:
	map<AnsiString, HINSTANCE>	map_dll_inst;	// Dll 名称,句柄


开头加个 导出函数声明:

typedef void __declspec(dllimport) ShowMDIFormType(TApplication *);
typedef void __declspec(dllimport) GetDescribeType(char *, int);


函数部分,其他都是BCB 自建的,我就不列出来了。

void __fastcall TMainForm::Button1Click(TObject *Sender)
{
	CreateDllForm("Form1.dll", false);	//建立唯一子窗口
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::Button2Click(TObject *Sender)
{
	CreateDllForm("Form1.dll", true);	//建立多个子窗口
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action)
{
	// Make sure all the children forms are closed
	while (MDIChildCount)
		MDIChildren[0]->Free();

	for (map<AnsiString, HINSTANCE>::iterator it = map_dll_inst.begin();
		it != map_dll_inst.end(); it++)
	{
		//DWORD dwError;
		//HINSTANCE hInst = it->second;
		if (FreeLibrary(it->second) == 0)
		{
			//dwError = GetLastError();
        	}
	}

	map_dll_inst.clear();
}
//---------------------------------------------------------------------------

bool  __fastcall TMainForm::IsMDIChildCreate(const String Name, TForm **Child)
{
	String TmpStr = "";

	for (int i=0; i<MDIChildCount; i++)
	{
		TmpStr = MDIChildren[i]->ClassName();
		if ( TmpStr == Name) {
			if (Child != NULL)
				*Child = MDIChildren[i];

			//return i;
			return true;
		}
	}
	return false;
	//return -1;
}
//---------------------------------------------------------------------------
bool __fastcall TMainForm::CreateDllForm(AnsiString DllName, bool MutilCreate/*是否创建多个窗体*/)	//通过 DLL 创建 Form
{
	if (DllName.IsEmpty()) return false;
	HINSTANCE	hInst;

	if (map_dll_inst[DllName] == NULL)
	{
		hInst = LoadLibrary(DllName.c_str());
		//if (hInst == NULL) return false;
	}
	else {
		hInst = map_dll_inst[DllName];
	}

	if (hInst == NULL) return false;
	else
	{
		ShowMDIFormType *ShowMDIForm = (ShowMDIFormType *)GetProcAddress(hInst, "ShowMDIForm");
		GetDescribeType *GetDescribe = (GetDescribeType *)GetProcAddress(hInst, "GetDescribe");

		if (ShowMDIForm != NULL && GetDescribe != NULL)
		{
			char szBuf[100] = {0};
			TForm *frm;

			GetDescribe(szBuf, 99);
			String DllFormTypeName = szBuf;

			if (!MutilCreate && IsMDIChildCreate(DllFormTypeName, &frm))
				frm->BringToFront();
			else
				ShowMDIForm(Application);

            map_dll_inst[DllName] = hInst;
		} // 获取地址完成
		else {
			//清除 队列  卸载 DLL
			FreeLibrary(hInst);
			map_dll_inst.erase(DllName);
		} // 获取地址不成功
	}
}
//---------------------------------------------------------------------------


如果 DLL 和 主窗体 是在一个 工程组里面,一定要分别 设置各自的 Options 设置 使用动态库什么的。直接把 相应工程激活,然后通过菜单栏设置的不行,我吃过这个亏,明明分别激活,然后勾选使用了动态库,运行的时候,主窗体就是识别不了子窗体,布局按钮无效。

参考文档:

<<C++ Builder 5 Developer's Guide>> P943页,"Using MDI Child Forms in DLLs " 上面讲的很清楚。

另附: 工程文件(基于BCB2010)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值