2010-07-08 4 views
5

Maintenant que .NET CLR 4.0 prend en charge l'opération côte à côte (SxS), il devrait maintenant être possible d'écrire les extensions shell dans le code managé. J'ai tenté ceci et j'ai codé avec succès un Property Handler qui implémente IPropertyStore, IInitializeWithStream et IPropertyStoreCapabilities.Quelle est la bonne façon d'implémenter une extension de gestionnaire de gestionnaire de propriété géré?

Le gestionnaire fonctionne correctement et est appelé comme prévu lors de la navigation dans les fichiers via l'explorateur. Il fonctionne également très bien en affichant les propriétés personnalisées dans le panneau de prévisualisation et le panneau «détail» des propriétés du fichier.

Cependant, lorsque je tente de modifier une propriété dans le panneau de prévisualisation, puis cliquez sur "Enregistrer", j'obtiens une erreur "Fichier utilisé" indiquant que le fichier est ouvert dans l'Explorateur Windows.

Quelques petits morceaux:

  1. Lorsque les appels d'explorateur IInitializeWithStream.Initialize la propriété STGM est réglé sur STGM_SHARE_DENY_WRITE.
  2. Et à aucun moment l'explorateur n'a appelé IPropertyStore.SetValue ou IPropertyStore.Commit.
  3. Je vois des appels répétés à mon gestionnaire sur différents threads pour les mêmes propriétés de fichier.

Alors, que dois-je changer (ou définir dans le registre) pour que la sauvegarde de la propriété fonctionne?

Mise à jour:

Merci à Ben Je l'ai travail. La «partie difficile» (du moins pour moi) était de comprendre que COM Interop n'appellerait jamais Dispose ou Finalize sur mon PropertyHandler. Cela laissait les fichiers que j'ai traités ouverts jusqu'à ce que le GC fonctionne. Heureusement, le "protocole du gestionnaire de propriétés" fonctionne de sorte que lorsque IInitializeWithSream.Initialize() est appelé pour ReadValue(), le streamMode est ReadOnly, et quand il est appelé pour SetValue(), le streamMode est ReadWrite et Commit () sera appelé à la fin.

int IInitializeWithStream.Initialize(IStream stream, uint grfMode) 
{ 
    _stream = stream; 
    _streamMode = (Stgm)grfMode; 

    Load(); 

    // We release here cause if this is a read operation we won't get called back, 
    // and our finializer isn't called. 
    if ((_streamMode & Stgm.ReadWrite) != Stgm.ReadWrite) 
    { 
     Marshal.ReleaseComObject(_stream); 
     _stream = null; 
    } 
    return HResult.S_OK; 
} 

int IPropertyStore.Commit() 
{ 
    bool result = false; 

    if (_stream != null) 
    { 
     result = WriteStream(_stream); 
     Marshal.ReleaseComObject(_stream); 
     _stream = null; 
    } 

    return result ? HResult.S_OK : HResult.E_FAIL; 
} 

Répondre

3

Oui, vous devez AddRef() le flux de le garder ouvert et de conserver la référence en vie correctement.

Notez que l'indexeur utilisera votre gestionnaire de propriétés pour ouvrir le fichier également. Donc, si vous perdez l'objet stream, le fichier restera ouvert. Vous pouvez utiliser le paramètre sysinternals procexp pour indiquer le processus dans lequel le fichier est ouvert ou procmon pour indiquer les appels et les paramètres utilisés.

1

L'Explorateur tente de s'assurer qu'il n'interfère pas avec d'autres applications susceptibles d'avoir le fichier ouvert. Le fichier peut-il être légitimement utilisé par une autre application? Y a-t-il un gestionnaire d'aperçu ouvert? Parfois, nous voyons des gestionnaires de propriété qui gardent leurs flux ouverts plus longtemps que nécessaire (ou des gestionnaires de fichiers qui ouvrent le fichier avec des permissions restrictives). Pouvez-vous vérifier si vous publiez le flux en temps opportun? Enfin, je ne pense pas que cela soit lié à votre problème immédiat, mais l'utilisation des extensions shell .NET n'est pas supportée. Nous recommandons que cela ne soit pas incorporé dans un produit.

-Ben

+0

Il n'y a pas de gestionnaire d'aperçu, mais le service Windows Search semble charger le gestionnaire de temps en temps. Mais il ne devrait pas verrouiller le fichier? En outre, je peux faire fonctionner l'édition en passant à IInitializeWithFile, et mes SaveValue() et Commit() sont appelés comme prévu. Quoi qu'il en soit, même si je supprime IInitializeWithStream pour qu'il n'utilise jamais le flux (et que GetValue() renvoie des valeurs vides par défaut), il donne toujours la même erreur lors de la modification d'une propriété. Explorer n'appelle même pas SaveValue() ou Commit(). –

+0

Ai-je besoin de AddRef() le IStream que j'ai dans Initialize()? Et puis Release() après Commit()? J'avais supposé que non. Selon votre dernier numéro, je pensais que l'utilisation de .NET 4.0 en mode côte à côte résolvait les problèmes de version CLR avec les extensions shell. J'ai vérifié que le bon CLR exécute mon code. –

Questions connexes