用MFC進(jìn)行COM編程- -
[轉(zhuǎn)載]VC++6.0中用MFC進(jìn)行COM編程
說(shuō)明 很有用的帖子 盡管有點(diǎn)老
首先應(yīng)當(dāng)明確,MFC中是通過(guò)嵌套類而不是多重繼承來(lái)實(shí)現(xiàn)COM接口的,,通過(guò)接口映射機(jī)制將接口和實(shí)現(xiàn)該接口的嵌套類關(guān)聯(lián)起來(lái),;MFC中提供一套簡(jiǎn)明的宏來(lái)實(shí)現(xiàn)嵌套類的定義.其次,MFC通過(guò)CCmdTarget類實(shí)現(xiàn)了IUnknown接口,。 本文首先描述創(chuàng)建一個(gè)COM服務(wù)器的步驟和核心代碼.然后說(shuō)明客戶程序關(guān)鍵代碼。
此COM服務(wù)器實(shí)現(xiàn)一個(gè)TimeLogServer組件,,為簡(jiǎn)明起見(jiàn),,此組件只有一個(gè)接口ITimeLog,通過(guò)ITimeLog的方法OutputLog可以將日志文本輸出至日志文件,。
創(chuàng)建一個(gè)MFC DLL工程,,選擇支持Automation(當(dāng)然本程序不一定是自動(dòng)化服務(wù)器,在這里這樣做好處在于自動(dòng)實(shí)現(xiàn)了幾個(gè)必要的輸出函數(shù)如DllGetClassObject,,DllRegisterServer等,,否則要自己寫(xiě))
第一節(jié) COM服務(wù)器
一. 聲明組件和接口
1.寫(xiě)一個(gè)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.寫(xiě)一個(gè)ITimeLogServer.h,,在ITimeLogServer.h文件中聲明組件和接口
//ITimeLogServer.h #include ";GUIDs.h",; //接口ITimeLog的聲明 DECLARE_INTERFACE_(ITimeLog,,IUnknown) { STDMETHOD(OutputLog)(BSTR* varLogText)PURE; },;
說(shuō)明:
1.宏DEFINE_GUID將組件和接口的progid與GUID相關(guān)聯(lián).可以用guidgen.exe工具產(chǎn)生,。
2.宏DECLARE_INTERFACE_聲明接口;該宏第一個(gè)參數(shù)為接口名,,第二個(gè)參數(shù)為該接口的基類.聲明沒(méi)有基類的接口用DECLARE_INTERFACE宏,。
3.宏STDMETHOD聲明接口中的方法.此方法的返回值為HRESULT.PURE被解釋為";=0",;,,即此方法為純虛函數(shù).當(dāng)方法的返回值不是HRESULT時(shí),用宏STDMETHOD_(返回類型,,函數(shù)名)(參數(shù))PURE,;
二.聲明組件類CTimeLogServer和實(shí)現(xiàn)接口的嵌套類
在ClassWizard中添加新類CTimeLogServer,其基類選擇為CCmdTarget.修改其頭文件TimeLogServer1.h,加上#include ",;ITimeLogServer.h",;;同時(shí)在類聲明體中加上
//聲明實(shí)現(xiàn)ITimelog接口的嵌套類 BEGIN_INTERFACE_PART(TimeLog,,ITimeLog)//自動(dòng)聲明IUnknown接口的三個(gè)方法 STDMETHOD(OutputLog)(BSTR* varLogText),; END_INTERFACE_PART(TimeLog) //聲明接口映射 DECLARE_INTERFACE_MAP() //聲明類廠 DECLARE_OLECREATE(CTimeLogServer)
三.實(shí)現(xiàn)類廠和接口映射
在CTimeLogServer的實(shí)現(xiàn)文件中寫(xiě)入:
//實(shí)現(xiàn)類廠 IMPLEMENT_OLECREATE(CTimeLogServer,",;TimeLogServer",;, 0xa433e701,, 0xe45e,, 0x11d3, 0x97,, 0xb5,, 0x52, 0x54,, 0x4c,, 0xba, 0x7f,, 0x28),; //映射接口到相應(yīng)的嵌套類 BEGIN_INTERFACE_MAP(CTimeLogServer,CCmdTarget) INTERFACE_PART(CTimeLogServer,,IID_ITimeLog,,TimeLog) END_INTERFACE_MAP()
四.在組件的構(gòu)造和析構(gòu)函數(shù)中對(duì)全局對(duì)象計(jì)數(shù)
CTimeLogServer::CTimeLogServer() { ::AfxOleLockApp(); }
CTimeLogServer::~CTimeLogServer() { ::AfxOleUnlockApp(),; }
五.為嵌套類實(shí)現(xiàn)IUnknown接口
//為嵌套類而實(shí)現(xiàn)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),; }
說(shuō)明:雖然CCmdTarget類已經(jīng)實(shí)現(xiàn)了IUnknown接口,,但是還必須通過(guò)上述代碼來(lái)將嵌套類的IUnknown映射到CCmdTarget支持的IUnknown接口.METHOD_PROLOGUEH宏的兩個(gè)參數(shù)分別是實(shí)現(xiàn)組件對(duì)象的類和實(shí)現(xiàn)接口的嵌套類,。
六.實(shí)現(xiàn)ItimeLog接口的方法OutputLog
注意本組件的功能是往日志文件中輸入日志.
1. 在組件類中添加一個(gè)文件指針:
// Attributes public: protected: FILE* m_logfile;
2. 初始化和退出
首先在CTimeLogServer的構(gòu)造函數(shù)中進(jìn)行一些初始化:
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(",;開(kāi)始于:%s",;),(LPCTSTR)TimeStamp.Format(",;%Y年%m月%d日%H:%M %S",;)); fprintf(m_logfile,,_T(",;n";)),; } } //然后在析構(gòu)函數(shù)中關(guān)閉文件 CTimeLogServer::~CTimeLogServer() { ::AfxOleUnlockApp(); if(m_logfile) { CTime TimeStamp = CTime::GetCurrentTime(),; fprintf(m_logfile,,_T(";n",;)),; fprintf(m_logfile,_T(",;結(jié)束于:%s",;),(LPCTSTR)TimeStamp.Format(";%Y年%m月%d日%H:%M %S",;)),; fprintf(m_logfile,_T(",;n",;)); fprintf(m_logfile,,_T(",;# # # # # # # # # # # # # # # # #n";)),; fclose(m_logfile),; } }
3. 實(shí)現(xiàn)接口ITimeLog方法
//實(shí)現(xiàn)接口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%sn%sn%",;,,NowTime,LogText),; return NOERROR,; } else { AfxMessageBox(";沒(méi)有日志文件!",;),; return S_FALSE; } }
七.完善組件服務(wù)器
在應(yīng)用對(duì)象CTimeLogServerApp的 實(shí)現(xiàn)文件中,,處理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(); }
第二節(jié) 客戶程序
使用COM組件服務(wù)器的客戶程序關(guān)鍵步驟是:初始化COM庫(kù),,創(chuàng)建組件對(duì)象并獲取IUnknown接口指針,,查詢接口并使用,,釋放組件。
#include ",;ITimeLogServer.h",; //初始化COM庫(kù),對(duì)組件實(shí)例化 HRESULT hResult,; IUnknown* pIUnknown,; hResult = ::CoInitialize(NULL); if(FAILED(hResult)) { ::AfxMessageBox(",;不能初始化COM庫(kù)!",;); return FALSE,; }
//創(chuàng)建組件實(shí)例 pIUnknown = NULL,; hResult = ::CoCreateInstance(CLSID_TimeLogServer,NULL,, CLSCTX_INPROC_SERVER,,IID_IUnknown,(void**)&,;pIUnknown),; if(FAILED(hResult)) { pIUnknown = NULL; ::AfxMessageBox(",;不能創(chuàng)建TimeLog對(duì)象!",;); 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(",;日志輸出出錯(cuò)!",;); pITimeLog->,;Release(),; return; } pITimeLog->,;Release(),; ::AfxMessageBox(";日志已經(jīng)寫(xiě)入!",;),; } //釋放組件 pIUnknown->;Release(),; pIUnknown = NULL,; ::CoUninitialize();
|