dll调用dll,dll文件的使用

  dll调用dll,dll文件的使用

  很久以前我写过关于MFC中CDialog和它的对话框资源的绑定,但是这几天做了一些MFC DLL的工作,发现当时的理解真的很肤浅。也许若干年后,我再回头看现在的这篇文章,会觉得这篇文章全是废话,哈哈。

  在DLL中使用资源的一个主要问题是,DLL和EXE中都有资源集,但这常常让我们怀疑程序在运行时会寻找哪个资源集。

  考虑以下经典案例:

  创建新的MFC DLL项目时选择使用共享MFC DLL的常规DLL选项,并创建一个与MFC自己的DLL共享的新DLL。在新DLL中创建一个名为IDD_DLLDIALOG的新对话框资源。导出此DLL中包含以下内容的ShowDialog()函数:

  新建一个MFC EXE项目,导入新建dll项目的lib和DLL,设置OK按钮的响应函数为:ShowDialog();链接编译好之后,当我们运行程序的时候,会发现点击确定按钮后没有任何响应!为什么.我们不是在DLL里明确设置了IDD_DLLDIALOG吗?在构建新的MFC dll项目时,请注意“使用共享MFC dll的常规DLL”这句话。如果我们当时选择“MFC静态链接的常规dll”会怎么样?又可以正常显示了!

  使用静态连接访问MFC库DLL会将MFC库DLL与项目本身打包在一起,而共享会在运行时将MFC库DLL动态加载到系统路径中。我们可以这样理解上面的现象:如果新创建的DLL以共享的方式访问库DLL,那么EXE程序运行时,实际上有两套上下文系统在运行,而静态连接只有一套上下文系统,所以静态连接时会需要切换模块状态。

  当我们的新DLL是共享访问库DLL时,解决上述问题的常用方法是在ShowDialog函数中增加一句afx _ manage _ state(afxgetstaticmodulestate());

  AfxGetStaticModuleState()的原型是:

  AFX _ MODULE _ STATE * AFX API AfxGetStaticModuleState();

  即当前模块的ModuleState指针。

  Af _ manage _ state宏将在堆栈上创建一个新类,以传入的指针作为参数。你可以猜到这个类会做什么。没错,它会将当前ThreadState指向的ModuleState指针保存在构造函数中,然后将传入的指针指定为当前ThreadState指向的指针。等到这个类的实例被析构后,再把它改回来。

  另一种方法是将AfxGetResourceHander()与AfxSetResourceHander(hin instance)结合使用(这正是我在MFC中CDialog及其对话框资源的绑定中介绍的方法)。

  如果我们不想在EXE中间接调用DLL导出的ShowDialog(),而是直接想在EXE的OnBnClickedOk()中使用DLL中的对话框资源生成对话框怎么办?此时afx _ manage _ state(afxgetstaticmodulestate())是没有用的(因为在DLL项目中使用)。最好的方法是将AfxSetResourceHander(HINSTANCE)与GetModuleHandle(LPCTSTR)一起使用。

  GetModuleHandle(LPCTSTR)会根据传入的字符串获取相应的模块句柄。注意,EXE和DLL都可以看作是模块。当传入为NULL时,将获得当前进程(EXE)的提示句柄。GetModuleHandle用于确保已加载相应的dll。也许你会说这个条件不是废话,但是真的很容易出错。

  如果dll是静态加载的(即生成的。lib文件直接导入),而且这个DLL中的任何函数或者变量之前都没有被调用过,GetModuleHandle只会得到一个空值。因为在某个语句调用dll的内容之前,系统不会真正加载dll。

  例如:

  上面的代码在运行时会报错,因为AfxSetResourceHandle在检查参数时发现了一个空值。下面的代码就可以了:

  其中TestOnly也是从RegDll导出的函数。它只返回1。我们只用它来加载RegDll。当然,如果我们直接用动态加载的方法,像下面这样直接加载库,也不会有问题。

  但是,眼尖的读者可能会马上发现,实际使用GetModuleHandle并不是上述情况下的最佳选择。因为直接的AfxSetResourceHandle(hm)可以解决问题。

  出发地:http://www.thankcreate.com/c/275

dll调用dll,dll文件的使用