TN041: Migrace z prostředí MFC/OLE1 do MFC/OLE2
[!POZNÁMKA]
Následující technická poznámka nebyla aktualizována, protože byla poprvé zahrnuta v dokumentaci online.V důsledku toho některé postupy a témata mohou být nesprávné nebo zastaralé.Pro nejnovější informace je vhodné vyhledat téma zájmu v dokumentaci online index.
Obecné problémy týkající se přenesení
Jedním z cílů návrhu OLE 2 tříd MFC 2.5 (a vyšší) bylo zachovat většinu stejnou architekturu zaveden pro podporu OLE 1.0 2.0 knihovny MFC.V důsledku toho mnoho třídy OLE 2.0 knihovny MFC stále existují v této verzi knihovny MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem).Kromě toho mnoho rozhraní API v těchto třídách jsou přesně stejné.OLE 2 je však výrazně liší od OLE 1.0, můžete očekávat, že některé údaje byly změněny.Pokud jste obeznámeni s podporou OLE1 2.0 knihovny MFC, budete cítit doma 2.0 podpory knihovny MFC.
Pokud jsou převzetím existující aplikace knihovny MFC nebo OLE1 a přidáním funkce OLE 2 k němu, přečtěte si tato poznámka první.Tato poznámka se vztahuje na některé obecné problémy mohou nastat při přenášení vašeho OLE1 funkce knihovny MFC/OLE 2 a pak pojednává o problémech zjištěných při portování dvě aplikace, které jsou zahrnuty v MFC 2.0: vzorky MFC OLE OCLIENT a HIERSVR.
Je důležité knihovny MFC Document/View Architecture
Pokud vaše aplikace nepoužívá MFC architekturu Document/View a chcete přidat do aplikace OLE 2 podporu, nyní je čas na přechod na Document/View.Pouze výhody OLE 2 tříd knihovny MFC jsou realizovány po aplikace používá integrované architektury a součásti knihovny MFC.
Implementace serveru nebo kontejner bez použití s architekturou knihovny MFC je možné, ale není doporučeno.
Použijte místo své vlastní implementace MFC
Třídy MFC implementace "konzervované" jako CToolBar, CStatusBar, a CScrollView mají vestavěné případu zvláštní kód pro podporu OLE 2.Ano Pokud tyto třídy můžete použít v aplikaci budete mít výhodu úsilí do nich informovat je OLE.Opět je možné "role vaše vlastní" zde třídy pro tyto účely, ale není navržen.Pokud potřebujete provádět podobné funkce MFC zdrojový kód je výborným zdrojem pro obchodování s některými jemnější body OLE (zejména pokud jde o místní aktivace).
Prozkoumejte ukázkový kód MFC
Existuje několik vzorků knihovny MFC, které obsahují funkce OLE.Každý z těchto aplikací implementuje OLE z jiného úhlu:
HIERSVR určen převážně pro použití jako aplikační server.Byl součástí 2.0 knihovny MFC jako aplikace knihovny MFC nebo OLE1 a bylo přesně do knihovny MFC/OLE 2 a pak se rozšíří tak, že implementuje mnoho funkce OLE OLE 2 k dispozici.
OCLIENT Toto je aplikace s samostatný kontejner má prokázat mnohé funkce OLE z hlediska kontejneru.To byl příliš přenést z 2.0 knihovny MFC a pak se rozšíří na podporu mnoho pokročilejší funkce OLE, například vlastní schránky formáty a odkazy na vložené položky.
DRAWCLI tuto aplikaci implementuje podporu OLE kontejneru mnohem jako OCLIENT, s tím rozdílem, že tak učiní v rámci existujícího výkresu programu objektově orientované.To se dozvíte, jak implementovat podporu OLE kontejneru a integrovat do aplikace.
SUPERPAD této aplikace, stejně jako jemné samostatná aplikace, přičemž je také OLE server.Podpora serveru, který implementuje je tichý minimalist.Zvláštního zájmu je jak používá služby OLE schránky zkopírovat data do schránky, ale používá k implementaci funkcí schránky vložit funkci zabudovanou do ovládacího prvku pro úpravy"Windows".To ukazuje zajímavou kombinací tradičního používání rozhraní API systému Windows, jakož i integrace se nové OLE API.
Další informace o ukázkové aplikace nápovědě k "MFC ukázkové".
Případová studie: OCLIENT z knihovny MFC 2.0
Jak již bylo uvedeno výše, OCLIENT byla zahrnuta v MFC verze 2.0 a implementace OLE s MFC/OLE1.Níže jsou popsány kroky, kterými tato aplikace byla převedena původně použití tříd knihovny MFC/OLE 2.Mnoho funkcí byly přidány po dokončení počáteční port pro lepší ilustraci tříd MFC/OLE.Tyto funkce nebudou uvedena zde; naleznete další informace o těchto rozšířených funkcí samotného vzorku.
[!POZNÁMKA]
Chyby kompilátoru a postup byl vytvořen pomocí Visual C++ 2.0.Konkrétní chybové zprávy a umístění mohlo dojít ke změně s Visual C++ 4.0, ale zůstává v platnosti rámcové informace.
Získání a systémem
Přístupem k portu OCLIENT vzorek MFC/OLE je začněte vytvářením a stanovení kompilátoru zjevné chyby, které způsobí.Pokud se odebere vzorek OCLIENT 2.0 knihovny MFC a kompilujte jej v této verzi knihovny MFC, zjistíte, že nejsou to mnoho chyb lze vyřešit.Chyby v pořadí, ve kterém došlo jsou popsány níže.
Kompilace a oprava chyb
\oclient\mainview.cpp(104) : error C2660: 'Draw' : function does not take 4 parameters
První chyba se týká COleClientItem::Draw.V MFC/OLE1 trvalo více parametrů, než má verzi knihovny MFC/OLE.Dodatečné parametry nebyly často nezbytné a obvykle NULL (jako v tomto příkladu).Tato verze knihovny MFC automaticky zjistit hodnoty lpWBounds po metasouboru DC CSP, který je nakreslena.Kromě toho pFormatDC parametr již není nezbytné vzhledem k tomu, že rámec bude stavět jeden z "atribut DC" primární řadič domény předaný.Takže chcete-li tento problém vyřešit, stačí odebrat dva extra NULL parametrů volání Draw.
\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 '
Chyby nad výsledkem ze skutečnosti, že všechny COleClientItem::CreateXXXX funkce v knihovně MFC/OLE1 vyžaduje, aby předávané představovat položku jedinečný název.To byl požadavek podkladové OLE rozhraní API.To není nutné v MFC/OLE 2 protože OLE 2 nepoužívá DDE jako podkladový mechanismus komunikace (název byl použit v konverzaci DDE).Chcete-li tento problém vyřešit, odeberte CreateNewName a všechny odkazy funkční.Je snadné zjistit, co jednotlivé funkce knihovny MFC/OLE očekává v této verzi jednoduše tak, že umístíte kurzor na volání a stisknutím klávesy F1.
Jiné oblasti, která se výrazně liší, je zpracování schránky OLE 2.S OLE1 použili jste schránky systému Windows API interakcí se schránkou.To lze provést pomocí jiný mechanismus, s OLE 2.Rozhraní API knihovny MFC/OLE1 předpokládá, že schránka byla otevřena před kopírováním COleClientItem objekt do schránky.To není nutné a způsobí, že všechny knihovny MFC/OLE schránky operace nezdaří.Při úpravách kódu odebrání závislostí na CreateNewName, měli byste odebrat také kód, který otevírá a zavírá do schránky systému 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'
Výsledkem těchto chyb CMainView::OnInsertObject obslužnou rutinu.Zpracování příkazu "Vložit nový objekt" je další oblastí, kde se věci změnily odlišují.V takovém případě je nejjednodušší jednoduše sloučit původní provedení s poskytnutá AppWizard pro nové aplikace OLE kontejneru.Ve skutečnosti to je metoda, pomocí které lze použít pro přenos dalších aplikací.V MFC/OLE1 zobrazí dialogové okno "Vložit objekt" voláním AfxOleInsertDialog funkce.V této verzi sestavení COleInsertObject dialogovém okně objektu a volání DoModal.Kromě toho jsou vytvořeny nové položky OLE s CLSID místo řetězce název třídy.Konečný výsledek by měl vypadat podobně jako tento
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();
[!POZNÁMKA]
Vložit nový objekt může být různé aplikace):
Je také nutné zahrnout <afxodlgs.h>, který obsahuje prohlášení COleInsertObject třída dialogu, jakož i ostatní standardní dialogy poskytnuté knihovnou MFC.
\oclient\mainview.cpp(367) : error C2065: 'OLEVERB_PRIMARY' : undeclared identifier
\oclient\mainview.cpp(367) : error C2660: 'DoVerb' : function does not take 1 parameters
Tyto chyby jsou způsobeny skutečnost, že některé konstanty OLE1 změnily v OLE 2, přestože v konceptu jsou stejné.V tomto případě OLEVERB_PRIMARY se změnil na OLEIVERB_PRIMARY.OLE1 a OLE 2 primární sloveso je obvykle prováděných kontejneru při poklepání na položku.
Kromě toho DoVerb nyní příjmá další parametr – ukazatel na zobrazení (CView*).Tento parametr se používá pouze pro implementaci "Vizuální úpravy" (nebo aktivaci na místě).Nyní nastavit tento parametr na hodnotu NULL, protože neimplementujete tuto funkci v současné době.
Chcete-li zajistit, že rámec nikdy pokusy o místní aktivaci, měli byste přepsat COleClientItem::CanActivate takto:
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
V MFC/OLE1 COleClientItem::GetBounds a SetBounds byly použity k dotazování a manipulaci s rozsah položky ( levé a horní členy byly vždy nula).Knihovna MFC/OLE 2 to je přímo podporována COleClientItem::GetExtent a SetExtent, vypořádat se s velikost nebo CSize místo.
Kód pro váš nový SetItemRectToServer a UpdateItemRectFromServer volání vypadat takto:
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
V MFC/OLE1 synchronní API volání z kontejneru na server byly simulované, protože byl v mnoha případech ze své podstaty asynchronní OLE1.Bylo nezbytné ke kontrole nevyřízených asynchronní volání probíhá před zpracováním příkazy od uživatele.MFC/OLE1 k dispozici COleClientItem::InWaitForRelease funkce pro to.Knihovna MFC/OLE 2 to není nutné, takže můžete odstranit přepsání OnCommand v CMainFrame společně.
OCLIENT v tomto okamžiku bude kompilace a propojení.
Další potřebné změny.
Existuje několik věcí, které nebyly provedeny uchová OCLIENT spuštění, ale.Je lepší vyřešit tyto problémy nyní místo později.
Nejprve je nutné inicializovat knihovny OLE.To se provádí voláním AfxOleInit z InitInstance:
if (!AfxOleInit())
{
AfxMessageBox("Failed to initialize OLE libraries");
return FALSE;
}
Je také vhodné vyhledat virtuální funkce změny seznamu parametr.Tato funkce je COleClientItem::OnChange, přepsané v každé aplikaci MFC/OLE kontejneru.Hledáním v nápovědě online uvidíte přidaná další "DWORD dwParam".Nový CRectItem::OnChange vypadá takto:
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
}
V MFC/OLE1 aplikace kontejneru odvozenou třídu dokumentu z COleClientDoc.Knihovna MFC/OLE 2 bylo odstraněno této třídy a nahrazuje COleDocument (toto nové uspořádání usnadňuje vytváření aplikací kontejneru server).Je #define která mapuje COleClientDoc k COleDocument pro zjednodušení portování aplikací knihovny MFC/OLE1 MFC/OLE 2, například OCLIENT.Jednou z funkcí v řádně COleDocument , dodal COleClientDoc je standardní příkaz zprávy položek mapování.To se provádí tak serverové aplikace, které používají také COleDocument (nepřímo) nemají s nimi režie tyto popisovače příkazu nejsou aplikace kontejneru server.Potřebujete mapu zpráv CMainDoc přidejte následující položky:
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)
Provádění těchto příkazů je v COleDocument, což je základní třída pro dokument.
V tomto okamžiku OCLIENT je funkční aplikace OLE kontejneru.Je možné vložit položky libovolného typu (OLE1 nebo OLE 2).Vzhledem k tomu, že kód nezbytné povolit aktivaci na místě není implementována, položky jsou upravovány v samostatném okně, podobně jako s OLE1.Další část popisuje nezbytné změny, chcete-li povolit úpravy na místě (někdy nazývané "Vizuální úpravy").
Přidávání "Vizuální úpravy"
Je jednou z nejzajímavějších funkcí OLE v místě aktivace (nebo "Vizuální úpravy").Tato funkce umožňuje převzít části kontejneru uživatelského rozhraní poskytovány bezproblémové úpravy rozhraní pro uživatele aplikace.Některé zvláštní prostředky k provedení aktivace na místě na OCLIENT, třeba přidali, a některé další kód.Tyto prostředky a kód jsou obvykle poskytovány AppWizard – ve skutečnosti byla velká část kódu zde vypůjčila přímo z čerstvých aplikací AppWizard s podporou "Kontejner".
Nejprve je nutné přidat zdroj nabídky použít, pokud je položka, která je aktivní v místě.Tento prostředek extra nabídky můžete vytvořit v aplikaci Visual C++ zkopírováním IDR_OCLITYPE prostředků a odebrání všech kromě souboru a okno automaticky otevíraná okna.Mezi soubory a okna automaticky otevíraná okna k označení oddělení skupin jsou vloženy dva pruhy oddělovač (by měl vypadat: soubor || Okno).Další informace o významu těchto oddělovačů a způsob sloučení nabídky serveru a kontejner naleznete v tématu "Nabídek a zdroje: nabídka slučování" v Třídy OLE 2.
Jakmile máte tyto nabídky vytvořeny, je třeba dát framework vědět o nich.To se provádí voláním CDocTemplate::SetContainerInfo pro šablonu dokumentu před přidáním do seznamu šablon dokumentu ve vašem InitInstance.Nový kód pro registraci šablony dokumentu vypadá takto:
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);
Zdroj IDR_OLECLITYPE_INPLACE je zvláštní místní zdroje vytvořené v aplikaci Visual C++.
Chcete-li aktivaci na místě, jsou některé kroky, které je třeba změnit v obou CView (CMainView) odvozené třídy společně s COleClientItem odvozené třídy (CRectItem).Všechny tyto lokální změny podle AppWizard a většina implementace budou pocházet přímo z AppWizard výchozí aplikace.
V prvním kroku tohoto portu bylo zakázáno aktivaci na místě zcela přepsáním COleClientItem::CanActivate.Povolit aktivaci na místě, je třeba odebrat toto přepsání.Kromě toho byla předána hodnota NULL pro všechna volání DoVerb (existují dva) vzhledem k tomu, že poskytnete zobrazení byla pouze potřebné pro aktivaci na místě.K plnému provedení aktivace na místě, je třeba předat na správné zobrazení v DoVerb volání.Je jedním z těchto v CMainView::OnInsertObject:
pItem->DoVerb(OLEIVERB_SHOW, this);
Další je v CMainView::OnLButtonDblClk:
m_pSelection->DoVerb(OLEIVERB_PRIMARY, this);
Je třeba přepsat COleClientItem::OnGetItemPosition.To ukazuje umístění okna vzhledem ke kontejneru okna položky při aktivaci serveru.OCLIENT provedení je triviální:
void CRectItem::OnGetItemPosition(CRect& rPosition)
{
rPosition = m_rect;
}
Většina serverů také implementovat, co se nazývá "na místě velikosti." To umožňuje serveru okno velikosti a v době, kdy uživatel upravuje položky přesunuty.Nádoby musí být součástí této akce, protože přesouvání nebo změně velikosti okna obvykle ovlivňuje umístění a velikost kontejneru samotného dokumentu.Provádění OCLIENT synchronizuje vnitřní udržovaný m_rect s nové umístění a velikost obdélníku.
BOOL CRectItem::OnChangeItemPosition(const CRect& rectPos)
{
ASSERT_VALID(this);
if (!COleClientItem::OnChangeItemPosition(rectPos))
return FALSE;
Invalidate();
m_rect = rectPos;
Invalidate();
GetDocument()->SetModifiedFlag();
return TRUE;
}
V tomto okamžiku existuje dostatek kód umožňující položku místo aktivován a řešení pro změnu velikosti a přesunutím položky, pokud je aktivní, ale žádný kód umožní uživatelům ukončit relaci úprav.I když některé servery budou tyto funkce poskytují sami pomocí klávesy ESC, je doporučeno, aby kontejnery nabízejí dva způsoby deaktivovat položku: (1) klepnutím mimo zboží a (2) stisknutím klávesy ESC.
Klávesy ESCAPE přidání akcelerátoru s Visual C++, mapující VK_ESCAPE klíč k příkazu, ID_CANCEL_EDIT je přidán do zdroje.Obslužné rutiny pro tento příkaz takto:
// 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);
}
K zpracování případu, kde uživatel klepne mimo položku, přidejte následující kód na začátek CMainView::SetSelection:
if (pNewSel != m_pSelection || pNewSel == NULL)
{
COleClientItem* pActiveItem =
GetDocument()->GetInPlaceActiveItem(this);
if (pActiveItem != NULL && pActiveItem != pNewSel)
pActiveItem->Close();
}
Pokud je položka aktivní na místě, měl by mít fokus.Ujistěte se, že v tomto případě zpracovat OnSetFocus zaměření vždy převedeno na aktivní položku při zobrazení vybrán tak, aby:
// 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);
}
Při změně velikosti zobrazení, je nutné upozornit na aktivní položku změněného Obdélník ořezu.K tomu poskytovat obslužnou rutinu pro 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();
}
Případová studie: HIERSVR z knihovny MFC 2.0
HIERSVR byl také zahrnuty v MFC verze 2.0 a implementace OLE s MFC/OLE1.Tato poznámka stručně popisuje kroky, kterými tato aplikace byla převedena původně použití tříd knihovny MFC/OLE 2.Mnoho funkcí byly přidány po dokončení počáteční port pro lepší ilustraci tříd MFC/OLE 2.Tyto funkce nebudou uvedena zde; naleznete další informace o těchto rozšířených funkcí samotného vzorku.
[!POZNÁMKA]
Chyby kompilátoru a postup byl vytvořen pomocí Visual C++ 2.0.Konkrétní chybové zprávy a umístění mohlo dojít ke změně s Visual C++ 4.0, ale zůstává v platnosti rámcové informace.
Získání a systémem
Přístupem k portu HIERSVR vzorek MFC/OLE je začněte vytvářením a stanovení kompilátoru zjevné chyby, které způsobí.Pokud se odebere vzorek HIERSVR 2.0 knihovny MFC a kompilujte jej v této verzi knihovny MFC, zjistíte, že nejsou mnoho chyb při řešení (i když existuje více než s OCLIENT vzorku).Chyby v pořadí, v jakém se obvykle objevují jsou popsány níže.
Kompilace a oprava chyb
\hiersvr\hiersvr.cpp(83) : error C2039: 'RunEmbedded' : is not a member of 'COleTemplateServer'
První chyba poukazuje na mnohem větší problém se InitInstance funkce pro servery.Inicializace potřebné pro OLE server je pravděpodobně jedna z největších změn, které budete muset provést aplikace knihovny MFC nebo OLE1 ho systémem.Nejlepším krokem je, podívejte se na AppWizard vytvoří pro OLE server a upravit kód podle potřeby.Zde jsou některé body třeba vzít v úvahu:
Je třeba inicializovat knihovny OLE voláním AfxOleInit
Volání SetServerInfo v objektu nastavení popisovače prostředku serveru a informace o provozní třídy, které nelze nastavit pomocí šablony dokumentu CDocTemplate konstruktoru.
Nezobrazovat v hlavním okně aplikace, pokud je k dispozici v příkazovém řádku /Embedding.
Budete potřebovat GUID dokumentu.Toto je jedinečný identifikátor pro typ dokumentu (128 bitů).AppWizard bude vytvořit novou, takže pokud zde použít techniku popsanou kopírování nového kódu z nové AppWizard generované aplikace serveru, můžete můžete jednoduše "ukrást" GUID z této aplikace.V opačném případě můžete použít cílem.EXE nástroj do adresáře BIN.
Je třeba "připojit" v COleTemplateServer do šablony dokumentu voláním objektu COleTemplateServer::ConnectTemplate.
Aktualizace systémového registru při spuštění samostatné aplikace.V případě, že uživatel přesune.EXE aplikace spuštěné ze své nové pozice bude aktualizovat registrační databázi systému Windows přejděte na nové umístění.
Po použití všech těchto změn podle AppWizard vytvoří pro InitInstance, InitInstance (a související identifikátor GUID) pro HIERSVR se nahrazuje tímto:
// 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;
}
Zjistíte, že výše uvedený kód odkazuje na nové ID prostředku IDR_HIERSVRTYPE_SRVR_EMB.To je zdroj nabídky pro použití při úpravě dokumentu, který je vložen do jiného kontejneru.V MFC/OLE1 byly upraveny zvláštní úpravy položky vložené položky nabídky průběžně.Při úpravě položky vložené místo úprav dokumentu založeného na souborech pomocí struktury zcela jiné nabídky mnohem snadněji stanovit tyto dva samostatné režimy různých uživatelských rozhraní.Jak uvidíte dále, prostředek zcela samostatné nabídky se používá při úpravách vložený objekt na místě.
Pokud chcete vytvořit prostředek, načíst zdroj skriptu do Visual C++ a kopírování existující nabídky Zdroj IDR_HIERSVRTYPE.Přejmenujte nové zdroje na IDR_HIERSVRTYPE_SRVR_EMB (je to stejné konvenci, která používá AppWizard).Další změna "Uložit" na "Update soubor"; ID příkazu mu ID_FILE_UPDATE.Také "Uložit jako" změňte na "Uložit kopii jako"; ID příkazu mu ID_FILE_SAVE_COPY_AS.Rozhraní framework poskytuje implementaci obou těchto příkazů.
\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
Existuje několik chyb, které vyplývají z přepsané OnSetData, protože se vztahuje OLESTATUS typu.OLESTATUS byla tak OLE1 vrátila chyby.To změnil na HRESULT v OLE 2, ačkoli MFC obvykle převede HRESULT do COleException obsahující chybu.V tomto konkrétním případě přepsané OnSetData již není nutné, tak je nejjednodušší cesta k jeho odebrání.
\hiersvr\svritem.cpp(30) : error C2660: 'COleServerItem::COleServerItem' : function does not take 1 parameters
COleServerItem Konstruktor přebírá další parametr "BOOL".Tento příznak určuje, jak se provádí správa paměti COleServerItem objekty.Nastavit na hodnotu TRUE, zpracovává rámci správy paměti těchto objektů, jejich odstranění, pokud již nejsou potřeba.Používá HIERSVR CServerItem (odvozené z COleServerItem) objekty v rámci nativní data, takže tento příznak bude nastavena na hodnotu FALSE.To umožňuje určit při odstranění položky serveru 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
Jako následek těchto chyb, je "čistý virtuální funkce, které nebyly přepsány v CServerItem.Nejpravděpodobnější příčinou je skutečnost, že došlo ke změně seznamu parametrů prvku OnDraw.Chcete-li tuto chybu vyřešit, změňte CServerItem::OnDraw takto (včetně prohlášení v 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);
}
Nový parametr je "parametru rSize je".To umožňuje zadat velikost výkresu, pokud je to vhodné.Tato velikost musí být v HIMETRIC.V tomto případě není vhodné vyplnit tuto hodnotu, tak volá architektura OnGetExtent k načtení v rozsahu.Pro tuto práci, budete muset implementovat 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 *'
Ve funkci CServerItem::CalcNodeSize velikost položky je převedena na HIMETRIC a uložené v m_rectBounds.Nezdokumentovaný 'm_rectBounds' člen COleServerItem neexistuje (byl částečně nahrazen podle m_sizeExtent, ale má trochu jiné využití než tento člen OLE 2 m_rectBounds v OLE1).Namísto nastavení HIMETRIC velikost do této členské proměnné bude opět ji.Tato vrácená hodnota se používá v OnGetExtent, dříve implementováno.
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;
}
Také přepisuje CServerItem COleServerItem::OnGetTextData.Tato funkce je zastaralá v MFC/OLE a nahrazuje jiný mechanismus.Verze knihovny MFC 3.0 ukázkové knihovny MFC OLE HIERSVR implementuje tuto funkci přepsáním COleServerItem::OnRenderFileData.Tato funkce není důležité pro tento port základní, takže můžete odstranit přepsání OnGetTextData.
Existuje mnoho další chyby v svritem.cpp, které nezabývalo.Nejsou "reálný" chyby – pouze chyby způsobené předchozí chyby.
\hiersvr\svrview.cpp(325) : error C2660: 'CopyToClipboard' : function does not take 2 parameters
COleServerItem::CopyToClipboardjiž nepodporuje příznak "bIncludeNative".Nativní data (data vytvořené položky serveru funkci serializovatelnou) vždy zkopírován, tedy odebrat první parametr.Kromě toho CopyToClipboard vyvolá výjimku, když dojde k chybě namísto vrácení FALSE.Změňte kód pro CServerView::OnEditCopy takto:
void CServerView::OnEditCopy()
{
if (m_pSelectedNode == NULL)
AfxThrowNotSupportedException();
TRY
{
m_pSelectedNode->CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox("Copy to clipboard failed");
}
END_CATCH_ALL
}
I když existovaly další chyby vyplývající z kompilace verzi 2.0 knihovny MFC HIERSVR, než byly stejné verze OCLIENT, byly ve skutečnosti méně změn.
V tomto okamžiku HIERSVR bude kompilace a propojení a fungovat jako OLE server, ale bez funkce úprav na místě, která se uskuteční další.
Přidávání "Vizuální úpravy"
Pokud chcete přidat tento server aplikace "Vizuální úpravy" (nebo aktivaci na místě), existuje pouze několik věcí, které se musí starat o:
Potřebujete speciální nabídka prostředků použitých při položka je aktivní v místě.
Tato aplikace má panel nástrojů, takže budete potřebovat nástrojů obsahující pouze podmnožinu běžných nástrojů tak, aby odpovídala příkazy k dispozici na serveru (odpovídá výše uvedené nabídce zdroj).
Potřebujete novou třídu, odvozenou z COleIPFrameWnd , který poskytuje přímo v uživatelském rozhraní (podobně jako CMainFrame, odvozené z CMDIFrameWnd, poskytuje uživatelské rozhraní MDI).
Je třeba sdělit rámci o těchto zvláštních prostředků a třídy.
Nabídka zdrojů je snadné vytváření.Spustit Visual C++, Kopírovat zdroj nabídky IDR_HIERSVRTYPE k nabídce zdroj s názvem IDR_HIERSVRTYPE_SRVR_IP.V nabídce upravte tak, aby zůstaly pouze popups nabídky Úpravy a nápovědu.Přidat dva oddělovače do nabídky mezi nabídky Úpravy a nápovědy (by měl vypadat: úpravy || Nápověda).Další informace o významu těchto oddělovačů a způsob sloučení nabídky serveru a kontejner naleznete v tématu "Nabídek a zdroje: nabídka slučování" v Třídy OLE 2.
Rastrový obrázek pro podmnožinu nástrojů lze snadno vytvořit zkopírováním z čerstvého AppWizard generované aplikací s možností "Server" kontrolovat.Tento rastrový obrázek lze poté importovat do aplikace Visual C++.Nezapomeňte poskytnout rastrového obrázku ID IDR_HIERSVRTYPE_SRVR_IP.
Třídy odvozené z COleIPFrameWnd lze zkopírovat z aplikace s podporou serveru také generovány AppWizard.Zkopírujte oba soubory IPFRAME.CPP a IPFRAME.H a přidat je do projektu.Ujistěte se, že LoadBitmap odkazuje volání IDR_HIERSVRTYPE_SRVR_IP rastrového obrázku vytvořeného v předchozím kroku.
Teď, když jsou vytvářeny nové zdroje a třídy, přidejte nezbytné kód tak, aby v rámci ví o těchto (a ví, že tato aplikace nyní podporuje úpravy na místě).To lze provést přidáním další parametry, které mají SetServerInfo volat InitInstance funkce:
pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB,
IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame));
Je nyní připraven ke spuštění na místě v kontejneru, který také podporuje aktivaci na místě.Existuje ale jedna malá chyba v kódu stále skrývá.HIERSVR podporuje kontextové nabídky, která se zobrazí, když uživatel stiskne tlačítko myši.Tato nabídka platí při HIERSVR je plně otevřený, ale nefunguje při vkládání místní úpravy.Důvod lze přichytit na tento jediný řádek kódu v CServerView::OnRButtonDown:
pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
point.x, point.y, AfxGetApp()->m_pMainWnd);
Všimněte si odkaz na AfxGetApp() ->m_pMainWnd.Po aktivaci serveru se má hlavní okno je nastavena m_pMainWnd, ale je obvykle neviditelné.Navíc se zde odkazuje hlavní okno aplikace MDI okno rámce, který se zobrazí, pokud je server plně otevřít nebo spustit samostatné.Neodkazuje na aktivní okno, které na místě při aktivaci je snímek okno odvozené z COleIPFrameWnd.Chcete-li získat správné aktivního okna i v případě, že místní úpravy, tato verze knihovny MFC, přidává nové funkce, AfxGetMainWnd.Obecně byste měli použít tuto funkci namísto AfxGetApp() ->m_pMainWnd.Tento kód je třeba změnit následujícím způsobem:
pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
point.x, point.y, AfxGetMainWnd());
Nyní máte server OLE povolena minimálně pro funkční aktivaci na místě.Ale s MFC/OLE 2, které nebyly k dispozici v knihovně MFC/OLE1 přetrvávají mnoho funkcí.Viz ukázkové HIERSVR Další nápady na funkce, které chcete implementovat.Níže jsou uvedeny některé funkce, které implementuje HIERSVR:
Přiblížení pro true WYSISYG chování ve vztahu k nádobě.
Přetáhněte či přetažení a formát vlastní schránky.
Posouvání okna kontejneru podle výběru se změní.
Ukázkové HIERSVR v MFC 3.0 také používá mírně odlišný design pro své položky na serveru.To pomáhá šetřit paměť a umožňuje propojení více flexibilní.S verze 2.0 HIERSVR každý uzel ve stromu, a jeCOleServerItem. COleServerItemmá o něco větší režii, než je nezbytně nutné pro každý z těchto uzlů, ale COleServerItem je vyžadována pro každé aktivní odkaz.Ale z větší části jsou velmi málo aktivních odkazů v kterémkoli okamžiku.Aby to bylo účinnější, odděluje HIERSVR v této verzi knihovny MFC z uzlu COleServerItem.Má obě CServerNode a CServerItem třídy.CServerItem (odvozené z COleServerItem) je vytvořen pouze v případě potřeby.Jakmile kontejneru (nebo kontejnery) přestat používat tento konkrétní odkaz na příslušném uzlu, CServerItem objekt přidružený CServerNode se zrušuje.Tento návrh je efektivnější a flexibilnější.Jeho flexibilita při zacházení s odkazy pro výběr více.Ani jedna z těchto dvou verzí HIERSVR podporuje vícenásobný výběr, ale je mnohem jednodušší přidat (a odkazy na tyto výběry na podporu) s verzí MFC 3.0 HIERSVR, protože COleServerItem je oddělen od nativní data.