【问题标题】:What is the correct way to implement a Managed Property Handler Shell Extension?实现托管属性处理程序外壳扩展的正确方法是什么?
【发布时间】:2010-07-08 02:05:57
【问题描述】:

现在 .NET CLR 4.0 支持并行 (SxS) 操作,现在应该可以编写 shell 托管代码中的扩展。我已经尝试过这个并成功编写了一个属性处理程序 实现了 IPropertyStore、IInitializeWithStream 和 IPropertyStoreCapabilities。

处理程序 工作正常,并在通过资源管理器浏览文件时按预期调用。它在显示 预览面板和文件属性“详细信息”面板中的自定义属性。

但是,当我尝试 在预览面板中编辑属性,然后单击“保存”我收到“正在使用的文件”错误说 该文件在 Windows 资源管理器中打开。

一些花絮:

  1. 当资源管理器调用 IInitializeWithStream.Initialize 时,STGM 属性设置为 STGM_SHARE_DENY_WRITE。
  2. 资源管理器从未调用 IPropertyStore.SetValue 或 IPropertyStore.Commit。
  3. 我看到在不同线程上针对相同文件属性重复调用我的处理程序。

那么我需要更改(或在注册表中设置)什么才能让属性保存工作?

更新:

多亏了 Ben,我已经成功了。 “困难的部分”(至少对我而言)是理解 COM 互操作永远不会在我的 PropertyHandler 上调用 Dispose 或 Finalize。这使我处理的文件保持打开状态,直到 GC 运行。

幸运的是,“属性处理程序协议”的工作原理是,当为 ReadValue() 调用 IInitializeWithSream.Initialize() 时,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;
}

【问题讨论】:

    标签: .net windows com-interop shell32


    【解决方案1】:

    是的,您必须对流进行 AddRef() 以使其保持打开状态并正确保持引用处于活动状态。

    请注意,索引器也将使用您的属性处理程序来打开文件。因此,如果您泄漏流对象,该文件将保持打开状态。您可以使用 sysinternals procexp 来判断哪个进程打开了文件,或者使用 procmon 来判断它使用了哪些调用和参数。

    【讨论】:

      【解决方案2】:

      Explorer 会尝试确保它不会干扰可能打开文件的其他应用程序。该文件是否可以被其他应用程序合法使用?是否打开了预览处理程序?

      有时,我们会看到属性处理程序使流的打开时间超过必要时间(或基于文件的处理程序以限制性权限打开文件)。您能否验证您是否及时发布了流?

      最后,我认为这与您的直接问题无关,但不支持使用 .NET shell 扩展。我们建议不要将其整合到任何产品中。

      -本

      【讨论】:

      • 没有预览处理程序,但 Windows Search 服务似乎偶尔会加载处理程序。但它不应该锁定文件?此外,我可以通过切换到使用 IInitializeWithFile 来进行编辑,并且我的 SaveValue() 和 Commit() 会按预期调用。无论如何,即使我将 IInitializeWithStream 存根以使其从不使用流(并且 GetValue() 返回默认的空值),它在编辑属性时仍然会给出相同的错误。 Explorer 甚至从不调用 SaveValue() 或 Commit()。
      • 我需要 AddRef() 我在 Initialize() 中获得的 IStream 吗?然后在 Commit() 之后 Release() 呢?我以为我没有。根据您的上一个问题,我认为在并排模式下使用 .NET 4.0 解决了带有 shell 扩展的 CLR 版本问题。我已经验证了正确的 CLR 正在运行我的代码。
      猜你喜欢
      • 1970-01-01
      • 2017-01-05
      • 1970-01-01
      • 2013-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多