COM技术内幕读书笔记————动态链接和组件

来源:互联网 发布:西安seo工资待遇 编辑:程序博客网 时间:2024/05/18 19:44

本章摘要

  组件是由二进制文件组成的,而我们需要在运行过程中可以随意替换组件,希望通过某种控制手段支持这种控制能力。

为了在运行时刻改变组件,所以需要将组件和动态链接链接到一起。

  如果不能动态链接会发生什么?用户需要改变组件的时候不得不将整个程序重新链接或者编译,然后发布新的版本。但是这种对于用户来说基本不可能,也有可能知道如何重新链接,但是他们可能也没有链接程序。

 COM组件是用win32的DLL形式或者可执行文件形式发布的可执行代码,遵循COM规范编写的,之所以用组件是因为动态链接没有封装性质,而组件必须剧本这个性质。

所以COM组件和dll是相互合作的关系,COM利用DLL提供的动态链接能力。


动态链接和组件关系?

   为了实现不在同一文件中用户和组件,改变这种密不可分的关系首先组件并不是DLL。DLL是一种服务程序,是一种发行组件的方式。而组件就是DLL中所实现的接口集。

DLL是一种形式,组件是实质。


组件是怎么被创建的?

 主要是将组件动态链接到客户中来,那么创建组件,这是临时性的创建方法。在用户获取组件接口之前,就需要先将DLL加载到进程空间,在此空间中创建组件。由于createInstance是唯一需要用户显示链接调用的函数所以需要从dll中引出。

第一步,将需要引出的函数加入dll中

从DLL中引出创建组件实例的函数,可以加入extern "C"从而引出函数

extern "C"
IUnknown*CreateInstance()
{
IUnknown*PI = (IUnknown*)(void*)new CA;
PI->AddRef();
return PI;
}


之所以加上extern "C"是可以防止C++编译器用类型信息修饰函数名。

比如Microsoft Visual C++会将该函数变成

?CreateInstance@@YAPAUUnkonwn@@XZ

在DLL中引出函数如果只加上标记是不够的。还需要告诉链接程序引出什么函数

加入一个叫做DEF的文件将函数名称加入这个文件

CMPNT1.DEF


LIBRARY Compnt1.dll
DESCRIPTION '(c)1996-1997 Dale E.Rogerson'
EXPORTS  CreateInstance @1 PRIVATE

这么做的牡蛎是在EXPORTS字段中列出DLL中引出的函数以及一个序号


第二步,如何装载dll

typedef IUnknown*(*CREATEEFUNCPTR)();
IUnknown*CallCreateInstance(char*name)
{
//先将动态链接库载入进程
HINSTANCE hComponent = ::LoadLibrary(name);
if (hComponent==NULL)
{
cout<<"CallCreateInstance:\tError Cannnot load"<<endl;
return NULL;
}
//获得函数地址
CREATEEFUNCPTR CreateInstance = (CREATEEFUNCPTR)::GetProcAddress(hComponent,"CreateInstance");
if (CreateInstance==NULL)
{
cout<<"CallCreateInstance:\tErro"
<<"cannot find CreateInstance "
<<endl;
return NULL;
}
return CreateInstance();
}

其中LoadLibrary是以被装在的DLL名称为参数,并返回句柄

但是我们并不应该知道DLL名称,需要更加清晰的界限,所以可以从一个DLL中移动到另外一个DLL中


总结:为什么使用DLL

由于DLL可以共享他们所链入的应用程序的地址空间,用户和组件通过接口交互。因为一个函数对应一个函数地址。客户可以访问组件为函数分配的内存说白了就是一个指针列表vtbl,组件为这个vtbl分配内存,由于在windows中动态链接库和客户是在同一个地址空间的,所以访问vtbl没有问题。

windows中一个正在被执行的程序是进程,一个进程中的地址和另外某个进程中某些地址不同。由于指针是在不同地址空间起作用的,所以不能将

一个指针从一个进程传到另一个进程。比如一个街道名可能位于这个城市也可能位于另一个城市,没城市名是无意义的。两个不同进程可能包含相同的地址值,但是不同的物理内存。幸运的是动态链接库将驻留在所链接应用程序的地址空间中。由于DLL和EXE共享同一个进程,因此共享同一个地址空间,所以DLL也叫做进程内服务程序。



组件和客户界限如何划分



组件文件实现了接口集的具体实现以及DLL中引出的函数名称。

组件和客户共享两个文件,包含所有接口以及接口ID

而客户通过接口ID查询是否有该接口,并载入create文件中LoadLibrary的DLL

并获得该DLL中引出函数的地址



总结:

    给组件添加活力,就是添加动态链接功能。一个用户不用重新链接和编译就可以使用多个不同的组件。

COM的各种努力都是在规定了一种二进制交互的协议。说起来简单,做起来相当复杂,要使使用不同语言编写的客户能够使用任意语言编写的服务程序谈何容易!这里说语言还是把问题简单化了,因为每种语言还有各式各样的编译器,不同编译器出来的二进制代码如何交互?   就拿DLL来说,DLL是对静态连接的一种改进,带来了更细的开发分工,也带来了很多问题,   其中就有二进制如何交互的问题。这个问题当DLL输出类时更加突出。COM为解决此问题提出了极负创意的解决方案,不仅如此,更进一步引申,提出了如何跨 网络的交互。然后,针对internet服务器的开发提出COM+。COM体系中融合了多种经典的设计模式,可以说是一种更加精干的C++。   

    留下的问题是:需要将DLL的名称向客户隐藏,组件应该在不影响客户正常运行下有改变DLL名称能力,也希望在DLL中实现多个组件



0 0
原创粉丝点击