var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-333696-1']); _gaq.push(['_trackPageview']); _gaq.push(['_trackPageLoadTime']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();
  • 2008年09月21日

    COM编程(3)

    分类:

    把接口和实现分开,是要把对象内部工作的细节(对客户而言)都隐藏起来。于是提供了一层间接性,允许实现类内部数据成员的数量和顺序变化,并无须客户程序重新编译。由于C++编程语言充满了模棱两可的因素,使得它无法很好地映射到所有可能的语言。模棱两可大多与指针、内存和数组间的松散关于有关。为了把“接口定义”与“特定实现过程所用到的语言”之间的关联尽可能地断开,必须把“定义接口使用的语言”与“定义实现使用的语言”分开。如果所有参与的各方同意使用一种语言来定义接口,那么就可能只定义一次接口,然后在必要时导出新的与实现语言相关的接口定义来。COM提供了这样一种语言,它只用到了基本的、大家都很熟悉的C语法,同时加入了某些用来“消除C语言中二义性特征”的能力(从而能够把这些特征精确地翻译到其它语言中)。这种语言被称为接口定义语言(Interface Definition Lauguage,IDL)

     

    Win32 SDK包含MIDL.EXEIDL编译器,它可以解析COM IDL文件,产生许多COM相关的信息文件。MIDL自动产生C/C++兼容头文件,可以避免“同一个接口拥有多个不相容的版本”的情况,也不必同时维护多个版本使它们总保持同步。MIDI产生的源码也允许接口被用于跨线程、进程,甚至跨机器。MIDI还产生一个二进制文件,允许其它“可感知COM的”环境能够为原始IDL文件中定义的接口产生响应的、针对特定语言映射的接口定义,这个二进制文件被称为类型库(type library),它包含符号化的IDL,是一种更有效的解析形式。MIDI还产生C源文件(.c),它包含原IDL文件中所办好的GUID的实际定义,要使用该接口的工程需要把它加入makefile文件中,或使C/C++文件中包含该.c文件,如果不这样做,那么符号IID/LIBID/CLSID将不会有存储控件存放它的128位值,工程将由于存在无法解析的外部符号而无法完成链接。IDL中用interface来开始接口定义,接口定义分为四部分:接口名字、基接口名字、接口体和接口属性。每个COM接口必须要有两个IDL属性,object属性是必须的,它说明该接口定义是一个COM接口,而不是DCE风格的接口。第二个可选属性指明接口的实质名字,一般是uuidCOM禁止多重继承。

     

    因为COM的动态特性,客户需要有一种机制来找到类对象,“把一个对象带入到活动状态”的动作称为对象激活(actiration)COM有三种激活模型,可以用来把对象带入到内存中,并允许客户调用它的方法。客户可以要求COM绑定到给定类的类对象;客户也可以要求COM根据CLSID所代表的类创建一个新实例;最后,客户还可以要求COM根据对象的永久状态把它带入到活动状态。在这三种模型中,只有第一种模型绝对必须,其它两种模型只是简单地将通常使用的激活概念作了优化。COM的三种激活模型都用到了COM服务控制管理器(SCM)所提供的服务,SCM是由RPCSS (RPC Server Service - %windir%\system32\rpcss.exe)实现的,SCM服务以高层名字对象模型(moniker types)或者底层API函数的形式暴露给应用程序,所有这些功能都在COM库中实现,Windows NTCOM库的绝大多数功能是在OLE32.DLL中实现的。

     

    COM类被定义在IDL中,以便对于“服务器可能引出的具体数据类型”提供独立于程序语言的描述,以coclass开头。IDL中,库定义用来把一组数据类型(interfacecoclasstypedef)组织到一个逻辑单元或名字空间中。凡出现在IDL库文件上下文环境中的所有数据类型都将被符号化(tokenized),并放到结果类型库(type library)中。一个IDL文件至多只能有一个library语句,其中[default]属性说明了哪个类最能表达这个类的本质类型。

     

    套间(apartment)定义了一组对象的逻辑组合,这些对象共享同一组并发性和重入限制。每个COM对象都属于某一个套间,但一个套间可以被多个对象所共享。对象所属的套间也是这个对象实体属性的一部分。套间既不是进程,也不是线程。每一个使用COM的进程都有一个或者多个套间,但套间只能包含在一个进程中。同一时刻,一个线程只能在一个套间中执行。一个线程要想使用COM,它必须先进入一个套间中。当线程进入套间中时,COM把关于这个套间的信息保存在线程局部存储(TLS)中,在线程退出这个套间之前,这一信息一直与线程联系在一起。并且COM规定,只有运行在对象的套间中的线程才能够访问该对象,这意味着如果一个线程与对象处于同一个进程中,虽然这个进程能够看到/访问到对象所占有的内存,但它有可能被禁止访问这个对象。Windows NT有两种类型的套间:多线程套间(MTA)和单线程套间(STA)。每个进程至多有一个MTA,但一个进程可以包含多个STA

     

    IDispatch是分发接口,将接收一个函数的名称并执行它。为执行这个函数,自动化控制程序将把DISPID传给Invoke成员函数。双重接口(dual)是让IDispatch::InvokeCOM组件继承IDipatch而不是IUnknown,从而使得通过Invoke能够访问的函数也能够直接通过vbtl访问的到。

    分享到: