Explorer 在使用我的缩略图提供程序后不会释放文件
Explorer Wont Release Files After Using My Thumbnail Provider
我已经为一种文件类型设置了缩略图提供程序。
该项目是用
制作的
- C#
- .NET 4.5
而我是 运行 Windows x64
我的提供商按预期成功生成了缩略图,我可以移动、删除、复制等文件。锁定问题似乎是由文件放在文件夹中引起的。此时,移动、删除等文件夹都报错,"File In Use".
我已经确认使用 Sysinternal 的 Process Explorer 探索锁定文件,如果您熟悉的话。
我已经尝试了 2 种方法来尝试解决这个问题...
- 我自己实现了
IThumbnailProvider
和 IInitializeWithStream
。
- 使用第 3 方 Sharpshell
两者都遇到同样的问题,文件未发布。
在 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
...我会遇到同样的问题吗?
我知道 "officially" 不支持 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 对象的内容得出了这个结论。
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;
}
}
}
这是一个示例。
按照上面的 link 查看 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 位图可能需要处理掉,但我找不到不丢失创建的缩略图的方法。
我已经为一种文件类型设置了缩略图提供程序。
该项目是用
制作的- C#
- .NET 4.5
而我是 运行 Windows x64
我的提供商按预期成功生成了缩略图,我可以移动、删除、复制等文件。锁定问题似乎是由文件放在文件夹中引起的。此时,移动、删除等文件夹都报错,"File In Use".
我已经确认使用 Sysinternal 的 Process Explorer 探索锁定文件,如果您熟悉的话。
我已经尝试了 2 种方法来尝试解决这个问题...
- 我自己实现了
IThumbnailProvider
和IInitializeWithStream
。 - 使用第 3 方 Sharpshell
两者都遇到同样的问题,文件未发布。
在 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
...我会遇到同样的问题吗?
我知道 "officially" 不支持 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 对象的内容得出了这个结论。
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; } } }
这是一个示例。
按照上面的 link 查看 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 位图可能需要处理掉,但我找不到不丢失创建的缩略图的方法。