Blender V4.3
blendthumb_win32_dll.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <new>
12#include <objbase.h>
13#include <shlobj.h> /* For #SHChangeNotify */
14#include <shlwapi.h>
15#include <thumbcache.h> /* For IThumbnailProvider */
16
17extern HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv);
18
19#define SZ_CLSID_BLENDTHUMBHANDLER L"{D45F043D-F17F-4e8a-8435-70971D9FA46D}"
20#define SZ_BLENDTHUMBHANDLER L"Blender Thumbnail Handler"
22 0xd45f043d, 0xf17f, 0x4e8a, {0x84, 0x35, 0x70, 0x97, 0x1d, 0x9f, 0xa4, 0x6d}};
23
24typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
29
30/* Add classes supported by this module here. */
33
34long g_cRefModule = 0;
35
37HINSTANCE g_hInst = nullptr;
38
40STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
41{
42 if (dwReason == DLL_PROCESS_ATTACH) {
43 g_hInst = hInstance;
44 DisableThreadLibraryCalls(hInstance);
45 }
46 return TRUE;
47}
48
50{
51 /* Only allow the DLL to be unloaded after all outstanding references have been released. */
52 return (g_cRefModule == 0) ? S_OK : S_FALSE;
53}
54
56{
57 InterlockedIncrement(&g_cRefModule);
58}
59
61{
62 InterlockedDecrement(&g_cRefModule);
63}
64
65class CClassFactory : public IClassFactory {
66 public:
67 static HRESULT CreateInstance(REFCLSID clsid,
68 const CLASS_OBJECT_INIT *pClassObjectInits,
69 size_t cClassObjectInits,
70 REFIID riid,
71 void **ppv)
72 {
73 *ppv = nullptr;
74 HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
75 for (size_t i = 0; i < cClassObjectInits; i++) {
76 if (clsid == *pClassObjectInits[i].pClsid) {
77 IClassFactory *pClassFactory = new (std::nothrow)
78 CClassFactory(pClassObjectInits[i].pfnCreate);
79 hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
80 if (SUCCEEDED(hr)) {
81 hr = pClassFactory->QueryInterface(riid, ppv);
82 pClassFactory->Release();
83 }
84 /* Match found. */
85 break;
86 }
87 }
88 return hr;
89 }
90
91 CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
92 {
93 DllAddRef();
94 }
95
97 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
98 {
99 static const QITAB qit[] = {QITABENT(CClassFactory, IClassFactory), {0}};
100 return QISearch(this, qit, riid, ppv);
101 }
102
103 IFACEMETHODIMP_(ULONG) AddRef()
104 {
105 return InterlockedIncrement(&_cRef);
106 }
107
108 IFACEMETHODIMP_(ULONG) Release()
109 {
110 long cRef = InterlockedDecrement(&_cRef);
111 if (cRef == 0) {
112 delete this;
113 }
114 return cRef;
115 }
116
118 IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
119 {
120 return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
121 }
122
123 IFACEMETHODIMP LockServer(BOOL fLock)
124 {
125 if (fLock) {
126 DllAddRef();
127 }
128 else {
129 DllRelease();
130 }
131 return S_OK;
132 }
133
134 private:
136 {
137 DllRelease();
138 }
139
140 long _cRef;
141 PFNCREATEINSTANCE _pfnCreate;
142};
143
144STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
145{
147 clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
148}
149
159 PCWSTR pszData;
161 DWORD dwData;
162};
163
167HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
168{
169 HKEY hKey;
170 HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot,
171 pRegistryEntry->pszKeyName,
172 0,
173 nullptr,
174 REG_OPTION_NON_VOLATILE,
175 KEY_SET_VALUE,
176 nullptr,
177 &hKey,
178 nullptr));
179 if (SUCCEEDED(hr)) {
180 /* All this just to support #REG_DWORD. */
181 DWORD size;
182 DWORD data;
183 BYTE *lpData = (LPBYTE)pRegistryEntry->pszData;
184 switch (pRegistryEntry->dwValueType) {
185 case REG_SZ:
186 size = ((DWORD)wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR);
187 break;
188 case REG_DWORD:
189 size = sizeof(DWORD);
190 data = pRegistryEntry->dwData;
191 lpData = (BYTE *)&data;
192 break;
193 default:
194 return E_INVALIDARG;
195 }
196
197 hr = HRESULT_FROM_WIN32(RegSetValueExW(
198 hKey, pRegistryEntry->pszValueName, 0, pRegistryEntry->dwValueType, lpData, size));
199 RegCloseKey(hKey);
200 }
201 return hr;
202}
203
208{
209 HRESULT hr;
210
211 WCHAR szModuleName[MAX_PATH];
212
213 if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName))) {
214 hr = HRESULT_FROM_WIN32(GetLastError());
215 }
216 else {
217 const REGISTRY_ENTRY rgRegistryEntries[] = {
218 /* `RootKey KeyName ValueName ValueType Data` */
219 {HKEY_CURRENT_USER,
220 L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
221 nullptr,
222 REG_SZ,
224 {HKEY_CURRENT_USER,
225 L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
226 nullptr,
227 REG_SZ,
228 szModuleName},
229 {HKEY_CURRENT_USER,
230 L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER L"\\InProcServer32",
231 L"ThreadingModel",
232 REG_SZ,
233 L"Apartment"},
234 {HKEY_CURRENT_USER,
235 L"Software\\Classes\\.blend\\",
236 L"Treatment",
237 REG_DWORD,
238 0,
239 0}, /* This doesn't appear to do anything. */
240 {HKEY_CURRENT_USER,
241 L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}",
242 nullptr,
243 REG_SZ,
245 };
246
247 hr = S_OK;
248 for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++) {
249 hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
250 }
251 }
252 if (SUCCEEDED(hr)) {
253 /* This tells the shell to invalidate the thumbnail cache.
254 * This is important because any `.blend` files viewed before registering this handler
255 * would otherwise show cached blank thumbnails. */
256 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
257 }
258 return hr;
259}
260
265{
266 HRESULT hr = S_OK;
267
268 const PCWSTR rgpszKeys[] = {
269 L"Software\\Classes\\CLSID\\" SZ_CLSID_BLENDTHUMBHANDLER,
270 L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"};
271
272 /* Delete the registry entries. */
273 for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++) {
274 hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
275 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
276 /* If the registry entry has already been deleted, say S_OK. */
277 hr = S_OK;
278 }
279 }
280 return hr;
281}
#define SZ_CLSID_BLENDTHUMBHANDLER
#define SZ_BLENDTHUMBHANDLER
long g_cRefModule
STDAPI DllRegisterServer()
STDAPI DllUnregisterServer()
void DllAddRef()
const CLASS_OBJECT_INIT c_rgClassObjectInit[]
DWORD dwReason
void DllRelease()
HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
DWORD void *STDAPI DllCanUnloadNow()
const CLSID CLSID_BlendThumbHandler
STDAPI_(BOOL) DllMain(HINSTANCE hInstance
HRESULT CBlendThumb_CreateInstance(REFIID riid, void **ppv)
HINSTANCE g_hInst
HRESULT(* PFNCREATEINSTANCE)(REFIID riid, void **ppvObject)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
IFACEMETHODIMP LockServer(BOOL fLock)
IFACEMETHODIMP_(ULONG) AddRef()
IFACEMETHODIMP_(ULONG) Release()
IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv)
CClassFactory(PFNCREATEINSTANCE pfnCreate)
#define L
PFNCREATEINSTANCE pfnCreate
PCWSTR pszKeyName
DWORD dwData
DWORD dwValueType
HKEY hkeyRoot
PCWSTR pszValueName
PCWSTR pszData