Trouble fetching thumbnails for hydrated files in a Cloud File API folder

1 day ago 4
ARTICLE AD BOX

I am working on an application that operates like OneDrive and uses the Cloud File API to show cloud hosted files in a folder on the user’s machine. I am trying to enhance my application by fetching thumbnails from locally cached files to display in my UI. This way local edits to files can be shown to the user before they are uploaded back to the cloud.

Windows Explorer is able to show thumbnails for all the hydrated files inside my folder. The problem is that my code is not always able to fetch these same thumbnails.

Some details:
My application is written in C#, so I am using P/Invoke to talk to the Shell to get thumbnails. Here’s some sample code with the error handling removed for simplicity:

[ComImportAttribute()] [GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface IShellItemImageFactory { HResult GetImage( [In, MarshalAs(UnmanagedType.Struct)] SIZE size, [In] SIIGBF flags, [Out] out IntPtr phbm); } [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] [return: MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] public static extern IShellItemImageFactory SHCreateItemFromParsingName( [In][MarshalAs(UnmanagedType.LPWStr)] string pszPath, [In] IntPtr pbc, [In][MarshalAs(UnmanagedType.LPStruct)] Guid riid); [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteObject( [In] IntPtr hObject); [Flags] public enum SIIGBF { SIIGBF_RESIZETOFIT = 00, SIIGBF_BIGGERSIZEOK = 01, SIIGBF_MEMORYONLY = 02, SIIGBF_ICONONLY = 04, SIIGBF_THUMBNAILONLY = 08, SIIGBF_INCACHEONLY = 10 } public Bitmap GetThumbnail(string parsingName) { // obtain the IShellItemImageFactory interface IShellItemImageFactory isiif = null; Guid iid = typeof(IShellItemImageFactory).GUID; isiif = SHCreateItemFromParsingName(parsingName, IntPtr.Zero, iid); if (isiif == null) return null; // extract memory bitmap SIIGBF flags = SIIGBF.SIIGBF_BIGGERSIZEOK | SIIGBF.SIIGBF_THUMBNAILONLY; IntPtr hBitmap = IntPtr.Zero; HResult result = isiif.GetImage(new SIZE(256, 256), flags, out hBitmap); Marshal.FinalReleaseComObject(isiif); if (hBitmap == IntPtr.Zero) return null; Bitmap bmp = Image.FromHbitmap(hBitmap); DeleteObject(hBitmap); return bmp; }

This code will give me back a bitmap of the thumbnail. This code works 100% of the time outside my CFAPI sync root in ordinary folders.

Inside the CFAPI sync root it does not always work. I haven’t been able to find a pattern yet for when it works and when it does not. I get the same inconsistent behavior when trying different file types (extensions), so it does not seem constrained to specific types. When it does not work, I get back an HRESULT from the GetImage call of 0x8004B207 which apparently translates to WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER. I would not expect to get this error (or any error) because the files are already showing thumbnails inside Explorer.

Another thing I have tried is bypassing the Shell and generating thumbnails directly myself. That looks roughly like:

Take the extension of the file, look it up in HKEY_CLASSES_ROOT, find the IThumbnailProvider CLSID

Find the implementation of the IThumbnailProvider by CLSID

Create an instance of the IThumbnailProvider, passing in either a stream or file based on what it supports

Call GetThumbnail on the resulting instance of IThumbnailProvider

It feels a little sketchy to generate thumbnails like this myself. The shell also does not appear to cache the results of this call. If I generate a thumbnail like this and then try my other code above, I do not get the freshly generated thumbnail back from the Shell. I would like to have the Shell cache the thumbnails so that they only get generated once by whichever process tries to view the file first.

So in summary I have the following questions:

How do I get the thumbnail that Explorer is already showing me in the GUI programmatically so I can show it in my own UI?

Is it safe to generate my own thumbnails directly with a file type’s IThumbnailProvider?

How can I get the Shell to cache my generated thumbnails so the generation only happens once?

Read Entire Article