关键词不能为空

当前您在: 主页 > 英语 >

什么是COM如何使用COM

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-03-03 12:38
tags:

-

2021年3月3日发(作者:shelf是什么意思)


什么是


COM,


如何使用


COM


























本文的目的是为刚刚接触


COM


的程序员提供编程指南,并帮助他们理



C OM


的基本概念。内容包括


COM


规范 简介,重要的


COM


术语以及如何重用现有的

< br>COM



件。本文不包括如何编写自己的


COM


对象和接口。





COM


即组件对象模型,是


Component Object Model


取前三个字母的缩写 ,这三个字母在当



Windows


的 世界中随处可见。


随时涌现出来的大把大把的新技术都以


COM


为基础。


各种文档


中也充斥着诸如


COM


对象、接口、服务器之类的术语。因此,对于一个程序员来说 ,不仅要掌


握使用


COM


的方法,而且 还要彻底熟悉


COM


的所有一切。





本文由浅入深描述


COM


的内在运行机制,


教你如何使用第三方提供的< /p>


COM


对象


(以


Windows


外壳组件


Shell


为例)


。读完本文后,你就能掌握如何使用


Windows


操作系统中内建的组件和第


三方提供的


CO M


对象。





本文假设你精通


C++


语言。在例子代 码中使用了一点


MFC



ATL



如果你不熟悉


MFC



ATL


也没关系,本文会对这些代码进行完全透彻的解释。 本文包括以下几个部分:




COM< /p>


——到底是什么?——


COM


标准的要点 介绍,它被设计用来解决什么问题




基本元素的定义——


COM


术语以及这些术语的含义

< p>



使用和处理


COM< /p>


对象——如何创建、使用和销毁


COM


对 象




基本接口——描述


IUnknown


基本接口及其方法




掌握串的处理——在


COM


代码中如何处理串




应用


COM


技术——例子代码,举例说明本文所讨论的所有概念




处理


HR ESULT


——


HRESULT


类型描 述,如何监测错误及成功代码




COM


——到底是什么





简单地说,


COM


是一种跨应用和语言共享二进制代码的方法。与


C++


不同,它提倡源代码


重用。


ATL


便是一个很好的例证。源码级重用虽然好,但只能用于


C++


。它还带来了名字冲突的


可能性,更不用说不断拷贝重用代码而导致工 程膨胀和臃肿。





Windows


使用


DLLs


在二进制级共享代码。这也是


Windows


程序运行的关键— —重用


,


等。


DLLs


是针对


C


接口而写的,< /p>


它们只能被


C


或理解

C


调用规范的语言


使用。由编程语言来负责实现共享代码, 而不是由


DLLs


本身。这样的话


DL Ls


的使用受到限制。



MFC


引入了另外一种


MFC


扩展

< br>DLLs


二进制共享机制。但它的使用仍受限制——只能在


MFC



序中使用。





COM


通 过定义二进制标准解决了这些问题,即


COM


明确指出二进制模 块(


DLLs



EXEs



必须被编译成与指定的结构匹配。


这个标准也确切 规定了在内存中如何组织


COM


对象。


COM



义的二进制标准还必须独立于任何编程语言(如


C++


中的命名修饰)


。一旦满足了这些条件 ,就


可以轻松地从任何编程语言中存取这些模块。


由编译器负责 所产生的二进制代码与标准兼容。



样使后来的人就能更容易地 使用这些二进



























制代码。





在内存中,


COM


对象的这种标准形式在


C++


虚函数中偶尔用到,


所以这就是为什么许多


COM


代码使用


C++


的原因。但是记住,编写模块所用的 语言是无关的,因为结果二进制代码为所有语


言可用。





此外,


C OM


不是


Win32


特有的。从理论上 讲,它可以被移植到


Unix


或其它操作系统。但是

< p>
我好像还从来没有在


Windows


以外的地方听 说过


COM





基本元素的定义






我们从 下往上看。


接口只不过是一组函数。


这些函数被称为方法。


接口名字以大写的


I


开头,


例如


C++


中的


IShell Link


,接口被设计成一个抽象基类,其中只有纯粹的虚拟函数。




接口可以从其它接口继承,


这里所说的继承的原理就好像


C++


中 的单继承。


接口是不允许多


继承的。



coclass


(简称组件对象类——


component object class


)被包含在


D LL



EXE


中,并且包含着一个


或者多个接口的代码。组件对象类(


coclasss


)实现这些接口。


COM


对象在内存中表现为组件对


象类(


coclasss


)的一个实例 。注意


COM


“类”和


C++


“类”是不相同的,尽管常常


COM


类实现


的就是一个


C++


类。




COM

服务器是包含了一个或多个


coclass


的二进制(


DLL



EXE






注册< /p>



Registration


)是创建注 册表入口的一个过程,告诉


Windows


操作系统


COM


服务器放在什


么位置。取消注册(


Unregistration


)则相反——从注册表删除这些注册入 口。




GUID

(谐音为



fluid




意思是全球唯一标示符——


globally unique identifier



是个

< br>128


位的数字。


它是一种独立于


COM


编程语言的标示方法。


每一个接口和

< br>coclass


有一个


GUID



因为每一个


GUID


都是全球唯一的 ,所以避免了名字冲突(只要你用


COM API


创建它们)< /p>


。有时你还会碰到另一个


术语


UUID< /p>


(意思也是全球唯一标示符——


universally


unique


identifier




UUIDs


GUIDs


在实际


使用时的用途是一样的。





ID

< br>或者


CLSID


是命名


cocl ass



GUID


。接口


ID


或者


IID


是命名接口 的


GUID






COM


中 广泛地使用


GUID


有两个理由:




GUIDs


只是简单的数字,任何编 程语言都可以对之进行处理;




GU IDs


可以在任何机器上被任何人创建,一旦完成创建,它就是唯一的。因此,


COM


开发人员


可以创建自己特有的

< p>
GUIDs


而不会与其它开发人员所创建的


GUI Ds


有冲突。这样就消除了集中


授权发布


GUIDs


的必要。






HRESULT

< br>是


COM


用来返回错误和成功代码的整型数字。除此之外 ,别无它意,虽然以


H



前缀,但没有 句柄之意。下文会对它有更多的讨论。





最后,


COM


库是在你使用


COM


时与你交互的操作系统的一部分,它常常 指的就是


COM



身。但是为了避免混 淆才分开描述的。




使用和处理


COM


对象






每一种语言都有其自己处理对象的 方式。例如,


C++


是在栈中创建对象,或者用


new


动态分


配。因




























COM


必须独立于语言,所以

< p>
COM


库为自己提供对象管理例程。下面


是对


COM


对象管理和


C++

< br>对象管理所做的一个比较:




创建一个新对象



< br>C++


中,用


new


操作符,或 者在栈中创建对象。



COM


中,调用


COM


库中的


API

< br>。




删除对象




C++


中,用


delete


操作符,或 将栈对象踢出。



COM


中,所有的对 象保持它们自己的引用计数。调用者必须通知对象什么时候用完这个对象。


当引用计数为 零时,


COM


对象将自己从内存中释放。





由此可见,对象处理的两个阶 段:创建和销毁,缺一不可。当创建


COM


对象时要通知


COM


库使用哪一个接口。如果这个对象创建成功,

< br>COM


库返回所请求接口的指针。然后通过这个指


针调用 方法,就像使用常规


C++


对象指针一样。



创建


COM

< br>对象




为了创建


COM


对象并从这个对象获得接口,必须调用


COM


库的


API


函数,

CoCreateInstance()



其原型如下:< /p>





HRESULT CoCreateInstance (


REFCLSID



rclsid,


LPUNKNOWN pUnkOuter,


DWORD






dwClsContext,


REFIID





riid,


LPVOID*




ppv );



以下是参数解释:



rclsid



coclass



CLSID


,例如,可以传递


CLSID_ShellLin k


创建一个


COM


对象


来建立快捷方式。



pUnkOuter


:这个参数只用于


COM


对象的聚合,利用它向现有 的


coclass


添加新方法。参数值为


null


表示不使用聚合。



dwC lsContext


:表示所使用


COM


服务器的种类。本文使用的是最简单的


COM


服务器,一个进 程


内(


in-process



DLL












所以传 递的参数值为


CLSCTX_INPROC_SERVER


。注 意这里不要随意使用


CLSCTX_ALL


(在


ATL


中,它是个缺省值)












因为在没有安装


DCOM



Windows95


系统上会导致失败。


< p>
riid


:请求接口的


IID

。例如,可以传递


IID_IShellLink


获得


IShellLink


接口指针。



ppv


:接口指针的地址。


COM

< p>
库通过这个参数返回请求的接口。








当你调用


CoCreateInstance()

< br>时,它负责在注册表中查找


COM


服务器的位置,将服务 器加载


到内存,并创建你所请求的


coclass


实例。以下是一个调用的例子,创建一个


CLSID_ShellLink< /p>



象的实例并请求指向这个对象


IShe llLink


接口指针。



HRESULT






hr;


IShellLink* pISL;



hr = CoCreateInstance ( CLSID_ShellLink,










// coclass



CLSID



NULL,





















//


不是用聚合



CLSCTX_INPROC_SERVER,





//


服务器类型



IID_IShellLink,











//


接口的


IID



(void**) &pISL );









//


指向接口的指针




if ( SUCCEEDED ( hr ) )


{


//



pISL

调用方法



}


else


{


//


不能创建

< br>COM


对象,


hr


为出错代码



}













CoCreat eInstance()






HRESULT



IShellLink







CoCreateInstance()< /p>


来创建新的


COM


对象。如果

< p>
hr




























受到一 个表示成功的代码,



SUCCEEDED

宏返回


TRUE



否则返回


FALSE



FAILED

< br>是一个与


SUCCEEDED


对应的宏用来检查失败代码 。



删除


COM


对象







前面说过,


你不用释放


COM


对象,


只要告诉它们你已经用完对象。


IUnknown


是每一个


COM

< p>
对象必须实现的接口,


它有一个方法,


Relea se()



调用这个方法通知


COM< /p>


对象你不再需要对象。


一旦调用了这个方法之后,就不能再次使用 这个接口,因为这个


COM


对象可能从此就从内存中

< p>
消失了。





如果你的应用程序使用许多不同的


COM


对象, 因此在用完某个接口后调用


Release()


就显得


非常重要。如果你不释放接口,这个


COM


对象 (包含代码的


DLLs


)将保留在内存中,这会增加

< p>
不必要的开销。如果你的应用程序要长时间运行,就应该在应用程序处于空闲期间调用


CoFreeUnusedLibraries() API



这个


API


将卸载任何没有明显引用的


COM


服务器,


因此这也降低了

应用程序使用的内存开销。



继续用上面的例子来说明如何 使用


Release()






//


像上面一样创建


COM


对象,



然后,




if ( SUCCEEDED ( hr ) )


{


//



pISL

调用方法




//


通知


COM


对象不再使用它



pISL->Release();


}



接下来将详细讨论


IUnknown


接口。



基本接口——


IUnknown





每一个


C OM


接口都派生于


IUnknown


。 这个名字有点误导人,其中没有未知(


Unknown


)接


口的意思。它的原意是如果有一个指向某


COM

对象的


IUnknown


指针,就不用知道潜在的对象


是什么,因为每个


COM


对象都实现


IUnknown





IUnknown


有三个方法:




AddRef()


——


< p>
通知


COM


对象增加它的引用计数。如果你进行了 一次接口指针的拷贝,就必须


调用一次这个方法,


并且原始的值 和拷贝的值两者都要用到。


在本文的例子中没有用到


AddRe f()


方法;




Release()


——



通知


COM


对象减少它的引用计数。参见前面的


Release()


示例代码段;




QueryInterface()


——




CO M


对象请求一个接口指针。当


coclass

< br>实现一个以上的接口时,就要


用到这个方法;






前面已 经看到了


Release()


的使用,但如何使用


QueryInterface()



?

< p>
当你用


CoCreateInstance()


创 建对象的时候,你得到一个返回的接口指针。如果这个


COM


对 象实现一个以上的接口(不包



IUnknown



,你就必须用


QueryInterface()


方法来获得任何你需要的附加的接口指针。


QueryInte rface()


的原型如下:





HRESULT IUnknown::QueryInterface (


REFIID iid,


void** ppv );



以下 是参数解释:


iid


:所请求的接口的


IID




ppv

:接口指针的地址,


QueryInterface()


通 过这个参数在成功时返回这个接口。





让我们继续外壳链接的例子。它实现了


IShellLink



IPersistFile


接口。如 果你已经有一个


IShellLink


指针,

< br>pISL


,可以从


COM


对象请 求


IPersistFile


接口:





HRESULT hr;


IPersistFile* pI


























PF;


hr = pISL->QueryInterface ( IID_IPersistFile, (void**) &pIPF );





然后使 用


SUCCEEDED


宏检查


hr


的值以确定


QueryInterface()

的调用情况,


如果成功的话你就


可以象使用其它接口指针那 样使用新的接口指针,


pIPF


。但必须记住调用


pIPF->Release()


通知


COM


对象已经用完这个接口。



仔细做好串处理






这一部分将花点时间来讨论如何在


COM


代码中处理串。


如果你熟悉


Unicode



ANSI



并知


道如何对它们进行转换的话,你就可以跳过这 一部分,否则还是读一下这一部分的内容。





不管什么时候,只要


COM


方法返回一个串,这个串都是


Unicode


串 (这里指的是写入


COM


规范的所有方法)


Unicode


是一种字符编码集,类似


ASCII


,但用两个字节表示一个字符。如果


你想更 好地控制或操作串的话,应该将它转换成


TCHAR


类型串。< /p>





TCHA R


和以


_t


开头的函数


(如


_tcscpy()



被 设计用来让你用相同的源代码处理


Unicode


< p>
ANSI


串。在大多数情况下编写的代码都是用来处理

ANSI


串和


ANSI


Wind owsAPIs


,所以在下文中,除


非另外说明,我所说的字符


/


串都是指


TCHAR


类型。你应该熟练掌握


TCHAR


类型,


尤其是当你阅


读其他人写的有关代码时,要特别注意


TCHAR


类型。





当你从某个


COM

< br>方法返回得到一个


Unicode


串时,


可以用下列几种方法之一将它转换成


char


类型串:




调用



WideCharToMultiByte() API





调用


CRT


函数

wcstombs()





使用


CString


构造器或赋值操 作


(


仅用于


MFC )





使用


ATL


串转换宏;




WideCharToMultiByte()


< p>
你可以用


WideCharToMultiByte()

< br>将一个


Unicode


串转换成一个

ANSI


串。此函数的原型如下:



int


WideCharToMultiByte (


UINT





CodePage,


DWORD




dwFlags,


LPCWSTR lpWideCharStr,


int






cchWideChar,


LPSTR




lpMultiByteStr,


int






cbMultiByte,


LPCSTR



lpDefaultChar,


LPBOOL



lpUsedDefaultChar );



以下是参数解释:



CodePage



Unicode

< br>字符转换成的代码页。你可以传递


CP_ACP


来使用当 前的


ANSI


代码页。代码


页是


256


个字符集。


字符


0


——


127


ANSI


编码一样。


字符


128< /p>


——


255



A NSI


字符不同,


它可


以包含图形字符 或者读音符号。


每一种语言或地区都有其自己的代码页,


所以使 用正确的代码页


对于正确地显示重音字符很重要。




dwFlags



dwFlags < /p>


确定


Windows


如何处理“复合”< /p>



Unicode


字符,它是一种后面带 读音符号的


字符。



如è就是一个复合 字符。如果这些字符在


CodePage


参数指定的代码页中, 不会出什么事。



否则,


Window s


必须对之进行转换。


传递


WC_CO MPOSITECHECK


使得这个


API

检查非映射复合字


符。



传递


WC_SEPCHARS


使得


Window s


将字符分为两段,即字符加读音,如


e`


-


-


-


-


-


-


-


-



本文更新与2021-03-03 12:38,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/699957.html

什么是COM如何使用COM的相关文章