2 * standard IPropertyStore implementation
4 * Copyright 2012 Vincent Povirk for CodeWeavers
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.
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.
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
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "wine/list.h"
36 #include "propsys_private.h"
38 DEFINE_GUID(FMTID_NamedProperties
, 0xd5cdd505, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae);
40 WINE_DEFAULT_DEBUG_CHANNEL(propsys
);
52 struct list values
; /* list of struct propstore_value */
57 IPropertyStoreCache IPropertyStoreCache_iface
;
59 CRITICAL_SECTION lock
;
60 struct list formats
; /* list of struct propstore_format */
63 static inline PropertyStore
*impl_from_IPropertyStoreCache(IPropertyStoreCache
*iface
)
65 return CONTAINING_RECORD(iface
, PropertyStore
, IPropertyStoreCache_iface
);
68 static HRESULT WINAPI
PropertyStore_QueryInterface(IPropertyStoreCache
*iface
, REFIID iid
,
71 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
72 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
74 if (!ppv
) return E_INVALIDARG
;
76 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IPropertyStore
, iid
) ||
77 IsEqualIID(&IID_IPropertyStoreCache
, iid
))
79 *ppv
= &This
->IPropertyStoreCache_iface
;
83 FIXME("No interface for %s\n", debugstr_guid(iid
));
88 IUnknown_AddRef((IUnknown
*)*ppv
);
92 static ULONG WINAPI
PropertyStore_AddRef(IPropertyStoreCache
*iface
)
94 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
95 ULONG ref
= InterlockedIncrement(&This
->ref
);
97 TRACE("(%p) refcount=%u\n", iface
, ref
);
102 static void destroy_format(propstore_format
*format
)
104 propstore_value
*cursor
, *cursor2
;
105 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &format
->values
, propstore_value
, entry
)
107 PropVariantClear(&cursor
->propvar
);
108 HeapFree(GetProcessHeap(), 0, cursor
);
110 HeapFree(GetProcessHeap(), 0, format
);
113 static ULONG WINAPI
PropertyStore_Release(IPropertyStoreCache
*iface
)
115 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
116 ULONG ref
= InterlockedDecrement(&This
->ref
);
118 TRACE("(%p) refcount=%u\n", iface
, ref
);
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
);
133 static HRESULT WINAPI
PropertyStore_GetCount(IPropertyStoreCache
*iface
,
136 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
137 propstore_format
*format
;
139 TRACE("%p,%p\n", iface
, cProps
);
146 EnterCriticalSection(&This
->lock
);
148 LIST_FOR_EACH_ENTRY(format
, &This
->formats
, propstore_format
, entry
)
149 *cProps
+= format
->count
;
151 LeaveCriticalSection(&This
->lock
);
156 static HRESULT WINAPI
PropertyStore_GetAt(IPropertyStoreCache
*iface
,
157 DWORD iProp
, PROPERTYKEY
*pkey
)
159 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
160 propstore_format
*format
=NULL
, *format_candidate
;
161 propstore_value
*value
;
164 TRACE("%p,%d,%p\n", iface
, iProp
, pkey
);
169 EnterCriticalSection(&This
->lock
);
171 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
173 if (format_candidate
->count
> iProp
)
175 format
= format_candidate
;
176 pkey
->fmtid
= format
->fmtid
;
180 iProp
-= format_candidate
->count
;
185 LIST_FOR_EACH_ENTRY(value
, &format
->values
, propstore_value
, entry
)
189 pkey
->pid
= value
->pid
;
201 LeaveCriticalSection(&This
->lock
);
206 static HRESULT
PropertyStore_LookupValue(PropertyStore
*This
, REFPROPERTYKEY key
,
207 int insert
, propstore_value
**result
)
209 propstore_format
*format
=NULL
, *format_candidate
;
210 propstore_value
*value
=NULL
, *value_candidate
;
212 if (IsEqualGUID(&key
->fmtid
, &FMTID_NamedProperties
))
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");
220 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
222 if (IsEqualGUID(&format_candidate
->fmtid
, &key
->fmtid
))
224 format
= format_candidate
;
232 return TYPE_E_ELEMENTNOTFOUND
;
234 format
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*format
));
236 return E_OUTOFMEMORY
;
238 format
->fmtid
= key
->fmtid
;
239 list_init(&format
->values
);
240 list_add_tail(&This
->formats
, &format
->entry
);
243 LIST_FOR_EACH_ENTRY(value_candidate
, &format
->values
, propstore_value
, entry
)
245 if (value_candidate
->pid
== key
->pid
)
247 value
= value_candidate
;
255 return TYPE_E_ELEMENTNOTFOUND
;
257 value
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*value
));
259 return E_OUTOFMEMORY
;
261 value
->pid
= key
->pid
;
262 list_add_tail(&format
->values
, &value
->entry
);
271 static HRESULT WINAPI
PropertyStore_GetValue(IPropertyStoreCache
*iface
,
272 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
274 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
275 propstore_value
*value
;
278 TRACE("%p,%p,%p\n", iface
, key
, pv
);
283 EnterCriticalSection(&This
->lock
);
285 hr
= PropertyStore_LookupValue(This
, key
, 0, &value
);
288 hr
= PropVariantCopy(pv
, &value
->propvar
);
289 else if (hr
== TYPE_E_ELEMENTNOTFOUND
)
295 LeaveCriticalSection(&This
->lock
);
300 static HRESULT WINAPI
PropertyStore_SetValue(IPropertyStoreCache
*iface
,
301 REFPROPERTYKEY key
, REFPROPVARIANT propvar
)
303 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
304 propstore_value
*value
;
307 TRACE("%p,%p,%p\n", iface
, key
, propvar
);
309 EnterCriticalSection(&This
->lock
);
311 hr
= PropertyStore_LookupValue(This
, key
, 1, &value
);
314 hr
= PropVariantCopy(&value
->propvar
, propvar
);
316 LeaveCriticalSection(&This
->lock
);
321 static HRESULT WINAPI
PropertyStore_Commit(IPropertyStoreCache
*iface
)
323 FIXME("%p: stub\n", iface
);
327 static HRESULT WINAPI
PropertyStore_GetState(IPropertyStoreCache
*iface
,
328 REFPROPERTYKEY key
, PSC_STATE
*pstate
)
330 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
331 propstore_value
*value
;
334 TRACE("%p,%p,%p\n", iface
, key
, pstate
);
336 EnterCriticalSection(&This
->lock
);
338 hr
= PropertyStore_LookupValue(This
, key
, 0, &value
);
341 *pstate
= value
->state
;
343 LeaveCriticalSection(&This
->lock
);
346 *pstate
= PSC_NORMAL
;
351 static HRESULT WINAPI
PropertyStore_GetValueAndState(IPropertyStoreCache
*iface
,
352 REFPROPERTYKEY key
, PROPVARIANT
*ppropvar
, PSC_STATE
*pstate
)
354 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
355 propstore_value
*value
;
358 TRACE("%p,%p,%p,%p\n", iface
, key
, ppropvar
, pstate
);
360 EnterCriticalSection(&This
->lock
);
362 hr
= PropertyStore_LookupValue(This
, key
, 0, &value
);
365 hr
= PropVariantCopy(ppropvar
, &value
->propvar
);
368 *pstate
= value
->state
;
370 LeaveCriticalSection(&This
->lock
);
374 PropVariantInit(ppropvar
);
375 *pstate
= PSC_NORMAL
;
381 static HRESULT WINAPI
PropertyStore_SetState(IPropertyStoreCache
*iface
,
382 REFPROPERTYKEY key
, PSC_STATE pstate
)
384 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
385 propstore_value
*value
;
388 TRACE("%p,%p,%d\n", iface
, key
, pstate
);
390 EnterCriticalSection(&This
->lock
);
392 hr
= PropertyStore_LookupValue(This
, key
, 0, &value
);
395 value
->state
= pstate
;
397 LeaveCriticalSection(&This
->lock
);
402 static HRESULT WINAPI
PropertyStore_SetValueAndState(IPropertyStoreCache
*iface
,
403 REFPROPERTYKEY key
, const PROPVARIANT
*ppropvar
, PSC_STATE state
)
405 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
406 propstore_value
*value
;
409 TRACE("%p,%p,%p,%d\n", iface
, key
, ppropvar
, state
);
411 EnterCriticalSection(&This
->lock
);
413 hr
= PropertyStore_LookupValue(This
, key
, 1, &value
);
416 hr
= PropVariantCopy(&value
->propvar
, ppropvar
);
419 value
->state
= state
;
421 LeaveCriticalSection(&This
->lock
);
426 static const IPropertyStoreCacheVtbl PropertyStore_Vtbl
= {
427 PropertyStore_QueryInterface
,
428 PropertyStore_AddRef
,
429 PropertyStore_Release
,
430 PropertyStore_GetCount
,
432 PropertyStore_GetValue
,
433 PropertyStore_SetValue
,
434 PropertyStore_Commit
,
435 PropertyStore_GetState
,
436 PropertyStore_GetValueAndState
,
437 PropertyStore_SetState
,
438 PropertyStore_SetValueAndState
441 HRESULT
PropertyStore_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
446 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
450 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
452 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyStore
));
453 if (!This
) return E_OUTOFMEMORY
;
455 This
->IPropertyStoreCache_iface
.lpVtbl
= &PropertyStore_Vtbl
;
457 InitializeCriticalSection(&This
->lock
);
458 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PropertyStore.lock");
459 list_init(&This
->formats
);
461 ret
= IPropertyStoreCache_QueryInterface(&This
->IPropertyStoreCache_iface
, iid
, ppv
);
462 IPropertyStoreCache_Release(&This
->IPropertyStoreCache_iface
);