[转]MFC .DLL指南(一)
MFC .DLL指南(一)- -
这
里要提到的一点是,在用COM和ATL前,程序员一般用.DLLs来代替它们. 你可以用.DLL做很多事.如果你有几个程序要用到相同的函数或资源,你
可以将代码放到一个.DLL中.将多个程序要共同用到的代码放到一个简单的.DLL中可以节省维护时间,因为代码就在一个地方.:)修理和其他的改动最多
做一次就够了.如果你有一个在不同时间用不同程序的程序,你应该把这些程序做成.DLLs,根据需要的导入相应的.DLL.有很多理由要用到.DLLS.
虽
然用.DLL能做的COM全能做,但是仍有很多好原因使得我们要用.DLLs,所以它们没有消失.但是.DLLs还是有很多严重缺点的,这些严重的缺点就
是我们为什么会首先想到用COM.但.DLLs仍然是很实用的工具.对照COM和ATL,.DLLs是非常简单的来实现的.学习COM和ATL需要投入大
量的时间和努力.实现.DLL却相对简单,修改起来也不难.如果你会一些C++和MFC,你现在就可以实现.DLLs.
这篇文章回顾一下用MFC实现.DLLs的几种形式,包括何时用和怎么用各种形式.在下一篇将讨论.DLLs的局限性(这就是为何会出现COM和ATL)
Different types of .DLLs
可 以用MFC来实现两种.DLLs:一个是MFC扩展.DLL,一个是正规的.DLLs.正规的.DLLs有两种实现方 式:dynamically linked 或者 statically linked.Visual C++也允许你用 generic Win32 .DLL,但本文我们只讨论以MFC为基础的.DLL形式.
MFC extension .DLLs
每
一个.DLL都有一些接口.接口是一套变量,指针,函数或者是类,可以通过客户程序来访问.MFC的扩展.DLL有一个C++形式的接口,也就是说它提供
给客户程序("export")C++函数或者整个类.导出函数可以用C++或者MFC的数据形式作为参数或返回值.当导出整个类,客户程序可以创建此类
的对象或者派生于此类.在.DLL中,你也可以用MFC和C++.
Visual C++用的MFC的类代码库也存在于.DLL中.一个扩
展.DLL是动态连接到MFC的代码库的.DLL的.客户程序也必须动态的连接到MFC的代码库.随着时间的推移,MFC的库也在增长.结果,就有了几个
不同的MFC的代码库的版本.客户端和扩展的.DLL必须建立在相同版本的MFC上.因此,一个MFC扩展的.DLL要运行,客户端和此扩展的.DLL必
须动态的连到相同的MFC代码库的.DLL上,并且,此库还得在该程序运行的机器上好使.
注意:如果你的程序静态的连接到MFC,但是你希望
改变它便于从一个扩展的.DLL中访问函数,这时,你要改此应用程序为动态连接到MFC.在Visual C++,在菜单中
选"Project | Settings",在"General"设置标签中可以把你的程序改成动态连接到MFC.
MFC扩展.DLLs非常小.你可以建立一个导出一些函数或者类的大约10-15KB的.DLL.显然的,你的.DLL的大小要以你要存多少代码到你的.DLL中为准.但是通常MFC扩展的.DLLs是相对小和快捷的.
Regular .DLLs
MFC
的扩展.DLL只能工作在用MFC编的客户程序上.如果你的.DLL可以被大多数的Win32程序导入和运行,你应改选择正规的.DLL.但你只能导出
C-style函数.你不能导出类.你不能导出C++函数或overloaded函数.不能用MFC的数据类型作为参数和返回值.但可以在你的.DLL中
用C++和MFC,但是你的接口必须全是C-style.
当然正规的.DLL也要访问MFC的代码库的.DLL.可以动态,可以静态连
接.如果动态连接,意味着你的.DLL函数所需的MFC代码不用建立在你的.DLL中,你的.DLL会从你的客户端的机器上MFC的代码库的.DLL中取
得所需要的代码.如果正确的MFC代码库的.DLL版本没找到,你的.DLL将不能工作.像MFC扩展的.DLL一样,正规的.DLL也非常小,只能在客
户端所在的机器有MFC代码库的.DLL情况下工作.
如果你静态连接到MFC代码库,你的.DLL包括它自己的所有的所需的MFC代码.那
么,它将非常庞大,但是它不依赖于客户端的电脑配置.如果你不知道主机的机器配置情况,这是一个很好的方法.如果你的客户在你的公司范围内,你可以知道他
们的MFC .DLL的配置情况,或者你的安装程序带了正确版本的MFC .DLL,那么静态连接就不是一个好方法了.
Building a .DLL
可
以用App Wizard来实现以MFC为基础的.DLL.选择"File | New",在"Projects"标签上,选
择"MFC AppWizard (.DLL).",为你的工程选一个名字,然后单击"OK".在下一个屏幕,选择建立一个MFC扩展的.DLL,或者正
规的.DLL"using shared MFC .DLL"(就是动态连接到MFC),或者正规的.DLL(静态的连接到MFC).选择其中一个,
按"Finish".
App Wizard新建立的.DLL没做任何事.编译新的.DLL,但是它不导出任何类和函数,本质上来说,没有任何用,你现在有两个工作:
1.增加函数.
2.修改客户端来调用你的.DLL.
Export a Class
上
面提到,只有MFC的扩展.DLL能导出MFC/C++类.假设你建立了一个扩展的.DLL,你可以通过从另一个工程加入.cpp和.h文件来创建一个
类,也可以在你的工程中创建新类.要导出这个新类,你必须在类的声明前加一个宏"AFX_EXT_CLASS",像这样:
class AFX_EXT_CLASS CMyClass
{
//class declaration goes here
};
还用一种方法来导出一个类,很简单而且很好,我会在下面讨论客户端如何做才能用上你的导出类提到.
Export objects and variables
代替导出整个类的方法,你可以导出该类在.DLL中的对象.客户端程序可以调用所有的该导出对象的公有函数和访问它的公有成员变量.
首先,创建一个.h文件,定义了你的新类.然后创建实现你的新类的.cpp文件.在.cpp文件底部,在你所有的公有的,私有的类函数后,创建一个这样的类的实例:
_declspec(dllexport) CMyClass myObject;
这
行的作用是创建一个CMyClass类的实例,当客户端导入.DLL时,使得客户端可以访问该实例.通过该实例,访问它的公有函数和成员编量.注意,每个
客户端导入.DLL将获得该实例的一个拷贝,也就是说,如果不同的程序访问相同的.DLL,如果一个程序改变了该实例,不会影响另一个程序.
除了导出实例,你可以用同样的方法导出变量.如果你加上此行:
_declspec(dllexport) int x;
就可以导出变量,为客户端应用.下面说的很重要:你只能导出全局的实例或者变量.局部的实例或者变量当它们跑出作用域,就会停止生存.如果用下面的方法,将不会正常工作:
MyFunction( )
{
_declspec(dllexport) CMyClass myObject;
_declspec(dllexport) int x;
}
一旦实例或者变量跑出作用域,它们将停止生存.
Export a function
导出函数和导出变量是很相似的.你可以简单的在函数前面加上"_declspec(dllexport)"
_declspec(dllexport) int MyExportedFunction(int);
这就是导出的全部.记住,只有MFC扩展的.DLL能导出C++函数或者以MFC的数据类型为参数或者返回值.正规的.DLLs只能导出C-style函数.
Using the .DLL in a client application
一个.DLL不能运行它自己.它需要客户端导入它,调用它的接口.
当你编译你的.DLL时,编译器创建两个很重要的文件: .DLL文件和.lib文件.你的客户端需要这两个文件.你必须拷贝它们到客户端的工程文件夹.
除了.DLL和.lib文件,你的客户端还需要要导出的类,函数,实例和变量所在的头文件.要导出函数时要加"_declspec(dllexport)"声明.现在要导入了,就要加入"_declspec(dllimport)"声明.如下:
_declspec(dllimport) CMyClass myObject;
_declspec(dllimport) int x;
_declspec(dllimport) int MyExportedFunction(int);
为了可读性,我们可以这样写:
#define DLLIMPORT _declspec(dllimport)
DLLIMPORT CMyClass myObject;
DLLIMPORT int x;
DLLIMPORT int MyExportedFunction(int);
现在你声明了你的实例,变量和函数,可以用了.:)
要导出整个类,你必须将整个.h头文件拷过来..DLL和客户端要有唯一的关于此导出类的头文件.记住,类的声明要加上: AFX_EXT_CLASS 宏.
一
旦你建立了客户端,你已经准备给客户用了,你应该给他们你的Release可执行文件和Release的.DLL.不用给用户.lib文件..DLL可以
放在客户程序的目录,或者系统目录.还有上面提到的,你要提供正确的MFC代码库的.DLL.这个.DLL是你的机器装Visual C++时候用的.