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
30 #include "wine/debug.h"
31 #include "wine/list.h"
34 #include "propsys_private.h"
36 DEFINE_GUID(FMTID_NamedProperties
, 0xd5cdd505, 0x2e9c, 0x101b, 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae);
38 WINE_DEFAULT_DEBUG_CHANNEL(propsys
);
50 struct list values
; /* list of struct propstore_value */
55 IPropertyStoreCache IPropertyStoreCache_iface
;
57 CRITICAL_SECTION lock
;
58 struct list formats
; /* list of struct propstore_format */
61 static inline PropertyStore
*impl_from_IPropertyStoreCache(IPropertyStoreCache
*iface
)
63 return CONTAINING_RECORD(iface
, PropertyStore
, IPropertyStoreCache_iface
);
66 static HRESULT WINAPI
PropertyStore_QueryInterface(IPropertyStoreCache
*iface
, REFIID iid
,
69 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
70 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
72 if (!ppv
) return E_INVALIDARG
;
74 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IPropertyStore
, iid
) ||
75 IsEqualIID(&IID_IPropertyStoreCache
, iid
))
77 *ppv
= &This
->IPropertyStoreCache_iface
;
81 FIXME("No interface for %s\n", debugstr_guid(iid
));
86 IUnknown_AddRef((IUnknown
*)*ppv
);
90 static ULONG WINAPI
PropertyStore_AddRef(IPropertyStoreCache
*iface
)
92 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
93 ULONG ref
= InterlockedIncrement(&This
->ref
);
95 TRACE("(%p) refcount=%u\n", iface
, ref
);
100 static void destroy_format(propstore_format
*format
)
102 propstore_value
*cursor
, *cursor2
;
103 LIST_FOR_EACH_ENTRY_SAFE(cursor
, cursor2
, &format
->values
, propstore_value
, entry
)
105 PropVariantClear(&cursor
->propvar
);
106 HeapFree(GetProcessHeap(), 0, cursor
);
108 HeapFree(GetProcessHeap(), 0, format
);
111 static ULONG WINAPI
PropertyStore_Release(IPropertyStoreCache
*iface
)
113 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
114 ULONG ref
= InterlockedDecrement(&This
->ref
);
116 TRACE("(%p) refcount=%u\n", iface
, ref
);
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
);
131 static HRESULT WINAPI
PropertyStore_GetCount(IPropertyStoreCache
*iface
,
134 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
135 propstore_format
*format
;
137 TRACE("%p,%p\n", iface
, cProps
);
144 EnterCriticalSection(&This
->lock
);
146 LIST_FOR_EACH_ENTRY(format
, &This
->formats
, propstore_format
, entry
)
147 *cProps
+= format
->count
;
149 LeaveCriticalSection(&This
->lock
);
154 static HRESULT WINAPI
PropertyStore_GetAt(IPropertyStoreCache
*iface
,
155 DWORD iProp
, PROPERTYKEY
*pkey
)
157 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
158 propstore_format
*format
=NULL
, *format_candidate
;
159 propstore_value
*value
;
162 TRACE("%p,%d,%p\n", iface
, iProp
, pkey
);
167 EnterCriticalSection(&This
->lock
);
169 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
171 if (format_candidate
->count
> iProp
)
173 format
= format_candidate
;
174 pkey
->fmtid
= format
->fmtid
;
178 iProp
-= format_candidate
->count
;
183 LIST_FOR_EACH_ENTRY(value
, &format
->values
, propstore_value
, entry
)
187 pkey
->pid
= value
->pid
;
199 LeaveCriticalSection(&This
->lock
);
204 static HRESULT
PropertyStore_LookupValue(PropertyStore
*This
, REFPROPERTYKEY key
,
205 BOOL insert
, propstore_value
**result
)
207 propstore_format
*format
=NULL
, *format_candidate
;
208 propstore_value
*value
=NULL
, *value_candidate
;
210 if (IsEqualGUID(&key
->fmtid
, &FMTID_NamedProperties
))
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");
218 LIST_FOR_EACH_ENTRY(format_candidate
, &This
->formats
, propstore_format
, entry
)
220 if (IsEqualGUID(&format_candidate
->fmtid
, &key
->fmtid
))
222 format
= format_candidate
;
230 return TYPE_E_ELEMENTNOTFOUND
;
232 format
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*format
));
234 return E_OUTOFMEMORY
;
236 format
->fmtid
= key
->fmtid
;
237 list_init(&format
->values
);
238 list_add_tail(&This
->formats
, &format
->entry
);
241 LIST_FOR_EACH_ENTRY(value_candidate
, &format
->values
, propstore_value
, entry
)
243 if (value_candidate
->pid
== key
->pid
)
245 value
= value_candidate
;
253 return TYPE_E_ELEMENTNOTFOUND
;
255 value
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*value
));
257 return E_OUTOFMEMORY
;
259 value
->pid
= key
->pid
;
260 list_add_tail(&format
->values
, &value
->entry
);
269 static HRESULT WINAPI
PropertyStore_GetValue(IPropertyStoreCache
*iface
,
270 REFPROPERTYKEY key
, PROPVARIANT
*pv
)
272 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
273 propstore_value
*value
;
276 TRACE("%p,%p,%p\n", iface
, key
, pv
);
281 EnterCriticalSection(&This
->lock
);
283 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
286 hr
= PropVariantCopy(pv
, &value
->propvar
);
287 else if (hr
== TYPE_E_ELEMENTNOTFOUND
)
293 LeaveCriticalSection(&This
->lock
);
298 static HRESULT WINAPI
PropertyStore_SetValue(IPropertyStoreCache
*iface
,
299 REFPROPERTYKEY key
, REFPROPVARIANT propvar
)
301 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
302 propstore_value
*value
;
306 TRACE("%p,%p,%p\n", iface
, key
, propvar
);
308 EnterCriticalSection(&This
->lock
);
310 hr
= PropertyStore_LookupValue(This
, key
, TRUE
, &value
);
313 hr
= PropVariantCopy(&temp
, propvar
);
317 PropVariantClear(&value
->propvar
);
318 value
->propvar
= temp
;
321 LeaveCriticalSection(&This
->lock
);
326 static HRESULT WINAPI
PropertyStore_Commit(IPropertyStoreCache
*iface
)
328 FIXME("%p: stub\n", iface
);
332 static HRESULT WINAPI
PropertyStore_GetState(IPropertyStoreCache
*iface
,
333 REFPROPERTYKEY key
, PSC_STATE
*pstate
)
335 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
336 propstore_value
*value
;
339 TRACE("%p,%p,%p\n", iface
, key
, pstate
);
341 EnterCriticalSection(&This
->lock
);
343 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
346 *pstate
= value
->state
;
348 LeaveCriticalSection(&This
->lock
);
351 *pstate
= PSC_NORMAL
;
356 static HRESULT WINAPI
PropertyStore_GetValueAndState(IPropertyStoreCache
*iface
,
357 REFPROPERTYKEY key
, PROPVARIANT
*ppropvar
, PSC_STATE
*pstate
)
359 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
360 propstore_value
*value
;
363 TRACE("%p,%p,%p,%p\n", iface
, key
, ppropvar
, pstate
);
365 EnterCriticalSection(&This
->lock
);
367 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
370 hr
= PropVariantCopy(ppropvar
, &value
->propvar
);
373 *pstate
= value
->state
;
375 LeaveCriticalSection(&This
->lock
);
379 PropVariantInit(ppropvar
);
380 *pstate
= PSC_NORMAL
;
386 static HRESULT WINAPI
PropertyStore_SetState(IPropertyStoreCache
*iface
,
387 REFPROPERTYKEY key
, PSC_STATE pstate
)
389 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
390 propstore_value
*value
;
393 TRACE("%p,%p,%d\n", iface
, key
, pstate
);
395 EnterCriticalSection(&This
->lock
);
397 hr
= PropertyStore_LookupValue(This
, key
, FALSE
, &value
);
400 value
->state
= pstate
;
402 LeaveCriticalSection(&This
->lock
);
407 static HRESULT WINAPI
PropertyStore_SetValueAndState(IPropertyStoreCache
*iface
,
408 REFPROPERTYKEY key
, const PROPVARIANT
*ppropvar
, PSC_STATE state
)
410 PropertyStore
*This
= impl_from_IPropertyStoreCache(iface
);
411 propstore_value
*value
;
415 TRACE("%p,%p,%p,%d\n", iface
, key
, ppropvar
, state
);
417 EnterCriticalSection(&This
->lock
);
419 hr
= PropertyStore_LookupValue(This
, key
, TRUE
, &value
);
422 hr
= PropVariantCopy(&temp
, ppropvar
);
426 PropVariantClear(&value
->propvar
);
427 value
->propvar
= temp
;
428 value
->state
= state
;
431 LeaveCriticalSection(&This
->lock
);
436 static const IPropertyStoreCacheVtbl PropertyStore_Vtbl
= {
437 PropertyStore_QueryInterface
,
438 PropertyStore_AddRef
,
439 PropertyStore_Release
,
440 PropertyStore_GetCount
,
442 PropertyStore_GetValue
,
443 PropertyStore_SetValue
,
444 PropertyStore_Commit
,
445 PropertyStore_GetState
,
446 PropertyStore_GetValueAndState
,
447 PropertyStore_SetState
,
448 PropertyStore_SetValueAndState
451 HRESULT
PropertyStore_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
456 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
460 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
462 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyStore
));
463 if (!This
) return E_OUTOFMEMORY
;
465 This
->IPropertyStoreCache_iface
.lpVtbl
= &PropertyStore_Vtbl
;
467 InitializeCriticalSection(&This
->lock
);
468 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PropertyStore.lock");
469 list_init(&This
->formats
);
471 ret
= IPropertyStoreCache_QueryInterface(&This
->IPropertyStoreCache_iface
, iid
, ppv
);
472 IPropertyStoreCache_Release(&This
->IPropertyStoreCache_iface
);
477 HRESULT WINAPI
PSCreatePropertyStoreFromObject(IUnknown
*obj
, DWORD access
, REFIID riid
, void **ret
)
481 TRACE("(%p, %d, %s, %p)\n", obj
, access
, debugstr_guid(riid
), ret
);
486 if (IsEqualIID(riid
, &IID_IPropertyStore
) && SUCCEEDED(hr
= IUnknown_QueryInterface(obj
, riid
, ret
)))
489 FIXME("Unimplemented for %s.\n", debugstr_guid(riid
));