dxdiagn: Stub out some properties for dxdiag.exe.
[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 "dshow.h"
33 #include "vfw.h"
34 #include "mmddk.h"
35 #include "ddraw.h"
36 #include "d3d9.h"
37 #include "strmif.h"
38 #include "initguid.h"
39 #include "fil_data.h"
40 #include "psapi.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 /* IDxDiagProvider IUnknown parts follow: */
52 static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(PDXDIAGPROVIDER iface, REFIID riid, LPVOID *ppobj)
53 {
54     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
55
56     if (!ppobj) return E_INVALIDARG;
57
58     if (IsEqualGUID(riid, &IID_IUnknown)
59         || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
60         IUnknown_AddRef(iface);
61         *ppobj = This;
62         return S_OK;
63     }
64
65     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
66     *ppobj = NULL;
67     return E_NOINTERFACE;
68 }
69
70 static ULONG WINAPI IDxDiagProviderImpl_AddRef(PDXDIAGPROVIDER iface) {
71     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
72     ULONG refCount = InterlockedIncrement(&This->ref);
73
74     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
75
76     DXDIAGN_LockModule();
77
78     return refCount;
79 }
80
81 static ULONG WINAPI IDxDiagProviderImpl_Release(PDXDIAGPROVIDER iface) {
82     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
83     ULONG refCount = InterlockedDecrement(&This->ref);
84
85     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
86
87     if (!refCount) {
88         free_information_tree(This->info_root);
89         HeapFree(GetProcessHeap(), 0, This);
90     }
91
92     DXDIAGN_UnlockModule();
93     
94     return refCount;
95 }
96
97 /* IDxDiagProvider Interface follow: */
98 static HRESULT WINAPI IDxDiagProviderImpl_Initialize(PDXDIAGPROVIDER iface, DXDIAG_INIT_PARAMS* pParams) {
99     IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
100     HRESULT hr;
101
102     TRACE("(%p,%p)\n", iface, pParams);
103
104     if (NULL == pParams) {
105       return E_POINTER;
106     }
107     if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS) ||
108         pParams->dwDxDiagHeaderVersion != DXDIAG_DX9_SDK_VERSION) {
109       return E_INVALIDARG;
110     }
111
112     if (!This->info_root)
113     {
114         hr = build_information_tree(&This->info_root);
115         if (FAILED(hr))
116             return hr;
117     }
118
119     This->init = TRUE;
120     memcpy(&This->params, pParams, pParams->dwSize);
121     return S_OK;
122 }
123
124 static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(PDXDIAGPROVIDER iface, IDxDiagContainer** ppInstance) {
125   IDxDiagProviderImpl *This = (IDxDiagProviderImpl *)iface;
126
127   TRACE("(%p,%p)\n", iface, ppInstance);
128
129   if (FALSE == This->init) {
130     return CO_E_NOTINITIALIZED;
131   }
132
133   return DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, This->info_root,
134                                       (IDxDiagProvider *)This, (void **)ppInstance);
135 }
136
137 static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
138 {
139     IDxDiagProviderImpl_QueryInterface,
140     IDxDiagProviderImpl_AddRef,
141     IDxDiagProviderImpl_Release,
142     IDxDiagProviderImpl_Initialize,
143     IDxDiagProviderImpl_GetRootContainer
144 };
145
146 HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
147   IDxDiagProviderImpl* provider;
148
149   TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
150
151   *ppobj = NULL;
152   if (punkOuter) return CLASS_E_NOAGGREGATION;
153
154   provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
155   if (NULL == provider) return E_OUTOFMEMORY;
156   provider->lpVtbl = &DxDiagProvider_Vtbl;
157   provider->ref = 0; /* will be inited with QueryInterface */
158   return IDxDiagProviderImpl_QueryInterface ((PDXDIAGPROVIDER)provider, riid, ppobj);
159 }
160
161 static void get_display_device_id(WCHAR *szIdentifierBuffer)
162 {
163     static const WCHAR szNA[] = {'n','/','a',0};
164
165     HRESULT hr = E_FAIL;
166
167     HMODULE                 d3d9_handle;
168     IDirect3D9             *(WINAPI *pDirect3DCreate9)(UINT) = NULL;
169     IDirect3D9             *pD3d = NULL;
170     D3DADAPTER_IDENTIFIER9  adapter_ident;
171
172     /* Retrieves the display device identifier from the d3d9 implementation. */
173     d3d9_handle = LoadLibraryA("d3d9.dll");
174     if(d3d9_handle)
175         pDirect3DCreate9 = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
176     if(pDirect3DCreate9)
177         pD3d = pDirect3DCreate9(D3D_SDK_VERSION);
178     if(pD3d)
179         hr = IDirect3D9_GetAdapterIdentifier(pD3d, D3DADAPTER_DEFAULT, 0, &adapter_ident);
180     if(SUCCEEDED(hr)) {
181         StringFromGUID2(&adapter_ident.DeviceIdentifier, szIdentifierBuffer, 39);
182     } else {
183         memcpy(szIdentifierBuffer, szNA, sizeof(szNA));
184     }
185
186     if (pD3d)
187         IDirect3D9_Release(pD3d);
188     if (d3d9_handle)
189         FreeLibrary(d3d9_handle);
190 }
191
192 static void free_property_information(IDxDiagContainerImpl_Property *prop)
193 {
194     VariantClear(&prop->vProp);
195     HeapFree(GetProcessHeap(), 0, prop->propName);
196     HeapFree(GetProcessHeap(), 0, prop);
197 }
198
199 static void free_information_tree(IDxDiagContainerImpl_Container *node)
200 {
201     IDxDiagContainerImpl_Container *ptr, *cursor2;
202
203     if (!node)
204         return;
205
206     HeapFree(GetProcessHeap(), 0, node->contName);
207
208     LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &node->subContainers, IDxDiagContainerImpl_Container, entry)
209     {
210         IDxDiagContainerImpl_Property *prop, *prop_cursor2;
211
212         LIST_FOR_EACH_ENTRY_SAFE(prop, prop_cursor2, &ptr->properties, IDxDiagContainerImpl_Property, entry)
213         {
214             list_remove(&prop->entry);
215             free_property_information(prop);
216         }
217
218         list_remove(&ptr->entry);
219         free_information_tree(ptr);
220     }
221
222     HeapFree(GetProcessHeap(), 0, node);
223 }
224
225 static IDxDiagContainerImpl_Container *allocate_information_node(const WCHAR *name)
226 {
227     IDxDiagContainerImpl_Container *ret;
228
229     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
230     if (!ret)
231         return NULL;
232
233     if (name)
234     {
235         ret->contName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
236         if (!ret->contName)
237         {
238             HeapFree(GetProcessHeap(), 0, ret);
239             return NULL;
240         }
241         strcpyW(ret->contName, name);
242     }
243
244     list_init(&ret->subContainers);
245     list_init(&ret->properties);
246
247     return ret;
248 }
249
250 static IDxDiagContainerImpl_Property *allocate_property_information(const WCHAR *name)
251 {
252     IDxDiagContainerImpl_Property *ret;
253
254     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
255     if (!ret)
256         return NULL;
257
258     ret->propName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
259     if (!ret->propName)
260     {
261         HeapFree(GetProcessHeap(), 0, ret);
262         return NULL;
263     }
264     strcpyW(ret->propName, name);
265
266     return ret;
267 }
268
269 static inline void add_subcontainer(IDxDiagContainerImpl_Container *node, IDxDiagContainerImpl_Container *subCont)
270 {
271     list_add_tail(&node->subContainers, &subCont->entry);
272     ++node->nSubContainers;
273 }
274
275 static inline HRESULT add_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, const WCHAR *str)
276 {
277     IDxDiagContainerImpl_Property *prop;
278     BSTR bstr;
279
280     prop = allocate_property_information(propName);
281     if (!prop)
282         return E_OUTOFMEMORY;
283
284     bstr = SysAllocString(str);
285     if (!bstr)
286     {
287         free_property_information(prop);
288         return E_OUTOFMEMORY;
289     }
290
291     V_VT(&prop->vProp) = VT_BSTR;
292     V_BSTR(&prop->vProp) = bstr;
293
294     list_add_tail(&node->properties, &prop->entry);
295     ++node->nProperties;
296
297     return S_OK;
298 }
299
300 static inline HRESULT add_ui4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, DWORD data)
301 {
302     IDxDiagContainerImpl_Property *prop;
303
304     prop = allocate_property_information(propName);
305     if (!prop)
306         return E_OUTOFMEMORY;
307
308     V_VT(&prop->vProp) = VT_UI4;
309     V_UI4(&prop->vProp) = data;
310
311     list_add_tail(&node->properties, &prop->entry);
312     ++node->nProperties;
313
314     return S_OK;
315 }
316
317 static inline HRESULT add_bool_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, BOOL data)
318 {
319     IDxDiagContainerImpl_Property *prop;
320
321     prop = allocate_property_information(propName);
322     if (!prop)
323         return E_OUTOFMEMORY;
324
325     V_VT(&prop->vProp) = VT_BOOL;
326     V_BOOL(&prop->vProp) = data;
327
328     list_add_tail(&node->properties, &prop->entry);
329     ++node->nProperties;
330
331     return S_OK;
332 }
333
334 static inline HRESULT add_ull_as_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, ULONGLONG data )
335 {
336     IDxDiagContainerImpl_Property *prop;
337
338     prop = allocate_property_information(propName);
339     if (!prop)
340         return E_OUTOFMEMORY;
341
342     V_VT(&prop->vProp) = VT_UI8;
343     V_UI8(&prop->vProp) = data;
344
345     VariantChangeType(&prop->vProp, &prop->vProp, 0, VT_BSTR);
346
347     list_add_tail(&node->properties, &prop->entry);
348     ++node->nProperties;
349
350     return S_OK;
351 }
352
353 /* Copied from programs/taskkill/taskkill.c. */
354 static DWORD *enumerate_processes(DWORD *list_count)
355 {
356     DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes;
357
358     pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes);
359     if (!pid_list)
360         return NULL;
361
362     for (;;)
363     {
364         DWORD *realloc_list;
365
366         if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes))
367         {
368             HeapFree(GetProcessHeap(), 0, pid_list);
369             return NULL;
370         }
371
372         /* EnumProcesses can't signal an insufficient buffer condition, so the
373          * only way to possibly determine whether a larger buffer is required
374          * is to see whether the written number of bytes is the same as the
375          * buffer size. If so, the buffer will be reallocated to twice the
376          * size. */
377         if (alloc_bytes != needed_bytes)
378             break;
379
380         alloc_bytes *= 2;
381         realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes);
382         if (!realloc_list)
383         {
384             HeapFree(GetProcessHeap(), 0, pid_list);
385             return NULL;
386         }
387         pid_list = realloc_list;
388     }
389
390     *list_count = needed_bytes / sizeof(*pid_list);
391     return pid_list;
392 }
393
394 /* Copied from programs/taskkill/taskkill.c. */
395 static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars)
396 {
397     HANDLE process;
398     HMODULE module;
399     DWORD required_size;
400
401     process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
402     if (!process)
403         return FALSE;
404
405     if (!EnumProcessModules(process, &module, sizeof(module), &required_size))
406     {
407         CloseHandle(process);
408         return FALSE;
409     }
410
411     if (!GetModuleBaseNameW(process, module, buf, chars))
412     {
413         CloseHandle(process);
414         return FALSE;
415     }
416
417     CloseHandle(process);
418     return TRUE;
419 }
420
421 /* dxdiagn's detection scheme is simply to look for a process called conf.exe. */
422 static BOOL is_netmeeting_running(void)
423 {
424     static const WCHAR conf_exe[] = {'c','o','n','f','.','e','x','e',0};
425
426     DWORD list_count;
427     DWORD *pid_list = enumerate_processes(&list_count);
428
429     if (pid_list)
430     {
431         DWORD i;
432         WCHAR process_name[MAX_PATH];
433
434         for (i = 0; i < list_count; i++)
435         {
436             if (get_process_name_from_pid(pid_list[i], process_name, sizeof(process_name)/sizeof(WCHAR)) &&
437                 !lstrcmpW(conf_exe, process_name))
438             {
439                 HeapFree(GetProcessHeap(), 0, pid_list);
440                 return TRUE;
441             }
442         }
443         HeapFree(GetProcessHeap(), 0, pid_list);
444     }
445
446     return FALSE;
447 }
448
449 static HRESULT fill_language_information(IDxDiagContainerImpl_Container *node)
450 {
451     static const WCHAR regional_setting_engW[] = {'R','e','g','i','o','n','a','l',' ','S','e','t','t','i','n','g',0};
452     static const WCHAR languages_fmtW[] = {'%','s',' ','(','%','s',':',' ','%','s',')',0};
453     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};
454     static const WCHAR szLanguagesEnglish[] = {'s','z','L','a','n','g','u','a','g','e','s','E','n','g','l','i','s','h',0};
455
456     WCHAR system_lang[80], regional_setting[100], user_lang[80], language_str[300];
457     HRESULT hr;
458
459     /* szLanguagesLocalized */
460     GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SNATIVELANGNAME, system_lang, sizeof(system_lang)/sizeof(WCHAR));
461     LoadStringW(dxdiagn_instance, IDS_REGIONAL_SETTING, regional_setting, sizeof(regional_setting)/sizeof(WCHAR));
462     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, user_lang, sizeof(user_lang)/sizeof(WCHAR));
463
464     snprintfW(language_str, sizeof(language_str)/sizeof(WCHAR), languages_fmtW, system_lang, regional_setting, user_lang);
465
466     hr = add_bstr_property(node, szLanguagesLocalized, language_str);
467     if (FAILED(hr))
468         return hr;
469
470     /* szLanguagesEnglish */
471     GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, system_lang, sizeof(system_lang)/sizeof(WCHAR));
472     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, user_lang, sizeof(user_lang)/sizeof(WCHAR));
473
474     snprintfW(language_str, sizeof(language_str)/sizeof(WCHAR), languages_fmtW, system_lang, regional_setting_engW, user_lang);
475
476     hr = add_bstr_property(node, szLanguagesEnglish, language_str);
477     if (FAILED(hr))
478         return hr;
479
480     return S_OK;
481 }
482
483 static HRESULT fill_datetime_information(IDxDiagContainerImpl_Container *node)
484 {
485     static const WCHAR date_fmtW[] = {'M','\'','/','\'','d','\'','/','\'','y','y','y','y',0};
486     static const WCHAR time_fmtW[] = {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
487     static const WCHAR datetime_fmtW[] = {'%','s',',',' ','%','s',0};
488     static const WCHAR szTimeLocalized[] = {'s','z','T','i','m','e','L','o','c','a','l','i','z','e','d',0};
489     static const WCHAR szTimeEnglish[] = {'s','z','T','i','m','e','E','n','g','l','i','s','h',0};
490
491     SYSTEMTIME curtime;
492     WCHAR date_str[80], time_str[80], datetime_str[200];
493     HRESULT hr;
494
495     GetLocalTime(&curtime);
496
497     GetTimeFormatW(LOCALE_NEUTRAL, 0, &curtime, time_fmtW, time_str, sizeof(time_str)/sizeof(WCHAR));
498
499     /* szTimeLocalized */
500     GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &curtime, NULL, date_str, sizeof(date_str)/sizeof(WCHAR));
501
502     snprintfW(datetime_str, sizeof(datetime_str)/sizeof(WCHAR), datetime_fmtW, date_str, time_str);
503
504     hr = add_bstr_property(node, szTimeLocalized, datetime_str);
505     if (FAILED(hr))
506         return hr;
507
508     /* szTimeEnglish */
509     GetDateFormatW(LOCALE_NEUTRAL, 0, &curtime, date_fmtW, 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, szTimeEnglish, datetime_str);
514     if (FAILED(hr))
515         return hr;
516
517     return S_OK;
518 }
519
520 static HRESULT fill_os_string_information(IDxDiagContainerImpl_Container *node, OSVERSIONINFOW *info)
521 {
522     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};
523     static const WCHAR szOSLocalized[] = {'s','z','O','S','L','o','c','a','l','i','z','e','d',0};
524     static const WCHAR szOSExLocalized[] = {'s','z','O','S','E','x','L','o','c','a','l','i','z','e','d',0};
525     static const WCHAR szOSExLongLocalized[] = {'s','z','O','S','E','x','L','o','n','g','L','o','c','a','l','i','z','e','d',0};
526     static const WCHAR szOSEnglish[] = {'s','z','O','S','E','n','g','l','i','s','h',0};
527     static const WCHAR szOSExEnglish[] = {'s','z','O','S','E','x','E','n','g','l','i','s','h',0};
528     static const WCHAR szOSExLongEnglish[] = {'s','z','O','S','E','x','L','o','n','g','E','n','g','l','i','s','h',0};
529
530     static const WCHAR *prop_list[] = {szOSLocalized, szOSExLocalized, szOSExLongLocalized,
531                                        szOSEnglish, szOSExEnglish, szOSExLongEnglish};
532
533     size_t i;
534     HRESULT hr;
535
536     /* FIXME: OS detection should be performed, and localized OS strings
537      * should contain translated versions of the "build" phrase. */
538     for (i = 0; i < sizeof(prop_list)/sizeof(prop_list[0]); i++)
539     {
540         hr = add_bstr_property(node, prop_list[i], winxpW);
541         if (FAILED(hr))
542             return hr;
543     }
544
545     return S_OK;
546 }
547
548 static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node)
549 {
550     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};
551     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};
552     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};
553     static const WCHAR szDirectXVersionLetter_v[] = {'c',0};
554     static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
555     static const WCHAR bNECPC98[] = {'b','N','E','C','P','C','9','8',0};
556     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};
557     static const WCHAR szDirectXVersionEnglish_v[] = {'4','.','0','9','.','0','0','0','0','.','0','9','0','4',0};
558     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};
559     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};
560     static const WCHAR ullPhysicalMemory[] = {'u','l','l','P','h','y','s','i','c','a','l','M','e','m','o','r','y',0};
561     static const WCHAR ullUsedPageFile[]   = {'u','l','l','U','s','e','d','P','a','g','e','F','i','l','e',0};
562     static const WCHAR ullAvailPageFile[]  = {'u','l','l','A','v','a','i','l','P','a','g','e','F','i','l','e',0};
563     static const WCHAR bNetMeetingRunning[] = {'b','N','e','t','M','e','e','t','i','n','g','R','u','n','n','i','n','g',0};
564     static const WCHAR szWindowsDir[] = {'s','z','W','i','n','d','o','w','s','D','i','r',0};
565     static const WCHAR dwOSMajorVersion[] = {'d','w','O','S','M','a','j','o','r','V','e','r','s','i','o','n',0};
566     static const WCHAR dwOSMinorVersion[] = {'d','w','O','S','M','i','n','o','r','V','e','r','s','i','o','n',0};
567     static const WCHAR dwOSBuildNumber[] = {'d','w','O','S','B','u','i','l','d','N','u','m','b','e','r',0};
568     static const WCHAR dwOSPlatformID[] = {'d','w','O','S','P','l','a','t','f','o','r','m','I','D',0};
569     static const WCHAR szCSDVersion[] = {'s','z','C','S','D','V','e','r','s','i','o','n',0};
570     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};
571     static const WCHAR szPageFileLocalized[] = {'s','z','P','a','g','e','F','i','l','e','L','o','c','a','l','i','z','e','d',0};
572     static const WCHAR szPageFileEnglish[] = {'s','z','P','a','g','e','F','i','l','e','E','n','g','l','i','s','h',0};
573     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};
574     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};
575     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};
576     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};
577     static const WCHAR szBIOSEnglish[] = {'s','z','B','I','O','S','E','n','g','l','i','s','h',0};
578     static const WCHAR szProcessorEnglish[] = {'s','z','P','r','o','c','e','s','s','o','r','E','n','g','l','i','s','h',0};
579     static const WCHAR szSetupParamEnglish[] = {'s','z','S','e','t','u','p','P','a','r','a','m','E','n','g','l','i','s','h',0};
580     static const WCHAR szDxDiagVersion[] = {'s','z','D','x','D','i','a','g','V','e','r','s','i','o','n',0};
581
582     static const WCHAR notpresentW[] = {'N','o','t',' ','p','r','e','s','e','n','t',0};
583
584     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};
585     static const WCHAR physmem_fmtW[] = {'%','u','M','B',' ','R','A','M',0};
586
587     HRESULT hr;
588     MEMORYSTATUSEX msex;
589     OSVERSIONINFOW info;
590     DWORD count, usedpage_mb, availpage_mb;
591     WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200];
592
593     hr = add_ui4_property(node, dwDirectXVersionMajor, 9);
594     if (FAILED(hr))
595         return hr;
596
597     hr = add_ui4_property(node, dwDirectXVersionMinor, 0);
598     if (FAILED(hr))
599         return hr;
600
601     hr = add_bstr_property(node, szDirectXVersionLetter, szDirectXVersionLetter_v);
602     if (FAILED(hr))
603         return hr;
604
605     hr = add_bstr_property(node, szDirectXVersionEnglish, szDirectXVersionEnglish_v);
606     if (FAILED(hr))
607         return hr;
608
609     hr = add_bstr_property(node, szDirectXVersionLongEnglish, szDirectXVersionLongEnglish_v);
610     if (FAILED(hr))
611         return hr;
612
613     hr = add_bool_property(node, bDebug, FALSE);
614     if (FAILED(hr))
615         return hr;
616
617     hr = add_bool_property(node, bNECPC98, FALSE);
618     if (FAILED(hr))
619         return hr;
620
621     msex.dwLength = sizeof(msex);
622     GlobalMemoryStatusEx(&msex);
623
624     hr = add_ull_as_bstr_property(node, ullPhysicalMemory, msex.ullTotalPhys);
625     if (FAILED(hr))
626         return hr;
627
628     hr = add_ull_as_bstr_property(node, ullUsedPageFile, msex.ullTotalPageFile - msex.ullAvailPageFile);
629     if (FAILED(hr))
630         return hr;
631
632     hr = add_ull_as_bstr_property(node, ullAvailPageFile, msex.ullAvailPageFile);
633     if (FAILED(hr))
634         return hr;
635
636     hr = add_bool_property(node, bNetMeetingRunning, is_netmeeting_running());
637     if (FAILED(hr))
638         return hr;
639
640     info.dwOSVersionInfoSize = sizeof(info);
641     GetVersionExW(&info);
642
643     hr = add_ui4_property(node, dwOSMajorVersion, info.dwMajorVersion);
644     if (FAILED(hr))
645         return hr;
646
647     hr = add_ui4_property(node, dwOSMinorVersion, info.dwMinorVersion);
648     if (FAILED(hr))
649         return hr;
650
651     hr = add_ui4_property(node, dwOSBuildNumber, info.dwBuildNumber);
652     if (FAILED(hr))
653         return hr;
654
655     hr = add_ui4_property(node, dwOSPlatformID, info.dwPlatformId);
656     if (FAILED(hr))
657         return hr;
658
659     hr = add_bstr_property(node, szCSDVersion, info.szCSDVersion);
660     if (FAILED(hr))
661         return hr;
662
663     /* FIXME: Roundoff should not be done with truncated division. */
664     snprintfW(print_buf, sizeof(print_buf)/sizeof(WCHAR), physmem_fmtW, (DWORD)(msex.ullTotalPhys / (1024 * 1024)));
665     hr = add_bstr_property(node, szPhysicalMemoryEnglish, print_buf);
666     if (FAILED(hr))
667         return hr;
668
669     usedpage_mb = (DWORD)((msex.ullTotalPageFile - msex.ullAvailPageFile) / (1024 * 1024));
670     availpage_mb = (DWORD)(msex.ullAvailPageFile / (1024 * 1024));
671     LoadStringW(dxdiagn_instance, IDS_PAGE_FILE_FORMAT, localized_pagefile_fmt, sizeof(localized_pagefile_fmt)/sizeof(WCHAR));
672     snprintfW(print_buf, sizeof(print_buf)/sizeof(WCHAR), localized_pagefile_fmt, usedpage_mb, availpage_mb);
673
674     hr = add_bstr_property(node, szPageFileLocalized, print_buf);
675     if (FAILED(hr))
676         return hr;
677
678     snprintfW(print_buf, sizeof(print_buf)/sizeof(WCHAR), pagefile_fmtW, usedpage_mb, availpage_mb);
679
680     hr = add_bstr_property(node, szPageFileEnglish, print_buf);
681     if (FAILED(hr))
682         return hr;
683
684     GetWindowsDirectoryW(buffer, MAX_PATH);
685
686     hr = add_bstr_property(node, szWindowsDir, buffer);
687     if (FAILED(hr))
688         return hr;
689
690     count = sizeof(computer_name)/sizeof(WCHAR);
691     if (!GetComputerNameW(computer_name, &count))
692         return E_FAIL;
693
694     hr = add_bstr_property(node, szMachineNameLocalized, computer_name);
695     if (FAILED(hr))
696         return hr;
697
698     hr = add_bstr_property(node, szMachineNameEnglish, computer_name);
699     if (FAILED(hr))
700         return hr;
701
702     hr = add_bstr_property(node, szSystemManufacturerEnglish, szEmpty);
703     if (FAILED(hr))
704         return hr;
705
706     hr = add_bstr_property(node, szSystemModelEnglish, szEmpty);
707     if (FAILED(hr))
708         return hr;
709
710     hr = add_bstr_property(node, szBIOSEnglish, szEmpty);
711     if (FAILED(hr))
712         return hr;
713
714     hr = add_bstr_property(node, szProcessorEnglish, szEmpty);
715     if (FAILED(hr))
716         return hr;
717
718     hr = add_bstr_property(node, szSetupParamEnglish, notpresentW);
719     if (FAILED(hr))
720         return hr;
721
722     hr = add_bstr_property(node, szDxDiagVersion, szEmpty);
723     if (FAILED(hr))
724         return hr;
725
726     hr = fill_language_information(node);
727     if (FAILED(hr))
728         return hr;
729
730     hr = fill_datetime_information(node);
731     if (FAILED(hr))
732         return hr;
733
734     hr = fill_os_string_information(node, &info);
735     if (FAILED(hr))
736         return hr;
737
738     return S_OK;
739 }
740
741 static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
742 {
743     static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
744     static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
745     static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
746     static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
747     static const WCHAR szVendorId[] = {'s','z','V','e','n','d','o','r','I','d',0};
748     static const WCHAR szDeviceId[] = {'s','z','D','e','v','i','c','e','I','d',0};
749     static const WCHAR szDeviceIdentifier[] = {'s','z','D','e','v','i','c','e','I','d','e','n','t','i','f','i','e','r',0};
750     static const WCHAR dwWidth[] = {'d','w','W','i','d','t','h',0};
751     static const WCHAR dwHeight[] = {'d','w','H','e','i','g','h','t',0};
752     static const WCHAR dwBpp[] = {'d','w','B','p','p',0};
753     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};
754     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};
755
756     static const WCHAR szAdapterID[] = {'0',0};
757
758     IDxDiagContainerImpl_Container *display_adapter;
759     HRESULT hr;
760     IDirectDraw7 *pDirectDraw;
761     DDSCAPS2 dd_caps;
762     DISPLAY_DEVICEW disp_dev;
763     DDSURFACEDESC2 surface_descr;
764     DWORD tmp;
765     WCHAR buffer[256];
766
767     display_adapter = allocate_information_node(szAdapterID);
768     if (!display_adapter)
769         return E_OUTOFMEMORY;
770
771     add_subcontainer(node, display_adapter);
772
773     disp_dev.cb = sizeof(disp_dev);
774     if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
775     {
776         hr = add_bstr_property(display_adapter, szDeviceName, disp_dev.DeviceName);
777         if (FAILED(hr))
778             return hr;
779
780         hr = add_bstr_property(display_adapter, szDescription, disp_dev.DeviceString);
781         if (FAILED(hr))
782             return hr;
783     }
784
785     /* For now, silently ignore a failure from DirectDrawCreateEx. */
786     hr = DirectDrawCreateEx(NULL, (LPVOID *)&pDirectDraw, &IID_IDirectDraw7, NULL);
787     if (FAILED(hr))
788         return S_OK;
789
790     dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
791     dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.dwCaps4 = 0;
792     hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, &tmp, NULL);
793     if (SUCCEEDED(hr))
794     {
795         static const WCHAR mem_fmt[] = {'%','.','1','f',' ','M','B',0};
796
797         snprintfW(buffer, sizeof(buffer)/sizeof(buffer[0]), mem_fmt, ((float)tmp) / 1000000.0);
798
799         hr = add_bstr_property(display_adapter, szDisplayMemoryLocalized, buffer);
800         if (FAILED(hr))
801             goto cleanup;
802
803         hr = add_bstr_property(display_adapter, szDisplayMemoryEnglish, buffer);
804         if (FAILED(hr))
805             goto cleanup;
806     }
807
808     surface_descr.dwSize = sizeof(surface_descr);
809     hr = IDirectDraw7_GetDisplayMode(pDirectDraw, &surface_descr);
810     if (SUCCEEDED(hr))
811     {
812         if (surface_descr.dwFlags & DDSD_WIDTH)
813         {
814             hr = add_ui4_property(display_adapter, dwWidth, surface_descr.dwWidth);
815             if (FAILED(hr))
816                 goto cleanup;
817         }
818
819         if (surface_descr.dwFlags & DDSD_HEIGHT)
820         {
821             hr = add_ui4_property(display_adapter, dwHeight, surface_descr.dwHeight);
822             if (FAILED(hr))
823                 goto cleanup;
824         }
825
826         if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
827         {
828             hr = add_ui4_property(display_adapter, dwBpp, surface_descr.u4.ddpfPixelFormat.u1.dwRGBBitCount);
829             if (FAILED(hr))
830                 goto cleanup;
831         }
832     }
833
834     get_display_device_id(buffer);
835
836     hr = add_bstr_property(display_adapter, szDeviceIdentifier, buffer);
837     if (FAILED(hr))
838         goto cleanup;
839
840     hr = add_bstr_property(display_adapter, szVendorId, szEmpty);
841     if (FAILED(hr))
842         goto cleanup;
843
844     hr = add_bstr_property(display_adapter, szDeviceId, szEmpty);
845     if (FAILED(hr))
846         goto cleanup;
847
848     hr = add_bstr_property(display_adapter, szKeyDeviceKey, szEmpty);
849     if (FAILED(hr))
850         goto cleanup;
851
852     hr = add_bstr_property(display_adapter, szKeyDeviceID, szEmpty);
853     if (FAILED(hr))
854         goto cleanup;
855
856     hr = S_OK;
857 cleanup:
858     IDirectDraw7_Release(pDirectDraw);
859     return hr;
860 }
861
862 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
863 {
864     static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
865     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};
866
867     IDxDiagContainerImpl_Container *cont;
868
869     cont = allocate_information_node(DxDiag_SoundDevices);
870     if (!cont)
871         return E_OUTOFMEMORY;
872
873     add_subcontainer(node, cont);
874
875     cont = allocate_information_node(DxDiag_SoundCaptureDevices);
876     if (!cont)
877         return E_OUTOFMEMORY;
878
879     add_subcontainer(node, cont);
880
881     return S_OK;
882 }
883
884 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
885 {
886     return S_OK;
887 }
888
889 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
890 {
891     return S_OK;
892 }
893
894 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
895 {
896     return S_OK;
897 }
898
899 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
900 {
901     return S_OK;
902 }
903
904 static HRESULT fill_file_description(IDxDiagContainerImpl_Container *node, const WCHAR *szFilePath, const WCHAR *szFileName)
905 {
906     static const WCHAR szSlashSep[] = {'\\',0};
907     static const WCHAR szPath[] = {'s','z','P','a','t','h',0};
908     static const WCHAR szName[] = {'s','z','N','a','m','e',0};
909     static const WCHAR szVersion[] = {'s','z','V','e','r','s','i','o','n',0};
910     static const WCHAR szAttributes[] = {'s','z','A','t','t','r','i','b','u','t','e','s',0};
911     static const WCHAR szLanguageEnglish[] = {'s','z','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
912     static const WCHAR dwFileTimeHigh[] = {'d','w','F','i','l','e','T','i','m','e','H','i','g','h',0};
913     static const WCHAR dwFileTimeLow[] = {'d','w','F','i','l','e','T','i','m','e','L','o','w',0};
914     static const WCHAR bBeta[] = {'b','B','e','t','a',0};
915     static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
916     static const WCHAR bExists[] = {'b','E','x','i','s','t','s',0};
917
918     /* Values */
919     static const WCHAR szFinal_Retail_v[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
920     static const WCHAR szEnglish_v[] = {'E','n','g','l','i','s','h',0};
921     static const WCHAR szVersionFormat[] = {'%','u','.','%','0','2','u','.','%','0','4','u','.','%','0','4','u',0};
922
923     HRESULT hr;
924     WCHAR *szFile;
925     WCHAR szVersion_v[1024];
926     DWORD retval, hdl;
927     void *pVersionInfo = NULL;
928     BOOL boolret = FALSE;
929     UINT uiLength;
930     VS_FIXEDFILEINFO *pFileInfo;
931
932     TRACE("Filling container %p for %s in %s\n", node,
933           debugstr_w(szFileName), debugstr_w(szFilePath));
934
935     szFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(szFilePath) +
936                                             lstrlenW(szFileName) + 2 /* slash + terminator */));
937     if (!szFile)
938         return E_OUTOFMEMORY;
939
940     lstrcpyW(szFile, szFilePath);
941     lstrcatW(szFile, szSlashSep);
942     lstrcatW(szFile, szFileName);
943
944     retval = GetFileVersionInfoSizeW(szFile, &hdl);
945     if (retval)
946     {
947         pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
948         if (!pVersionInfo)
949         {
950             hr = E_OUTOFMEMORY;
951             goto cleanup;
952         }
953
954         if (GetFileVersionInfoW(szFile, 0, retval, pVersionInfo) &&
955             VerQueryValueW(pVersionInfo, szSlashSep, (void **)&pFileInfo, &uiLength))
956             boolret = TRUE;
957     }
958
959     hr = add_bstr_property(node, szPath, szFile);
960     if (FAILED(hr))
961         goto cleanup;
962
963     hr = add_bstr_property(node, szName, szFileName);
964     if (FAILED(hr))
965         goto cleanup;
966
967     hr = add_bool_property(node, bExists, boolret);
968     if (FAILED(hr))
969         goto cleanup;
970
971     if (boolret)
972     {
973         snprintfW(szVersion_v, sizeof(szVersion_v)/sizeof(szVersion_v[0]),
974                   szVersionFormat,
975                   HIWORD(pFileInfo->dwFileVersionMS),
976                   LOWORD(pFileInfo->dwFileVersionMS),
977                   HIWORD(pFileInfo->dwFileVersionLS),
978                   LOWORD(pFileInfo->dwFileVersionLS));
979
980         TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));
981
982         hr = add_bstr_property(node, szVersion, szVersion_v);
983         if (FAILED(hr))
984             goto cleanup;
985
986         hr = add_bstr_property(node, szAttributes, szFinal_Retail_v);
987         if (FAILED(hr))
988             goto cleanup;
989
990         hr = add_bstr_property(node, szLanguageEnglish, szEnglish_v);
991         if (FAILED(hr))
992             goto cleanup;
993
994         hr = add_ui4_property(node, dwFileTimeHigh, pFileInfo->dwFileDateMS);
995         if (FAILED(hr))
996             goto cleanup;
997
998         hr = add_ui4_property(node, dwFileTimeLow, pFileInfo->dwFileDateLS);
999         if (FAILED(hr))
1000             goto cleanup;
1001
1002         hr = add_bool_property(node, bBeta, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
1003         if (FAILED(hr))
1004             goto cleanup;
1005
1006         hr = add_bool_property(node, bDebug, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
1007         if (FAILED(hr))
1008             goto cleanup;
1009     }
1010
1011     hr = S_OK;
1012 cleanup:
1013     HeapFree(GetProcessHeap(), 0, pVersionInfo);
1014     HeapFree(GetProcessHeap(), 0, szFile);
1015
1016     return hr;
1017 }
1018 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1019 {
1020     static const WCHAR dlls[][15] =
1021     {
1022         {'d','3','d','8','.','d','l','l',0},
1023         {'d','3','d','9','.','d','l','l',0},
1024         {'d','d','r','a','w','.','d','l','l',0},
1025         {'d','e','v','e','n','u','m','.','d','l','l',0},
1026         {'d','i','n','p','u','t','8','.','d','l','l',0},
1027         {'d','i','n','p','u','t','.','d','l','l',0},
1028         {'d','m','b','a','n','d','.','d','l','l',0},
1029         {'d','m','c','o','m','p','o','s','.','d','l','l',0},
1030         {'d','m','i','m','e','.','d','l','l',0},
1031         {'d','m','l','o','a','d','e','r','.','d','l','l',0},
1032         {'d','m','s','c','r','i','p','t','.','d','l','l',0},
1033         {'d','m','s','t','y','l','e','.','d','l','l',0},
1034         {'d','m','s','y','n','t','h','.','d','l','l',0},
1035         {'d','m','u','s','i','c','.','d','l','l',0},
1036         {'d','p','l','a','y','x','.','d','l','l',0},
1037         {'d','p','n','e','t','.','d','l','l',0},
1038         {'d','s','o','u','n','d','.','d','l','l',0},
1039         {'d','s','w','a','v','e','.','d','l','l',0},
1040         {'d','x','d','i','a','g','n','.','d','l','l',0},
1041         {'q','u','a','r','t','z','.','d','l','l',0}
1042     };
1043
1044     HRESULT hr;
1045     WCHAR szFilePath[MAX_PATH];
1046     INT i;
1047
1048     GetSystemDirectoryW(szFilePath, MAX_PATH);
1049
1050     for (i = 0; i < sizeof(dlls) / sizeof(dlls[0]); i++)
1051     {
1052         static const WCHAR szFormat[] = {'%','d',0};
1053
1054         WCHAR szFileID[5];
1055         IDxDiagContainerImpl_Container *file_container;
1056
1057         snprintfW(szFileID, sizeof(szFileID)/sizeof(szFileID[0]), szFormat, i);
1058
1059         file_container = allocate_information_node(szFileID);
1060         if (!file_container)
1061             return E_OUTOFMEMORY;
1062
1063         hr = fill_file_description(file_container, szFilePath, dlls[i]);
1064         if (FAILED(hr))
1065         {
1066             free_information_tree(file_container);
1067             continue;
1068         }
1069
1070         add_subcontainer(node, file_container);
1071     }
1072
1073     return S_OK;
1074 }
1075
1076 static HRESULT read_property_names(IPropertyBag *pPropBag, VARIANT *friendly_name, VARIANT *clsid_name)
1077 {
1078     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
1079     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
1080
1081     HRESULT hr;
1082
1083     VariantInit(friendly_name);
1084     VariantInit(clsid_name);
1085
1086     hr = IPropertyBag_Read(pPropBag, wszFriendlyName, friendly_name, 0);
1087     if (FAILED(hr))
1088         return hr;
1089
1090     hr = IPropertyBag_Read(pPropBag, wszClsidName, clsid_name, 0);
1091     if (FAILED(hr))
1092     {
1093         VariantClear(friendly_name);
1094         return hr;
1095     }
1096
1097     return S_OK;
1098 }
1099
1100 static HRESULT fill_filter_data_information(IDxDiagContainerImpl_Container *subcont, BYTE *pData, ULONG cb)
1101 {
1102     static const WCHAR szVersionW[] = {'s','z','V','e','r','s','i','o','n',0};
1103     static const WCHAR dwInputs[] = {'d','w','I','n','p','u','t','s',0};
1104     static const WCHAR dwOutputs[] = {'d','w','O','u','t','p','u','t','s',0};
1105     static const WCHAR dwMeritW[] = {'d','w','M','e','r','i','t',0};
1106     static const WCHAR szVersionFormat[] = {'v','%','d',0};
1107
1108     HRESULT hr;
1109     IFilterMapper2 *pFileMapper = NULL;
1110     IAMFilterData *pFilterData = NULL;
1111     REGFILTER2 *pRF = NULL;
1112     WCHAR bufferW[10];
1113     ULONG j;
1114     DWORD dwNOutputs = 0;
1115     DWORD dwNInputs = 0;
1116
1117     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
1118                           (void **)&pFileMapper);
1119     if (FAILED(hr))
1120         return hr;
1121
1122     hr = IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData);
1123     if (FAILED(hr))
1124         goto cleanup;
1125
1126     hr = IAMFilterData_ParseFilterData(pFilterData, pData, cb, (BYTE **)&pRF);
1127     if (FAILED(hr))
1128         goto cleanup;
1129
1130     snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szVersionFormat, pRF->dwVersion);
1131     hr = add_bstr_property(subcont, szVersionW, bufferW);
1132     if (FAILED(hr))
1133         goto cleanup;
1134
1135     if (pRF->dwVersion == 1)
1136     {
1137         for (j = 0; j < pRF->u.s.cPins; j++)
1138             if (pRF->u.s.rgPins[j].bOutput)
1139                 dwNOutputs++;
1140             else
1141                 dwNInputs++;
1142     }
1143     else if (pRF->dwVersion == 2)
1144     {
1145         for (j = 0; j < pRF->u.s1.cPins2; j++)
1146             if (pRF->u.s1.rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
1147                 dwNOutputs++;
1148             else
1149                 dwNInputs++;
1150     }
1151
1152     hr = add_ui4_property(subcont, dwInputs, dwNInputs);
1153     if (FAILED(hr))
1154         goto cleanup;
1155
1156     hr = add_ui4_property(subcont, dwOutputs, dwNOutputs);
1157     if (FAILED(hr))
1158         goto cleanup;
1159
1160     hr = add_ui4_property(subcont, dwMeritW, pRF->dwMerit);
1161     if (FAILED(hr))
1162         goto cleanup;
1163
1164     hr = S_OK;
1165 cleanup:
1166     CoTaskMemFree(pRF);
1167     if (pFilterData) IAMFilterData_Release(pFilterData);
1168     if (pFileMapper) IFilterMapper2_Release(pFileMapper);
1169
1170     return hr;
1171 }
1172
1173 static HRESULT fill_filter_container(IDxDiagContainerImpl_Container *subcont, IMoniker *pMoniker)
1174 {
1175     static const WCHAR szName[] = {'s','z','N','a','m','e',0};
1176     static const WCHAR ClsidFilterW[] = {'C','l','s','i','d','F','i','l','t','e','r',0};
1177     static const WCHAR wszFilterDataName[] = {'F','i','l','t','e','r','D','a','t','a',0};
1178
1179     HRESULT hr;
1180     IPropertyBag *pPropFilterBag = NULL;
1181     BYTE *pData;
1182     VARIANT friendly_name;
1183     VARIANT clsid_name;
1184     VARIANT v;
1185
1186     VariantInit(&friendly_name);
1187     VariantInit(&clsid_name);
1188     VariantInit(&v);
1189
1190     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void **)&pPropFilterBag);
1191     if (FAILED(hr))
1192         return hr;
1193
1194     hr = read_property_names(pPropFilterBag, &friendly_name, &clsid_name);
1195     if (FAILED(hr))
1196         goto cleanup;
1197
1198     TRACE("Name = %s\n", debugstr_w(V_BSTR(&friendly_name)));
1199     TRACE("CLSID = %s\n", debugstr_w(V_BSTR(&clsid_name)));
1200
1201     hr = add_bstr_property(subcont, szName, V_BSTR(&friendly_name));
1202     if (FAILED(hr))
1203         goto cleanup;
1204
1205     hr = add_bstr_property(subcont, ClsidFilterW, V_BSTR(&clsid_name));
1206     if (FAILED(hr))
1207         goto cleanup;
1208
1209     hr = IPropertyBag_Read(pPropFilterBag, wszFilterDataName, &v, NULL);
1210     if (FAILED(hr))
1211         goto cleanup;
1212
1213     hr = SafeArrayAccessData(V_ARRAY(&v), (void **)&pData);
1214     if (FAILED(hr))
1215         goto cleanup;
1216
1217     hr = fill_filter_data_information(subcont, pData, V_ARRAY(&v)->rgsabound->cElements);
1218     SafeArrayUnaccessData(V_ARRAY(&v));
1219     if (FAILED(hr))
1220         goto cleanup;
1221
1222     hr = S_OK;
1223 cleanup:
1224     VariantClear(&v);
1225     VariantClear(&clsid_name);
1226     VariantClear(&friendly_name);
1227     if (pPropFilterBag) IPropertyBag_Release(pPropFilterBag);
1228
1229     return hr;
1230 }
1231
1232 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1233 {
1234     static const WCHAR szCatName[] = {'s','z','C','a','t','N','a','m','e',0};
1235     static const WCHAR ClsidCatW[] = {'C','l','s','i','d','C','a','t',0};
1236     static const WCHAR szIdFormat[] = {'%','d',0};
1237
1238     HRESULT hr;
1239     int i = 0;
1240     ICreateDevEnum *pCreateDevEnum;
1241     IEnumMoniker *pEmCat = NULL;
1242     IMoniker *pMCat = NULL;
1243         IEnumMoniker *pEnum = NULL;
1244
1245     hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1246                           &IID_ICreateDevEnum, (void **)&pCreateDevEnum);
1247     if (FAILED(hr))
1248         return hr;
1249
1250     hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
1251     if (FAILED(hr))
1252         goto cleanup;
1253
1254     while (IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL) == S_OK)
1255     {
1256         VARIANT vCatName;
1257         VARIANT vCatClsid;
1258         IPropertyBag *pPropBag;
1259         CLSID clsidCat;
1260         IMoniker *pMoniker = NULL;
1261
1262         hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void **)&pPropBag);
1263         if (FAILED(hr))
1264         {
1265             IMoniker_Release(pMCat);
1266             break;
1267         }
1268
1269         hr = read_property_names(pPropBag, &vCatName, &vCatClsid);
1270         IPropertyBag_Release(pPropBag);
1271         if (FAILED(hr))
1272         {
1273             IMoniker_Release(pMCat);
1274             break;
1275         }
1276
1277         hr = CLSIDFromString(V_BSTR(&vCatClsid), &clsidCat);
1278         if (FAILED(hr))
1279         {
1280             IMoniker_Release(pMCat);
1281             VariantClear(&vCatClsid);
1282             VariantClear(&vCatName);
1283             break;
1284         }
1285
1286         hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1287         if (hr != S_OK)
1288         {
1289             IMoniker_Release(pMCat);
1290             VariantClear(&vCatClsid);
1291             VariantClear(&vCatName);
1292             continue;
1293         }
1294
1295         TRACE("Enumerating class %s\n", debugstr_guid(&clsidCat));
1296
1297         while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1298         {
1299             WCHAR bufferW[10];
1300             IDxDiagContainerImpl_Container *subcont;
1301
1302             snprintfW(bufferW, sizeof(bufferW)/sizeof(bufferW[0]), szIdFormat, i);
1303             subcont = allocate_information_node(bufferW);
1304             if (!subcont)
1305             {
1306                 hr = E_OUTOFMEMORY;
1307                 IMoniker_Release(pMoniker);
1308                 break;
1309             }
1310
1311             hr = add_bstr_property(subcont, szCatName, V_BSTR(&vCatName));
1312             if (FAILED(hr))
1313             {
1314                 free_information_tree(subcont);
1315                 IMoniker_Release(pMoniker);
1316                 break;
1317             }
1318
1319             hr = add_bstr_property(subcont, ClsidCatW, V_BSTR(&vCatClsid));
1320             if (FAILED(hr))
1321             {
1322                 free_information_tree(subcont);
1323                 IMoniker_Release(pMoniker);
1324                 break;
1325             }
1326
1327             hr = fill_filter_container(subcont, pMoniker);
1328             if (FAILED(hr))
1329             {
1330                 free_information_tree(subcont);
1331                 IMoniker_Release(pMoniker);
1332                 break;
1333             }
1334
1335             add_subcontainer(node, subcont);
1336             i++;
1337             IMoniker_Release(pMoniker);
1338         }
1339
1340         IEnumMoniker_Release(pEnum);
1341         IMoniker_Release(pMCat);
1342         VariantClear(&vCatClsid);
1343         VariantClear(&vCatName);
1344
1345         if (FAILED(hr))
1346             break;
1347     }
1348
1349 cleanup:
1350     if (pEmCat) IEnumMoniker_Release(pEmCat);
1351     ICreateDevEnum_Release(pCreateDevEnum);
1352     return hr;
1353 }
1354
1355 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1356 {
1357     return S_OK;
1358 }
1359
1360 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1361 {
1362     static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
1363     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};
1364     static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
1365     static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
1366     static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
1367     static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
1368     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};
1369     static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
1370     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};
1371     static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
1372
1373     static const struct
1374     {
1375         const WCHAR *name;
1376         HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1377     } root_children[] =
1378     {
1379         {DxDiag_SystemInfo, build_systeminfo_tree},
1380         {DxDiag_DisplayDevices, build_displaydevices_tree},
1381         {DxDiag_DirectSound, build_directsound_tree},
1382         {DxDiag_DirectMusic, build_directmusic_tree},
1383         {DxDiag_DirectInput, build_directinput_tree},
1384         {DxDiag_DirectPlay, build_directplay_tree},
1385         {DxDiag_SystemDevices, build_systemdevices_tree},
1386         {DxDiag_DirectXFiles, build_directxfiles_tree},
1387         {DxDiag_DirectShowFilters, build_directshowfilters_tree},
1388         {DxDiag_LogicalDisks, build_logicaldisks_tree},
1389     };
1390
1391     IDxDiagContainerImpl_Container *info_root;
1392     size_t index;
1393
1394     info_root = allocate_information_node(NULL);
1395     if (!info_root)
1396         return E_OUTOFMEMORY;
1397
1398     for (index = 0; index < sizeof(root_children)/sizeof(root_children[0]); index++)
1399     {
1400         IDxDiagContainerImpl_Container *node;
1401         HRESULT hr;
1402
1403         node = allocate_information_node(root_children[index].name);
1404         if (!node)
1405         {
1406             free_information_tree(info_root);
1407             return E_OUTOFMEMORY;
1408         }
1409
1410         hr = root_children[index].initfunc(node);
1411         if (FAILED(hr))
1412         {
1413             free_information_tree(node);
1414             free_information_tree(info_root);
1415             return hr;
1416         }
1417
1418         add_subcontainer(info_root, node);
1419     }
1420
1421     *pinfo_root = info_root;
1422     return S_OK;
1423 }