在MFC扩展dll里导出函数时应该也进行资源的切换。
在共享的(动态链接的)MFC规则dll里,在每一个导出函数前都需进行资源的切换,在扩展dll里同样也需要,因为它们都是动态链接到MFC库 的,在调用导出函数时,若要加载对应的资源,MFC会首先从应用程序模块里查找,找不到时才从dll中查找,所以若存在同名的资源,则可能会加载错误。
例子:
dll: MFCExtDll,它里边存在一个对话框资源IDD_DIALOG2,它对应的编号是2000,在resource.h里有如下定义
#define IDD_DIALOG2 2000
该dll有一个导出函数如下所示:
extern "C" __declspec(dllexport) void ShowDlg(void)
{
//HINSTANCE save_hInstance = AfxGetResourceHandle();
//AfxSetResourceHandle(theInstance);
CDialog dllDialog(IDD_DIALOG2);
dllDialog.DoModal();
//AfxSetResourceHandle(save_hInstance);
}
调用dll的应用程序: MFCExtDllCall,它里边有一个对话框资源IDD_DIALOG1,编号也是2000,在resource.h里有如下定义
#define IDD_DIALOG1 2000
调用导出函数处如下:
void CMFCExtDllCallDlg::OnButton1()
{
// TODO: Add your control notification handler code here
typedef void (*lpFun)(void);
HINSTANCE hDll; //DLL句柄
hDll = LoadLibrary("MFCExtDll.dll");
if (NULL==hDll)
{
MessageBox("DLL加载失败");
}
lpFun pShowDlg = (lpFun)GetProcAddress(hDll,"ShowDlg");
if (NULL==pShowDlg)
{
MessageBox("DLL中函数寻找失败");
}
pShowDlg();
}
此时,弹出的对话框不是dll中定义的对话框资源DIALOG2,而是应该程序中的DIALOG1,即由于它们的id重复造成了加载资源时的错误。
解决办法:
若dll是规则dll,则方法有三种,详见“VC++动态链接库(DLL)编程深入浅出(全)【三】”;现在是MFC扩展dll,也可借鉴其方法,如下:
1、在dll加载时,即DllMain函数处获得该dll的句柄:
HINSTANCE theInstance;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("MFCEXTDLL.DLL Initializing!/n");
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(MFCExtDllDLL, hInstance))
return 0;
new CDynLinkLibrary(MFCExtDllDLL);
theInstance = hInstance;
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("MFCEXTDLL.DLL Terminating!/n");
// Terminate the library before destructors are called
AfxTermExtensionModule(MFCExtDllDLL);
}
return 1; // ok
}
2、在导出函数处进行资源的切换:
extern HINSTANCE theInstance;
ExportFun
{
HINSTANCE save_hInstance = AfxGetResourceHandle();
AfxSetResourceHandle(theInstance);
···
AfxSetResourceHandle(save_hInstance);
}