Initialisation des gestionnaires d’extensions shell

Une grande partie de l’implémentation d’un objet gestionnaire d’extension Shell est dictée par son type. Il y a cependant quelques éléments communs. Cette rubrique traite des aspects de l’implémentation partagés par tous les gestionnaires d’extension Shell.

Tous les gestionnaires d’extension Shell sont des objets COM (Component Object Model) in-process. Ils doivent se voir attribuer un GUID et les inscrire comme décrit dans Inscription des gestionnaires d’extensions shell. Elles sont implémentées en tant que DLL et doivent exporter les fonctions standard suivantes :

  • DllMain. Point d’entrée standard de la DLL.
  • DllGetClassObject. Expose la fabrique de classes de l’objet.
  • DllCanUnloadNow. COM appelle cette fonction pour déterminer si l’objet sert des clients. Si ce n’est pas le cas, le système peut décharger la DLL et libérer la mémoire associée.

Comme tous les objets COM, les gestionnaires d’extension Shell doivent implémenter une interface IUnknown et une fabrique de classes. La plupart doivent également implémenter une interface IPersistFile ou IShellExtInit dans Windows XP ou une version antérieure. Ils ont été remplacés par IInitializeWithStream, IInitializeWithItem et IInitializeWithFile dans Windows Vista. L’interpréteur de commandes utilise ces interfaces pour initialiser le gestionnaire.

L’interface IPersistFile doit être implémentée par les éléments suivants :

  • Gestionnaires d’icônes
  • Gestionnaires de données
  • Drop handlers

L’interface IShellExtInit doit être implémentée par les éléments suivants :

  • Gestionnaires de menu contextuel
  • Gestionnaires glisser-déplacer
  • Gestionnaires de feuilles de propriétés

Les sujets suivants sont abordés dans le reste de cette rubrique :

Implémentation d’IPersistFile

L’interface IPersistFile est conçue pour permettre le chargement d’un objet à partir d’un fichier disque ou son enregistrement dans celui-ci. Il a six méthodes en plus de IUnknown, cinq de ses propres et la méthode GetClassID qu’il hérite d’IPersist. Avec les extensions Shell, IPersist est utilisé uniquement pour initialiser un objet gestionnaire d’extensions Shell. Étant donné qu’il n’est généralement pas nécessaire de lire ou d’écrire sur le disque, seules les méthodes GetClassID et Load nécessitent une implémentation non-automatique.

L’interpréteur de commandes appelle d’abord GetClassID , et la fonction retourne l’identificateur de classe (CLSID) de l’objet gestionnaire d’extensions. L’interpréteur de commandes appelle ensuite Load et passe deux valeurs. Le premier, pszFile, est une chaîne Unicode portant le nom du fichier ou du dossier sur lequel Shell est sur le point d’opérer. Le second est dwMode, qui indique le mode d’accès aux fichiers. Étant donné qu’il n’est normalement pas nécessaire d’accéder aux fichiers, dwMode est généralement égal à zéro. La méthode stocke ces valeurs si nécessaire pour une référence ultérieure.

Le fragment de code suivant illustre comment un gestionnaire d’extension Shell classique implémente les méthodes GetClassID et Load . Il est conçu pour gérer ANSI ou Unicode. CLSID_SampleExtHandler est le GUID de l’objet de gestionnaire d’extension, et CSampleShellExtension est le nom de la classe utilisée pour implémenter l’interface. Les variables m_szFileName et m_dwMode sont des variables privées utilisées pour stocker le nom et les indicateurs d’accès du fichier.

class CSampleShellExtension : public IPersistFile
{
    // Method declarations not included

    private:
    WCHAR m_szFileName[MAX_PATH];    // The file name
    DWORD m_dwMode;                  // The file access mode
}

IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID)
{
    *pCLSID = CLSID_SampleExtHandler;
}

IFACEMETHODIMP CSampleShellExtension::Load(PCWSTR pszFile, DWORD dwMode)
{
    m_dwMode = dwMode;
    return StringCchCopy(m_szFileName, ARRAYSIZE(m_szFileName), pszFile); 
}

// The implementation sample is continued in the next section.

Implémentation d’IShellExtInit

L’interface IShellExtInit a une seule méthode, IShellExtInit::Initialize, en plus de IUnknown. La méthode a trois paramètres que l’interpréteur de commandes peut utiliser pour passer différents types d’informations. Les valeurs passées dépendent du type de gestionnaire, et certaines peuvent être définies sur NULL.

  • pidlFolder contient le pointeur d’un dossier vers une liste d’identificateurs d’élément (PIDL). Il s’agit d’un PIDL absolu. Pour les extensions de feuille de propriétés, cette valeur est NULL. Pour les extensions de menu contextuel, il s’agit du PIDL du dossier qui contient l’élément dont le menu contextuel est affiché. Pour les gestionnaires de glisser-déplacer non par défaut, il s’agit du PIDL du dossier cible.
  • pDataObject contient un pointeur vers l’interface IDataObject d’un objet de données. L’objet de données contient un ou plusieurs noms de fichiers au format CF_HDROP .
  • hRegKey contient une clé de Registre pour l’objet fichier ou le type de dossier.

La méthode IShellExtInit::Initialize stocke le nom de fichier, le pointeur IDataObject et la clé de Registre si nécessaire pour une utilisation ultérieure. Le fragment de code suivant illustre une implémentation de IShellExtInit::Initialize. Par souci de simplicité, cet exemple suppose que l’objet de données ne contient qu’un seul fichier. En général, l’objet de données peut contenir plusieurs fichiers, chacun devant être extrait.

// This code continues the CSampleShellExtension sample shown in the
// "Implementing IPersistFile" section above.

class CSampleShellExtension : public IShellExtInit
{
    // Method declarations not included
    
    private:
    // IDList of the folder for extensions invoked on the folder, such as 
    // background context menu handlers or nondefault drag-and-drop handlers. 
    PIDLIST_ABSOLUTE m_pidlFolder;
    
    // The data object contains an expression of the items that the handler is 
    // being initialized for. Use SHCreateShellItemArrayFromDataObject to 
    // convert this object to an array of items. Use SHGetItemFromObject if you
    // are only interested in a single Shell item. If you need a file system
    // path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...).
    IDataObject *m_pdtobj;
    
    // For context menu handlers, the registry key provides access to verb 
    // instance data that might be stored there. This is a rare feature to use 
    // so most extensions do not need this variable.
    HKEY m_hRegKey;             
}
    
// This method must be very efficient. Do not do any unnecessary work here.
// Use Initialize to acquire resources that will be used later.

IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt PCIDLIST_ABSOLUTE pidlFolder,
                                                 __in_opt IDataObject *pDataObject, 
                                                 __in_opt HKEY hRegKey) 
{ 
    // In some cases, handlers are initialized multiple times. Therefore, 
    // clear any previous state here.
    CoTaskMemFree(m_pidlFolder);
    m_pidlFolder = NULL;
    
    if (m_pdtobj)
    { 
        m_pdtobj->Release(); 
    }
    
    if (m_hRegKey)
    {
        RegCloseKey(m_hRegKey);
        m_hRegKey = NULL;
    }
    
    // Capture the inputs for use later.
    HRESULT hr = S_OK;
    
    if (pidlFolder)
    {
        m_pidlFolder = ILClone(pidlFolder);   // Make a copy to use later.
        hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY;
    }
    
    if (SUCCEEDED(hr))
    {
        // If a data object pointer was passed into the method, save it and
        // extract the file name. 
        if (pDataObject) 
        { 
            m_pdtobj = pDataObject; 
            m_pdtobj->AddRef(); 
        }
    
        // It is uncommon to use the registry handle, but if you need it,
        // duplicate it now.
        if (hRegKey)
        {
            LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey); 
            hr = HRESULT_FROM_WIN32(result);
        }
    }
    
    return hr;
}

Personnalisation de l’info-bulle

Il existe deux façons de personnaliser les info-bulles. Une méthode consiste à implémenter un objet qui prend en charge IQueryInfo , puis à inscrire l’objet sous la sous-clé appropriée dans le Registre (voir ci-dessous). Vous pouvez également spécifier une chaîne fixe ou une liste de certaines propriétés de fichier à afficher.

Pour afficher une chaîne fixe pour une extension d’espace de noms, créez une sous-clé appelée Info-bulle sous la clé CLSID de votre extension d’espace de noms. Définissez les données de cette sous-clé sur la chaîne que vous souhaitez afficher.

HKEY_CLASSES_ROOT
   CLSID
      {CLSID}
         InfoTip = InfoTip string for your namespace extension

Pour afficher une chaîne fixe pour un type de fichier, créez une sous-clé appelée Info-bulle sous la clé ProgID du type de fichier pour lequel vous souhaitez fournir des info-bulles. Définissez les données de cette sous-clé sur la chaîne que vous souhaitez afficher.

HKEY_CLASSES_ROOT
   ProgID
      InfoTip = InfoTip string for all files of this type

Si vous souhaitez que l’interpréteur de commandes affiche certaines propriétés de fichier dans l’info-bulle pour un type de fichier spécifique, créez une sous-clé appelée InfoTip sous la clé ProgID de ce type de fichier. Définissez les données de cette sous-clé sur une liste délimitée par des points-virgules de noms de propriétés canoniques ou {fmtid}, paires pid où propname est un nom de propriété canonique et {fmtid},pid est une paire FMTID/PID.

HKEY_CLASSES_ROOT
   ProgID
      InfoTip = propname;propname;{fmtid},pid;{fmtid},pid

Les noms de propriétés suivants peuvent être utilisés.

Nom de la propriété Description Récupéré à partir de
Auteur Auteur du document PIDSI_AUTHOR
Titre Titre du document PIDSI_TITLE
Objet Résumé de l’objet PIDSI_SUBJECT
Commentaire Commentaires de document PIDSI_COMMENT ou propriétés de dossier/lecteur
PageCount Nombre de pages PIDSI_PAGECOUNT
Nom Nom convivial Affichage des dossiers standard
OriginalLocation Emplacement du fichier d’origine Dossier porte-documents et Dossier de la Corbeille
DateDeleted Le fichier de date a été supprimé Dossier de la Corbeille
Type Type de fichier Vue des détails du dossier standard
Taille Taille du fichier Vue des détails du dossier standard
SyncCopyIn Identique à OriginalLocation Identique à OriginalLocation
Modifié le Date de dernière modification Vue des détails du dossier standard
Date de création Date de création Vue des détails du dossier standard
Consulté Date du dernier accès Vue des détails du dossier standard
InFolder Répertoire contenant le fichier Résultats de la recherche de document
Rank Qualité de la correspondance de recherche Résultats de la recherche de document
FreeSpace Espace de stockage disponible Lecteurs de disque
NumberOfVisits Nombre de visites Dossier Favoris
Attributs Attributs de fichier Vue des détails du dossier standard
Company Nom de la société PIDDSI_COMPANY
Category Catégorie de document PIDDSI_CATEGORY
copyright Droits d’auteur multimédias PIDMSI_COPYRIGHT
HTMLInfoTipFile Fichier info-bulle HTML fichier Desktop.ini pour le dossier

 

Enregistrement de gestionnaires d’extensions d’environnement