什么是COM对象?
组件对象模型(COM)对象是一个使用COM规格的可以重复使用的软件组件。使用COM规格可以确保COM对象很好的工作,并且很容易的结合到你的应用程序中。事实上,COM基本相当于一个黑匣子,这个黑匣子能为你的应用程序完成很多的工作。
COM对象一般用动态连接库(DLL)实现。和普通的DLL一样,COM对象暴露一些方法,你的应用程序能够呼叫它,以便完成任何支持的操作。应用程序与COM对象的相互作用有点儿像应用程序与C++对象之间的相互作用,但他们之间又有一些明显的不同。
●COM对象实施了精确的封装。你不能简单的创建一个对象和任意呼叫它的公共方法。一个COM对象的公共方法被放入一个或更多的接口组中。对于方法的使用,你必须创建一个COM对象,并且从这个COM对象中获得这个COM对象的一个适当的接口。例如: IDirect3DCubeTexture8接口中包含一个使你能够处理立方体构架资源的方法。不属于这个接口的任何方法都是不能够访问的。
●COM对象的创建不同与C++对象的创建。有几种方法可以创建COM对象,但都涉及到了COM-specific 技术。微软的DirectX应用程序接口(API)包含了用于创建大多数DirectX对象的各种各样的帮助函数和方法。
●你必须用COM_specific 技术控制COM对象的寿命。
●COM对象不需要被显示的调入。COM对象被包含在一个DLL中。然而,在你使用这个COM对象的时候,不需要显示的调入DLL或着显示调入静态接库。每一个COM对象有一个用来创建这个对象的唯一的注册ID. COM会自动的调入正确的DLL.
●COM是二进制规格的。COM对象可以从各种的各样的语言写入和访问。你不需要知道关于COM对象源码的任何事情。例如:Microsofe Visual Bisice 应用程序日常用COM对象写入C++ .
内容:
●对象和接口
●GUIDS
●HRESULT值
●指针的地址
一、对象和接口
明白对象和接口之间的区别是很重要的。偶然的用法是, 有的时候一个对象的名字被引用为主要接口的名字。然而,严格的说,这两个条件是不能互换的。
▲一个COM对象能够暴露任意数量的接口。例如:所有的COM对象必须暴露IUnknown接口,它们一般至少暴露一个附加的接口,也可能更多。为了使用这些特殊的方法,你不仅要创建COM对象,而且还要获取正确的接口指针。
▲很多的对象可能暴露相同的接口。一个接口是一组能够执行指定操作的方法。接口的定义规定了方法的语法和他们功能。支持特殊操作的任何一个COM对象都暴露了一个适当的接口。有一些接口是高度专门化的,并且它们只被一个单一的对象暴露。其他多数情况下是被多个对象暴露的。一个很特殊的情况的是IUnknown接口必须被每一个COM对象暴露。
附注:假如一个对象暴露一个接口,它必须在接口中定义每一个支持的方法。换句话说,你能够呼叫的任何方法都要确信它是存在的。然而,从一个对象到另一个对象,方法实现的细节是能够改变的。例如:不同的对象可能用不同的算法得到最后的结果。有时候,一个对象暴露一个旧的接口,仅仅需要支持方法的子集。你仍然能够成功的呼叫余下的其它方法,但是,他们将返回E_NOTIMPL。要想知道一个接口如何被特定的对象实现,参阅文档。
COM标准要求一个接口一旦发行,它的定义便不能再改变。你不能再这个已经存在的接口中添加新的方法。你必须重新创建一个新的接口。通常一般的做法是在下一代接口中包含旧接口的所有方法,然后再添加上任何新的方法。
一个接口有几代这是很常见的。通常,他们的实质是一样的, 但是他们的细节不同。通常,一个对象能够暴露每一代的接口。这样做允许较老的程序继续使用对象的较老的接口,同样新的程序也能发挥新接口的特性。通常,接口家族有相同的名字,在名字的后面加上用于标示第几代的整数。例如:假如原始接口的名字为IMyInterface, 那么下两代的接口被命名为IMyInterface2和IMyInterface3。整数标示一般用directx的版本号。
二、GUIDS
全局唯一标示符(GUIDS)是COM程序模式的一个关键的部分。最基本的原则,GUIDS是一个128位的结构。然而,GUIDS的创建方式能够保证任何的两个GUIDS都是不相同的。COM广泛的使用GUIDS有两个主要的目的:
1、为了唯一标示一个特定的COM对象。
2、为了唯一标示一个特定的COM接口。
三、返回值(HRESULT)
所有的COM方法返回一个名叫HRESULT的32位值。对于大多数方法,HRESULT 实际上是一个包含了两部分信息的结构。
1、这个方法是否成功或失败。
2、输出关于方法支持的操作的详细信息。
一些方法返回的HRESULT的值是在Winerror.h中进了定义的。方法返回的HRESULT值也可以是用户专门的一些信息。这些值通常会在方法的参考页中被验证。
事实上,COM对象的方法调用能够返回各种各样的表示调用成功或失败的代码,这意味着你必须要很小心的测试其返回值。例如:假如一个方法调用的返回值是
S_OK,这表明这个方法调用成功,如果返回值时S_FAIL,表明调用失败,当然,方法调用也可能返回其他的标识调用成功或者失败的代码。下面的代码段举例说明对代码进行这样的简单的测试是不安全的。代码中hr的值时该方法调用的返回值:
if( hr == E_FAIL )
{
//Handle the failure
}
else
{
//Handle the success
}
如果这段代码只返回E_FAIL,这个代码段能够很好的工作。然而,事实不是这样,这个方法调用还有可能返回其他的值,例如:E_NOTIMPL, E_INVALIDARG.如果代码返回这些值,这个代码段没有对其进行处理,默认会标识程序执行正常,然而实际程序是出现错误的。
如果你想知道关于方法调用的更详细的信息,你必须测试每一个相关的返回值。然而,你也许只想知道这个方法调用是否成功。有一种很好的方法可以让你测试方法调用是否成功,就是把方法的返回值传递给下面的两个宏,他们在winerror.h文件中定义。
1、宏SUCCEEDED 返回TRUE表明调用成功,返回FALSE表明调用失败。
2、宏FAILED 返回TRUE 表明调用失败,返回FALSE表明调用成功。
你可以用FAILED宏来修改一下前面的代码段。
if( FAILED(hr) )
{
//Handle the failure.
}
else
{
//Handle the success.
}
上面的代码段对E_NOTIMPL 和 E_INVALIDARG的错误进行了处理。
虽然大部分的方法的返回值HRESULT是一个结构值,但有少数的方法的返回值HRESULT是一个简单的整数值。这就隐含着返回整数值的这些方法总是能够调用成功。假如你将这种类型的返回值传递给SUCCESS宏,这个宏将总是返回TRUE。一个常见的例子是:IUnkoown::Release 方法。这个方法的作用是释放(减少)一个对象的使用计数,并返回对象的当前使用计数。使用计数用来标识对象的存在寿命。
四、指针的地址
假如你看到过一些COM方法的参考页面,你可能遇到过像下面的这样的一些情况:
HRESULT CreateDevice(
.
.
.
IDirect3DDevice8 **ppReturnedDeviceInterface
)
通常,任何一个c 或者c ++开发者对指针都很熟悉,COM通常用一个附加的间接标准。这个标准是:在两个星号(**)后面紧跟着类型说明和带有典型"pp"前缀的变量的名字来标识。在前面的例子中,ppReturnedDeviceInterface参数是一个指向IDirect3DDevice8接口的指针的地址。
和c++不一样,你不能直接访问COM对象的方法,取而代之的是,你必须获得一个能够暴露方法的一个接口的指针。调用对象接口的方法的语法和用指针调用c++方法的语法是一样的。例如:调用IMyTnterface::DoSomething 的方法,你只需使用下面的语法就行了。
IMyInterfance *pMyTface;
.
.
.
pMyIface->DoSomething(...) ;
对于COM对象接口的指针来说,你不能直接创建一个指向接口的指针。你必须呼叫一个或多个其他的方法来得到这个指针。例如:前面提到的CreateDevice方法。
通过这个方法得到接口的指针,你需要声明一个变量,用来指向你所请求的接口。把这个变量的地址传递给CreateDevice方法,换句话说,你必须给这个方法传递一个变量的地址。当这个方法返回的时候,这个变量将指向你所请求的接口,并且你能够通过这个指针来访问这个接口的其方法。关于如何使用这个接口的指针,我们将在下一篇文章中详细介绍。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/closeall2008/archive/2005/09/03/470695.aspx