dxdiagn: Add code that populates the DxDiag_DirectShowFilters container.
[wine] / dlls / dxdiagn / provider.c
1 /* 
2  * IDxDiagProvider Implementation
3  * 
4  * Copyright 2004-2005 Raphael Junqueira
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
22 #include "config.h"
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "dxdiag_private.h"
28 #include "wine/unicode.h"
29 #include "winver.h"
30 #include "objidl.h"
31 #include "dshow.h"
32 #include "vfw.h"
33 #include "mmddk.h"
34 #include "ddraw.h"
35 #include "d3d9.h"
36 #include "strmif.h"
37 #include "initguid.h"
38 #include "fil_data.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
43
44 static HRESULT DXDiag_InitRootDXDiagContainer(IDxDiagContainer* pRootCont, IDxDiagProvider *pProv);
45
46 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root);
47 static void free_information_tree(IDxDiagContainerImpl_Container *node);
48
49 /* IDxDiagProvider IUnknown parts follow: */
50 static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(PDXDIAGPROVIDER iface, REFIID riid, LPVOID *ppobj)
51 {
52     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
53
54     if (!ppobj) return E_INVALIDARG;
55
56     if (IsEqualGUID(riid, &IID_IUnknown)
57         || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
58         IUnknown_AddRef(iface);
59         *ppobj = This;
60         return S_OK;
61     }
62
63     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
64     *ppobj = NULL;
65     return E_NOINTERFACE;
66 }
67
68 static ULONG WINAPI IDxDiagProviderImpl_AddRef(PDXDIAGPROVIDER iface) {
69     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
70     ULONG refCount = InterlockedIncrement(&This->ref);
71
72     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
73
74     DXDIAGN_LockModule();
75
76     return refCount;
77 }
78
79 static ULONG WINAPI IDxDiagProviderImpl_Release(PDXDIAGPROVIDER iface) {
80     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
81     ULONG refCount = InterlockedDecrement(&This->ref);
82
83     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
84
85     if (!refCount) {
86         free_information_tree(This->info_root);
87         HeapFree(GetProcessHeap(), 0, This);
88     }
89
90     DXDIAGN_UnlockModule();
91     
92     return refCount;
93 }
94
95 /* IDxDiagProvider Interface follow: */
96 static HRESULT WINAPI IDxDiagProviderImpl_Initialize(PDXDIAGPROVIDER iface, DXDIAG_INIT_PARAMS* pParams) {
97     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
98     HRESULT hr;
99
100     TRACE("(%p,%p)\n", iface, pParams);
101
102     if (NULL == pParams) {
103       return E_POINTER;
104     }
105     if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS) ||
106         pParams->dwDxDiagHeaderVersion != DXDIAG_DX9_SDK_VERSION) {
107       return E_INVALIDARG;
108     }
109
110     if (!This->info_root)
111     {
112         hr = build_information_tree(&This->info_root);
113         if (FAILED(hr))
114             return hr;
115     }
116
117     This->init = TRUE;
118     memcpy(&This->params, pParams, pParams->dwSize);
119     return S_OK;
120 }
121
122 static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(PDXDIAGPROVIDER iface, IDxDiagContainer** ppInstance) {
123   HRESULT hr;
124   IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
125   IDxDiagContainer *root;
126
127   TRACE("(%p,%p)\n", iface, ppInstance);
128
129   if (FALSE == This->init) {
130     return CO_E_NOTINITIALIZED;
131   }
132
133   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, (IDxDiagProvider *)This, (void **)&root);
134   if (FAILED(hr)) {
135     return hr;
136   }
137
138   DXDiag_InitRootDXDiagContainer(root, (IDxDiagProvider *)This);
139
140   return IDxDiagContainerImpl_QueryInterface(root, &IID_IDxDiagContainer, (void **)ppInstance);
141 }
142
143 static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
144 {
145     IDxDiagProviderImpl_QueryInterface,
146     IDxDiagProviderImpl_AddRef,
147     IDxDiagProviderImpl_Release,
148     IDxDiagProviderImpl_Initialize,
149     IDxDiagProviderImpl_GetRootContainer
150 };
151
152 HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
153   IDxDiagProviderImpl* provider;
154
155   TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
156
157   *ppobj = NULL;
158   if (punkOuter) return CLASS_E_NOAGGREGATION;
159
160   provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
161   if (NULL == provider) return E_OUTOFMEMORY;
162   provider->lpVtbl = &DxDiagProvider_Vtbl;
163   provider->ref = 0; /* will be inited with QueryInterface */
164   return IDxDiagProviderImpl_QueryInterface ((PDXDIAGPROVIDER)provider, riid, ppobj);
165
166
167 static inline HRESULT add_prop_str( IDxDiagContainer* cont, LPCWSTR prop, LPCWSTR str )
168 {
169     HRESULT hr;
170     VARIANT var;
171
172     V_VT( &var ) = VT_BSTR;
173     V_BSTR( &var ) = SysAllocString( str );
174     hr = IDxDiagContainerImpl_AddProp( cont, prop, &var );
175     VariantClear( &var );
176
177     return hr;
178 }
179
180 static inline HRESULT add_prop_ui4( IDxDiagContainer* cont, LPCWSTR prop, DWORD data )
181 {
182     VARIANT var;
183
184     V_VT( &var ) = VT_UI4;
185     V_UI4( &var ) = data;
186     return IDxDiagContainerImpl_AddProp( cont, prop, &var );
187 }
188
189 static inline HRESULT add_prop_bool( IDxDiagContainer* cont, LPCWSTR prop, BOOL data )
190 {
191     VARIANT var;
192
193     V_VT( &var ) = VT_BOOL;
194     V_BOOL( &var ) = data;
195     return IDxDiagContainerImpl_AddProp( cont, prop, &var );
196 }
197
198 static inline HRESULT add_prop_ull_as_str( IDxDiagContainer* cont, LPCWSTR prop, ULONGLONG data )
199 {
200     HRESULT hr;
201     VARIANT var;
202
203     V_VT( &var ) = VT_UI8;
204     V_UI8( &var ) = data;
205     VariantChangeType( &var, &var, 0, VT_BSTR );
206     hr = IDxDiagContainerImpl_AddProp( cont, prop, &var );
207     VariantClear( &var );
208
209     return hr;
210 }
211
212 static void get_display_device_id(WCHAR *szIdentifierBuffer)
213 {
214     static const WCHAR szNA[] = {'n','/','a',0};
215
216     HRESULT hr = E_FAIL;
217
218     HMODULE                 d3d9_handle;
219     IDirect3D9             *(WINAPI *pDirect3DCreate9)(UINT) = NULL;
220     IDirect3D9             *pD3d = NULL;
221     D3DADAPTER_IDENTIFIER9  adapter_ident;
222
223     /* Retrieves the display device identifier from the d3d9 implementation. */
224     d3d9_handle = LoadLibraryA("d3d9.dll");
225     if(d3d9_handle)
226         pDirect3DCreate9 = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
227     if(pDirect3DCreate9)
228         pD3d = pDirect3DCreate9(D3D_SDK_VERSION);
229     if(pD3d)
230         hr = IDirect3D9_GetAdapterIdentifier(pD3d, D3DADAPTER_DEFAULT, 0, &adapter_ident);
231     if(SUCCEEDED(hr)) {
232         StringFromGUID2(&adapter_ident.DeviceIdentifier, szIdentifierBuffer, 39);
233     } else {
234         memcpy(szIdentifierBuffer, szNA, sizeof(szNA));
235     }
236
237     if (pD3d)
238         IDirect3D9_Release(pD3d);
239     if (d3d9_handle)
240         FreeLibrary(d3d9_handle);
241 }
242
243 /**
244  * @param szFilePath: usually GetSystemDirectoryW
245  * @param szFileName: name of the dll without path
246  */
247 static HRESULT DXDiag_AddFileDescContainer(IDxDiagContainer* pSubCont, const WCHAR* szFilePath, const WCHAR* szFileName) {
248   HRESULT hr = S_OK;
249   /**/
250   static const WCHAR szSlashSep[] = {'\\',0};
251   static const WCHAR szPath[] = {'s','z','P','a','t','h',0};
252   static const WCHAR szName[] = {'s','z','N','a','m','e',0};
253   static const WCHAR szVersion[] = {'s','z','V','e','r','s','i','o','n',0};
254   static const WCHAR szAttributes[] = {'s','z','A','t','t','r','i','b','u','t','e','s',0};
255   static const WCHAR szLanguageEnglish[] = {'s','z','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
256   static const WCHAR dwFileTimeHigh[] = {'d','w','F','i','l','e','T','i','m','e','H','i','g','h',0};
257   static const WCHAR dwFileTimeLow[] = {'d','w','F','i','l','e','T','i','m','e','L','o','w',0};
258   static const WCHAR bBeta[] = {'b','B','e','t','a',0};
259   static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
260   static const WCHAR bExists[] = {'b','E','x','i','s','t','s',0};
261   /** values */
262   static const WCHAR szFinal_Retail_v[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
263   static const WCHAR szEnglish_v[] = {'E','n','g','l','i','s','h',0};
264   static const WCHAR szVersionFormat[] = {'%','u','.','%','0','2','u','.','%','0','4','u','.','%','0','4','u',0};
265
266   WCHAR szFile[512];
267   WCHAR szVersion_v[1024];
268   DWORD retval, hdl;
269   LPVOID pVersionInfo;
270   BOOL boolret;
271   UINT uiLength;
272   VS_FIXEDFILEINFO* pFileInfo;
273
274   TRACE("(%p,%s)\n", pSubCont, debugstr_w(szFileName));
275
276   lstrcpyW(szFile, szFilePath);
277   lstrcatW(szFile, szSlashSep);
278   lstrcatW(szFile, szFileName);
279
280   retval = GetFileVersionInfoSizeW(szFile, &hdl);
281   pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
282   boolret = GetFileVersionInfoW(szFile, 0, retval, pVersionInfo);
283   boolret = VerQueryValueW(pVersionInfo, szSlashSep, (LPVOID) &pFileInfo, &uiLength);
284
285   add_prop_str(pSubCont, szPath, szFile);
286   add_prop_str(pSubCont, szName, szFileName);
287   add_prop_bool(pSubCont, bExists, boolret);
288
289   if (boolret) {
290     snprintfW(szVersion_v, sizeof(szVersion_v)/sizeof(szVersion_v[0]),
291               szVersionFormat,
292               HIWORD(pFileInfo->dwFileVersionMS), 
293               LOWORD(pFileInfo->dwFileVersionMS),
294               HIWORD(pFileInfo->dwFileVersionLS),
295               LOWORD(pFileInfo->dwFileVersionLS));
296
297     TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));
298
299     add_prop_str(pSubCont, szVersion,         szVersion_v);
300     add_prop_str(pSubCont, szAttributes,      szFinal_Retail_v);
301     add_prop_str(pSubCont, szLanguageEnglish, szEnglish_v);
302     add_prop_ui4(pSubCont, dwFileTimeHigh,    pFileInfo->dwFileDateMS);
303     add_prop_ui4(pSubCont, dwFileTimeLow,     pFileInfo->dwFileDateLS);
304     add_prop_bool(pSubCont, bBeta,  0 != ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE));
305     add_prop_bool(pSubCont, bDebug, 0 != ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG));
306   }
307
308   HeapFree(GetProcessHeap(), 0, pVersionInfo);
309
310   return hr;
311 }
312
313 static HRESULT DXDiag_InitDXDiagSystemInfoContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
314   static const WCHAR dwDirectXVersionMajor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','a','j','o','r',0};
315   static const WCHAR dwDirectXVersionMinor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','i','n','o','r',0};
316   static const WCHAR szDirectXVersionLetter[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','e','t','t','e','r',0};
317   static const WCHAR szDirectXVersionLetter_v[] = {'c',0};
318   static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
319   static const WCHAR szDirectXVersionEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','E','n','g','l','i','s','h',0};
320   static const WCHAR szDirectXVersionEnglish_v[] = {'4','.','0','9','.','0','0','0','0','.','0','9','0','4',0};
321   static const WCHAR szDirectXVersionLongEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','o','n','g','E','n','g','l','i','s','h',0};
322   static const WCHAR szDirectXVersionLongEnglish_v[] = {'=',' ','"','D','i','r','e','c','t','X',' ','9','.','0','c',' ','(','4','.','0','9','.','0','0','0','0','.','0','9','0','4',')',0};
323   static const WCHAR ullPhysicalMemory[] = {'u','l','l','P','h','y','s','i','c','a','l','M','e','m','o','r','y',0};
324   static const WCHAR ullUsedPageFile[]   = {'u','l','l','U','s','e','d','P','a','g','e','F','i','l','e',0};
325   static const WCHAR ullAvailPageFile[]  = {'u','l','l','A','v','a','i','l','P','a','g','e','F','i','l','e',0};
326   /*static const WCHAR szDxDiagVersion[] = {'s','z','D','x','D','i','a','g','V','e','r','s','i','o','n',0};*/
327   static const WCHAR szWindowsDir[] = {'s','z','W','i','n','d','o','w','s','D','i','r',0};
328   static const WCHAR dwOSMajorVersion[] = {'d','w','O','S','M','a','j','o','r','V','e','r','s','i','o','n',0};
329   static const WCHAR dwOSMinorVersion[] = {'d','w','O','S','M','i','n','o','r','V','e','r','s','i','o','n',0};
330   static const WCHAR dwOSBuildNumber[] = {'d','w','O','S','B','u','i','l','d','N','u','m','b','e','r',0};
331   static const WCHAR dwOSPlatformID[] = {'d','w','O','S','P','l','a','t','f','o','r','m','I','D',0};
332   static const WCHAR szCSDVersion[] = {'s','z','C','S','D','V','e','r','s','i','o','n',0};
333   MEMORYSTATUSEX msex;
334   OSVERSIONINFOW info;
335   WCHAR buffer[MAX_PATH];
336
337   add_prop_ui4(pSubCont, dwDirectXVersionMajor, 9);
338   add_prop_ui4(pSubCont, dwDirectXVersionMinor, 0);
339   add_prop_str(pSubCont, szDirectXVersionLetter, szDirectXVersionLetter_v);
340   add_prop_str(pSubCont, szDirectXVersionEnglish, szDirectXVersionEnglish_v);
341   add_prop_str(pSubCont, szDirectXVersionLongEnglish, szDirectXVersionLongEnglish_v);
342   add_prop_bool(pSubCont, bDebug, FALSE);
343
344   msex.dwLength = sizeof(msex);
345   GlobalMemoryStatusEx( &msex );
346   add_prop_ull_as_str(pSubCont, ullPhysicalMemory, msex.ullTotalPhys);
347   add_prop_ull_as_str(pSubCont, ullUsedPageFile, msex.ullTotalPageFile - msex.ullAvailPageFile);
348   add_prop_ull_as_str(pSubCont, ullAvailPageFile, msex.ullAvailPageFile);
349
350   info.dwOSVersionInfoSize = sizeof(info);
351   GetVersionExW( &info );
352   add_prop_ui4(pSubCont, dwOSMajorVersion, info.dwMajorVersion);
353   add_prop_ui4(pSubCont, dwOSMinorVersion, info.dwMinorVersion);
354   add_prop_ui4(pSubCont, dwOSBuildNumber,  info.dwBuildNumber);
355   add_prop_ui4(pSubCont, dwOSPlatformID,   info.dwPlatformId);
356   add_prop_str(pSubCont, szCSDVersion,     info.szCSDVersion);
357
358   GetWindowsDirectoryW(buffer, MAX_PATH);
359   add_prop_str(pSubCont, szWindowsDir, buffer);
360
361   return S_OK;
362 }
363
364 static HRESULT DXDiag_InitDXDiagSystemDevicesContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
365   HRESULT hr = S_OK;
366   /*
367   static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
368   static const WCHAR szDeviceID[] = {'s','z','D','e','v','i','c','e','I','D',0};
369
370   static const WCHAR szDrivers[] = {'s','z','D','r','i','v','e','r','s',0};
371
372   VARIANT v;
373   IDxDiagContainer* pDeviceSubCont = NULL;
374   IDxDiagContainer* pDriversCont = NULL;
375
376   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, &pDeviceSubCont);
377   if (FAILED(hr)) { return hr; }
378   V_VT(pvarProp) = VT_BSTR; V_BSTR(pvarProp) = SysAllocString(property->psz);
379   hr = IDxDiagContainerImpl_AddProp(pDeviceSubCont, szDescription, &v);
380   VariantClear(&v);
381   V_VT(pvarProp) = VT_BSTR; V_BSTR(pvarProp) = SysAllocString(property->psz);
382   hr = IDxDiagContainerImpl_AddProp(pDeviceSubCont, szDeviceID, &v);
383   VariantClear(&v);
384
385   hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, "", pDeviceSubCont);
386   */
387
388   /*
389    * Drivers Cont contains Files Desc Containers
390    */
391   /*
392   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, &pDriversCont);
393   if (FAILED(hr)) { return hr; }
394   hr = IDxDiagContainerImpl_AddChildContainer(pDeviceSubCont, szDrivers, pDriversCont);
395
396   */
397   return hr;
398 }
399
400 static HRESULT DXDiag_InitDXDiagLogicalDisksContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
401   HRESULT hr = S_OK;
402   /*
403   static const WCHAR szDriveLetter[] = {'s','z','D','r','i','v','e','L','e','t','t','e','r',0};
404   static const WCHAR szFreeSpace[] = {'s','z','F','r','e','e','S','p','a','c','e',0};
405   static const WCHAR szMaxSpace[] = {'s','z','M','a','x','S','p','a','c','e',0};
406   static const WCHAR szFileSystem[] = {'s','z','F','i','l','e','S','y','s','t','e','m',0};
407   static const WCHAR szModel[] = {'s','z','M','o','d','e','l',0};
408   static const WCHAR szPNPDeviceID[] = {'s','z','P','N','P','D','e','v','i','c','e','I','D',0};
409   static const WCHAR dwHardDriveIndex[] = {'d','w','H','a','r','d','D','r','i','v','e','I','n','d','e','x',0};
410
411   static const WCHAR szDrivers[] = {'s','z','D','r','i','v','e','r','s',0};
412  
413   VARIANT v;
414   IDxDiagContainer* pDiskSubCont = NULL;
415   IDxDiagContainer* pDriversCont = NULL;
416
417   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, &pDiskSubCont);
418   if (FAILED(hr)) { return hr; }
419   hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, "" , pDiskSubCont);
420   */
421   
422   /*
423    * Drivers Cont contains Files Desc Containers
424    */
425   /*
426   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, &pDriversCont);
427   if (FAILED(hr)) { return hr; }
428   hr = IDxDiagContainerImpl_AddChildContainer(pDeviceSubCont, szDrivers, pDriversCont);
429   */
430   return hr;
431 }
432
433 static HRESULT DXDiag_InitDXDiagDirectXFilesContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv)
434 {
435     HRESULT hr = S_OK;
436     static const WCHAR dlls[][15] =
437     {
438         {'d','3','d','8','.','d','l','l',0},
439         {'d','3','d','9','.','d','l','l',0},
440         {'d','d','r','a','w','.','d','l','l',0},
441         {'d','e','v','e','n','u','m','.','d','l','l',0},
442         {'d','i','n','p','u','t','8','.','d','l','l',0},
443         {'d','i','n','p','u','t','.','d','l','l',0},
444         {'d','m','b','a','n','d','.','d','l','l',0},
445         {'d','m','c','o','m','p','o','s','.','d','l','l',0},
446         {'d','m','i','m','e','.','d','l','l',0},
447         {'d','m','l','o','a','d','e','r','.','d','l','l',0},
448         {'d','m','s','c','r','i','p','t','.','d','l','l',0},
449         {'d','m','s','t','y','l','e','.','d','l','l',0},
450         {'d','m','s','y','n','t','h','.','d','l','l',0},
451         {'d','m','u','s','i','c','.','d','l','l',0},
452         {'d','p','l','a','y','x','.','d','l','l',0},
453         {'d','p','n','e','t','.','d','l','l',0},
454         {'d','s','o','u','n','d','.','d','l','l',0},
455         {'d','s','w','a','v','e','.','d','l','l',0},
456         {'d','x','d','i','a','g','n','.','d','l','l',0},
457         {'q','u','a','r','t','z','.','d','l','l',0}
458     };
459     WCHAR szFilePath[MAX_PATH];
460     INT i;
461
462     GetSystemDirectoryW(szFilePath, MAX_PATH);
463
464     for (i = 0; i < sizeof(dlls) / sizeof(dlls[0]); i++)
465     {
466         static const WCHAR szFormat[] = {'%','d',0};
467         WCHAR szFileID[5];
468         IDxDiagContainer *pDXFileSubCont;
469
470         snprintfW(szFileID, sizeof(szFileID)/sizeof(szFileID[0]), szFormat, i);
471
472         hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pProv, (void**) &pDXFileSubCont);
473         if (FAILED(hr)) continue;
474
475         if (FAILED(DXDiag_AddFileDescContainer(pDXFileSubCont, szFilePath, dlls[i])) ||
476             FAILED(IDxDiagContainerImpl_AddChildContainer(pSubCont, szFileID, pDXFileSubCont)))
477         {
478             IUnknown_Release(pDXFileSubCont);
479             continue;
480         }
481     }
482     return hr;
483 }
484
485 static HRESULT DXDiag_InitDXDiagDisplayContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv)
486 {
487     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
488     static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
489     static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
490     static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
491     static const WCHAR szVendorId[] = {'s','z','V','e','n','d','o','r','I','d',0};
492     static const WCHAR szDeviceId[] = {'s','z','D','e','v','i','c','e','I','d',0};
493     static const WCHAR szDeviceIdentifier[] = {'s','z','D','e','v','i','c','e','I','d','e','n','t','i','f','i','e','r',0};
494     static const WCHAR dwWidth[] = {'d','w','W','i','d','t','h',0};
495     static const WCHAR dwHeight[] = {'d','w','H','e','i','g','h','t',0};
496     static const WCHAR dwBpp[] = {'d','w','B','p','p',0};
497     static const WCHAR szDisplayMemoryLocalized[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','L','o','c','a','l','i','z','e','d',0};
498     static const WCHAR szDisplayMemoryEnglish[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
499
500     static const WCHAR szAdapterID[] = {'0',0};
501     static const WCHAR szEmpty[] = {0};
502
503     HRESULT                 hr;
504     IDxDiagContainer       *pDisplayAdapterSubCont = NULL;
505
506     IDirectDraw7           *pDirectDraw;
507     DDSCAPS2                dd_caps;
508     DISPLAY_DEVICEW         disp_dev;
509     DDSURFACEDESC2          surface_descr;
510     DWORD                   tmp;
511     WCHAR                   buffer[256];
512
513     hr = DXDiag_CreateDXDiagContainer( &IID_IDxDiagContainer, pProv, (void**) &pDisplayAdapterSubCont );
514     if (FAILED( hr )) return hr;
515     hr = IDxDiagContainerImpl_AddChildContainer( pSubCont, szAdapterID, pDisplayAdapterSubCont );
516     if (FAILED( hr )) return hr;
517
518     disp_dev.cb = sizeof(disp_dev);
519     if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
520     {
521         add_prop_str( pDisplayAdapterSubCont, szDeviceName, disp_dev.DeviceName );
522         add_prop_str( pDisplayAdapterSubCont, szDescription, disp_dev.DeviceString );
523     }
524
525     hr = DirectDrawCreateEx( NULL, (LPVOID *)&pDirectDraw, &IID_IDirectDraw7, NULL);
526     if (FAILED( hr )) return hr;
527
528     dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
529     dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.dwCaps4 = 0;
530     hr = IDirectDraw7_GetAvailableVidMem( pDirectDraw, &dd_caps, &tmp, NULL );
531     if (SUCCEEDED(hr))
532     {
533         static const WCHAR mem_fmt[] = {'%','.','1','f',' ','M','B',0};
534
535         snprintfW( buffer, sizeof(buffer)/sizeof(buffer[0]), mem_fmt, ((float)tmp) / 1000000.0 );
536         add_prop_str( pDisplayAdapterSubCont, szDisplayMemoryLocalized, buffer );
537         add_prop_str( pDisplayAdapterSubCont, szDisplayMemoryEnglish, buffer );
538     }
539
540     surface_descr.dwSize = sizeof(surface_descr);
541     hr = IDirectDraw7_GetDisplayMode( pDirectDraw, &surface_descr );
542     if (SUCCEEDED(hr))
543     {
544         if (surface_descr.dwFlags & DDSD_WIDTH)
545             add_prop_ui4( pDisplayAdapterSubCont, dwWidth, surface_descr.dwWidth );
546         if (surface_descr.dwFlags & DDSD_HEIGHT)
547             add_prop_ui4( pDisplayAdapterSubCont, dwHeight, surface_descr.dwHeight );
548         if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
549             add_prop_ui4( pDisplayAdapterSubCont, dwBpp, surface_descr.u4.ddpfPixelFormat.u1.dwRGBBitCount );
550     }
551
552     get_display_device_id( buffer );
553     add_prop_str( pDisplayAdapterSubCont, szDeviceIdentifier, buffer );
554
555     add_prop_str( pDisplayAdapterSubCont, szVendorId, szEmpty );
556     add_prop_str( pDisplayAdapterSubCont, szDeviceId, szEmpty );
557     add_prop_str( pDisplayAdapterSubCont, szKeyDeviceKey, szEmpty );
558     add_prop_str( pDisplayAdapterSubCont, szKeyDeviceID, szEmpty );
559
560     IUnknown_Release( pDirectDraw );
561     return hr;
562 }
563
564 static HRESULT DXDiag_InitDXDiagDirectSoundContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
565   HRESULT hr = S_OK;
566   static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
567   static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e','D','e','v','i','c','e','s',0};
568   IDxDiagContainer* pSubSubCont = NULL;
569
570   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pProv, (void**) &pSubSubCont);
571   if (FAILED(hr)) { return hr; }
572   hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, DxDiag_SoundDevices, pSubSubCont);
573
574   hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pProv, (void**) &pSubSubCont);
575   if (FAILED(hr)) { return hr; }
576   hr = IDxDiagContainerImpl_AddChildContainer(pSubCont, DxDiag_SoundCaptureDevices, pSubSubCont);
577
578   return hr;
579 }
580
581 static HRESULT DXDiag_InitDXDiagDirectMusicContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
582   HRESULT hr = S_OK;
583   return hr;
584 }
585
586 static HRESULT DXDiag_InitDXDiagDirectInputContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
587   HRESULT hr = S_OK;
588   return hr;
589 }
590
591 static HRESULT DXDiag_InitDXDiagDirectPlayContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
592   HRESULT hr = S_OK;
593   return hr;
594 }
595
596 static HRESULT DXDiag_InitDXDiagDirectShowFiltersContainer(IDxDiagContainer* pSubCont, IDxDiagProvider *pProv) {
597   HRESULT hr = S_OK;
598   static const WCHAR szName[] = {'s','z','N','a','m','e',0};
599   static const WCHAR szVersionW[] = {'s','z','V','e','r','s','i','o','n',0};
600   static const WCHAR szCatName[] = {'s','z','C','a','t','N','a','m','e',0};
601   static const WCHAR ClsidCatW[] = {'C','l','s','i','d','C','a','t',0};
602   static const WCHAR ClsidFilterW[] = {'C','l','s','i','d','F','i','l','t','e','r',0};
603   static const WCHAR dwInputs[] = {'d','w','I','n','p','u','t','s',0};
604   static const WCHAR dwOutputs[] = {'d','w','O','u','t','p','u','t','s',0};
605   static const WCHAR dwMeritW[] = {'d','w','M','e','r','i','t',0};
606   /*
607   static const WCHAR szFileName[] = {'s','z','F','i','l','e','N','a','m','e',0};
608   static const WCHAR szFileVersion[] = {'s','z','F','i','l','e','V','e','r','s','i','o','n',0};
609   */
610   VARIANT v;
611
612   static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
613   static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};  
614   static const WCHAR wszFilterDataName[] = {'F','i','l','t','e','r','D','a','t','a',0};
615
616   static const WCHAR szVersionFormat[] = {'v','%','d',0};
617   static const WCHAR szIdFormat[] = {'%','d',0};
618   int i = 0;
619
620
621   ICreateDevEnum* pCreateDevEnum = NULL;
622   IEnumMoniker* pEmCat = NULL;
623   IMoniker* pMCat = NULL;
624   /** */
625   hr = CoCreateInstance(&CLSID_SystemDeviceEnum, 
626                         NULL, 
627                         CLSCTX_INPROC_SERVER,
628                         &IID_ICreateDevEnum, 
629                         (void**) &pCreateDevEnum);
630   if (FAILED(hr)) return hr; 
631   
632   hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
633   if (FAILED(hr)) goto out_show_filters; 
634
635   VariantInit(&v);
636
637   while (S_OK == IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL)) {
638     IPropertyBag* pPropBag = NULL;
639     CLSID clsidCat; 
640     hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void**) &pPropBag);
641     if (SUCCEEDED(hr)) {
642       WCHAR* wszCatName = NULL;
643       WCHAR* wszCatClsid = NULL;
644
645       hr = IPropertyBag_Read(pPropBag, wszFriendlyName, &v, 0);
646       wszCatName = SysAllocString(V_BSTR(&v));
647       VariantClear(&v);
648
649       hr = IPropertyBag_Read(pPropBag, wszClsidName, &v, 0);
650       wszCatClsid = SysAllocString(V_BSTR(&v));
651       hr = CLSIDFromString(V_UNION(&v, bstrVal), &clsidCat);
652       VariantClear(&v);
653
654       /*
655       hr = IPropertyBag_Read(pPropBag, wszMeritName, &v, 0);
656       hr = IDxDiagContainerImpl_AddProp(pSubCont, dwMerit, &v);
657       VariantClear(&v);
658       */
659
660       if (SUCCEEDED(hr)) {
661         IEnumMoniker* pEnum = NULL;
662         IMoniker* pMoniker = NULL;
663         hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);        
664         TRACE("\tClassEnumerator for clsid(%s) pEnum(%p)\n", debugstr_guid(&clsidCat), pEnum);
665         if (FAILED(hr) || pEnum == NULL) {
666           goto class_enum_failed;
667         }
668         while (NULL != pEnum && S_OK == IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL)) {          
669           IPropertyBag* pPropFilterBag = NULL;
670           TRACE("\tIEnumMoniker_Next(%p, 1, %p)\n", pEnum, pMoniker);
671           hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void**) &pPropFilterBag);
672           if (SUCCEEDED(hr)) {
673             LPBYTE pData = NULL;
674             DWORD dwNOutputs = 0;
675             DWORD dwNInputs = 0;
676             DWORD dwMerit = 0;
677             WCHAR bufferW[10];
678             IDxDiagContainer *pDShowSubCont = NULL;
679             IFilterMapper2 *pFileMapper = NULL;
680             IAMFilterData *pFilterData = NULL;
681
682             snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szIdFormat, i);
683             if (FAILED(DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pProv, (void**) &pDShowSubCont)) ||
684                 FAILED(IDxDiagContainerImpl_AddChildContainer(pSubCont, bufferW, pDShowSubCont)))
685             {
686               IPropertyBag_Release(pPropFilterBag);
687               if (pDShowSubCont) IUnknown_Release(pDShowSubCont);
688               continue;
689             }
690
691             bufferW[0] = 0;
692             hr = IPropertyBag_Read(pPropFilterBag, wszFriendlyName, &v, 0);
693             hr = IDxDiagContainerImpl_AddProp(pDShowSubCont, szName, &v);
694             TRACE("\tName:%s\n", debugstr_w(V_BSTR(&v)));
695             VariantClear(&v);
696
697             hr = IPropertyBag_Read(pPropFilterBag, wszClsidName, &v, 0);
698             TRACE("\tClsid:%s\n", debugstr_w(V_BSTR(&v)));
699             hr = IDxDiagContainerImpl_AddProp(pDShowSubCont, ClsidFilterW, &v);
700             VariantClear(&v);
701
702             hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
703                                   (LPVOID*)&pFileMapper);
704             if (SUCCEEDED(hr) &&
705                 SUCCEEDED(IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData)))
706             {
707               DWORD array_size;
708               REGFILTER2 *pRF;
709
710               if (SUCCEEDED(IPropertyBag_Read(pPropFilterBag, wszFilterDataName, &v, NULL)) &&
711                   SUCCEEDED(SafeArrayAccessData(V_UNION(&v, parray), (LPVOID*) &pData)))
712               {
713                 ULONG j;
714                 array_size = V_UNION(&v, parray)->rgsabound->cElements;
715
716                 if (SUCCEEDED(IAMFilterData_ParseFilterData(pFilterData, pData, array_size, (BYTE **)&pRF)))
717                 {
718                   snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szVersionFormat, pRF->dwVersion);
719                   if (pRF->dwVersion == 1)
720                   {
721                     for (j = 0; j < pRF->u.s.cPins; j++)
722                       if (pRF->u.s.rgPins[j].bOutput)
723                         dwNOutputs++;
724                       else
725                         dwNInputs++;
726                   }
727                   else if (pRF->dwVersion == 2)
728                   {
729                     for (j = 0; j < pRF->u.s1.cPins2; j++)
730                       if (pRF->u.s1.rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
731                         dwNOutputs++;
732                       else
733                         dwNInputs++;
734                   }
735
736                   dwMerit = pRF->dwMerit;
737                   CoTaskMemFree(pRF);
738                 }
739
740                 SafeArrayUnaccessData(V_UNION(&v, parray));
741                 VariantClear(&v);
742               }
743               IFilterMapper2_Release(pFilterData);
744             }
745             if (pFileMapper) IFilterMapper2_Release(pFileMapper);
746
747             add_prop_str(pDShowSubCont, szVersionW, bufferW);
748             add_prop_str(pDShowSubCont, szCatName, wszCatName);
749             add_prop_str(pDShowSubCont, ClsidCatW, wszCatClsid);
750             add_prop_ui4(pDShowSubCont, dwInputs,  dwNInputs);
751             add_prop_ui4(pDShowSubCont, dwOutputs, dwNOutputs);
752             add_prop_ui4(pDShowSubCont, dwMeritW, dwMerit);
753
754             i++;
755           }
756           IPropertyBag_Release(pPropFilterBag); pPropFilterBag = NULL;
757         }
758         IEnumMoniker_Release(pEnum); pEnum = NULL;
759       }
760 class_enum_failed:      
761       SysFreeString(wszCatName);
762       SysFreeString(wszCatClsid);
763       IPropertyBag_Release(pPropBag); pPropBag = NULL;
764     }
765     IEnumMoniker_Release(pMCat); pMCat = NULL;
766   }
767
768 out_show_filters:
769   if (NULL != pEmCat) { IEnumMoniker_Release(pEmCat); pEmCat = NULL; }
770   if (NULL != pCreateDevEnum) { ICreateDevEnum_Release(pCreateDevEnum); pCreateDevEnum = NULL; }
771   return hr;
772 }
773
774 static HRESULT DXDiag_InitRootDXDiagContainer(IDxDiagContainer* pRootCont, IDxDiagProvider *pProv) {
775   static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
776   static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
777   static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
778   static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
779   static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
780   static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
781   static const WCHAR DxDiag_SystemDevices[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','D','e','v','i','c','e','s',0};
782   static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
783   static const WCHAR DxDiag_DirectShowFilters[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','h','o','w','F','i','l','t','e','r','s',0};
784   static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
785
786   static const struct
787   {
788     const WCHAR *name;
789     HRESULT (*initfunc)(IDxDiagContainer*, IDxDiagProvider*);
790   } containers[] =
791   {
792     {DxDiag_SystemInfo,        DXDiag_InitDXDiagSystemInfoContainer},
793     {DxDiag_DisplayDevices,    DXDiag_InitDXDiagDisplayContainer},
794     {DxDiag_DirectSound,       DXDiag_InitDXDiagDirectSoundContainer},
795     {DxDiag_DirectMusic,       DXDiag_InitDXDiagDirectMusicContainer},
796     {DxDiag_DirectInput,       DXDiag_InitDXDiagDirectInputContainer},
797     {DxDiag_DirectPlay,        DXDiag_InitDXDiagDirectPlayContainer},
798     {DxDiag_SystemDevices,     DXDiag_InitDXDiagSystemDevicesContainer},
799     {DxDiag_DirectXFiles,      DXDiag_InitDXDiagDirectXFilesContainer},
800     {DxDiag_DirectShowFilters, DXDiag_InitDXDiagDirectShowFiltersContainer},
801     {DxDiag_LogicalDisks,      DXDiag_InitDXDiagLogicalDisksContainer},
802   };
803
804   size_t index;
805
806   TRACE("(%p)\n", pRootCont);
807
808   for (index = 0; index < sizeof(containers)/sizeof(containers[0]); index++)
809   {
810     IDxDiagContainer* pSubCont;
811     HRESULT hr;
812
813     hr = DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, pProv, (void**) &pSubCont);
814     if (FAILED(hr))
815       return hr;
816
817     hr = IDxDiagContainerImpl_AddChildContainer(pRootCont, containers[index].name, pSubCont);
818     if (FAILED(hr))
819     {
820       IDxDiagContainer_Release(pSubCont);
821       return hr;
822     }
823
824     /* The return value is ignored for now. */
825     containers[index].initfunc(pSubCont, pProv);
826   }
827
828   return S_OK;
829 }
830
831 static void free_property_information(IDxDiagContainerImpl_Property *prop)
832 {
833     VariantClear(&prop->vProp);
834     HeapFree(GetProcessHeap(), 0, prop->propName);
835     HeapFree(GetProcessHeap(), 0, prop);
836 }
837
838 static void free_information_tree(IDxDiagContainerImpl_Container *node)
839 {
840     IDxDiagContainerImpl_Container *ptr, *cursor2;
841
842     if (!node)
843         return;
844
845     HeapFree(GetProcessHeap(), 0, node->contName);
846
847     LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &node->subContainers, IDxDiagContainerImpl_Container, entry)
848     {
849         IDxDiagContainerImpl_Property *prop, *prop_cursor2;
850
851         LIST_FOR_EACH_ENTRY_SAFE(prop, prop_cursor2, &ptr->properties, IDxDiagContainerImpl_Property, entry)
852         {
853             list_remove(&prop->entry);
854             free_property_information(prop);
855         }
856
857         list_remove(&ptr->entry);
858         free_information_tree(ptr);
859     }
860
861     HeapFree(GetProcessHeap(), 0, node);
862 }
863
864 static IDxDiagContainerImpl_Container *allocate_information_node(const WCHAR *name)
865 {
866     IDxDiagContainerImpl_Container *ret;
867
868     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
869     if (!ret)
870         return NULL;
871
872     if (name)
873     {
874         ret->contName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
875         if (!ret->contName)
876         {
877             HeapFree(GetProcessHeap(), 0, ret);
878             return NULL;
879         }
880         strcpyW(ret->contName, name);
881     }
882
883     list_init(&ret->subContainers);
884     list_init(&ret->properties);
885
886     return ret;
887 }
888
889 static IDxDiagContainerImpl_Property *allocate_property_information(const WCHAR *name)
890 {
891     IDxDiagContainerImpl_Property *ret;
892
893     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
894     if (!ret)
895         return NULL;
896
897     ret->propName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
898     if (!ret->propName)
899     {
900         HeapFree(GetProcessHeap(), 0, ret);
901         return NULL;
902     }
903     strcpyW(ret->propName, name);
904
905     return ret;
906 }
907
908 static inline void add_subcontainer(IDxDiagContainerImpl_Container *node, IDxDiagContainerImpl_Container *subCont)
909 {
910     list_add_tail(&node->subContainers, &subCont->entry);
911     ++node->nSubContainers;
912 }
913
914 static inline HRESULT add_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, const WCHAR *str)
915 {
916     IDxDiagContainerImpl_Property *prop;
917     BSTR bstr;
918
919     prop = allocate_property_information(propName);
920     if (!prop)
921         return E_OUTOFMEMORY;
922
923     bstr = SysAllocString(str);
924     if (!bstr)
925     {
926         free_property_information(prop);
927         return E_OUTOFMEMORY;
928     }
929
930     V_VT(&prop->vProp) = VT_BSTR;
931     V_BSTR(&prop->vProp) = bstr;
932
933     list_add_tail(&node->properties, &prop->entry);
934     ++node->nProperties;
935
936     return S_OK;
937 }
938
939 static inline HRESULT add_ui4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, DWORD data)
940 {
941     IDxDiagContainerImpl_Property *prop;
942
943     prop = allocate_property_information(propName);
944     if (!prop)
945         return E_OUTOFMEMORY;
946
947     V_VT(&prop->vProp) = VT_UI4;
948     V_UI4(&prop->vProp) = data;
949
950     list_add_tail(&node->properties, &prop->entry);
951     ++node->nProperties;
952
953     return S_OK;
954 }
955
956 static inline HRESULT add_bool_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, BOOL data)
957 {
958     IDxDiagContainerImpl_Property *prop;
959
960     prop = allocate_property_information(propName);
961     if (!prop)
962         return E_OUTOFMEMORY;
963
964     V_VT(&prop->vProp) = VT_BOOL;
965     V_BOOL(&prop->vProp) = data;
966
967     list_add_tail(&node->properties, &prop->entry);
968     ++node->nProperties;
969
970     return S_OK;
971 }
972
973 static inline HRESULT add_ull_as_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, ULONGLONG data )
974 {
975     IDxDiagContainerImpl_Property *prop;
976
977     prop = allocate_property_information(propName);
978     if (!prop)
979         return E_OUTOFMEMORY;
980
981     V_VT(&prop->vProp) = VT_UI8;
982     V_UI8(&prop->vProp) = data;
983
984     VariantChangeType(&prop->vProp, &prop->vProp, 0, VT_BSTR);
985
986     list_add_tail(&node->properties, &prop->entry);
987     ++node->nProperties;
988
989     return S_OK;
990 }
991
992 static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node)
993 {
994     static const WCHAR dwDirectXVersionMajor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','a','j','o','r',0};
995     static const WCHAR dwDirectXVersionMinor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','i','n','o','r',0};
996     static const WCHAR szDirectXVersionLetter[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','e','t','t','e','r',0};
997     static const WCHAR szDirectXVersionLetter_v[] = {'c',0};
998     static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
999     static const WCHAR szDirectXVersionEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','E','n','g','l','i','s','h',0};
1000     static const WCHAR szDirectXVersionEnglish_v[] = {'4','.','0','9','.','0','0','0','0','.','0','9','0','4',0};
1001     static const WCHAR szDirectXVersionLongEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','o','n','g','E','n','g','l','i','s','h',0};
1002     static const WCHAR szDirectXVersionLongEnglish_v[] = {'=',' ','"','D','i','r','e','c','t','X',' ','9','.','0','c',' ','(','4','.','0','9','.','0','0','0','0','.','0','9','0','4',')',0};
1003     static const WCHAR ullPhysicalMemory[] = {'u','l','l','P','h','y','s','i','c','a','l','M','e','m','o','r','y',0};
1004     static const WCHAR ullUsedPageFile[]   = {'u','l','l','U','s','e','d','P','a','g','e','F','i','l','e',0};
1005     static const WCHAR ullAvailPageFile[]  = {'u','l','l','A','v','a','i','l','P','a','g','e','F','i','l','e',0};
1006     static const WCHAR szWindowsDir[] = {'s','z','W','i','n','d','o','w','s','D','i','r',0};
1007     static const WCHAR dwOSMajorVersion[] = {'d','w','O','S','M','a','j','o','r','V','e','r','s','i','o','n',0};
1008     static const WCHAR dwOSMinorVersion[] = {'d','w','O','S','M','i','n','o','r','V','e','r','s','i','o','n',0};
1009     static const WCHAR dwOSBuildNumber[] = {'d','w','O','S','B','u','i','l','d','N','u','m','b','e','r',0};
1010     static const WCHAR dwOSPlatformID[] = {'d','w','O','S','P','l','a','t','f','o','r','m','I','D',0};
1011     static const WCHAR szCSDVersion[] = {'s','z','C','S','D','V','e','r','s','i','o','n',0};
1012
1013     HRESULT hr;
1014     MEMORYSTATUSEX msex;
1015     OSVERSIONINFOW info;
1016     WCHAR buffer[MAX_PATH];
1017
1018     hr = add_ui4_property(node, dwDirectXVersionMajor, 9);
1019     if (FAILED(hr))
1020         return hr;
1021
1022     hr = add_ui4_property(node, dwDirectXVersionMinor, 0);
1023     if (FAILED(hr))
1024         return hr;
1025
1026     hr = add_bstr_property(node, szDirectXVersionLetter, szDirectXVersionLetter_v);
1027     if (FAILED(hr))
1028         return hr;
1029
1030     hr = add_bstr_property(node, szDirectXVersionEnglish, szDirectXVersionEnglish_v);
1031     if (FAILED(hr))
1032         return hr;
1033
1034     hr = add_bstr_property(node, szDirectXVersionLongEnglish, szDirectXVersionLongEnglish_v);
1035     if (FAILED(hr))
1036         return hr;
1037
1038     hr = add_bool_property(node, bDebug, FALSE);
1039     if (FAILED(hr))
1040         return hr;
1041
1042     msex.dwLength = sizeof(msex);
1043     GlobalMemoryStatusEx(&msex);
1044
1045     hr = add_ull_as_bstr_property(node, ullPhysicalMemory, msex.ullTotalPhys);
1046     if (FAILED(hr))
1047         return hr;
1048
1049     hr = add_ull_as_bstr_property(node, ullUsedPageFile, msex.ullTotalPageFile - msex.ullAvailPageFile);
1050     if (FAILED(hr))
1051         return hr;
1052
1053     hr = add_ull_as_bstr_property(node, ullAvailPageFile, msex.ullAvailPageFile);
1054     if (FAILED(hr))
1055         return hr;
1056
1057     info.dwOSVersionInfoSize = sizeof(info);
1058     GetVersionExW(&info);
1059
1060     hr = add_ui4_property(node, dwOSMajorVersion, info.dwMajorVersion);
1061     if (FAILED(hr))
1062         return hr;
1063
1064     hr = add_ui4_property(node, dwOSMinorVersion, info.dwMinorVersion);
1065     if (FAILED(hr))
1066         return hr;
1067
1068     hr = add_ui4_property(node, dwOSBuildNumber, info.dwBuildNumber);
1069     if (FAILED(hr))
1070         return hr;
1071
1072     hr = add_ui4_property(node, dwOSPlatformID, info.dwPlatformId);
1073     if (FAILED(hr))
1074         return hr;
1075
1076     hr = add_bstr_property(node, szCSDVersion, info.szCSDVersion);
1077     if (FAILED(hr))
1078         return hr;
1079
1080     GetWindowsDirectoryW(buffer, MAX_PATH);
1081
1082     hr = add_bstr_property(node, szWindowsDir, buffer);
1083     if (FAILED(hr))
1084         return hr;
1085
1086     return S_OK;
1087 }
1088
1089 static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
1090 {
1091     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
1092     static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
1093     static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
1094     static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
1095     static const WCHAR szVendorId[] = {'s','z','V','e','n','d','o','r','I','d',0};
1096     static const WCHAR szDeviceId[] = {'s','z','D','e','v','i','c','e','I','d',0};
1097     static const WCHAR szDeviceIdentifier[] = {'s','z','D','e','v','i','c','e','I','d','e','n','t','i','f','i','e','r',0};
1098     static const WCHAR dwWidth[] = {'d','w','W','i','d','t','h',0};
1099     static const WCHAR dwHeight[] = {'d','w','H','e','i','g','h','t',0};
1100     static const WCHAR dwBpp[] = {'d','w','B','p','p',0};
1101     static const WCHAR szDisplayMemoryLocalized[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','L','o','c','a','l','i','z','e','d',0};
1102     static const WCHAR szDisplayMemoryEnglish[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
1103
1104     static const WCHAR szAdapterID[] = {'0',0};
1105     static const WCHAR szEmpty[] = {0};
1106
1107     IDxDiagContainerImpl_Container *display_adapter;
1108     HRESULT hr;
1109     IDirectDraw7 *pDirectDraw;
1110     DDSCAPS2 dd_caps;
1111     DISPLAY_DEVICEW disp_dev;
1112     DDSURFACEDESC2 surface_descr;
1113     DWORD tmp;
1114     WCHAR buffer[256];
1115
1116     display_adapter = allocate_information_node(szAdapterID);
1117     if (!display_adapter)
1118         return E_OUTOFMEMORY;
1119
1120     add_subcontainer(node, display_adapter);
1121
1122     disp_dev.cb = sizeof(disp_dev);
1123     if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
1124     {
1125         hr = add_bstr_property(display_adapter, szDeviceName, disp_dev.DeviceName);
1126         if (FAILED(hr))
1127             return hr;
1128
1129         hr = add_bstr_property(display_adapter, szDescription, disp_dev.DeviceString);
1130         if (FAILED(hr))
1131             return hr;
1132     }
1133
1134     /* For now, silently ignore a failure from DirectDrawCreateEx. */
1135     hr = DirectDrawCreateEx(NULL, (LPVOID *)&pDirectDraw, &IID_IDirectDraw7, NULL);
1136     if (FAILED(hr))
1137         return S_OK;
1138
1139     dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
1140     dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.dwCaps4 = 0;
1141     hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, &tmp, NULL);
1142     if (SUCCEEDED(hr))
1143     {
1144         static const WCHAR mem_fmt[] = {'%','.','1','f',' ','M','B',0};
1145
1146         snprintfW(buffer, sizeof(buffer)/sizeof(buffer[0]), mem_fmt, ((float)tmp) / 1000000.0);
1147
1148         hr = add_bstr_property(display_adapter, szDisplayMemoryLocalized, buffer);
1149         if (FAILED(hr))
1150             goto cleanup;
1151
1152         hr = add_bstr_property(display_adapter, szDisplayMemoryEnglish, buffer);
1153         if (FAILED(hr))
1154             goto cleanup;
1155     }
1156
1157     surface_descr.dwSize = sizeof(surface_descr);
1158     hr = IDirectDraw7_GetDisplayMode(pDirectDraw, &surface_descr);
1159     if (SUCCEEDED(hr))
1160     {
1161         if (surface_descr.dwFlags & DDSD_WIDTH)
1162         {
1163             hr = add_ui4_property(display_adapter, dwWidth, surface_descr.dwWidth);
1164             if (FAILED(hr))
1165                 goto cleanup;
1166         }
1167
1168         if (surface_descr.dwFlags & DDSD_HEIGHT)
1169         {
1170             hr = add_ui4_property(display_adapter, dwHeight, surface_descr.dwHeight);
1171             if (FAILED(hr))
1172                 goto cleanup;
1173         }
1174
1175         if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
1176         {
1177             hr = add_ui4_property(display_adapter, dwBpp, surface_descr.u4.ddpfPixelFormat.u1.dwRGBBitCount);
1178             if (FAILED(hr))
1179                 goto cleanup;
1180         }
1181     }
1182
1183     get_display_device_id(buffer);
1184
1185     hr = add_bstr_property(display_adapter, szDeviceIdentifier, buffer);
1186     if (FAILED(hr))
1187         goto cleanup;
1188
1189     hr = add_bstr_property(display_adapter, szVendorId, szEmpty);
1190     if (FAILED(hr))
1191         goto cleanup;
1192
1193     hr = add_bstr_property(display_adapter, szDeviceId, szEmpty);
1194     if (FAILED(hr))
1195         goto cleanup;
1196
1197     hr = add_bstr_property(display_adapter, szKeyDeviceKey, szEmpty);
1198     if (FAILED(hr))
1199         goto cleanup;
1200
1201     hr = add_bstr_property(display_adapter, szKeyDeviceID, szEmpty);
1202     if (FAILED(hr))
1203         goto cleanup;
1204
1205     hr = S_OK;
1206 cleanup:
1207     IDirectDraw7_Release(pDirectDraw);
1208     return hr;
1209 }
1210
1211 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
1212 {
1213     static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
1214     static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e','D','e','v','i','c','e','s',0};
1215
1216     IDxDiagContainerImpl_Container *cont;
1217
1218     cont = allocate_information_node(DxDiag_SoundDevices);
1219     if (!cont)
1220         return E_OUTOFMEMORY;
1221
1222     add_subcontainer(node, cont);
1223
1224     cont = allocate_information_node(DxDiag_SoundCaptureDevices);
1225     if (!cont)
1226         return E_OUTOFMEMORY;
1227
1228     add_subcontainer(node, cont);
1229
1230     return S_OK;
1231 }
1232
1233 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
1234 {
1235     return S_OK;
1236 }
1237
1238 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
1239 {
1240     return S_OK;
1241 }
1242
1243 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
1244 {
1245     return S_OK;
1246 }
1247
1248 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
1249 {
1250     return S_OK;
1251 }
1252
1253 static HRESULT fill_file_description(IDxDiagContainerImpl_Container *node, const WCHAR *szFilePath, const WCHAR *szFileName)
1254 {
1255     static const WCHAR szSlashSep[] = {'\\',0};
1256     static const WCHAR szPath[] = {'s','z','P','a','t','h',0};
1257     static const WCHAR szName[] = {'s','z','N','a','m','e',0};
1258     static const WCHAR szVersion[] = {'s','z','V','e','r','s','i','o','n',0};
1259     static const WCHAR szAttributes[] = {'s','z','A','t','t','r','i','b','u','t','e','s',0};
1260     static const WCHAR szLanguageEnglish[] = {'s','z','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
1261     static const WCHAR dwFileTimeHigh[] = {'d','w','F','i','l','e','T','i','m','e','H','i','g','h',0};
1262     static const WCHAR dwFileTimeLow[] = {'d','w','F','i','l','e','T','i','m','e','L','o','w',0};
1263     static const WCHAR bBeta[] = {'b','B','e','t','a',0};
1264     static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
1265     static const WCHAR bExists[] = {'b','E','x','i','s','t','s',0};
1266
1267     /* Values */
1268     static const WCHAR szFinal_Retail_v[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
1269     static const WCHAR szEnglish_v[] = {'E','n','g','l','i','s','h',0};
1270     static const WCHAR szVersionFormat[] = {'%','u','.','%','0','2','u','.','%','0','4','u','.','%','0','4','u',0};
1271
1272     HRESULT hr;
1273     WCHAR *szFile;
1274     WCHAR szVersion_v[1024];
1275     DWORD retval, hdl;
1276     void *pVersionInfo = NULL;
1277     BOOL boolret = FALSE;
1278     UINT uiLength;
1279     VS_FIXEDFILEINFO *pFileInfo;
1280
1281     szFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(szFilePath) +
1282                                             lstrlenW(szFileName) + 2 /* slash + terminator */));
1283     if (!szFile)
1284         return E_OUTOFMEMORY;
1285
1286     lstrcpyW(szFile, szFilePath);
1287     lstrcatW(szFile, szSlashSep);
1288     lstrcatW(szFile, szFileName);
1289
1290     retval = GetFileVersionInfoSizeW(szFile, &hdl);
1291     if (retval)
1292     {
1293         pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
1294         if (!pVersionInfo)
1295         {
1296             hr = E_OUTOFMEMORY;
1297             goto cleanup;
1298         }
1299
1300         if (GetFileVersionInfoW(szFile, 0, retval, pVersionInfo) &&
1301             VerQueryValueW(pVersionInfo, szSlashSep, (void **)&pFileInfo, &uiLength))
1302             boolret = TRUE;
1303     }
1304
1305     hr = add_bstr_property(node, szPath, szFile);
1306     if (FAILED(hr))
1307         goto cleanup;
1308
1309     hr = add_bstr_property(node, szName, szFileName);
1310     if (FAILED(hr))
1311         goto cleanup;
1312
1313     hr = add_bool_property(node, bExists, boolret);
1314     if (FAILED(hr))
1315         goto cleanup;
1316
1317     if (boolret)
1318     {
1319         snprintfW(szVersion_v, sizeof(szVersion_v)/sizeof(szVersion_v[0]),
1320                   szVersionFormat,
1321                   HIWORD(pFileInfo->dwFileVersionMS),
1322                   LOWORD(pFileInfo->dwFileVersionMS),
1323                   HIWORD(pFileInfo->dwFileVersionLS),
1324                   LOWORD(pFileInfo->dwFileVersionLS));
1325
1326         hr = add_bstr_property(node, szVersion, szVersion_v);
1327         if (FAILED(hr))
1328             goto cleanup;
1329
1330         hr = add_bstr_property(node, szAttributes, szFinal_Retail_v);
1331         if (FAILED(hr))
1332             goto cleanup;
1333
1334         hr = add_bstr_property(node, szLanguageEnglish, szEnglish_v);
1335         if (FAILED(hr))
1336             goto cleanup;
1337
1338         hr = add_ui4_property(node, dwFileTimeHigh, pFileInfo->dwFileDateMS);
1339         if (FAILED(hr))
1340             goto cleanup;
1341
1342         hr = add_ui4_property(node, dwFileTimeLow, pFileInfo->dwFileDateLS);
1343         if (FAILED(hr))
1344             goto cleanup;
1345
1346         hr = add_bool_property(node, bBeta, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
1347         if (FAILED(hr))
1348             goto cleanup;
1349
1350         hr = add_bool_property(node, bDebug, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
1351         if (FAILED(hr))
1352             goto cleanup;
1353     }
1354
1355     hr = S_OK;
1356 cleanup:
1357     HeapFree(GetProcessHeap(), 0, pVersionInfo);
1358     HeapFree(GetProcessHeap(), 0, szFile);
1359
1360     return hr;
1361 }
1362 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1363 {
1364     static const WCHAR dlls[][15] =
1365     {
1366         {'d','3','d','8','.','d','l','l',0},
1367         {'d','3','d','9','.','d','l','l',0},
1368         {'d','d','r','a','w','.','d','l','l',0},
1369         {'d','e','v','e','n','u','m','.','d','l','l',0},
1370         {'d','i','n','p','u','t','8','.','d','l','l',0},
1371         {'d','i','n','p','u','t','.','d','l','l',0},
1372         {'d','m','b','a','n','d','.','d','l','l',0},
1373         {'d','m','c','o','m','p','o','s','.','d','l','l',0},
1374         {'d','m','i','m','e','.','d','l','l',0},
1375         {'d','m','l','o','a','d','e','r','.','d','l','l',0},
1376         {'d','m','s','c','r','i','p','t','.','d','l','l',0},
1377         {'d','m','s','t','y','l','e','.','d','l','l',0},
1378         {'d','m','s','y','n','t','h','.','d','l','l',0},
1379         {'d','m','u','s','i','c','.','d','l','l',0},
1380         {'d','p','l','a','y','x','.','d','l','l',0},
1381         {'d','p','n','e','t','.','d','l','l',0},
1382         {'d','s','o','u','n','d','.','d','l','l',0},
1383         {'d','s','w','a','v','e','.','d','l','l',0},
1384         {'d','x','d','i','a','g','n','.','d','l','l',0},
1385         {'q','u','a','r','t','z','.','d','l','l',0}
1386     };
1387
1388     HRESULT hr;
1389     WCHAR szFilePath[MAX_PATH];
1390     INT i;
1391
1392     GetSystemDirectoryW(szFilePath, MAX_PATH);
1393
1394     for (i = 0; i < sizeof(dlls) / sizeof(dlls[0]); i++)
1395     {
1396         static const WCHAR szFormat[] = {'%','d',0};
1397
1398         WCHAR szFileID[5];
1399         IDxDiagContainerImpl_Container *file_container;
1400
1401         snprintfW(szFileID, sizeof(szFileID)/sizeof(szFileID[0]), szFormat, i);
1402
1403         file_container = allocate_information_node(szFileID);
1404         if (!file_container)
1405             return E_OUTOFMEMORY;
1406
1407         hr = fill_file_description(file_container, szFilePath, dlls[i]);
1408         if (FAILED(hr))
1409         {
1410             free_information_tree(file_container);
1411             continue;
1412         }
1413
1414         add_subcontainer(node, file_container);
1415     }
1416
1417     return S_OK;
1418 }
1419
1420 static HRESULT read_property_names(IPropertyBag *pPropBag, VARIANT *friendly_name, VARIANT *clsid_name)
1421 {
1422     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
1423     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
1424
1425     HRESULT hr;
1426
1427     VariantInit(friendly_name);
1428     VariantInit(clsid_name);
1429
1430     hr = IPropertyBag_Read(pPropBag, wszFriendlyName, friendly_name, 0);
1431     if (FAILED(hr))
1432         return hr;
1433
1434     hr = IPropertyBag_Read(pPropBag, wszClsidName, clsid_name, 0);
1435     if (FAILED(hr))
1436     {
1437         VariantClear(friendly_name);
1438         return hr;
1439     }
1440
1441     return S_OK;
1442 }
1443
1444 static HRESULT fill_filter_data_information(IDxDiagContainerImpl_Container *subcont, BYTE *pData, ULONG cb)
1445 {
1446     static const WCHAR szVersionW[] = {'s','z','V','e','r','s','i','o','n',0};
1447     static const WCHAR dwInputs[] = {'d','w','I','n','p','u','t','s',0};
1448     static const WCHAR dwOutputs[] = {'d','w','O','u','t','p','u','t','s',0};
1449     static const WCHAR dwMeritW[] = {'d','w','M','e','r','i','t',0};
1450     static const WCHAR szVersionFormat[] = {'v','%','d',0};
1451
1452     HRESULT hr;
1453     IFilterMapper2 *pFileMapper = NULL;
1454     IAMFilterData *pFilterData = NULL;
1455     REGFILTER2 *pRF = NULL;
1456     WCHAR bufferW[10];
1457     ULONG j;
1458     DWORD dwNOutputs = 0;
1459     DWORD dwNInputs = 0;
1460
1461     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
1462                           (void **)&pFileMapper);
1463     if (FAILED(hr))
1464         return hr;
1465
1466     hr = IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData);
1467     if (FAILED(hr))
1468         goto cleanup;
1469
1470     hr = IAMFilterData_ParseFilterData(pFilterData, pData, cb, (BYTE **)&pRF);
1471     if (FAILED(hr))
1472         goto cleanup;
1473
1474     snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szVersionFormat, pRF->dwVersion);
1475     hr = add_bstr_property(subcont, szVersionW, bufferW);
1476     if (FAILED(hr))
1477         goto cleanup;
1478
1479     if (pRF->dwVersion == 1)
1480     {
1481         for (j = 0; j < pRF->u.s.cPins; j++)
1482             if (pRF->u.s.rgPins[j].bOutput)
1483                 dwNOutputs++;
1484             else
1485                 dwNInputs++;
1486     }
1487     else if (pRF->dwVersion == 2)
1488     {
1489         for (j = 0; j < pRF->u.s1.cPins2; j++)
1490             if (pRF->u.s1.rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
1491                 dwNOutputs++;
1492             else
1493                 dwNInputs++;
1494     }
1495
1496     hr = add_ui4_property(subcont, dwInputs, dwNInputs);
1497     if (FAILED(hr))
1498         goto cleanup;
1499
1500     hr = add_ui4_property(subcont, dwOutputs, dwNOutputs);
1501     if (FAILED(hr))
1502         goto cleanup;
1503
1504     hr = add_ui4_property(subcont, dwMeritW, pRF->dwMerit);
1505     if (FAILED(hr))
1506         goto cleanup;
1507
1508     hr = S_OK;
1509 cleanup:
1510     CoTaskMemFree(pRF);
1511     if (pFilterData) IAMFilterData_Release(pFilterData);
1512     if (pFileMapper) IFilterMapper2_Release(pFileMapper);
1513
1514     return hr;
1515 }
1516
1517 static HRESULT fill_filter_container(IDxDiagContainerImpl_Container *subcont, IMoniker *pMoniker)
1518 {
1519     static const WCHAR szName[] = {'s','z','N','a','m','e',0};
1520     static const WCHAR ClsidFilterW[] = {'C','l','s','i','d','F','i','l','t','e','r',0};
1521     static const WCHAR wszFilterDataName[] = {'F','i','l','t','e','r','D','a','t','a',0};
1522
1523     HRESULT hr;
1524     IPropertyBag *pPropFilterBag = NULL;
1525     BYTE *pData;
1526     VARIANT friendly_name;
1527     VARIANT clsid_name;
1528     VARIANT v;
1529
1530     VariantInit(&friendly_name);
1531     VariantInit(&clsid_name);
1532     VariantInit(&v);
1533
1534     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void **)&pPropFilterBag);
1535     if (FAILED(hr))
1536         return hr;
1537
1538     hr = read_property_names(pPropFilterBag, &friendly_name, &clsid_name);
1539     if (FAILED(hr))
1540         goto cleanup;
1541
1542     hr = add_bstr_property(subcont, szName, V_BSTR(&friendly_name));
1543     if (FAILED(hr))
1544         goto cleanup;
1545
1546     hr = add_bstr_property(subcont, ClsidFilterW, V_BSTR(&clsid_name));
1547     if (FAILED(hr))
1548         goto cleanup;
1549
1550     hr = IPropertyBag_Read(pPropFilterBag, wszFilterDataName, &v, NULL);
1551     if (FAILED(hr))
1552         goto cleanup;
1553
1554     hr = SafeArrayAccessData(V_ARRAY(&v), (void **)&pData);
1555     if (FAILED(hr))
1556         goto cleanup;
1557
1558     hr = fill_filter_data_information(subcont, pData, V_ARRAY(&v)->rgsabound->cElements);
1559     SafeArrayUnaccessData(V_ARRAY(&v));
1560     if (FAILED(hr))
1561         goto cleanup;
1562
1563     hr = S_OK;
1564 cleanup:
1565     VariantClear(&v);
1566     VariantClear(&clsid_name);
1567     VariantClear(&friendly_name);
1568     if (pPropFilterBag) IPropertyBag_Release(pPropFilterBag);
1569
1570     return hr;
1571 }
1572
1573 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1574 {
1575     static const WCHAR szCatName[] = {'s','z','C','a','t','N','a','m','e',0};
1576     static const WCHAR ClsidCatW[] = {'C','l','s','i','d','C','a','t',0};
1577     static const WCHAR szIdFormat[] = {'%','d',0};
1578
1579     HRESULT hr;
1580     int i = 0;
1581     ICreateDevEnum *pCreateDevEnum;
1582     IEnumMoniker *pEmCat = NULL;
1583     IMoniker *pMCat = NULL;
1584         IEnumMoniker *pEnum = NULL;
1585
1586     hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1587                           &IID_ICreateDevEnum, (void **)&pCreateDevEnum);
1588     if (FAILED(hr))
1589         return hr;
1590
1591     hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
1592     if (FAILED(hr))
1593         goto cleanup;
1594
1595     while (IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL) == S_OK)
1596     {
1597         VARIANT vCatName;
1598         VARIANT vCatClsid;
1599         IPropertyBag *pPropBag;
1600         CLSID clsidCat;
1601         IMoniker *pMoniker = NULL;
1602
1603         hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void **)&pPropBag);
1604         if (FAILED(hr))
1605         {
1606             IMoniker_Release(pMCat);
1607             break;
1608         }
1609
1610         hr = read_property_names(pPropBag, &vCatName, &vCatClsid);
1611         IPropertyBag_Release(pPropBag);
1612         if (FAILED(hr))
1613         {
1614             IMoniker_Release(pMCat);
1615             break;
1616         }
1617
1618         hr = CLSIDFromString(V_BSTR(&vCatClsid), &clsidCat);
1619         if (FAILED(hr))
1620         {
1621             IMoniker_Release(pMCat);
1622             VariantClear(&vCatClsid);
1623             VariantClear(&vCatName);
1624             break;
1625         }
1626
1627         hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1628         if (hr != S_OK)
1629         {
1630             IMoniker_Release(pMCat);
1631             VariantClear(&vCatClsid);
1632             VariantClear(&vCatName);
1633             continue;
1634         }
1635
1636         while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1637         {
1638             WCHAR bufferW[10];
1639             IDxDiagContainerImpl_Container *subcont;
1640
1641             snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szIdFormat, i);
1642             subcont = allocate_information_node(bufferW);
1643             if (!subcont)
1644             {
1645                 hr = E_OUTOFMEMORY;
1646                 IMoniker_Release(pMoniker);
1647                 break;
1648             }
1649
1650             hr = add_bstr_property(subcont, szCatName, V_BSTR(&vCatName));
1651             if (FAILED(hr))
1652             {
1653                 free_information_tree(subcont);
1654                 IMoniker_Release(pMoniker);
1655                 break;
1656             }
1657
1658             hr = add_bstr_property(subcont, ClsidCatW, V_BSTR(&vCatClsid));
1659             if (FAILED(hr))
1660             {
1661                 free_information_tree(subcont);
1662                 IMoniker_Release(pMoniker);
1663                 break;
1664             }
1665
1666             hr = fill_filter_container(subcont, pMoniker);
1667             if (FAILED(hr))
1668             {
1669                 free_information_tree(subcont);
1670                 IMoniker_Release(pMoniker);
1671                 break;
1672             }
1673
1674             add_subcontainer(node, subcont);
1675             i++;
1676             IMoniker_Release(pMoniker);
1677         }
1678
1679         IEnumMoniker_Release(pEnum);
1680         IMoniker_Release(pMCat);
1681         VariantClear(&vCatClsid);
1682         VariantClear(&vCatName);
1683
1684         if (FAILED(hr))
1685             break;
1686     }
1687
1688 cleanup:
1689     if (pEmCat) IEnumMoniker_Release(pEmCat);
1690     ICreateDevEnum_Release(pCreateDevEnum);
1691     return hr;
1692 }
1693
1694 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1695 {
1696     return S_OK;
1697 }
1698
1699 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1700 {
1701     static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
1702     static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
1703     static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
1704     static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
1705     static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
1706     static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
1707     static const WCHAR DxDiag_SystemDevices[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','D','e','v','i','c','e','s',0};
1708     static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
1709     static const WCHAR DxDiag_DirectShowFilters[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','h','o','w','F','i','l','t','e','r','s',0};
1710     static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
1711
1712     static const struct
1713     {
1714         const WCHAR *name;
1715         HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1716     } root_children[] =
1717     {
1718         {DxDiag_SystemInfo, build_systeminfo_tree},
1719         {DxDiag_DisplayDevices, build_displaydevices_tree},
1720         {DxDiag_DirectSound, build_directsound_tree},
1721         {DxDiag_DirectMusic, build_directmusic_tree},
1722         {DxDiag_DirectInput, build_directinput_tree},
1723         {DxDiag_DirectPlay, build_directplay_tree},
1724         {DxDiag_SystemDevices, build_systemdevices_tree},
1725         {DxDiag_DirectXFiles, build_directxfiles_tree},
1726         {DxDiag_DirectShowFilters, build_directshowfilters_tree},
1727         {DxDiag_LogicalDisks, build_logicaldisks_tree},
1728     };
1729
1730     IDxDiagContainerImpl_Container *info_root;
1731     size_t index;
1732
1733     info_root = allocate_information_node(NULL);
1734     if (!info_root)
1735         return E_OUTOFMEMORY;
1736
1737     for (index = 0; index < sizeof(root_children)/sizeof(root_children[0]); index++)
1738     {
1739         IDxDiagContainerImpl_Container *node;
1740         HRESULT hr;
1741
1742         node = allocate_information_node(root_children[index].name);
1743         if (!node)
1744         {
1745             free_information_tree(info_root);
1746             return E_OUTOFMEMORY;
1747         }
1748
1749         hr = root_children[index].initfunc(node);
1750         if (FAILED(hr))
1751         {
1752             free_information_tree(node);
1753             free_information_tree(info_root);
1754             return hr;
1755         }
1756
1757         add_subcontainer(info_root, node);
1758     }
1759
1760     *pinfo_root = info_root;
1761     return S_OK;
1762 }