TN039: implementazione di automazione di MFC/OLE
[!NOTA]
La seguente nota tecnica non è stata aggiornata dalla prima volta che viene inclusa nella documentazione online.Di conseguenza, alcune procedure e argomenti potrebbero non essere aggiornati o errati.Per le informazioni più recenti, è consigliabile cercare l'argomento di interesseindice della documentazione online.
Panoramica dell'interfaccia IDispatch OLE
L'interfaccia di IDispatch è il modo in cui le applicazioni espongono metodi e le proprietà in modo che le altre applicazioni in Visual Basic, o altri linguaggi, possono utilizzare le funzionalità dell'applicazione.La parte più importante di questa interfaccia è la funzione di IDispatch::Invoke .MFC utilizza “le mappe di invio„ per implementare IDispatch::Invoke.La mappa submit fornisce informazioni sull'implementazione mfc nel layout o su “forma„ del CCmdTargetalle classi derivate, in modo che possibile modificare direttamente le proprietà dell'oggetto, o chiama le funzioni membro all'interno dell'oggetto per soddisfare le richieste di IDispatch::Invoke .
In genere, ClassWizard e MFC prevedono per nascondere la maggior parte dei dettagli di automazione OLE dal programmatore di applicazione.Il programmatore è incentrato sulla funzionalità per esporre nell'applicazione e non è necessario preoccuparsi del modello grid idraulico sottostante.
Vi sono casi, tuttavia, dove è necessario capire cosa MFC esegue automaticamente.Questa nota si farà riferimento a nel framework assegna DISPIDoggetti alle funzioni membro e proprietà.La conoscenza di utilizza l'algoritmo MFC per assegnare DISPIDgli oggetti è necessaria solo quando è necessario conoscere gli ID, ad esempio quando si crea una “libreria dei tipi„ per gli oggetti dell'applicazione.
assegnazione di MFC DISPID
Sebbene l'utente finale di automazione (un utente di Visual Basic, ad esempio, vedere i nomi effettivi delle proprietà animate automazione i metodi e nel codice (ad esempio obj.ShowWindow), l'implementazione di IDispatch::Invoke non riceve i nomi effettivi.Per motivi di ottimizzazione, riceve DISPID, che è un 32 bit “cookie magiche„ che descrive il metodo o la proprietà che è necessario accedervi.Questi valori di DISPID vengono restituiti dall'implementazione di IDispatch con un altro metodo, chiamato IDispatch::GetIDsOfNames.Un'applicazione client di automazione chiamerà una volta GetIDsOfNames per ogni membro o proprietà che intende accedere e li memorizza nella cache per le chiamate successive a IDispatch::Invoke.In questo modo, la ricerca nella stringa viene eseguita solo una volta per l'utilizzo dell'oggetto, anziché una volta per chiamata di IDispatch::Invoke .
MFC determina DISPIDs per ogni metodo e proprietà basati su due fattori:
La distanza dall'inizio della mappa di invio (1) relativo
La distanza della mappa di invio dalla maggior parte della classe derivata (0 parenti)
DISPID viene diviso in due parti.LOWORD di DISPID contiene la prima parte, la distanza dall'inizio della mappa di invio.HIWORD contiene la distanza dalla maggior parte della classe derivata.Di seguito è riportato un esempio:
class CDispPoint : public CCmdTarget
{
public:
short m_x, m_y;
...
DECLARE_DISPATCH_MAP()
...
};
class CDisp3DPoint : public CDispPoint
{
public:
short m_z;
...
DECLARE_DISPATCH_MAP()
...
};
BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()
BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()
Come si può notare, esistono due classi, entrambi espongono le interfacce di automazione OLE.Una di queste classi è derivata dall'altro e così sfrutta le funzionalità della classe base, inclusa la parte di automazione OLE (proprietà y “e„ x in questo caso).
MFC genererà DISPIDoggetti per classe CDispPoint come segue:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Poiché le proprietà non sono in una classe base, HIWORD di DISPID è sempre zero (la distanza dalla maggior parte della classe derivata per CDispPoint è zero).
MFC genererà DISPIDoggetti per classe CDisp3DPoint come segue:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
La proprietà Z viene fornita DISPID con HIWORD zero poiché è definita nella classe che si sta esponendo le proprietà, CDisp3DPoint.La X le proprietà e Y viene definito in una classe base, HIWORD di DISPID è 1, la classe in cui tali proprietà sono definite corrisponde a una distanza di una derivazione dalla maggior parte della classe derivata.
[!NOTA]
LOWORD è determinato sempre dalla posizione nel mapping, anche se esiste alcuna voce nella mappa con DISPID esplicito (vedere la sezione successiva per informazioni sulle versioni di _ID delle macro di DISP_FUNCTION e di DISP_PROPERTY ).
Funzionalità avanzate della mappa di invio MFC
Esistono numerose funzionalità aggiuntive che ClassWizard non supporta con questa versione di Visual C++.ClassWizard supporta DISP_FUNCTION, DISP_PROPERTYe DISP_PROPERTY_EX che definiscono un metodo, una proprietà delle variabili membro e ottengono/una proprietà funzione del membro del gruppo, rispettivamente.Queste funzionalità sono in genere tutte che siano necessarie per creare la maggior parte dei server di automazione.
Nell'esempio di macro aggiuntive possono essere utilizzate quando macro supportate di ClassWizard non sono appropriate: DISP_PROPERTY_NOTIFYe DISP_PROPERTY_PARAM.
DISP PROPERTY NOTIFY - macro descrizione
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType
)
Note
Parametri
theClass
Nome della classe.pszName
Nome esterno della proprietà.memberName
Nome della variabile membro in cui la proprietà viene archiviata.pfnAfterSet
Nome della funzione membro per chiamare quando la proprietà viene modificata.vtPropType
Un valore che specifica il tipo della proprietà.
Note
Questa macro è molto simile a DISP_PROPERTY, con la differenza che accetta un argomento aggiuntivo.L'argomento aggiuntivo, pfnAfterSet, deve essere una funzione membro che non restituisce alcun e non accetta parametri, “OnPropertyNotify void ()„.Verrà chiamato dopo che la variabile membro è stato modificato.
DISP PROPERTY PARAM - macro descrizione
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
Note
Parametri
theClass
Nome della classe.pszName
Nome esterno della proprietà.memberGet
Nome della funzione membro utilizzata per ottenere la proprietà.memberSet
Il nome della funzione membro ha utilizzato per impostare la proprietà.vtPropType
Un valore che specifica il tipo della proprietà.vtsParams
Una serie di spazio separati VTS_ per ogni parametro.
Note
Analogamente alla macro di DISP_PROPERTY_EX , questa macro viene definita una proprietà accede con separato funzioni membro del gruppo e ottiene.Questa macro, tuttavia, consente di specificare un elenco di parametri per la proprietà.Ciò è utile per implementare le proprietà che vengono indicizzate o con parametri in altro modo.I parametri vengono sempre inseriti per primo, seguito dal nuovo valore per la proprietà.Di seguito è riportato un esempio:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
corrispondono a per ottenere e funzioni membro del gruppo:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
- Macro descrizioni
DISP_FUNCTION_ID(
theClass,
pszName,
dispid,
pfnMember,
vtRetVal,
vtsParams
)
DISP_PROPERTY_ID(
theClass,
pszName,
dispid,
memberName,
vtPropType
)
DISP_PROPERTY_NOTIFY_ID(
theClass,
pszName,
dispid,
memberName,
pfnAfterSet,
vtPropType
)
DISP_PROPERTY_EX_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType
)
DISP_PROPERTY_PARAM_ID(
theClass,
pszName,
dispid,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
Note
Parametri
theClass
Nome della classe.pszName
Nome esterno della proprietà.dispid
Il DISPID fisso per la proprietà o il metodo.pfnGet
Nome della funzione membro utilizzata per ottenere la proprietà.pfnSet
Il nome della funzione membro ha utilizzato per impostare la proprietà.memberName
Il nome della variabile membro per eseguire il mapping alla proprietàvtPropType
Un valore che specifica il tipo della proprietà.vtsParams
Una serie di spazio separati VTS_ per ogni parametro.
Note
Queste macro consentono di specificare DISPID anziché lasciare MFC automaticamente assegnare uno.Queste macro avanzate hanno gli stessi nomi con la differenza che l'ID viene accodato al nome della macro (ad esempioDISP_PROPERTY_ID) e l'ID è determinato dal parametro specificato immediatamente dopo il parametro di pszName .vedere AFXDISP.H per ulteriori informazioni su queste macro.Le voci di _ID devono essere inserite alla fine della mappa di invio.Avranno effetto sulla generazione automatica di DISPID come una versione non di**_ID** della macro ( DISPIDgli oggetti è determinato dalla posizione).Di seguito è riportato un esempio:
BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()
MFC genera i dispid per classe CDisp3DPoint come segue:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Specificare DISPID fisso è utile mantenere la compatibilità con le versioni precedenti a un'interfaccia dispatch già esistente, o ai metodi definiti o le proprietà di un determinato sistema di utilizzo (in genere indicati da DISPIDnegativo, ad esempio la raccolta di DISPID_NEWENUM ).
recuperare l'interfaccia IDispatch per un COleClientItem
Molti server supportano l'automazione all'interno degli oggetti documento, con la funzionalità del server OLE.Per accedere a questa interfaccia di automazione, è necessario direttamente da accedere alla variabile membro di COleClientItem::m_lpObject .Il codice riportato di seguito vengono recuperati l'interfaccia di IDispatch per un oggetto derivato da COleClientItem.È possibile includere il codice riportato di seguito nell'applicazione se si verifica questa funzionalità necessarie:
LPDISPATCH CMyClientItem::GetIDispatch()
{
ASSERT_VALID(this);
ASSERT(m_lpObject != NULL);
LPUNKNOWN lpUnk = m_lpObject;
Run(); // must be running
LPOLELINK lpOleLink = NULL;
if (m_lpObject->QueryInterface(IID_IOleLink,
(LPVOID FAR*)&lpOleLink) == NOERROR)
{
ASSERT(lpOleLink != NULL);
lpUnk = NULL;
if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
{
TRACE0("Warning: Link is not connected!\n");
lpOleLink->Release();
return NULL;
}
ASSERT(lpUnk != NULL);
}
LPDISPATCH lpDispatch = NULL;
if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch)
!= NOERROR)
{
TRACE0("Warning: does not support IDispatch!\n");
return NULL;
}
ASSERT(lpDispatch != NULL);
return lpDispatch;
}
L'interfaccia dispatch restituita dalla funzione può quindi essere utilizzata direttamente o essere associata a COleDispatchDriver per l'accesso indipendente dai tipi.Se si utilizza direttamente, assicurarsi di chiamare il relativo membro di Release quando tramite con il puntatore (il distruttore di COleDispatchDriver questa operazione viene eseguita per impostazione predefinita).