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