程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> COM應用程序框架 1.2 設計方案 試驗A版

COM應用程序框架 1.2 設計方案 試驗A版

編輯:關於VC++

本文只介紹《COM應用程序框架》的主要設計部分,更多、更詳細的文檔信息請參見下 載文件包中的文檔和源代碼。

一、設計說明

《COM應用程序框架》是把標准的Microsoft Windows多文檔處理應用程序使用COM技術 來設計.所以針對多文檔處理應用程序的需求,不再多寫。如果您不了解請參見MSDN或者 是其它編程基礎方面的書籍。

《COM應用程序框架》分為兩種,一種是COM多文檔應用程序框架,第二種是單文檔應 用程序框架。在這裡我們只介紹多文檔應用程序,不介紹單文檔應用程序。

《COM應用程序框架》建立在一個單獨的AIFrame.DLL文件中,所有的功能都通過COM接 口進行操作.《COM應用程序框架》將使用如下兩種庫的組合進行設計,1.使用MFC+ATL組 合, 2.使用WTL+ATL組合,下面分別對這兩種組合的優點和缺點說明一下,最後選擇一種 最優組合。

1.使用MFC+ATL組合圖:

2.使用WTL+ATL組合圖:

從上面兩附圖中很容易看出,使用MFC+ATL組合開發COM應用程序框架,MFC存在一層函 數調用,代碼執行速度會慢一些。小程序可能看不出來,大程序也就明顯了。   如果 使用WTL+ATL組合開發COM應用程序框架,就不會多一層調用,代碼執行速度非常快,就像 是用Win32 SDK編寫代碼一樣沒有什麼區別,因為WTL是模板代碼,在編譯後不會存在一層 函數調用。所以《COM應用程序框架》將采用WTL+ATL組合進行設計,這可能是最佳方案。

二、通用設計

1.數據視圖

所謂數據視圖,就是添加到《COM應用程序框架》中每一個窗口,無論這個窗口是用做 什麼,還是什麼形狀的,統稱為數據視圖。

所有客戶端程序向《COM應用程序框架》添加的數據視圖必須從IDataView純虛接口繼 承下來,必須是.這樣《COM應用程序框架》才能工作正常。

數據視圖純虛接口:IDataView。父類是IDispatch。

2.命令的響應函數

函數名稱:NotifyCommand(UINT codeNotify, UINT cmdID, VARIANT_BOOL *bHandle);

參數:codeNotify - 通報代碼,現在沒有使用。

cmdID – 某個命令ID,可以是菜單也可以是工具格中的按鈕。

bHandle – 如果命令還繼續向下路徑設置為VARIANT_TRUE,不向下路徑設置為 VARIANT_FALSE.

三、《COM多文檔應用程序框架》設計

1.框架

《COM多文檔(MDI)應用程序框架》只有一個MDI主窗口,但是可以擁有N多MDI子窗口, 每個MDI子窗口可以擁有多個數據視圖,每一個數據視圖必須從IDataView接口繼承下來。

MDI主窗口框架類名:CMDIFrame,接口是IMDIFrame,是所有MDI子窗口、停靠數據視圖 、工具條、菜單的容器,並負責把命令分發給當前活動的MDI子窗口或者是數據視圖。MDI 子窗口框架類名:CMDIChildFrame,接口是IMDIChildFrame。可以擁有N多數據視圖,並把 命令分發給當前活動的數據視圖。

MDI子窗口框架集合類名:CMDIChildFrames,接口是IMDIChildFrames,用來管理所有 的MDI子窗口和創建DMI子窗口。

《COM多文檔應用程序框架》接口圖:

2.事件

MDIFrame事件  目前僅提供兩個事件。

OnQuit(VARIANT_BOOL *vbQuit)

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

IMDIChildFrame事件 目前僅提供一個事件。

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

3.命令路由

MDI主窗口框架、MDI子窗口框架事件類和數據視圖都擁有一個命令處理方法 NotifyCommand。《COM多文檔應用程序框架》就是通過NotifyCommand向客戶端發送命令 處理。

MDI主窗口事件首先接收到菜單或者是工具條命令,處理完必後返回或者是發送給MDI 子窗口框架事件處理,在MDI子窗口框架處理完必後返回或者是發送給讓當前活動的數據 視圖處理.完成後命令返回。

命令是否向下路由是有NotifyCommand方法的bHandle變量決定,設置為VARIANT_TRUE 命令向下路由,設置為VARIANT_FALSE命令不向下路由。

4.UML類圖

用COM設計的類比較長抓圖不太方便,UML圖、類的信息和函數成員請參見源代碼。

四、 客戶端設計

客戶端應用程序必須實現兩個功能塊,第一個是數據視圖,第二個是命令處理。

五、 項目文件夾說明 文件夾名稱 類型 說明 AiFrame .dll 《COM應用程序框架》全部代碼所在文件夾。 inc .h 《COM應用程序框架》客戶端使用的一些公用頭文件和已經設計的類。 MFC_Test_AiFrame .exe 使用MFC調用《COM應用程序框架》的實例 WTL_Test_AiFrame .exe 使用WTL調用《COM應用程序框架》的實例 Bin Bin 生成的.dll 和.exe文件存放的文件夾

六、講解使用MFC調用《COM應用程序框架》的實例

這個實例使用MFC庫調用《COM應用程序框架》建立起的一個簡單的文本程序。以方便 了解如何使用《COM應用程序框架》的流程和主要部分,和《COM應用程序框架》方便之處 。 使用MFC項目向導,建立一個對話框項目應用(項目名稱自己定義)假如是 MFC_Test_AiFrame項目。在stdafx.h文件加入。

#include "..\inc\aiframeimpl.h"

在某個 .cpp中加入

#include "..\inc\AiFrame_i.c"

向項目中添加一個文本編輯視圖類,如下圖.

新建立的類名是CTextView, 基類(Base class)是CeditView類。單擊完成按鈕。

打開TextView.h文件加入如下代碼:

CDataViewImp是IDataView數據視圖接口實現模板類。

class CTextView : public CEditView
      ,public CDataViewImpl
{
  ....
  NC_BEGIN_MAP()
    //在這裡加入您的視圖命令處理.
  NC_END_MAP()
  virtual HRESULT STDMETHODCALLTYPE CreateWnd(HWND hWndParent);...
}

打開TextView.cpp文件加入如下代碼: //必須有CreateWnd方法,有《COM應用 程序框架》調用。

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,
          ("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;
}

CxxxxxApp類中主要完成一個功能.繼承CNotifyObjectImpl對象,用來處理 《COM應用程序框架》發送來的命令.CNotifyObjectImpl類是InotifyObject接口的實現 模板類。建立主窗口和一個新建文件的子菜單響應該命令.

class CFrameApp : public CWinApp
        ,public CComObjectRootEx
        ,public IDispEventImpl
{
public:
  CFrameApp();
    IMDIFrame *m_lpMdiFrame;
    void WinMain();
  BEGIN_SINK_MAP(CFrameApp)
    //不使用 _ATL_FUNC_INFO結構 iFrmae 在調用事件的時候返回"沒有注冊 的庫"。這是為什麼?
    //SINK_ENTRY_EX(EventType, DIID__IMDIFrameEvents, 0x1, OnQuit)
    //SINK_ENTRY_EX(EventType, DIID__IMDIFrameEvents, 0x2, NotifyCommand)
    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 codeNotify, UINT cmdID, VARIANT_BOOL *bHandle);
    void OnFileExit(UINT codeNotify, UINT cmdID, VARIANT_BOOL *bHandle);
    void OnAbout(UINT codeNotify, UINT cmdID, VARIANT_BOOL *bHandle);
    void OnWindowWindows(UINT codeNotify, UINT cmdID, VARIANT_BOOL *bHandle);
    
  STDMETHODIMP OnQuit(VARIANT_BOOL *vbQuit)
  {
    //MessageBox(0, _T("Events.Quit"), _T(""), 0);
    return S_OK;
  }
// 重寫
  public:
  virtual BOOL InitInstance();
// 實現
  DECLARE_MESSAGE_MAP()
};
 
HRESULT CFrameApp::CreateMain()
{
  CreateMDIStruct lpMDI={0};
  HRESULT hr = 0;
  hr = CoCreateInstance(CLSID_MDIFrame, NULL, CLSCTX_ALL, IID_IMDIFrame, (VOID**)&m_lpMdiFrame);
  if (FAILED(hr))
  {
    ATLASSERT(0);
    return hr;
  }
  lpMDI.cbSize = sizeof(CreateMDIStruct);
  lpMDI.lParam = NULL;
  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);
  if (FAILED(hr))
  {
    ATLASSERT(0);
  }
  return hr;
}

處理新建文件菜單的命令:

void CFrameApp::FileNew(UINT codeNotify, UINT cmdID, VARIANT_BOOL *bHandle)
{
  IMDIChildFrames *lpFrames = NULL;
  IMDIChildFrame *lpChildFrame = NULL;
  HRESULT hr = 0;
  //從主窗口IMDIFrame接口引出IMDIChildFrames 集合.
  hr = m_lpMdiFrame->get_MDIChildFrames((IDispatch**)&lpFrames);
  if (FAILED(hr))
  {
    ATLASSERT(0);
  }
  //用IMDIChildFrames 集合建立一個mdi子窗口.lpChildFrame,反回子窗口接口類 .
  CTextView *lpTexView = NULL;
  lpTexView = new CTextView();
  lpFrames->CreateChildFrame((IDataView*)lpTexView, &lpChildFrame);
  //設置子窗口標題.
  lpChildFrame->put_Title(L"MFC TextView");
}

七、其它信息

下載COM應用程序框架:http://www.vckbase.com/code/downcode.asp?id=2963

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved