Теперь, когда .NET CLR 4.0 поддерживает бок о бок (SxS), теперь теперь можно будет написать оболочки в управляемом коде. Я попытался это и успешно закодировал Обработчик свойств , который реализует IPropertyStore, IInitializeWithStream и IPropertyStoreCapabilities.Каков правильный способ реализации расширения оболочки обработчика управляемого объекта?
Обработчик работает нормально и называется ожидаемым при просмотре файлов через проводник. Он также отлично работает при отображении пользовательских свойств в панели предварительного просмотра и панели свойств «подробно».
Однако, когда я пытаюсь сделать , отредактируйте свойство в панели предварительного просмотра, а затем нажмите «Сохранить». Я получаю сообщение «Использовать файл», говоря, что файл открыт в Проводнике Windows.
Несколько лакомых кусочков:
- Когда проводник вызывает IInitializeWithStream.Initialize свойство STGM устанавливается в STGM_SHARE_DENY_WRITE.
- И ни в коем случае не вызывал проводник IPropertyStore.SetValue или IPropertyStore.Commit.
- Я вижу повторные вызовы для моего обработчика в разных потоках для тех же свойств файла.
Итак, что мне нужно изменить (или установить в реестре), чтобы сохранить свойство на работу?
Update:
Благодаря Бену я получил это работает. «Трудная часть» (по крайней мере для меня) заключалась в понимании того, что COM-взаимодействие никогда не будет вызывать Dispose или Finalize на моем PropertyHandler. Это оставило файлы, которые я обработал, пока GC не побежал.
К счастью, «протокол обработчика свойств» работает так, что когда IInitializeWithSream.Initialize() вызывается для ReadValue(), streamMode является ReadOnly, и когда он вызывается для SetValue(), streamMode является ReadWrite и Commit () будет вызываться в конце.
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;
}
Нет обработчика предварительного просмотра, но служба поиска Windows, похоже, иногда загружает обработчик. Но он не должен блокировать файл? Кроме того, я могу сделать работу по редактированию, переключившись на использование IInitializeWithFile, и мои SaveValue() и Commit() вызывают как ожидалось. В любом случае, даже если я отключу IInitializeWithStream, чтобы он никогда не использовал поток (и GetValue() возвращает значения пустых значений по умолчанию), он по-прежнему дает ту же ошибку при редактировании свойства. Explorer никогда даже не вызывает SaveValue() или Commit(). –
Должен ли я добавить в AddRef() IStream, который я получаю в Initialize()? А потом Release() после Commit()? Я предположил, что нет. В соответствии с вашей последней проблемой я думал, что использование .NET 4.0 в режиме «бок о бок» решило проблемы с версией CLR с расширением оболочки. Я проверил, что в правильном CLR работает мой код. –