I am writing a thumbnail provider that implements IInitializeWithFile
, however the file path that gets passed to the initialize method is invalid.
"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
.IInitializeWithStream
, which worked just fine.
Retrieving an IStream
object from the file path with SHCreateStreamOnFile()
fails.PathFileExistsW(FilePath)
returns false).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;
}
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.