分享
 
 
 

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

王朝c/c++·作者佚名  2006-01-06
窄屏简体版  字體: |||超大  

首先应当明确,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();

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有