实现托管属性处理程序Shell扩展的正确方法是什么?

时间:2010-07-08 02:05:58

标签: .net windows com-interop shell32

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

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

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

一些花絮:

  1. 当资源管理器调用IInitializeWithStream.Initialize时,STGM属性设置为STGM_SHARE_DENY_WRITE。
  2. 探险家决不会调用IPropertyStore.SetValue或IPropertyStore.Commit。
  3. 我看到在不同线程上对我的处理程序重复调用相同的文件属性。
  4. 那么我需要更改(或在注册中设置)以使属性保存才能工作?

    更新

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

2 个答案:

答案 0 :(得分:3)

是的,您必须使用AddRef()流来保持它的打开并保持引用正常运行。

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

答案 1 :(得分:1)

资源管理器尝试确保它不会干扰可能打开文件的其他应用程序。该文件是否可以被另一个应用程序合法使用?是否有预览处理程序打开?

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

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

-Ben