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