1 /* 2 * Shell Instance Objects - Add hot water and stir until dissolved. 3 * 4 * Copyright 2005 Michael Jung 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 /* 'Shell Instance Objects' allow you to add a node to the shell namespace 22 * (typically a shortcut to some location in the filesystem), just by setting 23 * some registry entries. This feature was introduced with win2k. Please 24 * search for 'Shell Instance Objects' on MSDN to get more information. */ 25 26 #include <stdarg.h> 27 28 #define COBJMACROS 29 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winreg.h" 33 #include "objbase.h" 34 #include "oleauto.h" 35 36 #include "shdocvw.h" 37 38 #include "wine/debug.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); 41 42 #define CHARS_IN_GUID 39 43 44 /****************************************************************************** 45 * RegistryPropertyBag 46 * 47 * Gives access to a registry key's values via the IPropertyBag interface. 48 */ 49 typedef struct _RegistryPropertyBag { 50 IPropertyBag IPropertyBag_iface; 51 LONG m_cRef; 52 HKEY m_hInitPropertyBagKey; 53 } RegistryPropertyBag; 54 55 static inline RegistryPropertyBag *impl_from_IPropertyBag(IPropertyBag *iface) 56 { 57 return CONTAINING_RECORD(iface, RegistryPropertyBag, IPropertyBag_iface); 58 } 59 60 static HRESULT WINAPI RegistryPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, 61 REFIID riid, void **ppv) 62 { 63 RegistryPropertyBag *This = impl_from_IPropertyBag(iface); 64 65 TRACE("(iface=%p, riid=%s, ppv=%p)\n", iface, debugstr_guid(riid), ppv); 66 67 if (!ppv) 68 return E_INVALIDARG; 69 70 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) { 71 *ppv = &This->IPropertyBag_iface; 72 } else { 73 *ppv = NULL; 74 return E_NOINTERFACE; 75 } 76 77 IUnknown_AddRef((IUnknown*)*ppv); 78 return S_OK; 79 } 80 81 static ULONG WINAPI RegistryPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) 82 { 83 RegistryPropertyBag *This = impl_from_IPropertyBag(iface); 84 ULONG cRef; 85 86 TRACE("(iface=%p)\n", iface); 87 88 cRef = InterlockedIncrement(&This->m_cRef); 89 90 if (cRef == 1) 91 SHDOCVW_LockModule(); 92 93 return cRef; 94 } 95 96 static ULONG WINAPI RegistryPropertyBag_IPropertyBag_Release(IPropertyBag *iface) 97 { 98 RegistryPropertyBag *This = impl_from_IPropertyBag(iface); 99 ULONG cRef; 100 101 TRACE("(iface=%p)\n", iface); 102 103 cRef = InterlockedDecrement(&This->m_cRef); 104 105 if (cRef == 0) { 106 TRACE("Destroying This=%p)\n", This); 107 RegCloseKey(This->m_hInitPropertyBagKey); 108 heap_free(This); 109 SHDOCVW_UnlockModule(); 110 } 111 112 return cRef; 113 } 114 115 static HRESULT WINAPI RegistryPropertyBag_IPropertyBag_Read(IPropertyBag *iface, 116 LPCOLESTR pwszPropName, VARIANT *pVar, IErrorLog *pErrorLog) 117 { 118 RegistryPropertyBag *This = impl_from_IPropertyBag(iface); 119 WCHAR *pwszValue; 120 DWORD dwType, cbData; 121 LONG res; 122 VARTYPE vtDst = V_VT(pVar); 123 HRESULT hr = S_OK; 124 125 TRACE("(iface=%p, pwszPropName=%s, pVar=%p, pErrorLog=%p)\n", iface, debugstr_w(pwszPropName), 126 pVar, pErrorLog); 127 128 res = RegQueryValueExW(This->m_hInitPropertyBagKey, pwszPropName, NULL, &dwType, NULL, &cbData); 129 if (res != ERROR_SUCCESS) 130 return E_INVALIDARG; 131 132 pwszValue = heap_alloc(cbData); 133 if (!pwszValue) 134 return E_OUTOFMEMORY; 135 136 res = RegQueryValueExW(This->m_hInitPropertyBagKey, pwszPropName, NULL, &dwType, 137 (LPBYTE)pwszValue, &cbData); 138 if (res != ERROR_SUCCESS) { 139 heap_free(pwszValue); 140 return E_INVALIDARG; 141 } 142 143 V_VT(pVar) = VT_BSTR; 144 V_BSTR(pVar) = SysAllocString(pwszValue); 145 heap_free(pwszValue); 146 147 if (vtDst != VT_BSTR) { 148 hr = VariantChangeTypeEx(pVar, pVar, LOCALE_SYSTEM_DEFAULT, 0, vtDst); 149 if (FAILED(hr)) 150 SysFreeString(V_BSTR(pVar)); 151 } 152 153 return hr; 154 } 155 156 static HRESULT WINAPI RegistryPropertyBag_IPropertyBag_Write(IPropertyBag *iface, 157 LPCOLESTR pwszPropName, VARIANT *pVar) 158 { 159 FIXME("(iface=%p, pwszPropName=%s, pVar=%p) stub\n", iface, debugstr_w(pwszPropName), pVar); 160 return E_NOTIMPL; 161 } 162 163 #ifdef __REACTOS__ 164 static IPropertyBagVtbl RegistryPropertyBag_IPropertyBagVtbl = { 165 #else 166 static const IPropertyBagVtbl RegistryPropertyBag_IPropertyBagVtbl = { 167 #endif 168 RegistryPropertyBag_IPropertyBag_QueryInterface, 169 RegistryPropertyBag_IPropertyBag_AddRef, 170 RegistryPropertyBag_IPropertyBag_Release, 171 RegistryPropertyBag_IPropertyBag_Read, 172 RegistryPropertyBag_IPropertyBag_Write 173 }; 174 175 static HRESULT RegistryPropertyBag_Constructor(HKEY hInitPropertyBagKey, REFIID riid, LPVOID *ppvObject) { 176 HRESULT hr = E_FAIL; 177 RegistryPropertyBag *pRegistryPropertyBag; 178 179 TRACE("(hInitPropertyBagKey=%p, riid=%s, ppvObject=%p)\n", hInitPropertyBagKey, 180 debugstr_guid(riid), ppvObject); 181 182 pRegistryPropertyBag = heap_alloc(sizeof(RegistryPropertyBag)); 183 if (pRegistryPropertyBag) { 184 pRegistryPropertyBag->IPropertyBag_iface.lpVtbl = &RegistryPropertyBag_IPropertyBagVtbl; 185 pRegistryPropertyBag->m_cRef = 0; 186 pRegistryPropertyBag->m_hInitPropertyBagKey = hInitPropertyBagKey; 187 188 /* The clasping AddRef/Release is for the case that QueryInterface fails, which will result 189 * in a reference count of 0 in the Release call, which will result in object destruction.*/ 190 IPropertyBag_AddRef(&pRegistryPropertyBag->IPropertyBag_iface); 191 hr = IPropertyBag_QueryInterface(&pRegistryPropertyBag->IPropertyBag_iface, riid, ppvObject); 192 IPropertyBag_Release(&pRegistryPropertyBag->IPropertyBag_iface); 193 } 194 195 return hr; 196 } 197 198 /****************************************************************************** 199 * InstanceObjectFactory 200 * Builds Instance Objects and asks them to initialize themselves based on the 201 * values of a PropertyBag. 202 */ 203 typedef struct _InstanceObjectFactory { 204 IClassFactory IClassFactory_iface; 205 LONG m_cRef; 206 CLSID m_clsidInstance; /* CLSID of the objects to create. */ 207 IPropertyBag *m_pPropertyBag; /* PropertyBag to initialize those objects. */ 208 } InstanceObjectFactory; 209 210 static inline InstanceObjectFactory *impl_from_IClassFactory(IClassFactory *iface) 211 { 212 return CONTAINING_RECORD(iface, InstanceObjectFactory, IClassFactory_iface); 213 } 214 215 static HRESULT WINAPI InstanceObjectFactory_IClassFactory_QueryInterface(IClassFactory *iface, 216 REFIID riid, void **ppv) 217 { 218 InstanceObjectFactory *This = impl_from_IClassFactory(iface); 219 220 TRACE("iface=%p, riid=%s, ppv=%p)\n", iface, debugstr_guid(riid), ppv); 221 222 if (!ppv) 223 return E_INVALIDARG; 224 225 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IClassFactory, riid)) { 226 *ppv = &This->IClassFactory_iface; 227 } else { 228 *ppv = NULL; 229 return E_NOINTERFACE; 230 } 231 232 IUnknown_AddRef((IUnknown*)*ppv); 233 return S_OK; 234 } 235 236 static ULONG WINAPI InstanceObjectFactory_IClassFactory_AddRef(IClassFactory *iface) 237 { 238 InstanceObjectFactory *This = impl_from_IClassFactory(iface); 239 ULONG cRef; 240 241 TRACE("(iface=%p)\n", iface); 242 243 cRef = InterlockedIncrement(&This->m_cRef); 244 245 if (cRef == 1) 246 IClassFactory_LockServer(iface, TRUE); 247 248 return cRef; 249 } 250 251 static ULONG WINAPI InstanceObjectFactory_IClassFactory_Release(IClassFactory *iface) 252 { 253 InstanceObjectFactory *This = impl_from_IClassFactory(iface); 254 ULONG cRef; 255 256 TRACE("(iface=%p)\n", iface); 257 258 cRef = InterlockedDecrement(&This->m_cRef); 259 260 if (cRef == 0) { 261 IClassFactory_LockServer(iface, FALSE); 262 IPropertyBag_Release(This->m_pPropertyBag); 263 heap_free(This); 264 } 265 266 return cRef; 267 } 268 269 static HRESULT WINAPI InstanceObjectFactory_IClassFactory_CreateInstance(IClassFactory *iface, 270 IUnknown *pUnkOuter, REFIID riid, LPVOID *ppvObj) 271 { 272 InstanceObjectFactory *This = impl_from_IClassFactory(iface); 273 IPersistPropertyBag *pPersistPropertyBag; 274 HRESULT hr; 275 276 TRACE("(pUnkOuter=%p, riid=%s, ppvObj=%p)\n", pUnkOuter, debugstr_guid(riid), ppvObj); 277 278 hr = CoCreateInstance(&This->m_clsidInstance, NULL, CLSCTX_INPROC_SERVER, 279 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag); 280 if (FAILED(hr)) { 281 TRACE("Failed to create instance of %s. hr = %08x\n", 282 debugstr_guid(&This->m_clsidInstance), hr); 283 return hr; 284 } 285 286 hr = IPersistPropertyBag_Load(pPersistPropertyBag, This->m_pPropertyBag, NULL); 287 if (FAILED(hr)) { 288 TRACE("Failed to initialize object from PropertyBag: hr = %08x\n", hr); 289 IPersistPropertyBag_Release(pPersistPropertyBag); 290 return hr; 291 } 292 293 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, riid, ppvObj); 294 IPersistPropertyBag_Release(pPersistPropertyBag); 295 296 return hr; 297 } 298 299 static HRESULT WINAPI InstanceObjectFactory_IClassFactory_LockServer(IClassFactory *iface, 300 BOOL fLock) 301 { 302 TRACE("(iface=%p, fLock=%d) stub\n", iface, fLock); 303 304 if (fLock) 305 SHDOCVW_LockModule(); 306 else 307 SHDOCVW_UnlockModule(); 308 309 return S_OK; 310 } 311 312 #ifdef __REACTOS__ 313 static IClassFactoryVtbl InstanceObjectFactory_IClassFactoryVtbl = { 314 #else 315 static const IClassFactoryVtbl InstanceObjectFactory_IClassFactoryVtbl = { 316 #endif 317 InstanceObjectFactory_IClassFactory_QueryInterface, 318 InstanceObjectFactory_IClassFactory_AddRef, 319 InstanceObjectFactory_IClassFactory_Release, 320 InstanceObjectFactory_IClassFactory_CreateInstance, 321 InstanceObjectFactory_IClassFactory_LockServer 322 }; 323 324 static HRESULT InstanceObjectFactory_Constructor(REFCLSID rclsid, IPropertyBag *pPropertyBag, 325 REFIID riid, LPVOID *ppvObject) 326 { 327 InstanceObjectFactory *pInstanceObjectFactory; 328 HRESULT hr = E_FAIL; 329 330 TRACE("(RegistryPropertyBag=%p, riid=%s, ppvObject=%p)\n", pPropertyBag, 331 debugstr_guid(riid), ppvObject); 332 333 pInstanceObjectFactory = heap_alloc(sizeof(InstanceObjectFactory)); 334 if (pInstanceObjectFactory) { 335 pInstanceObjectFactory->IClassFactory_iface.lpVtbl = &InstanceObjectFactory_IClassFactoryVtbl; 336 pInstanceObjectFactory->m_cRef = 0; 337 pInstanceObjectFactory->m_clsidInstance = *rclsid; 338 pInstanceObjectFactory->m_pPropertyBag = pPropertyBag; 339 IPropertyBag_AddRef(pPropertyBag); 340 341 IClassFactory_AddRef(&pInstanceObjectFactory->IClassFactory_iface); 342 hr = IClassFactory_QueryInterface(&pInstanceObjectFactory->IClassFactory_iface, 343 riid, ppvObject); 344 IClassFactory_Release(&pInstanceObjectFactory->IClassFactory_iface); 345 } 346 347 return hr; 348 } 349 350 /****************************************************************************** 351 * SHDOCVW_GetShellInstanceObjectClassObject [Internal] 352 * 353 * Figure if there is a 'Shell Instance Object' conformant registry entry for 354 * the given CLSID and if so create and return a corresponding ClassObject. 355 * 356 * PARAMS 357 * rclsid [I] CLSID of the 'Shell Instance Object'. 358 * riid [I] Desired interface. Only IClassFactory supported. 359 * ppvClassObj [O] The corresponding ClassObject. 360 * 361 * RETURNS 362 * Success: S_OK, 363 * Failure: CLASS_E_CLASSNOTAVAILABLE 364 */ 365 HRESULT SHDOCVW_GetShellInstanceObjectClassObject(REFCLSID rclsid, REFIID riid, 366 LPVOID *ppvClassObj) 367 { 368 WCHAR wszInstanceKey[] = { 'C','L','S','I','D','\\','{','0','0','0','0','0','0','0','0','-', 369 '0','0','0','0','-','0','0','0','0','-','0','0','0','0','-','0','0','0','0','0','0','0','0', 370 '0','0','0','0','}','\\','I','n','s','t','a','n','c','e', 0 }; 371 static const WCHAR wszCLSID[] = { 'C','L','S','I','D',0 }; 372 static const WCHAR wszInitPropertyBag[] = 373 { 'I','n','i','t','P','r','o','p','e','r','t','y','B','a','g',0 }; 374 WCHAR wszCLSIDInstance[CHARS_IN_GUID]; 375 CLSID clsidInstance; 376 HKEY hInstanceKey, hInitPropertyBagKey; 377 DWORD dwType, cbBytes = sizeof(wszCLSIDInstance); 378 IPropertyBag *pInitPropertyBag; 379 HRESULT hr; 380 LONG res; 381 382 TRACE("(rclsid=%s, riid=%s, ppvClassObject=%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), 383 ppvClassObj); 384 385 /* Figure if there is an 'Instance' subkey for the given CLSID and acquire a handle. */ 386 if (!StringFromGUID2(rclsid, wszInstanceKey + 6, CHARS_IN_GUID)) 387 return CLASS_E_CLASSNOTAVAILABLE; 388 wszInstanceKey[5+CHARS_IN_GUID] = '\\'; /* Repair the null-termination. */ 389 if (ERROR_SUCCESS != RegOpenKeyExW(HKEY_CLASSES_ROOT, wszInstanceKey, 0, KEY_READ, &hInstanceKey)) 390 /* If there is no 'Instance' subkey, then it's not a Shell Instance Object. */ 391 return CLASS_E_CLASSNOTAVAILABLE; 392 393 if (ERROR_SUCCESS != RegQueryValueExW(hInstanceKey, wszCLSID, NULL, &dwType, (LPBYTE)wszCLSIDInstance, &cbBytes) || 394 FAILED(CLSIDFromString(wszCLSIDInstance, &clsidInstance))) 395 { 396 /* 'Instance' should have a 'CLSID' value with a well-formed clsid-string. */ 397 FIXME("Failed to infer instance CLSID! %s\n", debugstr_w(wszCLSIDInstance)); 398 RegCloseKey(hInstanceKey); 399 return CLASS_E_CLASSNOTAVAILABLE; 400 } 401 402 /* Try to open the 'InitPropertyBag' subkey. */ 403 res = RegOpenKeyExW(hInstanceKey, wszInitPropertyBag, 0, KEY_READ, &hInitPropertyBagKey); 404 RegCloseKey(hInstanceKey); 405 if (res != ERROR_SUCCESS) { 406 /* Besides 'InitPropertyBag's, shell instance objects might be initialized by streams. 407 * So this case might not be an error. */ 408 TRACE("No InitPropertyBag key found!\n"); 409 return CLASS_E_CLASSNOTAVAILABLE; 410 } 411 412 /* If the construction succeeds, the new RegistryPropertyBag is responsible for closing 413 * hInitPropertyBagKey. */ 414 hr = RegistryPropertyBag_Constructor(hInitPropertyBagKey, &IID_IPropertyBag, 415 (LPVOID*)&pInitPropertyBag); 416 if (FAILED(hr)) { 417 RegCloseKey(hInitPropertyBagKey); 418 return hr; 419 } 420 421 /* Construct an Instance Object Factory, which creates objects of class 'clsidInstance' 422 * and asks them to initialize themselves with the help of the 'pInitiPropertyBag' */ 423 hr = InstanceObjectFactory_Constructor(&clsidInstance, pInitPropertyBag, riid, ppvClassObj); 424 IPropertyBag_Release(pInitPropertyBag); /* The factory will hold a reference the bag. */ 425 426 return hr; 427 } 428