COM样例(四)

——客户端代码

    本文为此系列文章的最后一篇,罗列客户端的源代码。客户端使用MFC实现,其中的框架类CMainFrame实现了IModuleSite、IErrorReport和ICompanyInfo,而另一个窗口包装类CTaskManager实现ITaskManager,并由CMainFrame聚合它以表现出CMainFrame实现了ITaskManager。由于代码较长,本篇只罗列CMainFrame::OnCreate和CMainFrame的定义,其中实现了获取部门组件的实例(通过COM的组件类别功能进行记录,而非通过注册表),并进行管理。
    如果欲查看本样例的所有代码,可于文末下载。而本样例的可执行文件也请于文末下载。由于本样例只是我很早以前编的一个程序精简修改而成,代码中可能有不少幼稚的地方,我现在也没兴致再仔细修改,只是大致修整了一下,还请见谅。


CMainFrame的定义

#include "NewStatusBar.h"

class CMainFrame : public CFrameWnd
{
// MFC定义宏
    DECLARE_DYNCREATE( CMainFrame )
    DECLARE_MESSAGE_MAP()
    DECLARE_INTERFACE_MAP()

// 辅助结构
private:
    struct TEMPSTRUCT
    {
        HWND      m_hWnd;
        HMENU     m_hMenu;
        IModule  *m_pModule;
        CLSID     m_CLSID;
        TEMPSTRUCT() : m_hWnd( NULL ), m_hMenu( NULL ), m_pModule( NULL )
        {
        // 什么都不做
        }
        ~TEMPSTRUCT()
        {
            SafeRelease( m_pModule );
        }
    };

// 构造、析构
public:
    CMainFrame();
    ~CMainFrame();
 
// 操作
public:
    void UpdateErrorState()  // 更新状态条上的错误标志以表示指示最新错误的发生
    {
        ASSERT_VALID( this );

        if( m_wndStatusBar.GetSafeHwnd() )
            m_wndStatusBar.Invalidate();
    }

// 辅助函数
protected:
    // 根据菜单项ID确定是否是基本框架的菜单命令
    BOOL BeMenuOfBase( DWORD nID ) const;

// 成员变量
protected:
    CNewStatusBar  m_wndStatusBar;
    CToolBar       m_wndToolBar;
    DWORD          m_Selected;
    long           m_OldViewID;
    IUnknown      *m_pTaskManager;

    CTypedPtrList< CPtrList, TEMPSTRUCT* > m_ModuleList;

// 重载
protected:
    void GetMessageString( UINT nID, CString &rMessage ) const;
    BOOL OnCommand( WPARAM wParam, LPARAM lParam );

// 窗口消息
protected:
    afx_msg int  OnCreate( LPCREATESTRUCT lpCreateStruct );
    afx_msg void OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized );
    afx_msg void OnSetFocus( CWnd *pOldWnd );
    afx_msg void OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu );
    afx_msg void OnInitMenu( CMenu *pMenu );
    afx_msg BOOL OnEraseBkgnd( CDC *pDC );
    afx_msg void OnClose();

// 菜单消息
protected:
    void OnModule( UINT nID );
    void OnUpdateModule( CCmdUI *pCmdUI );

// 自定消息
protected:
    afx_msg LRESULT OnAllTaskTerminated( WPARAM, LPARAM );

// 接口映射
public:
// IModuleSite
    BEGIN_INTERFACE_PART( ModuleSite, IModuleSite )
        INIT_INTERFACE_PART( CMainFrame, ModuleSite )
        STDMETHOD(ChangeModule)( REFCLSID clsid,
                                 WCHAR *pModuleName,
                                 ULONG command,
                                 ULONG param );
        STDMETHOD(GetFrameWindow)( HWND *pHwnd );
    END_INTERFACE_PART_STATIC( ModuleSite )

// IErrorReport
    BEGIN_INTERFACE_PART( ErrorReport, IErrorReport )
        INIT_INTERFACE_PART( CMainFrame, ErrorReport )
        STDMETHOD(ReportSoftError)( WCHAR *fileName,
                                    ULONG row,
                                    WCHAR *errorString );
        STDMETHOD(ReportHardError)( WCHAR *fileName,
                                    ULONG row,
                                    WCHAR *errorString );
    END_INTERFACE_PART_STATIC( ErrorReport )

// ICompanyInfo
    BEGIN_INTERFACE_PART( CompanyInfo, ICompanyInfo )
        INIT_INTERFACE_PART( CMainFrame, CompanyInfo )
        STDMETHOD(GetDataServerInfo)( WCHAR **pLoaction,
                                      WCHAR **pServer,
                                      WCHAR **pPassword );
    END_INTERFACE_PART_STATIC( CompanyInfo )
};


CMainFrame::OnCreate代码

int CMainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
    if( CFrameWnd::OnCreate( lpCreateStruct ) == -1 )
        return -1;

// 创建基本工具条及状态条
    EnableDocking( CBRS_ALIGN_ANY );

    if( !m_wndToolBar.CreateEx( this,
                                TBSTYLE_FLAT,
                                WS_CHILD | WS_VISIBLE | CBRS_TOP |
                                    CBRS_GRIPPER | CBRS_TOOLTIPS |
                                    CBRS_FLYBY | CBRS_SIZE_DYNAMIC,
                                CRect( 0, 0, 0, 0 ) ) )
        WriteSoftErrorLog( __LINE__,
                           __WFILE__,
                           IDS_MAINFRM_CREATETOOLBAR );
    else
    {
        m_wndToolBar.EnableDocking( CBRS_ALIGN_ANY );
        DockControlBar( &m_wndToolBar );
    }

    if( !m_wndStatusBar.Create( this ) ||
        !m_wndStatusBar.SetIndicators( indicators,
                                       sizeof( indicators ) / sizeof( UINT ) ) )
    {
        WriteSoftErrorLog( __LINE__,
                           __WFILE__,
                           IDS_MAINFRM_CREATESTATUSBAR );
        return -1;
    }
    else
    {
        CCmdTarget *pTarget = m_wndStatusBar.Initial();
        if( !pTarget )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_MAINFRM_CREATESTATUSBAR );
            return -1;
        }
        ASSERT_VALID( pTarget );

    // 设置任务管理器的指针以使得CMainFrame聚合CTaskManager
        pTarget->m_pOuterUnknown = GetControllingUnknown();
        m_pTaskManager = reinterpret_cast< IUnknown* >( &pTarget->m_xInnerUnknown );
        ASSERT( m_pTaskManager );
    }

// 创建组件类别管理器并获得模块CLSID枚举器
    IEnumCLSID      *pEnum = NULL;
    ICatInformation *pCat  = NULL;
    CATID tempCATID[1] = { CATID_Example };

    if( FAILED( CoCreateInstance( CLSID_StdComponentCategoriesMgr,
                                  NULL,
                                  CLSCTX_INPROC_SERVER,
                                  IID_ICatInformation,
                                  reinterpret_cast< void** >( &pCat ) ) ) ||
        FAILED( pCat->EnumClassesOfCategories( 1, tempCATID, 0, NULL, &pEnum ) ) )
    {
        MessageBox( L"致命错误!系统即将退出。", g_SysCaption );
        WriteHardErrorLog( __LINE__,
                           __WFILE__,
                           IDS_KILLINGERROR );
        SafeRelease( pCat );
        SafeRelease( pEnum );
        return -1;
    }
    pCat->Release();

// 枚举每个模块信息
    g_theApp.BeginWaitCursor();

    CLSID        clsid;
    CStringW     temp;
    TEMPSTRUCT  *pStruct = NULL;
    IModuleUI   *pUI     = NULL;
    IMenuUpdate *pMenuUp = NULL;
    long         index   = -1;
    IModuleSite *pSite   = static_cast< IModuleSite* >(
                               GetInterface( &IID_IModuleSite ) );

    pSite->AddRef();
    while( pEnum->Next( 1, &clsid, NULL ) == S_OK )
    {
        ++index;
        pStruct = new TEMPSTRUCT;
        if( !pStruct )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_OUTOFMEMORY );
            continue;
        }

    // 创建模块对象
        if( FAILED( CoCreateInstance( clsid,
                                      NULL,
                                      CLSCTX_INPROC_SERVER,
                                      IID_IModule,
                                      reinterpret_cast< void** >(
                                          &pStruct->m_pModule ) ) ) )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_MAINFRM_CREATEMODULE );
            delete pStruct;
            continue;
        }
        pStruct->m_CLSID = clsid;

    // 初始化模块
        if( FAILED( pStruct->m_pModule->InitialModule( pSite,
                                                       IDC_MODULE_VIEW +
                                                           index –
                                                           1 ) ) )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_MAINFRM_CREATEMODULE );
            delete pStruct;
            continue;
        }

    // 获取模块窗口
        if( FAILED( pStruct->m_pModule->QueryInterface(
                        IID_IModuleUI,
                        reinterpret_cast< void** >( &pUI ) ) ) )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_MAINFRM_GETMODULEWND );
            delete pStruct;
            continue;
        }
        if( FAILED( pUI->GetMainWindow( &pStruct->m_hWnd ) ) || !pStruct->m_hWnd )
        {
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_MAINFRM_GETMODULEWND );
            pUI->Release();
            delete pStruct;
            continue;
        }
        pUI->Release();

        {
        // 修改窗口风格,确保模块窗口具有WS_EX_CLIENTEDGE风格
            if( !::SetWindowLong( pStruct->m_hWnd,
                                  GWL_EXSTYLE,
                                  ::GetWindowLong( pStruct->m_hWnd,
                                                   GWL_EXSTYLE ) |
                                       WS_EX_CLIENTEDGE ) )
                WriteSoftErrorLog( __LINE__,
                                   __WFILE__,
                                   IDS_SETWINDOWSTYLE );
        }

    // 隐藏模块窗口
        ::ShowWindow( pStruct->m_hWnd, SW_HIDE );

    // 获取模块的菜单句柄,并插入到MainFrame
        if( SUCCEEDED( pStruct->m_pModule->QueryInterface(
                           IID_IMenuUpdate,
                           reinterpret_cast< void** >( &pMenuUp ) ) ) )
        {
        // 模块提供了菜单,获取菜单句柄
            if( FAILED( pMenuUp->GetMenu( &pStruct->m_hMenu ) ) )
                WriteSoftErrorLog( __LINE__,
                                   __WFILE__,
                                   IDS_MAINFRM_CREATEMODULEMENU );
            pMenuUp->Release();
        }

        m_ModuleList.AddTail( pStruct );
    }
    pSite->Release();
    pEnum->Release();

// 一个模块都不激活
    m_Selected = static_cast< ULONG >( -1 );

    ULONG count = m_ModuleList.GetCount();
    if( count )
    {
    // 获取模块的图标,并将其插入到模块工具条和菜单中
        m_wndToolBar.SetSizes( CSize( 23, 22 ), CSize( 16, 15 ) );
        if( !m_wndToolBar.SetButtons( NULL, count ) )
            WriteSoftErrorLog( __LINE__,
                               __WFILE__,
                               IDS_CREATETOOLBARBUTTON );
        else
        {
        // 将图标画到位图中
            CBitmap bitmap;
            CDC *pScreen = CDC::FromHandle( ::GetDC( NULL ) );
            CDC sdc;
            if( !bitmap.CreateCompatibleBitmap( pScreen,
                                                ICONWIDTH * count,
                                                ICONHEIGHT ) ||
                !sdc.CreateCompatibleDC( pScreen ) )
            {
                WriteSoftErrorLog( __LINE__,
                                   __WFILE__,
                                   L"创建缓冲位图失败!" );
                return 0;
            }
            sdc.SelectObject( &bitmap );
            sdc.FillSolidRect( 0,
                               0,
                               ICONWIDTH * count,
                               ICONHEIGHT,
                               RGB( 0xC0, 0xC0, 0xC0 ) );
            HICON     hIcon = NULL;
            ULONG     i     = 0;
            POSITION  pos   = m_ModuleList.GetHeadPosition();
            CMenu    *pMenu = GetMenu()->GetSubMenu(0)->GetSubMenu(0);
            ASSERT_VALID( pMenu );

        // 清空原来的占位符
            while( pMenu->DeleteMenu( 0, MF_BYPOSITION ) );

            while( pos )
            {
                pStruct = m_ModuleList.GetNext( pos );
                ASSERT( pStruct );

            // 将图标画到位图上
                if( SUCCEEDED( pStruct->m_pModule->GetIcon( &hIcon ) ) )
                    ::DrawIconEx( sdc.GetSafeHdc(),
                                  i * ICONWIDTH,
                                  0,
                                  hIcon,
                                  ICONWIDTH,
                                  ICONHEIGHT,
                                  0,
                                  NULL,
                                  DI_NORMAL );
                else
                    WriteSoftErrorLog( __LINE__,
                                       __WFILE__,
                                       IDS_MAINFRM_GETMODULEICON );

            // 添加菜单
                {
                // 获取模块的名字
                    WCHAR *io = NULL;
                    if( FAILED( pStruct->m_pModule->GetName( &io ) ) )
                        WriteSoftErrorLog( __LINE__,
                                           __WFILE__,
                                           IDS_MAINFRM_GETMODULENAME );
                    else
                    {
                        if( !pMenu->AppendMenu( MF_STRING, ID_MODULE + i, io ) )
                            WriteSoftErrorLog( __LINE__,
                                               __WFILE__,
                                               IDS_MAINFRM_CREATEMODULEMENU );
                        ::CoTaskMemFree( io );
                    }
                }

            // 设置工具条上的按钮
                m_wndToolBar.SetButtonInfo( i, ID_MODULE + i, TBBS_BUTTON, i );

                i++;
            }

        // 将位图设置到工具条中
            if( !m_wndToolBar.SetBitmap(
                    static_cast< HBITMAP >( bitmap.Detach() ) ) )
                WriteSoftErrorLog( __LINE__,
                                   __WFILE__,
                                   IDS_SETTOOLBARBITMAP );
        }
    }

    g_theApp.EndWaitCursor();

    return 0;
}

 

COM样例编译完成文件                        COM样例源码

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐