TN065: Supporto di interfaccia duale per i server di automazione OLE

Questa nota viene illustrato come aggiungere il supporto per interfaccia duale a un'applicazione server basata su MFC automazione OLE. La esempio ACDUAL viene illustrato il supporto di interfaccia duale, e il codice di esempio in questa nota è preso da ACDUAL. Le macro descritte in questa nota, come ad esempio DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , e IMPLEMENT_DUAL_ERRORINFO , fanno parte del campione ACDUAL e può essere trovato in MFCDUAL.H.

Interfacce duali

Anche se l'automazione OLE consente di implementare un'interfaccia IDispatch , un'interfaccia VTBL o un'interfaccia duale (che abbraccia entrambi), Microsoft consiglia vivamente implementare interfacce duali per tutti gli oggetti esposti di automazione OLE. Interfacce duali hanno vantaggi significativi rispetto IDispatch-interfacce sola o VTBL:

Aggiunta del supporto di interfaccia duale a una classe basata su CCmdTarget

Un'interfaccia duale è davvero solo un'interfaccia personalizzata derivata da IDispatch. Il modo più semplice per implementare il supporto di interfaccia duale in un CCmdTarget-classe base è quello di implementare prima la spedizione normale interfaccia sulla vostra classe usando MFC e ClassWizard, quindi aggiungere l'interfaccia personalizzata in seguito. Per la maggior parte, l'implementazione dell'interfaccia personalizzata delegherà semplicemente indietro per l'implementazione di IDispatch MFC.

In primo luogo, modificare il file ODL per il tuo server definire le interfacce duali per gli oggetti. Per definire un'interfaccia duale, è necessario utilizzare un'istruzione interface, anziché il DISPINTERFACE istruzione che generano le procedure guidate di Visual C++. Piuttosto che rimuovere l'esistente DISPINTERFACE dichiarazione, aggiungere una nuova dichiarazione di interfaccia. Mantenendo la DISPINTERFACE forma, è possibile continuare a utilizzare ClassWizard per aggiungere proprietà e metodi per l'oggetto, ma deve aggiungere metodi e le proprietà equivalente all'istruzione interfaccia.

Un'istruzione interface per un'interfaccia duale deve avere gli attributi DUAL e OLEAUTOMATION , e l'interfaccia deve essere derivato da IDispatch. È possibile utilizzare la esempio GUIDGEN per creare un IID per l'interfaccia duale

[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), / / IID_IDualAClick
   oleautomation,
   Dual
]
interfaccia IDualAClick: IDispatch
  {
  }

Una volta che avete l'istruzione interface in luogo, iniziare ad aggiungere voci per i metodi e le proprietà. Per le interfacce duali, è necessario ridisporre gli elenchi di parametri in modo che i metodi e le funzioni di accesso di proprietà nell'interfaccia dual restituiscono un HRESULT e passano i loro valori restituiti come parametri con gli attributi [retval,out] . Ricordate che per le proprietà, sarà necessario aggiungere sia una lettura ( propget ) e scrivere ( propput ) accedere alla funzione con lo stesso id. Ad esempio:

[propput, id(1)] Testo HRESULT ([in] BSTR newText);
[propget, id(1)] Testo HRESULT ([out, retval] BSTR * retval)

Dopo aver definito i metodi e le proprietà, è necessario aggiungere un riferimento per l'istruzione interface nell'istruzione coclasse. Ad esempio:

[uuid(4B115281-32F0-11cf-AC85-444553540000)]
Coclasse docume&nto
{
 nbsp; interfaccia dispatch IAClick;
   interfaccia [default] IDualAClick;
}

Una volta è stato aggiornato il file ODL, utilizzare il meccanismo di mappa interfaccia di MFC per definire una classe di implementazione per l'interfaccia duale nella classe di oggetto e rendere le voci corrispondenti nel meccanismo di QueryInterface di MFC. Bisogno di una voce nel INTERFACE_PART blocco per ogni voce l'istruzione interface dell'ODL, più le voci relative a un'interfaccia dispatch. Ogni voce ODL con l'attributo propput ha bisogno di una funzione denominata put_propertyname . Ogni voce con l'attributo propget ha bisogno di una funzione denominataget_propertyname.

Per definire una classe di implementazione per l'interfaccia duale, aggiungere un DUAL_INTERFACE_PART blocco alla definizione della classe oggetto. Ad esempio:

BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)
  STDMETHOD(put_text) (THIS_ BSTR newText);
  STDMETHOD(get_Text) (THIS_ BSTR estremo * retval);
  STDMETHOD(put_x) (THIS_ breve newX);
  STDMETHOD(get_X) (THIS_ breve estremo * retval);
  STDMETHOD(put_y) (THIS_ breve newY);
  STDMETHOD(get_Y) (THIS_ breve estremo * retval);
  STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint estremo * newPosition);
  STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint estremo * FAR * retval);
  STDMETHOD(RefreshWindow)(this);
  STDMETHOD(SetAllProps) (THIS_ breve x, y breve, testo BSTR);
  STDMETHOD(ShowWindow)(this);
END_DUAL_INTERFACE_PART(DualAClick)

A cui connettersi interfaccia duale di MFC meccanismo QueryInterface , aggiungere un INTERFACE_PART voce per la mappa dell'interfaccia

BEGIN_INTERFACE_MAP (CAutoClickDoc, CDocument)
  INTERFACE_PART (CAutoClickDoc, DIID_IAClick, Dispatch)
  INTERFACE_PART (CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()

Successivamente, è necessario compilare l'implementazione dell'interfaccia. Per la maggior parte, sarete in grado di delegare all'implementazione MFC IDispatch esistente. Ad esempio:

STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::AddRef()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::Release()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalRelease();
}
STDMETHODIMP CAutoClickDoc::XDualAClick::QueryInterface(
             REFIID iid, LPVOID* ppvObj)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfoCount(
            UINT FAR* pctinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfoCount(pctinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfo(
          UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetIDsOfNames(
       REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
       LCID lcid, DISPID FAR* rgdispid) 
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames, 
                                    lcid, rgdispid);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::Invoke(
    DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
    DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
    EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->Invoke(dispidMember, riid, lcid,
                             wFlags, pdispparams, pvarResult,
                             pexcepinfo, puArgErr);
}

Per i metodi e le funzioni di accesso di proprietà dell'oggetto, è necessario compilare l'attuazione. Le funzioni di metodo e proprietà generalmente possono delegare nuovamente ai metodi generati utilizzando ClassWizard. Tuttavia, se si imposta le proprietà per accedere direttamente le variabili, è necessario scrivere il codice per ottenere/put il valore alla variabile. Ad esempio:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
   / / MFC converte automaticamente da Unicode BSTR a / / Ansi CString, se necessario...
   pThis - > m_str = newText;
   return NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
   METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
   / / MFC converte automaticamente da CString Ansi a / / Unicode BSTR, se necessario...
   pThis - > m_str.SetSysString(retval);
   return NOERROR;
}

Puntatori di interfaccia duale di passaggio

Passando il puntatore a interfaccia duale non è semplice, soprattutto se avete bisogno di chiamare CCmdTarget::FromIDispatch. FromIDispatch funziona solo sui puntatori IDispatch di MFC. Un modo per aggirare questo consiste nell'eseguire una query per il set di puntatore IDispatch originale da MFC e passare tale puntatore a funzioni che ne hanno bisogno. Ad esempio

 STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position (
 nbsp;    IDualAutoClickPoint estremo * newPosition)
{
   METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
   LpDisp LPDISPATCH = NULL;
   newPosition - > QueryInterface (IID_IDispatch, (LPVOID *) & lpDisp);
   pThis - > SetPosition(lpDisp);
   lpDisp - > errato;
   return NOERROR;
}

Prima di passare un puntatore indietro attraverso il metodo di interfaccia duale, potrebbe essere necessario convertirlo dal puntatore MFC IDispatch il puntatore a interfaccia duale. Ad esempio:

STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position (
 nbsp;    IDualAutoClickPoint estremo * FAR * retval)
{
   METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
   LPDISPATCH lpDisp;
   lpDisp = pThis - > getPosition ();
   lpDisp - > QueryInterface (IID_IDualAutoClickPoint, (LPVOID *) retval);
   return NOERROR;
}

Registrazione tipo libreria dell'applicazione

Creazione guidata applicazione non genera codice per registrare la libreria dei tipi di un'applicazione server di automazione OLE con il sistema. Mentre ci sono altri modi per registrare la libreria dei tipi, è conveniente avere l'applicazione registra la libreria dei tipi quando sta aggiornando le informazioni sul tipo OLE, cioè, ogni volta che l'applicazione venga eseguita stand-alone.

Per registrare la libreria dei tipi dell'applicazione ogni volta che l'applicazione venga eseguita stand-alone:

Modifica delle impostazioni del progetto Build per accogliere modifiche al tipo di biblioteca

Per modificare un progetto costruzione impostazioni in modo che viene generato un file di intestazione che contiene le definizioni di UUID da MkTypLib ogni volta che viene ricostruita la libreria dei tipi

  1. Dal menu, fare clic su impostazioni, quindi selezionare il file ODL dall'elenco dei file per ogni configurazione.

  2. Fare clic sulla scheda tipi OLE e specificare un nome di file nel campo nome del file di intestazione Output. Utilizzare un nome di file che non è già utilizzato da un vostro progetto, dato che MkTypLib sovrascriverà qualsiasi file esistente. Fare clic su OK per chiudere la finestra di dialogo Impostazioni di costruire.

Per aggiungere le definizioni di UUID dal file di intestazione generato MkTypLib al progetto:

  1. Includono il MkTypLib generato dal file di intestazione in tuo standard include file di intestazione, STDAFX.H.

  2. Creare un nuovo file, INITIIDS.CPP e aggiungerlo al tuo progetto. In questo file, includere file di intestazione generato da MkTypLib dopo compresi OLE2.H e INITGUID.H:
    / / initIIDs.c: definisce gli IID per interfacce duali
    / / Questo non deve essere costruito con l'intestazione precompilata.
      # include lt;ole2.h >
      # include <initguid.h>
      # include "acdual.h"
    
    
  3. Dal menu, fare clic su impostazioni, quindi selezionare INITIIDS.CPP dall'elenco per ogni configurazione.

  4. Fare clic sulla scheda C++, categoria "intestazioni precompilate" e selezionare il "non utilizzando precompilati intestazioni" radio pulsante. Fare clic su OK per chiudere la finestra di dialogo Impostazioni di costruire.

Specificando il nome della classe oggetto corretto nella libreria dei tipi

I wizards forniti con Visual C++ in modo non corretto utilizzano il nome di classe di implementazione per specificare l'attributo coclass in file ODL del server per le classi OLE createable. Mentre questo lavoro, il nome della classe di implementazione è probabilmente non si desidera che gli utenti dell'oggetto, utilizzare il nome della classe. Per specificare il nome corretto, aprire il file ODL, individuare ogni istruzione di coclasse e sostituire il nome di classe di implementazione con il nome corretto esterno.

Si noti che quando l'istruzione di coclasse viene modificato, i nomi delle variabili di s CLSIDnel file di intestazione generato MkTypLib cambierà di conseguenza. Sarà necessario aggiornare il codice per utilizzare i nuovi nomi di variabili.

Gestione delle eccezioni e le interfacce di errore di automazione

Metodi e le funzioni di accesso di proprietà dell'oggetto automazione possono generare eccezioni. Se è così, dovreste gestirli nell'implementazione dell'interfaccia duale e passa le informazioni sull'eccezione al controller tramite l'interfaccia di gestione degli errori di automazione OLE, IErrorInfo. Questa interfaccia fornisce per informazioni dettagliate, contestuale errore tramite interfacce IDispatch e a VTBL. Per indicare che un gestore degli errori è disponibile, è necessario implementare l'interfaccia ISupportErrorInfo.

Per illustrare il meccanismo di gestione degli errori, si supponga che le funzioni generate ClassWizard utilizzate per implementare il supporto di spedizione standard generare eccezioni. Implementazione di MFC di se le catture in genere queste eccezioni e convertiti in un EXCEPTINFO struttura che rappresenta restituito tramite la chiamata a Invoke . Tuttavia, quando viene utilizzata l'interfaccia VTBL, vi sono responsabili per la cattura di eccezioni. Un esempio di proteggere i vostri metodi di interfaccia duale

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
   TRY_DUAL(IID_IDualAClick)
   {
      / / MFC converte automaticamente da Unicode BSTR a / / Ansi CString, se necessario...
      pThis - > m_str = newText;
      return NOERROR;
   }
   CATCH_ALL_DUAL
}

CATCH_ALL_DUALsi occupa di restituire il codice di errore corretto quando si verifica un'eccezione. CATCH_ALL_DUALconverte un'eccezione MFC in informazioni di gestione degli errori di automazione OLE utilizzando l'interfaccia ICreateErrorInfo . (Un esempio CATCH_ALL_DUAL macro è nel file MFCDUAL.H nei esempio ACDUAL . La funzione chiama per gestire le eccezioni, DualHandleException , si trova nel file MFCDUAL.CPP). CATCH_ALL_DUALdetermina il codice di errore da restituire in base al tipo di eccezione che si è verificato

Per indicare che il gestore di errori di automazione OLE viene utilizzato, è necessario implementare anche l'interfaccia ISupportErrorInfo.

In primo luogo, aggiungere il codice alla definizione della classe automazione per mostrare che supporta ISupportErrorInfo.

In secondo luogo, aggiungere il codice alla mappa dell'interfaccia della classe automazione per associare la classe di implementazione ISupportErrorInfo con meccanismo di QueryInterface di MFC. Il INTERFACE_PART istruzione corrisponde la classe definita per ISupportErrorInfo.

Infine, implementare la classe definita per supportare ISupportErrorInfo.

(Il esempio ACDUAL contiene tre macro per contribuire a fare questi tre passaggi, DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , e IMPLEMENT_DUAL_ERRORINFO , tutti racchiusi in MFCDUAL.H.)

Nell'esempio seguente viene implementata una classe definita per supportare ISupportErrorInfo. CAutoClickDocè il nome della vostra classe automazione e IID_IDualAClick è l' IID per l'interfaccia che è la fonte di errori segnalati tramite l'oggetto error automazione OLE:

STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() {
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) ritorno pThis - > ExternalAddRef(); 
} CAutoClickDoc::XSupportErrorInfo::Release() STDMETHODIMP_(ULONG) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) ritorno pThis - > ExternalRelease(); 
} CAutoClickDoc::XSupportErrorInfo::QueryInterface STDMETHODIMP (REFIID iid, LPVOID * ppvObj) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) ritorno pThis - > ExternalQueryInterface (& iid, ppvObj); 
} CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo STDMETHODIMP (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) ritorno (iid = = IID_IDualAClick)? S_OK: S_FALSE; 
}

&Note tecniche per numero |nbsp; Note tecniche per la categoria

Index