资源管理器在使用我的缩略图提供程序后不会释放文件

本文关键字:程序 文件 释放 我的 略图 资源管理器 | 更新日期: 2024-09-08 10:23:48

我已经为文件类型设置了一个缩略图提供程序。

该项目是用

  • C#
  • .NET 4.5

我正在运行Windows x64

我的提供程序按预期成功生成缩略图,我可以移动、删除、复制等文件。锁定问题似乎是由文件放置在文件夹中引起的。此时,移动,删除等文件夹都显示错误"文件正在使用中"。

如果您熟悉它,我已经确认使用 Sysinternal 的进程资源管理器探索锁定该文件。

我已经尝试了 2 种方法来尝试解决此问题......

  1. 实施IThumbnailProviderIInitializeWithStream自己。
  2. 二手第三方尖壳

两者都遇到同样的问题,文件未发布。

在Sharpshell的github上,也开始指定这个问题。https://github.com/dwmkerr/sharpshell/issues/78

我像这样关联注册表中的文件类型

HKEY_CLASSES_ROOT
---- .qb
      ----shellex
          ----{e357fccd-a995-4576-b01f-234630154e96} : my CLSID...

我也试过了...

HKEY_CLASSES_ROOT
---- .qb
     -----PersistentHandler : my CLSID...

两者都会导致产生此问题。

如果我要实现IExtractImage...我会看到同样的问题吗?

我知道 C# 不是"官方"支持这样做的,这是我的问题所在吗?如果我在C++年实现这一点,我最终会遇到同样的问题吗?

编辑:

我想提一下,大约 1 分钟后的文件似乎被释放了,事情恢复正常。

缩略图创建

某些字节被读入缓冲区...然后从中生成图像。

public void GetThumbnail(int cx, out IntPtr hBitmap, out WTS_ALPHATYPE   bitmapType)
{
    ... bunch of other code
    using (MemoryStream steam = new MemoryStream(buffer))
    using (var image = new Bitmap(steam))
    using (var scaled = new Bitmap(image, cx, cx))
    {
        hBitmap = scaled.GetHbitmap();
        hBitmap = (IntPtr)(hBitmap.ToInt64());
    }
}

编辑2:

做了更多的测试,我调用了DeleteObject(hBitmap(,(即使这会破坏缩略图(,文件仍然被锁定。我什至从GetThumbnail中删除了所有代码......只是给出相同的结果,文件锁定。一定还有什么事情要做吧?

资源管理器在使用我的缩略图提供程序后不会释放文件

事实证明,您需要释放从IInitializeWithStream获得的COM IStream对象。

我通过阅读有关释放 COM 对象的更多信息得出了此结论。

释放 COM 对象的正确方法?

我遵循了MS关于如何包装IStream的示例

https://msdn.microsoft.com/en-us/library/jj200585%28v=vs.85%29.aspx

    public class StreamWrapper : Stream
    {
        private IStream m_stream;
       // initialize the wrapper with the COM IStream
        public StreamWrapper(IStream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException();
            }
           m_stream = stream;
        }
       // .... bunch of other code
       protected override void Dispose(bool disposing)
        {
            if (m_stream != null)
            {
                Marshal.ReleaseComObject(m_stream); // releases the file
                m_stream = null;
            }
        }
    }

下面是一个示例。

点击上面的链接查看StreamWrapper的实现...

[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
[ProgId("mythumbnailer.provider"), Guid("insert-your-guid-here")]
public class QBThumbnailProvider : IThumbnailProvider, IInitializeWithStream
{
    #region IInitializeWithStream
    private StreamWrapper stream{ get; set; }
    public void Initialize(IStream stream, int grfMode)
    {
        // IStream passed to our wrapper which handles our clean up
        this.stream = new StreamWrapper(stream);
    }
    #endregion
    #region IThumbnailProvider
    public void GetThumbnail(int cx, out IntPtr hBitmap, out WTS_ALPHATYPE bitmapType)
    {
        hBitmap = IntPtr.Zero;
        bitmapType = WTS_ALPHATYPE.WTSAT_ARGB;
        try
        {
            //... bunch of other code
            // set the hBitmap somehow
            using (MemoryStream stream = new MemoryStream(buffer))
            using (var image = new Bitmap(stream))
            using (var scaled = new Bitmap(image, cx, cx))
            {
                hBitmap = scaled.GetHbitmap();
            }
        }
        catch (Exception ex)
        {
        }
        // release the IStream COM object
        stream.Dispose();
    }
    #endregion
}

基本上它归结为两行代码

Marshal.ReleaseComObject(your_istream); // releases the file
your_istream = null;

旁注

使用 scaled.GetHbitmap(); 创建的 GDI 位图可能需要处理,但我找不到一种方法在不丢失创建的缩略图的情况下做到这一点。