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...
请按任意键继续 . . .