2010-07-08 3 views
5

Теперь, когда .NET CLR 4.0 поддерживает бок о бок (SxS), теперь теперь можно будет написать оболочки в управляемом коде. Я попытался это и успешно закодировал Обработчик свойств , который реализует IPropertyStore, IInitializeWithStream и IPropertyStoreCapabilities.Каков правильный способ реализации расширения оболочки обработчика управляемого объекта?

Обработчик работает нормально и называется ожидаемым при просмотре файлов через проводник. Он также отлично работает при отображении пользовательских свойств в панели предварительного просмотра и панели свойств «подробно».

Однако, когда я пытаюсь сделать , отредактируйте свойство в панели предварительного просмотра, а затем нажмите «Сохранить». Я получаю сообщение «Использовать файл», говоря, что файл открыт в Проводнике Windows.

Несколько лакомых кусочков:

  1. Когда проводник вызывает IInitializeWithStream.Initialize свойство STGM устанавливается в STGM_SHARE_DENY_WRITE.
  2. И ни в коем случае не вызывал проводник IPropertyStore.SetValue или IPropertyStore.Commit.
  3. Я вижу повторные вызовы для моего обработчика в разных потоках для тех же свойств файла.

Итак, что мне нужно изменить (или установить в реестре), чтобы сохранить свойство на работу?

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

ответ

3

Да, вы должны AddRef() поток, чтобы держать его открытым и сохранить ссылку жив правильно.

Обратите внимание, что индексщик также будет использовать ваш обработчик свойств, чтобы открыть файл. Поэтому, если вы протечкаете объект потока, файл останется открытым. Вы можете использовать sysinternals procexp, чтобы указать, какой процесс имеет файл, или procmon, чтобы указать, какие вызовы и параметры он использовал.

1

Проводник пытается убедиться, что он не мешает другим приложениям, которые могут открыть файл. Может ли файл быть законным в использовании другим приложением? Открыт ли обработчик предварительного просмотра?

Иногда мы видим обработчики свойств, которые открывают свои потоки дольше, чем необходимо (или обработчики на основе файлов, которые открывают файл с ограничительными разрешениями). Можете ли вы проверить, своевременно ли вы отправляете поток?

И, наконец, я не думаю, что это связано с вашей непосредственной проблемой, но использование расширений оболочки .NET не поддерживается. Мы рекомендуем, чтобы это не было включено в какой-либо продукт.

-Бен

+0

Нет обработчика предварительного просмотра, но служба поиска Windows, похоже, иногда загружает обработчик. Но он не должен блокировать файл? Кроме того, я могу сделать работу по редактированию, переключившись на использование IInitializeWithFile, и мои SaveValue() и Commit() вызывают как ожидалось. В любом случае, даже если я отключу IInitializeWithStream, чтобы он никогда не использовал поток (и GetValue() возвращает значения пустых значений по умолчанию), он по-прежнему дает ту же ошибку при редактировании свойства. Explorer никогда даже не вызывает SaveValue() или Commit(). –

+0

Должен ли я добавить в AddRef() IStream, который я получаю в Initialize()? А потом Release() после Commit()? Я предположил, что нет. В соответствии с вашей последней проблемой я думал, что использование .NET 4.0 в режиме «бок о бок» решило проблемы с версией CLR с расширением оболочки. Я проверил, что в правильном CLR работает мой код. –

Смежные вопросы