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