Partager via


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

Le document Objet de données Shell a abordé l’approche générale utilisée pour transférer des données Shell avec 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 et techniques généraux aux différentes façons dont les données Shell peuvent être transférées. Ce document présente des scénarios courants de transfert de données Shell et explique comment implémenter chacun d’eux dans votre application.

Remarque

Bien que chacun de ces scénarios traite d’une opération de transfert de données spécifique, plusieurs d’entre eux s’appliquent à divers scénarios connexes. Par exemple, la principale différence entre la plupart des transferts de Presse-papiers et de glisser-déplacer est 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 largement identiques pour les deux types de transfert de données. Toutefois, certains scénarios sont limités à un type spécifique d’opération. Pour plus d’informations, reportez-vous au scénario individuel.

 

Instructions générales

Chacune des sections suivantes décrit 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. En règle générale, vous ne savez pas, à l’avance, quel scénario vous devrez réellement gérer. Voici quelques recommandations 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 des 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. En règle générale, vous ne savez 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 des formats CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Cette approche permet à la cible de créer un fichier à partir d’un objet de données sans avoir à savoir quoi que ce soit sur le stockage de données sous-jacent. Vous devez normalement présenter les données en tant qu’interface IStream . Ce mécanisme de transfert de données est plus flexible qu’un objet mémoire global et utilise beaucoup moins de mémoire.
  • Les sources de glisser doivent offrir le format CFSTR_SHELLIDLIST lors du glisser-déplacer 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 sur les éléments déplacés à l’aide du modèle de programmation d’éléments de l’interpréteur de commandes peuvent convertir un IDataObject en IShellItemArray à l’aide de SHCreateShellItemArrayFromDataObject.
  • Utilisez des curseurs de commentaires standard.
  • Prise en charge de la gauche et de 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 doit offrir et d’éviter de créer une couche supplémentaire de confinement. Par exemple, un objet incorporé à partir du serveur A est déplacé à partir du serveur/conteneur B et supprimé 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 optimisé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’emplacement de l’objet. Étant donné que vous ne savez généralement pas à l’avance 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 dans l’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 dans l’énumération qu’ils peuvent prendre en charge.
  • Prendre en charge le glisser vers la droite. Vous pouvez personnaliser le menu contextuel glisser-déplacer 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 règle générale, les applications qui acceptent des fichiers doivent également gérer les formats CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Bien que les fichiers du système de fichiers aient le format CF_HDROP, les fichiers provenant de fournisseurs tels que les extensions d’espace de noms utilisent généralement CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Par exemple, 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 des données à partir de son stockage en tant que fichier.
  • N’oubliez pas que l’interpréteur de commandes peut utiliser des opérations de déplacement ou de suppression optimisé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 dans une application

Scénario : un utilisateur sélectionne un ou plusieurs fichiers dans l’Explorateur Windows 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é, par exemple, pour permettre à un utilisateur de créer un lien HTML en coupant et en collant le fichier à 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’ancrage.

Lorsqu’un utilisateur sélectionne un fichier dans l’Explorateur Windows 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 d’énumérateur.
  3. Utilisez l’interface IEnumFORMATETC de l’objet énumérateur pour énumérer les formats contenus par l’objet de données.

Remarque

Les deux dernières étapes de cette procédure sont incluses pour l’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 à partir de l’objet de données

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 de glisser-déplacer.

La façon la 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 tymed 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 retourne, 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 vers une structure DROPFILES suivie d’une chaîne double terminée par 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 d’accès aux fichiers dans la liste. L’index de base zéro du chemin d’accès au fichier dans cette liste est utilisé à l’étape suivante pour identifier un chemin particulier.

  4. Extrayez les chemins de fichier 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 au fichier en fonction des besoins et collez-les dans votre application.

  6. Appelez ReleaseStgMedium et passez 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 l’Explorateur Windows et les supprime dans la fenêtre de votre application. Votre application extrait le contenu du fichier (s) et le colle dans l’application.

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

  1. Appelez RegisterClipboardFormat pour inscrire 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. L’Explorateur Windows crée un objet de données et charge les formats pris en charge.
  2. L’Explorateur Windows appelle DoDragDrop pour lancer la boucle de glisser.
  3. Lorsque l’image glisser 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 par l’objet de données. Si votre application ne souhaite pas accepter ces formats, retournez DROPEFFECT_NONE. Dans le cadre de ce scénario, votre application doit ignorer 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 processus d’extraction de données sera 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 retard inutile. Pour plus d’informations sur la façon de gérer l’extraction de données asynchrones, consultez Glisser-déplacer des objets Shell de manière asynchrone.

Utilisation du format CFSTR_FILECONTENTS pour extraire des données à partir 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 forme de fichier unique. Tout ce qui est requis pour ce format est que l’objet de données présente les données à la cible comme s’il s’agissait d’un fichier. Par exemple, les données réelles peuvent être une section d’un document texte ou un bloc de données extraits d’une base de données. La cible peut traiter les données en tant que fichier et n’a pas besoin de savoir quoi que ce soit sur 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 le mécanisme de stockage pratique et utiliser ce format pour présenter ses objets aux applications comme s’ils étaient des 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 mémoire globale, et IStream est un moyen plus simple de représenter les données que 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 de 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 global. Verrouillez cet objet en passant la valeur hGlobal à GlobalLock.
  3. Cassez le pointeur retourné par GlobalLock en pointeur FILEGROUPDESCRIPTOR. Il pointe vers une structure FILEGROUPDESCRIPTOR suivie d’une ou plusieurs structures FILEDESCRIPTOR . Chaque structure FILEDESCRIPTOR contient une description d’un fichier contenu par l’un des formats de CFSTR_FILECONTENTS qui accompagnent.
  4. Examinez les structures FILEDESCRIPTOR pour déterminer celle qui 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 par octet, utilisez les membres nFileSizeLow et nFileSizeHigh de la structure pour déterminer le nombre d’octets qui représentent le fichier dans l’objet mémoire globale.
  5. Appelez IDataObject ::GetData avec le membre cfFormat de la structure FORMATETC définie 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 tymed 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 contiendra un pointeur vers les données du fichier. Examinez le membre tymed 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 global. Pour une discussion sur l’extraction de données à partir d’un objet mémoire globale, consultez la section Extraction d’un objet mémoire globale à partir d’une section d’objet de données de l’objet de données Shell.
  8. Appelez GlobalLock pour déverrouiller l’objet 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 classique, 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 shell conviennent parfaitement aux déplacements optimisés, car la cible peut gérer toute l’opération à l’aide de l’API Shell. Un exemple typique consiste à déplacer des fichiers. Une fois que la cible a le chemin d’accès d’un fichier à déplacer, elle peut utiliser SHFileOperation pour la déplacer. Il n’est pas nécessaire que la source supprime le fichier d’origine.

Remarque

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 , indiquant 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 s’il 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 reçue par le biais de 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 la transmet à un identificateur de format CFSTR_PERFORMEDDROPEFFECT défini sur 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é :

  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 delete-on-paste

Scénario : un ou plusieurs fichiers sont coupés d’un dossier dans l’Explorateur Windows et collés dans une extension d’espace de noms. L’Explorateur Windows laisse les fichiers mis 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 les données, elle disparaît immédiatement de la vue. Cela peut ne pas être efficace et peut entraîner des problèmes d’utilisation si l’utilisateur se préoccupe de ce qui s’est passé aux données. Une autre approche consiste à utiliser une opération delete-on-paste.

Avec une opération de suppression sur collage, les données sélectionnées ne sont pas immédiatement supprimées de l’affichage. 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 informe 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 à son apparence d’origine.

Remarque

L’interpréteur de commandes utilise normalement delete-on-paste lorsqu’une opération couper/coller est utilisée pour déplacer des fichiers. Les opérations de suppression sur 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 capable de détecter et de gérer les opérations de suppression sur collage.

 

L’exigence essentielle pour la suppression sur le 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 coller, 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 d’une opération delete-on-paste est la suivante :

  1. La source marque l’affichage de l’écran des données sélectionnées.
  2. La source crée un objet de données. Il 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 uniquement sur DROPEFFECT_MOVE, 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 vérifier s’il 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 à son apparence d’origine.

Transfert de données vers et depuis des dossiers virtuels

Scénario : un utilisateur fait glisser un objet à partir d’un dossier virtuel ou le supprime.

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, comme 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 par un dossier virtuel sont présentés par l’interpréteur de commandes comme s’ils étaient des fichiers et dossiers normaux. Il incombe au dossier virtuel de prendre les données qu’il contient et de les présenter correctement à l’interpréteur de commandes. Cette exigence signifie que les dossiers virtuels prennent normalement en charge les transferts de données glisser-déplacer et 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 :

  • Développeurs dont les applications doivent accepter les données transférées à partir d’un dossier virtuel.
  • 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 n’importe quelle façon qu’elles choisissent. Certains dossiers virtuels peuvent contenir des fichiers et dossiers normaux du système de fichiers. D’autres peuvent, par exemple, packer tous leurs objets dans un document ou une base de données unique.

Lorsqu’un objet de système de fichiers est transféré à une application, l’objet de données contient normalement un format CF_HDROP avec le chemin 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 de 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 global, 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 son intégralité. Le transfert d’un pointeur d’interface nécessite presque aucune 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 que 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 façon de gérer les formats CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/, consultez Utilisation du format CFSTR_FILECONTENTS pour extraire des données à partir d’un fichier.

Transfert de données vers et depuis une extension NameSpace

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

  • Être en mesure de gérer les formats CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/. 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 delete-on-paste . L’interpréteur de commandes utilise delete-on-paste lorsque les objets sont déplacés 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 à partir d’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épôt, l’extension d’espace de noms doit extraire les données du stockage et les transmettre à la cible via cette interface.
      • En tant que cible déroulante, une extension d’espace de noms doit accepter les données d’une source via cette interface et la stocker correctement.

Suppression de fichiers dans la Corbeille

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

La Corbeille est un dossier virtuel utilisé comme référentiel 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 ultérieurement 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 sur 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 connaître le dossier sur lequel 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é sur 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 de la Corbeille (CLSID) (CLSID_RecycleBin). Pour gérer correctement le cas de 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.

Remarque

Lorsque IDataObject ::SetData est appelé avec un format CFSTR_TARGETCLSID défini sur CLSID_RecycleBin , la source de données doit fermer les handles ouverts aux objets transférés avant de revenir 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 le supprime sur le bureau ou l’Explorateur Windows.

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 dans 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 est extrait du nom court inscrit pour le CLSID de l’objet et les 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 récupération :

  • 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 de transférer un objet de données vers un autre conteneur, puis de revenir au document d’origine. Par exemple, 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 dans la feuille de calcul, les données doivent être intégrées dans le document tel qu’il était 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 la récupération est transférée vers un autre conteneur, elle est transférée 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 de données contenu dans la récupération 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 vérifie le Registre pour obtenir la liste des formats disponibles. Par défaut, il existe deux formats disponibles : CF_EMBEDSOURCE et CF_LINKSOURCE. Toutefois, il existe un certain nombre de scénarios où les applications peuvent avoir besoin d’avoir des fichiers de récupération dans différents formats :

  • Pour permettre le transfert de récupérations vers des conteneurs non OLE, qui ne peuvent pas accepter les formats d’objet 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 à la récupération 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 son intégralité dans la récupération de l’objet de données.
  • Formats rendus différés. 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 par délai, 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 mise en cache de priorité ou format rendu par délai, créez une sous-clé numérotée commençant par zéro. Définissez la valeur de cette clé sur une chaîne portant le nom inscrit du format ou une valeur de #X, où X représente le numéro de format d’un format Presse-papiers standard.

L’exemple suivant montre les formats mis en cache pour deux applications. L’application MyProg1 a le format de texte enrichi sous la forme d’un format de cache de priorité 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 de priorité.

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 frais de 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 retardé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.

Remarque

Étant donné que le rendu retardé est quelque peu risqué, il doit être utilisé avec précaution. Cela ne fonctionnera pas si le serveur n’est pas disponible ou sur les applications qui ne sont pas activées par 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 durée 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 synchrone peut bloquer les threads principaux des deux applications pendant une durée importante. En particulier, les deux threads doivent attendre pendant que la cible extrait les données. Pour de 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. Elle permet à la cible de suppression d’extraire des données de l’objet de données de manière asynchrone sur un thread d’arrière-plan. Une fois que l’extraction de données est remise au thread d’arrière-plan, les threads principaux des deux applications sont libres de continuer.

Utilisation de IASyncOperation/IDataObjectAsyncCapability

Remarque

L’interface a été initialement nommée IAsyncOperation, mais elle a été modifiée ultérieurement en IDataObjectAsyncCapability. Sinon, les deux interfaces sont identiques.

 

L’objectif d’IAsyncOperation /IDataObjectAsyncCapability est d’autoriser la source de suppression et la cible de suppression à négocier si les données peuvent être extraites de manière asynchrone. La procédure suivante décrit comment la source drop 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 et continuer.
    • Si InOperation retourne VARIANT_TRUE, les données sont extraites de façon asynchrone. Les opérations de nettoyage doivent être gérées par EndOperation.
  4. Relâchez l’objet de données.
  5. Une fois le transfert de données asynchrone terminé, l’objet de données avertit normalement la source via une interface privée.

La procédure suivante décrit comment la cible drop 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 IDataObjectAsyncCapability 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 normale de transfert de données. 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 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éblocé et libre de continuer.
  6. Si le transfert de données était une opération de déplacement ou de suppression 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.