Gestion des scénarios de transfert de données de Shell

Le document Shell Data Object décrit l’approche générale utilisée pour transférer des données Shell avec le glisser-déplacer ou le Presse-papiers. Toutefois, pour implémenter le transfert de données Shell dans votre application, vous devez également comprendre comment appliquer ces principes généraux et techniques aux différentes façons dont les données Shell peuvent être transférées. Ce document présente les scénarios de transfert de données Shell courants et explique comment implémenter chacun d’eux dans votre application.

Notes

Bien que chacun de ces scénarios traite d’une opération de transfert de données spécifique, la plupart d’entre eux s’appliquent à divers scénarios connexes. Par instance, la principale différence entre la plupart des transferts de Presse-papiers et de glisser-déplacer réside dans la façon dont l’objet de données arrive à la cible. Une fois que la cible a un pointeur vers l’interface IDataObject de l’objet de données, les procédures d’extraction d’informations sont en grande partie les mêmes pour les deux types de transfert de données. Toutefois, certains scénarios sont limités à un type d’opération spécifique. Pour plus d’informations, reportez-vous au scénario individuel.

 

Instructions générales

Chacune des sections suivantes traite d’un scénario de transfert de données unique et assez spécifique. Toutefois, les transferts de données sont souvent plus complexes et peuvent impliquer des aspects de plusieurs scénarios. Vous ne savez généralement pas à l’avance quel scénario vous devez réellement gérer. Voici quelques instructions générales à garder à l’esprit.

Pour les sources de données :

  • Les formats du Presse-papiers Shell, à l’exception de CF_HDROP, ne sont pas prédéfinis. Chaque format que vous souhaitez utiliser doit être inscrit en appelant RegisterClipboardFormat.
  • Les formats dans les objets de données sont fournis dans l’ordre de préférence de la source. Énumérez l’objet de données et choisissez le premier que vous pouvez consommer.
  • Incluez autant de formats que vous pouvez prendre en charge. Vous ne savez généralement pas où l’objet de données sera supprimé. Cette pratique améliore les chances que l’objet de données contienne un format que la cible de suppression peut accepter.
  • Les fichiers existants doivent être proposés au format CF_HDROP .
  • Proposez des données de type fichier avec CFSTR_FILECONTENTS/ formatsCFSTR_FILEDESCRIPTOR. Cette approche permet à la cible de créer un fichier à partir d’un objet de données sans avoir besoin de connaître quoi que ce soit sur le stockage de données sous-jacent. Vous devez normalement présenter les données sous forme d’interface IStream . Ce mécanisme de transfert de données est plus flexible qu’un objet de mémoire globale et utilise beaucoup moins de mémoire.
  • Les sources de glisser doivent offrir le format CFSTR_SHELLIDLIST lors du déplacement des éléments shell. Les objets de données pour les éléments peuvent être acquis via les méthodes IShellFolder::GetUIObjectOf ou IShellItem::BindToHandler . Les sources de données peuvent créer une implémentation d’objet de données standard qui prend en charge le format CFSTR_SHELLIDLIST à l’aide de SHCreateDataObject.
  • Les cibles de suppression qui souhaitent raisonner les éléments déplacés à l’aide du modèle de programmation d’élément d’interpréteur de commandes peuvent convertir un IDataObject en IShellItemArray à l’aidede SHCreateShellItemArrayFromDataObject.
  • Utilisez des curseurs de commentaires standard.
  • Prise en charge du glisser vers la gauche et la droite.
  • Utilisez l’objet de données lui-même à partir d’un objet incorporé. Cette approche permet à votre application de récupérer tous les formats supplémentaires que l’objet de données a à offrir et évite de créer une couche supplémentaire de confinement. Par instance, un objet incorporé du serveur A est déplacé à partir du serveur/conteneur B et déposé sur le conteneur C. C doit créer un objet incorporé du serveur A, et non un objet incorporé du serveur B contenant un objet incorporé du serveur A.
  • N’oubliez pas que l’interpréteur de commandes peut utiliser des opérations de déplacement ou de suppression sur collageoptimisées lors du déplacement de fichiers. Votre application doit être en mesure de reconnaître ces opérations et de répondre de manière appropriée.

Pour les cibles de données :

  • Les formats du Presse-papiers Shell, à l’exception de CF_HDROP, ne sont pas prédéfinis. Chaque format que vous souhaitez utiliser doit être inscrit en appelant RegisterClipboardFormat.
  • Implémentez et inscrivez une cible de suppression OLE. Évitez d’utiliser des cibles Windows 3.1 ou le message WM_DROPFILES , si possible.
  • Les formats contenus par un objet de données varient en fonction de l’endroit d’où provient l’objet. Étant donné que vous ne savez généralement pas à l’avance d’où provient un objet de données, ne supposez pas qu’un format particulier sera présent. L’objet de données doit énumérer les formats par ordre de qualité, en commençant par le meilleur. Ainsi, pour obtenir le meilleur format disponible, les applications énumèrent normalement les formats disponibles et utilisent le premier format de l’énumération qu’elles peuvent prendre en charge.
  • Prise en charge du glisser vers la droite. Vous pouvez personnaliser le menu contextuel glisser en créant un gestionnaire de glisser-déplacer.
  • Si votre application accepte des fichiers existants, elle doit être en mesure de gérer le format CF_HDROP .
  • En général, les applications qui acceptent des fichiers doivent également gérer les formats CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR . Alors que les fichiers du système de fichiers ont le format CF_HDROP , les fichiers de fournisseurs tels que les extensions d’espace de noms utilisent généralement CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Les exemples incluent les dossiers Windows CE, les dossiers FTP (File Transfer Protocol), les dossiers web et les dossiers CAB. La source implémente normalement une interface IStream pour présenter les données de son stockage sous forme de fichier.
  • N’oubliez pas que l’interpréteur de commandes peut utiliser des opérations de déplacement ou de suppression sur collageoptimisées lors du déplacement de fichiers. Votre application doit être en mesure de reconnaître ces opérations et de répondre de manière appropriée.

Copie de noms de fichiers du Presse-papiers vers une application

Scénario: Un utilisateur sélectionne un ou plusieurs fichiers dans Windows Explorer et les copie dans le Presse-papiers. Votre application extrait les noms de fichiers et les colle dans le document.

Ce scénario peut être utilisé, pour instance, pour permettre à un utilisateur de créer un lien HTML en coupant et collant le fichier dans votre application. Votre application peut ensuite extraire le nom de fichier de l’objet de données et le traiter pour créer une balise d’ancre.

Lorsqu’un utilisateur sélectionne un fichier dans Windows Explorer et le copie dans le Presse-papiers, l’interpréteur de commandes crée un objet de données. Il appelle ensuite OleSetClipboard pour placer un pointeur vers l’interface IDataObject de l’objet de données dans le Presse-papiers.

Lorsque l’utilisateur sélectionne la commande Coller dans le menu ou la barre d’outils de votre application :

  1. Appelez OleGetClipboard pour récupérer l’interface IDataObject de l’objet de données.
  2. Appelez IDataObject::EnumFormatEtc pour demander un objet énumérateur.
  3. Utilisez l’interface IEnumFORMATETC de l’objet énumérateur pour énumérer les formats contenus par l’objet de données.

Notes

Les deux dernières étapes de cette procédure sont incluses pour des fins d’exhaustivité. Ils ne sont généralement pas nécessaires pour les transferts de fichiers simples. Tous les objets de données utilisés pour ce type de transfert de données doivent contenir le format CF_HDROP , qui peut être utilisé pour déterminer les noms des fichiers contenus par l’objet. Toutefois, pour les transferts de données plus généraux, vous devez énumérer les formats et sélectionner le meilleur que votre application peut gérer.

 

Extraction des noms de fichiers de l’objet Data

L’étape suivante consiste à extraire un ou plusieurs noms de fichiers de l’objet de données et à les coller dans votre application. Notez que la procédure décrite dans cette section pour extraire un nom de fichier à partir d’un objet de données s’applique également aux transferts par glisser-déplacer.

Le moyen le plus simple de récupérer des noms de fichiers à partir d’un objet de données est le format CF_HDROP :

  1. Appelez IDataObject::GetData. Définissez le membre cfFormat de la structure FORMATETC sur CF_HDROP et le membre tydé sur TYMED_HGLOBAL. Le membre dwAspect est normalement défini sur DVASPECT_CONTENT. Toutefois, si vous devez avoir le chemin d’accès du fichier au format court (8.3), définissez dwAspect sur DVASPECT_SHORT.

    Lorsque IDataObject::GetData est retourné, le membre hGlobal de la structure STGMEDIUM pointe vers un objet mémoire global qui contient les données.

  2. Créez une variable HDROP et définissez-la sur le membre hGlobal de la structure STGMEDIUM . La variable HDROP est désormais un handle pour une structure DROPFILES suivie d’une chaîne à double fin null contenant les chemins d’accès complets des fichiers copiés.

  3. Déterminez le nombre de chemins d’accès aux fichiers dans la liste en appelant DragQueryFile avec le paramètre iFile défini sur 0xFFFFFFFF. La fonction retourne le nombre de chemins de fichiers dans la liste. L’index de base zéro du chemin d’accès du fichier dans cette liste est utilisé à l’étape suivante pour identifier un chemin d’accès particulier.

  4. Extrayez les chemins d’accès aux fichiers de l’objet mémoire globale en appelant DragQueryFile une fois pour chaque fichier, avec iFile défini sur l’index du fichier.

  5. Traitez les chemins d’accès aux fichiers en fonction des besoins et collez-les dans votre application.

  6. Appelez ReleaseStgMedium et transmettez le pointeur vers la structure STGMEDIUM que vous avez passée à IDataObject::GetData à l’étape 1. Une fois que vous avez libéré la structure, la valeur HDROP que vous avez créée à l’étape 2 n’est plus valide et ne doit pas être utilisée.

Copie du contenu d’un fichier supprimé dans une application

Scénario: Un utilisateur fait glisser un ou plusieurs fichiers à partir de Windows Explorer et les dépose dans la fenêtre de votre application. Votre application extrait le contenu du ou des fichiers et le colle dans l’application.

Ce scénario utilise le glisser-déplacer pour transférer les fichiers de Windows Explorer vers l’application. Avant l’opération, votre application doit :

  1. Appelez RegisterClipboardFormat pour inscrire tous les formats de Presse-papiers shell nécessaires.
  2. Appelez RegisterDragDrop pour inscrire une fenêtre cible et l’interface IDropTarget de votre application.

Une fois que l’utilisateur a lancé l’opération en sélectionnant un ou plusieurs fichiers et en commençant à les faire glisser :

  1. Windows Explorer crée un objet de données et y charge les formats pris en charge.
  2. Windows Explorer appelle DoDragDrop pour lancer la boucle de glissement.
  3. Lorsque l’image de glissement atteint votre fenêtre cible, le système vous avertit en appelant IDropTarget::D ragEnter.
  4. Pour déterminer ce que contient l’objet de données, appelez la méthode IDataObject::EnumFormatEtc de l’objet de données. Utilisez l’objet énumérateur retourné par la méthode pour énumérer les formats contenus dans l’objet de données. Si votre application ne souhaite accepter aucun de ces formats, retournez DROPEFFECT_NONE. Dans le cadre de ce scénario, votre application doit ignorer tous les objets de données qui ne contiennent pas de formats utilisés pour transférer des fichiers, tels que CF_HDROP.
  5. Lorsque l’utilisateur supprime les données, le système appelle IDropTarget::D rop.
  6. Utilisez l’interface IDataObject pour extraire le contenu des fichiers.

Il existe plusieurs façons d’extraire le contenu d’un objet Shell à partir d’un objet de données. En général, utilisez l’ordre suivant :

  • Si le fichier contient un format CF_TEXT , les données sont du texte ANSI. Vous pouvez utiliser le format CF_TEXT pour extraire les données, au lieu d’ouvrir le fichier lui-même.
  • Si le fichier contient un objet OLE lié ou incorporé, l’objet de données contient un format CF_EMBEDDEDOBJECT. Utilisez des techniques OLE standard pour extraire les données. Les fichiers de récupération contiennent toujours un format CF_EMBEDDEDOBJECT.
  • Si l’objet Shell provient du système de fichiers, l’objet de données contient un format CF_HDROP avec les noms des fichiers. Extrayez le nom de fichier de CF_HDROP et appelez OleCreateFromFile pour créer un objet lié ou incorporé. Pour savoir comment récupérer un nom de fichier à partir d’un format CF_HDROP , consultez Copie de noms de fichiers du Presse-papiers vers une application.
  • Si l’objet de données contient un format CFSTR_FILEDESCRIPTOR , vous pouvez extraire le contenu d’un fichier à partir du format CFSTR_FILECONTENTS du fichier. Pour plus d’informations sur cette procédure, consultez Utilisation du format CFSTR_FILECONTENTS pour extraire des données d’un fichier.
  • Avant la version 4.71 de Shell, une application indiquait qu’elle transférait un type de fichier de raccourci en définissant FD_LINKUI dans le membre dwFlags de la structure FILEDESCRIPTOR . Pour les versions ultérieures de l’interpréteur de commandes, la méthode recommandée pour indiquer que des raccourcis sont transférés consiste à utiliser le format CFSTR_PREFERREDDROPEFFECT défini sur DROPEFFECT_LINK. Cette approche est beaucoup plus efficace que l’extraction de la structure FILEDESCRIPTOR pour case activée un indicateur.

Si le processus d’extraction de données est long, vous pouvez effectuer l’opération de manière asynchrone sur un thread d’arrière-plan. Votre thread principal peut ensuite continuer sans délai inutile. Pour plus d’informations sur la façon de gérer l’extraction asynchrone de données, consultez Glisser-déplacer des objets shell de manière asynchrone.

Utilisation du format CFSTR_FILECONTENTS pour extraire des données d’un fichier

Le format CFSTR_FILECONTENTS offre un moyen très flexible et puissant de transférer le contenu d’un fichier. Il n’est même pas nécessaire que les données soient stockées sous la forme d’un fichier unique. Pour ce format, il suffit que l’objet de données présente les données à la cible comme s’il s’agissait d’un fichier. Par instance, les données réelles peuvent être une section d’un document texte ou un bloc de données extraites d’une base de données. La cible peut traiter les données comme un fichier et n’a pas besoin de connaître le mécanisme de stockage sous-jacent.

Les extensions d’espace de noms utilisent normalement CFSTR_FILECONTENTS pour transférer des données, car ce format ne suppose aucun mécanisme de stockage particulier. Une extension d’espace de noms peut utiliser n’importe quel mécanisme de stockage pratique et utiliser ce format pour présenter ses objets aux applications comme s’il s’agissait de fichiers.

Le mécanisme de transfert de données pour CFSTR_FILECONTENTS est normalement TYMED_ISTREAM. Le transfert d’un pointeur d’interface IStream nécessite beaucoup moins de mémoire que le chargement des données dans un objet de mémoire globale, et IStream est un moyen plus simple de représenter des données qu’IStorage.

Un format CFSTR_FILECONTENTS est toujours accompagné d’un format CFSTR_FILEDESCRIPTOR . Vous devez d’abord examiner le contenu de ce format. Si plusieurs fichiers sont transférés, l’objet de données contient en fait plusieurs formats CFSTR_FILECONTENTS , un pour chaque fichier. Le format CFSTR_FILEDESCRIPTOR contient le nom et les attributs de chaque fichier, et fournit une valeur d’index pour chaque fichier nécessaire pour extraire le format CFSTR_FILECONTENTS d’un fichier particulier.

Pour extraire un format CFSTR_FILECONTENTS :

  1. Extrayez le format CFSTR_FILEDESCRIPTOR en tant que valeur TYMED_HGLOBAL .
  2. Le membre hGlobal de la structure STGMEDIUM retournée pointe vers un objet mémoire globale. Verrouillez cet objet en passant la valeur hGlobal à GlobalLock.
  3. Cast du pointeur retourné par GlobalLock en pointeur FILEGROUPDESCRIPTOR . Elle pointe vers une structure FILEGROUPDESCRIPTOR suivie d’une ou plusieurs structures FILEDESCRIPTOR . Chaque structure FILEDESCRIPTOR contient une description d’un fichier contenu dans l’un des formats de CFSTR_FILECONTENTS qui l’accompagnent.
  4. Examinez les structures FILEDESCRIPTOR pour déterminer laquelle correspond au fichier que vous souhaitez extraire. L’index de base zéro de cette structure FILEDESCRIPTOR est utilisé pour identifier le format CFSTR_FILECONTENTS du fichier. Étant donné que la taille d’un bloc de mémoire global n’est pas précise en octets, utilisez les membres nFileSizeLow et nFileSizeHigh de la structure pour déterminer le nombre d’octets qui représentent le fichier dans l’objet de mémoire globale.
  5. Appelez IDataObject::GetData avec le membre cfFormat de la structure FORMATETC défini sur la valeur CFSTR_FILECONTENTS et le membre lIndex défini sur l’index que vous avez déterminé à l’étape précédente. Le membre lié est généralement défini sur TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE. L’objet de données peut ensuite choisir son mécanisme de transfert de données préféré.
  6. La structure STGMEDIUM retournée par IDataObject::GetData contient un pointeur vers les données du fichier. Examinez le membre tyd de la structure pour déterminer le mécanisme de transfert de données.
  7. Si tymed est défini sur TYMED_ISTREAM ou TYMED_ISTORAGE, utilisez l’interface pour extraire les données. Si tymed est défini sur TYMED_HGLOBAL, les données sont contenues dans un objet mémoire globale. Pour savoir comment extraire des données d’un objet mémoire globale, consultez la section Extraction d’un objet mémoire globale à partir d’un objet de données de Shell Data Object.
  8. Appelez GlobalLock pour déverrouiller l’objet de mémoire globale que vous avez verrouillé à l’étape 2.

Gestion des opérations de déplacement optimisées

Scénario: Un fichier est déplacé du système de fichiers vers une extension d’espace de noms à l’aide d’un déplacement optimisé.

Dans une opération de déplacement conventionnelle, la cible effectue une copie des données et la source supprime l’original. Cette procédure peut être inefficace, car elle nécessite deux copies des données. Avec des objets volumineux tels que des bases de données, une opération de déplacement conventionnelle peut même ne pas être pratique.

Avec un déplacement optimisé, la cible utilise sa compréhension de la façon dont les données sont stockées pour gérer l’ensemble de l’opération de déplacement. Il n’y a jamais de deuxième copie des données et il n’est pas nécessaire que la source supprime les données d’origine. Les données de l’interpréteur de commandes sont bien adaptées aux déplacements optimisés, car la cible peut gérer l’ensemble de l’opération à l’aide de l’API Shell. Un exemple classique est le déplacement de fichiers. Une fois que la cible a le chemin d’accès d’un fichier à déplacer, elle peut utiliser SHFileOperation pour le déplacer. Il n’est pas nécessaire que la source supprime le fichier d’origine.

Notes

L’interpréteur de commandes utilise normalement un déplacement optimisé pour déplacer des fichiers. Pour gérer correctement le transfert de données shell, votre application doit être capable de détecter et de gérer un déplacement optimisé.

 

Les déplacements optimisés sont gérés de la manière suivante :

  1. La source appelle DoDragDrop avec le paramètre dwEffect défini sur DROPEFFECT_MOVE pour indiquer que les objets sources peuvent être déplacés.

  2. La cible reçoit la valeur DROPEFFECT_MOVE via l’une de ses méthodes IDropTarget , ce qui indique qu’un déplacement est autorisé.

  3. La cible copie l’objet (déplacement non optimisé) ou déplace l’objet (déplacement optimisé).

  4. La cible indique ensuite à la source si elle doit supprimer les données d’origine.

    Un déplacement optimisé est l’opération par défaut, avec les données supprimées par la cible. Pour informer la source qu’un déplacement optimisé a été effectué :

      • La cible définit la valeur pdwEffect qu’elle a reçue via sa méthode IDropTarget::D rop sur une valeur autre que DROPEFFECT_MOVE. Il est généralement défini sur DROPEFFECT_NONE ou DROPEFFECT_COPY. La valeur est retournée à la source par DoDragDrop.
      • La cible appelle également la méthode IDataObject::SetData de l’objet de données et lui transmet un identificateur de format CFSTR_PERFORMEDDROPEFFECT défini à DROPEFFECT_NONE. Cet appel de méthode est nécessaire, car certaines cibles de suppression peuvent ne pas définir correctement le paramètre pdwEffect de DoDragDrop . Le format CFSTR_PERFORMEDDROPEFFECT est le moyen fiable d’indiquer qu’un déplacement optimisé a eu lieu.

    Si la cible a effectué un déplacement non optimisé, les données doivent être supprimées par la source. Pour informer la source qu’un déplacement non optimisé a été effectué :

      • La cible définit la valeur pdwEffect qu’elle a reçue via sa méthode IDropTarget::D rop sur DROPEFFECT_MOVE. La valeur est retournée à la source par DoDragDrop.
      • La cible appelle également la méthode IDataObject::SetData de l’objet de données et lui transmet un identificateur de format CFSTR_PERFORMEDDROPEFFECT défini à DROPEFFECT_MOVE. Cet appel de méthode est nécessaire, car certaines cibles de suppression peuvent ne pas définir correctement le paramètre pdwEffect de DoDragDrop . Le format CFSTR_PERFORMEDDROPEFFECT est le moyen fiable d’indiquer qu’un déplacement non optimisé a eu lieu.
  5. La source inspecte les deux valeurs qui peuvent être retournées par la cible. Si les deux sont définis sur DROPEFFECT_MOVE, il termine le déplacement non optimisé en supprimant les données d’origine. Sinon, la cible a effectué un déplacement optimisé et les données d’origine ont été supprimées.

Gestion des opérations de suppression sur collage

Scénario: Un ou plusieurs fichiers sont coupés d’un dossier dans Windows Explorer et collés dans une extension d’espace de noms. Windows Explorer laisse les fichiers en surbrillance jusqu’à ce qu’il reçoive des commentaires sur le résultat de l’opération de collage.

Traditionnellement, lorsqu’un utilisateur coupe des données, elles disparaissent immédiatement de la vue. Cela peut ne pas être efficace et entraîner des problèmes d’utilisation si l’utilisateur s’inquiète de ce qui est arrivé aux données. Une autre approche consiste à utiliser une opération de suppression sur collage.

Avec une opération de suppression sur collage, les données sélectionnées ne sont pas immédiatement supprimées de la vue. Au lieu de cela, l’application source la marque comme sélectionnée, peut-être en modifiant la police ou la couleur d’arrière-plan. Une fois que l’application cible a collé les données, elle avertit la source du résultat de l’opération. Si la cible a effectué un déplacement optimisé, la source peut simplement mettre à jour son affichage. Si la cible a effectué un déplacement normal, la source doit également supprimer sa copie des données. Si le collage échoue, l’application source restaure les données sélectionnées à leur apparence d’origine.

Notes

L’interpréteur de commandes utilise normalement supprimer-coller lorsqu’une opération couper/coller est utilisée pour déplacer des fichiers. Les opérations de suppression-collage avec des objets Shell utilisent normalement un déplacement optimisé pour déplacer les fichiers. Pour gérer correctement le transfert de données shell, votre application doit être en mesure de détecter et de gérer les opérations de suppression sur collage.

 

L’exigence essentielle pour la suppression sur collage est que la cible doit signaler le résultat de l’opération à la source. Toutefois, les techniques standard du Presse-papiers ne peuvent pas être utilisées pour implémenter la suppression sur collage, car elles ne permettent pas à la cible de communiquer avec la source. Au lieu de cela, l’application cible utilise la méthode IDataObject::SetData de l’objet de données pour signaler le résultat à l’objet de données. L’objet de données peut ensuite communiquer avec la source via une interface privée.

La procédure de base pour une opération de suppression sur collage est la suivante :

  1. La source marque l’affichage à l’écran des données sélectionnées.
  2. La source crée un objet de données. Elle indique une opération de coupe en ajoutant le format CFSTR_PREFERREDDROPEFFECT avec une valeur de données de DROPEFFECT_MOVE.
  3. La source place l’objet de données dans le Presse-papiers à l’aide d’OleSetClipboard.
  4. La cible récupère l’objet de données du Presse-papiers à l’aide d’OleGetClipboard.
  5. La cible extrait les données CFSTR_PREFERREDDROPEFFECT . S’il est défini sur DROPEFFECT_MOVE uniquement, la cible peut effectuer un déplacement optimisé ou simplement copier les données.
  6. Si la cible n’effectue pas de déplacement optimisé, elle appelle la méthode IDataObject::SetData avec le format CFSTR_PERFORMEDDROPEFFECT défini sur DROPEFFECT_MOVE.
  7. Une fois le collage terminé, la cible appelle la méthode IDataObject::SetData avec le format CFSTR_PASTESUCCEEDED défini sur DROPEFFECT_MOVE.
  8. Lorsque la méthode IDataObject::SetData de la source est appelée avec le format CFSTR_PASTESUCCEEDED défini sur DROPEFFECT_MOVE, elle doit case activée pour voir si elle a également reçu le format CFSTR_PERFORMEDDROPEFFECT défini sur DROPEFFECT_MOVE. Si les deux formats sont envoyés par la cible, la source doit supprimer les données. Si seul le format CFSTR_PASTESUCCEEDED est reçu, la source peut simplement supprimer les données de son affichage. Si le transfert échoue, la source met à jour l’affichage vers son apparence d’origine.

Transfert de données vers et depuis des dossiers virtuels

Scénario: Un utilisateur fait glisser un objet à partir de ou le dépose dans un dossier virtuel.

Les dossiers virtuels contiennent des objets qui ne font généralement pas partie du système de fichiers. Certains dossiers virtuels, tels que la Corbeille, peuvent représenter des données stockées sur le disque dur, mais pas en tant qu’objets de système de fichiers ordinaires. Certains peuvent représenter des données stockées qui se trouvent sur un système distant, tel qu’un PC portable ou un site FTP. D’autres, comme le dossier Imprimantes, contiennent des objets qui ne représentent pas du tout les données stockées. Bien que certains dossiers virtuels font partie du système, les développeurs peuvent également créer et installer des dossiers virtuels personnalisés en implémentant une extension d’espace de noms.

Quel que soit le type de données ou la façon dont elles sont stockées, les objets de dossier et de fichier contenus dans un dossier virtuel sont présentés par l’interpréteur de commandes comme s’il s’agissait de fichiers et de dossiers normaux. Il incombe au dossier virtuel de prendre les données qu’il contient et de les présenter à l’interpréteur de commandes de manière appropriée. Cette exigence signifie que les dossiers virtuels prennent normalement en charge les transferts de données par glisser-déplacer et dans le Presse-papiers.

Il existe donc deux groupes de développeurs qui doivent être concernés par le transfert de données vers et depuis des dossiers virtuels :

  • Les développeurs dont les applications doivent accepter les données transférées à partir d’un dossier virtuel.
  • Les développeurs dont les extensions d’espace de noms doivent prendre correctement en charge le transfert de données.

Acceptation de données à partir d’un dossier virtuel

Les dossiers virtuels peuvent représenter pratiquement n’importe quel type de données et peuvent stocker ces données de la manière de leur choix. Certains dossiers virtuels peuvent en fait contenir des fichiers et des dossiers de système de fichiers normaux. D’autres peuvent, par instance, emballer tous leurs objets dans un document ou une base de données unique.

Lorsqu’un objet de système de fichiers est transféré vers une application, l’objet de données contient normalement un format CF_HDROP avec le chemin d’accès complet de l’objet. Votre application peut extraire cette chaîne et utiliser les fonctions normales du système de fichiers pour ouvrir le fichier et extraire ses données. Toutefois, étant donné que les dossiers virtuels ne contiennent généralement pas d’objets de système de fichiers normaux, ils n’utilisent généralement pas CF_HDROP.

Au lieu de CF_HDROP, les données sont normalement transférées à partir de dossiers virtuels avec les formats CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS . Le format CFSTR_FILECONTENTS présente deux avantages par rapport à CF_HDROP :

  • Aucune méthode particulière de stockage des données n’est supposée.
  • Le format est plus flexible. Il prend en charge trois mécanismes de transfert de données : un objet mémoire globale, une interface IStream ou une interface IStorage .

Les objets de mémoire globale sont rarement utilisés pour transférer des données vers ou depuis des objets virtuels, car les données doivent être copiées en mémoire dans leur intégralité. Le transfert d’un pointeur d’interface ne nécessite presque pas de mémoire et est beaucoup plus efficace. Avec des fichiers très volumineux, un pointeur d’interface peut être le seul mécanisme de transfert de données pratique. En règle générale, les données sont représentées par un pointeur IStream , car cette interface est un peu plus flexible qu’IStorage. La cible extrait le pointeur de l’objet de données et utilise les méthodes d’interface pour extraire les données.

Pour plus d’informations sur la gestion des formats CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/, consultez Utilisation du format CFSTR_FILECONTENTS pour extraire des données d’un fichier.

Transfert de données vers et depuis une extension NameSpace

Lorsque vous implémentez une extension d’espace de noms, vous souhaitez normalement prendre en charge les fonctionnalités de glisser-déplacer. Suivez les recommandations pour supprimer les sources et les cibles décrites dans les Instructions générales. En particulier, une extension d’espace de noms doit :

  • Être en mesure de gérer les formats CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Ces deux formats sont normalement utilisés pour transférer des objets vers et depuis des extensions d’espace de noms.
  • Être en mesure de gérer les déplacements optimisés. L’interpréteur de commandes s’attend à ce que les objets Shell soient déplacés avec un déplacement optimisé.
  • Être en mesure de gérer une opération de suppression sur collage . L’interpréteur de commandes utilise la suppression sur collage lorsque des objets sont déplacés à partir de l’interpréteur de commandes avec une opération couper/coller.
  • Être en mesure de gérer le transfert de données via une interface IStream ou IStorage . Le transfert de données vers ou depuis un dossier virtuel est normalement géré en transférant l’un de ces deux pointeurs d’interface, généralement un pointeur IStream . La cible appelle ensuite les méthodes d’interface pour extraire les données :
      • En tant que source de déplacement, l’extension d’espace de noms doit extraire les données du stockage et les transmettre via cette interface à la cible.
      • En tant que cible de déplacement, une extension d’espace de noms doit accepter les données d’une source via cette interface et les stocker correctement.

Suppression de fichiers dans la Corbeille

Scénario: L’utilisateur supprime un fichier dans la Corbeille. Votre extension d’application ou d’espace de noms supprime le fichier d’origine.

La Corbeille est un dossier virtuel utilisé comme dépôt pour les fichiers qui ne sont plus nécessaires. Tant que la Corbeille n’a pas été vidée, l’utilisateur peut récupérer le fichier et le retourner au système de fichiers.

Pour la plupart, le transfert d’objets Shell vers la Corbeille fonctionne comme n’importe quel autre dossier. Toutefois, lorsqu’un utilisateur supprime un fichier dans la Corbeille, la source doit supprimer l’original, même si les commentaires du dossier indiquent une opération de copie. Normalement, une source de suppression n’a aucun moyen de savoir dans quel dossier son objet de données a été supprimé. Toutefois, pour les systèmes Windows 2000 et ultérieurs, lorsqu’un objet de données est supprimé dans la Corbeille, l’interpréteur de commandes appelle la méthode IDataObject::SetData de l’objet de données avec un format CFSTR_TARGETCLSID défini sur l’identificateur de classe (CLSID) (CLSID_RecycleBin) de la Corbeille. Pour gérer correctement le cas de la Corbeille, votre objet de données doit être en mesure de reconnaître ce format et de communiquer les informations à la source via une interface privée.

Notes

Lorsque IDataObject::SetData est appelé avec un format CFSTR_TARGETCLSID défini sur CLSID_RecycleBin, la source de données doit fermer tous les handles ouverts aux objets transférés avant de retourner à partir de la méthode . Sinon, vous pouvez créer des violations de partage.

 

Création et importation de fichiers de récupération

Scénario: Un utilisateur fait glisser des données à partir du fichier de données d’une application OLE et les dépose sur le bureau ou windows Explorer.

Windows permet aux utilisateurs de faire glisser un objet à partir du fichier de données d’une application OLE et de le déposer sur le bureau ou un dossier de système de fichiers. Cette opération crée un fichier de récupération, qui contient les données ou un lien vers les données. Le nom de fichier provient du nom court inscrit pour le CLSID de l’objet et des données CF_TEXT . Pour que l’interpréteur de commandes crée un fichier de récupération contenant des données, l’interface IDataObject de l’application doit prendre en charge le format CF_EMBEDSOURCE Presse-papiers. Pour créer un fichier contenant un lien, IDataObject doit prendre en charge le format CF_LINKSOURCE.

Il existe également trois fonctionnalités facultatives qu’une application peut implémenter pour prendre en charge les fichiers de suppression :

  • Prise en charge des allers-retours
  • Formats de données mis en cache
  • Rendu différé

Prise en charge des allers-retours

Un aller-retour implique le transfert d’un objet de données vers un autre conteneur, puis le retour au document d’origine. Par instance, un utilisateur peut transférer un groupe de cellules d’une feuille de calcul vers le bureau, en créant un fichier de récupération avec les données. Si l’utilisateur transfère ensuite la récupération vers la feuille de calcul, les données doivent être intégrées dans le document comme avant le transfert d’origine.

Lorsque l’interpréteur de commandes crée le fichier de récupération, il représente les données en tant qu’objet d’incorporation. Lorsque le scrap est transféré vers un autre conteneur, il est transféré en tant qu’objet d’incorporation, même s’il est retourné au document d’origine. Votre application est chargée de déterminer le format des données contenues dans le scrap et de remettre les données dans son format natif si nécessaire.

Pour établir le format de l’objet incorporé, déterminez son CLSID en récupérant le format CF_OBJECTDESCRIPTOR de l’objet. Si le CLSID indique un format de données qui appartient à l’application, il doit transférer les données natives au lieu d’appeler OleCreateFromData.

Formats de données mis en cache

Lorsque l’interpréteur de commandes crée un fichier de récupération, il recherche dans le Registre la liste des formats disponibles. Par défaut, deux formats sont disponibles : CF_EMBEDSOURCE et CF_LINKSOURCE. Toutefois, il existe un certain nombre de scénarios dans lesquels les applications peuvent avoir besoin d’avoir des fichiers de récupération dans différents formats :

  • Pour permettre le transfert de scraps vers des conteneurs non OLE, qui ne peuvent pas accepter les formats d’objets incorporés.
  • Pour permettre aux suites d’applications de communiquer avec un format privé.
  • Pour faciliter la gestion des allers-retours.

Les applications peuvent ajouter des formats au scrap en les mettant en cache dans le Registre. Il existe deux types de formats mis en cache :

  • Formats de cache de priorité. Pour ces formats, les données sont copiées dans leur intégralité dans le scrap de l’objet de données.
  • Formats à rendu différé. Pour ces formats, l’objet de données n’est pas copié dans la récupération. Au lieu de cela, le rendu est retardé jusqu’à ce qu’une cible demande les données. Le rendu des retards est abordé plus en détail dans la section suivante.

Pour ajouter un cache de priorité ou un format à rendu différé, créez une sous-clé DataFormat sous la clé CLSID de l’application qui est la source des données. Sous cette sous-clé, créez une sous-clé PriorityCacheFormats ou DelayRenderFormats . Pour chaque cache de priorité ou format de rendu différé, créez une sous-clé numérotée commençant par zéro. Définissez la valeur de cette clé sur une chaîne avec le nom inscrit du format ou une valeur de #X, où X représente le numéro de format d’un format standard du Presse-papiers.

L’exemple suivant montre les formats mis en cache pour deux applications. L’application MyProg1 a le format de texte enrichi comme format de cache prioritaire, et un format privé « Mon format » en tant que format à rendu différé. L’application MyProg2 a le format CF_BITMAP (#8 ») comme format de cache prioritaire.

HKEY_CLASSES_ROOT
   CLSID
      {GUID}
         (Default) = MyProg1
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = Rich Text Format
            DelayRenderFormats
               0
                  (Default) = My Format
      {GUID}
         (Default) = MyProg2
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = #8

Des formats supplémentaires peuvent être ajoutés en créant des sous-clés numérotées supplémentaires.

Rendu différé

Un format de rendu différé permet à une application de créer un fichier de récupération, mais de retarder les dépenses liées au rendu des données jusqu’à ce qu’elles sont demandées par une cible. L’interface IDataObject d’un scrap offre les formats de rendu différés à la cible, ainsi que les données natives et mises en cache. Si la cible demande un format de rendu différé, l’interpréteur de commandes exécute l’application et fournit les données à la cible à partir de l’objet actif.

Notes

Étant donné que le rendu différé est quelque peu risqué, il doit être utilisé avec précaution. Cela ne fonctionne pas si le serveur n’est pas disponible ou sur les applications qui ne sont pas compatibles AVEC OLE.

 

Glisser-déplacer des objets shell de manière asynchrone

Scénario: Un utilisateur transfère un grand bloc de données de la source à la cible. Pour éviter de bloquer les deux applications pendant une période importante, la cible extrait les données de manière asynchrone.

Normalement, le glisser-déplacer est une opération synchrone. En bref :

  1. La source de suppression appelle DoDragDrop et bloque son thread principal jusqu’à ce que la fonction retourne. Le blocage du thread principal bloque normalement le traitement de l’interface utilisateur.
  2. Une fois la méthode IDropTarget::D rop de la cible appelée, la cible extrait les données de l’objet de données sur son thread principal. Cette procédure bloque normalement le traitement de l’interface utilisateur de la cible pendant la durée du processus d’extraction.
  3. Une fois les données extraites, la cible retourne l’appel IDropTarget::D rop , le système retourne DoDragDrop, et les deux threads peuvent continuer.

En bref, le transfert de données synchrones peut bloquer les threads principaux des deux applications pendant une période importante. En particulier, les deux threads doivent attendre que la cible extrait les données. Pour les petites quantités de données, le temps nécessaire à l’extraction des données est faible et le transfert de données synchrone fonctionne très bien. Toutefois, l’extraction synchrone de grandes quantités de données peut entraîner de longs retards et interférer avec l’interface utilisateur de la cible et de la source.

L’interface IAsyncOperation/IDataObjectAsyncCapability est une interface facultative qui peut être implémentée par un objet de données. Il donne à la cible de déplacement la possibilité d’extraire des données de l’objet de données de manière asynchrone sur un thread d’arrière-plan. Une fois l’extraction de données transmise au thread d’arrière-plan, les threads principaux des deux applications sont libres de continuer.

Utilisation d’IASyncOperation/IDataObjectAsyncCapability

Notes

L’interface s’appelait à l’origine IAsyncOperation, mais elle a été remplacée par IDataObjectAsyncCapability. Sinon, les deux interfaces sont identiques.

 

L’objectif d’IAsyncOperation/IDataObjectAsyncCapability est de permettre à la source de déplacement et à la cible de suppression de négocier si les données peuvent être extraites de manière asynchrone. La procédure suivante décrit la façon dont la source de suppression utilise l’interface :

  1. Créez un objet de données qui expose IAsyncOperation/IDataObjectAsyncCapability.
  2. Appelez SetAsyncMode avec fDoOpAsync défini sur VARIANT_TRUE pour indiquer qu’une opération asynchrone est prise en charge.
  3. Une fois doDragDrop retourné, appelez InOperation :
    • Si InOperation échoue ou retourne VARIANT_FALSE, un transfert de données synchrone normal a eu lieu et le processus d’extraction de données est terminé. La source doit effectuer tout nettoyage requis, puis continuer.
    • Si InOperation retourne VARIANT_TRUE, les données sont extraites de manière asynchrone. Les opérations de nettoyage doivent être gérées par EndOperation.
  4. Libérez l’objet de données.
  5. Une fois le transfert de données asynchrone terminé, l’objet de données avertit normalement la source par le biais d’une interface privée.

La procédure suivante décrit comment la cible de déplacement utilise l’interface IAsyncOperation/IDataObjectAsyncCapability pour extraire des données de manière asynchrone :

  1. Lorsque le système appelle IDropTarget::D rop, appelez IDataObject::QueryInterface et demandez une interface IAsyncOperation/IDataObjectAsyncCapability (IID_IAsyncOperation/IID_IDataObjectAsyncCapability) à partir de l’objet de données.
  2. Appelez GetAsyncMode. Si la méthode retourne VARIANT_TRUE, l’objet de données prend en charge l’extraction de données asynchrone.
  3. Créez un thread distinct pour gérer l’extraction de données et appeler StartOperation.
  4. Retournez l’appel IDropTarget::D rop , comme vous le feriez pour une opération de transfert de données normale. DoDragDrop retourne et débloque la source de dépôt. N’appelez pas IDataObject::SetData pour indiquer le résultat d’une opération de déplacement ou de suppression sur collage optimisée. Attendez que l’opération soit terminée.
  5. Extrayez les données sur le thread d’arrière-plan. Le thread principal de la cible est débloqué et libre de continuer.
  6. Si le transfert de données était une opération de déplacement ou de suppression sur collage optimisée, appelez IDataObject::SetData pour indiquer le résultat.
  7. Informez l’objet de données que l’extraction est terminée en appelant EndOperation.