Aperçu de l'Interface IDispatch OLE
L'interface IDispatch est le moyen par les méthodes d'exposer les applications et les propriétés telles que d'autres applications telles que Visual BASIC, ou d'autres langues, peuvent faire l'utilisation des fonctionnalités de l'application. La partie la plus importante de cette interface est la fonction de IDispatch::Invoke . MFC utilise « envoyer des cartes » à mettre en œuvre de IDispatch::Invoke. La carte de répartition fournit les informations de mise en œuvre de MFC sur la mise en page ou de la « forme » de votre CCmdTarget-dérivées des classes, telle qu'elle peut directement manipuler les propriétés de l'objet, ou appeler des fonctions au sein de votre objet de satisfaire les demandes de IDispatch::Invoke membre.
Pour l'essentiel, le ClassWizard et MFC coopérent pour masquer la plupart des détails de OLE automation par le programmeur de l'application. Le programmeur se concentre sur les fonctionnalités d'exposer dans l'application et n'a pas à se soucier de la plomberie sous-jacente.
Il y a des cas, cependant, où il est nécessaire de comprendre ce que MFC est fait dans les coulisses. Cette note portera sur comment le framework assigne DISPIDs à des propriétés et fonctions membres. Connaissance de l'algorithme de que MFC utilise pour l'attribution des DISPIDs est seulement nécessaire lorsque vous devez connaître l'ID, comme lorsque vous créez une bibliothèque de « type » pour les objets de votre application.
Cession de DISPID MFC
Bien que l'utilisateur final d'automation (Visual Basic utilisateur, par exemple), les noms réels de l'automatisation a permis des propriétés et méthodes dans leur code (par exemple obj.ShowWindow), la mise en œuvre de IDispatch::Invoke ne reçoit pas les noms réels. Pour des raisons d'optimisation, il reçoit un DISPID, qui est un 32-bit "magic cookie" qui décrit la méthode ou la propriété qui doit être consulté. Ces valeurs DISPID sont renvoyées de l'implémentation IDispatch par une autre méthode, appelée IDispatch::GetIDsOfNames. Une application cliente automation va appeler GetIDsOfNames une fois pour chaque membre ou bien à qu'elle a l'intention d'accéder et leur cache pour les appels ultérieurs à IDispatch::Invoke. De cette façon, la recherche de chaîne cher est seulement faite une fois par l'utilisation de l'objet, au lieu d'une fois par appel de IDispatch::Invoke.
MFC détermine le DISPIDs pour chaque méthode et une propriété basée sur deux choses:
Le DISPID est divisé en deux parties. Le LOWORD du DISPID contient la première composante, la distance entre le haut de la carte de répartition. Le HIWORD contient la distance de la classe dérivée plus. Par exemple:
class CDispPoint : public CCmdTarget
{
public :
nbsp ; court m_x, m_y ;
...
DECLARE_DISPATCH_MAP()
...
};
Class CDisp3DPoint : public CDispPoint
{
public :
court m_y ;
...
DECLARE_DISPATCH_MAP()
...
};
BEGI&N_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()
Comme vous pouvez le voir, il y a deux classes, qui exposent les interfaces d'automation OLE. Une de ces classes est dérivée de l'autre et donc tire parti des fonctionnalités de la classe de base, y compris l'automatisation OLE (« x » et « y » propriétés dans ce cas).
MFC génère DISPIDs pour la classe CDispPoint comme suit:
propriété X  ; (DISPID) 0 X 00000001
propriété Y (DISPID) 0 x 00000002
Étant donné que les propriétés ne sont pas dans une classe de base, le HIWORD du DISPID est toujours zéro (de la classe la plus dérivée pour CDispPoint la distance est égale à zéro).
MFC génère DISPIDs pour la classe CDisp3DPoint comme suit:
propriété Z  ; (DISPID) 0 X 00000001
propriété X (DISPID) 0x00010001
propriété Y (DISPID) 0 x 00010002
La propriété de z est donnée un DISPID avec un zéro HIWORD puisqu'elle est définie dans la classe qui est d'exposer les propriétés, CDisp3DPoint. Étant donné que les propriétés x et y sont définies dans une classe de base, le HIWORD du DISPID est 1, puisque la classe dans laquelle ces propriétés sont définies est à une distance d'une dérivation à partir de la classe dérivée plus.
&Notenbsp ; Le LOWORD est toujours déterminé par la position sur la carte, même s'il existent des entrées à la carte avec explicite DISPID (voir la section suivante pour plus d'informations sur les versions _ID les macros DISP_PROPERTY et DISP_FUNCTION ).
MFC envoi carte fonctionnalités avancées
Il y a un certain nombre de fonctionnalités supplémentaires que ClassWizard ne prend pas en charge cette version de Visual C++. ClassWizard prend en charge DISP_FUNCTION, DISP_PROPERTYet DISP_PROPERTY_EX qui définissent une méthode, la propriété variables de membre et propriété get/set de fonction membre, respectivement. Ces capacités sont généralement tout ce qui est nécessaire pour créer la plupart des serveurs automation.
Les macros complémentaires suivantes peuvent être utilisées lorsque les ClassWizard pris en charge les macros ne sont pas suffisantes : DISP_PROPERTY_NOTIFYet DISP_PROPERTY_PARAM.
DISP_PROPERTY_NOTIFY — Description de Macro
DISP_PROPERTY_NOTIFY (theClass, pszName, memberName, pfnAfterSet, vtPropType)
theClass
Nom de la classe.
pszName
Nom externe de la propriété.
memberName
Nom de la variable de membre dans lequel la propriété est stockée.
pfnAfterSet
Nom de la fonction membre à appeler lorsque la propriété est modifiée.
vtPropType
Une valeur qui spécifie le type de la propriété.
&Notenbsp ; Cette macro est assez semblable à DISP_PROPERTY, sauf qu'elle accepte un argument supplémentaire. L'argument supplémentaire, pfnAfterSet, doit être une fonction membre qui ne renvoie rien et ne prend aucun paramètre, 'void OnPropertyNotify()'. Elle sera appelée après que la modification de la variable de membre.
DISP_PROPERTY_PARAM — Description de Macro
DISP_PROPERTY_PARAM (theClass, pszName, pfnGet, pfnSet, vtPropType, vtsParams)
theClass
Nom de la classe.
pszName
Nom externe de la propriété.
memberGet
Nom de la fonction de membre utilisée pour obtenir la propriété.
jeu de membres
Nom de la fonction de membre utilisée pour définir la propriété.
vtPropType
Une valeur qui spécifie le type de la propriété.
vtsParams
Une chaîne d'espace séparé VTS_ pour chaque paramètre.
&Notenbsp ; Beaucoup comme la macro DISP_PROPERTY_EX , cette macro définit une propriété accédée avec les fonctions de membres distinctes Get et Set. Cette macro, cependant, vous permet de spécifier une liste de paramètre de la propriété. Ceci est utile pour la mise en œuvre des propriétés qui sont indexées ou paramétrées de quelque autre manière. Les paramètres seront toujours placés tout d'abord, suivie par la nouvelle valeur pour la propriété. Par exemple:
DISP_PROPERTY_PARAM (CMyObject, « point », GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
correspondrait pour obtenir et définir des fonctions membres:
LPDISPATCH CMyObject::GetItem(short row, short col)
VOID CMyObject::SetItem (ligne courte, col court, LPDISPATCH newValue)
DISP_XXXX_ID — Descriptions de Macro
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)
theClass
Nom de la classe.
pszName
Nom externe de la propriété.
dispid
Le DISPID fixe pour la propriété ou la méthode.
pfnGet
Nom de la fonction de membre utilisée pour obtenir la propriété.
pfnSet
Nom de la fonction de membre utilisée pour définir la propriété.
memberName
Le nom de la variable membre à la carte à la propriété
vtPropType
Une valeur qui spécifie le type de la propriété.
vtsParams
Une chaîne d'espace séparé VTS_ pour chaque paramètre.
&Notenbsp ; Ces macros permettent de spécifier un DISPID au lieu de laisser les MFC à attribuer automatiquement une. Ces macros ont les mêmes noms sauf que ID est ajouté au nom de macro (par exemple DISP_PROPERTY_ID) et l'ID est déterminé par le paramètre spécifié juste après le paramètre pszName . Voir AFXDISP.H pour plus d'informations sur ces macros. Les entrées _ID doivent être placées à la fin de la carte de répartition. Ils influeront sur la génération automatique de DISPID de la même façon qu'un non - serait_ID version de la macro (le DISPIDs sont déterminés par la poste). Par exemple:
BEGI&N_DISPATCH_MAP (CDisp3DPoint, CCmdTarget)
nbsp ; 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 générera DISPID pour la classe CDisp3DPoint comme suit:
propriété X  ; (DISPID) 0X00020003
propriété Y (DISPID) 0 x 00000002
propriété Z (DISPID) 0 x 00000001
Spécification d'un fixe DISPID est utile pour maintenir la compatibilité descendante pour une interface de dispatch déjà existantes ou à mettre en œuvre certain système défini méthodes ou propriétés (généralement indiquées par un négatif DISPID, tels que la collection de DISPID_NEWENUM ).
Extraire l'Interface IDispatch pour un COleClientItem
De nombreux serveurs soutiendra l'automatisation au sein de leurs objets de document, avec la fonctionnalité de serveur OLE. Afin d'avoir accès à cette interface d'automatisation, il est nécessaire d'accéder directement à la variable membre COleClientItem::m_lpObject . Le code ci-dessous permet d'extraire l'interface IDispatch pour un objet dérivé de COleClientItem. Vous pouvez inclure le code ci-dessous dans votre application, si vous trouvez cette fonctionnalité nécessaire
LPDISPATCH CMyClientItem::GetIDispatch()
{
nbsp ; ASSERT_VALID(this) ;
ASSERT (m_lpObject! = NULL) ;
LPUNKNOWN lpUnk = m_lpObject ;
Run() ; / / doit être en cours d'exécution
LPOLELINK lpOleLink = NULL ;
Si (m_lpObject - > QueryInterface (IID_IOleLink, (LPVOID FAR **) & lpOleLink) == NOERROR)
{
ASSERT (lpOleLink! = NULL) ;
lpUnk = NULL ;
Si (lpOleLink - > GetBoundSource(&lpUnk)! = NOERROR)
{
TRACE0 ("Warning : lien n'est pas connecté! \n") ;
lpOleLink - > Release() ;
retourner la valeur NULL ;
}
ASSERT (lpUnk! = NULL) ;
}
LPDISPATCH lpDispatch = NULL ;
Si (lpUnk - > QueryInterface (IID_IDispatch, & lpDispatch)! = NOERROR)
{
TRACE0 ("mise en garde : ne prend pas en charge IDispatch! \n") ;
retourner la valeur NULL ;
}
ASSERT (lpDispatch! = NULL) ;
Return lpDispatch ;
}
L'interface de dispatch retournée par cette fonction pourrait être ensuite utilisée directement ou attachée à un objet COleDispatchDriver pour un accès de type sécurisé. Si vous l'utilisez directement, assurez-vous que vous appelez son membre de libération quand à travers avec le pointeur (le destructeur de COleDispatchDriver le fait par défaut).
&Notes techniques par le numéro |nbsp ; Notes techniques par catégorie