Explorer不会在使用我的缩略图提供程序后释放文件

时间:2015-02-28 02:20:11

标签: c# .net thumbnails

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

该项目是用

制作的
  • C#
  • .NET 4.5

我正在运行Windows x64

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

我已经确认使用Sysinternal的Process Explorer锁定文件,如果您熟悉它。

我尝试了两种尝试解决此问题的方法......

  1. 自己实施了IThumbnailProviderIInitializeWithStream
  2. 使用了第三方Sharpshell
  3. 两者都遭遇同样的问题,文件没有被释放。

    在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中删除了所有代码...只是给出相同的结果,文件已锁定。还有什么事情要继续吗?

1 个答案:

答案 0 :(得分:1)

原来你需要释放从IInitializeWithStream获得的COM IStream对象。

通过阅读有关处理COM对象的更多信息,我得出了这个结论。

Proper way of releasing COM objects?

我按照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位图可能需要处理,但我无法在不丢失创建的缩略图的情况下找到方法。