Как правильно реализовать расширение оболочки обработчика управляемого свойства? - PullRequest
5 голосов
/ 08 июля 2010

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

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

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

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

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

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

Обновление:

Спасибо Бену, у меня все работает.«Трудной частью» (по крайней мере для меня) было понимание того, что 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;
}

Ответы [ 2 ]

3 голосов
/ 13 июля 2010

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

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

1 голос
/ 13 июля 2010

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

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

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

-Бен

...