本框架以 COM 技術重新設計標準 Windows MDI 應用程式,核心封裝於 AIFrame.dll,所有功能透過 COM 介面操作。提供 MDI 與 SDI 兩種框架,本文著重 MDI 設計。
| 組合 | 特點 | 結論 |
|---|---|---|
| MFC+ATL | 存在 MFC 封裝層函式呼叫,大型專案效能較慢 | 不採用 |
| WTL+ATL | 模板程式碼編譯後無額外呼叫層,效能接近純 Win32 SDK | 採用此方案 |
所有加入框架的視圖必須繼承純虛介面 IDataView (父介面 IDispatch)。
NotifyCommand(UINT codeNotify, UINT cmdID, VARIANT_BOOL* bHandle);
codeNotify:通知代碼 (保留)cmdID:選單/工具列按鈕命令 IDbHandle:VARIANT_TRUE 繼續向下路由,VARIANT_FALSE 停止路由CMDIFrame / IMDIFrame — 容器,管理子視窗、停靠視圖、工具列、選單,分發命令至作用中子視窗或視圖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 決定是否繼續向下傳遞。
// 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 | .exe | MFC 調用範例 |
| WTL_Test_AiFrame | .exe | WTL 調用範例 |
| Bin | Bin | 編譯輸出 .dll/.exe |