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

 

在VC++6.0中用MFC进行COM编程
2000-03-21· 杨宁·vchelp

首先应当明确,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: Add your specialized code here and/or call the base class
 ::AfxOleUnlockApp();	
	return CWinApp::ExitInstance();
}

  第二节 客户程序

  使用COM组件服务器的客户程序关键步骤是:初始化COM库,创建组件对象并获取IUnknown接口指针,查询接口并使用,释放组件.

 #include "ITimeLogServer.h"
 //初始化COM库,对组件实例化
	HRESULT hResult;
 IUnknown* pIUnknown;
	hResult = ::CoInitialize(NULL);
	if(FAILED(hResult))
	{
		::AfxMessageBox("不能初始化COM库!");
		return FALSE;
	}
	
 //创建组件实例
 pIUnknown = NULL;
	hResult = ::CoCreateInstance(CLSID_TimeLogServer,NULL,
		CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&pIUnknown);
	if(FAILED(hResult))
	{
		pIUnknown = NULL;
		::AfxMessageBox("不能创建TimeLog对象!");
		return FALSE;
	}
 //查询接口并使用
 if(pIUnknown!=NULL)
		{
			ITimeLog* pITimeLog;
			HResult=pIUnknown->QueryInterface(IID_ITimeLog,(void**)&pITimeLog);
			if(FAILED(hResult))
			{
				::AfxMessageBox("不能获取接口ITimeLog!");
				pIUnknown->Release();
				return;
			}
			BSTR bstrLogText;
			bstrLogText = m_logtext.AllocSysString();
			CString text((LPCWSTR)bstrLogText);
			::AfxMessageBox(text);
						
			if(FAILED(pITimeLog->OutputLog(&bstrLogText)))
			{
				::AfxMessageBox("日志输出出错!");
				pITimeLog->Release();
				return;
			}
			pITimeLog->Release();
			::AfxMessageBox("日志已经写入!");
		}
 //释放组件
 pIUnknown->Release();
 pIUnknown = NULL;
::CoUninitialize();
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
VC++编程指南(中文版),不错的一本电子书。啥也不说了,直接看内容预览: 第一课 Windows编程和面向对象技术   1.1 Windows发展历史   1.2 Windows操作系统特点   1.3 Windows应用程序设计的特点   1.4 Windows应用程序的开发工具   1.5 面向对象和Windows编程 第二课 使用Visual C++ 5.0   2.1 Visual C++可视化集成开发环境   2.2 创建、组织文件、工程和工作区   2.3 WIN32开发   2.4 MFC编程   2.5 移植C Windows程序到MFC   2.6 Visual C++5.0新特性 第三课 窗口、菜单与消息框   3.1 编写第一个窗口程序   3.2 AppWizard所创建的文件   3.3 编译和链接Hello程序   3.4 应用程序执行机制   3.5几种窗口类型   3.6 使用菜单   3.7 更新命令用户接口(UI)消息   3.8 快捷菜单 第四课 工具条和状态栏   4.1 工具条的可视化设计   4.2 工具条的编程技术   4.3 状态栏的设计与实现 第五课 对话框   5.1对话框和控件的基本概念   5.2 对话框模板的设计   5.3 对话框类的设计   5.4 非模态对话框   5.5 标签式对话框   5.6 公用对话框   5.7 小结 第六课 控件 6.1 传统控件   6.2 新型Win32控件   6.3 控件的技术总结   6.4 在非对话框窗口中使用控件   6.5 如何设计新的控件   6.6 小结 第七课 文档视结构   7.1 文档/视图概念   7.2 文档视结构程序实例   7.3 让文档视结构程序支持卷滚   7.4 定制串行化   7.5 不使用串行化的文档视结构程序   7.6 小 结 第八课 多文档界面MDI   8.1多文档界面窗口   8.2图形设备接口(GDI)   8.3 绘图程序   8.4访问当前活动视图和活动文档   8.5分隔视图   8.6打印和打印预览   8.7支持多个文档类型的文档视结构程序   8.8防止应用程序运行时创建空白窗口   8.9小结 第九课 创建用户模块   9.1用户模块   9.2静态连接库   9.3创建动态库   9.4小结 第十课 数据库编程   10.1 数据库的基本概念   10.2 ODBC基本概念   10.3 MFC的ODBC类简介   10.4 CDatabase类   10.5 CRecordset类   10.6 CRecordView类   10.7 编写Enroll数据库应用例程   10.8 DAO和DAO类   10.9 自动注册DSN和创建表   10.10 小结 第十一课 多媒体编程   11.1 调色板   11.2位图   11.3依赖于设备的位图(DDB)   1.4与设备无关的位图(DIB)   11.5动画控件   11.6媒体控制接口(MCI).   11,7小结  第十二章 多线程与串行通信   12.1 多任务、进程和线程   12.2 线程的同步   12.3 串行通信与重叠I/O   12.4 一个通信演示程序   12.5 小结
MFC(Microsoft Foundation Class)是一种面向对象的框架,用于开发Windows图形用户界面应用程序。VC 6.0是Visual C++ 6.0的简称,是一种集成开发环境(IDE),用于开发Windows应用程序。串口编程是指对计算机的串行接口进行编程,用来实现与外部设备的数据交互。 在VC 6.0 MFC进行串口编程,可以通过以下步骤来实现: 1. 包含相关的头文件和库文件:在程序代码中使用#include和#pragma等指令来引用串口编程所需的头文件和库文件。 2. 打开串口:使用相关的函数调用打开要使用的串口。这可以通过调用相关MFC类的成员函数来实现,如CSerialPort类的Open函数。 3. 配置串口参数:使用串口的属性和参数,如波特率、数据位、停止位等进行配置。可以通过调用相关MFC类的成员函数来实现,如CSerialPort类的SetBaudRate和SetDataBits函数。 4. 发送和接收数据:可以通过调用相关MFC类的成员函数,如CSerialPort的Write和Read函数来发送和接收数据。 5. 关闭串口:在程序结束时,需要调用相关函数关闭串口。这可以通过调用相关MFC类的成员函数来实现,如CSerialPort类的Close函数。 需要注意的是,在进行串口编程时,需要考虑到串口的可靠性、错误处理以及通信协议等方面的问题,以确保数据的正确传输。此外,可以使用MFC提供的一些辅助类和函数来简化串口编程的相关操作,如CSerialPort类和相关函数。 总之,VC 6.0 MFC串口编程需要通过调用相关的类和函数来实现串口的打开、配置、数据发送和接收等操作,以实现与外部设备的数据交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxyxl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值