Objet de données de Shell

L’objet de données est central pour tous les transferts de données shell. Il s’agit principalement d’un conteneur pour contenir les données transférées. Toutefois, la cible peut également communiquer avec l’objet de données pour faciliter certains types spécialisés de transfert de données Shell, tels que les déplacements optimisés. Cette rubrique fournit une présentation générale du fonctionnement des objets de données Shell, de la façon dont ils sont construits par une source et de la façon dont ils sont gérés par une cible. Pour une présentation détaillée de l’utilisation d’objets de données pour transférer différents types de données Shell, consultez Gestion des scénarios de transfert de données shell.

Fonctionnement des objets de données

Les objets de données sont des objets COM (Component Object Model), créés par la source de données pour transférer des données vers une cible. Ils transportent généralement plusieurs éléments de données. Il existe deux raisons à cette pratique :

  • Alors que presque tous les types de données peuvent être transférés avec un objet de données, la source ne sait généralement pas quel type de données la cible peut accepter. Par instance, les données peuvent être une partie d’un document texte mis en forme. Bien que la cible puisse gérer des informations de mise en forme complexes, elle peut également accepter uniquement du texte ANSI. Pour cette raison, les objets de données incluent souvent les mêmes données dans plusieurs formats différents. La cible peut ensuite extraire les données dans un format qu’elle peut gérer.
  • Les objets de données peuvent également contenir des éléments de données auxiliaires qui ne sont pas des versions des données sources. Ce type d’élément de données fournit généralement des informations supplémentaires sur l’opération de transfert de données. Par instance, l’interpréteur de commandes utilise des éléments de données auxiliaires pour indiquer si un fichier doit être copié ou déplacé.

Formats du Presse-papiers

Chaque élément de données d’un objet de données a un format associé, généralement appelé format du Presse-papiers. Il existe un certain nombre de formats de Presse-papiers standard, déclarés dans Winuser.h, qui correspondent à des types de données couramment utilisés. Les formats du Presse-papiers sont des entiers, mais ils sont normalement référencés par leur nom équivalent, qui a la forme CF_XXX. Par instance, le format du presse-papiers pour le texte ANSI est CF_TEXT.

Les applications peuvent étendre la gamme des formats de Presse-papiers disponibles en définissant des formats privés. Pour définir un format privé, une application appelle RegisterClipboardFormat avec une chaîne qui identifie le format. L’entier non signé retourné par la fonction est une valeur de format valide qui peut être utilisée comme un format de Presse-papiers standard. Toutefois, la source et la cible doivent inscrire le format pour pouvoir l’utiliser. À une exception près, CF_HDROP, les formats du Presse-papiers utilisé pour transférer des données shell sont définis comme des formats privés. Ils doivent être inscrits par la source et la cible avant de pouvoir être utilisés. Pour obtenir une description des formats disponibles du Presse-papiers Shell, consultez Formats du Presse-papiers shell.

Bien qu’il existe quelques exceptions, les objets de données ne contiennent normalement qu’un seul élément de données pour chaque format de Presse-papiers qu’ils prennent en charge. Cette corrélation un-à-un entre le format et les données permet d’utiliser la valeur de format comme identificateur de l’élément de données associé. En fait, lors de la discussion du contenu d’un objet de données, un élément de données particulier est généralement appelé « format » et est référencé par son nom de format. Par exemple, des expressions telles que « Extraire le format CF_TEXT... » sont généralement utilisés lors de la discussion de l’élément de données de texte ANSI d’un objet de données.

Lorsque la cible de suppression reçoit le pointeur vers l’objet de données, la cible de suppression énumère les formats disponibles pour déterminer les types de données disponibles. Il demande ensuite un ou plusieurs des formats disponibles et extrait les données. La façon spécifique dont la cible extrait les données shell d’un objet de données varie en fonction du format ; Cela est décrit en détail dans Comment une cible gère un objet de données.

Avec les transferts de données du Presse-papiers simples, les données sont placées dans un objet de mémoire globale. L’adresse de cet objet est placée dans le Presse-papiers, ainsi que son format. Le format du Presse-papiers indique à la cible le type de données qu’elle trouvera à l’adresse associée. Bien que les transferts simples du Presse-papiers soient faciles à implémenter :

  • Les objets de données offrent un moyen beaucoup plus flexible de transférer des données.
  • Les objets de données sont mieux adaptés au transfert de grandes quantités de données.
  • Les objets de données doivent être utilisés pour transférer des données à l’aide d’une opération de glisser-déplacer.

Pour ces raisons, tous les transferts de données shell utilisent des objets de données. Avec les objets de données, les formats du Presse-papiers ne sont pas utilisés directement. Au lieu de cela, les éléments de données sont identifiés avec une généralisation du format du Presse-papiers, une structure FORMATETC .

FORMATETC, structure

La structure FORMATETC est une version étendue d’un format de Presse-papiers. Utilisée pour les transferts de données shell, la structure FORMATETC présente les caractéristiques suivantes :

  • Un élément de données est toujours identifié par son format de Presse-papiers, dans le membre cfFormat .

  • Le transfert de données n’est pas limité aux objets de mémoire globale. Le membre bloqué est utilisé pour indiquer le mécanisme de transfert de données contenu dans la structure STGMEDIUM associée. Elle est définie sur l’une des valeurs TYMED_XXX .

  • L’interpréteur de commandes utilise le membre lIndex avec son format CFSTR_FILECONTENTS pour permettre à un objet de données de contenir plusieurs éléments de données par format. Pour plus d’informations sur l’utilisation de ce format, consultez la section Utilisation du format CFSTR_FILECONTENTS pour extraire des données d’un fichier de La gestion des scénarios de transfert de données shell.

  • Le membre dwAspect est généralement défini sur DVASPECT_CONTENT. Toutefois, il existe trois valeurs définies dans Shlobj.h qui peuvent être utilisées pour le transfert de données shell.

    Valeur Description
    DVASPECT_COPY Utilisé pour indiquer que le format représente une copie des données.
    DVASPECT_LINK Utilisé pour indiquer que le format représente un raccourci vers les données.
    DVASPECT_SHORTNAME Utilisé avec le format CF_HDROP pour demander un chemin d’accès de fichier avec les noms raccourcis au format 8.3.

     

  • Le membre ptd n’est pas utilisé pour les transferts de données shell et est normalement défini sur NULL.

Structure STGMEDIUM

La structure STGMEDIUM permet d’accéder aux données transférées. Trois mécanismes de transfert de données sont pris en charge pour les données shell :

Le membre lié de la structure STGMEDIUM est une valeur TYMED_XXX qui identifie le mécanisme de transfert de données. Le deuxième membre est un pointeur utilisé par la cible pour extraire les données. Le pointeur peut être de différents types, en fonction de la valeur liée . Les trois valeurs bloquées utilisées pour les transferts de données Shell sont résumées dans le tableau suivant, ainsi que leur nom de membre STGMEDIUM correspondant.

valeur tymed Nom du membre Description
TYMED_HGLOBAL hGlobal Pointeur vers un objet mémoire globale. Ce type de pointeur est généralement utilisé pour transférer de petites quantités de données. Par instance, l’interpréteur de commandes utilise des objets de mémoire globale pour transférer des chaînes de texte courtes telles que des noms de fichiers ou des URL.
TYMED_ISTREAM pstm Pointeur vers une interface IStream . Ce type de pointeur est préféré pour la plupart des transferts de données Shell, car il nécessite relativement peu de mémoire par rapport à TYMED_HGLOBAL. En outre, le mécanisme de transfert de données TYMED_ISTREAM ne nécessite pas que la source stocke ses données d’une manière particulière.
TYMED_ISTORAGE pstg Pointeur vers une interface IStorage . La cible appelle les méthodes d’interface pour extraire les données. Comme TYMED_ISTREAM, ce type de pointeur nécessite relativement peu de mémoire. Toutefois, comme TYMED_ISTORAGE est moins flexible que TYMED_ISTREAM, il n’est pas aussi couramment utilisé.

 

Comment une source crée un objet de données

Lorsqu’un utilisateur lance un transfert de données Shell, la source est chargée de créer un objet de données et de le charger avec des données. La procédure suivante résume le processus :

  1. Appelez RegisterClipboardFormat pour obtenir une valeur de format de Presse-papiers valide pour chaque format Shell qui sera inclus dans l’objet de données. N’oubliez pas que CF_HDROP est déjà un format de Presse-papiers valide et n’a pas besoin d’être inscrit.
  2. Pour chaque format à transférer, placez les données associées dans un objet de mémoire globale ou créez un objet qui fournit l’accès à ces données via une interface IStream ou IStorage . Les interfaces IStream et IStorage sont créées à l’aide de techniques COM standard. Pour plus d’informations sur la gestion des objets de mémoire globale, consultez Comment ajouter un objet mémoire globale à un objet de données.
  3. Créez des structures FORMATETC et STGMEDIUM pour chaque format.
  4. Instancier un objet de données.
  5. Chargez les données dans l’objet de données en appelant la méthode IDataObject::SetData pour chaque format pris en charge et en transmettant les structures FORMATETC et STGMEDIUM du format.
  6. Avec les transferts de données du Presse-papiers, appelez OleSetClipboard pour placer un pointeur vers l’interface IDataObject de l’objet de données dans le Presse-papiers. Pour les transferts par glisser-déplacer, lancez une boucle de glisser-déplacer en appelant DoDragDrop. Le pointeur IDataObject est passé à la cible de suppression lorsque les données sont supprimées, mettant fin à la boucle de glisser.

L’objet de données est maintenant prêt à être transféré vers la cible. Pour les transferts de données du Presse-papiers, l’objet est simplement conservé jusqu’à ce que la cible le demande en appelant OleGetClipboard. Pour les transferts de données par glisser-déplacer, l’objet de données est chargé de créer une icône pour représenter les données et de les déplacer à mesure que l’utilisateur déplace le curseur. Lorsque l’objet se trouve dans la boucle de glisser, la source reçoit status informations via son interface IDropSource. Pour plus d’informations, consultez Implémentation d’IDropSource.

La source ne reçoit aucune notification si l’objet de données est récupéré dans le Presse-papiers par une cible. Lorsqu’un objet est supprimé sur une cible par glisser-déplacer, la fonction DoDragDrop appelée pour lancer la boucle de glisser-déplacer retourne.

Comment ajouter un objet de mémoire globale à un objet de données

La plupart des formats de données Shell se présentent sous la forme d’un objet de mémoire globale. Utilisez la procédure suivante pour créer un format contenant un objet de mémoire globale et le charger dans l’objet de données :

  1. Créez une structure FORMATETC . Définissez le membre cfFormat sur la valeur de format du Presse-papiers appropriée et le membre tyd sur TYMED_HGLOBAL.
  2. Créez une structure STGMEDIUM . Définissez le membre tyd sur TYMED_HGLOBAL.
  3. Créez un objet de mémoire globale en appelant GlobalAlloc pour allouer un bloc de mémoire de taille adaptée.
  4. Affectez le bloc de données à transférer à l’adresse retournée par GlobalAlloc.
  5. Attribuez l’adresse de l’objet mémoire globale au membre hGlobal de la structure STGMEDIUM .
  6. Chargez le format dans l’objet de données en appelant IDataObject::SetData et en transmettant les structures FORMATETC et STGMEDIUM créées aux étapes précédentes.

L’exemple de fonction suivant crée un objet de mémoire globale contenant une valeur DWORD et le charge dans un objet de données. Le paramètre pdtobj est un pointeur vers l’interface IDataObject de l’objet de données, cf est la valeur du format du Presse-papiers et dw est la valeur de données.

STDAPI DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dw)
{
    FORMATETC fmte = {(CLIPFORMAT) cf, 
                      NULL, 
                      DVASPECT_CONTENT, 
                      -1, 
                      TYMED_HGLOBAL};
    STGMEDIUM medium;

    HRESULT hres = E_OUTOFMEMORY;
    DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
    
    if (pdw)
    {
        *pdw = dw;       
        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pdw;
        medium.pUnkForRelease = NULL;

        hres = pdtobj->SetData(&fmte, &medium, TRUE);
 
        if (FAILED(hres))
            GlobalFree((HGLOBAL)pdw);
    }
    return hres;
}

Implémentation d’IDataObject

IDataObject est l’interface principale d’un objet de données. Il doit être implémenté par tous les objets de données. Il est utilisé à la fois par la source et la cible à diverses fins, notamment :

  • Chargement de données dans l’objet de données.
  • Extraction de données de l’objet de données.
  • Détermination des types de données dans l’objet de données.
  • Fournir des commentaires à l’objet de données sur le résultat du transfert de données.

IDataObject prend en charge un certain nombre de méthodes. Cette section explique comment implémenter les trois méthodes les plus importantes pour les objets de données Shell, SetData, EnumFormatEtc et GetData. Pour plus d’informations sur les autres méthodes, consultez la référence IDataObject .

SetData (méthode)

La fonction principale de la méthode IDataObject::SetData est de permettre à la source de charger des données dans l’objet de données. Pour chaque format à inclure, la source crée une structure FORMATETC pour identifier le format et une structure STGMEDIUM pour contenir un pointeur vers les données. La source appelle ensuite la méthode IDataObject::SetData de l’objet et passe les structures FORMATETC et STGMEDIUM du format. La méthode doit stocker ces informations afin qu’elles soient disponibles lorsque la cible appelle IDataObject::GetData pour extraire des données de l’objet.

Toutefois, lors du transfert de fichiers, l’interpréteur de commandes place souvent les informations relatives à chaque fichier à transférer dans un format CFSTR_FILECONTENTS distinct. Pour distinguer les différents fichiers, le membre lIndex de la structure FORMATETC de chaque fichier est défini sur une valeur d’index qui identifie le fichier particulier. Votre implémentation IDataObject::SetData doit être capable de stocker plusieurs formats CFSTR_FILECONTENTS qui diffèrent uniquement par leurs membres lIndex .

Lorsque le curseur se trouve sur la fenêtre cible, la cible peut utiliser l’objet d’assistance glisser-déplacer pour spécifier l’image de glissement. L’objet d’assistance glisser-déplacer appelle IDataObject::SetData pour charger des formats privés dans l’objet de données utilisé pour la prise en charge inter-processus. Pour prendre en charge l’objet d’assistance par glisser-déplacer, votre implémentation IDataObject::SetData doit être en mesure d’accepter et de stocker des formats privés arbitraires.

Une fois les données supprimées, certains types de transfert de données Shell nécessitent que la cible appelle IDataObject::SetData pour fournir à l’objet de données des informations sur le résultat de l’opération de suppression. Par exemple, lors du déplacement de fichiers avec une opération de déplacement optimisée, la cible supprime normalement les fichiers d’origine, mais elle n’est pas tenue de le faire. La cible indique à l’objet de données s’il a supprimé les fichiers en appelant IDataObject::SetData avec un format CFSTR_LOGICALPERFORMEDDROPEFFECT . Il existe plusieurs autres formats de Presse-papiers Shell qui sont également utilisés par la cible pour transmettre des informations à l’objet de données. Votre implémentation IDataObject::SetData doit être en mesure de reconnaître ces formats et de répondre de manière appropriée. Pour plus d’informations, consultez Gestion des scénarios de transfert de données shell.

Méthode EnumFormatEtc

Lorsque la cible reçoit un objet de données, elle appelle généralement FORMATETC pour déterminer les formats que contient l’objet. La méthode crée un objet d’énumération OLE et retourne un pointeur vers l’interface IEnumFORMATETC de l’objet. La cible utilise ensuite l’interface pour énumérer les formats disponibles.

Un objet d’énumération doit toujours énumérer les formats disponibles par ordre de qualité, en commençant par le meilleur. La qualité relative des formats est définie par la source de suppression. En général, les formats de qualité supérieure contiennent les données les plus riches et les plus complètes. Par instance, une image couleur 24 bits est normalement considérée comme de qualité supérieure à celle d’une version à l’échelle du gris de cette image. La raison de l’énumération des formats par ordre de qualité est que les cibles énumèrent généralement jusqu’à ce qu’elles accèdent à un format qu’elles prennent en charge, puis qu’elles utilisent ce format pour extraire les données. Pour que cette procédure produise le meilleur format disponible que la cible peut prendre en charge, les formats doivent être énumérés par ordre de qualité.

Un objet d’énumération pour les données Shell est implémenté de la même manière que pour d’autres types de transfert de données, à une exception notable. Étant donné que les objets de données ne contiennent généralement qu’un seul élément de données par format, ils énumèrent normalement chaque format passé à IDataObject::SetData. Toutefois, comme indiqué dans la section Méthode SetData , les objets de données Shell peuvent contenir plusieurs formats CFSTR_FILECONTENTS .

Étant donné que l’objectif d’IDataObject::EnumFormatEtc est de permettre à la cible de déterminer les types de données présents, il n’est pas nécessaire d’énumérer plusieurs CFSTR_FILECONTENTS format. Si la cible doit savoir combien de ces formats l’objet de données contient, la cible peut récupérer ces informations à partir du format CFSTR_FILEDESCRIPTOR associé. Pour plus d’informations sur l’implémentation d’IDataObject::EnumFormatEtc, consultez la documentation de référence de la méthode.

Méthode GetData

La cible appelle IDataObject::GetData pour extraire un format de données particulier. La cible spécifie le format en transmettant la structure FORMATETC appropriée. IDataObject::GetData retourne la structure STGMEDIUM du format.

La cible peut définir le membre tymed de la structure FORMATETC sur une valeur TYMED_XXX spécifique pour spécifier le mécanisme de transfert de données qu’elle utilisera pour extraire les données. Toutefois, la cible peut également effectuer une requête plus générique et laisser l’objet de données décider. Pour demander à l’objet de données de sélectionner le mécanisme de transfert de données, la cible définit toutes les valeurs TYMED_XXX qu’elle prend en charge. IDataObject::GetData sélectionne l’un de ces mécanismes de transfert de données et retourne la structure STGMEDIUM appropriée. Pour instance, tymed est généralement défini sur TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE demander l’un des trois mécanismes de transfert de données Shell.

Notes

Étant donné qu’il peut y avoir plusieurs formats CFSTR_FILECONTENTS , les membres cfFormat et liés de la structure FORMATETC ne sont pas suffisants pour indiquer la structure STGMEDIUMIDataObject::GetData à retourner. Pour le format CFSTR_FILECONTENTS, IDataObject::GetData doit également examiner le membre lIndex de la structure FORMATETC afin de retourner la structure STGMEDIUM correcte.

 

Le format CFSTR_INDRAGLOOP est placé dans des objets de données pour permettre aux cibles de case activée la status de la boucle de glisser-déplacer tout en évitant le rendu des données de l’objet nécessitant beaucoup de mémoire. Les données du format sont une valeur DWORD définie sur une valeur différente de zéro si l’objet de données se trouve dans une boucle de glisser. La valeur des données du format est définie sur zéro si les données ont été supprimées. Si une cible demande ce format et qu’il n’a pas été chargé par la source, IDataObject::GetData doit répondre comme si la source avait chargé le format avec une valeur zéro.

Lorsque le curseur se trouve sur la fenêtre cible, la cible peut utiliser l’objet d’assistance glisser-déplacer pour spécifier l’image de glissement. L’objet d’assistance glisser-déplacer appelle IDataObject::SetData pour charger des formats privés dans l’objet de données utilisé pour la prise en charge inter-processus. Il appelle plus tard IDataObject::GetData pour les récupérer. Pour prendre en charge l’objet d’assistance par glisser-déplacer, votre implémentation d’objet de données Shell doit être en mesure de retourner des formats privés arbitraires lorsqu’ils sont demandés.

Implémentation d’IDropSource

La source doit créer un objet qui expose une interface IDropSource . Cette interface permet à la source de mettre à jour l’image de glisser qui indique la position actuelle du curseur et de fournir des commentaires au système sur la façon de mettre fin à une opération de glisser-déplacer. IDropSource a deux méthodes : GiveFeedback et QueryContinueDrag.

GiveFeedback (méthode)

Dans la boucle de glissement, une source de déplacement est responsable du suivi de la position du curseur et de l’affichage d’une image de glisser appropriée. Toutefois, dans certains cas, vous pouvez modifier l’apparence de l’image glisser lorsqu’elle se trouve sur la fenêtre de la cible de déplacement.

Lorsque le curseur entre ou quitte la fenêtre cible et qu’il se déplace sur la fenêtre cible, le système appelle régulièrement l’interface IDropTarget de la cible. La cible répond avec une valeur DROPEFFECT qui est transmise à la source via la méthode GiveFeedback . Si nécessaire, la source peut modifier l’apparence du curseur en fonction de la valeur DROPEFFECT . Pour plus d’informations, consultez les références GiveFeedback et DoDragDrop .

QueryContinueDrag (méthode)

Cette méthode est appelée si l’état du bouton de la souris ou du clavier change lorsque l’objet de données se trouve dans la boucle de glissement. Il indique à la source si la touche Échap a été enfoncée et fournit l’état actuel des touches de modificateur du clavier, telles que CTRL ou Maj. La valeur de retour de la méthode QueryContinueDrag spécifie l’une des trois actions suivantes :

  • S_OK. Continuer l’opération de glissement
  • DRAGDROP_S_DROP. Supprimez les données. Le système appelle ensuite la méthode IDropTarget::D rop de la cible.
  • DRAGDROP_S_CANCEL. Terminez la boucle de glisser sans supprimer les données. Cette valeur est normalement retournée si la touche ESCAPE a été enfoncée.

Pour plus d’informations, consultez les références QueryContinueDrag et DoDragDrop .

Comment une cible gère un objet de données

La cible reçoit un objet de données lorsqu’elle récupère l’objet de données du Presse-papiers ou l’a supprimé dans la fenêtre cible par l’utilisateur. La cible peut ensuite extraire des données de l’objet de données. Si nécessaire, la cible peut également notifier l’objet de données du résultat de l’opération. Avant un transfert de données Shell, une cible de suppression doit se préparer à l’opération :

  1. La cible doit appeler RegisterClipboardFormat pour obtenir une valeur de format de Presse-papiers valide pour tous les formats Shell, autres que CF_HDROP, qui peuvent être inclus dans l’objet de données. CF_HDROP est déjà un format de Presse-papiers valide et n’a pas besoin d’être inscrit.
  2. Pour prendre en charge une opération de glisser-déplacer, la cible doit implémenter une interface IDropTarget et inscrire une fenêtre cible. Pour inscrire une fenêtre cible, la cible appelle RegisterDragDrop et passe le handle de la fenêtre et le pointeur d’interface IDropTarget .

Pour les transferts dans le Presse-papiers, la cible ne reçoit aucune notification indiquant qu’un objet de données a été placé dans le Presse-papiers. En règle générale, une application est avertie qu’un objet se trouve dans le Presse-papiers par une action utilisateur, par exemple en cliquant sur le bouton Coller dans la barre d’outils de l’application. La cible récupère ensuite le pointeur IDataObject de l’objet de données dans le Presse-papiers en appelant OleGetClipboard. Pour les transferts de données par glisser-déplacer, le système utilise l’interface IDropTarget de la cible pour fournir à la cible des informations sur la progression du transfert de données :

  • Le système appelle IDropTarget::D ragEnter lorsque le curseur entre dans la fenêtre cible.
  • Le système appelle régulièrement IDropTarget::D ragOver lorsque le curseur passe sur la fenêtre cible, pour donner à la cible la position actuelle du curseur.
  • Le système appelle IDropTarget::D ragLeave lorsque le curseur quitte la fenêtre cible.
  • Le système appelle IDropTarget::D rop lorsque l’utilisateur supprime l’objet de données dans la fenêtre cible.

Pour plus d’informations sur l’implémentation de ces méthodes, consultez IDropTarget.

Lorsque les données sont supprimées, IDropTarget::D rop fournit à la cible un pointeur vers l’interface IDataObject de l’objet de données. La cible utilise ensuite cette interface pour extraire des données de l’objet de données.

Extraction de données shell à partir d’un objet de données

Une fois qu’un objet de données a été supprimé ou récupéré dans le Presse-papiers, la cible peut extraire les données dont elle a besoin. La première étape du processus d’extraction consiste généralement à énumérer les formats contenus dans l’objet de données :

  • Appelez IDataObject::EnumFormatEtc. L’objet de données crée un objet d’énumération OLE standard et retourne un pointeur vers son interface IEnumFORMATETC .
  • Utilisez les méthodes IEnumFORMATETC pour énumérer les formats contenus par l’objet de données. Cette opération récupère généralement une structure FORMATETC pour chaque format que l’objet contient. Toutefois, l’objet énumération ne retourne normalement qu’une seule structure FORMATETC pour le format CFSTR_FILECONTENTS , quel que soit le nombre de formats contenus par l’objet de données.
  • Sélectionnez un ou plusieurs formats à extraire et stockez leurs structures FORMATETC .

Pour récupérer un format particulier, transmettez la structure FORMATETC associée à IDataObject::GetData. Cette méthode retourne une structure STGMEDIUM qui fournit l’accès aux données. Pour spécifier un mécanisme de transfert de données particulier, définissez la valeur liée de la structure FORMATETC sur la valeur TYMED_XXX correspondante. Pour demander à l’objet de données de sélectionner un mécanisme de transfert de données, la cible définit les valeurs TYMED_XXX pour chaque mécanisme de transfert de données que la cible peut gérer. L’objet de données sélectionne l’un de ces mécanismes de transfert de données et retourne la structure STGMEDIUM appropriée.

Pour la plupart des formats, la cible peut récupérer les données en transmettant la structure FORMATETC qu’elle a reçue lors de l’énumération des formats disponibles. L’une des exceptions à cette règle est CFSTR_FILECONTENTS. Étant donné qu’un objet de données peut contenir plusieurs instances de ce format, la structure FORMATETC retournée par l’énumérateur peut ne pas correspondre au format particulier que vous souhaitez extraire. En plus de spécifier les membres cfFormat et tymed , vous devez également définir le membre lIndex sur la valeur d’index du fichier. Pour plus d’informations, consultez la section Utilisation du format CFSTR_FILECONTENTS pour extraire des données à partir d’un fichier de gestion des scénarios de transfert de données de l’interpréteur de commandes

Le processus d’extraction de données dépend du type de pointeur contenu par la structure STGMEDIUM retournée. Si la structure contient un pointeur vers une interface IStream ou IStorage , utilisez les méthodes d’interface pour extraire les données. Le processus d’extraction de données à partir d’un objet de mémoire globale est décrit dans la section suivante.

Extraction d’un objet de mémoire globale à partir d’un objet de données

La plupart des formats de données Shell se présentent sous la forme d’un objet de mémoire globale. Utilisez la procédure suivante pour extraire un format contenant un objet de mémoire globale d’un objet de données et affecter ses données à une variable locale :

  1. Créez une structure FORMATETC . Définissez le membre cfFormat sur la valeur de format du Presse-papiers appropriée et le membre tyd sur TYMED_HGLOBAL.

  2. Créez une structure STGMEDIUM vide.

  3. Appelez IDataObject::GetData et passez des pointeurs vers les structures FORMATETC et STGMEDIUM .

    Quand IDataObject::GetData retourne, la structure STGMEDIUM contient un pointeur vers l’objet de mémoire globale qui contient les données.

  4. Attribuez les données à une variable locale en appelant GlobalLock et en transmettant le membre hGlobal de la structure STGMEDIUM .

  5. Appelez GlobalUnlock pour libérer le verrou sur l’objet mémoire globale.

  6. Appelez ReleaseStgMedium pour libérer l’objet mémoire globale.

Notes

Vous devez utiliser ReleaseStgMedium pour libérer l’objet mémoire globale, et non GlobalFree.

 

L’exemple suivant montre comment extraire une valeur DWORD stockée en tant qu’objet mémoire globale à partir d’un objet de données. Le paramètre pdtobj est un pointeur vers l’interface IDataObject de l’objet de données, cf est le format du Presse-papiers qui identifie les données souhaitées et pdwOut est utilisé pour renvoyer la valeur des données.

STDAPI DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{    STGMEDIUM medium;
   FORMATETC fmte = {(CLIPFORMAT) cf, NULL, DVASPECT_CONTENT, -1, 
       TYMED_HGLOBAL};
    HRESULT hres = pdtobj->GetData(&fmte, &medium);
    if (SUCCEEDED(hres))
   {
       DWORD *pdw = (DWORD *)GlobalLock(medium.hGlobal);
       if (pdw)
       {
           *pdwOut = *pdw;
           GlobalUnlock(medium.hGlobal);
       }
       else
       {
           hres = E_UNEXPECTED;
       }
       ReleaseStgMedium(&medium);
   }
   return hres;
}

Implémentation d’IDropTarget

Le système utilise l’interface IDropTarget pour communiquer avec la cible pendant que le curseur se trouve sur la fenêtre cible. Les réponses de la cible sont transférées à la source via son interface IDropSource . En fonction de la réponse, la source peut modifier l’icône qui représente les données. Si la cible de suppression doit spécifier l’icône de données, elle peut le faire en créant un objet d’assistance glisser-déplacer.

Avec les opérations de glisser-déplacer conventionnelles, la cible informe l’objet de données du résultat de l’opération en définissant le paramètre pdwEffect de IDropTarget::D rop sur la valeur DROPEFFECT appropriée. Avec les objets de données Shell, la cible peut également devoir appeler IDataObject::SetData. Pour une présentation de la façon dont les cibles doivent répondre aux différents scénarios de transfert de données, consultez Gestion des scénarios de transfert de données shell.

Les sections suivantes expliquent brièvement comment implémenter les méthodes IDropTarget::D ragEnter, IDropTarget::D ragOver et IDropTarget::D rop . Pour plus d’informations, consultez la documentation de référence.

DragEnter, méthode

Le système appelle la méthode IDropTarget::D ragEnter lorsque le curseur entre dans la fenêtre cible. Ses paramètres fournissent à la cible l’emplacement du curseur, l’état des touches de modification du clavier telles que la touche CTRL et un pointeur vers l’interface IDataObject de l’objet de données. La cible est responsable de l’utilisation de cette interface pour déterminer si elle peut accepter l’un des formats contenus par l’objet de données. S’il le peut, il laisse normalement la valeur de pdwEffect inchangée. S’il ne peut accepter aucune donnée de l’objet de données, il définit le paramètre pdwEffect sur DROPEFFECT_NONE. Le système transmet la valeur de ce paramètre à l’interface IDropSource de l’objet de données pour lui permettre d’afficher l’image de glisser appropriée.

Les cibles ne doivent pas utiliser la méthode IDataObject::GetData pour afficher les données shell avant qu’elles n’ont été supprimées. Le rendu complet des données de l’objet pour chaque occurrence de ce type peut entraîner le blocage du curseur de glissement. Pour éviter ce problème, certains objets Shell contiennent un format CFSTR_INDRAGLOOP . En extrayant ce format, les cibles peuvent case activée la status de la boucle de glissement tout en évitant un rendu gourmand en mémoire des données de l’objet. La valeur de données du format est un DWORD défini sur une valeur différente de zéro si l’objet de données se trouve dans une boucle de glissement. La valeur des données du format est définie sur zéro si les données ont été supprimées.

Si la cible peut accepter des données de l’objet de données, elle doit examiner grfKeyState pour déterminer si des touches de modification ont été enfoncées pour modifier le comportement normal de la suppression. Par instance, l’opération par défaut est généralement un déplacement, mais la pression sur la touche CTRL indique généralement une opération de copie.

Lorsque le curseur se trouve sur la fenêtre cible, la cible peut utiliser l’objet d’assistance glisser-déplacer pour remplacer l’image glisser-déplacer de l’objet de données par la sienne. Dans ce cas, IDropTarget::D ragEnter doit appeler IDropTargetHelper::D ragEnter pour transmettre les informations contenues dans les paramètres DragEnter à l’objet d’assistance glisser-déplacer.

DragOver, méthode

Lorsque le curseur se déplace dans la fenêtre cible, le système appelle régulièrement la méthode IDropTarget::D ragOver . Ses paramètres fournissent à la cible l’emplacement du curseur et l’état des touches de modification du clavier telles que la touche CTRL. IDropTarget::D ragOver a les mêmes responsabilités que IDropTarget::D ragEnter, et les implémentations sont généralement très similaires.

Si la cible utilise l’objet d’assistance glisser-déplacer, IDropTarget::D ragOver doit appeler IDropTargetHelper::D ragOver pour transférer les informations contenues dans les paramètres DragOver à l’objet d’assistance glisser-déplacer.

Drop, méthode

Le système appelle la méthode IDropTarget::D rop pour informer la cible que l’utilisateur a supprimé les données, généralement en relâchant le bouton de la souris. IDropTarget::D rop a les mêmes paramètres que IDropTarget::D ragEnter. La cible répond normalement en extrayant un ou plusieurs formats de l’objet de données. Lorsque vous avez terminé, la cible doit définir le paramètre pdwEffect sur une valeur DROPEFFECT qui indique le résultat de l’opération. Pour certains types de transfert de données Shell, la cible doit également appeler IDataObject::SetData pour passer un format avec des informations supplémentaires sur le résultat de l’opération à l’objet de données. Pour une discussion détaillée, consultez Gestion des scénarios de transfert de données shell.

Si la cible utilise l’objet d’assistance glisser-déplacer, IDropTarget::D rop doit appeler IDropTargetHelper::D rop pour transférer les informations contenues dans les paramètres IDropTargetHelper::D ragOver à l’objet d’assistance glisser-déplacer.

Utilisation de l’objet d’assistance glisser-déplacer

L’objet d’assistance glisser-déplacer (CLSID_DragDropHelper) est exporté par l’interpréteur de commandes pour permettre aux cibles de spécifier l’image de glissement alors qu’elle se trouve sur la fenêtre cible. Pour utiliser l’objet d’assistance glisser-déplacer, créez un objet serveur in-process en appelant CoCreateInstance avec un identificateur de classe (CLSID) de CLSID_DragDropHelper. L’objet d’assistance glisser-déplacer expose deux interfaces utilisées de la manière suivante :

  • L’interface IDragSourceHelper permet à la cible de déplacement de spécifier une icône pour représenter l’objet de données.
  • L’interface IDropTargetHelper permet à la cible de déplacement d’informer l’objet d’assistance par glisser-déplacer de l’emplacement du curseur et d’afficher ou de masquer l’icône de données.

Utilisation de l’interface IDragSourceHelper

L’interface IDragSourceHelper est exposée par l’objet d’assistance glisser-déplacer pour permettre à une cible de déplacement de fournir l’image qui sera affichée pendant que le curseur se trouve sur la fenêtre cible. IDragSourceHelper fournit deux autres façons de spécifier la bitmap à utiliser comme image de glisser :

  • Les cibles de déplacement qui ont une fenêtre peuvent inscrire un message de fenêtre DI_GETDRAGIMAGE pour celle-ci en initialisant l’objet d’assistance glisser-déplacer avec IDragSourceHelper::InitializeFromWindow. Lorsque la cible reçoit un message DI_GETDRAGIMAGE, le gestionnaire place les informations bitmap de l’image glisser dans la structure SHDRAGIMAGE qui est passée en tant que valeur lParam du message.
  • Les cibles de dépôt sans fenêtre spécifient une bitmap lorsqu’elles initialisent l’objet d’assistance glisser-déplacer avec IDragSourceHelper::InitializeFromBitmap.

Utilisation de l’interface IDropTargetHelper

Cette interface permet à la cible de déplacement de notifier l’objet d’assistance glisser-déplacer lorsque le curseur entre ou quitte la cible. Lorsque le curseur se trouve sur la fenêtre cible, IDropTargetHelper permet à la cible de fournir à l’objet d’assistance par glisser-déplacer les informations que la cible reçoit via son interface IDropTarget .

Quatre des méthodes IDropTargetHelper (IDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper::D ragOver et IDropTargetHelper::D rop) sont associées à la méthode IDropTarget du même nom. Pour utiliser l’objet d’assistance glisser-déplacer, chacune des méthodes IDropTarget doit appeler la méthode IDropTargetHelper correspondante pour transférer les informations à l’objet d’assistance glisser-déplacer. La cinquième méthode IDropTargetHelper , IDropTargetHelper::Show, avertit l’objet d’assistance glisser-déplacer pour afficher ou masquer l’image de glissement. Cette méthode est utilisée lors du glisser-déplacer sur une fenêtre cible dans un mode vidéo de faible profondeur de couleur. Il permet à la cible de masquer l’image de glissement pendant qu’elle peint la fenêtre.