2010-07-08 15 views
5

Ahora que .NET CLR 4.0 es compatible con el funcionamiento codo a codo (SxS), ahora debería ser posible escribir extensiones de shell en el código administrado. Intenté esto y codifiqué correctamente un Property Handler que implementa IPropertyStore, IInitializeWithStream y IPropertyStoreCapabilities.¿Cuál es la forma correcta de implementar una extensión de shell de manejador de propiedades administradas?

El controlador funciona bien y se ejecuta como se esperaba al explorar archivos a través del explorador. También funciona bien al mostrar las propiedades personalizadas en el panel de vista previa y el panel de "detalle" de propiedades del archivo.

Sin embargo, cuando intento editar una propiedad en el panel de vista previa y, a continuación, haga clic en "Guardar" me sale un error "Archivo en uso" diciendo que el archivo está abierto en el Explorador de Windows.

algunas curiosidades:

  1. Cuando las llamadas explorador IInitializeWithStream.Initialize la propiedad STGM se establece en STGM_SHARE_DENY_WRITE.
  2. Y en ningún momento el explorador llamó a IPropertyStore.SetValue o IPropertyStore.Commit.
  3. Veo llamadas repetidas a mi controlador en diferentes subprocesos para las mismas propiedades de archivo.

Entonces, ¿qué tengo que cambiar (o configurar en el registro) para obtener la propiedad de guardar para trabajar?

Actualización:

Gracias a Ben lo tengo trabajo. La "parte difícil" (al menos para mí) era entender que la interoperabilidad COM nunca llamaría Dispose o Finalize en mi PropertyHandler. Esto dejaba abiertos los archivos que procesé hasta que se ejecutó el GC.

Afortunadamente, el "protocolo del manejador de propiedades" funciona de manera que cuando se llama a IInitializeWithSream.Initialize() para ReadValue() el streamMode es ReadOnly, y cuando se llama para SetValue() el streamMode es ReadWrite y Commit () se llamará al final.

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; 
} 

Respuesta

3

Sí, usted tiene que AddRef() la corriente para mantenerla abierta y mantener la referencia viva correctamente.

Tenga en cuenta que el indexador utilizará su manejador de propiedades para abrir el archivo también. Entonces, si filtra el objeto de transmisión, el archivo permanecerá abierto. Puede usar el procexp sysinternals para indicar qué proceso tiene el archivo abierto, o procmon para indicar qué llamadas y parámetros utilizó.

1

Explorer intenta asegurarse de que no interfiere con otras aplicaciones que pueden tener el archivo abierto. ¿Podría el archivo estar legítimamente en uso por otra aplicación? ¿Hay un controlador de vista previa abierto?

A veces, vemos controladores de propiedades que mantienen sus transmisiones abiertas más de lo necesario (o manejadores basados ​​en archivos que abren el archivo con permisos restrictivos). ¿Puedes verificar si estás liberando la transmisión de manera oportuna?

Por último, no creo que esto esté relacionado con su problema inmediato, pero el uso de extensiones de shell .NET no es compatible. Recomendamos que esto no se incorpore a ningún producto.

-Ben

+0

No hay controlador de vista previa, pero el servicio de búsqueda de Windows parece cargar el controlador de vez en cuando. Pero no debería bloquear el archivo? Además, puedo hacer que la edición funcione cambiando a usar IInitializeWithFile, y mi SaveValue() y Commit() se llaman como se esperaba. De todos modos, incluso cuando termino IInitializeWithStream para que nunca use la secuencia (y tenga GetValue() devuelva valores vacíos predeterminados) todavía da el mismo error al editar una propiedad. Explorer nunca llama a SaveValue() ni a Commit(). –

+0

¿Debo agregar AddRef() el IStream que obtengo en Initialize()? Y luego Release() después de Commit()? Yo había supuesto que no. Según su último problema, pensé que el uso de .NET 4.0 en el modo de lado a lado resolvió los problemas de la versión de CLR con las extensiones de shell. Verifiqué que el CLR correcto está ejecutando mi código. –

Cuestiones relacionadas