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%sn%sn%";,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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 VC++6.0 MFC 应用程序,演示如何使用 MFC 实现串口通信: 1. 创建一个 MFC 对话框应用程序。 2. 在 CMyDialog 类的头文件中添加以下成员变量: ```c++ HANDLE m_hComm; OVERLAPPED m_osRead; OVERLAPPED m_osWrite; ``` 3. 在 OnInitDialog 函数中初始化串口: ```c++ CMyDialog::OnInitDialog() { CDialog::OnInitDialog(); // 初始化串口 m_hComm = CreateFile(_T("COM1"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (m_hComm == INVALID_HANDLE_VALUE) { MessageBox(_T("无法打开串口"), _T("错误"), MB_OK); return TRUE; } SetupComm(m_hComm, 1024, 1024); DCB dcb; GetCommState(m_hComm, &dcb); dcb.BaudRate = 9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; SetCommState(m_hComm, &dcb); PurgeComm(m_hComm, PURGE_TXCLEAR | PURGE_RXCLEAR); // 初始化读写事件 m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); return TRUE; } ``` 4. 在 OnOK 函数中关闭串口: ```c++ CMyDialog::OnOK() { CloseHandle(m_osRead.hEvent); CloseHandle(m_osWrite.hEvent); CloseHandle(m_hComm); CDialog::OnOK(); } ``` 5. 实现一个函数来读取串口数据: ```c++ void CMyDialog::ReadFromPort() { char buf[1024]; DWORD dwRead; if (!ReadFile(m_hComm, buf, 1024, &dwRead, &m_osRead)) { if (GetLastError() != ERROR_IO_PENDING) { // 读取失败 return; } } WaitForSingleObject(m_osRead.hEvent, INFINITE); if (!GetOverlappedResult(m_hComm, &m_osRead, &dwRead, TRUE)) { // 获取结果失败 return; } // 处理读取到的数据 buf[dwRead] = '\0'; AfxMessageBox(buf); } ``` 6. 实现一个函数来写入串口数据: ```c++ void CMyDialog::WriteToPort(LPCTSTR lpBuf) { DWORD dwWritten; if (!WriteFile(m_hComm, lpBuf, _tcslen(lpBuf), &dwWritten, &m_osWrite)) { if (GetLastError() != ERROR_IO_PENDING) { // 写入失败 return; } } WaitForSingleObject(m_osWrite.hEvent, INFINITE); if (!GetOverlappedResult(m_hComm, &m_osWrite, &dwWritten, TRUE)) { // 获取结果失败 return; } // 写入成功 } ``` 7. 在需要读取或写入串口数据的地方调用上述函数即可。例如,在按钮点击事件中读取串口数据: ```c++ void CMyDialog::OnButtonRead() { ReadFromPort(); } ``` 注意,以上代码只是一个简单的示例,实际应用中还需要进行错误处理和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值