`

实例深入学习COM技术

    博客分类:
  • COM
阅读更多

COM技术介绍

一、COM介绍

1、  定义

(Component Object Model)

COM是微软公司的最高级的,包罗万象的二进制通讯规范(也就是说是大家都要遵守的合同)。用于软件组件间跨进程,跨机器,和操作系统进行交互操作。COM是透明位置的。它可以在EXE,DLL或者远程机器上使用。

OLE是一个主要与用户界面相关的高级功能的集合。COM和OLE的概念界限原本就不清晰,总是容易混淆。

2、  历史

OLE(Object Linking & Embedding )是1991年首次出现的(是WINDOWS3.1自带的)。OLE最初的含义是对象链接和嵌入。当时用DDE(动态数据交换)作为底层通讯协议。

1993,COM首次出现。微软推出OLE2.0,开始用COM代替DDE作为底层通讯协议。这也是COM第一个重要的用途。

1996年,大多数开发人员开始编写32位的WIN95应用程序。他们发现,OLE使用COM的方式是一种非常好的设计软件的方法。开发人员开始使用类似的方法编写自己的对象和界面。另外,操作系统也开始要求使用COM技术编程,如编写WIN95用户界面。这些即不是OLE,也不是AUTOMATION,那么他到底是什么呢?这个属于大多数人倾向于使用COM。

3、  发展

1996年,微软推出NT4.0,DCOM首次出现,作为NT的一部分。它实现了将COM在分布式系统中的应用。

1997年开始流行ATL。COM作为一种技术规范,最早是由C语言来实现的,但是实现起来比较复杂。出现VC以后,又对COM进行了预制和封装,大大简化COM应用的开发。这就是ATL(Active Template Library)。

4、  现状

我们经常见到的用途:

使用外来控件。特别是在网页上使用ACTIVEX控件。ADO

WORD/EXCEL的应用。(两者交叉使用,在应用程序中调用)

二、概念

接口:可以理解为一个抽象的类。

OBJCET(component),相当与组件。与VC和VB中理解的OBJECT是两个不同的概念。千万不要混淆。一个纯粹封装的OBJCET


它是一个封装好的黑匣子。是一个不能看到内部数据结构的东西。是一个抽象的东西。

最基本的OBJCET,给这个OBJECT 加上接口,用于访问这个黑匣子。那么这个OBJECT就是一个COM OBJECT了。

Func1()

IFOO

Func2()


相当于一个手机充电器。用插销作为标准接口,但是内部实现被隐藏了起来。

在C++中,接口被表示为一个抽象的类。

例如: 程序清单:

class IFoo {

   virtual void Func1();

   virtual void Func2();

};

特点:

内部有多个纯虚函数。并且没有函数的实现。而且也不能包含任何内部数据成员。

把接口与实现隔离开来的目的:要把对象内部的工作细节隐藏起来,而这些实现都在类中实现。当实现类的数据成员发生变化时,客户程序是与已经编译好的二进制的接口通讯,所以它也无须重新编译。

例子:

手机是一个COM。它的芯片是接口。无论信息如何发生变化。我们都能接受。它的实现是个不不相同。而不同的实现就是不同的国产手机厂家。但是国内所有的厂家生产的手机全部都是使用的国外同一家的芯片产品,也就是说用同一个接口。

常见(有两个接口)

对象支持多接口。如果老版本的接口不方便,可以继承一个新的接口。但不能修改老的接口。接口一旦发布,就不能修改。

如果增加一个接口IFOO2,该接口仍然包含原接口IFOO的两个函数,而且新增加一个函数

IFOO    

IFOO2

程序清单:

class IFoo2 : public IFoo {

   // Inherited Func1, Func2

   virtual void Func2Ex(double nCount) = 0;

};

如何在C++中使用该接口的方法?

实现接口的来首先要从接口继承下来。

实现该接口:

class CFoo : public IFoo {

   void Func1() { /* ... */ }

   void Func2(int nCount) { /* ... */ }

};

调用:

首先要引入接口的定义。

创建一个指向对象的指针!!这只是为了方便而说的。实际上是错误的。COM中没有对象的指针。只有指向接口的指针。由于VC++调用内部虚拟函数是用了VTBL技术。即建立一个指针表,表中的指针指向成员函数。所以,指向接口的指针实质就是一个指向指针的指针。

将指针指向对象,那么意思实际上就是说,将指针指向对象的接口的简称。

所以,我们可以将指针指向对象的任意一个接口。最后都达到了将指针指向一个对象的目的。

用DELPHI语法写,更清晰易懂。

var pFoo:IFoo;

pFoo:=CFoo.Create;

//实现接口的函数

pFoo.Func1()

COM接口的实现。

COM定义了大量的接口及相对应的IID。

CLSID (class identifier GUID) (identifier:标识)

IID (interface identifier GUID)

GUID:是一个16个字节长的结构。能有3.4的10的38次方的组合。相当与宇宙中原子总数的平方根。所以,永远都用不完的。尽量不要拷贝它。

使用 GUIDGEN.EXE 来生成。

例如 IUnknown

IID of "00000000-0000-0000-c000-000000000046"

任何一个COM对象都包含一个IUNKNOWN接口。所有的接口都是从它这里派生的。

IUnknown 接口有三个函数:

HRESULT QueryInterface(REFIID riid, void **ppvObject);

ULONG AddRef();

ULONG Release();

简要功能介绍:

QueryInterface:用来查询riid对应的接口是否存在。结果在输出参数中。

AddRef:在对象的使用期限内增加引用记数。当对象第一次被创建时或者其他的用户将一个指针指向该对象时,调用该函数,内部记数将增加1。

Release:当用户不再使用的时候,调用它。最后一次调用时,记数变为0,对象将释放自己。

所以,前面的CLASS的定义

class IFoo {

   virtual void Func1(void) = 0;

   virtual void Func2(int nCount) = 0;

};

应该被改写为:COM对应的定义方式:

interface IFoo : IUnknown {

virtual HRESULT STDMETHODCALLTYPE Func1(void) = 0;

virtual HRESULT STDMETHODCALLTYPE Func2(int nCount) = 0;

};

用宏替换以后:

interface IFoo : IUnknown {

STDMETHOD Func1(void) PURE;

STDMETHOD Func2(int nCount) PURE;

};

创建OBJECT的实例,通过接口的指针引用对象(不能简单的说是:获取指向对象的指针)

IFoo *pFoo = NULL;

HRESULT hr = CoCreateInstance(CLSID_Foo, NULL, CLSCTX_ALL,

               IID_IFoo, (void **)&pFoo);

if (SUCCEEDED(hr)) {

   pFoo->Func1();   // Call methods.

   pFoo->Func2(5);

   pFoo->Release();   // MUST release interface when done.

}

一个实际例子:

     

IUnknown.  

IFoo

Ifoo2 

(IUNKNOWN接口有三个函数)

上边的接口是公共保留接口,左边的是自己定义的接口,都派生自IUNKNOWN。

QueryInterface的作用,获取同一个对象的另外一个接口。

IFoo *pFoo = NULL;

HRESULT hr = CoCreateInstance(CLSID_Foo2, NULL, CLSCTX_ALL,

               IID_IFoo, (void **)&pFoo);

if (SUCCEEDED(hr)) {

   pFoo->Func1();   // call IFoo::Func1

   IFoo2 *pFoo2 = NULL;

   hr = pFoo->QueryInterface(IID_IFoo2, (void **)&pFoo2);

   if (SUCCEEDED(hr)) {

      int inoutval = 5;

      pFoo2->Func3(&inoutval);   // IFoo2::Func3

      pFoo2->Release();

   }

   pFoo->Release();

}

IclassFactory的概念:

我们不能让COM对象自己创建自己的实例。要通过服务器。服务器则通过建立一个产生COM对象的工厂:类厂。用IclassFactory来产生很多新的OBJECT。但是,IclassFactory本身也是一个OBJECT。

 

IDL文件的目的:

达到跨语言实现。它以OSF(Open Software Foundation)的DCE RPC(Distributed Computing Environment Remote Procedure Call) IDL为基础,对它进行了扩展。

[object, uuid(3AB1D289-2145-4a33-9A98-9635C3518CD7)] //uuid和GUID是一个概念。

interface IFoo:Iunkonown

HRESULT Func2([in] long * p);

}

在VC中,实际上MFC也支持COM,但是,建议用ATL开发COM。应为它更简单,更纯净,更高级。ATL技术代表着COM技术的精华,提供了建立COM应用的核心构架,大大节省了手工代码量。所以我们从ATL实例开始了解COM技术。

三、COM应用

1、  OLE

2、  ATUOMATION

3、  ACTIVEX

4、 ATL

四、COM实际例子

一、建立一个服务器

1、  利用 MICROSOFT VISUALSTATIO 建立一个ATL PROJECT WIZARD 。选择默认的DLL。

2、  建立后,保存为mycomservice,REBUILD(编译)。

3、  右键调出 NEW ATL OBJECT 。

4、  选择默认的SIAMPLE,然后NEXT。

5、  输入名字为:First表示第一个接口。

6、  取默认值双接口。(DUAL)

7、  确定后,系统自动生成接口Ifirst和类Cfirst。

类实现,还没有代码。

8、  右键添加方法Methd1 

[in] long mPara ,[out,retval] long newPara

9、  右键添加属性 Ppty1

10、              在类定义中的PUBLIC部分增加成员变量定义: long m_x; 注意要将变量放到与方法和属性在同一个代码段。

11、              增加一些功能。比如增1,代码是:

       m_x=mPara;

*newPara=m_x+1;

12、              新定义一个自定义接口。(通过右键添加一个新的ATL OBJECT)

13、              在新的接口 Second上添加新的方法Methd2

14、              定义新的方法的内容:system("dir|more");

15、              服务器完成定义。

16、              所有的代码:

IDL文件:

// mycomservice.idl : IDL source for mycomservice.dll

//

// This file will be processed by the MIDL tool to

// produce the type library (mycomservice.tlb) and marshalling code.

import "oaidl.idl";

import "ocidl.idl";

       [

              object,

              uuid(913EFDEE-3FD8-4F66-852E-57D95490A196),

              dual,

              helpstring("IFirst Interface"),

              pointer_default(unique)

       ]

       interface IFirst : IDispatch

       {                                

              [propget, id(2), helpstring("property Ppty1")] HRESULT Ppty1([out, retval] long *pVal);

              [propput, id(2), helpstring("property Ppty1")] HRESULT Ppty1([in] long newVal);

              [id(3), helpstring("method Methd1")] HRESULT Methd1([in] long mPara,[out ,retval] long * newPara);

       };

       [

              object,

              uuid(ADD28210-06E1-4FF7-BC76-FF559ED7254A),

      

              helpstring("ISecond Interface"),

              pointer_default(unique)

       ]

       interface ISecond : IUnknown

       {

              [helpstring("method Methd2")] HRESULT Methd2();

       };

[

       uuid(7C025B97-09F8-4BB9-9951-2B8AFBB377EB),

       version(1.0),

       helpstring("mycomservice 1.0 Type Library")

]

library MYCOMSERVICELib

{

       importlib("stdole32.tlb");

       importlib("stdole2.tlb");

       [

              uuid(2BF62644-5257-414C-911C-8DBFACEFDBCC),

              helpstring("First Class")

       ]

       coclass First

       {

              [default] interface IFirst;

       };

       [

              uuid(7CBE299E-0965-4504-B4EB-06F841B7EF0F),

              helpstring("Second Class")

       ]

       coclass Second

       {

              [default] interface ISecond;

       };

};

FIRST类定义:

// First.h : Declaration of the CFirst

#ifndef __FIRST_H_

#define __FIRST_H_

#include "resource.h"       // main symbols

/////////////////////////////////////////////////////////////////////////////

// CFirst

class ATL_NO_VTABLE CFirst :

       public CComObjectRootEx<CComSingleThreadModel>,

       public CComCoClass<CFirst, &CLSID_First>,

       public IDispatchImpl<IFirst, &IID_IFirst, &LIBID_MYCOMSERVICELib>

{

public:

      

       CFirst()

       {

       }

DECLARE_REGISTRY_RESOURCEID(IDR_FIRST)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CFirst)

       COM_INTERFACE_ENTRY(IFirst)

       COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

// IFirst

public:

       long m_x;

       long m_p;

       STDMETHOD(Methd1)(/*[in]*/ long mPara,/*[out ,retval]*/ long * newPara);

       STDMETHOD(get_Ppty1)(/*[out, retval]*/ long *pVal);

       STDMETHOD(put_Ppty1)(/*[in]*/ long newVal);

      

};

#endif //__FIRST_H_

FIRST类的实现:

// First.cpp : Implementation of CFirst

#include "stdafx.h"

#include "Mycomservice.h"

#include "First.h"

/////////////////////////////////////////////////////////////////////////////

// CFirst

STDMETHODIMP CFirst::get_Ppty1(long *pVal)

{

       // TODO: Add your implementation code here

       *pVal =m_p;

       return S_OK;

}

STDMETHODIMP CFirst::put_Ppty1(long newVal)

{

       // TODO: Add your implementation code here

m_p=newVal;

       return S_OK;

}

STDMETHODIMP CFirst::Methd1(long mPara, long *newPara)

{

       // TODO: Add your implementation code here

       m_x=mPara;

       *newPara=m_x+1;

       return S_OK;

}

SECOND类定义:

// Second.h : Declaration of the CSecond

#ifndef __SECOND_H_

#define __SECOND_H_

#include "resource.h"       // main symbols

/////////////////////////////////////////////////////////////////////////////

// CSecond

class ATL_NO_VTABLE CSecond :

       public CComObjectRootEx<CComSingleThreadModel>,

       public CComCoClass<CSecond, &CLSID_Second>,

       public ISecond

{

public:

       CSecond()

       {

       }

DECLARE_REGISTRY_RESOURCEID(IDR_SECOND)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSecond)

       COM_INTERFACE_ENTRY(ISecond)

END_COM_MAP()

// ISecond

public:

       STDMETHOD(Methd2)();

};

#endif //__SECOND_H_

Second类的实现

// Second.cpp : Implementation of CSecond

#include "stdafx.h"

#include "Mycomservice.h"

#include "Second.h"

/////////////////////////////////////////////////////////////////////////////

// CSecond

 

STDMETHODIMP CSecond::Methd2()

{

       // TODO: Add your implementation code here

       //system("dir|more");

       MessageBox(NULL,"???hello????","",0);

       return S_OK;

}

二、建立一个客户

1、  建立一个基于对话框的EXE文件,名字是:mycomclient。

2、  在StdAfx.h头文件中加入引入代码:

#import "..\mycomservice\mycomservice.tlb" no_namespace named_guids

编译,将自动增加新的文件(External Dependencies)。

3、  建立一个按钮和对应的函数。

4、  在函数中写代码。

5、  首先采用传统的方法。

6、  在对话框的公共部分:

IUnknown * pUnk;

 HRESULT hr;    

 IFirst    *pFirst;     

 ISecond   *pSecond;      

 CString   s;

7、  在对话框初始化时:

        HRESULT hr;    

       hr=CoInitialize(NULL);

        if FAILED(hr) // SUCCEEDED    

        AfxMessageBox("INITE Failed!!");

8、  第一个BUTTON的事件。

/*

       //方法1:直接将指针指到要使用的接口,创建COM对象

       hr=CoCreateInstance

       (CLSID_First,//或者clsid

       NULL,

       //CLSCTX_LOCAL_SERVER,

       CLSCTX_INPROC_SERVER,      //这是从MSDN中查到的唯一正确的用法

       IID_IFirst,

       (LPVOID* ) &pFirst //首先指向该接口,这是一个基本接口,可以代表该对象

       )                              ;     

       if (S_OK!=hr)

       AfxMessageBox("创建并初始化COM接口失败!!");

       else

       AfxMessageBox("创建并初始化COM接口成功!!");

       */                        

       /*

               //调通!!

               pFirst->put_Ppty1(7);

               long p                  ;

               pFirst->get_Ppty1(&p);

               s.Format("the car's fuel is %d ",p);

               AfxMessageBox(s);                  

       */

      

       //方法2:      接口间查询!

              hr=CoCreateInstance

                      (CLSID_Second,//或者clsid

                      NULL,         

                      CLSCTX_INPROC_SERVER,   

                      IID_IUnknown,

                      (LPVOID* ) &pFirst

//首先指向该接口,这是一个基本接口,可以代表该对象

                      )                            ;     

               if (S_OK!=hr)

                      AfxMessageBox("获取IKNOWN接口失败!!!");

               else

                      AfxMessageBox("获取IKNOWN接口成功!!");

               

               hr=pFirst->QueryInterface(IID_ISecond, (LPVOID *) &pSecond);              

               

               if SUCCEEDED(hr)

                      AfxMessageBox("query seond interface succefully!!");

               else

                      AfxMessageBox("query seond interface Failed!!");

                

               pSecond->Methd2();

                            

               //CoUninitialize();                     

9、  第二个BUTTON准备

//用到了灵敏指针

    IFirstPtr pFirst;

       pFirst.CreateInstance(CLSID_First);

      

       pFirst->put_Ppty1(15);

       long p;

       pFirst->get_Ppty1(&p);

       s.Format("the car fuel level is %d",p);

       MessageBox(s);       

通过DELPHI实现这些在VC下编写的接口

首先引入库。

Project/import library

implementation

 uses MYCOMSERVICELib_TLB,comobj;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);

var x:ISecond;

begin

 x:=CoSecond.Create;

 x.Methd2;

end;

procedure TForm1.Button2Click(Sender: TObject);

var

y:variant;

z:IFirst;

L:Longint;

S:shortint;

begin

y:=createoleobject('MYCOMSERVICE.First');

//y:=createoleobject('TSecond.Second');   //自动化不支持这个接口

y.ppty1:=5;

L:=y.ppty1;

S:=shortint(L);

showmessage(inttostr(S));

(*

z:=CoFirst.Create;

//z.Ppty1:=5;

z.Set_Ppty1(5);

showmessage(inttostr(z.Get_Ppty1));

*)

end;

分享到:
评论

相关推荐

    深入学习com高级编程 深入学习com高级编程

    通过深入学习COM高级编程,你可以更好地理解和利用这一强大的技术,无论是开发桌面应用程序、构建分布式系统,还是与其他语言的组件集成,COM都是不可或缺的工具。理解并熟练运用上述知识点,将有助于提升你的编程...

    数据库及其相关技术实例

    在这个"数据库及其相关技术实例"中,我们深入探讨了多种与数据库交互的技术,包括ADO(ActiveX Data Objects)和ODBC(Open Database Connectivity)。这些技术在IT行业中扮演着至关重要的角色,特别是在数据驱动的...

    VisualC++数据库编程技术与实例沈炜著3

    《Visual C++数据库编程技术与实例》是一本深入探讨如何使用Microsoft Visual C++进行数据库编程的专业书籍,由沈炜著。这本书旨在帮助开发者理解和掌握在C++环境下与数据库交互的各种技术和方法,尤其针对Visual ...

    COM技术学习的最好书籍C++源码实例讲解

    本资源《COM技术学习的最好书籍C++源码实例讲解》是针对COM技术的深度学习资料,通过C++语言和丰富的源码实例来阐述COM的核心概念和实践应用。 首先,COM的基础概念包括组件、接口、实例和代理/ stub。组件是COM的...

    MFC技术内幕 精典实例

    《MFC技术内幕 精典实例》是一本专为MFC初学者设计的教程,旨在深入剖析MFC(Microsoft Foundation Classes)库的核心概念和技术,通过丰富的实例来帮助读者掌握这一强大的Windows应用程序开发框架。MFC是微软为C++...

    Visual C++高级编程技术与实例

    《Visual C++高级编程技术与实例》是一本深入探讨Visual C++编程的书籍,它旨在帮助读者掌握更复杂的编程技巧并解决实际问题。通过实际的示例,书中的内容不仅涵盖了基本的C++语言特性,还涉及了MFC(Microsoft ...

    DELPHI接口技术开发实例解析

    通过学习和实践这些DELPHI接口技术开发实例,你可以提升你的Delphi编程技能,更好地理解和利用接口技术来构建高效、可维护的软件系统。同时,阅读《DELPHI接口技术开发实例解析.pdf》这本书将为你提供更深入的理论...

    wpf技术开发编程实例

    在"wpf技术开发编程实例"中,我们将深入探讨如何利用这些功能来构建高效的应用程序。 首先,让我们了解WPF的基本架构。WPF的核心是XAML(eXtensible Application Markup Language),这是一种XML标记语言,用于声明...

    ASP编程技术与综合实例演练

    在"ASP编程技术与综合实例演练"中,我们将深入探讨ASP的核心概念和实践技巧。 1. **基础概念**:ASP包含服务器端脚本、组件、对象模型等元素。服务器端脚本是ASP的核心,VBScript或JScript是默认的脚本语言,它们在...

    ASP网络编程技术与实例

    在"ASP网络编程技术与实例"这个主题中,我们将深入探讨ASP的基础概念、核心组件、以及如何通过实际案例来应用这些技术。 1. **基础概念** - **服务器端脚本**:ASP脚本在服务器上执行,而非在用户的浏览器中,生成...

    Delphi网络应用开发技术与实例

    《Delphi网络应用开发技术与实例》是一本深入探讨如何使用Delphi进行网络应用程序开发的专业教程。这本书通过详细的章节划分,覆盖了从基础概念到高级技术的各个方面,旨在帮助开发者熟练掌握Delphi在网络编程中的...

    Asp编程技术与综合实例演练(PDF)

    在这个"ASP编程技术与综合实例演练"的PDF文档中,读者可以期待学习到以下关键知识点: 1. **ASP基础**:了解ASP的基本架构,包括如何在服务器上运行ASP页面,以及ASP的主要组成部分,如脚本语言(如VBScript或...

    杨素行 模拟电子技术基础简明教程第三版 仿真实例

    《杨素行 模拟电子技术基础简明教程第三版 仿真实例》是一本针对电子技术初学者和爱好者的专业教程,特别强调了利用Multisim软件进行模拟电子技术的仿真学习。这本书的核心内容涵盖了模拟电子电路的基础知识,以及...

    Tangram,七巧板实例

    通过深入学习和实践Tangram,开发者可以更好地理解和掌握COM技术,为自己的软件开发带来更多的创新和可能性。而“Tangram”这个压缩包中的文件,无疑为我们提供了宝贵的参考资料,供我们进一步探索和研究。

    com好书合集 com本质论 COM原理与应用COM技术内幕 深入解析ATL

    COM,Component Object Model,是微软提出的一种组件对象模型,它是一种接口标准,允许不同软件组件之间进行交互...通过深入学习,开发者能够更好地驾驭Windows平台上的组件开发,为软件工程带来更大的灵活性和复用性。

    Visual C++高级编程技术与实例源代码

    《Visual C++高级编程技术与实例源代码》是一份针对有志于深入学习和实践Visual C++编程的开发者的重要资源。这份资料不仅涵盖了基础概念,更深入探讨了Visual C++的高级特性,旨在帮助读者从初级阶段提升至精通水平...

    《COM编程精彩实例》配套代码

    在《COM编程精彩实例》这本书中,作者深入浅出地介绍了COM技术,并提供了丰富的实践案例。这本书的配套代码是为了帮助读者更好地理解和应用书中的理论知识,下面将对这些知识点进行详细解释。 1. **COM基本概念**:...

    精通Verilog HDL:IC设计核心技术实例详解part3(total4)

    本书从实际应用的角度详细地向读者介绍了Verilog HDL语言的使用,并利用实例深入剖析了Verilog HDL语法在实际应用中的要点,结构清晰,内容丰富。  全书共分为9章。前7章分别介绍了设计方法概论,Verilog HDL的语法...

    Com组件实例

    COM(Component Object Model)组件对象模型是微软提出的一种软件组件标准,它允许不同编程语言编写的组件之间进行交互。...通过学习这个实例,开发者可以更好地理解和应用COM技术,提高软件开发的效率和可维护性。

    vc++ 开发实例源码

    为了深入学习,你需要: 1. 打开每个实例,阅读源代码,理解其结构和逻辑。 2. 查看项目配置文件,了解如何在VC++环境中设置和编译项目。 3. 阅读README文档,获取实例背景和步骤说明。 4. 运行程序并观察结果,...

Global site tag (gtag.js) - Google Analytics