原文链接:
http://www.codeproject.com/Articles/633/Introduction-to-COM-What-It-Is-and-How-to-Use-It COM是个啥?
是一个可以跨语言跨进成的二进制复用方法。不同于C++的模板和继承是源代码级别的复用,COM是二进制级别的。windows下服用二进制代码的例子就是dll文件。但是之前这些dll的接口都是用c写的,所以只有c语言能够明白这些接口,vb都不行。
COM通过定义二进制标准来解决这些问题。COM指定这些DLL或者EXE必须按特定的结构在内存中进行组织。并且,这些二进制代码与语言不相关。一旦这么做了,那么用不同的语言访问这些二进制代码将变成现实。
由于COM对象在内存中的结构碰巧同那些用c++虚函数编写的结构相同,所以,很多COM代码用C++来些,但是记住COM其实是语言无关的。
COM基本概念1.
接口类: 一组函数或者方法。一般是抽象类,方法全部为纯虚函数。作为父类,提供服务。接口类一般以I开头,例如IShellLink。接口可以从其他接口继承,接口的继承是单根继承模式,即从一个IUnknown继承而来。不允许多重继承,有点像Java。
2. coclass类(component object class)包含在一个DLL或者一个EXE文件中,继
承一个或多个接口,具体实现这些接口。3. COM对象:一个coclass类在内存中的实例。4. COM服务器:提供coclass的二进制文件(DLL或EXE),包含一个或多个coclass类。要想提供服务,该COM服务器必须注册到本地的注册表中,也就是说,这个COM服务器放在了哪里,可以在那个文件目录下找到。每个COM服务器都可以在注册表中找到。
那么整个的层次结构应该是:
GUID(Globally Unique identifier)128位数,因为是个数值,所以是语言无关的。每个接口类和coclass都有一个GUID,而且全球唯一。
CLSID 是coclass 的GUIDIID是接口类的GUID有两个原因使得GUID在COM中被广泛应用
1. 只是一个数值,每个编程语言都可以处理。
2. 每个被创建的GUID都是唯一的。因此,COM开发者可以穿件自己的GUID而不会同别人相同。
5. HRESULT: 一个整形,是返回值。
6. COM库是操作系统的一部分,当你在做COM相关的工作时,会和它交互。开动:
先看看COM和C++的不同:1.
创建新对象: C++ operator new 在堆上创建,或者在栈上创建
COM,调用COM库中的API函数创建
2.
删除对象: C++ operator delete删除堆上对象,或者移动栈指针清楚栈上的临时变量
COM中调用COM库中的API函数删除
当你创建一个COM对象时,你要跟COM库的API函数说你需要哪个接口,如果对象创建成功,会返回指向那个接口的指针。
然后你就可以调用这个接口中的方法了。
从代码中看看怎么创建一个COM对象
COM库API
HRESULT CoCreateInstance (
REFCLSID rclsid,// coclass 的CLSID
LPUNKNOWN pUnkOuter,// 用于聚合
DWORD dwClsContext,//COM server 的类型
REFIID riid, // 你请求的接口IID
LPVOID* ppv // 请求的接口返回值);
你可能会问,如果所有的COM库API的返回值都是HRESULT的话,那么有时候我要返回一些结果怎么办?COM中有个属性是OUT的参数来存放该返回结果,这里就是ppv。
当你调用上述的函数的时候,该函数会在注册表中搜索与CLSID相符合的ID,并且获取该COM服务所在的文件夹,把它放到内存中去,并且创建一个coclass的实力。
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.
}
删除一个COM对象:
我们不必释放掉一个COM对象,只要说我不用它就行了。每个COM对象都实现了IUnknown接口(因为所有的接口类都从这个接口继承),这个接口中有个release()方法。当你调用了这个方法,你就不能再用这个接口指针了
IUnknown接口类不是不知道接口类,而是如果你有个一个IUnknown接口指针指向COM对象,
你不需要知道这个对象是个啥,这就是向上类型转换的结果,IUnknown是所有类的父类,所有的类都可以向上转型为IUnknown类,这样的好处是所有的函数都可以接受IUnkonwn指针或者引用。
只有三个方法,非常重要
1.
AddRef()--告诉COM对象增加自己的引用计数。如果你copy了一个接口指针,比如通过赋值操作,就的把引用计数加一。2. Release()--减小引用计数。3. QueryInterface()--请求一个COM对象的接口。当你用CoCreateInstance()创建了一个COM对象之后,你将会得到一个接口指针。如果这个COM对象有多个接口,即从多个接口继承的话,你就要用QueryInterface()来获得这个接口的指针。
HRESULT IUnknown::QueryInterface ( REFIID iid, void** ppv );
iid就是你要请求的接口ID
ppv就是你要请求的接口的指
一个简单的例子:
利用shell中的Active Desktop coclass获得当前壁纸的名字。
步骤:
1. 初始化COM库,因为我们要用到其中的函数
2. Create COM对象,获得一个IActiveDesktop借口
3. 调用GetWallpaper方法
4. 如果成功打印名字
5. Release()接口
6. 卸载COM库。
WCHAR wszWallpaper [MAX_PATH];
CString strPath;
HRESULT hr;
IActiveDesktop* pIAD;
// 1. Initialize the COM library (make Windows load the DLLs). Normally you would
// call this in your InitInstance() or other startup code. In MFC apps, use
// AfxOleInit() instead.</FONT>
CoInitialize ( NULL );
<FONT COLOR="#009900">// 2. Create a COM object, using the Active Desktop coclass provided by the shell.
// The 4th parameter tells COM what interface we want (IActiveDesktop).</FONT>
hr = CoCreateInstance ( CLSID_ActiveDesktop,
NULL,
CLSCTX_INPROC_SERVER,
IID_IActiveDesktop,
(void**) &pIAD );
if ( SUCCEEDED(hr) )
{
<FONT COLOR="#009900">// 3. If the COM object was created, call its GetWallpaper() method.</FONT>
hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 );
if ( SUCCEEDED(hr) )
{
// 4. If GetWallpaper() succeeded, print the filename it returned.
// Note that I'm using wcout to display the Unicode string wszWallpaper.
// wcout is the Unicode equivalent of cout.
wcout << L"Wallpaper path is:\n " << wszWallpaper << endl << endl;
}
else
{
cout << _T("GetWallpaper() failed.") << endl << endl;
}
// 5. Release the interface.
pIAD->Release();
}
else
{
cout << _T("CoCreateInstance() failed.") << endl << endl;
}
// 6. Uninit the COM library. In MFC apps, this is not necessary since MFC does
// it for us.
CoUninitialize();
1
。
1
1
posted on 2012-04-18 17:17
Dino-Tech 阅读(295)
评论(0) 编辑 收藏 引用