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:
- Cuando las llamadas explorador IInitializeWithStream.Initialize la propiedad STGM se establece en STGM_SHARE_DENY_WRITE.
- Y en ningún momento el explorador llamó a IPropertyStore.SetValue o IPropertyStore.Commit.
- 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;
}
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(). –
¿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. –