用户登录  |  用户注册
首 页商业源码原创产品编程论坛
当前位置:PB创新网文章中心编程技巧Visual C++

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

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-03-16 20:29:08

首先应当明确,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();}STDMETHODIMPCTimeLogServer::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("# # # # # # # # # # # # # # # # # "));fprintf(m_logfile,_T("开始于:%s"),(LPCTSTR)TimeStamp.Format("%Y年%m月%d日%H:%M %S"));fprintf(m_logfile,_T(""));}}//然后在析构函数中关闭文件CTimeLogServer::~CTimeLogServer(){::AfxOleUnlockApp();if(m_logfile){CTime TimeStamp = CTime::GetCurrentTime();fprintf(m_logfile,_T(""));fprintf(m_logfile,_T("结束于:%s"),(LPCTSTR)TimeStamp.Format("%Y年%m月%d日%H:%M %S"));        fprintf(m_logfile,_T(""));fprintf(m_logfile,_T("# # # # # # # # # # # # # # # # #"));fclose(m_logfile);}}

3. 实现接口ITimeLog方法

//实现接口ITimeLog方法STDMETHODIMPCTimeLogServer::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,"%s%s%",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();

Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
PB创新网ourmis.com】Copyright © 2000-2009 . All Rights Reserved .
页面执行时间:23,062.50000 毫秒
Email:ourmis@126.com QQ:2322888 蜀ICP备05006790号