转:IDL接口描述语言和COM接口COM组件

https://blog.csdn.net/rankun1/article/details/50850593

接口描述语言(Interface description language,缩写IDL

c++写的接口,只能c++和c识别,为了接口的通用性,让所有的语言都通用的定义使用接口
引入IDL,使用IDL定义接口以后,用MIDL编译为c++可用的接口定义

  接口描述语言 - IDL(Interface Definition Language )

   1 IDL和MIDL

     IDL - 定义接口的一种语言,与开发
       语言无关.
     MIDL.EXE - 可以将IDL语言定义接口,
       编译成C++语言的接口定义

   2 IDL的基础

IDL接口定义方式:
在项目中添加**.idl文件,在文件中:
1导入idl
      import "XXXX.idl"
2定义属性     
      [
        attribute
      ]
3定义接口
      interface A : interface_base
      {
      }
编译后生成三个文件
**_h.h 接口头文件
**_i.cpp 接口GUID
**_p.cpp 远程调用相关,代理层
   
    2.1 Import 导入IDL文件,相当于C++的
        #include
    2.2 使用"[]"定义区域,属性描述
      关键字,描述接口GUID等信息
       1) object - 后续是对象
       2) uuid - 定义对象GUID
       3) helpstring - 帮助信息
       4) version - 版本
       5) point_default - 后续对象
         中指针的默认使用方式
         比如: uniqune - 表示指针可以
           为空,但是不能修改
  
    2.3 对象定义
       1) 父接口是IUnknown接口      
       2) 在对象内添加函数,函数定义必须
       是返回 HRESULT.
       HRESULT是32位整数,返回函数是否
       执行成功,需要使用 SUCCESSED和
       FAILED宏来判断返回值.

COM接口  

按照COM规范定义的接口,即为COM接口

    1 COM接口的规范

1.1 IUnknown接口的等价性 -
判断两个接口相等,需要获取两个接口的IUnknown接口
判断IUnknown接口的地址是都相等。
1.2自反性
接口可以使用QueryInterface查询到自己
1.3 对称性
接口A可以查询到接口B,那么接口B也可以查询到接口A
1.4 传递性
接口A可以查询到接口B,接口B可以查询到接口C,那么接口A就可以查询到接口C
1.5 时间无关性
接口A在某个时间可以查询到接口B,那么在后续的任何时间中也可以查询到接口B

    2 接口的编写

2.1 定义IDL(编译后生成3个文件)
IDL文件项目属性有了 MIDL(将IDL定义的接口编译为c++语言)选项,其中Mktyplib compa...选项去掉,组件内部相关,不去掉IDL编译失败
*_i.c 接口ID定义   
*_h.h 接口头文件
*_p.c 接口代理层实现
2.2 实现接口
自定义实现类继承接口类,并实现相关函数,注意引入相关头文件(接口头文件和GUID定义文件)
自定义实现类中实现相关函数时必须使用STDMETHOD(无返回值)STDMETHOD_(有返回值)声明函数,STDMETHODIMP STDMETHODIMP_实现函数
2.3 实现接口的导出
实现全局接口创建函数
定义def文件中导出接口创建函数

COM组件

    1 COM接口和COM组件

      COM接口 - 函数集合
      COM组件 - 
从接口角度:COM组件是一个接口的集合
        从C++语言看:COM组件是一个类或多个类
从编程看:COM组件是一段可以执行的代码
      COM组件通过一个或多个COM接口展示自己的功能
    ---------
||----o IUnknown  接口
|组件|
||----o IMath   接口
||
---------

    2 组件的实现

2.1 定义类实现组件的功能
2.2 每个组件都具有一个GUID
一般宏定义为:CLSID_组件名称
2.3 在IDL中,定义组件
[
uuid(39B16755-783D-49B1-93E2-0FCA9F66CC2D)
]
coclass Math
{
interface IMath;
};
2.4 创建组件,并获取接口
创建时传入组件GUID,在查询接口时加入组件GUID的判断

IDL实现COM组件代码示例

math.idl

  1. import "oaidl.idl";  
  2. import "ocidl.idl";  
  3. import "objidl.idl";  
  4.   
  5. [  
  6.     object,  
  7.     uuid(CFF0849D-61E2-4ED1-9DC9-0E43E2FBDE25)  
  8. ]  
  9.   
  10. interface IMath :IUnknown  
  11. {  
  12.     HRESULT Add(long nAdd1, long nAdd2, long* pnAdd) = 0;  
  13.     HRESULT Sub(long nSub1, long nSub2, long* pnSub) = 0;  
  14. };  
  15. [  
  16.     uuid(39B16755-783D-49B1-93E2-0FCA9F66CC2D)  
  17. ]  
  18. coclass Math  
  19. {  
  20.     interface IMath;  
  21. };  


CimpMath.h

  1. #pragma once  
  2. #include "math_h.h"  
  3.   
  4. class ClmpMath:public IMath  
  5. {  
  6. public:  
  7.     ClmpMath();  
  8.     ~ClmpMath();  
  9. //IUnKnuwn  
  10. public:  
  11.     STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppiObject);  
  12.     STDMETHOD_(ULONG, AddRef)();  
  13.     STDMETHOD_(ULONG, Release)();  
  14. //IMath  
  15. public:  
  16.     STDMETHOD(Add)(long nAdd1, long nAdd2, long* pnAdd);  
  17.     STDMETHOD(Sub)(long nSub1, long nSub2, long* pnSub);  
  18. //  
  19. public:  
  20.     LONG m_nRef;  
  21. };  

CimpMath.cpp

  1. #include "stdafx.h"  
  2. #include "ClmpMath.h"  
  3.   
  4.   
  5. ClmpMath::ClmpMath()  
  6. {  
  7.     m_nRef = 0;  
  8. }  
  9.   
  10.   
  11. ClmpMath::~ClmpMath()  
  12. {  
  13. }  
  14.   
  15. STDMETHODIMP ClmpMath::QueryInterface(  
  16.     REFIID iid, LPVOID* ppiObject)  
  17. {  
  18.     if (iid == IID_IUnknown)  
  19.     {  
  20.         *ppiObject = static_cast<IUnknown*>(this);  
  21.     }  
  22.     else if (iid == IID_IMath)  
  23.     {  
  24.         *ppiObject = static_cast<IMath*>(this);  
  25.     }  
  26.     else  
  27.     {  
  28.         *ppiObject = NULL;  
  29.         return E_NOINTERFACE;  
  30.     }  
  31.     AddRef();  
  32.     return S_OK;  
  33. }  
  34.   
  35. STDMETHODIMP_(ULONG)ClmpMath:: AddRef()  
  36. {  
  37.     InterlockedIncrement(&m_nRef);  
  38.     return m_nRef;  
  39. }  
  40. STDMETHODIMP_(ULONG)ClmpMath::Release()  
  41. {  
  42.     InterlockedDecrement(&m_nRef);  
  43.     if (m_nRef == 0)  
  44.     {  
  45.         delete this;  
  46.     }  
  47.     return m_nRef;  
  48. }  
  49.   
  50. STDMETHODIMP ClmpMath::Add(  
  51.     long nAdd1, long nAdd2, long* pnAdd)  
  52. {  
  53.     if (pnAdd == NULL)  
  54.     {  
  55.         return E_POINTER;  
  56.     }  
  57.     *pnAdd = nAdd1 + nAdd2;  
  58.     return S_OK;  
  59. }  
  60. STDMETHODIMP ClmpMath::Sub(  
  61.     long nSub1, long nSub2, long* pnSub)  
  62. {  
  63.   
  64.     if (pnSub == NULL)  
  65.     {  
  66.         return E_POINTER;  
  67.     }  
  68.     *pnSub = nSub1 + nSub2;  
  69.     return S_OK;  
  70. }  

组件创建函数

  1. IUnknown* CreateInstanceEx(CLSID clsid)  
  2. {//判断组件的CLSID  
  3.     if (clsid == CLSID_Math)  
  4.     {  
  5.         //创建对象  
  6.         ClmpMath* pMath = new ClmpMath;  
  7.         //获取接口  
  8.         IUnknown* piUnknown = NULL;  
  9.         pMath->QueryInterface(IID_IUnknown,  
  10.             (LPVOID*)&piUnknown);  
  11.         //返回接口  
  12.         return NULL;  
  13.     }  
  14.   
  15.     return FALSE;  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值