天天看點

IDL接口描述語言和COM接口COM元件  接口描述語言 - IDL(Interface Definition Language )COM接口  COM元件IDL實作COM元件代碼示例

接口描述語言(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

import "oaidl.idl";
import "ocidl.idl";
import "objidl.idl";

[
	object,
	uuid(CFF0849D-61E2-4ED1-9DC9-0E43E2FBDE25)
]

interface IMath :IUnknown
{
	HRESULT Add(long nAdd1, long nAdd2, long* pnAdd) = 0;
	HRESULT Sub(long nSub1, long nSub2, long* pnSub) = 0;
};
[
	uuid(39B16755-783D-49B1-93E2-0FCA9F66CC2D)
]
coclass Math
{
	interface IMath;
};
           

CimpMath.h

#pragma once
#include "math_h.h"

class ClmpMath:public IMath
{
public:
	ClmpMath();
	~ClmpMath();
//IUnKnuwn
public:
	STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppiObject);
	STDMETHOD_(ULONG, AddRef)();
	STDMETHOD_(ULONG, Release)();
//IMath
public:
	STDMETHOD(Add)(long nAdd1, long nAdd2, long* pnAdd);
	STDMETHOD(Sub)(long nSub1, long nSub2, long* pnSub);
//
public:
	LONG m_nRef;
};
           

CimpMath.cpp

#include "stdafx.h"
#include "ClmpMath.h"


ClmpMath::ClmpMath()
{
	m_nRef = 0;
}


ClmpMath::~ClmpMath()
{
}

STDMETHODIMP ClmpMath::QueryInterface(
	REFIID iid, LPVOID* ppiObject)
{
	if (iid == IID_IUnknown)
	{
		*ppiObject = static_cast<IUnknown*>(this);
	}
	else if (iid == IID_IMath)
	{
		*ppiObject = static_cast<IMath*>(this);
	}
	else
	{
		*ppiObject = NULL;
		return E_NOINTERFACE;
	}
	AddRef();
	return S_OK;
}

STDMETHODIMP_(ULONG)ClmpMath:: AddRef()
{
	InterlockedIncrement(&m_nRef);
	return m_nRef;
}
STDMETHODIMP_(ULONG)ClmpMath::Release()
{
	InterlockedDecrement(&m_nRef);
	if (m_nRef == 0)
	{
		delete this;
	}
	return m_nRef;
}

STDMETHODIMP ClmpMath::Add(
	long nAdd1, long nAdd2, long* pnAdd)
{
	if (pnAdd == NULL)
	{
		return E_POINTER;
	}
	*pnAdd = nAdd1 + nAdd2;
	return S_OK;
}
STDMETHODIMP ClmpMath::Sub(
	long nSub1, long nSub2, long* pnSub)
{

	if (pnSub == NULL)
	{
		return E_POINTER;
	}
	*pnSub = nSub1 + nSub2;
	return S_OK;
}
           

元件建立函數

IUnknown* CreateInstanceEx(CLSID clsid)
{//判斷元件的CLSID
	if (clsid == CLSID_Math)
	{
		//建立對象
		ClmpMath* pMath = new ClmpMath;
		//擷取接口
		IUnknown* piUnknown = NULL;
		pMath->QueryInterface(IID_IUnknown,
			(LPVOID*)&piUnknown);
		//傳回接口
		return piUnknown;
	}

	return FALSE;
}