关闭

COM入门2(引用)

262人阅读 评论(0) 收藏 举报

Introduction to COM - What It Is and How to Use It
By Michael Dunn
From www.codeproject.com

/**********原创翻译,转载请注明出处*********** 新手水平有限,欢迎批评指教 By FreeKid /

COM入门简介 -- 什么是COM , 怎样使用它 (2)

基本元素定义

让我们从头开始。简单的说,接口就是一组函数。这些函数被称作"方法"。接口的名称以大写字母'I'打头,例如"IShellLink"。在C++中,接口总被写成一个只含有纯虚函数的抽象基类。

接口可以从其它接口"继承"而来,它的机制就像C++中的单继承一样。而接口是不允许多重继承的。

COClass(Component Object Class)被包含在DLL或者EXE文件之中,并且它包含着一个或多个接口代码。COClass就是来实现这些接口的。COM对象是COClass在内存中的一个实例。虽然在通常情况下一个用来实现COM的类就是C++类,但要注意COM的"类"与C++中的"类"是不同的。

COM服务器是包含一个或多个COClass的二进制单位(DLL或者EXE)。

为了通知Windows COM服务器的位置,需要在注册表中"注册"(Registration)相应信息。同样,反注册(Unregistration)是用来消除那些注册信息的。

GUID(Globally Unique Identifier)是一串128位的数字。GUIDs是COM识别事物的一种方法,且这种方法是与语言无关的。每个接口和COClass都有一个GUID。GUIDs是全球唯一的,所以这就避免了命名冲突问题(只要你使用COM API来创建它们)。你有时也会发现UUID(Universally Unique Identifier)这个术语。然而,UUIDs和GUIDs在实际用途方面是相同的。

Class ID或者是CLSID,它们都是用来命名COClass的GUID。Interface ID或者IID,它们是用来命名接口的GUID。

其实有两个原因使得GUIDs在COM中使用的如此广泛:

1.GUIDs仅仅是一串数字,任何语言都可以处理它们。
2.当任何人在任意机器上创建GUIDs的时候,它都是唯一的。因此,COM开发者们可以自己创建GUIDs,而且不用担心有两名开发者选择了相同的GUID。这就免除了需要一个中央权威机构发放GUIDs的要求。

COM用HRESULT这个类型(整型)来返回错误或者成功的代码。尽管有个'H'前缀,但它并不是指向什么东西的"句柄"。稍后我将会详细的说明HRESULTs以及怎样测试它们。

最后,在做COM相关的事务时,与你进行交互的COM库其实是操作系统的一部分。通常情况下,COM库就被成为COM,但在这里为了避免误解,我没有这样做。

使用COM对象

每种语言都有其处理对象的方法。例如,在C++中你可以在栈上创建它们,或者使用new操作符动态的分配它们。COM库提供了它自己的一套对象管理方法,使得COM是与语言无关的。比较一下COM和C++的对象管理,区别如下:

创建一个新对象

 在C++中,使用new操作符或直接在栈上创建对象。
 在COM中,需要调用COM库中的API。

删除对象

 在C++中,使用delete操作符或者让栈上的对象超出作用域,自动删除。
 在COM中,所有的对象必须维持它们自己的引用计数。调用者必须在使用完对象之后通知对象,COM对象会在引用计数为0的时候在内存中自动删除。

事实上在创建和删除两个阶段之间,你必须去使用它。在创建COM对象的时候,你要告诉COM需要什么样的接口,请求获取它。如果对象创建成功,COM库会返回一个指向所请求接口的指针。之后你就可以像使用C++对象指针一样,通过这个指针来调用方法了。

创建COM对象

为了要创建COM对象并从中获得一个接口,你可以调用COM库的API函数 CoCreateInstance()。它的原型如下:

HRESULT CoCreateInstance (
    REFCLSID  rclsid,
    LPUNKNOWN pUnkOuter,
    DWORD     dwClsContext,
    REFIID    riid,
    LPVOID
*   ppv );

形参如下:

rclsid
 COClass的CLSID。例如,你可以将CLSID_ShellLink传入创建一个COM对象用来建立快捷方式。
pUnkOuter
 这个参数只有在聚合(aggregate)COM对象的时候才使用。聚合COM对象可以在已经存在的COClass中加入新的方法。在这里,只需要传入NULL表明我们不需要使用聚合。
dwClsContext
 用来说明我们需要使用什么样的COM服务器。对这篇文章来说,我们总使用一个进程DLL作为最简单的服务器,因此传入CLSCTX_INPROC_SERVER。请注意,这里不应该使用CLSCTX_ALL(ATL的默认参数),因为它将在没有安装DCOM的Windows95系统上运行失败。
riid
 你所需要接口的IID,例如,你可以传入IID_IShellLink用来获取IShellLink接口的指针。
ppv
 接口指针的地址。COM库将通过这个参数返回所请求的接口。

当你调用CoCreateInstance()时,它将在注册表中查找CLSID,读取服务器的位置,并将服务器加载到内存中,最后创建一个你所申请的COClass实例。

下面是一个简单的调用,展示了一个CLSID_ShellLink对象并获取了COM对象的IShellLink接口指针。

HRESULT     hr;
IShellLink
* pISL;

hr 
= CoCreateInstance ( CLSID_ShellLink,         // CLSID of coclass
                        NULL,                    // not used - aggregation
                        CLSCTX_INPROC_SERVER,    // type of server
                        IID_IShellLink,          // IID of interface
                        (void**&pISL );        // Pointer to our interface pointer

    
if ( SUCCEEDED ( hr ) )
        
{
        
// Call methods using pISL here.
        }

    
else
        
{
        
// Couldn't create the COM object.  hr holds the error code.
        }

首先我们声明了一个用来接收CoCreateInstance()返回结果的HRESULT和一个IShellLink指针。之后调用CoCreateInstance()函数创建一个新的COM对象。如果hr包含成功的代码,则SUCCEEDED宏返回TRUE,否则返回FALSE。相应的,也有一个用来检测失败代码的FAILED宏。

(未完待续)

 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1416次
    • 积分:27
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章存档