First, Introduction
Windows Thumbnail handler is a set of COM interfaces that are used under the Windows platform to provide a content preview of the associated file types. By implementing thumbnail-related COM interfaces, you can provide a preview of the content for a custom file format. As shown in the following:
Thumbnail handler is registered in the form of COM components. So, if we want to develop a thumbnail handler for our own file format to provide a preview of the content, we want to develop it in the way that COM components are developed. I did not have the relevant COM development experience before, and I know very little about the concepts, threading models and principles associated with COM components. Fortunately, Microsoft has provided us with a model project (Cppshellextthumbnailhandler). On the basis of this project, we can make changes to complete our own functions.
Second, the realization
Before we start modifying the code, we might as well compile and run the project. This project generates a preview of the image in the. recipe format by reading the contents of the picture in the file. This is the second, the key point is: The project Recipethumbnailprovider inherit from the iinitializewithstream. This class has a pure virtual function initialize, whose function prototype is:
Iinitializewithstream:public iunknown{public: Virtual/* [local] */HRESULT stdmethodcalltype Initialize (/ * [ Annotation][in] */ _in_ IStream *pstream,/ * [annotation][in] */ _in_ DWORD grfmode) = 0; };
The only parameter that is useful to us is the Pstream or istream* type. Through this interface we can only get the byte stream to the associated file. This is not a problem for small files, and it is no harm to read the byte stream directly into memory, but if the custom file reaches hundreds of MB or several gigabytes, it is certainly unrealistic. At this point we prefer to get the absolute path to the file. The first idea is to see if there is an interface to pass the file path? Another interface is listed in MSDN: Iinitializewithfile. This interface also has a pure virtual function, whose prototype is:
Iinitializewithfile:public iunknown{public: virtual HRESULT stdmethodcalltype Initialize (/ * [String][in] * /__rpc__in_string LPCWSTR Pszfilepath,/ * [in] */DWORD Grfmode) = 0; };
Overjoyed,Pszfilepath is not exactly what we dreamed of! Well, basically, as long as the parts related to the IInitializeWithStream all replaced not OK. The modifications are addressed in the following areas:
Class Recipethumbnailprovider: Public iinitializewithfile, public ithumbnailprovider{public: // IUnknown ifacemethodimp QueryInterface (REFIID riid, void **PPV); Ifacemethodimp_ (ULONG) AddRef (); Ifacemethodimp_ (ULONG) Release (); Iinitializewithfile ifacemethodimp Initialize (lpcwstr Pfilepath, DWORD grfmode); IThumbnailProvider ifacemethodimp GetThumbnail (UINT cx, Hbitmap *phbmp, Wts_alphatype *pdwalpha); ... ...}
Query to the interface the component supported. Ifacemethodimp Recipethumbnailprovider::queryinterface (REFIID riid, void **PPV) {static const qitab qit[] ={qitabent ( Recipethumbnailprovider, IThumbnailProvider), Qitabent (Recipethumbnailprovider, iinitializewithfile), {0},};return Qisearch (This, Qit, riid, PPV);}
Initializes the thumbnail handler with a stream. Ifacemethodimp recipethumbnailprovider::initialize (lpcwstr Pfilepath, DWORD grfmode) {loginfo (PfilePath); return 1;}
None of the other files need to be moved, and are registered for use after compilation. I thought I could see the output of the file path in the log file, and I didn't have any reaction. Obviously, the Initialize () method after our modification has not been called. A search on the internet, many people also have similar needs, but also have the same experience, but did not find effective solutions. How to solve it? As explained by MSDN, you need to register dissableprocessisolation=1 in the registry. According to StackOverflow, the previous explanation is that the old Windows is loading the shell extension into Explorer.exe, but this is not very secure. So the new Windows system will separate this part of the functionality, using Dllhost.exe to load the shell Extension, out of the association with Explorer.exe. This reduces the probability of Explorer.exe collapse to a certain extent. The IInitializeWithStream is also more respected on MSDN than Iinitializewithfile, to ensure the security of the system.
In this case, you will have to modify the code in the program to manipulate the Registry section:
HRESULT Sethkcrregistrykeyandvalue (PCWSTR Pszsubkey, Pcwstr pszvaluename, Pcwstr pszdata, UINT type) {HRESULT hr; HKEY HKEY = null;//creates the specified registry key. If The key already exists, the//function opens it. hr = HRESULT_FROM_WIN32 (RegCreateKeyEx (HKEY_CLASSES_ROOT, Pszsubkey, 0,null, Reg_option_non_volatile, KEY_WRITE, NULL , &hkey, NULL)), if (SUCCEEDED (HR)) { if (pszdata! = NULL) {//Set the specified value of the key. DWORD cbdata = lstrlen (pszdata) * sizeof (*PSZDATA); if (type = = REG_DWORD) { cbdata = 4;} hr = HRESULT_FROM_WIN32 (RegSetValueEx (HKey, pszvaluename, 0, type, reinterpret_ Cast<const BYTE *> (pszdata), cbdata)); } RegCloseKey (HKey);} return HR;}
HRESULT Registerinprocserver (pcwstr pszmodule, const clsid& CLSID, Pcwstr pszfriendlyname, Pcwstr Pszthreadmodel) { if (Pszmodule = = NULL | | pszthreadmodel = = NULL) {return E_INVALIDARG; } HRESULT HR; wchar_t Szclsid[max_path]; StringFromGUID2 (CLSID, Szclsid, ARRAYSIZE (SZCLSID)); wchar_t Szsubkey[max_path]; Create the Hkcr\clsid\{<clsid>} key. hr = stringcchprintf (Szsubkey, ARRAYSIZE (Szsubkey), L "clsid\\%s", Szclsid); if (SUCCEEDED (HR)) {hr = Sethkcrregistrykeyandvalue (Szsubkey, NULL, Pszfriendlyname, REG_SZ); Create the Hkcr\clsid\{<clsid>}\inprocserver32 key. if (SUCCEEDED (HR)) {WCHAR Data[4] = {0x01, 0x00, 0x00, 0x00}; Sethkcrregistrykeyandvalue (Szsubkey, L "disableprocessisolation", data, REG_DWORD); hr = stringcchprintf (Szsubkey, ARRAYSIZE (Szsubkey), L "Clsid\\%s\\inprocserver32", Szclsid); if (SUCCEEDED (HR)) {//Set the default value Of the InprocServer32 key to the//path of the COM module. hr = Sethkcrregistrykeyandvalue (Szsubkey, NULL, Pszmodule, REG_SZ); if (SUCCEEDED (HR)) {//Set the threading model of the component. hr = Sethkcrregistrykeyandvalue (Szsubkey, L "ThreadingModel", Pszthreadmodel, REG_SZ); }}}} return hr;}
Register to see the results:
There is nothing wrong with the registration form. And our file path also appears in the log file successfully:
And we can also see the customization file to get a preview of the content:
Third, summary
The most painful part of the whole groping process is the blindness of the debugging method. Because there is no specific tutorials on the web, it is not known that this change is due to the principle of not working or because of operational errors, which led to the shell extension does not work. In addition, the Shell extension debugging is also very difficult, only through the output of the log file to determine the approximate range of errors. The compiled COM service can only be registered with RegSvr32.exe:
$ RegSvr32 CppShellExtThumbnailHandler.dll
Although the RegSvr32.exe with a 32, but in fact 32-bit and 64-bit is called this name. On 64-bit systems, 32-bit RegSvr32.exe will register the service under Hkey_classes_root\wow6432node\clsid and 64-bit will register to hkey_classes_root\ go under the CLSID. RegSvr32.exe will invoke the corresponding version of RegSvr32.exe based on the number of bits of the compiled DLL
In addition, if the current DLL also relies on other DLLs when using RegSvr32.exe to register the service, there will be a case of registration failure:
All you have to do is put all your dependent DLLs together, or put them under the System32 directory. This will allow for normal registration.
A detailed sample project has been uploaded to my github: Https://github.com/csuft/WindowsThumbnail.
Iv. Reference Links
- Http://slion.net/view/Dev/MakingOfMs3dThumbnailProvider#Code_Samples
- https://social.msdn.microsoft.com/Forums/en-US/80617ead-f9c4-422a-a405-06fd3837f7be/ Problem-about-iinitializewithfile-ithumbnailprovider?forum=windowssearch
- Http://stackoverflow.com/questions/24232451/debugging-shell-extensions-in-win-7-and-8-1
- Https://code.msdn.microsoft.com/windowsapps/CppShellExtThumbnailHandler-32399b35
- Http://stackoverflow.com/questions/4508012/unable-to-register-dll-using-regsvr32
Summary of development of thumbnail under windows