mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / dxdiagn / provider.c
blobaaffb5c213d392724cba57fb077a9ed551a9791d
1 /*
2 * IDxDiagProvider Implementation
3 *
4 * Copyright 2004-2005 Raphael Junqueira
5 * Copyright 2010 Andrew Nguyen
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.
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.
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
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "dxdiag_private.h"
28 #include "winver.h"
29 #include "objidl.h"
30 #include "uuids.h"
31 #include "vfw.h"
32 #include "mmddk.h"
33 #include "d3d9.h"
34 #include "strmif.h"
35 #include "initguid.h"
36 #include "wine/fil_data.h"
37 #include "psapi.h"
38 #include "wbemcli.h"
39 #include "dsound.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
45 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root);
46 static void free_information_tree(IDxDiagContainerImpl_Container *node);
48 struct IDxDiagProviderImpl
50 IDxDiagProvider IDxDiagProvider_iface;
51 LONG ref;
52 BOOL init;
53 DXDIAG_INIT_PARAMS params;
54 IDxDiagContainerImpl_Container *info_root;
57 static inline IDxDiagProviderImpl *impl_from_IDxDiagProvider(IDxDiagProvider *iface)
59 return CONTAINING_RECORD(iface, IDxDiagProviderImpl, IDxDiagProvider_iface);
62 /* IDxDiagProvider IUnknown parts follow: */
63 static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(IDxDiagProvider *iface, REFIID riid,
64 void **ppobj)
66 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
68 if (!ppobj) return E_INVALIDARG;
70 if (IsEqualGUID(riid, &IID_IUnknown)
71 || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
72 IUnknown_AddRef(iface);
73 *ppobj = This;
74 return S_OK;
77 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
78 *ppobj = NULL;
79 return E_NOINTERFACE;
82 static ULONG WINAPI IDxDiagProviderImpl_AddRef(IDxDiagProvider *iface)
84 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
85 ULONG refCount = InterlockedIncrement(&This->ref);
87 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
89 DXDIAGN_LockModule();
91 return refCount;
94 static ULONG WINAPI IDxDiagProviderImpl_Release(IDxDiagProvider *iface)
96 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
97 ULONG refCount = InterlockedDecrement(&This->ref);
99 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
101 if (!refCount) {
102 free_information_tree(This->info_root);
103 HeapFree(GetProcessHeap(), 0, This);
106 DXDIAGN_UnlockModule();
108 return refCount;
111 /* IDxDiagProvider Interface follow: */
112 static HRESULT WINAPI IDxDiagProviderImpl_Initialize(IDxDiagProvider *iface,
113 DXDIAG_INIT_PARAMS *pParams)
115 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
116 HRESULT hr;
118 TRACE("(%p,%p)\n", iface, pParams);
120 if (NULL == pParams) {
121 return E_POINTER;
123 if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS) ||
124 pParams->dwDxDiagHeaderVersion != DXDIAG_DX9_SDK_VERSION) {
125 return E_INVALIDARG;
128 if (!This->info_root)
130 hr = build_information_tree(&This->info_root);
131 if (FAILED(hr))
132 return hr;
135 This->init = TRUE;
136 memcpy(&This->params, pParams, pParams->dwSize);
137 return S_OK;
140 static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(IDxDiagProvider *iface,
141 IDxDiagContainer **ppInstance)
143 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
145 TRACE("(%p,%p)\n", iface, ppInstance);
147 if (FALSE == This->init) {
148 return CO_E_NOTINITIALIZED;
151 return DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, This->info_root,
152 &This->IDxDiagProvider_iface, (void **)ppInstance);
155 static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
157 IDxDiagProviderImpl_QueryInterface,
158 IDxDiagProviderImpl_AddRef,
159 IDxDiagProviderImpl_Release,
160 IDxDiagProviderImpl_Initialize,
161 IDxDiagProviderImpl_GetRootContainer
164 HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
165 IDxDiagProviderImpl* provider;
167 TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
169 *ppobj = NULL;
170 if (punkOuter) return CLASS_E_NOAGGREGATION;
172 provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
173 if (NULL == provider) return E_OUTOFMEMORY;
174 provider->IDxDiagProvider_iface.lpVtbl = &DxDiagProvider_Vtbl;
175 provider->ref = 0; /* will be inited with QueryInterface */
176 return IDxDiagProviderImpl_QueryInterface(&provider->IDxDiagProvider_iface, riid, ppobj);
179 static void free_property_information(IDxDiagContainerImpl_Property *prop)
181 VariantClear(&prop->vProp);
182 HeapFree(GetProcessHeap(), 0, prop->propName);
183 HeapFree(GetProcessHeap(), 0, prop);
186 static void free_information_tree(IDxDiagContainerImpl_Container *node)
188 IDxDiagContainerImpl_Container *ptr, *cursor2;
190 if (!node)
191 return;
193 HeapFree(GetProcessHeap(), 0, node->contName);
195 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &node->subContainers, IDxDiagContainerImpl_Container, entry)
197 IDxDiagContainerImpl_Property *prop, *prop_cursor2;
199 LIST_FOR_EACH_ENTRY_SAFE(prop, prop_cursor2, &ptr->properties, IDxDiagContainerImpl_Property, entry)
201 list_remove(&prop->entry);
202 free_property_information(prop);
205 list_remove(&ptr->entry);
206 free_information_tree(ptr);
209 HeapFree(GetProcessHeap(), 0, node);
212 static IDxDiagContainerImpl_Container *allocate_information_node(const WCHAR *name)
214 IDxDiagContainerImpl_Container *ret;
216 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
217 if (!ret)
218 return NULL;
220 if (name)
222 ret->contName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name) + 1) * sizeof(*name));
223 if (!ret->contName)
225 HeapFree(GetProcessHeap(), 0, ret);
226 return NULL;
228 lstrcpyW(ret->contName, name);
231 list_init(&ret->subContainers);
232 list_init(&ret->properties);
234 return ret;
237 static IDxDiagContainerImpl_Property *allocate_property_information(const WCHAR *name)
239 IDxDiagContainerImpl_Property *ret;
241 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
242 if (!ret)
243 return NULL;
245 ret->propName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name) + 1) * sizeof(*name));
246 if (!ret->propName)
248 HeapFree(GetProcessHeap(), 0, ret);
249 return NULL;
251 lstrcpyW(ret->propName, name);
253 return ret;
256 static inline void add_subcontainer(IDxDiagContainerImpl_Container *node, IDxDiagContainerImpl_Container *subCont)
258 list_add_tail(&node->subContainers, &subCont->entry);
259 ++node->nSubContainers;
262 static inline HRESULT add_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, const WCHAR *str)
264 IDxDiagContainerImpl_Property *prop;
265 BSTR bstr;
267 prop = allocate_property_information(propName);
268 if (!prop)
269 return E_OUTOFMEMORY;
271 bstr = SysAllocString(str);
272 if (!bstr)
274 free_property_information(prop);
275 return E_OUTOFMEMORY;
278 V_VT(&prop->vProp) = VT_BSTR;
279 V_BSTR(&prop->vProp) = bstr;
281 list_add_tail(&node->properties, &prop->entry);
282 ++node->nProperties;
284 return S_OK;
287 static inline HRESULT add_ui4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, DWORD data)
289 IDxDiagContainerImpl_Property *prop;
291 prop = allocate_property_information(propName);
292 if (!prop)
293 return E_OUTOFMEMORY;
295 V_VT(&prop->vProp) = VT_UI4;
296 V_UI4(&prop->vProp) = data;
298 list_add_tail(&node->properties, &prop->entry);
299 ++node->nProperties;
301 return S_OK;
304 static inline HRESULT add_i4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, LONG data)
306 IDxDiagContainerImpl_Property *prop;
308 prop = allocate_property_information(propName);
309 if (!prop)
310 return E_OUTOFMEMORY;
312 V_VT(&prop->vProp) = VT_I4;
313 V_I4(&prop->vProp) = data;
315 list_add_tail(&node->properties, &prop->entry);
316 ++node->nProperties;
318 return S_OK;
321 static inline HRESULT add_bool_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, BOOL data)
323 IDxDiagContainerImpl_Property *prop;
325 prop = allocate_property_information(propName);
326 if (!prop)
327 return E_OUTOFMEMORY;
329 V_VT(&prop->vProp) = VT_BOOL;
330 V_BOOL(&prop->vProp) = data ? VARIANT_TRUE : VARIANT_FALSE;
332 list_add_tail(&node->properties, &prop->entry);
333 ++node->nProperties;
335 return S_OK;
338 static inline HRESULT add_ull_as_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, ULONGLONG data )
340 IDxDiagContainerImpl_Property *prop;
341 HRESULT hr;
343 prop = allocate_property_information(propName);
344 if (!prop)
345 return E_OUTOFMEMORY;
347 V_VT(&prop->vProp) = VT_UI8;
348 V_UI8(&prop->vProp) = data;
350 hr = VariantChangeType(&prop->vProp, &prop->vProp, 0, VT_BSTR);
351 if (FAILED(hr))
353 free_property_information(prop);
354 return hr;
357 list_add_tail(&node->properties, &prop->entry);
358 ++node->nProperties;
360 return S_OK;
363 /* Copied from programs/taskkill/taskkill.c. */
364 static DWORD *enumerate_processes(DWORD *list_count)
366 DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes;
368 pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes);
369 if (!pid_list)
370 return NULL;
372 for (;;)
374 DWORD *realloc_list;
376 if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes))
378 HeapFree(GetProcessHeap(), 0, pid_list);
379 return NULL;
382 /* EnumProcesses can't signal an insufficient buffer condition, so the
383 * only way to possibly determine whether a larger buffer is required
384 * is to see whether the written number of bytes is the same as the
385 * buffer size. If so, the buffer will be reallocated to twice the
386 * size. */
387 if (alloc_bytes != needed_bytes)
388 break;
390 alloc_bytes *= 2;
391 realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes);
392 if (!realloc_list)
394 HeapFree(GetProcessHeap(), 0, pid_list);
395 return NULL;
397 pid_list = realloc_list;
400 *list_count = needed_bytes / sizeof(*pid_list);
401 return pid_list;
404 /* Copied from programs/taskkill/taskkill.c. */
405 static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars)
407 HANDLE process;
408 HMODULE module;
409 DWORD required_size;
411 process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
412 if (!process)
413 return FALSE;
415 if (!EnumProcessModules(process, &module, sizeof(module), &required_size))
417 CloseHandle(process);
418 return FALSE;
421 if (!GetModuleBaseNameW(process, module, buf, chars))
423 CloseHandle(process);
424 return FALSE;
427 CloseHandle(process);
428 return TRUE;
431 /* dxdiagn's detection scheme is simply to look for a process called conf.exe. */
432 static BOOL is_netmeeting_running(void)
434 DWORD list_count;
435 DWORD *pid_list = enumerate_processes(&list_count);
437 if (pid_list)
439 DWORD i;
440 WCHAR process_name[MAX_PATH];
442 for (i = 0; i < list_count; i++)
444 if (get_process_name_from_pid(pid_list[i], process_name, ARRAY_SIZE(process_name)) &&
445 !lstrcmpW(L"conf.exe", process_name))
447 HeapFree(GetProcessHeap(), 0, pid_list);
448 return TRUE;
451 HeapFree(GetProcessHeap(), 0, pid_list);
454 return FALSE;
457 static HRESULT fill_language_information(IDxDiagContainerImpl_Container *node)
459 WCHAR system_lang[80], regional_setting[100], user_lang[80], language_str[300];
460 HRESULT hr;
462 /* szLanguagesLocalized */
463 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SNATIVELANGNAME, system_lang, ARRAY_SIZE(system_lang));
464 LoadStringW(dxdiagn_instance, IDS_REGIONAL_SETTING, regional_setting, ARRAY_SIZE(regional_setting));
465 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, user_lang, ARRAY_SIZE(user_lang));
467 swprintf(language_str, ARRAY_SIZE(language_str), L"%s (%s: %s)", system_lang, regional_setting,
468 user_lang);
470 hr = add_bstr_property(node, L"szLanguagesLocalized", language_str);
471 if (FAILED(hr))
472 return hr;
474 /* szLanguagesEnglish */
475 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, system_lang, ARRAY_SIZE(system_lang));
476 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, user_lang, ARRAY_SIZE(user_lang));
478 swprintf(language_str, ARRAY_SIZE(language_str), L"%s (%s: %s)", system_lang,
479 L"Regional Setting", user_lang);
481 hr = add_bstr_property(node, L"szLanguagesEnglish", language_str);
482 if (FAILED(hr))
483 return hr;
485 return S_OK;
488 static HRESULT fill_datetime_information(IDxDiagContainerImpl_Container *node)
490 SYSTEMTIME curtime;
491 WCHAR date_str[80], time_str[80], datetime_str[200];
492 HRESULT hr;
494 GetLocalTime(&curtime);
496 GetTimeFormatW(LOCALE_NEUTRAL, 0, &curtime, L"HH':'mm':'ss", time_str, ARRAY_SIZE(time_str));
498 /* szTimeLocalized */
499 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &curtime, NULL, date_str, ARRAY_SIZE(date_str));
501 swprintf(datetime_str, ARRAY_SIZE(datetime_str), L"%s, %s", date_str, time_str);
503 hr = add_bstr_property(node, L"szTimeLocalized", datetime_str);
504 if (FAILED(hr))
505 return hr;
507 /* szTimeEnglish */
508 GetDateFormatW(LOCALE_NEUTRAL, 0, &curtime, L"M'/'d'/'yyyy", date_str, ARRAY_SIZE(date_str));
510 swprintf(datetime_str, ARRAY_SIZE(datetime_str), L"%s, %s", date_str, time_str);
512 hr = add_bstr_property(node, L"szTimeEnglish", datetime_str);
513 if (FAILED(hr))
514 return hr;
516 return S_OK;
519 static HRESULT fill_os_string_information(IDxDiagContainerImpl_Container *node, OSVERSIONINFOW *info)
521 static const WCHAR *prop_list[] =
523 L"szOSLocalized", L"szOSExLocalized", L"szOSExLongLocalized",
524 L"szOSEnglish", L"szOSExEnglish", L"szOSExLongEnglish"
526 size_t i;
527 HRESULT hr;
529 /* FIXME: OS detection should be performed, and localized OS strings
530 * should contain translated versions of the "build" phrase. */
531 for (i = 0; i < ARRAY_SIZE(prop_list); i++)
533 hr = add_bstr_property(node, prop_list[i], L"Windows XP Professional");
534 if (FAILED(hr))
535 return hr;
538 return S_OK;
541 static HRESULT fill_processor_information(IDxDiagContainerImpl_Container *node)
543 IWbemLocator *wbem_locator;
544 IWbemServices *wbem_service;
545 IWbemClassObject *wbem_class;
546 IEnumWbemClassObject *wbem_enum;
547 VARIANT cpu_name, cpu_no, clock_speed;
548 WCHAR print_buf[200];
549 BSTR bstr;
550 ULONG no;
551 HRESULT hr;
553 hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (void**)&wbem_locator);
554 if(FAILED(hr))
555 return hr;
557 bstr = SysAllocString(L"\\\\.\\root\\cimv2");
558 if(!bstr) {
559 IWbemLocator_Release(wbem_locator);
560 return E_OUTOFMEMORY;
562 hr = IWbemLocator_ConnectServer(wbem_locator, bstr, NULL, NULL, NULL, 0, NULL, NULL, &wbem_service);
563 IWbemLocator_Release(wbem_locator);
564 SysFreeString(bstr);
565 if(FAILED(hr))
566 return hr;
568 bstr = SysAllocString(L"Win32_Processor");
569 if(!bstr) {
570 IWbemServices_Release(wbem_service);
571 return E_OUTOFMEMORY;
573 hr = IWbemServices_CreateInstanceEnum(wbem_service, bstr, WBEM_FLAG_SYSTEM_ONLY, NULL, &wbem_enum);
574 IWbemServices_Release(wbem_service);
575 SysFreeString(bstr);
576 if(FAILED(hr))
577 return hr;
579 hr = IEnumWbemClassObject_Next(wbem_enum, 1000, 1, &wbem_class, &no);
580 IEnumWbemClassObject_Release(wbem_enum);
581 if(FAILED(hr))
582 return hr;
584 hr = IWbemClassObject_Get(wbem_class, L"NumberOfLogicalProcessors", 0, &cpu_no, NULL, NULL);
585 if(FAILED(hr)) {
586 IWbemClassObject_Release(wbem_class);
587 return hr;
589 hr = IWbemClassObject_Get(wbem_class, L"MaxClockSpeed", 0, &clock_speed, NULL, NULL);
590 if(FAILED(hr)) {
591 IWbemClassObject_Release(wbem_class);
592 return hr;
594 hr = IWbemClassObject_Get(wbem_class, L"Name", 0, &cpu_name, NULL, NULL);
595 IWbemClassObject_Release(wbem_class);
596 if(FAILED(hr))
597 return hr;
599 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%s(%d CPUs), ~%dMHz",
600 V_BSTR(&cpu_name), V_I4(&cpu_no), V_I4(&clock_speed));
601 VariantClear(&cpu_name);
602 VariantClear(&cpu_no);
603 VariantClear(&clock_speed);
605 return add_bstr_property(node, L"szProcessorEnglish", print_buf);
608 static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node)
610 HRESULT hr;
611 MEMORYSTATUSEX msex;
612 OSVERSIONINFOW info;
613 DWORD count, usedpage_mb, availpage_mb;
614 WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200];
615 DWORD_PTR args[2];
617 hr = add_ui4_property(node, L"dwDirectXVersionMajor", 9);
618 if (FAILED(hr))
619 return hr;
621 hr = add_ui4_property(node, L"dwDirectXVersionMinor", 0);
622 if (FAILED(hr))
623 return hr;
625 hr = add_bstr_property(node, L"szDirectXVersionLetter", L"c");
626 if (FAILED(hr))
627 return hr;
629 hr = add_bstr_property(node, L"szDirectXVersionEnglish", L"4.09.0000.0904");
630 if (FAILED(hr))
631 return hr;
633 hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"= \"DirectX 9.0c (4.09.0000.0904)");
634 if (FAILED(hr))
635 return hr;
637 hr = add_bool_property(node, L"bDebug", FALSE);
638 if (FAILED(hr))
639 return hr;
641 hr = add_bool_property(node, L"bNECPC98", FALSE);
642 if (FAILED(hr))
643 return hr;
645 msex.dwLength = sizeof(msex);
646 GlobalMemoryStatusEx(&msex);
648 hr = add_ull_as_bstr_property(node, L"ullPhysicalMemory", msex.ullTotalPhys);
649 if (FAILED(hr))
650 return hr;
652 hr = add_ull_as_bstr_property(node, L"ullUsedPageFile", msex.ullTotalPageFile - msex.ullAvailPageFile);
653 if (FAILED(hr))
654 return hr;
656 hr = add_ull_as_bstr_property(node, L"ullAvailPageFile", msex.ullAvailPageFile);
657 if (FAILED(hr))
658 return hr;
660 hr = add_bool_property(node, L"bNetMeetingRunning", is_netmeeting_running());
661 if (FAILED(hr))
662 return hr;
664 info.dwOSVersionInfoSize = sizeof(info);
665 GetVersionExW(&info);
667 hr = add_ui4_property(node, L"dwOSMajorVersion", info.dwMajorVersion);
668 if (FAILED(hr))
669 return hr;
671 hr = add_ui4_property(node, L"dwOSMinorVersion", info.dwMinorVersion);
672 if (FAILED(hr))
673 return hr;
675 hr = add_ui4_property(node, L"dwOSBuildNumber", info.dwBuildNumber);
676 if (FAILED(hr))
677 return hr;
679 hr = add_ui4_property(node, L"dwOSPlatformID", info.dwPlatformId);
680 if (FAILED(hr))
681 return hr;
683 hr = add_bstr_property(node, L"szCSDVersion", info.szCSDVersion);
684 if (FAILED(hr))
685 return hr;
687 /* FIXME: Roundoff should not be done with truncated division. */
688 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%uMB RAM", (DWORD)(msex.ullTotalPhys / (1024 * 1024)));
689 hr = add_bstr_property(node, L"szPhysicalMemoryEnglish", print_buf);
690 if (FAILED(hr))
691 return hr;
693 usedpage_mb = (DWORD)((msex.ullTotalPageFile - msex.ullAvailPageFile) / (1024 * 1024));
694 availpage_mb = (DWORD)(msex.ullAvailPageFile / (1024 * 1024));
695 LoadStringW(dxdiagn_instance, IDS_PAGE_FILE_FORMAT, localized_pagefile_fmt,
696 ARRAY_SIZE(localized_pagefile_fmt));
697 args[0] = usedpage_mb;
698 args[1] = availpage_mb;
699 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, localized_pagefile_fmt,
700 0, 0, print_buf, ARRAY_SIZE(print_buf), (__ms_va_list*)args);
702 hr = add_bstr_property(node, L"szPageFileLocalized", print_buf);
703 if (FAILED(hr))
704 return hr;
706 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%uMB used, %uMB available", usedpage_mb, availpage_mb);
708 hr = add_bstr_property(node, L"szPageFileEnglish", print_buf);
709 if (FAILED(hr))
710 return hr;
712 GetWindowsDirectoryW(buffer, MAX_PATH);
714 hr = add_bstr_property(node, L"szWindowsDir", buffer);
715 if (FAILED(hr))
716 return hr;
718 count = ARRAY_SIZE(computer_name);
719 if (!GetComputerNameW(computer_name, &count))
720 return E_FAIL;
722 hr = add_bstr_property(node, L"szMachineNameLocalized", computer_name);
723 if (FAILED(hr))
724 return hr;
726 hr = add_bstr_property(node, L"szMachineNameEnglish", computer_name);
727 if (FAILED(hr))
728 return hr;
730 hr = add_bstr_property(node, L"szSystemManufacturerEnglish", L"");
731 if (FAILED(hr))
732 return hr;
734 hr = add_bstr_property(node, L"szSystemModelEnglish", L"");
735 if (FAILED(hr))
736 return hr;
738 hr = add_bstr_property(node, L"szBIOSEnglish", L"");
739 if (FAILED(hr))
740 return hr;
742 hr = fill_processor_information(node);
743 if (FAILED(hr))
744 return hr;
746 hr = add_bstr_property(node, L"szSetupParamEnglish", L"Not present");
747 if (FAILED(hr))
748 return hr;
750 hr = add_bstr_property(node, L"szDxDiagVersion", L"");
751 if (FAILED(hr))
752 return hr;
754 hr = fill_language_information(node);
755 if (FAILED(hr))
756 return hr;
758 hr = fill_datetime_information(node);
759 if (FAILED(hr))
760 return hr;
762 hr = fill_os_string_information(node, &info);
763 if (FAILED(hr))
764 return hr;
766 return S_OK;
769 /* The logic from pixelformat_for_depth() in dlls/wined3d/utils.c is reversed. */
770 static DWORD depth_for_pixelformat(D3DFORMAT format)
772 switch (format)
774 case D3DFMT_P8: return 8;
775 case D3DFMT_X1R5G5B5: return 15;
776 case D3DFMT_R5G6B5: return 16;
777 /* This case will fail to distinguish an original bpp of 24. */
778 case D3DFMT_X8R8G8B8: return 32;
779 default:
780 FIXME("Unknown D3DFORMAT %d, returning 32 bpp\n", format);
781 return 32;
785 static BOOL get_texture_memory(GUID *adapter, DWORD *available_mem)
787 IDirectDraw7 *pDirectDraw;
788 HRESULT hr;
789 DDSCAPS2 dd_caps;
791 hr = DirectDrawCreateEx(adapter, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
792 if (SUCCEEDED(hr))
794 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
795 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.u1.dwCaps4 = 0;
796 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, available_mem, NULL);
797 IDirectDraw7_Release(pDirectDraw);
798 if (SUCCEEDED(hr))
799 return TRUE;
802 return FALSE;
805 static const WCHAR *vendor_id_to_manufacturer_string(DWORD vendor_id)
807 unsigned int i;
808 static const struct
810 DWORD id;
811 const WCHAR *name;
813 vendors[] =
815 {0x1002, L"ATI Technologies Inc."},
816 {0x10de, L"NVIDIA"},
817 {0x15ad, L"VMware"},
818 {0x1af4, L"Red Hat"},
819 {0x8086, L"Intel Corporation"},
822 for (i = 0; i < ARRAY_SIZE(vendors); ++i)
824 if (vendors[i].id == vendor_id)
825 return vendors[i].name;
828 FIXME("Unknown PCI vendor ID 0x%04x.\n", vendor_id);
830 return L"Unknown";
833 static HRESULT fill_display_information_d3d(IDxDiagContainerImpl_Container *node)
835 IDxDiagContainerImpl_Container *display_adapter;
836 HRESULT hr;
837 IDirect3D9 *pDirect3D9;
838 WCHAR buffer[256];
839 UINT index, count;
841 pDirect3D9 = Direct3DCreate9(D3D_SDK_VERSION);
842 if (!pDirect3D9)
843 return E_FAIL;
845 count = IDirect3D9_GetAdapterCount(pDirect3D9);
846 for (index = 0; index < count; index++)
848 D3DADAPTER_IDENTIFIER9 adapter_info;
849 D3DDISPLAYMODE adapter_mode;
850 D3DCAPS9 device_caps;
851 DWORD available_mem = 0;
852 BOOL hardware_accel;
854 swprintf(buffer, ARRAY_SIZE(buffer), L"%u", index);
855 display_adapter = allocate_information_node(buffer);
856 if (!display_adapter)
858 hr = E_OUTOFMEMORY;
859 goto cleanup;
862 add_subcontainer(node, display_adapter);
864 hr = IDirect3D9_GetAdapterIdentifier(pDirect3D9, index, 0, &adapter_info);
865 if (SUCCEEDED(hr))
867 WCHAR driverW[sizeof(adapter_info.Driver)];
868 WCHAR descriptionW[sizeof(adapter_info.Description)];
869 WCHAR devicenameW[sizeof(adapter_info.DeviceName)];
871 MultiByteToWideChar(CP_ACP, 0, adapter_info.Driver, -1, driverW, ARRAY_SIZE(driverW));
872 MultiByteToWideChar(CP_ACP, 0, adapter_info.Description, -1, descriptionW,
873 ARRAY_SIZE(descriptionW));
874 MultiByteToWideChar(CP_ACP, 0, adapter_info.DeviceName, -1, devicenameW,
875 ARRAY_SIZE(devicenameW));
877 hr = add_bstr_property(display_adapter, L"szDriverName", driverW);
878 if (FAILED(hr))
879 goto cleanup;
881 hr = add_bstr_property(display_adapter, L"szDescription", descriptionW);
882 if (FAILED(hr))
883 goto cleanup;
885 hr = add_bstr_property(display_adapter, L"szDeviceName", devicenameW);
886 if (FAILED(hr))
887 goto cleanup;
889 swprintf(buffer, ARRAY_SIZE(buffer), L"%u.%u.%04u.%04u",
890 HIWORD(adapter_info.DriverVersion.u.HighPart), LOWORD(adapter_info.DriverVersion.u.HighPart),
891 HIWORD(adapter_info.DriverVersion.u.LowPart), LOWORD(adapter_info.DriverVersion.u.LowPart));
893 hr = add_bstr_property(display_adapter, L"szDriverVersion", buffer);
894 if (FAILED(hr))
895 goto cleanup;
897 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.VendorId);
898 hr = add_bstr_property(display_adapter, L"szVendorId", buffer);
899 if (FAILED(hr))
900 goto cleanup;
902 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.DeviceId);
903 hr = add_bstr_property(display_adapter, L"szDeviceId", buffer);
904 if (FAILED(hr))
905 goto cleanup;
907 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%08x", adapter_info.SubSysId);
908 hr = add_bstr_property(display_adapter, L"szSubSysId", buffer);
909 if (FAILED(hr))
910 goto cleanup;
912 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.Revision);
913 hr = add_bstr_property(display_adapter, L"szRevisionId", buffer);
914 if (FAILED(hr))
915 goto cleanup;
917 StringFromGUID2(&adapter_info.DeviceIdentifier, buffer, 39);
918 hr = add_bstr_property(display_adapter, L"szDeviceIdentifier", buffer);
919 if (FAILED(hr))
920 goto cleanup;
922 hr = add_bstr_property(display_adapter, L"szManufacturer",
923 vendor_id_to_manufacturer_string(adapter_info.VendorId));
924 if (FAILED(hr))
925 goto cleanup;
928 hr = IDirect3D9_GetAdapterDisplayMode(pDirect3D9, index, &adapter_mode);
929 if (SUCCEEDED(hr))
931 hr = add_ui4_property(display_adapter, L"dwWidth", adapter_mode.Width);
932 if (FAILED(hr))
933 goto cleanup;
935 hr = add_ui4_property(display_adapter, L"dwHeight", adapter_mode.Height);
936 if (FAILED(hr))
937 goto cleanup;
939 hr = add_ui4_property(display_adapter, L"dwRefreshRate", adapter_mode.RefreshRate);
940 if (FAILED(hr))
941 goto cleanup;
943 hr = add_ui4_property(display_adapter, L"dwBpp", depth_for_pixelformat(adapter_mode.Format));
944 if (FAILED(hr))
945 goto cleanup;
947 swprintf(buffer, ARRAY_SIZE(buffer), L"%d x %d (%d bit) (%dHz)", adapter_mode.Width,
948 adapter_mode.Height, depth_for_pixelformat(adapter_mode.Format),
949 adapter_mode.RefreshRate);
951 hr = add_bstr_property(display_adapter, L"szDisplayModeLocalized", buffer);
952 if (FAILED(hr))
953 goto cleanup;
955 hr = add_bstr_property(display_adapter, L"szDisplayModeEnglish", buffer);
956 if (FAILED(hr))
957 goto cleanup;
960 hr = add_bstr_property(display_adapter, L"szKeyDeviceKey", L"");
961 if (FAILED(hr))
962 goto cleanup;
964 hr = add_bstr_property(display_adapter, L"szKeyDeviceID", L"");
965 if (FAILED(hr))
966 goto cleanup;
968 hr = add_bstr_property(display_adapter, L"szChipType", L"");
969 if (FAILED(hr))
970 goto cleanup;
972 hr = add_bstr_property(display_adapter, L"szDACType", L"");
973 if (FAILED(hr))
974 goto cleanup;
976 hr = add_bstr_property(display_adapter, L"szRevision", L"");
977 if (FAILED(hr))
978 goto cleanup;
980 if (!get_texture_memory(&adapter_info.DeviceIdentifier, &available_mem))
981 WARN("get_texture_memory helper failed\n");
983 swprintf(buffer, ARRAY_SIZE(buffer), L"%.1f MB", available_mem / 1000000.0f);
985 hr = add_bstr_property(display_adapter, L"szDisplayMemoryLocalized", buffer);
986 if (FAILED(hr))
987 goto cleanup;
989 hr = add_bstr_property(display_adapter, L"szDisplayMemoryEnglish", buffer);
990 if (FAILED(hr))
991 goto cleanup;
993 hr = IDirect3D9_GetDeviceCaps(pDirect3D9, index, D3DDEVTYPE_HAL, &device_caps);
994 hardware_accel = SUCCEEDED(hr);
996 hr = add_bool_property(display_adapter, L"b3DAccelerationEnabled", hardware_accel);
997 if (FAILED(hr))
998 goto cleanup;
1000 hr = add_bool_property(display_adapter, L"b3DAccelerationExists", hardware_accel);
1001 if (FAILED(hr))
1002 goto cleanup;
1004 hr = add_bool_property(display_adapter, L"bDDAccelerationEnabled", hardware_accel);
1005 if (FAILED(hr))
1006 goto cleanup;
1008 hr = add_bool_property(display_adapter, L"bNoHardware", FALSE);
1009 if (FAILED(hr))
1010 goto cleanup;
1012 hr = add_bool_property(display_adapter, L"bCanRenderWindow", TRUE);
1013 if (FAILED(hr))
1014 goto cleanup;
1016 hr = add_bstr_property(display_adapter, L"szMonitorName", L"Generic PnP Monitor");
1017 if (FAILED(hr))
1018 goto cleanup;
1020 hr = add_bstr_property(display_adapter, L"szMonitorMaxRes", L"Failed to get parameter");
1021 if (FAILED(hr))
1022 goto cleanup;
1024 hr = add_bstr_property(display_adapter, L"szDriverAttributes", L"Final Retail");
1025 if (FAILED(hr))
1026 goto cleanup;
1028 hr = add_bstr_property(display_adapter, L"szDriverLanguageEnglish", L"English");
1029 if (FAILED(hr))
1030 goto cleanup;
1032 hr = add_bstr_property(display_adapter, L"szDriverLanguageLocalized", L"English");
1033 if (FAILED(hr))
1034 goto cleanup;
1036 hr = add_bstr_property(display_adapter, L"szDriverDateEnglish", L"1/1/2016 10:00:00");
1037 if (FAILED(hr))
1038 goto cleanup;
1040 hr = add_bstr_property(display_adapter, L"szDriverDateLocalized", L"1/1/2016 10:00:00 AM");
1041 if (FAILED(hr))
1042 goto cleanup;
1044 hr = add_i4_property(display_adapter, L"lDriverSize", 10 * 1024 * 1024);
1045 if (FAILED(hr))
1046 goto cleanup;
1048 hr = add_bstr_property(display_adapter, L"szMiniVdd", L"n/a");
1049 if (FAILED(hr))
1050 goto cleanup;
1052 hr = add_bstr_property(display_adapter, L"szMiniVddDateLocalized", L"n/a");
1053 if (FAILED(hr))
1054 goto cleanup;
1056 hr = add_bstr_property(display_adapter, L"szMiniVddDateEnglish", L"n/a");
1057 if (FAILED(hr))
1058 goto cleanup;
1060 hr = add_i4_property(display_adapter, L"lMiniVddSize", 0);
1061 if (FAILED(hr))
1062 goto cleanup;
1064 hr = add_bstr_property(display_adapter, L"szVdd", L"n/a");
1065 if (FAILED(hr))
1066 goto cleanup;
1068 hr = add_bool_property(display_adapter, L"bDriverBeta", FALSE);
1069 if (FAILED(hr))
1070 goto cleanup;
1072 hr = add_bool_property(display_adapter, L"bDriverDebug", FALSE);
1073 if (FAILED(hr))
1074 goto cleanup;
1076 hr = add_bool_property(display_adapter, L"bDriverSigned", TRUE);
1077 if (FAILED(hr))
1078 goto cleanup;
1080 hr = add_bool_property(display_adapter, L"bDriverSignedValid", TRUE);
1081 if (FAILED(hr))
1082 goto cleanup;
1084 hr = add_bstr_property(display_adapter, L"szDriverSignDate", L"n/a");
1085 if (FAILED(hr))
1086 goto cleanup;
1088 hr = add_ui4_property(display_adapter, L"dwDDIVersion", 11);
1089 if (FAILED(hr))
1090 goto cleanup;
1092 hr = add_bstr_property(display_adapter, L"szDDIVersionEnglish", L"11");
1093 if (FAILED(hr))
1094 goto cleanup;
1096 hr = add_bstr_property(display_adapter, L"szDDIVersionLocalized", L"11");
1097 if (FAILED(hr))
1098 goto cleanup;
1100 hr = add_ui4_property(display_adapter, L"iAdapter", index);
1101 if (FAILED(hr))
1102 goto cleanup;
1104 hr = add_ui4_property(display_adapter, L"dwWHQLLevel", 0);
1105 if (FAILED(hr))
1106 goto cleanup;
1109 hr = S_OK;
1110 cleanup:
1111 IDirect3D9_Release(pDirect3D9);
1112 return hr;
1115 static HRESULT fill_display_information_fallback(IDxDiagContainerImpl_Container *node)
1117 static const WCHAR *empty_properties[] =
1119 L"szDeviceIdentifier", L"szVendorId", L"szDeviceId", L"szKeyDeviceKey",
1120 L"szKeyDeviceID", L"szDriverName", L"szDriverVersion", L"szSubSysId",
1121 L"szRevisionId", L"szManufacturer", L"szChipType", L"szDACType", L"szRevision"
1124 IDxDiagContainerImpl_Container *display_adapter;
1125 HRESULT hr;
1126 IDirectDraw7 *pDirectDraw;
1127 DDSCAPS2 dd_caps;
1128 DISPLAY_DEVICEW disp_dev;
1129 DDSURFACEDESC2 surface_descr;
1130 DWORD tmp;
1131 WCHAR buffer[256];
1133 display_adapter = allocate_information_node(L"0");
1134 if (!display_adapter)
1135 return E_OUTOFMEMORY;
1137 add_subcontainer(node, display_adapter);
1139 disp_dev.cb = sizeof(disp_dev);
1140 if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
1142 hr = add_bstr_property(display_adapter, L"szDeviceName", disp_dev.DeviceName);
1143 if (FAILED(hr))
1144 return hr;
1146 hr = add_bstr_property(display_adapter, L"szDescription", disp_dev.DeviceString);
1147 if (FAILED(hr))
1148 return hr;
1151 /* Silently ignore a failure from DirectDrawCreateEx. */
1152 hr = DirectDrawCreateEx(NULL, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
1153 if (FAILED(hr))
1154 return S_OK;
1156 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
1157 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.u1.dwCaps4 = 0;
1158 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, &tmp, NULL);
1159 if (SUCCEEDED(hr))
1161 swprintf(buffer, ARRAY_SIZE(buffer), L"%.1f MB", tmp / 1000000.0f);
1163 hr = add_bstr_property(display_adapter, L"szDisplayMemoryLocalized", buffer);
1164 if (FAILED(hr))
1165 goto cleanup;
1167 hr = add_bstr_property(display_adapter, L"szDisplayMemoryEnglish", buffer);
1168 if (FAILED(hr))
1169 goto cleanup;
1172 surface_descr.dwSize = sizeof(surface_descr);
1173 hr = IDirectDraw7_GetDisplayMode(pDirectDraw, &surface_descr);
1174 if (SUCCEEDED(hr))
1176 if (surface_descr.dwFlags & DDSD_WIDTH)
1178 hr = add_ui4_property(display_adapter, L"dwWidth", surface_descr.dwWidth);
1179 if (FAILED(hr))
1180 goto cleanup;
1183 if (surface_descr.dwFlags & DDSD_HEIGHT)
1185 hr = add_ui4_property(display_adapter, L"dwHeight", surface_descr.dwHeight);
1186 if (FAILED(hr))
1187 goto cleanup;
1190 if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
1192 hr = add_ui4_property(display_adapter, L"dwBpp",
1193 surface_descr.u4.ddpfPixelFormat.u1.dwRGBBitCount);
1194 if (FAILED(hr))
1195 goto cleanup;
1199 hr = add_ui4_property(display_adapter, L"dwRefreshRate", 60);
1200 if (FAILED(hr))
1201 goto cleanup;
1203 for (tmp = 0; tmp < ARRAY_SIZE(empty_properties); tmp++)
1205 hr = add_bstr_property(display_adapter, empty_properties[tmp], L"");
1206 if (FAILED(hr))
1207 goto cleanup;
1210 hr = S_OK;
1211 cleanup:
1212 IDirectDraw7_Release(pDirectDraw);
1213 return hr;
1216 static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
1218 HRESULT hr;
1220 /* Try to use Direct3D to obtain the required information first. */
1221 hr = fill_display_information_d3d(node);
1222 if (hr != E_FAIL)
1223 return hr;
1225 return fill_display_information_fallback(node);
1228 struct enum_context
1230 IDxDiagContainerImpl_Container *cont;
1231 HRESULT hr;
1232 int index;
1235 static LPWSTR guid_to_string(LPWSTR lpwstr, REFGUID lpcguid)
1237 wsprintfW(lpwstr, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", lpcguid->Data1, lpcguid->Data2,
1238 lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1], lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
1239 lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
1241 return lpwstr;
1244 BOOL CALLBACK dsound_enum(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID context)
1246 struct enum_context *enum_ctx = context;
1247 IDxDiagContainerImpl_Container *device;
1248 WCHAR buffer[256];
1249 const WCHAR *p, *name;
1251 /* the default device is enumerated twice, one time without GUID */
1252 if (!guid) return TRUE;
1254 swprintf(buffer, ARRAY_SIZE(buffer), L"%u", enum_ctx->index);
1255 device = allocate_information_node(buffer);
1256 if (!device)
1258 enum_ctx->hr = E_OUTOFMEMORY;
1259 return FALSE;
1262 add_subcontainer(enum_ctx->cont, device);
1264 guid_to_string(buffer, guid);
1265 enum_ctx->hr = add_bstr_property(device, L"szGuidDeviceID", buffer);
1266 if (FAILED(enum_ctx->hr))
1267 return FALSE;
1269 enum_ctx->hr = add_bstr_property(device, L"szDescription", desc);
1270 if (FAILED(enum_ctx->hr))
1271 return FALSE;
1273 enum_ctx->hr = add_bstr_property(device, L"szDriverPath", module);
1274 if (FAILED(enum_ctx->hr))
1275 return FALSE;
1277 name = module;
1278 if ((p = wcsrchr(name, '\\'))) name = p + 1;
1279 if ((p = wcsrchr(name, '/'))) name = p + 1;
1281 enum_ctx->hr = add_bstr_property(device, L"szDriverName", name);
1282 if (FAILED(enum_ctx->hr))
1283 return FALSE;
1285 enum_ctx->index++;
1286 return TRUE;
1289 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
1291 struct enum_context enum_ctx;
1292 IDxDiagContainerImpl_Container *cont;
1294 cont = allocate_information_node(L"DxDiag_SoundDevices");
1295 if (!cont)
1296 return E_OUTOFMEMORY;
1298 add_subcontainer(node, cont);
1300 enum_ctx.cont = cont;
1301 enum_ctx.hr = S_OK;
1302 enum_ctx.index = 0;
1304 DirectSoundEnumerateW(dsound_enum, &enum_ctx);
1305 if (FAILED(enum_ctx.hr))
1306 return enum_ctx.hr;
1308 cont = allocate_information_node(L"DxDiag_SoundCaptureDevices");
1309 if (!cont)
1310 return E_OUTOFMEMORY;
1312 add_subcontainer(node, cont);
1314 enum_ctx.cont = cont;
1315 enum_ctx.hr = S_OK;
1316 enum_ctx.index = 0;
1318 DirectSoundCaptureEnumerateW(dsound_enum, &enum_ctx);
1319 if (FAILED(enum_ctx.hr))
1320 return enum_ctx.hr;
1322 return S_OK;
1325 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
1327 return S_OK;
1330 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
1332 return S_OK;
1335 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
1337 return S_OK;
1340 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
1342 return S_OK;
1345 static HRESULT fill_file_description(IDxDiagContainerImpl_Container *node, const WCHAR *szFilePath, const WCHAR *szFileName)
1347 HRESULT hr;
1348 WCHAR *szFile;
1349 WCHAR szVersion_v[1024];
1350 DWORD retval, hdl;
1351 void *pVersionInfo = NULL;
1352 BOOL boolret = FALSE;
1353 UINT uiLength;
1354 VS_FIXEDFILEINFO *pFileInfo;
1356 TRACE("Filling container %p for %s in %s\n", node,
1357 debugstr_w(szFileName), debugstr_w(szFilePath));
1359 szFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(szFilePath) +
1360 lstrlenW(szFileName) + 2 /* slash + terminator */));
1361 if (!szFile)
1362 return E_OUTOFMEMORY;
1364 lstrcpyW(szFile, szFilePath);
1365 lstrcatW(szFile, L"\\");
1366 lstrcatW(szFile, szFileName);
1368 retval = GetFileVersionInfoSizeW(szFile, &hdl);
1369 if (retval)
1371 pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
1372 if (!pVersionInfo)
1374 hr = E_OUTOFMEMORY;
1375 goto cleanup;
1378 if (GetFileVersionInfoW(szFile, 0, retval, pVersionInfo) &&
1379 VerQueryValueW(pVersionInfo, L"\\", (void **)&pFileInfo, &uiLength))
1380 boolret = TRUE;
1383 hr = add_bstr_property(node, L"szPath", szFile);
1384 if (FAILED(hr))
1385 goto cleanup;
1387 hr = add_bstr_property(node, L"szName", szFileName);
1388 if (FAILED(hr))
1389 goto cleanup;
1391 hr = add_bool_property(node, L"bExists", boolret);
1392 if (FAILED(hr))
1393 goto cleanup;
1395 if (boolret)
1397 swprintf(szVersion_v, ARRAY_SIZE(szVersion_v), L"%u.%02u.%04u.%04u",
1398 HIWORD(pFileInfo->dwFileVersionMS), LOWORD(pFileInfo->dwFileVersionMS),
1399 HIWORD(pFileInfo->dwFileVersionLS), LOWORD(pFileInfo->dwFileVersionLS));
1401 TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));
1403 hr = add_bstr_property(node, L"szVersion", szVersion_v);
1404 if (FAILED(hr))
1405 goto cleanup;
1407 hr = add_bstr_property(node, L"szAttributes", L"Final Retail");
1408 if (FAILED(hr))
1409 goto cleanup;
1411 hr = add_bstr_property(node, L"szLanguageEnglish", L"English");
1412 if (FAILED(hr))
1413 goto cleanup;
1415 hr = add_ui4_property(node, L"dwFileTimeHigh", pFileInfo->dwFileDateMS);
1416 if (FAILED(hr))
1417 goto cleanup;
1419 hr = add_ui4_property(node, L"dwFileTimeLow", pFileInfo->dwFileDateLS);
1420 if (FAILED(hr))
1421 goto cleanup;
1423 hr = add_bool_property(node, L"bBeta",
1424 ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
1425 if (FAILED(hr))
1426 goto cleanup;
1428 hr = add_bool_property(node, L"bDebug",
1429 ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
1430 if (FAILED(hr))
1431 goto cleanup;
1434 hr = S_OK;
1435 cleanup:
1436 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1437 HeapFree(GetProcessHeap(), 0, szFile);
1439 return hr;
1441 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1443 static const WCHAR dlls[][15] =
1445 L"d3d8.dll",
1446 L"d3d9.dll",
1447 L"ddraw.dll",
1448 L"devenum.dll",
1449 L"dinput8.dll",
1450 L"dinput.dll",
1451 L"dmband.dll",
1452 L"dmcompos.dll",
1453 L"dmime.dll",
1454 L"dmloader.dll",
1455 L"dmscript.dll",
1456 L"dmstyle.dll",
1457 L"dmsynth.dll",
1458 L"dmusic.dll",
1459 L"dplayx.dll",
1460 L"dpnet.dll",
1461 L"dsound.dll",
1462 L"dswave.dll",
1463 L"dxdiagn.dll",
1464 L"quartz.dll"
1467 HRESULT hr;
1468 WCHAR szFilePath[MAX_PATH];
1469 INT i;
1471 GetSystemDirectoryW(szFilePath, MAX_PATH);
1473 for (i = 0; i < ARRAY_SIZE(dlls); i++)
1475 WCHAR szFileID[5];
1476 IDxDiagContainerImpl_Container *file_container;
1478 swprintf(szFileID, ARRAY_SIZE(szFileID), L"%d", i);
1480 file_container = allocate_information_node(szFileID);
1481 if (!file_container)
1482 return E_OUTOFMEMORY;
1484 hr = fill_file_description(file_container, szFilePath, dlls[i]);
1485 if (FAILED(hr))
1487 free_information_tree(file_container);
1488 continue;
1491 add_subcontainer(node, file_container);
1494 return S_OK;
1497 static HRESULT read_property_names(IPropertyBag *pPropBag, VARIANT *friendly_name, VARIANT *clsid_name)
1499 HRESULT hr;
1501 VariantInit(friendly_name);
1502 VariantInit(clsid_name);
1504 hr = IPropertyBag_Read(pPropBag, L"FriendlyName", friendly_name, 0);
1505 if (FAILED(hr))
1506 return hr;
1508 hr = IPropertyBag_Read(pPropBag, L"CLSID", clsid_name, 0);
1509 if (FAILED(hr))
1511 VariantClear(friendly_name);
1512 return hr;
1515 return S_OK;
1518 static HRESULT fill_filter_data_information(IDxDiagContainerImpl_Container *subcont, BYTE *pData, ULONG cb)
1520 HRESULT hr;
1521 IFilterMapper2 *pFileMapper = NULL;
1522 IAMFilterData *pFilterData = NULL;
1523 BYTE *ppRF = NULL;
1524 REGFILTER2 *pRF = NULL;
1525 WCHAR bufferW[10];
1526 ULONG j;
1527 DWORD dwNOutputs = 0;
1528 DWORD dwNInputs = 0;
1530 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
1531 (void **)&pFileMapper);
1532 if (FAILED(hr))
1533 return hr;
1535 hr = IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData);
1536 if (FAILED(hr))
1537 goto cleanup;
1539 hr = IAMFilterData_ParseFilterData(pFilterData, pData, cb, &ppRF);
1540 if (FAILED(hr))
1541 goto cleanup;
1542 pRF = ((REGFILTER2**)ppRF)[0];
1544 swprintf(bufferW, ARRAY_SIZE(bufferW), L"v%d", pRF->dwVersion);
1545 hr = add_bstr_property(subcont, L"szVersion", bufferW);
1546 if (FAILED(hr))
1547 goto cleanup;
1549 if (pRF->dwVersion == 1)
1551 for (j = 0; j < pRF->cPins; j++)
1552 if (pRF->rgPins[j].bOutput)
1553 dwNOutputs++;
1554 else
1555 dwNInputs++;
1557 else if (pRF->dwVersion == 2)
1559 for (j = 0; j < pRF->cPins2; j++)
1560 if (pRF->rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
1561 dwNOutputs++;
1562 else
1563 dwNInputs++;
1566 hr = add_ui4_property(subcont, L"dwInputs", dwNInputs);
1567 if (FAILED(hr))
1568 goto cleanup;
1570 hr = add_ui4_property(subcont, L"dwOutputs", dwNOutputs);
1571 if (FAILED(hr))
1572 goto cleanup;
1574 hr = add_ui4_property(subcont, L"dwMerit", pRF->dwMerit);
1575 if (FAILED(hr))
1576 goto cleanup;
1578 hr = S_OK;
1579 cleanup:
1580 CoTaskMemFree(pRF);
1581 if (pFilterData) IAMFilterData_Release(pFilterData);
1582 if (pFileMapper) IFilterMapper2_Release(pFileMapper);
1584 return hr;
1587 static HRESULT fill_filter_container(IDxDiagContainerImpl_Container *subcont, IMoniker *pMoniker)
1589 HRESULT hr;
1590 IPropertyBag *pPropFilterBag = NULL;
1591 BYTE *pData;
1592 VARIANT friendly_name;
1593 VARIANT clsid_name;
1594 VARIANT v;
1596 VariantInit(&friendly_name);
1597 VariantInit(&clsid_name);
1598 VariantInit(&v);
1600 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void **)&pPropFilterBag);
1601 if (FAILED(hr))
1602 return hr;
1604 hr = read_property_names(pPropFilterBag, &friendly_name, &clsid_name);
1605 if (FAILED(hr))
1606 goto cleanup;
1608 TRACE("Name = %s\n", debugstr_w(V_BSTR(&friendly_name)));
1609 TRACE("CLSID = %s\n", debugstr_w(V_BSTR(&clsid_name)));
1611 hr = add_bstr_property(subcont, L"szName", V_BSTR(&friendly_name));
1612 if (FAILED(hr))
1613 goto cleanup;
1615 hr = add_bstr_property(subcont, L"ClsidFilter", V_BSTR(&clsid_name));
1616 if (FAILED(hr))
1617 goto cleanup;
1619 hr = IPropertyBag_Read(pPropFilterBag, L"FilterData", &v, NULL);
1620 if (FAILED(hr))
1621 goto cleanup;
1623 hr = SafeArrayAccessData(V_ARRAY(&v), (void **)&pData);
1624 if (FAILED(hr))
1625 goto cleanup;
1627 hr = fill_filter_data_information(subcont, pData, V_ARRAY(&v)->rgsabound->cElements);
1628 SafeArrayUnaccessData(V_ARRAY(&v));
1629 if (FAILED(hr))
1630 goto cleanup;
1632 hr = S_OK;
1633 cleanup:
1634 VariantClear(&v);
1635 VariantClear(&clsid_name);
1636 VariantClear(&friendly_name);
1637 if (pPropFilterBag) IPropertyBag_Release(pPropFilterBag);
1639 return hr;
1642 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1644 HRESULT hr;
1645 int i = 0;
1646 ICreateDevEnum *pCreateDevEnum;
1647 IEnumMoniker *pEmCat = NULL;
1648 IMoniker *pMCat = NULL;
1649 IEnumMoniker *pEnum = NULL;
1651 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1652 &IID_ICreateDevEnum, (void **)&pCreateDevEnum);
1653 if (FAILED(hr))
1654 return hr;
1656 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
1657 if (FAILED(hr))
1658 goto cleanup;
1660 while (IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL) == S_OK)
1662 VARIANT vCatName;
1663 VARIANT vCatClsid;
1664 IPropertyBag *pPropBag;
1665 CLSID clsidCat;
1666 IMoniker *pMoniker = NULL;
1668 hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void **)&pPropBag);
1669 if (FAILED(hr))
1671 IMoniker_Release(pMCat);
1672 break;
1675 hr = read_property_names(pPropBag, &vCatName, &vCatClsid);
1676 IPropertyBag_Release(pPropBag);
1677 if (FAILED(hr))
1679 IMoniker_Release(pMCat);
1680 break;
1683 hr = CLSIDFromString(V_BSTR(&vCatClsid), &clsidCat);
1684 if (FAILED(hr))
1686 IMoniker_Release(pMCat);
1687 VariantClear(&vCatClsid);
1688 VariantClear(&vCatName);
1689 break;
1692 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1693 if (hr != S_OK)
1695 IMoniker_Release(pMCat);
1696 VariantClear(&vCatClsid);
1697 VariantClear(&vCatName);
1698 continue;
1701 TRACE("Enumerating class %s\n", debugstr_guid(&clsidCat));
1703 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1705 WCHAR bufferW[10];
1706 IDxDiagContainerImpl_Container *subcont;
1708 swprintf(bufferW, ARRAY_SIZE(bufferW), L"%d", i);
1709 subcont = allocate_information_node(bufferW);
1710 if (!subcont)
1712 hr = E_OUTOFMEMORY;
1713 IMoniker_Release(pMoniker);
1714 break;
1717 hr = add_bstr_property(subcont, L"szCatName", V_BSTR(&vCatName));
1718 if (FAILED(hr))
1720 free_information_tree(subcont);
1721 IMoniker_Release(pMoniker);
1722 break;
1725 hr = add_bstr_property(subcont, L"ClsidCat", V_BSTR(&vCatClsid));
1726 if (FAILED(hr))
1728 free_information_tree(subcont);
1729 IMoniker_Release(pMoniker);
1730 break;
1733 hr = fill_filter_container(subcont, pMoniker);
1734 IMoniker_Release(pMoniker);
1735 if (FAILED(hr))
1737 WARN("Skipping invalid filter\n");
1738 free_information_tree(subcont);
1739 hr = S_OK;
1740 continue;
1743 add_subcontainer(node, subcont);
1744 i++;
1747 IEnumMoniker_Release(pEnum);
1748 IMoniker_Release(pMCat);
1749 VariantClear(&vCatClsid);
1750 VariantClear(&vCatName);
1752 if (FAILED(hr))
1753 break;
1756 cleanup:
1757 if (pEmCat) IEnumMoniker_Release(pEmCat);
1758 ICreateDevEnum_Release(pCreateDevEnum);
1759 return hr;
1762 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1764 return S_OK;
1767 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1769 static const struct
1771 const WCHAR *name;
1772 HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1773 } root_children[] =
1775 {L"DxDiag_SystemInfo", build_systeminfo_tree},
1776 {L"DxDiag_DisplayDevices", build_displaydevices_tree},
1777 {L"DxDiag_DirectSound", build_directsound_tree},
1778 {L"DxDiag_DirectMusic", build_directmusic_tree},
1779 {L"DxDiag_DirectInput", build_directinput_tree},
1780 {L"DxDiag_DirectPlay", build_directplay_tree},
1781 {L"DxDiag_SystemDevices", build_systemdevices_tree},
1782 {L"DxDiag_DirectXFiles", build_directxfiles_tree},
1783 {L"DxDiag_DirectShowFilters", build_directshowfilters_tree},
1784 {L"DxDiag_LogicalDisks", build_logicaldisks_tree},
1787 IDxDiagContainerImpl_Container *info_root;
1788 size_t index;
1790 info_root = allocate_information_node(NULL);
1791 if (!info_root)
1792 return E_OUTOFMEMORY;
1794 for (index = 0; index < ARRAY_SIZE(root_children); index++)
1796 IDxDiagContainerImpl_Container *node;
1797 HRESULT hr;
1799 node = allocate_information_node(root_children[index].name);
1800 if (!node)
1802 free_information_tree(info_root);
1803 return E_OUTOFMEMORY;
1806 hr = root_children[index].initfunc(node);
1807 if (FAILED(hr))
1809 free_information_tree(node);
1810 free_information_tree(info_root);
1811 return hr;
1814 add_subcontainer(info_root, node);
1817 *pinfo_root = info_root;
1818 return S_OK;