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