Questioni generali relative alla migrazione
Uno degli obiettivi di progettazione per le classi OLE 2 in MFC 2.5 (e superiori) doveva conservare gran parte della stessa architettura messa in atto in MFC 2.0 per supporto OLE 1.0. Come risultato, molte delle stesse classi OLE 2.0 MFC esistono ancora in questa versione di MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem). Inoltre, molte delle API in queste classi sono esattamente gli stessi. Tuttavia, OLE 2 è drasticamente diverso da OLE 1.0, quindi ci si può aspettare che alcuni dettagli sono cambiate. Se si ha familiarità con il supporto di OLE1 di MFC 2.0, vi sentirete a casa con supporto 2.0 di MFC.
Se siete prendendo un'applicazione MFC/OLE1 esistente e aggiungendo funzionalità OLE 2 a esso, dovrebbe leggere prima questa nota. Questa nota copre alcune questioni generali si può incontrare mentre il porting la funzionalità OLE1 a MFC/OLE 2 e poi discute i problemi scoperti mentre il porting di due applicazioni incluse in MFC 2.0: i campioni di OLE MFC OCLIENT e HIERSVR.
Architettura documento/vista MFC È importante
Se l'applicazione non utilizza l'architettura documento/visualizzazione di MFC e si desidera aggiungere supporto OLE 2 all'applicazione, ora è il tempo per passare al documento/vista. Molti dei vantaggi delle classi OLE 2 di MFC vengono realizzati solo una volta che l'applicazione utilizza l'architettura integrata e componenti di MFC.
L'implementazione di un server o un contenitore senza utilizzare l'architettura MFC è possibile, ma non è raccomandato.
Utilizzare MFC implementazione anziché il proprio
MFC ", in scatola implementazione" classi quali CToolBar, CStatusBare CScrollView hanno incorporato codice speciale case per supporto OLE 2. Così, se è possibile utilizzare queste classi nell'applicazione potrete beneficiare lo sforzo messo in loro per renderli OLE consapevoli. Ancora una volta, è possibile "roll-your-own" classi qui per questi scopi, ma non è suggerito. Se avete bisogno di implementare funzionalità simili, il codice sorgente MFC è un ottimo riferimento per affrontare alcuni dei punti più sottili di OLE (soprattutto quando si tratta di attivazione sul posto).
Esaminare il codice di esempio MFC
Ci sono un certo numero di esempi di MFC che includono funzionalità OLE. Ciascuna di queste applicazioni implementa OLE da una diversa angolazione:
HIERSVR - destinata principalmente all'utilizzo come un'applicazione server. È stato incluso in MFC 2.0 come un'applicazione MFC/OLE1 ed è stato portato su MFC/OLE 2 e poi esteso tale che implementa molte caratteristiche OLE disponibile in OLE 2.
OCLIENT - questa è un'applicazione stand-alone contenitore, lo scopo di dimostrare molte delle caratteristiche OLE da un punto di vista del contenitore. È troppo fu portato da MFC 2.0 e poi estesa a sostegno di molte delle funzionalità più avanzate OLE, quali formati personalizzati negli appunti e collegamenti a elementi incorporati.
DRAWCLI - questa applicazione implementa supporto del contenitore OLE molto come fa OCLIENT, salvo che lo fa nel quadro di un programma di disegno orientati agli oggetti esistente. Vi mostra come si potrebbe implementare il supporto per il contenitore OLE e integrarla in applicazione esistente.
SUPERPAD - questa applicazione, oltre ad essere un'applicazione stand-alone bene, è anche server OLE. Il supporto per il server che implementa è abbastanza minimalista. Di particolare interesse è come utilizza i servizi di appunti OLE per copiare i dati negli appunti, ma utilizza la funzionalità incorporata in Windows "modifica" controllo di implementare funzionalità incolla negli Appunti. Questo dimostra un interessante mix di uso tradizionale di API di Windows, nonché integrazione con le nuove API di OLE.
Per ulteriori informazioni sulle applicazioni di esempio, vedere "MFC campione Help".
Studio di caso: OCLIENT da MFC 2.0
Come discusso in precedenza, OCLIENT è stato incluso in MFC 2.0 e implementato OLE con MFC/OLE1. La procedura con cui inizialmente è stata convertita in questa applicazione per utilizzare le classi MFC/OLE 2 è descritte di seguito. Una serie di caratteristiche sono state aggiunte dopo la porta iniziale è stata completata per meglio illustrare le classi MFC/OLE. Queste caratteristiche non saranno coperti qui; fare riferimento al campione per ulteriori informazioni su queste funzionalità avanzate.
&Notanbsp; Gli errori del compilatore e la descrizione dettagliata del processo è stato creato con Visual C++ 2.0. Luoghi e messaggi di errore specifici possono essere cambiati con Visual C++ 4.0, ma le informazioni concettuali rimangano valide.
Esso alzarsi e in esecuzione
L'approccio adottato alla porta del campione OCLIENT MFC/OLE è avviare costruirlo e risolvendo gli errori del compilatore ovvio che si tradurrà. Se prendete l'esempio OCLIENT da MFC 2.0 e compilarlo con questa versione di MFC, troverete che ci sono errori che molti per risolvere. Gli errori nell'ordine in cui si sono verificati vengono descritte di seguito.
Compilazione e correggere gli errori
\oclient\mainview.cpp(104): errore C2660: 'Draw': funzione non prende 4 parametri
Il primo errore riguarda COleClientItem::Draw. In MFC/OLE1 ci sono voluti più parametri prende la versione MFC/OLE. Parametri extra spesso non erano necessarie e solitamente NULL (come in questo esempio). Questa versione di MFC può determinare automaticamente i valori per la lpWBounds quando il CDC che viene disegnato a è un DC metafile. Inoltre, il parametro pFormatDC non più è necessario dal momento che il quadro costruirà uno da "attributo DC" del passato in pDC. Modo per risolvere questo problema, semplicemente rimuovere i due extra NULL parametri della chiamata Draw.
\oclient\mainview.cpp(273): errore C2065: 'OLE_MAXNAMESIZE': identificatore non dichiarato
\oclient\mainview.cpp(273): errore C2057: prevista espressione costante
\oclient\mainview.cpp(280): errore C2664: 'CreateLinkFromClipboard': Impossibile convertire il parametro 1 da 'char [1]' a ' enum:: tagOLERENDER '
\oclient\mainview.cpp(286): errore C2664: 'CreateFromClipboard': Impossibile convertire il parametro 1 da 'char [1]' a ' enum:: tagOLERENDER '
\oclient\mainview.cpp(288): errore C2664: 'CreateStaticFromClipboard': Impossibile convertire il parametro 1 da 'char [1]' a ' enum:: tagOLERENDER '
Il fatto che tutte le funzioni COleClientItem::CreateXXXX in MFC/OLE1 richiesto che un nome univoco essere passati per rappresentare l'elemento si localizzano gli errori di cui sopra. Questo era un requisito del sottostante OLE API. Ciò non è necessario in MFC/OLE 2 Poiché OLE 2 non utilizza DDE come meccanismo di comunicazione sottostante (il nome è stato utilizzato nelle conversazioni DDE). Per risolvere questo problema, è possibile rimuovere la funzione CreateNewName così come tutti i riferimenti ad esso. È facile scoprire che cosa si aspetta ogni funzione MFC/OLE in questa versione semplicemente da posizionando il cursore sulla chiamata e premendo F1.
Un'altra area che è significativamente diversa è OLE 2 gestione negli Appunti. Con OLE1, è stato utilizzato negli Appunti di Windows che API di interagiscono con gli appunti. Con OLE 2 questo viene fatto con un meccanismo diverso. Le API di MFC/OLE1 presuppone che gli appunti era aperto prima di copiare un oggetto COleClientItem negli Appunti. Questo non è più necessario e farà sì che tutte le operazioni di appunti MFC/OLE a fallire. Mentre si modifica il codice per rimuovere le dipendenze su CreateNewName, si dovrebbe anche rimuovere il codice che si apre e chiude gli appunti di Windows.
\oclient\mainview.cpp(332): errore C2065: 'AfxOleInsertDialog': identificatore non dichiarato
\oclient\mainview.cpp(332): errore C2064: termine non restituisce una funzione
\oclient\mainview.cpp(344): errore C2057: prevista espressione costante
\oclient\mainview.cpp(347): errore C2039: 'CreateNewObject': non è un membro di 'CRectItem'
Questi errori causati dal gestore CMainView::OnInsertObject . La gestione il comando "Inserire il nuovo oggetto" è un'altra area dove le cose sono cambiate un po. In questo caso, è più facile unire semplicemente l'implementazione originale con quello fornito da creazione guidata applicazione per una nuova applicazione contenitore OLE. In realtà, questa è una tecnica che è possibile applicare al porting di altre applicazioni. In MFC/OLE1, è visualizzata la finestra di dialogo "Inserisci oggetto" chiamando la funzione AfxOleInsertDialog . In questa versione si costruisce un oggetto finestra di dialogo COleInsertObject e chiamare DoModal. Inoltre, nuovi oggetti OLE vengono creati con un CLSID anziché una stringa classname. Il risultato finale dovrebbe essere qualcosa di simile
COleInsertDialog dlg;
Se (dlg.DoModal()! = IDOK)
nbsp; ritorno;
BeginWaitCursor();
CRectItem * pItem = NULL;
PROVARE
{
/ / Prima di creare l'oggetto C++
pItem = GetDocument() - > CreateItem();
ASSERT_VALID(pItem);
/ / Initialize l'elemento dai dati della finestra di dialogo.
Se (! dlg.CreateItem(pItem))
AfxThrowMemoryException();
/ / qualsiasi eccezione farà
ASSERT_VALID(pItem);
/ / run dell'oggetto, se del caso
Se (dlg.GetSelectionType() = = COleInsertDialog::createNewItem)
pItem - > DoVerb(OLEIVERB_SHOW, this);
/ / Aggiorna subito
pItem - > UpdateLink();
pItem - > UpdateItemRectFromServer();
/ / imposta la selezione all'elemento appena inserita
SetSelection(pItem);
pItem - > Invalidate();
}
CATCH (CException, e)
{/ / ripulire elemento
Se (pItem! = NULL)
GetDocument() - > DeleteItem(pItem);
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
EndWaitCursor()
&Notanbsp; Inserisci nuovo oggetto può essere diverso per l'applicazione):
Esso è inoltre necessario includere lt;afxodlgs.h > che contiene la dichiarazione per la classe della finestra di dialogo COleInsertObject , così come le altre finestre standard fornite da MFC.
\oclient\mainview.cpp(367): errore C2065: 'OLEVERB_PRIMARY': identificatore non dichiarato
\oclient\mainview.cpp(367): errore C2660: 'DoVerb': funzione non accettano parametri 1
Questi errori sono causati dal fatto che alcune costanti OLE1 sono cambiati in OLE 2, anche se nel concetto sono lo stesso. In questo caso OLEVERB_PRIMARY è cambiato in OLEIVERB_PRIMARY. In OLE1 e OLE 2, il verbo primario viene solitamente eseguito da un contenitore quando l'utente fa doppio clic su un elemento.
Inoltre, DoVerb ora prende un parametro supplementare — un puntatore a una visualizzazione (CView*). Questo parametro viene utilizzato solo per implementare "Modifica visiva" (o attivazione sul posto). Per ora è impostare tale parametro su NULL, dal momento che non si implementa questa caratteristica in questo momento.
Per assicurarsi che il quadro mai tentativi di posto attivano, si dovrebbe ignorare le COleClientItem::CanActivate
BOOL CRectItem::Ca&nActivate()
{
nbsp; return FALSE;
}
\oclient\rectitem.cpp(53): errore C2065: 'GetBounds': identificatore non dichiarato
\oclient\rectitem.cpp(53): errore C2064: termine non restituisce una funzione
\oclient\rectitem.cpp(84): errore C2065: 'SetBounds': identificatore non dichiarato
\oclient\rectitem.cpp(84): errore C2064: termine non restituisce una funzione
In MFC/OLE1, COleClientItem::GetBounds e SetBounds furono utilizzate per eseguire query e modificare l'estensione di un elemento (i membri di sinistra e top erano sempre zero). MFC/OLE 2 più direttamente questo è supportato da COleClientItem::GetExtent e SetExtent, che si occupano di una dimensione o CSize invece.
Il codice per il vostro nuovo SetItemRectToServer, e UpdateItemRectFromServer chiamate questo aspetto:
BOOL CRectItem::UpdateItemRectFromServer()
{
nbsp; Assert(m_bTrackServerSize);
CSize dimensioni;
if (!.GetExtent(&size))
return FALSE; / / bianco
/ / map da HIMETRIC a coordinate dello schermo
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.LPtoDP(&size);
}
/ / imposta solo la dimensione dell'elemento
Se (m_rect.Size()! = size)
{
/ / invalidare la vecchia dimensione/posizione
Invalidate();
m_rect.Right = m_rect.left + size.cx;
m_rect.Bottom = m_rect.top + size.cy;
/ / così come la nuova dimensione/posizione
Invalidate();
}
return TRUE;
}
BOOL CRectItem::SetItemRectToServer()
{
/ / imposta i limiti ufficiali per l'elemento incorporato
Dimensioni CSize = m_rect.Size();
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.DPtoLP(&size);
}
PROVARE
{
SetExtent(size); / / può fare un'attesa
}
CATCH (CException, e)
{
return FALSE; / / link non permetterà SetBounds
}
END_CATCH
return TRUE;
}
\oclient\frame.cpp(50): errore C2039: 'InWaitForRelease': non è un membro di 'COleClientItem'
\oclient\frame.cpp(50): errore C2065: 'InWaitForRelease': identificatore non dichiarato
\oclient\frame.cpp(50): errore C2064: termine non restituisce una funzione
In MFC/OLE1 sincrone chiamate API da un contenitore a un server sono stati simulati, poiché OLE1 era intrinsecamente asincrona in molti casi. È stato necessario controllare per una chiamata asincrona eccezionale in corso prima di elaborare i comandi da parte dell'utente. MFC/OLE1 fornito la funzione COleClientItem::InWaitForRelease per farlo. MFC/OLE 2, questo non è necessario, così si può rimuovere l'override di OnCommand in CMainFrame tutti insieme.
A questo punto OCLIENT si compila e si collega.
Altre modifiche necessarie
Ci sono alcune cose che non sono fatto che manterrà OCLIENT da corsa, tuttavia. È meglio risolvere questi problemi anziché ora.
Prima di tutto è necessario inizializzare le librerie OLE. Questo è fatto chiamando AfxOleInit da InitInstance:
if (!.AfxOleInit())
{
AfxMessageBox ("Impossibile inizializzare le librerie OLE");
return FALSE;
}
Essa è anche una buona idea per controllare le funzioni virtuali per le modifiche di elenco di parametri. Una tale funzione è COleClientItem::OnChange, sottoposto a override in ogni applicazione contenitore OLE/MFC. Guardando la guida in linea, vedrete che è stato aggiunto un ulteriore 'DWORD dwParam'. Il nuovo CRectItem::OnChange appare come segue
void CRectItem::OnChange (OLE_NOTIFICATION wNotification, DWORD dwParam)
{
Se (m_bTrackServerSize amp; &
!UpdateItemRectFromServer())
{
/ / Oggetto in bianco
Se (wNotification = = OLE_CLOSED)
{
/ / no dati ricevuti per l'oggetto - distruggerlo
AFFERMARE (!.IsVisible());
GetDocument() - > DeleteItem(this);
ritorno; / / nessun aggiornamento (elemento è andata ora)
}
}
Se (wNotification! = OLE_CLOSED)
Dirty();
Invalidate(); / / qualsiasi cambiamento causerà un ridisegno
}
In MFC/OLE1, applicazioni contenitore derivano la classe documento da COleClientDoc. MFC/OLE 2 questa classe è stato rimossa e sostituita da COleDocument (questa nuova organizzazione rende più facile costruire applicazioni contenitore/server). C'è un # define che esegue il mapping tra COleClientDoc e COleDocument per semplificare il porting di applicazioni MFC/OLE1 a MFC/OLE 2, come ad esempio OCLIENT. Una delle caratteristiche non fornite da COleDocument che è stato fornito da COleClientDoc è le voci della mappa messaggio comando standard. Questo viene fatto in modo che le applicazioni server, che utilizzano anche COleDocument (indirettamente), non portare con sé il sovraccarico di questi gestori di comandi a meno che siano un'applicazione contenitore/server. Così, è necessario aggiungere le seguenti voci per la mappa di messaggi 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)
L'implementazione di tutti questi comandi è in COleDocument, che è la classe base per il documento.
A questo punto, OCLIENT è una funzionale applicazione contenitore OLE. È possibile inserire oggetti di qualsiasi tipo (OLE1 o OLE 2). Poiché non viene implementato il codice necessario per consentire l'attivazione sul posto, gli elementi vengono modificati in una finestra separata molto simile con OLE1. La prossima sezione discute le modifiche necessarie per consentire la modifica sul posto (a volte chiamato "Modifica visiva").
Aggiunta di "Modifica visiva"
Una delle caratteristiche più interessanti di OLE è attivazione sul posto (o "Modifica visiva"). Questa funzione consente all'applicazione server di prendere sulle parti dell'interfaccia utente del contenitore a fornito un interfaccia di modifica più trasparente per l'utente. Per implementare l'attivazione sul posto a OCLIENT, alcune risorse speciali devono essere aggiunto, così come il codice aggiuntivo. Queste risorse e codice sono normalmente forniti da AppWizard — infatti, gran parte del codice qui venne presa in prestito direttamente da un'applicazione di creazione guidata applicazione fresca con il supporto di "Contenitore".
Prima di tutto, è necessario aggiungere una risorsa di menu per essere usato quando c'è un elemento che è attivo sul posto. È possibile creare questa risorsa dal menu extra in Visual C++ copiando la risorsa IDR_OCLITYPE e rimozione di tutti, ma il File e la finestra pop-up. Due barre separatrici vengono inserite tra le File e la finestra pop-up per indicare la separazione dei gruppi (dovrebbe assomigliare: File | | Finestra). Per ulteriori informazioni su che cosa significano questi separatori e come i server e contenitore menu vengono Uniti vedere "Menu e risorse: Unione di Menu" nelle Classi OLE 2.
Una volta che avete questi menu creati, è necessario fare il quadro sapere su di loro. Ciò avviene mediante la chiamata a SetContainerInfo per il modello di documento prima di aggiungerlo all'elenco dei modelli di documento nel tuo InitInstance. Il nuovo codice per registrare il modello di documento assomiglia a questo
CDocTemplate * pTemplate = nuova (CMultiDocTemplate
nbsp; IDR_OLECLITYPE,
RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd), / / standard cornice figlio MDI
RUNTIME_CLASS(CMainView));
pTemplate - > SetContainerInfo(IDR_OLECLITYPE_INPLACE);
AddDocTemplate(pTemplate)
La risorsa IDR_OLECLITYPE_INPLACE è la risorsa sul posto speciale creata in Visual C++.
Al fine di consentire l'attivazione sul posto, ci sono alcune cose che hanno bisogno di cambiare in entrambe le CView (CMainView) derivato di classe, nonché la classe COleClientItem derivati (CRectItem). Tutte queste sostituzioni sono fornite da AppWizard e la maggior parte dell'implementazione verrà direttamente da un'applicazione di creazione guidata applicazione predefinita.
Il primo passo di questo porto, attivazione sul posto è stato disabilitato interamente eseguendo l'override di COleClientItem::CanActivate. Questo override deve essere rimosso per consentire l'attivazione sul posto. Inoltre, NULL è stato passato tutte le chiamate a DoVerb (ci sono due di loro) perché fornendo che la vista solo era necessaria per l'attivazione sul posto. Per implementare completamente attivazione sul posto, è necessario passare la corretta visione nella chiamata DoVerb . Una di queste chiamate è in CMainView::OnInsertObject
pItem-> DoVerb(OLEIVERB_SHOW, this)
Un altro è in CMainView::OnLButtonDblClk
>-m_pSelection; DoVerb(OLEIVERB_PRIMARY, this)
È necessario eseguire l'override di COleClientItem::OnGetItemPosition. Questo dice il server dove mettere la sua finestra relativo alla finestra del contenitore quando l'elemento è attivato sul posto. Per OCLIENT, l'implementazione è banale
public st&atic void CRectItem::OnGetItemPosition (CRectamp; rPosition)
{
rPosition = m_rect;
}
Maggior parte dei server implementare anche quello che viene chiamato "sul posto ridimensionamento." In questo modo la finestra del server essere di dimensioni e spostati mentre l'utente sta modificando l'elemento. Il contenitore deve partecipare a questa azione, dato che lo spostamento o il ridimensionamento della finestra di solito colpisce la posizione e la dimensione nel documento contenitore stesso. L'implementazione per OCLIENT sincronizza il rettangolo interno gestito da m_rect con la nuova posizione e la dimensione.
BOOL CRectItem::OnChangeItemPosition(const CRectamp; rectPos)
{
ASSERT_VALID(this);
if (!.COleClientItem::OnChangeItemPosition(rectPos))
return FALSE;
Invalidate();
m_rect = rectPos;
Invalidate();
GetDocument() - > SetModifiedFlag();
return TRUE;
}
A questo punto, non c'è abbastanza codice per consentire un elemento per essere attivato sul posto e di trattare con il ridimensionamento e lo spostamento dell'elemento quando è attivo, ma non non c'è nessun codice che permetterà all'utente di uscire la sessione di modifica. Anche se alcuni server fornirà questa funzionalità se stessi mediante la gestione della chiave di fuga, è suggerito che contenitori forniscano disattivare un elemento in due modi: (1) facendo clic di fuori dell'elemento e (2) premendo il tasto di fuga.
Per la fuga ID_CANCEL_EDIT chiave aggiungere un acceleratore con Visual C++ che esegue il mapping a un comando, la chiave VK_ESCAPE viene aggiunto alle risorse. Il gestore per questo comando segue:
/ / Gestore comando seguente fornisce lo standard
/ / tastiera interfaccia utente per annullare sul posto
/ / modifica session.void CMainView::OnCancelEdit()
{
nbsp; / / Chiudere qualsiasi elemento attivo sul posto su questo punto di vista.
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Se (pActiveItem! = NULL)
pActiveItem - > Close ();
Assert(GetDocument()-> GetInPlaceActiveItem(this) = = NULL);
}
Per gestire il caso in cui l'utente seleziona l'elemento di fuori, aggiungere il codice seguente all'inizio del CMainView::SetSelection
se (pNewSel! = m_pSelection | | pNewSel = = NULL)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Se (pActiveItem! = NULL & & pActiveItem! = pNewSel)
pActiveItem - > Close ();
}
& nbsp
Quando un elemento è attivo sul posto, dovrebbe avere lo stato attivo. Per assicurarsi che questo è il caso si gestire OnSetFocus in modo che la messa a fuoco è sempre trasferita all'elemento attivo quando riceve il vostro punto di vista del fuoco:
/ / Gestione speciale di OnSetFocus e OnSize sono necessari / / quando un oggetto viene modificato sul posto.
public static void CMainView::OnSetFocus (CWnd pOldWnd)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Se (pActiveItem! = NULL & &
pActiveItem - > GetItemState() = = COleClientItem::activeUIState)
{
/ / necessario impostare lo stato attivo a questo elemento se è la stessa vista
CWnd * pWnd = pActiveItem - > GetInPlaceWindow();
Se (pWnd! = NULL)
{
pWnd - > SetFocus; / / non chiamare la classe base
ritorno;
}
}
CView::OnSetFocus(pOldWnd);
}
Quando viene ridimensionata la visualizzazione, è necessario notificare l'elemento attivo che ha cambiato il rettangolo di ritaglio. A tale scopo fornire un gestore per OnSize:
public static void CMainView::OnSize (UINT nType, int cx, int cy)
{
nbsp; CView::OnSize (nType, cx, cy);
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Se (pActiveItem! = NULL)
pActiveItem - > SetItemRects();
}
Studio di caso: HIERSVR da MFC 2.0
HIERSVR è stato anche incluso in MFC 2.0 e implementato OLE con MFC/OLE1. Questa nota viene brevemente descritto la procedura con cui inizialmente è stata convertita in questa applicazione per utilizzare le classi MFC/OLE 2. Una serie di caratteristiche sono state aggiunte dopo la porta iniziale è stata completata per meglio illustrare le classi MFC/OLE 2. Queste caratteristiche non saranno coperti qui; fare riferimento al campione per ulteriori informazioni su queste funzionalità avanzate.
&Notanbsp; Gli errori del compilatore e la descrizione dettagliata del processo è stato creato con Visual C++ 2.0. Luoghi e messaggi di errore specifici possono essere cambiati con Visual C++ 4.0, ma le informazioni concettuali rimangano valide.
Esso alzarsi e in esecuzione
L'approccio adottato alla porta del campione HIERSVR MFC/OLE è avviare costruirlo e risolvendo gli errori del compilatore ovvio che si tradurrà. Se prendete l'esempio HIERSVR da MFC 2.0 e compilarlo con questa versione di MFC, troverete che ci sono molti errori di risolvere (anche se ci sono più che con l'esempio OCLIENT). Gli errori nell'ordine in cui si verificano di solito vengono descritte di seguito.
Compilazione e correggere gli errori
\hiersvr\hiersvr.cpp(83): errore C2039: 'RunEmbedded': non è un membro di 'COleTemplateServer'
Questo primo errore rileva un problema molto più grande con la funzione InitInstance per i server. L'inizializzazione necessaria per server OLE è probabilmente uno dei cambiamenti più grandi che si deve fare per l'applicazione MFC/OLE1 per farlo funzionare. La cosa migliore da fare è guardare a ciò che la creazione guidata applicazione crea per server OLE e modificare il codice in modo appropriato. Qui ci sono alcuni punti da tenere a mente:
È necessario inizializzare le librerie OLE chiamando AfxOleInit
Chiamare SetServerInfo sull'oggetto modello di documento per impostare il server risorsa maniglie e informazioni sulla classe di runtime non è possibile impostare con il costruttore CDocTemplate.
Non mostrare la finestra principale dell'applicazione se /Embedding è presente sulla riga di comando.
Avrete bisogno di un GUID per il documento. Questo è un identificatore univoco per il tipo del documento (128 bit). Creazione guidata applicazione creerà uno per voi — così se si utilizza la tecnica descritta qui di copiare il nuovo codice da una nuova applicazione server AppWizard generato, si può semplicemente "rubare" il GUID da quell'applicazione. In caso contrario, è possibile utilizzare la GUIDGEN.Utilità EXE nella directory BIN.
È necessario "collegare" l'oggetto COleTemplateServer per il modello di documento chiamando COleTemplateServer::ConnectTemplate.
Aggiorna il Registro di sistema quando l'esecuzione dell'applicazione stand-alone. In questo modo, se l'utente sposta il.EXE per la vostra applicazione, eseguendolo dalla sua nuova posizione aggiornerà il database di registrazione di sistema di Windows per puntare al nuovo percorso.
Dopo l'applicazione di tutti questi cambiamenti basati su ciò che la creazione guidata applicazione crea per InitInstance, InitInstance (e relativi GUID) per HIERSVR dovrebbe leggere come segue:
// 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;
}
Si noterà che il codice di cui sopra si riferisce a un nuovo ID di risorsa, IDR_HIERSVRTYPE_SRVR_EMB. Questa è la risorsa di menu da utilizzare quando viene modificato un documento che è incorporato in un altro contenitore. In MFC/OLE1 sono state modificate le voci di menu specifiche per la modifica di un elemento incorporato al volo. Utilizzando una struttura di menu completamente diverso quando si modifica un elemento incorporato invece di modifica un documento basato su file rende molto più facile per fornire interfacce utente diverso per queste due modalità separata. Come si vedrà più avanti, una risorsa completamente separati dal menu viene utilizzata quando si modifica un oggetto incorporato sul posto.
Per creare questa risorsa, caricare lo script di risorsa in Visual C++ e copia della risorsa di menu IDR_HIERSVRTYPE esistente. Rinominare la nuova risorsa IDR_HIERSVRTYPE_SRVR_EMB (questa è la stessa convenzione di denominazione che utilizza AppWizard). Successivamente modificare "Salva File" in "File Update"; Dategli un ID di comando ID_FILE_UPDATE. Anche modificare "File Salva come" in "File Salva copia come"; Dategli un ID di comando ID_FILE_SAVE_COPY_AS. Il framework fornisce l'implementazione di entrambi questi comandi.
\hiersvr\svritem.h(60): errore C2433: 'OLESTATUS': 'virtuale' non consentito in dichiarazioni di dati
\hiersvr\svritem.h(60): errore C2501: 'OLESTATUS': mancano gli specificatori di decl
\hiersvr\svritem.h(60): errore C2146: errore di sintassi: manca ';' prima ' identificatore 'OnSetData'
\hiersvr\svritem.h(60): errore C2061: errore di sintassi: identificatore 'OLECLIPFORMAT'
\hiersvr\svritem.h(60): errore C2501: 'OnSetData': mancano gli specificatori di decl
Ci sono un certo numero di errori risultanti dall'override di OnSetData, dal momento che si riferisce al tipo di OLESTATUS . OLESTATUS era il modo che OLE1 restituiti errori. Questo è cambiato a HRESULT OLE 2, sebbene MFC solitamente converte un HRESULT in un COleException che contiene l'errore. In questo caso particolare, l'override di OnSetData non è più necessario, quindi la cosa più semplice da fare è quello di rimuoverlo.
\hiersvr\svritem.cpp(30): errore C2660: 'COleServerItem::COleServerItem': funzione non accettano parametri 1
Il costruttore COleServerItem accetta un parametro supplementare "BOOL". Questo flag determina come la gestione della memoria è fatto sugli oggetti COleServerItem . Impostandola su TRUE, il framework gestisce la gestione della memoria di questi oggetti — eliminandoli quando non sono più necessarie. HIERSVR utilizza CServerItem (derivata da COleServerItem) oggetti come parte dei relativi dati nativi, potrai impostare questo flag su FALSE. In questo modo HIERSVR determinare quando viene eliminato ogni elemento server.
\hiersvr\svritem.cpp(44): errore C2259: 'CServerItem': tentativo illegale per istanziare la classe astratta
\hiersvr\svritem.cpp(44): errore C2259: 'CServerItem': tentativo illegale per istanziare la classe astratta
Come implicano questi errori, ci sono alcune funzioni 'puri virtuale' che non sono stato eseguito l'override in CServerItem. Molto probabilmente questo è causato dal fatto che ha cambiato l'elenco di parametri di OnDraw. Per correggere questo errore, modificare CServerItem::OnDraw come segue (così come la dichiarazione in svritem.h)
BOOL CServerItem::OnDraw(CDC* pDC, CSizeamp; rSize)
{
/ / richiesta da OLE per disegnare il nodo
pDC - > SetMapMode(MM_TEXT); / / sempre in pixel
return DoDraw (pDC, CPoint(0,0), FALSE);
}
Il nuovo parametro è 'rSize'. Ciò consente di compilare le dimensioni del disegno, se conveniente. Questa dimensione deve essere HIMETRIC. In questo caso, esso non è conveniente riempire questo valore, pertanto il framework chiama OnGetExtent per recuperare la misura. Per questo al lavoro, sarà necessario implementare OnGetExtent:
BOOL CServerItem::OnGetExtent(DV&ASPECT dwDrawAspect, CSizeamp; rSize)
{
Se (dwDrawAspect! = DVASPECT_CONTENT)
return COleServerItem::OnGetExtent (dwDrawAspect, rSize);
rSize = CalcNodeSize();
return TRUE;
}
\hiersvr\svritem.cpp(104): errore C2065: 'm_rectBounds': identificatore non dichiarato
\hiersvr\svritem.cpp(104): errore C2228: sinistra del '.SetRect' deve avere un tipo classe, struttura o Unione
\hiersvr\svritem.cpp(106): errore C2664: ' void __pascal __far DPtoLP (struct:: tagPOINT __far *, int) __far const ': non è possibile convertire il parametro 1 da ' int __far *' a ' struct:: tagPOINT __far *'
Nella CServerItem::CalcNodeSize funzione delle dimensioni dell'elemento viene convertita in HIMETRIC e memorizzati in m_rectBounds. Il membro non documentati 'm_rectBounds' COleServerItem non esiste (è stato parzialmente sostituito da m_sizeExtent, ma in OLE 2 questo membro ha un utilizzo leggermente diverso in quanto m_rectBounds fece nel OLE1). Anziché impostare le dimensioni HIMETRIC in questa variabile membro, potrai restituirlo. Il valore restituito viene utilizzato in OnGetExtent, implementata in precedenza.
CSize CServerItem::CalcNodeSize()
{
nbsp; CClientDC dcScreen(NULL);
m_sizeNode = dcScreen.GetTextExtent (m_strDescription,
m_strDescription.GetLength());
m_sizeNode + = CSize (CX_INSET * 2, CY_INSET * 2);
/ / imposta la dimensione HIMETRIC suggeriti
Dimensioni CSize (m_sizeNode.cx, m_sizeNode.cy);
dcScreen.SetMapMode(MM_HIMETRIC);
dcScreen.DPtoLP(&size);
restituire dimensioni;
}
CServerItem esegue l'override COleServerItem::OnGetTextData. Questa funzione è obsoleta in MFC/OLE e viene sostituita da un meccanismo diverso. La versione 3.0 di MFC dell'esempio OLE di MFC HIERSVR implementa questa funzionalità eseguendo l'override di COleServerItem::OnRenderFileData. Questa funzionalità non è importante per questa porta di base, così è possibile rimuovere l'override OnGetTextData.
Ci sono molti più errori in svritem.cpp che non sono state affrontate. Essi non sono errori "reale" — pochi errori causati da errori precedenti.
\hiersvr\svrview.cpp(325): errore C2660: 'CopyToClipboard': funzione non prende 2 parametri
COleServerItem::CopyToClipboard non supporta più il flag 'bIncludeNative'. Dei dati nativi (i dati scritti da funzione Serialize dell'elemento server) viene sempre copiati, così rimuovere il primo parametro. Inoltre, CopyToClipboard genererà un'eccezione quando si verifica un errore anziché restituire FALSE. Modificare il codice per CServerView::OnEditCopy come segue
public static void CServerView::OnEditCopy()
{
nbsp; Se (m_pSelectedNode = = NULL)
AfxThrowNotSupportedException();
PROVARE
{
m_pSelectedNode - > CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox ("copia negli Appunti non riuscita");
}
END_CATCH_ALL}
Anche se ci fossero più errori risultanti dalla compilation della versione 2.0 di MFC di HIERSVR che non c'erano per la stessa versione di OCLIENT, c'erano in realtà meno modifiche.
A questo punto HIERSVR compilerà e collegare e funzionare come server OLE, ma senza la funzionalità di modifica sul posto, che sarà attuata successivamente.
Aggiunta di "Modifica visiva"
Per aggiungere questa applicazione server "Modifica visiva" (o attivazione sul posto), ci sono solo alcune cose, di che si deve prendere cura:
Della risorsa di menu è facile creare. Eseguire Visual C++, copia della risorsa di menu IDR_HIERSVRTYPE a una risorsa dal menu chiamata IDR_HIERSVRTYPE_SRVR_IP. Modificare il menu in modo che solo i popups di dal menu Modifica e aiuto sono di sinistra. Aggiungere due separatori al menu tra i menu Modifica e aiuto (dovrebbe assomigliare: Edit | | Aiuto). Per ulteriori informazioni su che cosa significano questi separatori e come vengono Uniti i menu di server e container, vedere "Menu e risorse: Unione di Menu" nelle Classi OLE 2.
La bitmap per la barra degli strumenti del sottoinsieme può essere creata facilmente copiando quello da un nuovo ricorso AppWizard generato con l'opzione "Server" controllata. Questa bitmap può quindi essere importata in Visual C++. Essere sicuri di dare la bitmap un ID di IDR_HIERSVRTYPE_SRVR_IP.
La classe derivata da COleIPFrameWnd può essere copiata da un'applicazione di creazione guidata applicazione generata con supporto server pure. Copiare entrambi i file, IPFRAME.CPP e IPFRAME.H e aggiungerli al progetto. Assicurarsi che la chiamata di LoadBitmap si riferisce al IDR_HIERSVRTYPE_SRVR_IP, la bitmap creata nel passaggio precedente.
Ora che tutte le nuove risorse e classi vengono create, aggiungere il codice necessario affinché il quadro conosce queste (e si sa che questa applicazione ora supporta la modifica sul posto). Questo è fatto con l'aggiunta di che alcuni ulteriori parametri per il SetServerInfo chiamano la funzione InitInstance:
pDocTemplate->SetServerInfo (IDR_HIERSVRTYPE_SRVR_EMB,
IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame))
Ora è pronto per essere eseguito sul posto in qualsiasi contenitore che supporta anche l'attivazione sul posto. Ma, c'è un bug minori ancora in agguato nel codice. HIERSVR supporta un menu di scelta rapida visualizzato quando l'utente preme il pulsante destro del mouse. Questo menu funziona quando HIERSVR è completamente aperta, ma non funziona quando si modifica un incorporamento sul posto. Il motivo può essere inchiodato a questa sola riga di codice in CServerView::OnRButtonDown
pMenu-gt;TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetApp() - > m_pMainWnd)
Si noti il riferimento a (AfxGetApp)-gt; m_pMainWnd. Quando il server viene attivato sul posto, ha una finestra principale e m_pMainWnd è impostato, ma è di solito invisibili. Inoltre, questa finestra si riferisce alla finestra principale dell'applicazione, la finestra cornice MDI che appare quando il server è completamente aperto o eseguito in modalità autonoma. Non si riferisce alla finestra frame attivo — che quando sul posto attivato è una finestra cornice derivata da COleIPFrameWnd. Per ottenere la corretta finestra attiva anche quando sul posto di editing, questa versione di MFC aggiunge una nuova funzione, AfxGetMainWnd. In generale, è opportuno utilizzare questa funzione anziché AfxGetApp() - > m_pMainWnd. Questo codice deve cambiare come segue:
pMenu-gt;TrackPopupMenu(TPM_CENTERALI&GN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetMainWnd())
Ora avete un server OLE minimamente abilitato per attivazione funzionale sul posto. Ma ci sono ancora molte funzionalità disponibili con MFC/OLE 2 che non erano disponibili in MFC/OLE1. Vedere l'esempio HIERSVR per ulteriori idee sulle caratteristiche si potrebbe desidera implementare. Alcune delle caratteristiche che implementa HIERSVR sono elencate di seguito:
L'esempio HIERSVR in MFC 3.0 utilizza anche un design leggermente diverso per i relativi elementi di server. Questo aiuta a risparmiare memoria e rende più flessibile il vostro link. Con la versione 2.0 di HIERSVR ogni nodo della struttura è un COleServerItem. COleServerItem porta un po' più sovraccarico di quanto strettamente necessario per ciascuno di questi nodi, ma un COleServerItem è necessaria per ogni link attivo. Ma per la maggior parte, ci sono pochissimi link attivi in un determinato momento. Per rendere più efficiente, HIERSVR in questa versione di MFC separa il nodo dalla COleServerItem. Esso ha sia una CServerNode e una classe CServerItem . CServerItem (derivata da COleServerItem) nasce come necessario. Una volta che il contenitore (o contenitori) smettere di usare quel particolare link a quel nodo particolare, viene eliminato l'oggetto CServerItem connesso con il CServerNode. Questo disegno è più efficiente e più flessibile. La flessibilità è disponibile in quando si lavora con più collegamenti di selezione. Nessuna di queste due versioni di HIERSVR supporta la selezione multipla, ma sarebbe molto più facile per aggiungere (e per sostenere i collegamenti a tali selezioni) con la versione 3.0 di MFC di HIERSVR, dal momento che il COleServerItem è separato dei dati nativi.
&Note tecniche per numero |nbsp; Note tecniche per la categoria