I am trying to write handler for Windows COM IThumbnailProvider interface, to generate thumb images for custom file type (.URLtest to test things). Using C# .Net.
No matter what I try, my ThumbnailProvider class / handler dll is never called (based on my simple text file logging). And my .URLtest files are displayed in Explorer like they do not have thumbnail provider assigned.
I am testing this under Windows 7 64
I compiled the Thumbnail provider lib as both x86 and x64
Registered each version with right RegAsm
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" ThumbUrlThumbnailProvider.dll /codebase
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" ThumbUrlThumbnailProvider.dll /codebase
That created all these registry data
[HKEY_CLASSES_ROOT]
[ThumbUrlHandler.ThumbnailProvider]
@="ThumbUrlHandler.ThumbnailProvider"
[CLSID]
@="{E7CBDB01-06C9-4C8F-A061-2EDCE8598F99}"
[CLSID]
[{E7CBDB01-06C9-4C8F-A061-2EDCE8598F99}]
@="ThumbUrlHandler.ThumbnailProvider"
DisableProcessIsolation=1 <<< added by me as one attempt to make things work
[Implemented Categories]
[{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
[InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="ThumbUrlHandler.ThumbnailProvider"
"Assembly"="ThumbUrlThumbnailProvider, Version=0.1.0.0, Culture=neutral, PublicKeyToken=bb72a5681544afed"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///W:/bin/x64/Debug/ThumbUrlThumbnailProvider.dll"
[0.1.0.0]
"Class"="ThumbUrlHandler.ThumbnailProvider"
"Assembly"="ThumbUrlThumbnailProvider, Version=0.1.0.0, Culture=neutral, PublicKeyToken=bb72a5681544afed"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///W:/bin/x64/Debug/ThumbUrlThumbnailProvider.dll"
[ProgId]
@="ThumbUrlHandler.ThumbnailProvider"
[Record]
[{40FD8D55-6F91-3A5C-A049-6664E649643C}] <<< no idea why this is registered
[0.1.0.0]
"Class"="ThumbUrlHandler.WTS_ALPHATYPE"
"Assembly"="ThumbUrlThumbnailProvider, Version=0.1.0.0, Culture=neutral, PublicKeyToken=bb72a5681544afed"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///W:/bin/x64/Debug/ThumbUrlThumbnailProvider.dll"
I created file type registry entry
[HKEY_CLASSES_ROOT]
[.URLtest]
"PerceivedType"="Image"
"Content Type"="image/jpeg"
[ShellEx]
[{e357fccd-a995-4576-b01f-234630154e96}] <<<< IThumbnailProvider COM interface CLSID
@="{E7CBDB01-06C9-4C8F-A061-2EDCE8598F99}" <<<< my ThumbnailProvider class CLSID
My simple test thumb provider code
// COM interfaces
public enum WTS_ALPHATYPE
{ .. }
[ComVisible(true)]
[Guid("e357fccd-a995-4576-b01f-234630154e96")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThumbnailProvider
{
void GetThumbnail(int cx, out IntPtr hBitmap, out WTS_ALPHATYPE bitmapType);
}
[ComVisible(true)]
[Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInitializeWithStream
{
void Initialize(IStream stream, int grfMode);
}
// my thumbnail provider class
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
[ProgId("ThumbUrlHandler.ThumbnailProvider")]
[Guid("E7CBDB01-06C9-4C8F-A061-2EDCE8598F99")]
public class ThumbnailProvider : IThumbnailProvider, IInitializeWithStream
{
public void Initialize(IStream stream, int grfMode)
{
// instantly dispose the COM stream, as I don't need it for the test
Marshal.ReleaseComObject(stream);
}
public void GetThumbnail(int cx, out IntPtr hBitmap, out WTS_ALPHATYPE bitmapType)
{
bitmapType = WTS_ALPHATYPE.WTSAT_RGB;
var outBitmap = new Bitmap(cx, cx, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
hBitmap = outBitmap.GetHbitmap();
}
}
I tried restarting Explorer process.
I tried creating new .URLtest files to get around thumbnails caching.
My handler is still ignored.
After several Explorer restart I noticed that now my x64 ThumbUrlThumbnailProvider.dll is locked by Explorer. But still no thumbnails show for the files and ThumbnailProvider methods are not called.
Does anybody know if this interface and approach is still supported in Windows ?
Does anybody see any error in my code or registry data ?
I am out of ideas.
I managed to make my shell extension to work. This is not really an answer, but at least a collection of things I have learnet, that may help others.
There were 2 main problems:
System.Diagnostics.TextWriterTraceListener
)!So there isn't really an easy way to detect if your code was even run by shell, and verify if your registry registrations part is right.
I tried to attach Explorer process to VisualStudio, but my breakpoint was never hit, even though my extension code was run.
What you can do is opt out of "Process isolation" in your assembly registration. See my question for DisableProcessIsolation=1
param and context. Than your assembly will be loaded by Explorer process directly and you can see that in sysinternals Process Explorer utility. If your registrations are right.
This may require Explorer process restart to work.
If you do not opt out, your assembly will be loaded for only a brief time and than uloaded again, so you will not be able to spot it, or as I read elsewhere, it may be loaded by other process than Explorer.exe entirely.
Few other things I learned:
Marshal.ReleaseComObject()
in Initialize()
method and not keeping any reference to the original IStream pointer.Marshal.ReleaseComObject()
is not a good idea, but that was the only solution I was able to find.GetThumbnail()
method call. Shell may keep your thumbnail provider instance and call GetThumbnail()
more times, for different thumbnail sizes atc.