首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

COM 應用程式框架 1.2 設計方案:基於 WTL+ATL 的 MDI 架構

     編輯:關於VC++

設計說明

本框架以 COM 技術重新設計標準 Windows MDI 應用程式,核心封裝於 AIFrame.dll,所有功能透過 COM 介面操作。提供 MDI 與 SDI 兩種框架,本文著重 MDI 設計。


技術選型:WTL+ATL vs MFC+ATL

組合特點結論
MFC+ATL存在 MFC 封裝層函式呼叫,大型專案效能較慢不採用
WTL+ATL模板程式碼編譯後無額外呼叫層,效能接近純 Win32 SDK採用此方案

通用設計規範

資料視圖介面

所有加入框架的視圖必須繼承純虛介面 IDataView (父介面 IDispatch)。

命令通知標準

NotifyCommand(UINT codeNotify, UINT cmdID, VARIANT_BOOL* bHandle);
  • codeNotify:通知代碼 (保留)
  • cmdID:選單/工具列按鈕命令 ID
  • bHandle:VARIANT_TRUE 繼續向下路由,VARIANT_FALSE 停止路由

COM MDI 應用程式框架架構

核心類別與介面

  • MDI 主視窗: CMDIFrame / IMDIFrame — 容器,管理子視窗、停靠視圖、工具列、選單,分發命令至作用中子視窗或視圖
  • MDI 子視窗: CMDIChildFrame / IMDIChildFrame — 擁有多個資料視圖,分發命令至作用中視圖
  • 子視窗集合: CMDIChildFrames / IMDIChildFrames — 管理所有子視窗、建立新子視窗

事件介面

// IMDIFrameEvents
OnQuit(VARIANT_BOOL* vbQuit)
NotifyCommand(UINT codeNotify, UINT cmdID, VARIANT_BOOL* bHandle)

// IMDIChildFrameEvents
NotifyCommand(UINT codeNotify, UINT cmdID, VARIANT_BOOL* bHandle)

命令路由機制

主視窗 → 子視窗 → 作用中視圖,每層 NotifyCommand 透過 bHandle 決定是否繼續向下傳遞。


客戶端實作範例 (MFC 調用框架)

專案設定

// stdafx.h
#include "..\inc\aiframeimpl.h"
// 某 .cpp
#include "..\inc\AiFrame_i.c"

資料視圖實作 (文字編輯視圖)

// TextView.h
class CTextView : public CEditView, public CDataViewImpl
{
    NC_BEGIN_MAP()
    // 視圖命令處理
    NC_END_MAP()
    virtual HRESULT STDMETHODCALLTYPE CreateWnd(HWND hWndParent);
};

// TextView.cpp
HRESULT STDMETHODCALLTYPE CTextView::CreateWnd(HWND hWndParent)
{
    CWnd* pWnd = (CWnd*)this;
    CWnd* wndParent = CWnd::FromHandle(hWndParent);
    CRect rect(0, 0, 100, 100);
    if (pWnd->Create(NULL, _T("MFC CEditView"),
        WS_HSCROLL|WS_VSCROLL|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_VISIBLE|ES_MULTILINE|ES_AUTOHSCROLL,
        rect, wndParent, 0))
    {
        m_pEdit = &GetEditCtrl();
        return S_OK;
    }
    return S_FALSE;
}

應用程式類別:命令處理與主視窗建立

class CFrameApp : public CWinApp, public CComObjectRootEx, public IDispEventImpl
{
    IMDIFrame* m_lpMdiFrame;

    BEGIN_SINK_MAP(CFrameApp)
        SINK_ENTRY_INFO(EventType, DIID__IMDIFrameEvents, DISPID_SHOW, OnQuit, &OnShowInfo1)
        SINK_ENTRY_INFO(EventType, DIID__IMDIFrameEvents, DISPID_SHOW2, NotifyCommand, &OnShowInfo3)
    END_SINK_MAP()

    NC_BEGIN_MAP()
        NC_COMMAND_ID_HANDLER(ID_FILE_NEW, FileNew)
        NC_COMMAND_ID_HANDLER(ID_FILE_EXIT, OnFileExit)
        NC_COMMAND_ID_HANDLER(ID_HELP_ABOUT, OnAbout)
        NC_COMMAND_ID_HANDLER(ID_HELP_WINDOWS, OnWindowWindows)
    NC_END_MAP()

    HRESULT CreateMain();
    void FileNew(UINT, UINT, VARIANT_BOOL*);
    // ... 其他處理函式 ...

    STDMETHODIMP OnQuit(VARIANT_BOOL* vbQuit) { return S_OK; }
};

建立主視窗與事件連接

HRESULT CFrameApp::CreateMain()
{
    CreateMDIStruct lpMDI = {0};
    HRESULT hr = CoCreateInstance(CLSID_MDIFrame, NULL, CLSCTX_ALL, IID_IMDIFrame, (VOID**)&m_lpMdiFrame);
    if (FAILED(hr)) return hr;

    lpMDI.cbSize = sizeof(CreateMDIStruct);
    lpMDI.lpszWindowName = L"Test COM MDIFrame";
    lpMDI.hMenu = LoadMenu(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
    hr = m_lpMdiFrame->CreateWnd(&lpMDI);
    m_lpMdiFrame->ShowMe(VARIANT_TRUE);
    hr = this->DispEventAdvise((IUnknown*)m_lpMdiFrame);  // 連接事件
    return hr;
}

處理「新增檔案」命令:建立子視窗

void CFrameApp::FileNew(UINT, UINT, VARIANT_BOOL*)
{
    IMDIChildFrames* lpFrames = NULL;
    IMDIChildFrame* lpChildFrame = NULL;
    HRESULT hr = m_lpMdiFrame->get_MDIChildFrames((IDispatch**)&lpFrames);
    if (FAILED(hr)) return;

    CTextView* lpTexView = new CTextView();
    lpFrames->CreateChildFrame((IDataView*)lpTexView, &lpChildFrame);
    lpChildFrame->put_Title(L"MFC TextView");
}

專案目錄結構

資料夾類型說明
AiFrame.dll框架核心程式碼
inc.h客戶端使用的公用標頭檔與設計類別
MFC_Test_AiFrame.exeMFC 調用範例
WTL_Test_AiFrame.exeWTL 調用範例
BinBin編譯輸出 .dll/.exe

下載資源

框架完整原始碼:https://www.vckbase.com/code/downcode.asp?id=2963

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved