利用动态链接库DLL来实现组件。
DLL只是组件的一种实现方式,组件是DLL中实现的一组接口集。
组件描述的是本质,DLL是形式。
从DLL中输出函数
1、extern “C”
需要输出的函数用extern "C"进行标记,防止C++编译器在函数名称上加上类型信息。
(不同编译器会使用不同的名称修改方法)
// Creation functioni
extern "C"
IUnknown * CreateInstance()
{
IUnknown * pI = (IUnknown *) (void *) new CA;
pI->AddRef(); // important!!!
return pI;
}
vc++是,可以用bumpbin.exe来得到某个DLL的符号清单。如
dumpbin -exports cmpnt1.dll
2、建立DEF函数
除了在函数前加上extern “C”标记,为了从DLL中输出函数,还需要告诉链接程序需要输出什么函数。
为此需要建立一个DEF函数。
vs2005 ActiveX向导会自动生成一个def文件,def文件属源文件。
COMPNT1.DEF
;compnt1 module-definition file
LIBRARY Compnt1.dll
DESCRIPTION '(C) BLABLABLA....'
EXPORTS
CreateInstance @1 PRIVATE
关键在EXPORTS中的内容。列出待从DLL中输出的函数的名称,对每一个名称还可以加上一个序号。
在LIBRARY行,必须写上DLL文件的名称。
DLL的装载
使用win32的LoadLibrary和GetProcAddress,客户可以动态的链接到组件上。
HISTANCE LoadLibrary (
LPCTSTR lpLibFileName ) ;
LoadLibrary以被装载的DLL的名称作为参数并返回一个指向所装载的DLL的句柄。
GetProcAddress函数可以使用此句柄以及待调用的函数的名称,然后返回一个指向该函数的指针。
FARPROC GetProcAddress(
HMODULE hModule,
LPCSTR lpProcName);
为何可以使用DLL来实现组件?
原因在于DLL可以共享它们所链入的应用程序的地址空间。
C++使用的虚函数来实现接口,实际上也就是一个指向函数的指针列表,VTBL。组件将为虚表分配内存,并用函数地址来初始化之。要使用VTBL,也就需要客户能访问组件为其分配的内存空间。windows中,动态链接库与客户使用的是同一地址空间,因此。互相访问不成问题。
在windows中一个正在被执行的程序称为进程,每个应用程序都以单独的进程运行,每个进程有4GB的地址空间。两个进程内的地址可能是同样的值,但物理位置却不同。因为它们的内存空间不同,就好像不同大巴车上的座位号可能一样。指针并不能从一个地址空间转到另一个地址控件。
动态链接库,会驻留在所链接的应用程序的地址空间中,与EXE共享进程,即共享地址空间。也因此,DLL也被称作进程中服务器(in-process server)。