ShellBoost

Files On-Demand

The ShellBoost Files On-Demand feature can be used without creating a Shell Namespace Extension. However, the two techniques can be combined to have a Shell Namespace Extension that displays on-demand files and folders. The Files On-Demand feature is demonstrated in the Google Drive Folder sample and the Cloud Folder Sync sample.

ShellBoost supports the Windows 10 Files On-Demand feature (starting with version 1709, or “Fall Creators Update”) through the OnDemandLocalFileSystem class which can be used in the context of the File System Synchronization (see previous chapter File Systems Synchronization for more on that).

This is how you would start synchronization between a local folder, and a custom file system, for example a file system that serves files from the cloud:

var onDemandRootPath = @"c:\myPath";
 
// Register the File On-Demand root, use an end-user friendly display name.
// Note his must not be ran all the time, just once, for example at install time
var reg = new OnDemandLocalFileSystemRegistration();
reg.ProviderName = "My Cloud File Provider";
OnDemandLocalFileSystem.EnsureRegistered(onDemandRootPath, reg);
 
// create the MPS. We need a globally unique identifier (could be a guid)
using (var mps = new MultiPointSynchronizer("MyCompany.MyProgram"))
{
    // add one endpoint with the ShellBoost-provided on-demand local file system
    mps.AddEndPoint("local", new OnDemandLocalFileSystem(onDemandRootPath));
 
    // add one endpoint with a custom file system (cloud, etc.)
    mps.AddEndPoint("local", new CustomFileSystem());
 
    Console.WriteLine("Press ESC to quit, C to clear...");
 
    // start the MPS
    mps.Start();
 
    do
    {
        var k = Console.ReadKey(true);
        if (k.Key == ConsoleKey.Escape)
            break;
    }
    while (true);
}

Registration

To be able to use the OnDemandLocalFileSystem class, you must register the directory it serves as being a “sync root”. This requires talking to the Windows File System and to the Windows Shell, but this needs to be done only once per machine and user, so probably at install time. To do that, you can simply use OnDemandLocalFileSystem class’ static methods:

// OnDemandRegistration is a configuration class. myDirectoryPath is the sync root path.
OnDemandLocalFileSystem.EnsureRegistered(myDirectoryPath, new OnDemandRegistration());

You can also unregister a sync root like this, but you should only do that when uninstalling your program for a given user and machine.

OnDemandLocalFileSystem.Unregister(myDirectoryPath, new OnDemandRegistration());

Shell Reporting

Starting with ShellBoost version 1.8.0.0, the OnDemandLocalFileSystem class reports information to the Shell automatically during file downloads. The shell will therefore be able to show progress Dialog Boxes and/or progress indicator in the Status column. When and how the Shell ultimately uses the information is independent from ShellBoost.

Note for this Shell reporting feature to work, the Windows Search service must be running.

Thumbnails On-Demand

Starting with ShellBoost version 1.7.0.3, the OnDemandLocalFileSystem class supports On-Demand thumbnails. The Windows Shell (and all UI application that support Shell Thumbnails) can display thumbnails for a placeholder without the need for this placeholder to be hydrated. It means the actual size of the placeholder may be 0 bytes (or more) but a full thumbnail can be displayed.

Technically, the Shell requires a thumbnail provider component (a COM object) to provide these thumbnails. ShellBoost provides a simple to use .NET wrapper class that only requires you as a developer to register the object and provide the implementation that will build a bitmap (from System.Drawing or using a Windows HBITMAP handle) from a Shell Item. Here is a sample implementation for such an object loading a thumbnail from a hypothetical cloud server:

    [Guid("7503e3a5-21e3-43de-830b-6b87e4b98552")] // TODO: don't use this guid! create a new one!
    [ComVisible(true), ClassInterface(ClassInterfaceType.None)]
    public class CloudThumbnailProvider : ThumbnailProvider // derive from a ShellBoost-provided class
    {
       ... registration methods, using ShellBoost-provided COM registration methods
        public static void Register() => new CloudFolderThumbnailProvider(null, null).RegisterOutOfProcess(RegistrationMode.User, Process.GetCurrentProcess().MainModule.FileName);
        public static void Unregister() => new CloudFolderThumbnailProvider(null, null).Unregister(RegistrationMode.User);
 
       ... required implementation
        protected override Bitmap GetThumbnailBitmap(int width)
        {
             ...
            if (Item == null) // in this context, we should have a ShellBoost-provided Item (a native IShellItem)
                return null;
 
            // get relative path from passed item’s full path
            var relativePath = GetRelativePath(Item.SIGDN_FILESYSPATH);
 
            // get cloud id using some cloud method that does local => remote id matching
            var cloudId  = GetCloudIdFromRelativePath(...)
 
            using (var ms = new MemoryStream())
            {
                // ask the cloud API to download the thumbnail for the required with
                CloudApi.DownloadThumbnail(cloudId, ms, width);
                ms.Position = 0; // rewind stream
                
                // build a Winforms/GDI bitmap
                return (Bitmap)Image.FromStream(ms);
            }
        }
    }

This is demonstrated by the Cloud Folder Sync sample. It also requires the corresponding version of the Cloud Folder Site sample that has thumbnail support.

Note: Since a thumbnail provider implemented as demonstrated in the Cloud Folder Site sample is an out-of-process COM object, the process holding that object must run at the same UAC level as the Explorer (or other client application) for the thumbnails to be displayed in its view. It means if you run Explorer as normal (unelevated), you must run the ThumbnailProvider COM object as unelevated. If you run the ThumbnailProvider COM object as out-of-process admin, a standard Explorer (unelevated) cannot communicate with it.
So, if you start the Cloud Folder Sync sample as admin (or run or debug it from a Visual Studio started as admin), and use Explorer normally (unelevated), this won’t work and cause Explorer to display the green “waiting” progress bar.

Combining with a namespace extension

You can use the file on-demand feature from a Shell Namespace Extension written with ShellBoost. However, only the physical shell items (or folders) will be able to support on-demand feature as it relies technically on Windows NTFS storage. You can still combine virtual shell item with physical on-demand shell items, though. The MultiPointSynchronizer instance can be hosted in the same .exe as the Shell Namespace Extension server.

Here are the same files, but displayed in the context of a namespace extension:

Combining with a namespace extension - Picture 4

The “Status” column has been added by code to the folder, like this:

public OnDemandRootFolder(OnDemandShellFolderServer server, ShellItemIdList idList, DirectoryInfo info)
    : base(idList, info)
{
    // since this is a FileSystem oriented NSE, we let base (properties provided by the Shell) properties pass through
    ReadPropertiesFromShell = true;
 
    /// We just add the sync status column.
    AddColumn(Props.System.StorageProviderUIStatus, SHCOLSTATE.SHCOLSTATE_ONBYDEFAULT);
}
 

System.StorageProviderUIStatus is a Windows property that represents the status folder. It’s a property of type Icon. Refer to the “Item icon properties” sub-chapter of Item properties / folder columns for more on this. The only difference is, here, the two properties (System.StorageProviderUIStatus , StorageProviderState) are already defined by Windows, so for each item, we just have to set their value according to the item sync status.

The ReadPropertiesFromShell property set to true instructs the ShellItem instance to fall back to the physical file’s Shell built-in properties for properties not handled by the ShellItem instance itself. It guarantees maximum shell integration (menus, etc.).

Note: System.StorageProviderUIStatus is in fact a very special property for the Shell as it’s also capable of displaying custom states aside the main cloud state icon, using a Shell feature known as “Custom State Providers”. ShellBoost currently provi