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

    首先应当明确,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()
   
    {<pre name="code" class="cpp">   #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();

// 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值