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