引用本为说明出处:chinabinlang的专栏;(以下示例均在VC6上编译执行通过)
一:COM的创建:
网上有很多关于com的文章,比较好的有杨老师文章(在vc知识库上有连载),还有一些经典的com书籍,这里不做过多介绍,从com编写直接开始,简单迅速的了解com;
一般com开发可以用ATL向导(这里vc6),当然如果你很牛,可以不用向导;
开发步骤:ATL COM AppWizard -> Dynamic Link Library(DLL) -> Insert -> New ATL Object... -> Category Objects(选择 Simple Object) -> next -> Names属性框中写你的com对象名字, Attributes属性框,可以修改 Interface 下的为 Custom(也可以默认Dual)-> 确定;
这样就添加了com对象了,如何先进接口的方法呢? 鼠标右键到接口上(像一个小勺子)选择 Add Method...,具体实现在类里面;
用ATL创建com组件:
1:通常通过添加 New ATL Object | Simple Object 添加com组件的一个对象;默认情况下,一个组件对象对应一个接口(一个dll可以添加多个Simple Object ,每个Simple Object 都是一个组件对象,通过CoCreateInstance创建同时创建一个接口),可以通过这种方式添加多个组件对象;
可以在一个对象下添加多个接口类(com组件的接口就是外部看见的类)(就是QueryInterface到同一个组件下的多个不同接口类,如第2点所示);
2:com中对象的可以包含多个接口,在ATL中,默认情况下,一个对象对应一个接口;
可以通过鼠标右键到某个对象上 选择:Implement Interface,给这个对象添加新的接口,但是同名函数会被隐藏;
注意:虽然都是同一个接口,但是,在不同对象下的具体函数内容要具体实现,如:
Objectone对象添加 Objecttwo对象的接口Iobjtow,同时Iobjtow有objtowFun1函数,
这时,Objectone 和 Objecttwo 都要具体实现objtowFun1函数,函数内容可以不同;
3:调用Iobjtow接口,如果是想调用Objecttwo对象的实现,这样调用:
::CoCreateInstance(CLSID_objtwo,NULL, CLSCTX_INPROC_SERVER, IID_Iobjtwo, (LPVOID *) &pobjtwo);
pobjtow-objtowFun1();
如果是想调用Objectonw对象的实现,这样调用:
hr = ::CoCreateInstance(CLSID_objone,NULL, CLSCTX_INPROC_SERVER, IID_Iobjone, (LPVOID *) &pobjone);
hr = pobjone->QueryInterface( IID_Iobjtow, (LPVOID *)&pobjtow );
pobjtow-objtowFun1();
4:如果我们只想在一个对象添加多个接口,不想看见其他对象,我们可以屏蔽(注释)某个对象的源文件,.h和.cpp文件 和 OBJECT_ENTRY(CLSID_objtow, Cobjtow);
示例:
一:一个dll中一个组件对象关联多个接口:
组件中,一个clsid关联多个iiid;
调用方法:
======================================================================================================================================================================================================================================================================
二:COM的调用(注:COM必须先注册):
网上有关com调用的方法比较多,这里我详细说明一下:
方法1:
如果我创建了一个com组件,那么可以通过已有的文件调用导入调用com(这样就和directshow调用差不多了):
#include " ..\ATLComDemo\ATLComDemo.h"
#include "..\ATLComDemo_i.c"
#include <atlbase.h>
HRESULT QueryInterfacecom()
{
HRESULT hr = CoInitialize(NULL);
Iobjone * pobjone = NULL;
Iobjtow * pobjtow = NULL ;
Iobjthree * pobjthree = NULL;
//´´½¨COM ¶ÔÏóCobjoneʵÀý£¬Í¬Ê±»ñÈ¡CobjoneÏ嵀 Iobjone ½Ó¿Ú£»
hr = ::CoCreateInstance(CLSID_objone,NULL, CLSCTX_INPROC_SERVER, IID_Iobjone, (LPVOID *) &pobjone); if( FAILED( hr ) ){cout<<"hr";};
pobjone->fun1(); if( FAILED( hr ) ){cout<<"hr";};
//»ñÈ¡CobjoneÏ嵀 Iobjtow ½Ó¿Ú£»
hr = pobjone->QueryInterface( IID_Iobjtow, (LPVOID *)&pobjtow ); if( FAILED( hr ) ){cout<<"hr";};
pobjtow->fun3();
//»ñÈ¡CobjoneÏ嵀 Iobjtow ½Ó¿Ú£»
hr = pobjone->QueryInterface( IID_Iobjthree, (LPVOID *)&pobjthree ); if( FAILED( hr ) ){cout<<"hr";};
pobjthree->funthree1();
pobjthree->funthree2();
pobjone->Release();
pobjtow->Release();
pobjthree->Release();
CoUninitialize();
return hr;
}#include <atlbase.h>
HRESULT QueryInterfacecom()
{
HRESULT hr = CoInitialize(NULL);
Iobjone * pobjone = NULL;
Iobjtow * pobjtow = NULL ;
Iobjthree * pobjthree = NULL;
//´´½¨COM ¶ÔÏóCobjoneʵÀý£¬Í¬Ê±»ñÈ¡CobjoneÏ嵀 Iobjone ½Ó¿Ú£»
hr = ::CoCreateInstance(CLSID_objone,NULL, CLSCTX_INPROC_SERVER, IID_Iobjone, (LPVOID *) &pobjone); if( FAILED( hr ) ){cout<<"hr";};
pobjone->fun1(); if( FAILED( hr ) ){cout<<"hr";};
//»ñÈ¡CobjoneÏ嵀 Iobjtow ½Ó¿Ú£»
hr = pobjone->QueryInterface( IID_Iobjtow, (LPVOID *)&pobjtow ); if( FAILED( hr ) ){cout<<"hr";};
pobjtow->fun3();
//»ñÈ¡CobjoneÏ嵀 Iobjtow ½Ó¿Ú£»
hr = pobjone->QueryInterface( IID_Iobjthree, (LPVOID *)&pobjthree ); if( FAILED( hr ) ){cout<<"hr";};
pobjthree->funthree1();
pobjthree->funthree2();
pobjone->Release();
pobjtow->Release();
pobjthree->Release();
CoUninitialize();
return hr;
}
方法2:
通过向导添加com组件到工程,这样组件中的接口类和相应的成员函数就显示到工程中了,想到ocx一样:
调用方法:
1:导入生成的头文件
2: 声明对象,然后用CreateDispatch创建实例,参数为:com名.接口类名(类名不需要前面默认的I);
3:最后释放示例;
#include "atlone.h"
void CTalonecomexeDlg::OnButton1()
{
// TODO: Add your control notification handler code here
CoInitialize(NULL);
Icomone Icomoneobj;
if ( Icomoneobj.CreateDispatch("atlone.comone") !=0 )
{
Icomoneobj.fun1();
Icomoneobj.fun2();
}
Icomoneobj.ReleaseDispatch();
CoUninitialize();
}
方法3:导入com组件后会生成相应的tlh,可以用下列方法使用dll;
#import "../atlone/Debug/atlone.dll" no_namespace
void CTDlg::OnButton1()
{
// TODO: Add your control notification handler code here
CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(L"atlone.comone",&clsid);
Icomone * pcomone = NULL;
HRESULT hr = CoCreateInstance( /*CLSID_comone*/clsid,NULL,CLSCTX_INPROC_SERVER,/*IID_Icomone*/__uuidof(Icomone), (void**)&pcomone );
pcomone->fun1();
pcomone->fun2();
pcomone->Release();
CoUninitialize();
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
转载一篇VC调用com组件的文章:《vc中调用Com组件的方法详解》(注:没有全部验证)
Requirement:
1.创建myCom.dll,该COM只有一个组件,两个接口IGetRes--方法Hello(),IGetResEx--方法HelloEx();
2.在工程中导入组件或类型库
------------------------------------ Method 1 ------------------------------------
------------------------------------ Method 2 ------------------------------------
------------------------------------ Method 3 ------------------------------------
------------------------------------ Method 4 ------------------------------------
------------------------------------ Method 5 ------------------------------------
------------------------------------ Notice------------------------------------
--------------------------------------------------------------------
以上就是COM的5中方法,当然具体怎么使用还是要根据具体情况而定。
======================================================================================================================================================================================================================================================================
转一篇关于com基本概念的文章:
组件不一定就是一个dll,一个dll中可以包含很多个组件,而且一般见到的dll里也不止包含一个组件,一个dll里的每个组件都有自己的CLSID和ProgID。对于ATL工程来说,一个ATL Object就是一个组件,很明显,我们可以在一个工程里加入很多个ATL Object。
对于ATL来说,一个组件对应着一个C++类,这在IDL中叫做coclass,一般情况下,一个coclas对应一个接口。实际上,一个coclass可以有很多个接口,这就是一个组件实现多个接口,并且这些接口共享一个组件中的函数。
比如:coclass A有一个接口IA,接口导出了一个函数Foo(),那么coclass A里有一个Foo()函数来实现IA接口中的Foo()函数。后来想要对组件A升级,加入一个导出函数Foo2(),但是又不想影响以前的用户,当然重做 一个新组件是可以的,但是没有必要,并且有了重复代码。这时我们可以在组件A中新建一个接口IA2,IA2导出两个函数:Foo()和Foo2(),IA2仍然由coclass A来实现,也就是说现在coclass A里有了两个函数Foo()和Foo2(),接口IA和IA2共享coclass A里的Foo()函数。这样一来,以前的用户不用变化,因为接口IA没有改动,新的用户可以使用接口IA2,使用IA2也仍然可以完成IA的功能,因为时 而也有Foo()函数。