[DEVENUM]
[reactos.git] / reactos / dll / directx / wine / devenum / mediacatenum.c
1 /*
2 * IEnumMoniker implementation for DEVENUM.dll
3 *
4 * Copyright (C) 2002 Robert Shearman
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 * NOTES ON THIS FILE:
21 * - Implements IEnumMoniker interface which enumerates through moniker
22 * objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
23 */
24
25 #include "devenum_private.h"
26
27 #include <ocidl.h>
28 #include <oleauto.h>
29
30 typedef struct
31 {
32 IEnumMoniker IEnumMoniker_iface;
33 LONG ref;
34 DWORD index;
35 DWORD subkey_cnt;
36 HKEY hkey;
37 HKEY special_hkey;
38 } EnumMonikerImpl;
39
40 typedef struct
41 {
42 IPropertyBag IPropertyBag_iface;
43 LONG ref;
44 HKEY hkey;
45 } RegPropBagImpl;
46
47
48 static inline RegPropBagImpl *impl_from_IPropertyBag(IPropertyBag *iface)
49 {
50 return CONTAINING_RECORD(iface, RegPropBagImpl, IPropertyBag_iface);
51 }
52
53 static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface(
54 LPPROPERTYBAG iface,
55 REFIID riid,
56 LPVOID *ppvObj)
57 {
58 RegPropBagImpl *This = impl_from_IPropertyBag(iface);
59
60 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj);
61
62 if (This == NULL || ppvObj == NULL) return E_POINTER;
63
64 if (IsEqualGUID(riid, &IID_IUnknown) ||
65 IsEqualGUID(riid, &IID_IPropertyBag))
66 {
67 *ppvObj = iface;
68 IPropertyBag_AddRef(iface);
69 return S_OK;
70 }
71
72 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
73 return E_NOINTERFACE;
74 }
75
76 /**********************************************************************
77 * DEVENUM_IPropertyBag_AddRef (also IUnknown)
78 */
79 static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)
80 {
81 RegPropBagImpl *This = impl_from_IPropertyBag(iface);
82
83 TRACE("(%p)->() AddRef from %d\n", iface, This->ref);
84
85 return InterlockedIncrement(&This->ref);
86 }
87
88 /**********************************************************************
89 * DEVENUM_IPropertyBag_Release (also IUnknown)
90 */
91 static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
92 {
93 RegPropBagImpl *This = impl_from_IPropertyBag(iface);
94 ULONG ref;
95
96 TRACE("(%p)->() ReleaseThis->ref from %d\n", iface, This->ref);
97
98 ref = InterlockedDecrement(&This->ref);
99 if (ref == 0) {
100 RegCloseKey(This->hkey);
101 CoTaskMemFree(This);
102 DEVENUM_UnlockModule();
103 }
104 return ref;
105 }
106
107 static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
108 LPPROPERTYBAG iface,
109 LPCOLESTR pszPropName,
110 VARIANT* pVar,
111 IErrorLog* pErrorLog)
112 {
113 LPVOID pData = NULL;
114 DWORD received;
115 DWORD type = 0;
116 RegPropBagImpl *This = impl_from_IPropertyBag(iface);
117 HRESULT res = S_OK;
118 LONG reswin32;
119
120 TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
121
122 if (!pszPropName || !pVar)
123 return E_POINTER;
124
125 reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, NULL, NULL, &received);
126 res = HRESULT_FROM_WIN32(reswin32);
127
128 if (SUCCEEDED(res))
129 {
130 pData = HeapAlloc(GetProcessHeap(), 0, received);
131
132 /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */
133 reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, pData, &received);
134 res = HRESULT_FROM_WIN32(reswin32);
135 }
136
137 if (SUCCEEDED(res))
138 {
139 res = E_INVALIDARG; /* assume we cannot coerce into right type */
140
141 TRACE("Read %d bytes (%s)\n", received, type == REG_SZ ? debugstr_w(pData) : "binary data");
142
143 switch (type)
144 {
145 case REG_SZ:
146 switch (V_VT(pVar))
147 {
148 case VT_LPWSTR:
149 V_BSTR(pVar) = CoTaskMemAlloc(received);
150 memcpy(V_BSTR(pVar), pData, received);
151 res = S_OK;
152 break;
153 case VT_EMPTY:
154 V_VT(pVar) = VT_BSTR;
155 /* fall through */
156 case VT_BSTR:
157 V_BSTR(pVar) = SysAllocStringLen(pData, received/sizeof(WCHAR) - 1);
158 res = S_OK;
159 break;
160 }
161 break;
162 case REG_DWORD:
163 TRACE("REG_DWORD: %x\n", *(DWORD *)pData);
164 switch (V_VT(pVar))
165 {
166 case VT_EMPTY:
167 V_VT(pVar) = VT_I4;
168 /* fall through */
169 case VT_I4:
170 case VT_UI4:
171 V_I4(pVar) = *(DWORD *)pData;
172 res = S_OK;
173 break;
174 }
175 break;
176 case REG_BINARY:
177 {
178 SAFEARRAYBOUND bound;
179 void * pArrayElements;
180 bound.lLbound = 0;
181 bound.cElements = received;
182 TRACE("REG_BINARY: len = %d\n", received);
183 switch (V_VT(pVar))
184 {
185 case VT_EMPTY:
186 V_VT(pVar) = VT_ARRAY | VT_UI1;
187 /* fall through */
188 case VT_ARRAY | VT_UI1:
189 if (!(V_ARRAY(pVar) = SafeArrayCreate(VT_UI1, 1, &bound)))
190 res = E_OUTOFMEMORY;
191 else
192 res = S_OK;
193 break;
194 }
195
196 if (res == E_INVALIDARG)
197 break;
198
199 res = SafeArrayAccessData(V_ARRAY(pVar), &pArrayElements);
200 if (FAILED(res))
201 break;
202
203 CopyMemory(pArrayElements, pData, received);
204 res = SafeArrayUnaccessData(V_ARRAY(pVar));
205 break;
206 }
207 }
208 if (res == E_INVALIDARG)
209 FIXME("Variant type %x not supported for regtype %x\n", V_VT(pVar), type);
210 }
211
212 HeapFree(GetProcessHeap(), 0, pData);
213
214 TRACE("<- %x\n", res);
215 return res;
216 }
217
218 static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
219 LPPROPERTYBAG iface,
220 LPCOLESTR pszPropName,
221 VARIANT* pVar)
222 {
223 RegPropBagImpl *This = impl_from_IPropertyBag(iface);
224 LPVOID lpData = NULL;
225 DWORD cbData = 0;
226 DWORD dwType = 0;
227 HRESULT res = S_OK;
228
229 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
230
231 switch (V_VT(pVar))
232 {
233 case VT_BSTR:
234 case VT_LPWSTR:
235 TRACE("writing %s\n", debugstr_w(V_BSTR(pVar)));
236 lpData = V_BSTR(pVar);
237 dwType = REG_SZ;
238 cbData = (lstrlenW(V_BSTR(pVar)) + 1) * sizeof(WCHAR);
239 break;
240 case VT_I4:
241 case VT_UI4:
242 TRACE("writing %u\n", V_UI4(pVar));
243 lpData = &V_UI4(pVar);
244 dwType = REG_DWORD;
245 cbData = sizeof(DWORD);
246 break;
247 case VT_ARRAY | VT_UI1:
248 {
249 LONG lUbound = 0;
250 LONG lLbound = 0;
251 dwType = REG_BINARY;
252 res = SafeArrayGetLBound(V_ARRAY(pVar), 1, &lLbound);
253 res = SafeArrayGetUBound(V_ARRAY(pVar), 1, &lUbound);
254 cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/;
255 TRACE("cbData: %d\n", cbData);
256 res = SafeArrayAccessData(V_ARRAY(pVar), &lpData);
257 break;
258 }
259 default:
260 FIXME("Variant type %d not handled\n", V_VT(pVar));
261 return E_FAIL;
262 }
263
264 if (RegSetValueExW(This->hkey,
265 pszPropName, 0,
266 dwType, lpData, cbData) != ERROR_SUCCESS)
267 res = E_FAIL;
268
269 if (V_VT(pVar) & VT_ARRAY)
270 res = SafeArrayUnaccessData(V_ARRAY(pVar));
271
272 return res;
273 }
274
275 static const IPropertyBagVtbl IPropertyBag_Vtbl =
276 {
277 DEVENUM_IPropertyBag_QueryInterface,
278 DEVENUM_IPropertyBag_AddRef,
279 DEVENUM_IPropertyBag_Release,
280 DEVENUM_IPropertyBag_Read,
281 DEVENUM_IPropertyBag_Write
282 };
283
284 static HRESULT DEVENUM_IPropertyBag_Construct(HANDLE hkey, IPropertyBag **ppBag)
285 {
286 RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl));
287 if (!rpb)
288 return E_OUTOFMEMORY;
289 rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
290 rpb->ref = 1;
291 rpb->hkey = hkey;
292 *ppBag = &rpb->IPropertyBag_iface;
293 DEVENUM_LockModule();
294 return S_OK;
295 }
296
297
298 static inline MediaCatMoniker *impl_from_IMoniker(IMoniker *iface)
299 {
300 return CONTAINING_RECORD(iface, MediaCatMoniker, IMoniker_iface);
301 }
302
303 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker *iface, REFIID riid,
304 void **ppv)
305 {
306 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
307
308 if (!ppv)
309 return E_POINTER;
310
311 if (IsEqualGUID(riid, &IID_IUnknown) ||
312 IsEqualGUID(riid, &IID_IPersist) ||
313 IsEqualGUID(riid, &IID_IPersistStream) ||
314 IsEqualGUID(riid, &IID_IMoniker))
315 {
316 *ppv = iface;
317 IMoniker_AddRef(iface);
318 return S_OK;
319 }
320
321 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
322 *ppv = NULL;
323 return E_NOINTERFACE;
324 }
325
326 static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(IMoniker *iface)
327 {
328 MediaCatMoniker *This = impl_from_IMoniker(iface);
329 ULONG ref = InterlockedIncrement(&This->ref);
330
331 TRACE("(%p) ref=%d\n", This, ref);
332
333 return ref;
334 }
335
336 static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface)
337 {
338 MediaCatMoniker *This = impl_from_IMoniker(iface);
339 ULONG ref = InterlockedDecrement(&This->ref);
340
341 TRACE("(%p) ref=%d\n", This, ref);
342
343 if (ref == 0) {
344 RegCloseKey(This->hkey);
345 CoTaskMemFree(This);
346 DEVENUM_UnlockModule();
347 }
348 return ref;
349 }
350
351 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
352 {
353 MediaCatMoniker *This = impl_from_IMoniker(iface);
354
355 FIXME("(%p)->(%p): stub\n", This, pClassID);
356
357 if (pClassID == NULL)
358 return E_POINTER;
359
360 return E_NOTIMPL;
361 }
362
363 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(IMoniker *iface)
364 {
365 FIXME("(%p)->(): stub\n", iface);
366
367 return S_FALSE;
368 }
369
370 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(IMoniker *iface, IStream *pStm)
371 {
372 FIXME("(%p)->(%p): stub\n", iface, pStm);
373
374 return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
378 {
379 FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
380
381 return STG_E_CANTSAVE;
382 }
383
384 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
385 {
386 FIXME("(%p)->(%p): stub\n", iface, pcbSize);
387
388 ZeroMemory(pcbSize, sizeof(*pcbSize));
389
390 return S_OK;
391 }
392
393 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBindCtx *pbc,
394 IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult)
395 {
396 MediaCatMoniker *This = impl_from_IMoniker(iface);
397 IUnknown * pObj = NULL;
398 IPropertyBag * pProp = NULL;
399 CLSID clsID;
400 VARIANT var;
401 HRESULT res = E_FAIL;
402
403 TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult);
404
405 VariantInit(&var);
406 *ppvResult = NULL;
407
408 if(pmkToLeft==NULL)
409 {
410 /* first activation of this class */
411 LPVOID pvptr;
412 res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr);
413 pProp = pvptr;
414 if (SUCCEEDED(res))
415 {
416 V_VT(&var) = VT_LPWSTR;
417 res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL);
418 }
419 if (SUCCEEDED(res))
420 {
421 res = CLSIDFromString(V_BSTR(&var), &clsID);
422 CoTaskMemFree(V_BSTR(&var));
423 }
424 if (SUCCEEDED(res))
425 {
426 res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr);
427 pObj = pvptr;
428 }
429 }
430
431 if (pObj!=NULL)
432 {
433 /* get the requested interface from the loaded class */
434 res = S_OK;
435 if (pProp) {
436 HRESULT res2;
437 LPVOID ppv = NULL;
438 res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv);
439 if (SUCCEEDED(res2)) {
440 res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL);
441 IPersistPropertyBag_Release((IPersistPropertyBag *) ppv);
442 }
443 }
444 if (SUCCEEDED(res))
445 res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
446 IUnknown_Release(pObj);
447 }
448
449 if (pProp)
450 {
451 IPropertyBag_Release(pProp);
452 }
453
454 TRACE("<- 0x%x\n", res);
455
456 return res;
457 }
458
459 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
460 IMoniker *pmkToLeft, REFIID riid, void **ppvObj)
461 {
462 MediaCatMoniker *This = impl_from_IMoniker(iface);
463
464 TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
465
466 *ppvObj = NULL;
467
468 if (pmkToLeft)
469 return MK_E_NOSTORAGE;
470
471 if (pbc != NULL)
472 {
473 static DWORD reported;
474 if (!reported)
475 {
476 FIXME("ignoring IBindCtx %p\n", pbc);
477 reported++;
478 }
479 }
480
481 if (IsEqualGUID(riid, &IID_IPropertyBag))
482 {
483 HANDLE hkey;
484 DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), &hkey, 0, 0, DUPLICATE_SAME_ACCESS);
485 return DEVENUM_IPropertyBag_Construct(hkey, (IPropertyBag**)ppvObj);
486 }
487
488 return MK_E_NOSTORAGE;
489 }
490
491 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
492 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
493 {
494 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
495
496 if (ppmkToLeft)
497 *ppmkToLeft = NULL;
498 *ppmkReduced = iface;
499
500 return MK_S_REDUCED_TO_SELF;
501 }
502
503 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
504 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
505 {
506 FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
507
508 /* FIXME: use CreateGenericComposite? */
509 *ppmkComposite = NULL;
510
511 return E_NOTIMPL;
512 }
513
514 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(IMoniker *iface, BOOL fForward,
515 IEnumMoniker **ppenumMoniker)
516 {
517 FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
518
519 *ppenumMoniker = NULL;
520
521 return S_OK;
522 }
523
524 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
525 {
526 FIXME("(%p)->(%p): stub\n", iface, pmkOtherMoniker);
527
528 return E_NOTIMPL;
529 }
530
531 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
532 {
533 TRACE("(%p)->(%p)\n", iface, pdwHash);
534
535 *pdwHash = 0;
536
537 return S_OK;
538 }
539
540 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
541 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
542 {
543 FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
544
545 return S_FALSE;
546 }
547
548 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
549 IMoniker *pmkToLeft, FILETIME *pFileTime)
550 {
551 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
552
553 pFileTime->dwLowDateTime = 0xFFFFFFFF;
554 pFileTime->dwHighDateTime = 0x7FFFFFFF;
555
556 return MK_E_UNAVAILABLE;
557 }
558
559 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
560 {
561 TRACE("(%p)->(%p)\n", iface, ppmk);
562
563 *ppmk = NULL;
564
565 return MK_E_NOINVERSE;
566 }
567
568 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker *iface,
569 IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
570 {
571 TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
572
573 *ppmkPrefix = NULL;
574
575 return MK_E_NOPREFIX;
576 }
577
578 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
579 IMoniker **ppmkRelPath)
580 {
581 TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
582
583 *ppmkRelPath = pmkOther;
584
585 return MK_S_HIM;
586 }
587
588 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
589 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
590 {
591 MediaCatMoniker *This = impl_from_IMoniker(iface);
592 WCHAR wszBuffer[MAX_PATH];
593 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
594 LONG received = sizeof(wszFriendlyName);
595
596 TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
597
598 *ppszDisplayName = NULL;
599
600 /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */
601 if (RegQueryValueW(This->hkey, wszFriendlyName, wszBuffer, &received) == ERROR_SUCCESS)
602 {
603 *ppszDisplayName = CoTaskMemAlloc(received);
604 strcpyW(*ppszDisplayName, wszBuffer);
605 return S_OK;
606 }
607
608 return E_FAIL;
609 }
610
611 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
612 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
613 {
614 FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
615
616 *pchEaten = 0;
617 *ppmkOut = NULL;
618
619 return MK_E_SYNTAX;
620 }
621
622 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
623 {
624 TRACE("(%p)->(%p)\n", iface, pdwMksys);
625
626 return S_FALSE;
627 }
628
629 static const IMonikerVtbl IMoniker_Vtbl =
630 {
631 DEVENUM_IMediaCatMoniker_QueryInterface,
632 DEVENUM_IMediaCatMoniker_AddRef,
633 DEVENUM_IMediaCatMoniker_Release,
634 DEVENUM_IMediaCatMoniker_GetClassID,
635 DEVENUM_IMediaCatMoniker_IsDirty,
636 DEVENUM_IMediaCatMoniker_Load,
637 DEVENUM_IMediaCatMoniker_Save,
638 DEVENUM_IMediaCatMoniker_GetSizeMax,
639 DEVENUM_IMediaCatMoniker_BindToObject,
640 DEVENUM_IMediaCatMoniker_BindToStorage,
641 DEVENUM_IMediaCatMoniker_Reduce,
642 DEVENUM_IMediaCatMoniker_ComposeWith,
643 DEVENUM_IMediaCatMoniker_Enum,
644 DEVENUM_IMediaCatMoniker_IsEqual,
645 DEVENUM_IMediaCatMoniker_Hash,
646 DEVENUM_IMediaCatMoniker_IsRunning,
647 DEVENUM_IMediaCatMoniker_GetTimeOfLastChange,
648 DEVENUM_IMediaCatMoniker_Inverse,
649 DEVENUM_IMediaCatMoniker_CommonPrefixWith,
650 DEVENUM_IMediaCatMoniker_RelativePathTo,
651 DEVENUM_IMediaCatMoniker_GetDisplayName,
652 DEVENUM_IMediaCatMoniker_ParseDisplayName,
653 DEVENUM_IMediaCatMoniker_IsSystemMoniker
654 };
655
656 MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void)
657 {
658 MediaCatMoniker * pMoniker = NULL;
659 pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
660 if (!pMoniker)
661 return NULL;
662
663 pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
664 pMoniker->ref = 0;
665 pMoniker->hkey = NULL;
666
667 DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface);
668
669 DEVENUM_LockModule();
670
671 return pMoniker;
672 }
673
674 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
675 {
676 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
677 }
678
679 static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker *iface, REFIID riid,
680 void **ppv)
681 {
682 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
683
684 if (!ppv)
685 return E_POINTER;
686
687 if (IsEqualGUID(riid, &IID_IUnknown) ||
688 IsEqualGUID(riid, &IID_IEnumMoniker))
689 {
690 *ppv = iface;
691 IEnumMoniker_AddRef(iface);
692 return S_OK;
693 }
694
695 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
696 *ppv = NULL;
697 return E_NOINTERFACE;
698 }
699
700 static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(IEnumMoniker *iface)
701 {
702 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
703 ULONG ref = InterlockedIncrement(&This->ref);
704
705 TRACE("(%p) ref=%d\n", This, ref);
706
707 return ref;
708 }
709
710 static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
711 {
712 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
713 ULONG ref = InterlockedDecrement(&This->ref);
714
715 TRACE("(%p) ref=%d\n", This, ref);
716
717 if (!ref)
718 {
719 if(This->special_hkey)
720 RegCloseKey(This->special_hkey);
721 RegCloseKey(This->hkey);
722 CoTaskMemFree(This);
723 DEVENUM_UnlockModule();
724 return 0;
725 }
726 return ref;
727 }
728
729 static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
730 ULONG *pceltFetched)
731 {
732 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
733 WCHAR buffer[MAX_PATH + 1];
734 LONG res;
735 ULONG fetched = 0;
736 MediaCatMoniker * pMoniker;
737
738 TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
739
740 while (fetched < celt)
741 {
742 if(This->index+fetched < This->subkey_cnt)
743 res = RegEnumKeyW(This->hkey, This->index+fetched, buffer, sizeof(buffer) / sizeof(WCHAR));
744 else if(This->special_hkey)
745 res = RegEnumKeyW(This->special_hkey, This->index+fetched-This->subkey_cnt, buffer, sizeof(buffer) / sizeof(WCHAR));
746 else
747 break;
748 if (res != ERROR_SUCCESS)
749 {
750 break;
751 }
752 pMoniker = DEVENUM_IMediaCatMoniker_Construct();
753 if (!pMoniker)
754 return E_OUTOFMEMORY;
755
756 if (RegOpenKeyW(This->index+fetched < This->subkey_cnt ? This->hkey : This->special_hkey,
757 buffer, &pMoniker->hkey) != ERROR_SUCCESS)
758 {
759 IMoniker_Release(&pMoniker->IMoniker_iface);
760 break;
761 }
762 rgelt[fetched] = &pMoniker->IMoniker_iface;
763 fetched++;
764 }
765
766 This->index += fetched;
767
768 TRACE("-- fetched %d\n", fetched);
769
770 if (pceltFetched)
771 *pceltFetched = fetched;
772
773 if (fetched != celt)
774 return S_FALSE;
775 else
776 return S_OK;
777 }
778
779 static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt)
780 {
781 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
782 DWORD special_subkeys = 0;
783
784 TRACE("(%p)->(%d)\n", iface, celt);
785
786 /* Before incrementing, check if there are any more values to run through.
787 Some programs use the Skip() function to get the number of devices */
788 if(This->special_hkey)
789 RegQueryInfoKeyW(This->special_hkey, NULL, NULL, NULL, &special_subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
790
791 if((This->index + celt) >= This->subkey_cnt + special_subkeys)
792 {
793 return S_FALSE;
794 }
795
796 This->index += celt;
797
798 return S_OK;
799 }
800
801 static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
802 {
803 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
804
805 TRACE("(%p)->()\n", iface);
806
807 This->index = 0;
808
809 return S_OK;
810 }
811
812 static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
813 {
814 FIXME("(%p)->(%p): stub\n", iface, ppenum);
815
816 return E_NOTIMPL;
817 }
818
819 /**********************************************************************
820 * IEnumMoniker_Vtbl
821 */
822 static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
823 {
824 DEVENUM_IEnumMoniker_QueryInterface,
825 DEVENUM_IEnumMoniker_AddRef,
826 DEVENUM_IEnumMoniker_Release,
827 DEVENUM_IEnumMoniker_Next,
828 DEVENUM_IEnumMoniker_Skip,
829 DEVENUM_IEnumMoniker_Reset,
830 DEVENUM_IEnumMoniker_Clone
831 };
832
833 HRESULT DEVENUM_IEnumMoniker_Construct(HKEY hkey, HKEY special_hkey, IEnumMoniker ** ppEnumMoniker)
834 {
835 EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl));
836 if (!pEnumMoniker)
837 return E_OUTOFMEMORY;
838
839 pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
840 pEnumMoniker->ref = 1;
841 pEnumMoniker->index = 0;
842 pEnumMoniker->hkey = hkey;
843 pEnumMoniker->special_hkey = special_hkey;
844
845 *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
846
847 if(RegQueryInfoKeyW(pEnumMoniker->hkey, NULL, NULL, NULL, &pEnumMoniker->subkey_cnt, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
848 pEnumMoniker->subkey_cnt = 0;
849
850
851 DEVENUM_LockModule();
852
853 return S_OK;
854 }