Search code examples
c++winapicomthumbnails

Can I Initialize a IThumbnailProvider Object with a File?


I am writing a thumbnail provider that implements IInitializeWithFile, however the file path that gets passed to the initialize method is invalid.

  • I created the "DisableProcessIsolation" value in the Registry in HKCR\CLSID\{CLSID of my thumbnail provider} to opt out from process isolation to be able to use IInitializeWithFile/IInitializeWithItem instead of IInitializeWithStream.
  • I tested my code with IInitializeWithStream, which worked just fine. Retrieving an IStream object from the file path with SHCreateStreamOnFile() fails.
  • The file path that gets passed is invalid (PathFileExistsW(FilePath) returns false).
  • The thumbnail provider is registered properly (the Registry keys are all set properly, and it works just fine when using IInitializeWithStream instead).

The reason why I cant use IInitializeWithStream is that I need the path of the file to return the correct thumbnail.

IFACEMETHODIMP RecipeThumbnailProvider::Initialize(LPCWSTR FilePath, DWORD Mode){
    std::wofstream *FileStream1 = new std::wofstream("D:\\test1.txt");

    if(!PathFileExistsW(FilePath)){//check if the passed path is valid
        (*FileStream1)<< L"path invalid";
    }else{
        (*FileStream1)<<L"path valid" << FilePath;
    }
    (*FileStream1).close();

    // A handler instance should be initialized only once in its lifetime. 
    HRESULT hr = ERROR_ALREADY_INITIALIZED;
    if (m_pStream == NULL)
    {
        hr = SHCreateStreamOnFileW(FilePath, Mode, &m_pStream);//get IStream from file path
    }
    return hr;
}

Solution

  • It seems that you can only use IInitializeWithStream as of Windows Vista.

    I have done some extensive testing here (see this pull request and this pull request. Testing indicates the Initialize method is not called unless the server implements IInitializeWithStream.

    The latest MSDN documentation at:

    https://learn.microsoft.com/en-us/windows/win32/api/thumbcache/nn-thumbcache-ithumbnailprovider

    Also seems to imply this:

    The Shell calls IInitializeWithStream::Initialize with the stream of the item, and IInitializeWithStream is the only initialization interface used when IThumbnailProvider instances are loaded out-of-proc (for isolation purposes). This is the primary code path for Windows for all IThumbnailCache code paths.

    It is possible for a thumbnail implementation to be initialized with IInitializeWithItem or IInitializeWithFile when the handler is request by a 3rd party without using the IThumbnailCache API, but this is uncommon. If you implement IInitializeWithItem, the Shell calls IInitializeWithItem::Initialize with the IShellItem representation of the item. If you implement IInitializeWithFile, the Shell calls IInitializeWithFile::Initialize with the path of the file.

    I believe that due to the security issue mentioned here Microsoft have probably ensured that the shell will only use IInitializeWithStream.

    I am still investigating into whether there is some roundabout way to get the path from an IStream - so far I can only get the display name. However if the object which is the IStream also implements some other interface, it might be possible to query it for the path, I'll update this answer if I discover a way.