COM初探(一)

来源:互联网 发布:淘宝首页热点链接 编辑:程序博客网 时间:2024/04/30 19:05

COM初探(一)

(一)目标
本文实现了一个简单完整的COM例子程序,希望对初学者有所帮助和启发。程序完全依靠c++进行编码,没有使用到IDL文件,为了便于理解,也没有利用COM机制来生成对象。程序功能是得到当前的北京时间。

(二)预备
建立vc console application,选择MFC support

(三)接口文件Interface.h
以下是接口ITimeBeijing的定义,它从IUnknown继承,具有方法GetHour, GetMinute和GetSecond。

#pragma once
#include <unknwn.h> // 根接口IUnknown的定义

// 使用工具GuidGen生成下面的GUID
// {3EF3D0F2-148B-4684-83AB-BAD7D62912A1}
static const GUID IID_ITimeBeijing =
{ 0x3ef3d0f2, 0x148b, 0x4684, { 0x83, 0xab, 0xba, 0xd7, 0xd6, 0x29, 0x12, 0xa1 } };


interface ITimeBeijing : public IUnknown //接口ITimeBeijing,获取当前的北京时间
{
public:
 virtual int GetHour() = 0; //获取小时
 virtual int GetMinute() = 0; //获取分钟
 virtual int GetSecond() = 0; //获取秒
};

(四)类MyTimeBeijing的定义
类MyTimeBeijing从ITimeBeijing接口继承,并实现其所有接口函数,同时它也必须提供根接口IUnknown的接口函数实现。

class MyTimeBeijing : public ITimeBeijing  //实现了接口的类MyTimeBeijing
{
public:
 MyTimeBeijing();
 ~MyTimeBeijing();

private:
 ULONG m_cRef; //引用计数
 
public://以下实现接口

 //IUnknown接口
 STDMETHOD(QueryInterface)(REFIID riid, void **ppv);//接口查询
 STDMETHOD_(ULONG, AddRef)();//增加一个引用
 STDMETHOD_(ULONG, Release)();//减少一个引用
 
 //ITimeBeijing接口
 int GetHour();
 int GetMinute();
 int GetSecond();

};

(五)类MyTimeBeijing的实现

构造析构函数用于对象初始化和清理工作。
MyTimeBeijing::MyTimeBeijing()
{
 printf("Constructor called.../n");
 m_cRef = 0;
}

MyTimeBeijing::~MyTimeBeijing()
{
 printf("Destructor called.../n");
}

以下是对IUnknown的实现:
STDMETHODIMP MyTimeBeijing::QueryInterface(REFIID riid, void **ppv)
{
 printf("QueryInterface called.../n");
 if(riid == IID_ITimeBeijing) //判断接口类型
  *ppv = static_cast<ITimeBeijing*>(this);
 else if(riid == IID_IUnknown)
  *ppv = static_cast<IUnknown*>(this);
 else
 {
  *ppv = 0;
  return E_NOINTERFACE;
 }
 
 reinterpret_cast<IUnknown*>(*ppv)->AddRef(); //进行计数
 return S_OK;
}

STDMETHODIMP_(ULONG) MyTimeBeijing::AddRef()
{
 printf("AddRef called.../n");
 return ++m_cRef;
}

STDMETHODIMP_(ULONG) MyTimeBeijing::Release()
{
 printf("Release called.../n");
 ULONG res = --m_cRef; // 用临时变量把修改后的引用计数值缓存起来,
                         // 因为在对象已经销毁后再引用这个对象的数据将是非法的
 if(res == 0)
  delete this;
 
 return res;
}

以下是对ITimeBeijing的实现:
int MyTimeBeijing::GetHour()
{
 m_Time = CTime::GetCurrentTime();
 
 return m_Time.GetHour();
}

int MyTimeBeijing::GetMinute()
{
 m_Time = CTime::GetCurrentTime();

 return m_Time.GetMinute();
}

int MyTimeBeijing::GetSecond()
{
 m_Time = CTime::GetCurrentTime();

 return m_Time.GetSecond();
}

(六)测试程序
以下是一个简单的测试。这里,为了方便初学者理解,生成对象时使用new来代替COM机制,实际上不应该使用new,而应该利用COM的机制来得到对象的接口。

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
 ITimeBeijing * pTimeBeijing = NULL;//声明接口
 IUnknown * pUnknown = NULL;
 
 //生成对象(这里使用new来代替COM机制,为了方便初学者理解,实际上不应该使用new
 //而应该利用COM的机制来得到对象的接口
 pUnknown = (IUnknown *)new MyTimeBeijing;//获得对象IUnknown接口

 if(pUnknown)//查询接口ITimeBeijing
 {
  pUnknown->QueryInterface(IID_ITimeBeijing, (void**)&pTimeBeijing);
 }

 if(pTimeBeijing)//调用接口方法
 {
  printf("当前时间为:%d : %d : %d/n",
   pTimeBeijing->GetHour(), pTimeBeijing->GetMinute(),
   pTimeBeijing->GetSecond());
 }

 pTimeBeijing->Release();//释放接口

 system("pause");
 return 0;
}

(七)运行结果
  Constructor called...
  QueryInterface called...
  AddRef called...
  当前时间为:10 : 57 : 44
  Release called...
  Destructor called...
  请按任意键继续 . . .