dxdiagn: Add code that populates the DxDiag_SystemInfo 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     return S_OK;
1092 }
1093
1094 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
1095 {
1096     return S_OK;
1097 }
1098
1099 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
1100 {
1101     return S_OK;
1102 }
1103
1104 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
1105 {
1106     return S_OK;
1107 }
1108
1109 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
1110 {
1111     return S_OK;
1112 }
1113
1114 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
1115 {
1116     return S_OK;
1117 }
1118
1119 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1120 {
1121     return S_OK;
1122 }
1123
1124 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1125 {
1126     return S_OK;
1127 }
1128
1129 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1130 {
1131     return S_OK;
1132 }
1133
1134 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1135 {
1136     static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
1137     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};
1138     static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
1139     static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
1140     static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
1141     static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
1142     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};
1143     static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
1144     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};
1145     static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
1146
1147     static const struct
1148     {
1149         const WCHAR *name;
1150         HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1151     } root_children[] =
1152     {
1153         {DxDiag_SystemInfo, build_systeminfo_tree},
1154         {DxDiag_DisplayDevices, build_displaydevices_tree},
1155         {DxDiag_DirectSound, build_directsound_tree},
1156         {DxDiag_DirectMusic, build_directmusic_tree},
1157         {DxDiag_DirectInput, build_directinput_tree},
1158         {DxDiag_DirectPlay, build_directplay_tree},
1159         {DxDiag_SystemDevices, build_systemdevices_tree},
1160         {DxDiag_DirectXFiles, build_directxfiles_tree},
1161         {DxDiag_DirectShowFilters, build_directshowfilters_tree},
1162         {DxDiag_LogicalDisks, build_logicaldisks_tree},
1163     };
1164
1165     IDxDiagContainerImpl_Container *info_root;
1166     size_t index;
1167
1168     info_root = allocate_information_node(NULL);
1169     if (!info_root)
1170         return E_OUTOFMEMORY;
1171
1172     for (index = 0; index < sizeof(root_children)/sizeof(root_children[0]); index++)
1173     {
1174         IDxDiagContainerImpl_Container *node;
1175         HRESULT hr;
1176
1177         node = allocate_information_node(root_children[index].name);
1178         if (!node)
1179         {
1180             free_information_tree(info_root);
1181             return E_OUTOFMEMORY;
1182         }
1183
1184         hr = root_children[index].initfunc(node);
1185         if (FAILED(hr))
1186         {
1187             free_information_tree(node);
1188             free_information_tree(info_root);
1189             return hr;
1190         }
1191
1192         add_subcontainer(info_root, node);
1193     }
1194
1195     *pinfo_root = info_root;
1196     return S_OK;
1197 }