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