Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / devenum.c
1 /*
2  * Implementation of CLSID_SystemDeviceEnum.
3  * Implements IMoniker for CLSID_CDeviceMoniker.
4  * Implements IPropertyBag. (internal)
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31 #include "objidl.h"
32 #include "oleidl.h"
33 #include "ocidl.h"
34 #include "oleauto.h"
35 #include "strmif.h"
36 #include "uuids.h"
37
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
40
41 #include "quartz_private.h"
42 #include "devenum.h"
43 #include "enumunk.h"
44 #include "complist.h"
45 #include "regsvr.h"
46
47 #ifndef NUMELEMS
48 #define NUMELEMS(elem)  (sizeof(elem)/sizeof(elem[0]))
49 #endif  /* NUMELEMS */
50
51 /***************************************************************************
52  *
53  *      new/delete for CLSID_SystemDeviceEnum
54  *
55  */
56
57 /* can I use offsetof safely? - FIXME? */
58 static QUARTZ_IFEntry CSysDevEnum_IFEntries[] =
59 {
60   { &IID_ICreateDevEnum, offsetof(CSysDevEnum,createdevenum)-offsetof(CSysDevEnum,unk) },
61 };
62
63
64 static void QUARTZ_DestroySystemDeviceEnum(IUnknown* punk)
65 {
66         CSysDevEnum_THIS(punk,unk);
67
68         CSysDevEnum_UninitICreateDevEnum( This );
69 }
70
71 HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
72 {
73         CSysDevEnum*    psde;
74         HRESULT hr;
75
76         TRACE("(%p,%p)\n",punkOuter,ppobj);
77
78         psde = (CSysDevEnum*)QUARTZ_AllocObj( sizeof(CSysDevEnum) );
79         if ( psde == NULL )
80                 return E_OUTOFMEMORY;
81
82         QUARTZ_IUnkInit( &psde->unk, punkOuter );
83
84         hr = CSysDevEnum_InitICreateDevEnum( psde );
85         if ( FAILED(hr) )
86         {
87                 QUARTZ_FreeObj( psde );
88                 return hr;
89         }
90
91         psde->unk.pEntries = CSysDevEnum_IFEntries;
92         psde->unk.dwEntries = sizeof(CSysDevEnum_IFEntries)/sizeof(CSysDevEnum_IFEntries[0]);
93         psde->unk.pOnFinalRelease = QUARTZ_DestroySystemDeviceEnum;
94
95         *ppobj = (void*)(&psde->unk);
96
97         return S_OK;
98 }
99
100
101 /***************************************************************************
102  *
103  *      CSysDevEnum::ICreateDevEnum
104  *
105  */
106
107
108 static HRESULT WINAPI
109 ICreateDevEnum_fnQueryInterface(ICreateDevEnum* iface,REFIID riid,void** ppobj)
110 {
111         CSysDevEnum_THIS(iface,createdevenum);
112
113         TRACE("(%p)->()\n",This);
114
115         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
116 }
117
118 static ULONG WINAPI
119 ICreateDevEnum_fnAddRef(ICreateDevEnum* iface)
120 {
121         CSysDevEnum_THIS(iface,createdevenum);
122
123         TRACE("(%p)->()\n",This);
124
125         return IUnknown_AddRef(This->unk.punkControl);
126 }
127
128 static ULONG WINAPI
129 ICreateDevEnum_fnRelease(ICreateDevEnum* iface)
130 {
131         CSysDevEnum_THIS(iface,createdevenum);
132
133         TRACE("(%p)->()\n",This);
134
135         return IUnknown_Release(This->unk.punkControl);
136 }
137
138 static HRESULT WINAPI
139 ICreateDevEnum_fnCreateClassEnumerator(ICreateDevEnum* iface,REFCLSID rclsidDeviceClass,IEnumMoniker** ppobj, DWORD dwFlags)
140 {
141         CSysDevEnum_THIS(iface,createdevenum);
142         HRESULT hr;
143         HKEY    hKey;
144         QUARTZ_CompList*        pMonList;
145         IMoniker*       pMon;
146         DWORD   dwIndex;
147         LONG    lr;
148         WCHAR   wszPath[ 1024 ];
149         DWORD   dwLen;
150         DWORD   dwNameMax;
151         DWORD   cbName;
152         FILETIME        ftLastWrite;
153
154         TRACE("(%p)->(%s,%p,%08lx)\n",This,
155                 debugstr_guid(rclsidDeviceClass),ppobj,dwFlags);
156         if ( dwFlags != 0 )
157         {
158                 FIXME("unknown flags %08lx\n",dwFlags);
159                 return E_NOTIMPL;
160         }
161
162         if ( ppobj == NULL )
163                 return E_POINTER;
164         *ppobj = NULL;
165
166         hr = QUARTZ_CreateCLSIDPath(
167                 wszPath, sizeof(wszPath)/sizeof(wszPath[0]) - 16,
168                 rclsidDeviceClass, QUARTZ_wszInstance );
169         if ( FAILED(hr) )
170                 return hr;
171
172         lr = RegOpenKeyExW( HKEY_CLASSES_ROOT, wszPath,
173                 0, KEY_READ, &hKey );
174         if ( lr != ERROR_SUCCESS )
175         {
176                 TRACE("cannot open %s\n",debugstr_w(wszPath));
177                 if ( lr == ERROR_FILE_NOT_FOUND ||
178                          lr == ERROR_PATH_NOT_FOUND )
179                         return S_FALSE;
180                 return E_FAIL;
181         }
182
183         dwLen = lstrlenW(wszPath);
184         wszPath[dwLen++] = '\\'; wszPath[dwLen] = 0;
185         dwNameMax = sizeof(wszPath)/sizeof(wszPath[0]) - dwLen - 8;
186
187         pMonList = QUARTZ_CompList_Alloc();
188         if ( pMonList == NULL )
189         {
190                 hr = E_OUTOFMEMORY;
191                 goto err;
192         }
193
194         /* enumerate all subkeys. */
195         dwIndex = 0;
196         while ( 1 )
197         {
198                 cbName = dwNameMax;
199                 lr = RegEnumKeyExW(
200                         hKey, dwIndex, &wszPath[dwLen], &cbName,
201                         NULL, NULL, NULL, &ftLastWrite );
202                 if ( lr == ERROR_NO_MORE_ITEMS )
203                         break;
204                 if ( lr != ERROR_SUCCESS )
205                 {
206                         TRACE("RegEnumKeyEx returns %08lx\n",lr);
207                         hr = E_FAIL;
208                         goto err;
209                 }
210
211                 hr = QUARTZ_CreateDeviceMoniker(
212                         HKEY_CLASSES_ROOT, wszPath, &pMon );
213                 if ( FAILED(hr) )
214                         goto err;
215
216                 hr = QUARTZ_CompList_AddComp(
217                         pMonList, (IUnknown*)pMon, NULL, 0 );
218                 IMoniker_Release( pMon );
219
220                 if ( FAILED(hr) )
221                         goto err;
222
223                 dwIndex ++;
224         }
225
226         /* create an enumerator. */
227         hr = QUARTZ_CreateEnumUnknown(
228                 &IID_IEnumMoniker, (void**)ppobj, pMonList );
229         if ( FAILED(hr) )
230                 goto err;
231
232         hr = S_OK;
233 err:
234         if ( pMonList != NULL )
235                 QUARTZ_CompList_Free( pMonList );
236         RegCloseKey( hKey );
237
238         return hr;
239 }
240
241 static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
242 {
243         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
244         /* IUnknown fields */
245         ICreateDevEnum_fnQueryInterface,
246         ICreateDevEnum_fnAddRef,
247         ICreateDevEnum_fnRelease,
248         /* ICreateDevEnum fields */
249         ICreateDevEnum_fnCreateClassEnumerator,
250 };
251
252 HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
253 {
254         TRACE("(%p)\n",psde);
255         ICOM_VTBL(&psde->createdevenum) = &icreatedevenum;
256
257         return NOERROR;
258 }
259
260 void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde )
261 {
262         TRACE("(%p)\n",psde);
263 }
264
265
266 /***************************************************************************
267  *
268  *      CDeviceMoniker::IMoniker
269  *
270  */
271
272 static HRESULT WINAPI
273 IMoniker_fnQueryInterface(IMoniker* iface,REFIID riid,void** ppobj)
274 {
275         CDeviceMoniker_THIS(iface,moniker);
276
277         TRACE("(%p)->()\n",This);
278
279         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
280 }
281
282 static ULONG WINAPI
283 IMoniker_fnAddRef(IMoniker* iface)
284 {
285         CDeviceMoniker_THIS(iface,moniker);
286
287         TRACE("(%p)->()\n",This);
288
289         return IUnknown_AddRef(This->unk.punkControl);
290 }
291
292 static ULONG WINAPI
293 IMoniker_fnRelease(IMoniker* iface)
294 {
295         CDeviceMoniker_THIS(iface,moniker);
296
297         TRACE("(%p)->()\n",This);
298
299         return IUnknown_Release(This->unk.punkControl);
300 }
301
302 static HRESULT WINAPI IMoniker_fnGetClassID(IMoniker* iface, CLSID *pClassID)
303 {
304         CDeviceMoniker_THIS(iface,moniker);
305
306         TRACE("(%p)->()\n",This);
307
308         if ( pClassID == NULL )
309                 return E_POINTER;
310         memcpy( pClassID, &CLSID_CDeviceMoniker, sizeof(CLSID) );
311
312         return NOERROR;
313 }
314
315 static HRESULT WINAPI IMoniker_fnIsDirty(IMoniker* iface)
316 {
317         CDeviceMoniker_THIS(iface,moniker);
318
319         FIXME("(%p)->() stub!\n",This);
320
321         return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI IMoniker_fnLoad(IMoniker* iface, IStream* pStm)
325 {
326         CDeviceMoniker_THIS(iface,moniker);
327
328         FIXME("(%p)->() stub!\n",This);
329
330         return E_NOTIMPL;
331 }
332
333 static HRESULT WINAPI IMoniker_fnSave(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
334 {
335         CDeviceMoniker_THIS(iface,moniker);
336
337         FIXME("(%p)->() stub!\n",This);
338
339         return E_NOTIMPL;
340 }
341
342 static HRESULT WINAPI IMoniker_fnGetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
343 {
344         CDeviceMoniker_THIS(iface,moniker);
345
346         FIXME("(%p)->() stub!\n",This);
347
348         return E_NOTIMPL;
349 }
350
351 static HRESULT WINAPI IMoniker_fnBindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
352 {
353         CDeviceMoniker_THIS(iface,moniker);
354         HRESULT hr;
355         IPropertyBag*   pPropBag;
356         IPersistPropertyBag*    pPersistPropBag;
357         VARIANT vClsid;
358         CLSID   clsid;
359
360         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
361                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
362         if ( pbc != NULL )
363         {
364                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
365                 return E_FAIL;
366         }
367         if ( pmkToLeft != NULL )
368         {
369                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
370                 return E_FAIL;
371         }
372         if ( ppvResult == NULL )
373                 return E_POINTER;
374
375         hr = QUARTZ_CreateRegPropertyBag(
376                         This->m_hkRoot, This->m_pwszPath, &pPropBag );
377         if ( FAILED(hr) )
378                 return hr;
379
380         vClsid.n1.n2.vt = VT_BSTR;
381         hr = IPropertyBag_Read(
382                         pPropBag, QUARTZ_wszCLSID, &vClsid, NULL );
383         IPropertyBag_Release( pPropBag );
384         if ( FAILED(hr) )
385                 return hr;
386
387         hr = CLSIDFromString( vClsid.n1.n2.n3.bstrVal, &clsid );
388         SysFreeString(vClsid.n1.n2.n3.bstrVal);
389         if ( FAILED(hr) )
390                 return hr;
391
392         hr = CoCreateInstance(
393                 &clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppvResult );
394         if ( FAILED(hr) )
395                 return hr;
396
397         hr = IUnknown_QueryInterface((IUnknown*)*ppvResult,&IID_IPersistPropertyBag,(void**)&pPersistPropBag);
398         if ( hr == E_NOINTERFACE )
399         {
400                 hr = S_OK;
401         }
402         else
403         if ( SUCCEEDED(hr) )
404         {
405                 hr = QUARTZ_CreateRegPropertyBag(
406                                 This->m_hkRoot, This->m_pwszPath, &pPropBag );
407                 if ( SUCCEEDED(hr) )
408                 {
409                         hr = IPersistPropertyBag_Load(pPersistPropBag,pPropBag,NULL);
410                         IPropertyBag_Release( pPropBag );
411                 }
412                 IPersistPropertyBag_Release(pPersistPropBag);
413         }
414
415         if ( FAILED(hr) )
416         {
417                 IUnknown_Release((IUnknown*)*ppvResult);
418                 *ppvResult = NULL;
419         }
420
421         TRACE( "hr = %08lx\n", hr );
422
423         return hr;
424 }
425
426 static HRESULT WINAPI IMoniker_fnBindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
427 {
428         CDeviceMoniker_THIS(iface,moniker);
429         HRESULT hr;
430
431         TRACE("(%p)->(%p,%p,%s,%p)\n",This,
432                 pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
433         if ( pbc != NULL )
434         {
435                 FIXME("IBindCtx* pbc != NULL not implemented.\n");
436                 return E_FAIL;
437         }
438         if ( pmkToLeft != NULL )
439         {
440                 FIXME("IMoniker* pmkToLeft != NULL not implemented.\n");
441                 return E_FAIL;
442         }
443         if ( ppvResult == NULL )
444                 return E_POINTER;
445
446         hr = E_NOINTERFACE;
447         if ( IsEqualGUID(riid,&IID_IUnknown) ||
448                  IsEqualGUID(riid,&IID_IPropertyBag) )
449         {
450                 hr = QUARTZ_CreateRegPropertyBag(
451                         This->m_hkRoot, This->m_pwszPath,
452                         (IPropertyBag**)ppvResult );
453         }
454
455         return hr;
456 }
457
458 static HRESULT WINAPI IMoniker_fnReduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
459 {
460         CDeviceMoniker_THIS(iface,moniker);
461
462         TRACE("(%p)->()\n",This);
463
464         if ( ppmkReduced == NULL )
465                 return E_POINTER;
466
467         *ppmkReduced = iface; IMoniker_AddRef(iface);
468
469         return MK_S_REDUCED_TO_SELF;
470 }
471
472 static HRESULT WINAPI IMoniker_fnComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
473 {
474         CDeviceMoniker_THIS(iface,moniker);
475
476         FIXME("(%p)->() stub!\n",This);
477
478         return E_NOTIMPL;
479 }
480
481 static HRESULT WINAPI IMoniker_fnEnum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
482 {
483         CDeviceMoniker_THIS(iface,moniker);
484
485         TRACE("(%p)->()\n",This);
486
487         if ( ppenumMoniker == NULL )
488                 return E_POINTER;
489
490         *ppenumMoniker = NULL;
491         return NOERROR;
492 }
493
494 static HRESULT WINAPI IMoniker_fnIsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
495 {
496         CDeviceMoniker_THIS(iface,moniker);
497
498         FIXME("(%p)->() stub!\n",This);
499
500         return E_NOTIMPL;
501 }
502
503 static HRESULT WINAPI IMoniker_fnHash(IMoniker* iface,DWORD* pdwHash)
504 {
505         CDeviceMoniker_THIS(iface,moniker);
506
507         FIXME("(%p)->() stub!\n",This);
508
509         return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI IMoniker_fnIsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
513 {
514         CDeviceMoniker_THIS(iface,moniker);
515
516         FIXME("(%p)->() stub!\n",This);
517
518         return E_NOTIMPL;
519 }
520
521 static HRESULT WINAPI IMoniker_fnGetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime)
522 {
523         CDeviceMoniker_THIS(iface,moniker);
524
525         FIXME("(%p)->() stub!\n",This);
526
527         return E_NOTIMPL;
528 }
529
530 static HRESULT WINAPI IMoniker_fnInverse(IMoniker* iface,IMoniker** ppmk)
531 {
532         CDeviceMoniker_THIS(iface,moniker);
533
534         FIXME("(%p)->() stub!\n",This);
535
536         return E_NOTIMPL;
537 }
538
539 static HRESULT WINAPI IMoniker_fnCommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix)
540 {
541         CDeviceMoniker_THIS(iface,moniker);
542
543         FIXME("(%p)->() stub!\n",This);
544
545         return E_NOTIMPL;
546 }
547
548 static HRESULT WINAPI IMoniker_fnRelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
549 {
550         CDeviceMoniker_THIS(iface,moniker);
551
552         FIXME("(%p)->() stub!\n",This);
553
554         return E_NOTIMPL;
555 }
556
557 static HRESULT WINAPI IMoniker_fnGetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
558 {
559         CDeviceMoniker_THIS(iface,moniker);
560
561         FIXME("(%p)->() stub!\n",This);
562
563         return E_NOTIMPL;
564 }
565
566 static HRESULT WINAPI IMoniker_fnParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
567 {
568         CDeviceMoniker_THIS(iface,moniker);
569
570         FIXME("(%p)->() stub!\n",This);
571
572         return E_NOTIMPL;
573 }
574
575 static HRESULT WINAPI IMoniker_fnIsSystemMoniker(IMoniker* iface,DWORD* pdwMksys)
576 {
577         CDeviceMoniker_THIS(iface,moniker);
578
579         TRACE("(%p)->()\n",This);
580         if ( pdwMksys == NULL )
581                 return E_POINTER;
582
583         *pdwMksys = MKSYS_NONE;
584         return S_FALSE;
585 }
586
587
588 static ICOM_VTABLE(IMoniker) imoniker =
589 {
590         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
591         /* IUnknown fields */
592         IMoniker_fnQueryInterface,
593         IMoniker_fnAddRef,
594         IMoniker_fnRelease,
595         /* IPersist fields */
596         IMoniker_fnGetClassID,
597         /* IPersistStream fields */
598         IMoniker_fnIsDirty,
599         IMoniker_fnLoad,
600         IMoniker_fnSave,
601         IMoniker_fnGetSizeMax,
602         /* IMoniker fields */
603         IMoniker_fnBindToObject,
604         IMoniker_fnBindToStorage,
605         IMoniker_fnReduce,
606         IMoniker_fnComposeWith,
607         IMoniker_fnEnum,
608         IMoniker_fnIsEqual,
609         IMoniker_fnHash,
610         IMoniker_fnIsRunning,
611         IMoniker_fnGetTimeOfLastChange,
612         IMoniker_fnInverse,
613         IMoniker_fnCommonPrefixWith,
614         IMoniker_fnRelativePathTo,
615         IMoniker_fnGetDisplayName,
616         IMoniker_fnParseDisplayName,
617         IMoniker_fnIsSystemMoniker,
618 };
619
620
621 static HRESULT CDeviceMoniker_InitIMoniker(
622         CDeviceMoniker* pdm, HKEY hkRoot, LPCWSTR lpKeyPath )
623 {
624         DWORD   dwLen;
625
626         ICOM_VTBL(&pdm->moniker) = &imoniker;
627         pdm->m_hkRoot = hkRoot;
628         pdm->m_pwszPath = NULL;
629
630         dwLen = sizeof(WCHAR)*(lstrlenW(lpKeyPath)+1);
631         pdm->m_pwszPath = (WCHAR*)QUARTZ_AllocMem( dwLen );
632         if ( pdm->m_pwszPath == NULL )
633                 return E_OUTOFMEMORY;
634         memcpy( pdm->m_pwszPath, lpKeyPath, dwLen );
635
636         return NOERROR;
637 }
638
639 static void CDeviceMoniker_UninitIMoniker(
640         CDeviceMoniker* pdm )
641 {
642         if ( pdm->m_pwszPath != NULL )
643                 QUARTZ_FreeMem( pdm->m_pwszPath );
644 }
645
646 /***************************************************************************
647  *
648  *      new/delete for CDeviceMoniker
649  *
650  */
651
652 static void QUARTZ_DestroyDeviceMoniker(IUnknown* punk)
653 {
654         CDeviceMoniker_THIS(punk,unk);
655
656         CDeviceMoniker_UninitIMoniker( This );
657 }
658
659 /* can I use offsetof safely? - FIXME? */
660 static QUARTZ_IFEntry CDeviceMoniker_IFEntries[] =
661 {
662   { &IID_IPersist, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
663   { &IID_IPersistStream, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
664   { &IID_IMoniker, offsetof(CDeviceMoniker,moniker)-offsetof(CDeviceMoniker,unk) },
665 };
666
667 HRESULT QUARTZ_CreateDeviceMoniker(
668         HKEY hkRoot, LPCWSTR lpKeyPath,
669         IMoniker** ppMoniker )
670 {
671         CDeviceMoniker* pdm;
672         HRESULT hr;
673
674         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppMoniker );
675
676         pdm = (CDeviceMoniker*)QUARTZ_AllocObj( sizeof(CDeviceMoniker) );
677         if ( pdm == NULL )
678                 return E_OUTOFMEMORY;
679
680         QUARTZ_IUnkInit( &pdm->unk, NULL );
681         hr = CDeviceMoniker_InitIMoniker( pdm, hkRoot, lpKeyPath );
682         if ( FAILED(hr) )
683         {
684                 QUARTZ_FreeObj( pdm );
685                 return hr;
686         }
687
688         pdm->unk.pEntries = CDeviceMoniker_IFEntries;
689         pdm->unk.dwEntries = sizeof(CDeviceMoniker_IFEntries)/sizeof(CDeviceMoniker_IFEntries[0]);
690         pdm->unk.pOnFinalRelease = &QUARTZ_DestroyDeviceMoniker;
691
692         *ppMoniker = (IMoniker*)(&pdm->moniker);
693
694         return S_OK;
695 }
696
697
698 /***************************************************************************
699  *
700  *      CRegPropertyBag::IPropertyBag
701  *
702  */
703
704 static HRESULT WINAPI
705 IPropertyBag_fnQueryInterface(IPropertyBag* iface,REFIID riid,void** ppobj)
706 {
707         CRegPropertyBag_THIS(iface,propbag);
708
709         TRACE("(%p)->()\n",This);
710
711         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
712 }
713
714 static ULONG WINAPI
715 IPropertyBag_fnAddRef(IPropertyBag* iface)
716 {
717         CRegPropertyBag_THIS(iface,propbag);
718
719         TRACE("(%p)->()\n",This);
720
721         return IUnknown_AddRef(This->unk.punkControl);
722 }
723
724 static ULONG WINAPI
725 IPropertyBag_fnRelease(IPropertyBag* iface)
726 {
727         CRegPropertyBag_THIS(iface,propbag);
728
729         TRACE("(%p)->()\n",This);
730
731         return IUnknown_Release(This->unk.punkControl);
732 }
733
734 static HRESULT WINAPI
735 IPropertyBag_fnRead(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar,IErrorLog* pLog)
736 {
737         CRegPropertyBag_THIS(iface,propbag);
738         HRESULT hr;
739         LONG    lr;
740         DWORD   dwSize;
741         DWORD   dwValueType;
742         DWORD   dwDWordValue;
743         SAFEARRAYBOUND  sab;
744         SAFEARRAY*      pArray;
745
746         TRACE("(%p)->(%s,%p,%p)\n",This,
747                 debugstr_w(lpszPropName),pVar,pLog);
748
749         if ( lpszPropName == NULL || pVar == NULL )
750                 return E_POINTER;
751
752         dwSize = 0;
753         lr = RegQueryValueExW(
754                 This->m_hKey, lpszPropName, NULL,
755                 &dwValueType, NULL, &dwSize );
756         if ( lr != ERROR_SUCCESS )
757         {
758                 WARN( "RegQueryValueExW failed.\n" );
759                 return E_INVALIDARG;
760         }
761
762         switch ( dwValueType )
763         {
764         case REG_SZ:
765                 TRACE( "REG_SZ / length = %lu\n", dwSize );
766                 if ( pVar->n1.n2.vt == VT_EMPTY )
767                         pVar->n1.n2.vt = VT_BSTR;
768                 if ( pVar->n1.n2.vt != VT_BSTR )
769                 {
770                         FIXME( "type of VARIANT is not BSTR.\n" );
771                         return E_FAIL;
772                 }
773
774                 pVar->n1.n2.n3.bstrVal = SysAllocStringByteLen(
775                         NULL, dwSize );
776                 if ( pVar->n1.n2.n3.bstrVal == NULL )
777                 {
778                         WARN( "out of memory.\n" );
779                         return E_OUTOFMEMORY;
780                 }
781                 lr = RegQueryValueExW(
782                         This->m_hKey, lpszPropName, NULL,
783                         &dwValueType,
784                         (BYTE*)pVar->n1.n2.n3.bstrVal, &dwSize );
785                 if ( lr != ERROR_SUCCESS )
786                 {
787                         WARN( "failed to query value\n" );
788                         SysFreeString(pVar->n1.n2.n3.bstrVal);
789                         return E_FAIL;
790                 }
791                 TRACE( "value is BSTR; %s\n", debugstr_w(pVar->n1.n2.n3.bstrVal) );
792                 break;
793         case REG_BINARY:
794                 TRACE( "REG_BINARY / length = %lu\n", dwSize );
795                 if ( pVar->n1.n2.vt == VT_EMPTY )
796                         pVar->n1.n2.vt = VT_ARRAY|VT_UI1;
797                 if ( pVar->n1.n2.vt != (VT_ARRAY|VT_UI1) )
798                 {
799                         FIXME( "type of VARIANT is not VT_ARRAY|VT_UI1.\n" );
800                         return E_FAIL;
801                 }
802                 sab.lLbound = 0;
803                 sab.cElements = dwSize;
804                 pArray = SafeArrayCreate( VT_UI1, 1, &sab );
805                 if ( pArray == NULL )
806                         return E_OUTOFMEMORY;
807                 hr = SafeArrayLock( pArray );
808                 if ( FAILED(hr) )
809                 {
810                         WARN( "safe array can't be locked\n" );
811                         SafeArrayDestroy( pArray );
812                         return hr;
813                 }
814                 lr = RegQueryValueExW(
815                         This->m_hKey, lpszPropName, NULL,
816                         &dwValueType,
817                         (BYTE*)pArray->pvData, &dwSize );
818                 SafeArrayUnlock( pArray );
819                 if ( lr != ERROR_SUCCESS )
820                 {
821                         WARN( "failed to query value\n" );
822                         SafeArrayDestroy( pArray );
823                         return E_FAIL;
824                 }
825                 pVar->n1.n2.n3.parray = pArray;
826                 TRACE( "value is SAFEARRAY - array of BYTE; \n" );
827                 break;
828         case REG_DWORD:
829                 TRACE( "REG_DWORD / length = %lu\n", dwSize );
830                 if ( dwSize != sizeof(DWORD) )
831                 {
832                         WARN( "The length of REG_DWORD value is not sizeof(DWORD).\n" );
833                         return E_FAIL;
834                 }
835                 if ( pVar->n1.n2.vt == VT_EMPTY )
836                         pVar->n1.n2.vt = VT_I4;
837                 if ( pVar->n1.n2.vt != VT_I4 )
838                 {
839                         FIXME( "type of VARIANT is not VT_I4.\n" );
840                         return E_FAIL;
841                 }
842                 lr = RegQueryValueExW(
843                         This->m_hKey, lpszPropName, NULL,
844                         &dwValueType,
845                         (BYTE*)(&dwDWordValue), &dwSize );
846                 if ( lr != ERROR_SUCCESS )
847                 {
848                         WARN( "failed to query value\n" );
849                         return E_FAIL;
850                 }
851                 pVar->n1.n2.n3.lVal = dwDWordValue;
852                 TRACE( "value is DWORD; %08lx\n", dwDWordValue );
853                 break;
854         default:
855                 FIXME("(%p)->(%s,%p,%p) - unsupported value type.\n",This,
856                         debugstr_w(lpszPropName),pVar,pLog);
857                 return E_FAIL;
858         }
859
860         TRACE( "returned successfully.\n" );
861         return NOERROR;
862 }
863
864 static HRESULT WINAPI
865 IPropertyBag_fnWrite(IPropertyBag* iface,LPCOLESTR lpszPropName,VARIANT* pVar)
866 {
867         CRegPropertyBag_THIS(iface,propbag);
868         HRESULT hr;
869         LONG    lr;
870         DWORD   dwDWordValue;
871         SAFEARRAY*      pArray;
872
873         TRACE("(%p)->(%s,%p)\n",This,
874                 debugstr_w(lpszPropName),pVar);
875
876         if ( lpszPropName == NULL || pVar == NULL )
877                 return E_POINTER;
878
879         switch ( pVar->n1.n2.vt )
880         {
881         case VT_I4: /* REG_DWORD */
882                 dwDWordValue = pVar->n1.n2.n3.lVal;
883                 lr = RegSetValueExW(
884                         This->m_hKey, lpszPropName, 0,
885                         REG_DWORD,
886                         (const BYTE*)(&dwDWordValue), sizeof(DWORD) );
887                 if ( lr != ERROR_SUCCESS )
888                 {
889                         WARN( "failed to set value\n" );
890                         return E_FAIL;
891                 }
892                 break;
893         case VT_BSTR: /* REG_SZ */
894                 lr = RegSetValueExW(
895                         This->m_hKey, lpszPropName, 0,
896                         REG_SZ,
897                         (const BYTE*)(pVar->n1.n2.n3.bstrVal),
898                         SysStringByteLen( pVar->n1.n2.n3.bstrVal ) );
899                 if ( lr != ERROR_SUCCESS )
900                 {
901                         WARN( "failed to set value\n" );
902                         return E_FAIL;
903                 }
904                 break;
905         case (VT_ARRAY|VT_UI1): /* REG_BINARY */
906                 pArray = pVar->n1.n2.n3.parray;
907                 if ( pArray->cDims != 1 || pArray->cbElements != 1 ||
908                          pArray->rgsabound[0].lLbound != 0 )
909                 {
910                         WARN( "invalid array\n" );
911                         return E_INVALIDARG;
912                 }
913                 hr = SafeArrayLock( pArray );
914                 if ( FAILED(hr) )
915                 {
916                         WARN( "safe array can't be locked\n" );
917                         return hr;
918                 }
919                 lr = RegSetValueExW(
920                         This->m_hKey, lpszPropName, 0,
921                         REG_BINARY,
922                         (const BYTE*)pArray->pvData,
923                         pArray->rgsabound[0].cElements );
924                 SafeArrayUnlock( pArray );
925                 if ( lr != ERROR_SUCCESS )
926                 {
927                         WARN( "failed to set value\n" );
928                         return E_FAIL;
929                 }
930                 break;
931         default:
932                 FIXME("(%p)->(%s,%p) invalid/unsupported VARIANT type %04x\n",This,
933                         debugstr_w(lpszPropName),pVar,pVar->n1.n2.vt);
934                 return E_INVALIDARG;
935         }
936
937         TRACE( "returned successfully.\n" );
938         return NOERROR;
939 }
940
941
942
943
944 static ICOM_VTABLE(IPropertyBag) ipropbag =
945 {
946         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
947         /* IUnknown fields */
948         IPropertyBag_fnQueryInterface,
949         IPropertyBag_fnAddRef,
950         IPropertyBag_fnRelease,
951         /* IPropertyBag fields */
952         IPropertyBag_fnRead,
953         IPropertyBag_fnWrite,
954 };
955
956 static HRESULT CRegPropertyBag_InitIPropertyBag(
957         CRegPropertyBag* prpb, HKEY hkRoot, LPCWSTR lpKeyPath )
958 {
959         WCHAR   wszREG_SZ[ NUMELEMS(QUARTZ_wszREG_SZ) ];
960         DWORD   dwDisp;
961
962         ICOM_VTBL(&prpb->propbag) = &ipropbag;
963
964         memcpy(wszREG_SZ,QUARTZ_wszREG_SZ,sizeof(QUARTZ_wszREG_SZ) );
965
966         if ( RegCreateKeyExW(
967                         hkRoot, lpKeyPath, 0, wszREG_SZ,
968                         REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
969                         &prpb->m_hKey, &dwDisp ) != ERROR_SUCCESS )
970                 return E_FAIL;
971
972         return NOERROR;
973 }
974
975 static void CRegPropertyBag_UninitIPropertyBag(
976         CRegPropertyBag* prpb )
977 {
978         RegCloseKey( prpb->m_hKey );
979 }
980
981
982 /***************************************************************************
983  *
984  *      new/delete for CRegPropertyBag
985  *
986  */
987
988 static void QUARTZ_DestroyRegPropertyBag(IUnknown* punk)
989 {
990         CRegPropertyBag_THIS(punk,unk);
991
992         CRegPropertyBag_UninitIPropertyBag(This);
993 }
994
995
996 /* can I use offsetof safely? - FIXME? */
997 static QUARTZ_IFEntry CRegPropertyBag_IFEntries[] =
998 {
999   { &IID_IPropertyBag, offsetof(CRegPropertyBag,propbag)-offsetof(CRegPropertyBag,unk) },
1000 };
1001
1002 HRESULT QUARTZ_CreateRegPropertyBag(
1003         HKEY hkRoot, LPCWSTR lpKeyPath,
1004         IPropertyBag** ppPropBag )
1005 {
1006         CRegPropertyBag*        prpb;
1007         HRESULT hr;
1008
1009         TRACE("(%08x,%s,%p)\n",hkRoot,debugstr_w(lpKeyPath),ppPropBag );
1010
1011         prpb = (CRegPropertyBag*)QUARTZ_AllocObj( sizeof(CRegPropertyBag) );
1012         if ( prpb == NULL )
1013                 return E_OUTOFMEMORY;
1014
1015         QUARTZ_IUnkInit( &prpb->unk, NULL );
1016         hr = CRegPropertyBag_InitIPropertyBag( prpb, hkRoot, lpKeyPath );
1017         if ( FAILED(hr) )
1018         {
1019                 QUARTZ_FreeObj( prpb );
1020                 return hr;
1021         }
1022
1023         prpb->unk.pEntries = CRegPropertyBag_IFEntries;
1024         prpb->unk.dwEntries = sizeof(CRegPropertyBag_IFEntries)/sizeof(CRegPropertyBag_IFEntries[0]);
1025         prpb->unk.pOnFinalRelease = &QUARTZ_DestroyRegPropertyBag;
1026
1027         *ppPropBag = (IPropertyBag*)(&prpb->propbag);
1028
1029         return S_OK;
1030 }
1031
1032 /***************************************************************************
1033  *
1034  *      Helper for registering filters.
1035  *
1036  */
1037
1038 HRESULT QUARTZ_GetFilterRegPath(
1039         WCHAR** ppwszPath,      /* [OUT] path from HKEY_CLASSES_ROOT */
1040         const CLSID* pguidFilterCategory,       /* [IN] Category */
1041         const CLSID* pclsid,    /* [IN] CLSID of this filter */
1042         LPCWSTR lpInstance )    /* [IN] instance */
1043 {
1044         HRESULT hr;
1045         WCHAR   szKey[ 1024 ];
1046         WCHAR   szFilterPath[ 512 ];
1047         WCHAR   szCLSID[ 256 ];
1048         int     buflen;
1049
1050         TRACE("(%p,%s,%s,%s)\n",ppwszPath,debugstr_guid(pguidFilterCategory),debugstr_guid(pclsid),debugstr_w(lpInstance) );
1051
1052         *ppwszPath = NULL;
1053
1054         QUARTZ_GUIDtoString( szCLSID, pclsid );
1055         lstrcpyW( szFilterPath, QUARTZ_wszInstance );
1056         QUARTZ_CatPathSepW( szFilterPath );
1057         if ( lpInstance != NULL )
1058         {
1059                 if ( lstrlenW(lpInstance) >= 256 )
1060                         return E_INVALIDARG;
1061                 lstrcatW( szFilterPath, lpInstance );
1062         }
1063         else
1064         {
1065                 lstrcatW( szFilterPath, szCLSID );
1066         }
1067
1068         hr = QUARTZ_CreateCLSIDPath(
1069                 szKey, NUMELEMS(szKey),
1070                 pguidFilterCategory, szFilterPath );
1071         if ( FAILED(hr) )
1072                 return hr;
1073
1074         buflen = sizeof(WCHAR)*(lstrlenW(szKey)+1);
1075         *ppwszPath = QUARTZ_AllocMem( buflen );
1076         if ( *ppwszPath == NULL )
1077                 return E_OUTOFMEMORY;
1078         memcpy( *ppwszPath, szKey, buflen );
1079         return S_OK;
1080 }
1081
1082 HRESULT QUARTZ_RegisterFilterToMoniker(
1083         IMoniker* pMoniker,     /* [IN] Moniker */
1084         const CLSID* pclsid,    /* [IN] CLSID of this filter */
1085         LPCWSTR lpFriendlyName, /* [IN] friendly name */
1086         const BYTE* pbFilterData,       /* [IN] filter data */
1087         DWORD cbFilterData )    /* [IN] size of the filter data */
1088 {
1089         IPropertyBag*   pPropBag = NULL;
1090         WCHAR   wszClsid[128];
1091         VARIANT var;
1092         HRESULT hr;
1093         SAFEARRAYBOUND  sab;
1094         SAFEARRAY*      pArray = NULL;
1095
1096         TRACE("(%p,%s,%s,%p,%08lu)\n",pMoniker,debugstr_guid(pclsid),debugstr_w(lpFriendlyName),pbFilterData,cbFilterData);
1097
1098         hr = IMoniker_BindToStorage(pMoniker,NULL,NULL,&IID_IPropertyBag,(void**)&pPropBag);
1099         if ( FAILED(hr) )
1100                 goto err;
1101         QUARTZ_GUIDtoString( wszClsid, pclsid );
1102         var.n1.n2.vt = VT_BSTR;
1103         var.n1.n2.n3.bstrVal = SysAllocString(wszClsid);
1104         if ( var.n1.n2.n3.bstrVal == NULL )
1105         {
1106                 hr = E_OUTOFMEMORY;
1107                 goto err;
1108         }
1109         hr = IPropertyBag_Write(pPropBag,QUARTZ_wszCLSID,&var);
1110         SysFreeString(var.n1.n2.n3.bstrVal);
1111         if ( FAILED(hr) )
1112                 goto err;
1113
1114         var.n1.n2.vt = VT_BSTR;
1115         var.n1.n2.n3.bstrVal = SysAllocString(lpFriendlyName);
1116         if ( var.n1.n2.n3.bstrVal == NULL )
1117         {
1118                 hr = E_OUTOFMEMORY;
1119                 goto err;
1120         }
1121         hr = IPropertyBag_Write(pPropBag,QUARTZ_wszFriendlyName,&var);
1122         SysFreeString(var.n1.n2.n3.bstrVal);
1123         if ( FAILED(hr) )
1124                 goto err;
1125
1126         if ( pbFilterData != NULL )
1127         {
1128                 var.n1.n2.vt = VT_ARRAY|VT_UI1;
1129                 sab.lLbound = 0;
1130                 sab.cElements = cbFilterData;
1131                 pArray = SafeArrayCreate( VT_UI1, 1, &sab );
1132                 if ( pArray == NULL )
1133                 {
1134                         hr = E_OUTOFMEMORY;
1135                         goto err;
1136                 }
1137                 hr = SafeArrayLock( pArray );
1138                 if ( FAILED(hr) )
1139                         goto err;
1140                 var.n1.n2.n3.parray = pArray;
1141                 memcpy( pArray->pvData, pbFilterData, cbFilterData );
1142                 hr = IPropertyBag_Write(pPropBag,QUARTZ_wszFilterData,&var);
1143                 SafeArrayUnlock( pArray );
1144                 if ( FAILED(hr) )
1145                         goto err;
1146         }
1147
1148         hr = NOERROR;
1149 err:
1150         if ( pArray != NULL )
1151                 SafeArrayDestroy( pArray );
1152         if ( pPropBag != NULL )
1153                 IPropertyBag_Release(pPropBag);
1154
1155         return hr;
1156 }
1157
1158 HRESULT QUARTZ_RegDeleteKey( HKEY hkRoot, LPCWSTR lpKeyPath )
1159 {
1160         LONG    lr;
1161         HRESULT hr;
1162         HKEY    hKey;
1163         DWORD   dwIndex;
1164         DWORD   cbName;
1165         FILETIME        ftLastWrite;
1166         DWORD   dwType;
1167         WCHAR   wszPath[ 512 ];
1168
1169         TRACE("(%08x,%s)\n",hkRoot,debugstr_w(lpKeyPath));
1170
1171         lr = RegOpenKeyExW( hkRoot, lpKeyPath, 0, KEY_ALL_ACCESS, &hKey );
1172         if ( lr == ERROR_SUCCESS )
1173         {
1174                 dwIndex = 0;
1175                 while ( 1 )
1176                 {
1177                         cbName = NUMELEMS(wszPath);
1178                         lr = RegEnumKeyExW(
1179                                 hKey, dwIndex, wszPath, &cbName,
1180                                 NULL, NULL, NULL, &ftLastWrite );
1181                         if ( lr != ERROR_SUCCESS )
1182                                 break;
1183                         hr = QUARTZ_RegDeleteKey( hKey, wszPath );
1184                         if ( FAILED(hr) )
1185                                 return hr;
1186                         if ( hr != S_OK )
1187                                 dwIndex ++;
1188                 }
1189                 while ( 1 )
1190                 {
1191                         cbName = NUMELEMS(wszPath);
1192                         lr = RegEnumValueW(
1193                                 hKey, 0, wszPath, &cbName, 0,
1194                                 &dwType, NULL, 0 );
1195                         if ( lr != ERROR_SUCCESS )
1196                                 break;
1197                         lr = RegDeleteValueW( hKey, wszPath );
1198                         if ( lr != ERROR_SUCCESS )
1199                         {
1200                                 WARN("RegDeleteValueW - %08lx\n",lr);
1201                                 return E_FAIL;
1202                         }
1203                 }
1204         }
1205         RegCloseKey( hKey );
1206
1207         lr = RegDeleteKeyW( hkRoot, lpKeyPath );
1208         WARN("RegDeleteKeyW - %08lx\n",lr);
1209         if ( lr != ERROR_SUCCESS && lr != ERROR_FILE_NOT_FOUND )
1210                 return S_FALSE;
1211         return S_OK;
1212 }
1213
1214 static
1215 HRESULT QUARTZ_GetPropertyFromMoniker(
1216         IMoniker* pMoniker,     /* [IN] Moniker */
1217         LPCOLESTR lpszPropName, /* [IN] Property */
1218         VARIANT* pVar ) /* [OUT] */
1219 {
1220         IPropertyBag*   pPropBag = NULL;
1221         HRESULT hr;
1222
1223         TRACE("(%p,%s,%p)\n",pMoniker,debugstr_w(lpszPropName),pVar);
1224
1225         hr = IMoniker_BindToStorage(pMoniker,NULL,NULL,&IID_IPropertyBag,(void**)&pPropBag);
1226         if ( FAILED(hr) )
1227                 return hr;
1228         hr = IPropertyBag_Read(pPropBag,lpszPropName,pVar,NULL);
1229         IPropertyBag_Release(pPropBag);
1230
1231         return hr;
1232 }
1233
1234 HRESULT QUARTZ_GetCLSIDFromMoniker(
1235         IMoniker* pMoniker,     /* [IN] Moniker */
1236         CLSID* pclsid ) /* [OUT] */
1237 {
1238         VARIANT var;
1239         HRESULT hr;
1240
1241         var.n1.n2.vt = VT_BSTR;
1242         hr = QUARTZ_GetPropertyFromMoniker(
1243                 pMoniker, QUARTZ_wszCLSID, &var );
1244         if ( hr == S_OK )
1245         {
1246                 hr = CLSIDFromString(var.n1.n2.n3.bstrVal,pclsid);
1247                 SysFreeString(var.n1.n2.n3.bstrVal);
1248         }
1249
1250         return hr;
1251 }
1252
1253 HRESULT QUARTZ_GetMeritFromMoniker(
1254         IMoniker* pMoniker,     /* [IN] Moniker */
1255         DWORD* pdwMerit )       /* [OUT] */
1256 {
1257         VARIANT var;
1258         HRESULT hr;
1259
1260         var.n1.n2.vt = VT_I4;
1261         hr = QUARTZ_GetPropertyFromMoniker(
1262                 pMoniker, QUARTZ_wszMerit, &var );
1263         if ( hr == S_OK )
1264                 *pdwMerit = var.n1.n2.n3.lVal;
1265
1266         return hr;
1267 }
1268
1269 HRESULT QUARTZ_GetFilterDataFromMoniker(
1270         IMoniker* pMoniker,     /* [IN] Moniker */
1271         BYTE** ppbFilterData,   /* [OUT] */
1272         DWORD* pcbFilterData )  /* [OUT] */
1273 {
1274         VARIANT var;
1275         HRESULT hr;
1276         SAFEARRAY*      pArray;
1277
1278         var.n1.n2.vt = VT_ARRAY|VT_UI1;
1279         hr = QUARTZ_GetPropertyFromMoniker(
1280                 pMoniker, QUARTZ_wszFilterData, &var );
1281         if ( hr == S_OK )
1282         {
1283                 pArray = var.n1.n2.n3.parray;
1284                 hr = SafeArrayLock( pArray );
1285                 if ( SUCCEEDED(hr) )
1286                 {
1287                         *pcbFilterData = pArray->rgsabound[0].cElements - pArray->rgsabound[0].lLbound;
1288                         *ppbFilterData = (BYTE*)QUARTZ_AllocMem( *pcbFilterData );
1289                         if ( *ppbFilterData == NULL )
1290                                 hr = E_OUTOFMEMORY;
1291                         else
1292                                 memcpy( *ppbFilterData, pArray->pvData, *pcbFilterData );
1293
1294                         SafeArrayUnlock( pArray );
1295                 }
1296                 SafeArrayDestroy( pArray );
1297         }
1298
1299         return hr;
1300 }
1301