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
21 #include "propsys_private.h"
23 #include <wine/list.h>
26 DEFINE_GUID(FMTID_NamedProperties
, 0xd5cdd505, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae);
38 struct list values
; /* list of struct propstore_value */
43 IPropertyStoreCache IPropertyStoreCache_iface
;
45 CRITICAL_SECTION lock
;
46 struct list formats
; /* list of struct propstore_format */
49 static inline PropertyStore
*impl_from_IPropertyStoreCache(IPropertyStoreCache
*iface
)
51 return CONTAINING_RECORD(iface
, PropertyStore
, IPropertyStoreCache_iface
);
54 static HRESULT WINAPI
PropertyStore_QueryInterface(IPropertyStoreCache
*iface
, REFIID iid
,
57 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
58 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
60 if (!ppv
) return E_INVALIDARG
;
62 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IPropertyStore
, iid
) ||
63 IsEqualIID(&IID_IPropertyStoreCache
, iid
))
65 *ppv
= &This
->IPropertyStoreCache_iface
;
69 FIXME("No interface for %s\n", debugstr_guid(iid
));
74 IUnknown_AddRef((IUnknown
*)*ppv
);
78 static ULONG WINAPI
PropertyStore_AddRef(IPropertyStoreCache
*iface
)
80 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
81 ULONG ref
= InterlockedIncrement(&This
->ref
);
83 TRACE("(%p) refcount=%u\n", iface
, ref
);
88 static void destroy_format(propstore_format
*format
)
90 propstore_value
*cursor
, *cursor2
;
91 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &format
->values
, propstore_value
, entry
)
93 PropVariantClear(&cursor
->propvar
);
94 HeapFree(GetProcessHeap(), 0, cursor
);
96 HeapFree(GetProcessHeap(), 0, format
);
99 static ULONG WINAPI
PropertyStore_Release(IPropertyStoreCache
*iface
)
101 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
102 ULONG ref
= InterlockedDecrement(&This
->ref
);
104 TRACE("(%p) refcount=%u\n", iface
, ref
);
108 propstore_format
*cursor
, *cursor2
;
109 This
->lock
.DebugInfo
->Spare
[0] = 0;
110 DeleteCriticalSection(&This
->lock
);
111 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &This
->formats
, propstore_format
, entry
)
112 destroy_format(cursor
);
113 HeapFree(GetProcessHeap(), 0, This
);
119 static HRESULT WINAPI
PropertyStore_GetCount(IPropertyStoreCache
*iface
,
122 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
123 propstore_format
*format
;
125 TRACE("%p,%p\n", iface
, cProps
);
132 EnterCriticalSection(&This
->lock
);
134 LIST_FOR_EACH_ENTRY(format
, &This
->formats
, propstore_format
, entry
)
135 *cProps
+= format
->count
;
137 LeaveCriticalSection(&This
->lock
);
142 static HRESULT WINAPI
PropertyStore_GetAt(IPropertyStoreCache
*iface
,
143 DWORD iProp
, PROPERTYKEY
*pkey
)
145 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
146 propstore_format
*format
=NULL
, *format_candidate
;
147 propstore_value
*value
;
150 TRACE("%p,%d,%p\n", iface
, iProp
, pkey
);
155 EnterCriticalSection(&This
->lock
);
157 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
159 if (format_candidate
->count
> iProp
)
161 format
= format_candidate
;
162 pkey
->fmtid
= format
->fmtid
;
166 iProp
-= format_candidate
->count
;
171 LIST_FOR_EACH_ENTRY(value
, &format
->values
, propstore_value
, entry
)
175 pkey
->pid
= value
->pid
;
187 LeaveCriticalSection(&This
->lock
);
192 static HRESULT
PropertyStore_LookupValue(PropertyStore
*This
, REFPROPERTYKEY key
,
193 BOOL insert
, propstore_value
**result
)
195 propstore_format
*format
=NULL
, *format_candidate
;
196 propstore_value
*value
=NULL
, *value_candidate
;
198 if (IsEqualGUID(&key
->fmtid
, &FMTID_NamedProperties
))
200 /* This is used in the property store format [MS-PROPSTORE]
201 * for named values and probably gets special treatment. */
202 ERR("don't know how to handle FMTID_NamedProperties\n");
206 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
208 if (IsEqualGUID(&format_candidate
->fmtid
, &key
->fmtid
))
210 format
= format_candidate
;
218 return TYPE_E_ELEMENTNOTFOUND
;
220 format
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*format
));
222 return E_OUTOFMEMORY
;
224 format
->fmtid
= key
->fmtid
;
225 list_init(&format
->values
);
226 list_add_tail(&This
->formats
, &format
->entry
);
229 LIST_FOR_EACH_ENTRY(value_candidate
, &format
->values
, propstore_value
, entry
)
231 if (value_candidate
->pid
== key
->pid
)
233 value
= value_candidate
;
241 return TYPE_E_ELEMENTNOTFOUND
;
243 value
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*value
));
245 return E_OUTOFMEMORY
;
247 value
->pid
= key
->pid
;
248 list_add_tail(&format
->values
, &value
->entry
);
257 static HRESULT WINAPI
PropertyStore_GetValue(IPropertyStoreCache
*iface
,
258 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
260 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
261 propstore_value
*value
;
264 TRACE("%p,%p,%p\n", iface
, key
, pv
);
269 EnterCriticalSection(&This
->lock
);
271 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
274 hr
= PropVariantCopy(pv
, &value
->propvar
);
275 else if (hr
== TYPE_E_ELEMENTNOTFOUND
)
281 LeaveCriticalSection(&This
->lock
);
286 static HRESULT WINAPI
PropertyStore_SetValue(IPropertyStoreCache
*iface
,
287 REFPROPERTYKEY key
, REFPROPVARIANT propvar
)
289 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
290 propstore_value
*value
;
294 TRACE("%p,%p,%p\n", iface
, key
, propvar
);
296 EnterCriticalSection(&This
->lock
);
298 hr
= PropertyStore_LookupValue(This
, key
, TRUE
, &value
);
301 hr
= PropVariantCopy(&temp
, propvar
);
305 PropVariantClear(&value
->propvar
);
306 value
->propvar
= temp
;
309 LeaveCriticalSection(&This
->lock
);
314 static HRESULT WINAPI
PropertyStore_Commit(IPropertyStoreCache
*iface
)
316 FIXME("%p: stub\n", iface
);
320 static HRESULT WINAPI
PropertyStore_GetState(IPropertyStoreCache
*iface
,
321 REFPROPERTYKEY key
, PSC_STATE
*pstate
)
323 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
324 propstore_value
*value
;
327 TRACE("%p,%p,%p\n", iface
, key
, pstate
);
329 EnterCriticalSection(&This
->lock
);
331 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
334 *pstate
= value
->state
;
336 LeaveCriticalSection(&This
->lock
);
339 *pstate
= PSC_NORMAL
;
344 static HRESULT WINAPI
PropertyStore_GetValueAndState(IPropertyStoreCache
*iface
,
345 REFPROPERTYKEY key
, PROPVARIANT
*ppropvar
, PSC_STATE
*pstate
)
347 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
348 propstore_value
*value
;
351 TRACE("%p,%p,%p,%p\n", iface
, key
, ppropvar
, pstate
);
353 EnterCriticalSection(&This
->lock
);
355 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
358 hr
= PropVariantCopy(ppropvar
, &value
->propvar
);
361 *pstate
= value
->state
;
363 LeaveCriticalSection(&This
->lock
);
367 PropVariantInit(ppropvar
);
368 *pstate
= PSC_NORMAL
;
374 static HRESULT WINAPI
PropertyStore_SetState(IPropertyStoreCache
*iface
,
375 REFPROPERTYKEY key
, PSC_STATE pstate
)
377 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
378 propstore_value
*value
;
381 TRACE("%p,%p,%d\n", iface
, key
, pstate
);
383 EnterCriticalSection(&This
->lock
);
385 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
388 value
->state
= pstate
;
390 LeaveCriticalSection(&This
->lock
);
395 static HRESULT WINAPI
PropertyStore_SetValueAndState(IPropertyStoreCache
*iface
,
396 REFPROPERTYKEY key
, const PROPVARIANT
*ppropvar
, PSC_STATE state
)
398 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
399 propstore_value
*value
;
403 TRACE("%p,%p,%p,%d\n", iface
, key
, ppropvar
, state
);
405 EnterCriticalSection(&This
->lock
);
407 hr
= PropertyStore_LookupValue(This
, key
, TRUE
, &value
);
410 hr
= PropVariantCopy(&temp
, ppropvar
);
414 PropVariantClear(&value
->propvar
);
415 value
->propvar
= temp
;
416 value
->state
= state
;
419 LeaveCriticalSection(&This
->lock
);
424 static const IPropertyStoreCacheVtbl PropertyStore_Vtbl
= {
425 PropertyStore_QueryInterface
,
426 PropertyStore_AddRef
,
427 PropertyStore_Release
,
428 PropertyStore_GetCount
,
430 PropertyStore_GetValue
,
431 PropertyStore_SetValue
,
432 PropertyStore_Commit
,
433 PropertyStore_GetState
,
434 PropertyStore_GetValueAndState
,
435 PropertyStore_SetState
,
436 PropertyStore_SetValueAndState
439 HRESULT
PropertyStore_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
444 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
448 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
450 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyStore
));
451 if (!This
) return E_OUTOFMEMORY
;
453 This
->IPropertyStoreCache_iface
.lpVtbl
= &PropertyStore_Vtbl
;
455 InitializeCriticalSection(&This
->lock
);
456 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PropertyStore.lock");
457 list_init(&This
->formats
);
459 ret
= IPropertyStoreCache_QueryInterface(&This
->IPropertyStoreCache_iface
, iid
, ppv
);
460 IPropertyStoreCache_Release(&This
->IPropertyStoreCache_iface
);