在VC++6.0中用MFC进行COM编程[1]

[入库:2005年8月18日] [更新:2007年3月25日]

本文简介:选择自 showman 的 blog

首先应当明确,mfc中是通过嵌套类而不是多重继承来实现com接口的,通过接口映射机制将接口和实现该接口的嵌套类关联起来;mfc中提供一套简明的宏来实现嵌套类的定义.其次,mfc通过ccmdtarget类实现了iunknown接口.

本文首先描述创建一个com服务器的步骤和核心代码.然后说明客户程序关键代码.

此com服务器实现一个timelogserver组件,为简明起见,此组件只有一个接口itimelog,通过itimelog的方法outputlog可以将日志文本输出至日志文件.

创建一个mfc dll工程,选择支持automation(当然本程序不一定是自动化服务器,在这里这样做好处在于自动实现了几个必要的输出函数如dllgetclassobject,dllregisterserver等,否则要自己写)

第一节 com服务器

一. 声明组件和接口

1.写一个guids.h,在guids.h中声明组件和接口的guid

//声明组件guid {a433e701-e45e-11d3-97b5-52544cba7f28}
//define_guid(clsid_timelogserver, 
//0xa433e701, 0xe45e, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28);
static const iid clsid_timelogserver = 
{0xa433e701, 0xe45e, 0x11d3, {0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28}};
// 声明接口guid{a433e702-e45e-11d3-97b5-52544cba7f28}
//define_guid(iid_itimelog,
//0xa433e702, 0xe45e, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28);
static const iid iid_itimelog = 
{0xa433e702, 0xe45e, 0x11d3, {0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28}};

2.写一个itimelogserver.h,在itimelogserver.h文件中声明组件和接口

//itimelogserver.h
#include "guids.h"
//接口itimelog的声明
declare_interface_(itimelog,iunknown)
{
  	stdmethod(outputlog)(bstr* varlogtext)pure;
};

说明:1.宏define_guid将组件和接口的progid与guid相关联.可以用guidgen.exe工具产生.

2.宏declare_interface_声明接口;该宏第一个参数为接口名,第二个参数为该接口的基类.声明没有基类的接口用declare_interface宏.

3.宏stdmethod声明接口中的方法.此方法的返回值为hresult.pure被解释为"=0",即此方法为纯虚函数.当方法的返回值不是hresult时,用宏stdmethod_(返回类型,函数名)(参数)pure;

二.声明组件类ctimelogserver和实现接口的嵌套类

在classwizard中添加新类ctimelogserver,其基类选择为ccmdtarget.修改其头文件timelogserver1.h,加上#include "itimelogserver.h";同时在类声明体中加上

//声明实现itimelog接口的嵌套类
	begin_interface_part(timelog,itimelog)//自动声明iunknown接口的三个方法
	  stdmethod(outputlog)(bstr* varlogtext);
	end_interface_part(timelog)
	//声明接口映射
	declare_interface_map()
	//声明类厂
	declare_olecreate(ctimelogserver)

三.实现类厂和接口映射

在ctimelogserver的实现文件中写入:

//实现类厂
implement_olecreate(ctimelogserver,"timelogserver",
           0xa433e701, 0xe45e, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0x4c, 0xba, 0x7f, 0x28);
//映射接口到相应的嵌套类
begin_interface_map(ctimelogserver,ccmdtarget)
  interface_part(ctimelogserver,iid_itimelog,timelog)
end_interface_map()
四.在组件的构造和析构函数中对全局对象计数
ctimelogserver::ctimelogserver()
{
	::afxolelockapp();
}

ctimelogserver::~ctimelogserver()
{
	::afxoleunlockapp();
}

五.为嵌套类实现iunknown接口

//为嵌套类而实现iunknown接口
stdmethodimp_(ulong)
ctimelogserver::xtimelog::addref()
{
	method_prologue(ctimelogserver,timelog)
	return pthis->externaladdref();
}

stdmethodimp_(ulong)
ctimelogserver::xtimelog::release()
{
	method_prologue(ctimelogserver,timelog)
	return pthis->externalrelease();
}

stdmethodimp
ctimelogserver::xtimelog::queryinterface(refiid riid,void**ppvobj)
{
	method_prologue(ctimelogserver,timelog)
	return pthis->externalqueryinterface(&riid,ppvobj);
}

说明:虽然ccmdtarget类已经实现了iunknown接口,但是还必须通过上述代码来将嵌套类的iunknown映射到ccmdtarget支持的iunknown接口.method_prologueh宏的两个参数分别是实现组件对象的类和实现接口的嵌套类.

六.实现itimelog接口的方法outputlog

注意本组件的功能是往日志文件中输入日志.

1. 在组件类中添加一个文件指针:

  // attributes
  public:
  protected:
	    file* m_logfile;

2. 初始化和退出

首先在ctimelogserver的构造函数中进行一些初始化:

ctimelogserver::ctimelogserver()
{
	::afxolelockapp();
	ctime timestamp = ctime::getcurrenttime();
	cstring filename;
	filename.format(_t("%s.log"),timestamp.format("%y%m%d"));
	m_logfile = fopen(filename,_t("a"));
	if(m_logfile)
	{
		fprintf(m_logfile,_t("# # # # # # # # # # # # # # # # # \n"));
		fprintf(m_logfile,_t("开始于:%s"),(lpctstr)timestamp.format("%y年%m月%d日%h:%m %s"));
		fprintf(m_logfile,_t("\n"));
	}
}
//然后在析构函数中关闭文件
ctimelogserver::~ctimelogserver()
{
	::afxoleunlockapp();
	if(m_logfile)
	{
		ctime timestamp = ctime::getcurrenttime();
		fprintf(m_logfile,_t("\n"));
		fprintf(m_logfile,_t("结束于:%s"),(lpctstr)timestamp.format("%y年%m月%d日%h:%m %s"));
        fprintf(m_logfile,_t("\n"));
		fprintf(m_logfile,_t("# # # # # # # # # # # # # # # # #\n"));
		fclose(m_logfile);
	}
}

3. 实现接口itimelog方法

//实现接口itimelog方法
stdmethodimp
ctimelogserver::xtimelog::outputlog(bstr* varlogtext)
{
	method_prologue(ctimelogserver,timelog)
	if(pthis->m_logfile)
	{
		ctime timestamp = ctime::getcurrenttime();
		cstring nowtime = timestamp.format("%y年%m月%d日%h:%m:%s");
		cstring logtext((lpcwstr)*varlogtext);
		fprintf(pthis->m_logfile,"\n%s\n%s\n%",nowtime,logtext);
		return noerror;
	}
	else
	{
		afxmessagebox("没有日志文件!");
		return s_false;
	}
}

七.完善组件服务器

在应用对象ctimelogserverapp的 实现文件中,处理instance()和exitinstance()

bool ctimelogserverapp::initinstance()
{
	::afxolelockapp();
	// register all ole server (factories) as running.  this enables the
	//  ole libraries to create objects from other applications.
	coleobjectfactory::registerall();

	return true;
}
int ctimelogserverapp::exitinstance() 
{
	// todo: a

本文关键:VC
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top