共用方式為


TN041: MFC/OLE1 移轉給 MFC OLE 2

注意事項注意事項

由於它第一次線上文件中包含尚未更新下列技術提示。如此一來,某些程序和主題可能已經過期或不正確。如需最新資訊,建議您先搜尋線上文件索引中有興趣的主題。

移轉與相關的一般問題

為 OLE 2 類別在 MFC 2.5 (和以上) 的設計目的是結構的要保留大部分的 OLE 1.0 支援 MFC 2.0 就地導入相同。 如此一來,許多相同的 OLE 類別 MFC 2.0 仍存在於這個版本的 MFC (COleDocumentCOleServerDocCOleClientItemCOleServerItem)。 此外,許多這些類別中的 Api 是完全相同。 不過,OLE 2 是從 OLE 1.0 大相逕庭,因此部分詳細資料已變更,您可以預期。 如果您熟悉 MFC 2.0 OLE1 支援,您就能夠在家裡使用 MFC 的 2.0 支援。

如果您是採用現有的 MFC/OLE1 應用程式,並且加入 OLE 2 功能,您應該要先閱讀這個注意事項。 這張便箋包含一些一般問題,可能會遇到移植到 MFC/OLE 2 您 OLE1 功能時,並接著討論同時連接兩個應用程式包含在 MFC 2.0 中發現的問題: MFC OLE 範例 OCLIENTHIERSVR

MFC 文件/檢視架構很重要,

如果您的應用程式不會使用 MFC 的文件/檢視架構,而您想要將 OLE 2 支援加入至您的應用程式,現在正是移至文件/檢視。 一旦您的應用程式正在使用的內建的架構和元件的 MFC MFC 的 OLE 2 類別的好處是只實現的。

實作的伺服器或容器,而不需使用 MFC 架構是可行的但不是建議使用。

使用 MFC 實作,而不是您自己的

"Canned 實作 「 MFC 類別,例如CToolBarCStatusBar,以及CScrollView有內建特殊大小寫的程式碼 OLE 2 支援。 因此,如果應用程式中,您可以使用這些類別會因所需的努力將放入這些讓它們 OLE 知道。 同樣地,也可用於 「 彙總-您-擁有 」 類別這裡基於上述目的,但我們並不建議。 如果您需要實作類似的功能,MFC 原始程式碼 (特別是在談到就地啟動),就會是極佳的參考,以因應某些 OLE 的更細微的點。

檢查的 MFC 範例程式碼

有許多的 MFC 範例含有 OLE 功能。 每個這些應用程式會實作 OLE 從不同角度:

  • HIERSVR 多半是用於做為伺服器應用程式使用。 它包含在 MFC 2.0,做為 MFC/OLE1 應用程式中和已移植到 MFC/OLE 2 並再延伸,讓它實作 OLE 2 許多 OLE 功能。

  • OCLIENT 這是一個獨立的容器應用程式中,用來示範許多 OLE 功能從容器的觀點來看。 移植而它太來從 MFC 2.0 中,然後再擴展支援許多更進階的 OLE 功能,例如自訂的剪貼簿格式與內嵌項目的連結。

  • DRAWCLI 這個應用程式實作 OLE 容器支援更像 OCLIENT 的話,不同之處在於它是在架構的現有物件導向繪圖程式中。 它會顯示如何實作 OLE 容器支援並將它整合到現有的應用程式。

  • SUPERPAD 這個應用程式,以及細緻的獨立應用程式,同時也是 OLE 伺服器。 它會實作伺服程式支援是很最簡單。 最重要的是如何將資料複製到剪貼簿] 中,使用 OLE 剪貼簿] 服務,但會使用內建於 Windows [編輯] 控制項的功能來實作剪貼簿貼上功能。 這會顯示傳統 Windows API 的使用方式,以及與新的 OLE Api 整合多種有趣。

如需有關範例應用程式的詳細資訊,請參閱 「 MFC 範例說明 」。

案例研究: OCLIENT 從 MFC 2.0

如前所述, OCLIENT 已包含在 MFC 2.0 和實作 OLE 的 MFC/OLE1。 如下所述的步驟,讓這個應用程式已經一開始轉換成使用 MFC OLE/2 的類別。 內部連接埠為了更清楚說明 MFC OLE/類別完成後,已加入了許多的功能。 這些功能將會是此處未含蓋 ; 如需有關這些進階功能本身的範例,請參閱。

注意事項注意事項

編譯器錯誤和逐步程序是由 Visual C++ 2.0 建立的。特定的錯誤訊息和位置可能已經變更,Visual C++ 4.0 中,但概念的資訊就會保持有效。

它快速安裝和執行

若要移植到 MFC/OLE OCLIENT 範例採用的方法是先建立它,並修正會造成明顯的編譯器錯誤。 如果您從 MFC 2.0 進行 OCLIENT 取樣,並在此版本的 MFC 中進行編譯,您會發現並沒有那麼多的錯誤,如果要解決。 如下所述的錯誤發生的順序。

編譯和修正錯誤

\oclient\mainview.cpp(104) : error C2660: 'Draw' : function does not take 4 parameters

第一個問題,錯誤COleClientItem::Draw。 在 [MFC/OLE1 亞非 MFC/OLE 版本會使用更多的參數。 必要的而且通常是 NULL (如下例所示),通常沒有額外的參數。 這個版本的 MFC 會繪製到 CDC 中繼檔 DC 時,可以自動判斷 lpWBounds 的值。 此外,pFormatDC 參數已經不再需要因為架構會建立一個從"屬性 DC"的傳入的 pDC。 因此若要修正這個問題,您只需移除這兩個額外 NULL 繪製呼叫的參數。

\oclient\mainview.cpp(273) : error C2065: 'OLE_MAXNAMESIZE' : undeclared identifier
\oclient\mainview.cpp(273) : error C2057: expected constant expression
\oclient\mainview.cpp(280) : error C2664: 'CreateLinkFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(286) : error C2664: 'CreateFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(288) : error C2664: 'CreateStaticFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '

結果來自事實上述的錯誤,所有的 COleClientItem::CreateXXXX MFC/OLE1 中的函式需要一個唯一的名稱會傳遞至代表項目。 這是基礎 OLE API 的需求。 由於 OLE 2 不使用 DDE 做為基礎的通訊機制 (在 DDE 對話中使用的名稱),這並不需要 MFC OLE/2。 若要修正這個問題,您可以移除 CreateNewName 函式,以及它的所有參考。 很容易了解什麼每一個 MFC/OLE 函式所預期在此版本只要將游標放在呼叫,然後按下 f1 鍵。

另一個很大的差異的區域為 OLE 2 剪貼簿] 的處理。 使用 OLE1,您會利用 Windows 剪貼簿互動的 Api 與剪貼簿。 設為 OLE 2 這是一個不同的機制。 MFC/OLE1 Api 假設 [剪貼簿] 複製之前已開啟COleClientItem物件到剪貼簿。 這已經不再需要,將會造成所有 MFC/OLE 剪貼簿作業失敗。 當您編輯的程式碼,以移除相依性,在 CreateNewName,您也應該取出的程式碼,以開啟和關閉 [Windows 剪貼簿]。

\oclient\mainview.cpp(332) : error C2065: 'AfxOleInsertDialog' : undeclared identifier
\oclient\mainview.cpp(332) : error C2064: term does not evaluate to a function
\oclient\mainview.cpp(344) : error C2057: expected constant expression
\oclient\mainview.cpp(347) : error C2039: 'CreateNewObject' : is not a member of 'CRectItem'

這些錯誤造成的 CMainView::OnInsertObject 處理常式。 處理 」 插入新物件] 命令是另一個稍微變更項目了。 如此一來,就最簡單的方法只是合併,即 AppWizard 提供新的 OLE 容器應用程式的原始實作。 事實上,這是一種技術,您可以套用至連接其他應用程式。 您可以在 [MFC/OLE1,顯示"插入物件] 對話方塊來藉由呼叫 AfxOleInsertDialog 函式。 在此版本中建構 COleInsertObject dialog 物件和呼叫DoModal。 此外,會使用建立新的 OLE 項目 CLSID 而非類別名稱字串。 最後的結果看起來像這類的符號

COleInsertDialog dlg;
if (dlg.DoModal() != IDOK)
    return;

BeginWaitCursor();

CRectItem* pItem = NULL;
TRY
{
    // First create the C++ object
    pItem = GetDocument()->CreateItem();
    ASSERT_VALID(pItem);

    // Initialize the item from the dialog data.
    if (!dlg.CreateItem(pItem))
        AfxThrowMemoryException();
           // any exception will do
    ASSERT_VALID(pItem);
        
    // run the object if appropriate
    if (dlg.GetSelectionType() == 
            COleInsertDialog::createNewItem)
        pItem->DoVerb(OLEIVERB_SHOW, this);
        
    // update right away
    pItem->UpdateLink();
    pItem->UpdateItemRectFromServer();
        
    // set selection to newly inserted item
    SetSelection(pItem);
    pItem->Invalidate();
}
CATCH (CException, e)
{  
    // clean up item
    if (pItem != NULL)
        GetDocument()->DeleteItem(pItem);
            
    AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
    
EndWaitCursor();
注意事項注意事項

插入新的物件可能是不同應用程式):

它也會需要包含 <afxodlgs.h>,其中包含的宣告 COleInsertObject 對話方塊類別,以及其他 MFC 所提供的標準對話方塊。

\oclient\mainview.cpp(367) : error C2065: 'OLEVERB_PRIMARY' : undeclared identifier
\oclient\mainview.cpp(367) : error C2660: 'DoVerb' : function does not take 1 parameters

這些錯誤被因某些 OLE1 常數已經變更 OLE 2 的事實,即使它們是相同的概念。 在此情況下 OLEVERB_PRIMARY 已經變更成OLEIVERB_PRIMARY。 在 OLE1 和 OLE 2 中,這個主動作是通常由容器時,執行使用者連按兩下的項目。

此外, DoVerb現在會使用額外的參數,變數的指標,以檢視 (CView1)。 這個參數僅用於實作 「 視覺化編輯"(或在就地啟動)。 現在您將該參數設定為 NULL,因為您在此時沒有實作這項功能。

若要確定架構永遠不會嘗試以就地啟動,您應該覆寫COleClientItem::CanActivate ,如下所示:

BOOL CRectItem::CanActivate()
{
    return FALSE;
}

\oclient\rectitem.cpp(53) : error C2065: 'GetBounds' : undeclared identifier
\oclient\rectitem.cpp(53) : error C2064: term does not evaluate to a function
\oclient\rectitem.cpp(84) : error C2065: 'SetBounds' : undeclared identifier
\oclient\rectitem.cpp(84) : error C2064: term does not evaluate to a function

在 MFC/OLE1, COleClientItem::GetBoundsSetBounds 用於查詢及操作的項目之範圍內 ( 成員都是零)。 MFC/OLE 2 這更直接支援的COleClientItem::GetExtentSetExtent,而處理大小CSize相反的。

您新的 SetItemRectToServer 的程式碼和 UpdateItemRectFromServer 的呼叫,看起來像這樣:

BOOL CRectItem::UpdateItemRectFromServer()
{
   ASSERT(m_bTrackServerSize);
   CSize size;
   if (!GetExtent(&size))
      return FALSE;    // blank

   // map from HIMETRIC to screen coordinates
   {
      CClientDC screenDC(NULL);
      screenDC.SetMapMode(MM_HIMETRIC);
      screenDC.LPtoDP(&size);
   }
   // just set the item size
   if (m_rect.Size() != size)
   {
      // invalidate the old size/position
      Invalidate();
      m_rect.right = m_rect.left + size.cx;
      m_rect.bottom = m_rect.top + size.cy;
      // as well as the new size/position
      Invalidate();
   }
   return TRUE;
}

BOOL CRectItem::SetItemRectToServer()
{
   // set the official bounds for the embedded item
   CSize size = m_rect.Size();
   {
      CClientDC screenDC(NULL);
      screenDC.SetMapMode(MM_HIMETRIC);
      screenDC.DPtoLP(&size);
   }
   TRY
   {
      SetExtent(size);  // may do a wait
   }
   CATCH(CException, e)
   {
      return FALSE;  // links will not allow SetBounds
   }
   END_CATCH
   return TRUE;
}

\oclient\frame.cpp(50) : error C2039: 'InWaitForRelease' : is not a member of 'COleClientItem'
\oclient\frame.cpp(50) : error C2065: 'InWaitForRelease' : undeclared identifier
\oclient\frame.cpp(50) : error C2064: term does not evaluate to a function

MFC/OLE1 同步 API 呼叫的伺服器從容器是模擬,因為 OLE1 已在許多情況下原本就是非同步。 它是需要處理來自使用者的命令之前,先檢查未完成非同步呼叫正在進行中。 所提供的 MFC/OLE1 COleClientItem::InWaitForRelease 需要這樣的函式。 MFC/OLE 2] 中這並沒有必要,以便您可以用全部一起移除 CMainFrame 中的 OnCommand 的覆寫。

在這個時候 OCLIENT 會編譯及連結。

其他必要的變更

有幾件事,不會執行動作,會讓 OCLIENT 不再執行,不過。 最好是以修正這些問題,現在代替稍後。

首先,就必須初始化 OLE 程式庫。 這是藉由呼叫 AfxOleInitInitInstance

if (!AfxOleInit())
{
  AfxMessageBox("Failed to initialize OLE libraries");
  return FALSE;
}

它也是要檢查有虛擬函式的參數清單的變更是個好主意。 有一個這類函式是COleClientItem::OnChange、 覆寫每一個 MFC/OLE 容器應用程式中。 藉由查看線上說明,您會看到額外 'DWORD dwParam' 已加入。 新 CRectItem::OnChange 會如下所示:

void 
CRectItem::OnChange(OLE_NOTIFICATION wNotification, DWORD dwParam)
{
  if (m_bTrackServerSize &&
        !UpdateItemRectFromServer())
  {
    // Blank object
    if (wNotification == OLE_CLOSED)
    {
      // no data received for the object - destroy it
      ASSERT(!IsVisible());
      GetDocument()->DeleteItem(this);
      return;   // no update (item is gone now)
    }
  }
  if (wNotification != OLE_CLOSED)
      Dirty();
  Invalidate();  // any change will cause a redraw
}

在 [MFC/OLE1,容器應用程式衍生的文件類別,從 COleClientDoc。 在 MFC/OLE 2 這個類別已經移除並取代COleDocument (新的組織,方便建立容器/伺服應用程式)。 沒有#define對應 COleClientDocCOleDocument來簡化移植到 MFC/OLE 2,例如 OCLIENT MFC/OLE1 應用程式。 不提供的功能之一COleDocument ,所提供的 COleClientDoc 是標準的命令訊息對應項目。 這也這麼做該伺服器應用程式,也使用COleDocument (間接),無法傳遞與其這些命令處理常式的額外負荷除非這些容器/伺服應用程式。 您必須將下列項目加入至 CMainDoc 的訊息對應:

ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdatePasteMenu)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_LINK, OnUpdatePasteLinkMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, OnUpdateEditLinksMenu)
ON_COMMAND(ID_OLE_EDIT_LINKS, COleDocument::OnEditLinks)
ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, OnUpdateObjectVerbMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_CONVERT, OnUpdateObjectVerbMenu)
ON_COMMAND(ID_OLE_EDIT_CONVERT, OnEditConvert)

所有這些命令的實作是採用COleDocument,也就是您的文件的基底類別。

在這個時候,OCLIENT 是功能的 OLE 容器應用程式。 就可以插入任何類型 (OLE1 或 OLE 2) 的項目。 未實作必要的程式碼,以便在就地啟動,因為大部分像 OLE1 使用另一個視窗中編輯項目。 下一節將告訴您必要的變更,以便進行就地編輯 (有時稱為 「 視覺化編輯")。

新增 「 視覺化編輯"

其中一個最有趣功能是 OLE 的就地啟動 (或 「 視覺化編輯")。 這項功能可讓伺服器應用程式,來為使用者提供更順暢的編輯介面接管容器的使用者介面的某些部份。 若要實作至 OCLIENT 就地啟動時,某些特殊的資源必須加入,以及一些額外的程式碼。 這些資源和程式碼通常所提供的 AppWizard — 事實上,大部分的程式碼的借直接從全新的 AppWizard 應用程式具有 「 容器 」 支援。

首先,就必須要加入的項目,也就是就地啟動時,使用中的功能表資源。 您可以建立 Visual C++ 中的這項額外的功能表資源複製 IDR_OCLITYPE 資源,並移除除了檔案和視窗快顯視窗。 之間,表示群組的分隔的檔案和視窗快顯視窗就會插入兩個分隔線 (看起來就像: 檔案 | |視窗)。 如需更多有關這些分隔元的意義,以及如何合併伺服器與容器功能表請參閱 」 功能表和資源: 功能表合併" OLE 2 類別

一旦建立這些功能表之後,您需要讓知道有關它們的架構。 這是藉由呼叫CDocTemplate::SetContainerInfo才新增至 [文件範本] 清單中您 InitInstance 的文件範本。 若要註冊的文件範本的新程式碼看起來像這樣:

CDocTemplate* pTemplate = new CMultiDocTemplate(
    IDR_OLECLITYPE,
    RUNTIME_CLASS(CMainDoc),
    RUNTIME_CLASS(CMDIChildWnd),    // standard MDI child frame
    RUNTIME_CLASS(CMainView));
pTemplate->SetContainerInfo(IDR_OLECLITYPE_INPLACE);
AddDocTemplate(pTemplate);

IDR_OLECLITYPE_INPLACE 資源已在 Visual C++ 中建立特殊的就地資源。

若要啟用就地啟動時,有幾個步驟,必須同時變更CView (CMainView) 衍生的類別,以及COleClientItem衍生的類別 (CRectItem)。 所有的這些覆寫所提供的 AppWizard,大部分的實作會直接從預設即 AppWizard 的應用程式。

在此連接埠的第一個步驟中,在就地啟動已停用整個藉由覆寫COleClientItem::CanActivate。 若要允許在就地啟動,應該移除這個覆寫。 此外,NULL 傳遞至所有的呼叫DoVerb (有兩項),所以提供檢視只需在就地啟動的。 若要完全實作就地啟動,就必須通過了正確的檢視,在DoVerb呼叫。 其中一個呼叫是在 CMainView::OnInsertObject

pItem->DoVerb(OLEIVERB_SHOW, this);

另一個是在 CMainView::OnLButtonDblClk

m_pSelection->DoVerb(OLEIVERB_PRIMARY, this);

若要覆寫必須COleClientItem::OnGetItemPosition。 這會告知伺服器来放置它的視窗相對於容器的視窗,項目是就地啟動時的位置。 OCLIENT,實作是小事一樁:

void CRectItem::OnGetItemPosition(CRect& rPosition)
{
    rPosition = m_rect;
}

大部分的伺服器也會實作所謂 「 就地調整大小。"這可讓 [伺服器] 視窗來縮放和移動時的使用者正在編輯的項目。 容器必須參與這項動作,因為移動或調整視窗大小通常會影響的位置和大小,容器文件中。 OCLIENT 的實作會同步處理內部維護的 m_rect,以新的位置和大小的矩形。

BOOL CRectItem::OnChangeItemPosition(const CRect& rectPos)
{
    ASSERT_VALID(this);

    if (!COleClientItem::OnChangeItemPosition(rectPos))
        return FALSE;

    Invalidate();
    m_rect = rectPos;
    Invalidate();
    GetDocument()->SetModifiedFlag();

    return TRUE;
}

在這個時候,沒有足夠的程式碼,以允許項目就地啟動並處理縮放或移動項目,當它正在使用,但沒有程式碼可讓使用者結束編輯階段作業。 雖然有些伺服器會提供這項功能本身所處理的 esc 鍵,並建議容器會提供兩種方法可以停用項目: (1) 依序按一下 [項目,之外,(2) 藉由按下 ESCAPE 鍵。

對於 ESCAPE 鍵,新增 [加速器將 VK_ESCAPE 機碼對應到一個指令的 Visual C++,ID_CANCEL_EDIT 會新增到資源。 這個命令的處理常式如下:

// The following command handler provides the standard
// keyboard user interface to cancel an in-place
// editing session.void CMainView::OnCancelEdit()
{
    // Close any in-place active item on this view.
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL)
        pActiveItem->Close();
    ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
}

若要處理使用者按一下項目之外的位置的大小寫,您必須加入下列程式碼的開頭 CMainView::SetSelection

if (pNewSel != m_pSelection || pNewSel == NULL)
{
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL && pActiveItem != pNewSel)
        pActiveItem->Close();
}
    

當項目就地啟動時,應該有焦點。 若要並確定此時您會處理 OnSetFocus,讓您檢視取得焦點時永遠焦點轉移到使用中的項目:

// Special handling of OnSetFocus and OnSize are required 
// when an object is being edited in-place.
void CMainView::OnSetFocus(CWnd* pOldWnd)
{
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL &&
    pActiveItem->GetItemState() == COleClientItem::activeUIState)
    {
        // need to set focus to this item if it is same view
        CWnd* pWnd = pActiveItem->GetInPlaceWindow();
        if (pWnd != NULL)
        {
            pWnd->SetFocus();  // don't call the base class
            return;
        }
    }

    CView::OnSetFocus(pOldWnd);
}

檢視重新調整大小時,您必須通知裁剪方框變更使用中的項目。 若要這樣做您提供的處理常式OnSize

void CMainView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL)
        pActiveItem->SetItemRects();
}

案例研究: HIERSVR 從 MFC 2.0

HIERSVR 也列入 MFC 2.0 和實作 OLE 的 MFC/OLE1。 這張便箋簡短描述,讓這個應用程式已經一開始轉換成使用 MFC/OLE 2 類別的步驟。 內部連接埠為了更清楚說明 MFC OLE/2 類別完成後,已加入了許多的功能。 這些功能將會是此處未含蓋 ; 如需有關這些進階功能本身的範例,請參閱。

注意事項注意事項

編譯器錯誤和逐步程序是由 Visual C++ 2.0 建立的。特定的錯誤訊息和位置可能已經變更,Visual C++ 4.0 中,但概念的資訊就會保持有效。

它快速安裝和執行

若要移植到 MFC/OLE HIERSVR 範例採用的方法是先建立它,並修正會造成明顯的編譯器錯誤。 如果您從 MFC 2.0 採取 HIERSVR 範例,並在此版本的 MFC 中進行編譯,您會發現並不會顯示許多錯誤,如果要解決 (雖然有多個與 OCLIENT 樣本)。 如下所述的錯誤通常發生的順序。

編譯和修正錯誤

\hiersvr\hiersvr.cpp(83) : error C2039: 'RunEmbedded' : is not a member of 'COleTemplateServer'

這第一項錯誤會指出的是什麼大問題InitInstance函式的伺服器。 所需的 「 OLE 伺服器元件的初始化動作可能是其中一項重大的變更,您都必須進行您的 MFC/OLE1 應用程式,才能讓它執行。 最佳的做法是查看即 AppWizard 的 OLE 伺服器會建立和修改適當的程式碼。 下面幾個重點来牢記在心:

必須初始化 OLE 程式庫,藉由呼叫 AfxOleInit

若要設定伺服器資源控制代碼和執行階段類別資訊,您無法使用設定文件樣板物件上呼叫 SetServerInfo CDocTemplate建構函式。

如果 /Embedding 是出現在命令列上,以後不再顯示您的應用程式的主視窗。

您將需要 GUID 文件。 這是您的文件型別 (128 位元) 的唯一識別項。 即 AppWizard 會為您建立一個,因此,如果您使用此處所提的方法中複製新的程式碼從新的 AppWizard 產生伺服器應用程式以外,您可以只是 「 竊取 」 從那個應用程式的 GUID。 否則,您可以使用 GUIDGEN。EXE 公用程式的 BIN 目錄中。

需要 「 連線 」 您COleTemplateServer物件至文件範本,藉由呼叫COleTemplateServer::ConnectTemplate

當單獨執行您的應用程式,請更新系統登錄。 如此一來,如果使用者移動。您的應用程式的執行檔,從新的位置執行將會更新 Windows 系統登錄資料庫,以指向新位置。

在所有基礎 AppWizard 為建立這些變更套用後InitInstanceInitInstance (和相關的 GUID) 的 HIERSVR 應該看起來的樣子:

// this is the GUID for HIERSVR documents
static const GUID BASED_CODE clsid =
    { 0xA0A16360L, 0xC19B, 0x101A, { 0x8C, 0xE5, 0x00, 0xDD, 0x01, 0x11, 0x3F, 0x12 } };
    
/////////////////////////////////////////////////////////////////////////////
// COLEServerApp initialization

BOOL COLEServerApp::InitInstance()
{
    // OLE 2 initialization
    if (!AfxOleInit())
    {
        AfxMessageBox("Initialization of the OLE failed!");
        return FALSE;
    }

    // Standard initialization
    LoadStdProfileSettings(); // Load standard INI file options 

    // Register document templates
    CDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(IDR_HIERSVRTYPE,
        RUNTIME_CLASS(CServerDoc),   
        RUNTIME_CLASS(CMDIChildWnd),
        RUNTIME_CLASS(CServerView));
    pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB);
    AddDocTemplate(pDocTemplate);

    // create main MDI Frame window
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
        return FALSE;
    m_pMainWnd = pMainFrame;

    SetDialogBkColor();   // gray look

    // enable file manager drag/drop and DDE Execute open
    m_pMainWnd->DragAcceptFiles();
    EnableShellOpen();
    
    m_server.ConnectTemplate(clsid, pDocTemplate, FALSE);
    COleTemplateServer::RegisterAll();

    // try to launch as an OLE server
    if (RunEmbedded())
    {
        // "short-circuit" initialization -- run as server!
        return TRUE;
    }
    m_server.UpdateRegistry();
    RegisterShellFileTypes();

    // not run as OLE server, so show the main window
    if (m_lpCmdLine[0] == '\0')
    {
        // create a new (empty) document
        OnFileNew();
    }
    else
    {
        // open an existing document
        OpenDocumentFile(m_lpCmdLine);
    }

    pMainFrame->ShowWindow(m_nCmdShow);
    pMainFrame->UpdateWindow();
    
    return TRUE;
}

您會注意到上述的程式碼是指新的資源 ID、 IDR_HIERSVRTYPE_SRVR_EMB。 這是編輯內嵌於另一個容器文件時所要使用的功能表資源。 在 MFC/OLE1 即時修改特定編輯內嵌項目的功能表項目。 編輯內嵌項目而非編輯檔案架構的文件時,請使用完全不同的功能表結構,使得更容易地為這兩種不同模式提供不同的使用者介面。 當您稍後就會看到,編輯內嵌的物件現用時,會使用完全不同的功能表資源。

若要建立此資源時,Visual C++ 中載入的資源指令碼,複製現有的 IDR_HIERSVRTYPE 功能表資源。 重新命名新的資源 (亦即 AppWizard 使用相同的命名慣例) 的 IDR_HIERSVRTYPE_SRVR_EMB。 接下來變為 「 儲存檔案""檔案更新 」 項目。 為它指定命令 ID ID_FILE_UPDATE。 也變更 [檔案另存為""複本存新檔]。 為它指定命令 ID ID_FILE_SAVE_COPY_AS。 此架構提供這兩種命令的實作。

\hiersvr\svritem.h(60) : error C2433: 'OLESTATUS' : 'virtual' not permitted on data declarations
\hiersvr\svritem.h(60) : error C2501: 'OLESTATUS' : missing decl-specifiers
\hiersvr\svritem.h(60) : error C2146: syntax error : missing ';' before identifier 'OnSetData'
\hiersvr\svritem.h(60) : error C2061: syntax error : identifier 'OLECLIPFORMAT'
\hiersvr\svritem.h(60) : error C2501: 'OnSetData' : missing decl-specifiers

有數個錯誤所導致的覆寫的OnSetData,因為它指的 OLESTATUS 型別。 OLESTATUS OLE1 傳回錯誤的方法。 這已經變更成HRESULT OLE 2 中,雖然 MFC 通常將轉換HRESULTCOleException包含錯誤。 在此特定情況的覆寫OnSetData已不必要的因此最簡單的事就是先將它移除。

\hiersvr\svritem.cpp(30) : error C2660: 'COleServerItem::COleServerItem' : function does not take 1 parameters

COleServerItem建構函式會使用額外的 'BOOL' 參數。 這個旗標判定,記憶體管理會對進行COleServerItem物件。 藉由將它設定為 TRUE,此架構會處理這些物件的記憶體管理 — 就不再需要時刪除它們。 HIERSVR 會使用 CServerItem (衍生自COleServerItem) 物件做為其原生的資料,所以您將會設定這個旗標設為 FALSE 的一部分。 如此一來判斷每個伺服器項目刪除時的 HIERSVR。

\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class
\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class

這些錯誤所暗示,有一些 '純虛擬' 的函式不在 CServerItem 中已被覆寫。 很可能這被因為 OnDraw 的參數清單已變更的事實。 若要更正這個錯誤,變更 CServerItem::OnDraw ,如下所示 (以及在 svritem.h 中宣告):

BOOL CServerItem::OnDraw(CDC* pDC, CSize& rSize)
{
    // request from OLE to draw node
    pDC->SetMapMode(MM_TEXT); // always in pixels
    return DoDraw(pDC, CPoint(0,0), FALSE);
}

新的參數是 'rSize'。 這可讓您填入的繪圖,大小如果很方便。 這種大小必須在微米。 如此一來,很不方便地填滿,這個值,架構會呼叫OnGetExtent要擷取之範圍內。 對於那樣運作,您需要實作OnGetExtent

BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
    if (dwDrawAspect != DVASPECT_CONTENT)
        return COleServerItem::OnGetExtent(dwDrawAspect, rSize);
        
    rSize = CalcNodeSize();
    return TRUE;
}

\hiersvr\svritem.cpp(104) : error C2065: 'm_rectBounds' : undeclared identifier
\hiersvr\svritem.cpp(104) : error C2228: left of '.SetRect' must have class/struct/union type
\hiersvr\svritem.cpp(106) : error C2664: 'void __pascal __far DPtoLP(struct ::tagPOINT __far *,int )__far const ' : cannot convert parameter 1 from 'int __far *' to 'struct ::tagPOINT __far *'

在 CServerItem::CalcNodeSize 函式中的項目大小會轉換成微米 ,且儲存在 m_rectBounds。 Undocumented 'm_rectBounds' 的成員COleServerItem不存在 (它部分取代了m_sizeExtent,但 OLE 2 組員有稍微不同的使用方式比 m_rectBounds 在 OLE1 一樣)。 而不是設定的微米大小到這個成員變數,您會將它傳回。 這個傳回值可以用於OnGetExtent的先前實作。

CSize CServerItem::CalcNodeSize()
{
    CClientDC dcScreen(NULL);

    m_sizeNode = dcScreen.GetTextExtent(m_strDescription,
      m_strDescription.GetLength());
    m_sizeNode += CSize(CX_INSET * 2, CY_INSET * 2);

    // set suggested HIMETRIC size
    CSize size(m_sizeNode.cx, m_sizeNode.cy);
    dcScreen.SetMapMode(MM_HIMETRIC);
    dcScreen.DPtoLP(&size);
    return size;
}

CServerItem 也會覆寫 COleServerItem::OnGetTextData。 此函式/OLE 的 MFC 中已過時,並已由不同的機制。 MFC OLE 範例的 MFC 3.0 版 HIERSVR 實作這項功能,藉由覆寫COleServerItem::OnRenderFileData。 所以您可以移除 OnGetTextData 覆寫,並不重要這個基本的連接埠,這項功能。

有許多多個錯誤在 svritem.cpp 中的,都不能獲得解決。 它們不是 「 真正 」 的錯誤,只是由先前的錯誤所造成的錯誤。

\hiersvr\svrview.cpp(325) : error C2660: 'CopyToClipboard' : function does not take 2 parameters

COleServerItem::CopyToClipboard不支援 'bIncludeNative' 旗標。 永遠複製原生資料 (由伺服器項目的 Serialize 函式所寫出的資料),所以您移除第一個參數。 此外, CopyToClipboard將會擲回例外狀況代替傳回 FALSE 就會發生錯誤時。 變更程式碼為 CServerView::OnEditCopy,如下所示:

void CServerView::OnEditCopy()
{
    if (m_pSelectedNode == NULL)
        AfxThrowNotSupportedException();
        
    TRY
    {
        m_pSelectedNode->CopyToClipboard(TRUE);
    }
    CATCH_ALL(e)
    {
        AfxMessageBox("Copy to clipboard failed");
    }
    END_CATCH_ALL   
}

雖然發生了超過原先為相同版本的 OCLIENT HIERSVR MFC 2.0 版的編譯所產生的多個錯誤,發生了實際較少的變更。

到目前為止 HIERSVR 將會編譯和連結,並為 OLE 伺服器,但不就地編輯功能,接下來將會實作的情況下運作。

新增 「 視覺化編輯"

要加入此伺服應用程式的 「 視覺編輯"(或在就地啟動),請有只有幾件事您必須要特別注意的:

  • 您需要的項目是就地啟動時所要使用的特餐菜資源。

  • 這個應用程式會有一個工具列,所以您必須具有 [一般] 工具列來比對的功能表命令可從伺服器 (符合前面所提到的功能表資源) 的子集的工具列。

  • 您需要新的類別衍生自COleIPFrameWnd所提供的現用使用者介面 (就像是 CMainFrame,衍生自CMDIFrameWnd,提供 MDI 使用者介面)。

  • 您需要告訴這些特殊的資源和類別的架構。

功能表資源很容易建立的。 執行 Visual C++,稱為 IDR_HIERSVRTYPE_SRVR_IP 的功能表資源複製的功能表資源 IDR_HIERSVRTYPE。 修改 [] 功能表中,使快顯只能編輯及說明] 功能表畫面剩下的軍團成員。 新增到 [編輯] 與 [說明] 功能表之間功能表的兩個分隔符號 (看起來就像: 編輯 | |說明)。 如需有關這些分隔元的意義,以及如何合併伺服器] 與 [容器] 功能表的詳細資訊,請參閱 」 功能表和資源: 功能表合併" OLE 2 類別

複製從全新的 AppWizard 產生應用程式的一個,以檢查 [伺服器] 選項,可以很容易就建立子集合] 工具列的點陣圖。 這個點陣圖接著匯入至 Visual C++。 請務必提供點陣圖 ID 的 IDR_HIERSVRTYPE_SRVR_IP。

此類別衍生自COleIPFrameWnd從伺服器支援,以及使用 AppWizard 產生應用程式就可以複製。 將複製這兩個檔案,而 IPFRAME。CPP 和 IPFRAME。H,並將它們加入至專案。 請確定LoadBitmap呼叫指的是 IDR_HIERSVRTYPE_SRVR_IP,在前一個步驟中建立的點陣圖。

現在會建立所有新的資源和類別,加入必要的程式碼,以便在架構知道這些 (以及知道現在這個應用程式支援就地編輯)。 這是藉由加入至某些多個參數SetServerInfo呼叫中的InitInstance函式:

pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB,
    IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame));

現在已準備好可以執行就地也支援就地啟動任何容器中。 但是,沒有一個次要的 bug 仍然潛藏在程式碼。 Hiersvr 並未支援內容功能表,當使用者按下滑鼠右鍵時顯示。 HIERSVR 完全開啟,但是編輯內嵌現用時無法使用時的運作方式此功能表。 原因可以向下釘選到 CServerView::OnRButtonDown 中的程式碼的這一行:

pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
    point.x, point.y, AfxGetApp()->m_pMainWnd);

請注意參照類型的 AfxGetApp()-> m_pMainWnd。 就地啟動伺服器時,它有主視窗和 m_pMainWnd 設定,但是通常是不可見。 此外,此視窗是指主要 ] 視窗中的應用程式,完全是由伺服器時,會出現 MDI 框架視窗開啟,或單獨執行。 它不是指在使用中框架視窗 — 當就地啟動即為框架視窗衍生自COleIPFrameWnd。 若要取得正確的使用中視窗,即使就地編輯,這一版的 MFC 會加入新的函式, AfxGetMainWnd。 一般而言,您應該使用這個函式,而不是 AfxGetApp()-> m_pMainWnd。 這段程式碼需要變更,如下所示:

pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
    point.x, point.y, AfxGetMainWnd());

現在,您必須至少啟用功能的就地啟動 OLE 伺服器。 但仍有許多功能適用於 MFC/OLE1 中所沒有的 MFC OLE/2。 您可能想要執行的功能,請參閱 HIERSVR 範例如需詳細資訊。 以下列出部分 HIERSVR 實作的功能:

  • 縮放功能,則為 true 的 WYSISYG 行為至容器。

  • 拖曳 / 卸除和自訂的剪貼簿格式。

  • 將與選取的容器視窗捲動會變更。

在 MFC 3.0 HIERSVR 範例也會使用它的伺服器項目稍有不同的設計。 這麼做可節省記憶體,並可讓您的連結更有彈性。 HIERSVR 的 2.0 版與每個節點在樹狀目錄中 is-aCOleServerItemCOleServerItem執行更多的額外負荷,比絕對必要,每個節點,但COleServerItem都需要每個使用中的連結。 但大多數的情況下,在任何時候產生了很少使用的連結。 若要讓這更有效率,在這個版本的 MFC HIERSVR 分隔的節點,從COleServerItem。 它有兩個 CServerNode 和 CServerItem 類別。 CServerItem (衍生自COleServerItem) 只會建立在必要的時候。 一旦容器 (或) 容器停止使用該特定的連結到該特定的節點,則會刪除相關的 CServerNode 的 CServerItem 物件。 這種設計是更有效率且更具彈性。 處理多個選取的連結時,它的彈性會伴隨。 HIERSVR 的這兩種版本都不支援多重選取,但很容易多了新增 (和支援這類選項的連結) MFC 3.0 版 HIERSVR,因為COleServerItem與原生資料分離。

請參閱

其他資源

技術的備忘稿編號

依類別的技術注意事項