When including 'wine/port.h', include it first.
[wine] / dlls / quartz / devenum.c
1 /*
2  * Implementation of CLSID_SystemDeviceEnum.
3  *
4  * FIXME - not tested enough.
5  *
6  * hidenori@a2.ctktv.ne.jp
7  */
8
9 #include "config.h"
10
11 #include "windef.h"
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "winreg.h"
16 #include "winerror.h"
17 #include "strmif.h"
18
19 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(quartz);
21
22 #include "quartz_private.h"
23 #include "devenum.h"
24 #include "regsvr.h"
25 #include "enumunk.h"
26 #include "complist.h"
27 #include "devmon.h"
28
29
30 /***************************************************************************
31  *
32  *      new/delete for CLSID_SystemDeviceEnum
33  *
34  */
35
36 /* can I use offsetof safely? - FIXME? */
37 static QUARTZ_IFEntry IFEntries[] =
38 {
39   { &IID_ICreateDevEnum, offsetof(CSysDevEnum,createdevenum)-offsetof(CSysDevEnum,unk) },
40 };
41
42
43 static void QUARTZ_DestroySystemDeviceEnum(IUnknown* punk)
44 {
45         CSysDevEnum_THIS(punk,unk);
46
47         CSysDevEnum_UninitICreateDevEnum( This );
48 }
49
50 HRESULT QUARTZ_CreateSystemDeviceEnum(IUnknown* punkOuter,void** ppobj)
51 {
52         CSysDevEnum*    psde;
53         HRESULT hr;
54
55         TRACE("(%p,%p)\n",punkOuter,ppobj);
56
57         psde = (CSysDevEnum*)QUARTZ_AllocObj( sizeof(CSysDevEnum) );
58         if ( psde == NULL )
59                 return E_OUTOFMEMORY;
60
61         QUARTZ_IUnkInit( &psde->unk, punkOuter );
62
63         hr = CSysDevEnum_InitICreateDevEnum( psde );
64         if ( FAILED(hr) )
65         {
66                 QUARTZ_FreeObj( psde );
67                 return hr;
68         }
69
70         psde->unk.pEntries = IFEntries;
71         psde->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
72         psde->unk.pOnFinalRelease = QUARTZ_DestroySystemDeviceEnum;
73
74         *ppobj = (void*)(&psde->unk);
75
76         return S_OK;
77 }
78
79
80 /***************************************************************************
81  *
82  *      CSysDevEnum::ICreateDevEnum
83  *
84  */
85
86
87 static HRESULT WINAPI
88 ICreateDevEnum_fnQueryInterface(ICreateDevEnum* iface,REFIID riid,void** ppobj)
89 {
90         CSysDevEnum_THIS(iface,createdevenum);
91
92         TRACE("(%p)->()\n",This);
93
94         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
95 }
96
97 static ULONG WINAPI
98 ICreateDevEnum_fnAddRef(ICreateDevEnum* iface)
99 {
100         CSysDevEnum_THIS(iface,createdevenum);
101
102         TRACE("(%p)->()\n",This);
103
104         return IUnknown_AddRef(This->unk.punkControl);
105 }
106
107 static ULONG WINAPI
108 ICreateDevEnum_fnRelease(ICreateDevEnum* iface)
109 {
110         CSysDevEnum_THIS(iface,createdevenum);
111
112         TRACE("(%p)->()\n",This);
113
114         return IUnknown_Release(This->unk.punkControl);
115 }
116
117 static HRESULT WINAPI
118 ICreateDevEnum_fnCreateClassEnumerator(ICreateDevEnum* iface,REFCLSID rclsidDeviceClass,IEnumMoniker** ppobj, DWORD dwFlags)
119 {
120         CSysDevEnum_THIS(iface,createdevenum);
121         HRESULT hr;
122         HKEY    hKey;
123         QUARTZ_CompList*        pMonList;
124         IMoniker*       pMon;
125         DWORD   dwIndex;
126         LONG    lr;
127         WCHAR   wszPath[ 1024 ];
128         DWORD   dwLen;
129         DWORD   dwNameMax;
130         DWORD   cbName;
131         FILETIME        ftLastWrite;
132
133         TRACE("(%p)->(%s,%p,%08lx)\n",This,
134                 debugstr_guid(rclsidDeviceClass),ppobj,dwFlags);
135         if ( dwFlags != 0 )
136         {
137                 FIXME("unknown flags %08lx\n",dwFlags);
138                 return E_NOTIMPL;
139         }
140
141         if ( ppobj == NULL )
142                 return E_POINTER;
143         *ppobj = NULL;
144
145         hr = QUARTZ_CreateCLSIDPath(
146                 wszPath, sizeof(wszPath)/sizeof(wszPath[0]),
147                 rclsidDeviceClass, QUARTZ_wszInstance );
148         if ( FAILED(hr) )
149                 return hr;
150
151         if ( RegOpenKeyExW( HKEY_CLASSES_ROOT, wszPath,
152                 0, KEY_READ, &hKey ) != ERROR_SUCCESS )
153                 return E_FAIL;
154
155         dwLen = lstrlenW(wszPath);
156         wszPath[dwLen++] = '\\'; wszPath[dwLen] = 0;
157         dwNameMax = sizeof(wszPath)/sizeof(wszPath[0]) - dwLen - 8;
158
159         pMonList = QUARTZ_CompList_Alloc();
160         if ( pMonList == NULL )
161         {
162                 hr = E_OUTOFMEMORY;
163                 goto err;
164         }
165
166         /* enumerate all subkeys. */
167         dwIndex = 0;
168         while ( 1 )
169         {
170                 cbName = dwNameMax;
171                 lr = RegEnumKeyExW(
172                         hKey, dwIndex, &wszPath[dwLen], &cbName,
173                         NULL, NULL, NULL, &ftLastWrite );
174                 if ( lr == ERROR_NO_MORE_ITEMS )
175                         break;
176                 if ( lr != ERROR_SUCCESS )
177                 {
178                         hr = E_FAIL;
179                         goto err;
180                 }
181
182                 hr = QUARTZ_CreateDeviceMoniker(
183                         HKEY_CLASSES_ROOT, wszPath, &pMon );
184                 if ( FAILED(hr) )
185                         goto err;
186
187                 hr = QUARTZ_CompList_AddComp(
188                         pMonList, (IUnknown*)pMon, NULL, 0 );
189                 IMoniker_Release( pMon );
190
191                 if ( FAILED(hr) )
192                         goto err;
193
194                 dwIndex ++;
195         }
196
197         /* create an enumerator. */
198         hr = QUARTZ_CreateEnumUnknown(
199                 &IID_IEnumMoniker, (void**)ppobj, pMonList );
200         if ( FAILED(hr) )
201                 goto err;
202
203         hr = S_OK;
204 err:
205         if ( pMonList != NULL )
206                 QUARTZ_CompList_Free( pMonList );
207         RegCloseKey( hKey );
208
209         return hr;
210 }
211
212 static ICOM_VTABLE(ICreateDevEnum) icreatedevenum =
213 {
214         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
215         /* IUnknown fields */
216         ICreateDevEnum_fnQueryInterface,
217         ICreateDevEnum_fnAddRef,
218         ICreateDevEnum_fnRelease,
219         /* ICreateDevEnum fields */
220         ICreateDevEnum_fnCreateClassEnumerator,
221 };
222
223 HRESULT CSysDevEnum_InitICreateDevEnum( CSysDevEnum* psde )
224 {
225         TRACE("(%p)\n",psde);
226         ICOM_VTBL(&psde->createdevenum) = &icreatedevenum;
227
228         return NOERROR;
229 }
230
231 void CSysDevEnum_UninitICreateDevEnum( CSysDevEnum* psde )
232 {
233         TRACE("(%p)\n",psde);
234 }