1 /* 2 * standard IPropertyStore implementation 3 * 4 * Copyright 2012 Vincent Povirk for CodeWeavers 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 #define COBJMACROS 22 #include "config.h" 23 24 #include <stdarg.h> 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "objbase.h" 29 #include "rpcproxy.h" 30 #include "propsys.h" 31 #include "wine/debug.h" 32 #include "wine/unicode.h" 33 #include "wine/list.h" 34 35 #include "initguid.h" 36 #include "propsys_private.h" 37 38 DEFINE_GUID(FMTID_NamedProperties, 0xd5cdd505, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae); 39 40 WINE_DEFAULT_DEBUG_CHANNEL(propsys); 41 42 typedef struct { 43 struct list entry; 44 DWORD pid; 45 PROPVARIANT propvar; 46 PSC_STATE state; 47 } propstore_value; 48 49 typedef struct { 50 struct list entry; 51 GUID fmtid; 52 struct list values; /* list of struct propstore_value */ 53 DWORD count; 54 } propstore_format; 55 56 typedef struct { 57 IPropertyStoreCache IPropertyStoreCache_iface; 58 LONG ref; 59 CRITICAL_SECTION lock; 60 struct list formats; /* list of struct propstore_format */ 61 } PropertyStore; 62 63 static inline PropertyStore *impl_from_IPropertyStoreCache(IPropertyStoreCache *iface) 64 { 65 return CONTAINING_RECORD(iface, PropertyStore, IPropertyStoreCache_iface); 66 } 67 68 static HRESULT WINAPI PropertyStore_QueryInterface(IPropertyStoreCache *iface, REFIID iid, 69 void **ppv) 70 { 71 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 72 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 73 74 if (!ppv) return E_INVALIDARG; 75 76 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IPropertyStore, iid) || 77 IsEqualIID(&IID_IPropertyStoreCache, iid)) 78 { 79 *ppv = &This->IPropertyStoreCache_iface; 80 } 81 else 82 { 83 FIXME("No interface for %s\n", debugstr_guid(iid)); 84 *ppv = NULL; 85 return E_NOINTERFACE; 86 } 87 88 IUnknown_AddRef((IUnknown*)*ppv); 89 return S_OK; 90 } 91 92 static ULONG WINAPI PropertyStore_AddRef(IPropertyStoreCache *iface) 93 { 94 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 95 ULONG ref = InterlockedIncrement(&This->ref); 96 97 TRACE("(%p) refcount=%u\n", iface, ref); 98 99 return ref; 100 } 101 102 static void destroy_format(propstore_format *format) 103 { 104 propstore_value *cursor, *cursor2; 105 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &format->values, propstore_value, entry) 106 { 107 PropVariantClear(&cursor->propvar); 108 HeapFree(GetProcessHeap(), 0, cursor); 109 } 110 HeapFree(GetProcessHeap(), 0, format); 111 } 112 113 static ULONG WINAPI PropertyStore_Release(IPropertyStoreCache *iface) 114 { 115 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 116 ULONG ref = InterlockedDecrement(&This->ref); 117 118 TRACE("(%p) refcount=%u\n", iface, ref); 119 120 if (ref == 0) 121 { 122 propstore_format *cursor, *cursor2; 123 This->lock.DebugInfo->Spare[0] = 0; 124 DeleteCriticalSection(&This->lock); 125 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->formats, propstore_format, entry) 126 destroy_format(cursor); 127 HeapFree(GetProcessHeap(), 0, This); 128 } 129 130 return ref; 131 } 132 133 static HRESULT WINAPI PropertyStore_GetCount(IPropertyStoreCache *iface, 134 DWORD *cProps) 135 { 136 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 137 propstore_format *format; 138 139 TRACE("%p,%p\n", iface, cProps); 140 141 if (!cProps) 142 return E_POINTER; 143 144 *cProps = 0; 145 146 EnterCriticalSection(&This->lock); 147 148 LIST_FOR_EACH_ENTRY(format, &This->formats, propstore_format, entry) 149 *cProps += format->count; 150 151 LeaveCriticalSection(&This->lock); 152 153 return S_OK; 154 } 155 156 static HRESULT WINAPI PropertyStore_GetAt(IPropertyStoreCache *iface, 157 DWORD iProp, PROPERTYKEY *pkey) 158 { 159 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 160 propstore_format *format=NULL, *format_candidate; 161 propstore_value *value; 162 HRESULT hr; 163 164 TRACE("%p,%d,%p\n", iface, iProp, pkey); 165 166 if (!pkey) 167 return E_POINTER; 168 169 EnterCriticalSection(&This->lock); 170 171 LIST_FOR_EACH_ENTRY(format_candidate, &This->formats, propstore_format, entry) 172 { 173 if (format_candidate->count > iProp) 174 { 175 format = format_candidate; 176 pkey->fmtid = format->fmtid; 177 break; 178 } 179 180 iProp -= format_candidate->count; 181 } 182 183 if (format) 184 { 185 LIST_FOR_EACH_ENTRY(value, &format->values, propstore_value, entry) 186 { 187 if (iProp == 0) 188 { 189 pkey->pid = value->pid; 190 break; 191 } 192 193 iProp--; 194 } 195 196 hr = S_OK; 197 } 198 else 199 hr = E_INVALIDARG; 200 201 LeaveCriticalSection(&This->lock); 202 203 return hr; 204 } 205 206 static HRESULT PropertyStore_LookupValue(PropertyStore *This, REFPROPERTYKEY key, 207 BOOL insert, propstore_value **result) 208 { 209 propstore_format *format=NULL, *format_candidate; 210 propstore_value *value=NULL, *value_candidate; 211 212 if (IsEqualGUID(&key->fmtid, &FMTID_NamedProperties)) 213 { 214 /* This is used in the property store format [MS-PROPSTORE] 215 * for named values and probably gets special treatment. */ 216 ERR("don't know how to handle FMTID_NamedProperties\n"); 217 return E_FAIL; 218 } 219 220 LIST_FOR_EACH_ENTRY(format_candidate, &This->formats, propstore_format, entry) 221 { 222 if (IsEqualGUID(&format_candidate->fmtid, &key->fmtid)) 223 { 224 format = format_candidate; 225 break; 226 } 227 } 228 229 if (!format) 230 { 231 if (!insert) 232 return TYPE_E_ELEMENTNOTFOUND; 233 234 format = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format)); 235 if (!format) 236 return E_OUTOFMEMORY; 237 238 format->fmtid = key->fmtid; 239 list_init(&format->values); 240 list_add_tail(&This->formats, &format->entry); 241 } 242 243 LIST_FOR_EACH_ENTRY(value_candidate, &format->values, propstore_value, entry) 244 { 245 if (value_candidate->pid == key->pid) 246 { 247 value = value_candidate; 248 break; 249 } 250 } 251 252 if (!value) 253 { 254 if (!insert) 255 return TYPE_E_ELEMENTNOTFOUND; 256 257 value = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*value)); 258 if (!value) 259 return E_OUTOFMEMORY; 260 261 value->pid = key->pid; 262 list_add_tail(&format->values, &value->entry); 263 format->count++; 264 } 265 266 *result = value; 267 268 return S_OK; 269 } 270 271 static HRESULT WINAPI PropertyStore_GetValue(IPropertyStoreCache *iface, 272 REFPROPERTYKEY key, PROPVARIANT *pv) 273 { 274 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 275 propstore_value *value; 276 HRESULT hr; 277 278 TRACE("%p,%p,%p\n", iface, key, pv); 279 280 if (!pv) 281 return E_POINTER; 282 283 EnterCriticalSection(&This->lock); 284 285 hr = PropertyStore_LookupValue(This, key, FALSE, &value); 286 287 if (SUCCEEDED(hr)) 288 hr = PropVariantCopy(pv, &value->propvar); 289 else if (hr == TYPE_E_ELEMENTNOTFOUND) 290 { 291 PropVariantInit(pv); 292 hr = S_OK; 293 } 294 295 LeaveCriticalSection(&This->lock); 296 297 return hr; 298 } 299 300 static HRESULT WINAPI PropertyStore_SetValue(IPropertyStoreCache *iface, 301 REFPROPERTYKEY key, REFPROPVARIANT propvar) 302 { 303 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 304 propstore_value *value; 305 HRESULT hr; 306 PROPVARIANT temp; 307 308 TRACE("%p,%p,%p\n", iface, key, propvar); 309 310 EnterCriticalSection(&This->lock); 311 312 hr = PropertyStore_LookupValue(This, key, TRUE, &value); 313 314 if (SUCCEEDED(hr)) 315 hr = PropVariantCopy(&temp, propvar); 316 317 if (SUCCEEDED(hr)) 318 { 319 PropVariantClear(&value->propvar); 320 value->propvar = temp; 321 } 322 323 LeaveCriticalSection(&This->lock); 324 325 return hr; 326 } 327 328 static HRESULT WINAPI PropertyStore_Commit(IPropertyStoreCache *iface) 329 { 330 FIXME("%p: stub\n", iface); 331 return S_OK; 332 } 333 334 static HRESULT WINAPI PropertyStore_GetState(IPropertyStoreCache *iface, 335 REFPROPERTYKEY key, PSC_STATE *pstate) 336 { 337 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 338 propstore_value *value; 339 HRESULT hr; 340 341 TRACE("%p,%p,%p\n", iface, key, pstate); 342 343 EnterCriticalSection(&This->lock); 344 345 hr = PropertyStore_LookupValue(This, key, FALSE, &value); 346 347 if (SUCCEEDED(hr)) 348 *pstate = value->state; 349 350 LeaveCriticalSection(&This->lock); 351 352 if (FAILED(hr)) 353 *pstate = PSC_NORMAL; 354 355 return hr; 356 } 357 358 static HRESULT WINAPI PropertyStore_GetValueAndState(IPropertyStoreCache *iface, 359 REFPROPERTYKEY key, PROPVARIANT *ppropvar, PSC_STATE *pstate) 360 { 361 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 362 propstore_value *value; 363 HRESULT hr; 364 365 TRACE("%p,%p,%p,%p\n", iface, key, ppropvar, pstate); 366 367 EnterCriticalSection(&This->lock); 368 369 hr = PropertyStore_LookupValue(This, key, FALSE, &value); 370 371 if (SUCCEEDED(hr)) 372 hr = PropVariantCopy(ppropvar, &value->propvar); 373 374 if (SUCCEEDED(hr)) 375 *pstate = value->state; 376 377 LeaveCriticalSection(&This->lock); 378 379 if (FAILED(hr)) 380 { 381 PropVariantInit(ppropvar); 382 *pstate = PSC_NORMAL; 383 } 384 385 return hr; 386 } 387 388 static HRESULT WINAPI PropertyStore_SetState(IPropertyStoreCache *iface, 389 REFPROPERTYKEY key, PSC_STATE pstate) 390 { 391 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 392 propstore_value *value; 393 HRESULT hr; 394 395 TRACE("%p,%p,%d\n", iface, key, pstate); 396 397 EnterCriticalSection(&This->lock); 398 399 hr = PropertyStore_LookupValue(This, key, FALSE, &value); 400 401 if (SUCCEEDED(hr)) 402 value->state = pstate; 403 404 LeaveCriticalSection(&This->lock); 405 406 return hr; 407 } 408 409 static HRESULT WINAPI PropertyStore_SetValueAndState(IPropertyStoreCache *iface, 410 REFPROPERTYKEY key, const PROPVARIANT *ppropvar, PSC_STATE state) 411 { 412 PropertyStore *This = impl_from_IPropertyStoreCache(iface); 413 propstore_value *value; 414 HRESULT hr; 415 PROPVARIANT temp; 416 417 TRACE("%p,%p,%p,%d\n", iface, key, ppropvar, state); 418 419 EnterCriticalSection(&This->lock); 420 421 hr = PropertyStore_LookupValue(This, key, TRUE, &value); 422 423 if (SUCCEEDED(hr)) 424 hr = PropVariantCopy(&temp, ppropvar); 425 426 if (SUCCEEDED(hr)) 427 { 428 PropVariantClear(&value->propvar); 429 value->propvar = temp; 430 value->state = state; 431 } 432 433 LeaveCriticalSection(&This->lock); 434 435 return hr; 436 } 437 438 static const IPropertyStoreCacheVtbl PropertyStore_Vtbl = { 439 PropertyStore_QueryInterface, 440 PropertyStore_AddRef, 441 PropertyStore_Release, 442 PropertyStore_GetCount, 443 PropertyStore_GetAt, 444 PropertyStore_GetValue, 445 PropertyStore_SetValue, 446 PropertyStore_Commit, 447 PropertyStore_GetState, 448 PropertyStore_GetValueAndState, 449 PropertyStore_SetState, 450 PropertyStore_SetValueAndState 451 }; 452 453 HRESULT PropertyStore_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 454 { 455 PropertyStore *This; 456 HRESULT ret; 457 458 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv); 459 460 *ppv = NULL; 461 462 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 463 464 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyStore)); 465 if (!This) return E_OUTOFMEMORY; 466 467 This->IPropertyStoreCache_iface.lpVtbl = &PropertyStore_Vtbl; 468 This->ref = 1; 469 InitializeCriticalSection(&This->lock); 470 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PropertyStore.lock"); 471 list_init(&This->formats); 472 473 ret = IPropertyStoreCache_QueryInterface(&This->IPropertyStoreCache_iface, iid, ppv); 474 IPropertyStoreCache_Release(&This->IPropertyStoreCache_iface); 475 476 return ret; 477 } 478