dxgi: Add IDXGISwapChain2 stubs for D3D11.
[wine.git] / dlls / dxdiagn / provider.c
blob0a6111fff2567fed85a20f1cdb54d18db75cfd9e
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 #include "dxdiag_private.h"
26 #include "winver.h"
27 #include "objidl.h"
28 #include "uuids.h"
29 #include "vfw.h"
30 #include "mmddk.h"
31 #include "d3d9.h"
32 #include "strmif.h"
33 #include "initguid.h"
34 #include "wine/fil_data.h"
35 #include "psapi.h"
36 #include "wbemcli.h"
37 #include "dsound.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
43 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root);
44 static void free_information_tree(IDxDiagContainerImpl_Container *node);
46 struct IDxDiagProviderImpl
48 IDxDiagProvider IDxDiagProvider_iface;
49 LONG ref;
50 BOOL init;
51 DXDIAG_INIT_PARAMS params;
52 IDxDiagContainerImpl_Container *info_root;
55 static inline IDxDiagProviderImpl *impl_from_IDxDiagProvider(IDxDiagProvider *iface)
57 return CONTAINING_RECORD(iface, IDxDiagProviderImpl, IDxDiagProvider_iface);
60 /* IDxDiagProvider IUnknown parts follow: */
61 static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(IDxDiagProvider *iface, REFIID riid,
62 void **ppobj)
64 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
66 if (!ppobj) return E_INVALIDARG;
68 if (IsEqualGUID(riid, &IID_IUnknown)
69 || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
70 IUnknown_AddRef(iface);
71 *ppobj = &This->IDxDiagProvider_iface;
72 return S_OK;
75 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
76 *ppobj = NULL;
77 return E_NOINTERFACE;
80 static ULONG WINAPI IDxDiagProviderImpl_AddRef(IDxDiagProvider *iface)
82 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
83 ULONG refCount = InterlockedIncrement(&This->ref);
85 TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
87 DXDIAGN_LockModule();
89 return refCount;
92 static ULONG WINAPI IDxDiagProviderImpl_Release(IDxDiagProvider *iface)
94 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
95 ULONG refCount = InterlockedDecrement(&This->ref);
97 TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
99 if (!refCount) {
100 free_information_tree(This->info_root);
101 HeapFree(GetProcessHeap(), 0, This);
104 DXDIAGN_UnlockModule();
106 return refCount;
109 /* IDxDiagProvider Interface follow: */
110 static HRESULT WINAPI IDxDiagProviderImpl_Initialize(IDxDiagProvider *iface,
111 DXDIAG_INIT_PARAMS *pParams)
113 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
114 HRESULT hr;
116 TRACE("(%p,%p)\n", iface, pParams);
118 if (NULL == pParams) {
119 return E_POINTER;
121 if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS) ||
122 pParams->dwDxDiagHeaderVersion != DXDIAG_DX9_SDK_VERSION) {
123 return E_INVALIDARG;
126 if (!This->info_root)
128 hr = build_information_tree(&This->info_root);
129 if (FAILED(hr))
130 return hr;
133 This->init = TRUE;
134 memcpy(&This->params, pParams, pParams->dwSize);
135 return S_OK;
138 static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(IDxDiagProvider *iface,
139 IDxDiagContainer **ppInstance)
141 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
143 TRACE("(%p,%p)\n", iface, ppInstance);
145 if (FALSE == This->init) {
146 return CO_E_NOTINITIALIZED;
149 return DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, This->info_root,
150 &This->IDxDiagProvider_iface, (void **)ppInstance);
153 static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
155 IDxDiagProviderImpl_QueryInterface,
156 IDxDiagProviderImpl_AddRef,
157 IDxDiagProviderImpl_Release,
158 IDxDiagProviderImpl_Initialize,
159 IDxDiagProviderImpl_GetRootContainer
162 HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
163 IDxDiagProviderImpl* provider;
165 TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
167 *ppobj = NULL;
168 if (punkOuter) return CLASS_E_NOAGGREGATION;
170 provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
171 if (NULL == provider) return E_OUTOFMEMORY;
172 provider->IDxDiagProvider_iface.lpVtbl = &DxDiagProvider_Vtbl;
173 provider->ref = 0; /* will be inited with QueryInterface */
174 return IDxDiagProviderImpl_QueryInterface(&provider->IDxDiagProvider_iface, riid, ppobj);
177 static void free_property_information(IDxDiagContainerImpl_Property *prop)
179 VariantClear(&prop->vProp);
180 HeapFree(GetProcessHeap(), 0, prop->propName);
181 HeapFree(GetProcessHeap(), 0, prop);
184 static void free_information_tree(IDxDiagContainerImpl_Container *node)
186 IDxDiagContainerImpl_Container *ptr, *cursor2;
188 if (!node)
189 return;
191 HeapFree(GetProcessHeap(), 0, node->contName);
193 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &node->subContainers, IDxDiagContainerImpl_Container, entry)
195 IDxDiagContainerImpl_Property *prop, *prop_cursor2;
197 LIST_FOR_EACH_ENTRY_SAFE(prop, prop_cursor2, &ptr->properties, IDxDiagContainerImpl_Property, entry)
199 list_remove(&prop->entry);
200 free_property_information(prop);
203 list_remove(&ptr->entry);
204 free_information_tree(ptr);
207 HeapFree(GetProcessHeap(), 0, node);
210 static IDxDiagContainerImpl_Container *allocate_information_node(const WCHAR *name)
212 IDxDiagContainerImpl_Container *ret;
214 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
215 if (!ret)
216 return NULL;
218 if (name)
220 ret->contName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name) + 1) * sizeof(*name));
221 if (!ret->contName)
223 HeapFree(GetProcessHeap(), 0, ret);
224 return NULL;
226 lstrcpyW(ret->contName, name);
229 list_init(&ret->subContainers);
230 list_init(&ret->properties);
232 return ret;
235 static IDxDiagContainerImpl_Property *allocate_property_information(const WCHAR *name)
237 IDxDiagContainerImpl_Property *ret;
239 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
240 if (!ret)
241 return NULL;
243 ret->propName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name) + 1) * sizeof(*name));
244 if (!ret->propName)
246 HeapFree(GetProcessHeap(), 0, ret);
247 return NULL;
249 lstrcpyW(ret->propName, name);
251 return ret;
254 static inline void add_subcontainer(IDxDiagContainerImpl_Container *node, IDxDiagContainerImpl_Container *subCont)
256 list_add_tail(&node->subContainers, &subCont->entry);
257 ++node->nSubContainers;
260 static inline HRESULT add_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, const WCHAR *str)
262 IDxDiagContainerImpl_Property *prop;
263 BSTR bstr;
265 prop = allocate_property_information(propName);
266 if (!prop)
267 return E_OUTOFMEMORY;
269 bstr = SysAllocString(str);
270 if (!bstr)
272 free_property_information(prop);
273 return E_OUTOFMEMORY;
276 V_VT(&prop->vProp) = VT_BSTR;
277 V_BSTR(&prop->vProp) = bstr;
279 list_add_tail(&node->properties, &prop->entry);
280 ++node->nProperties;
282 return S_OK;
285 static inline HRESULT add_ui4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, DWORD data)
287 IDxDiagContainerImpl_Property *prop;
289 prop = allocate_property_information(propName);
290 if (!prop)
291 return E_OUTOFMEMORY;
293 V_VT(&prop->vProp) = VT_UI4;
294 V_UI4(&prop->vProp) = data;
296 list_add_tail(&node->properties, &prop->entry);
297 ++node->nProperties;
299 return S_OK;
302 static inline HRESULT add_i4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, LONG data)
304 IDxDiagContainerImpl_Property *prop;
306 prop = allocate_property_information(propName);
307 if (!prop)
308 return E_OUTOFMEMORY;
310 V_VT(&prop->vProp) = VT_I4;
311 V_I4(&prop->vProp) = data;
313 list_add_tail(&node->properties, &prop->entry);
314 ++node->nProperties;
316 return S_OK;
319 static inline HRESULT add_bool_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, BOOL data)
321 IDxDiagContainerImpl_Property *prop;
323 prop = allocate_property_information(propName);
324 if (!prop)
325 return E_OUTOFMEMORY;
327 V_VT(&prop->vProp) = VT_BOOL;
328 V_BOOL(&prop->vProp) = data ? VARIANT_TRUE : VARIANT_FALSE;
330 list_add_tail(&node->properties, &prop->entry);
331 ++node->nProperties;
333 return S_OK;
336 static inline HRESULT add_ull_as_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, ULONGLONG data )
338 IDxDiagContainerImpl_Property *prop;
339 HRESULT hr;
341 prop = allocate_property_information(propName);
342 if (!prop)
343 return E_OUTOFMEMORY;
345 V_VT(&prop->vProp) = VT_UI8;
346 V_UI8(&prop->vProp) = data;
348 hr = VariantChangeType(&prop->vProp, &prop->vProp, 0, VT_BSTR);
349 if (FAILED(hr))
351 free_property_information(prop);
352 return hr;
355 list_add_tail(&node->properties, &prop->entry);
356 ++node->nProperties;
358 return S_OK;
361 /* Copied from programs/taskkill/taskkill.c. */
362 static DWORD *enumerate_processes(DWORD *list_count)
364 DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes;
366 pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes);
367 if (!pid_list)
368 return NULL;
370 for (;;)
372 DWORD *realloc_list;
374 if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes))
376 HeapFree(GetProcessHeap(), 0, pid_list);
377 return NULL;
380 /* EnumProcesses can't signal an insufficient buffer condition, so the
381 * only way to possibly determine whether a larger buffer is required
382 * is to see whether the written number of bytes is the same as the
383 * buffer size. If so, the buffer will be reallocated to twice the
384 * size. */
385 if (alloc_bytes != needed_bytes)
386 break;
388 alloc_bytes *= 2;
389 realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes);
390 if (!realloc_list)
392 HeapFree(GetProcessHeap(), 0, pid_list);
393 return NULL;
395 pid_list = realloc_list;
398 *list_count = needed_bytes / sizeof(*pid_list);
399 return pid_list;
402 /* Copied from programs/taskkill/taskkill.c. */
403 static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars)
405 HANDLE process;
406 HMODULE module;
407 DWORD required_size;
409 process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
410 if (!process)
411 return FALSE;
413 if (!EnumProcessModules(process, &module, sizeof(module), &required_size))
415 CloseHandle(process);
416 return FALSE;
419 if (!GetModuleBaseNameW(process, module, buf, chars))
421 CloseHandle(process);
422 return FALSE;
425 CloseHandle(process);
426 return TRUE;
429 /* dxdiagn's detection scheme is simply to look for a process called conf.exe. */
430 static BOOL is_netmeeting_running(void)
432 DWORD list_count;
433 DWORD *pid_list = enumerate_processes(&list_count);
435 if (pid_list)
437 DWORD i;
438 WCHAR process_name[MAX_PATH];
440 for (i = 0; i < list_count; i++)
442 if (get_process_name_from_pid(pid_list[i], process_name, ARRAY_SIZE(process_name)) &&
443 !lstrcmpW(L"conf.exe", process_name))
445 HeapFree(GetProcessHeap(), 0, pid_list);
446 return TRUE;
449 HeapFree(GetProcessHeap(), 0, pid_list);
452 return FALSE;
455 static HRESULT fill_language_information(IDxDiagContainerImpl_Container *node)
457 WCHAR system_lang[80], regional_setting[100], user_lang[80], language_str[300];
458 HRESULT hr;
460 /* szLanguagesLocalized */
461 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SNATIVELANGNAME, system_lang, ARRAY_SIZE(system_lang));
462 LoadStringW(dxdiagn_instance, IDS_REGIONAL_SETTING, regional_setting, ARRAY_SIZE(regional_setting));
463 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, user_lang, ARRAY_SIZE(user_lang));
465 swprintf(language_str, ARRAY_SIZE(language_str), L"%s (%s: %s)", system_lang, regional_setting,
466 user_lang);
468 hr = add_bstr_property(node, L"szLanguagesLocalized", language_str);
469 if (FAILED(hr))
470 return hr;
472 /* szLanguagesEnglish */
473 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, system_lang, ARRAY_SIZE(system_lang));
474 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, user_lang, ARRAY_SIZE(user_lang));
476 swprintf(language_str, ARRAY_SIZE(language_str), L"%s (%s: %s)", system_lang,
477 L"Regional Setting", user_lang);
479 hr = add_bstr_property(node, L"szLanguagesEnglish", language_str);
480 if (FAILED(hr))
481 return hr;
483 return S_OK;
486 static HRESULT fill_datetime_information(IDxDiagContainerImpl_Container *node)
488 SYSTEMTIME curtime;
489 WCHAR date_str[80], time_str[80], datetime_str[200];
490 HRESULT hr;
492 GetLocalTime(&curtime);
494 GetTimeFormatW(LOCALE_NEUTRAL, 0, &curtime, L"HH':'mm':'ss", time_str, ARRAY_SIZE(time_str));
496 /* szTimeLocalized */
497 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &curtime, NULL, date_str, ARRAY_SIZE(date_str));
499 swprintf(datetime_str, ARRAY_SIZE(datetime_str), L"%s, %s", date_str, time_str);
501 hr = add_bstr_property(node, L"szTimeLocalized", datetime_str);
502 if (FAILED(hr))
503 return hr;
505 /* szTimeEnglish */
506 GetDateFormatW(LOCALE_NEUTRAL, 0, &curtime, L"M'/'d'/'yyyy", date_str, ARRAY_SIZE(date_str));
508 swprintf(datetime_str, ARRAY_SIZE(datetime_str), L"%s, %s", date_str, time_str);
510 hr = add_bstr_property(node, L"szTimeEnglish", datetime_str);
511 if (FAILED(hr))
512 return hr;
514 return S_OK;
517 static HRESULT fill_os_string_information(IDxDiagContainerImpl_Container *node, OSVERSIONINFOW *info)
519 static const WCHAR *prop_list[] =
521 L"szOSLocalized", L"szOSExLocalized", L"szOSExLongLocalized",
522 L"szOSEnglish", L"szOSExEnglish", L"szOSExLongEnglish"
524 size_t i;
525 HRESULT hr;
527 /* FIXME: OS detection should be performed, and localized OS strings
528 * should contain translated versions of the "build" phrase. */
529 for (i = 0; i < ARRAY_SIZE(prop_list); i++)
531 hr = add_bstr_property(node, prop_list[i], L"Windows XP Professional");
532 if (FAILED(hr))
533 return hr;
536 return S_OK;
539 static HRESULT fill_processor_information(IDxDiagContainerImpl_Container *node)
541 IWbemLocator *wbem_locator;
542 IWbemServices *wbem_service;
543 IWbemClassObject *wbem_class;
544 IEnumWbemClassObject *wbem_enum;
545 VARIANT cpu_name, cpu_no, clock_speed;
546 WCHAR print_buf[200];
547 BSTR bstr;
548 ULONG no;
549 HRESULT hr;
551 hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (void**)&wbem_locator);
552 if(FAILED(hr))
553 return hr;
555 bstr = SysAllocString(L"\\\\.\\root\\cimv2");
556 if(!bstr) {
557 IWbemLocator_Release(wbem_locator);
558 return E_OUTOFMEMORY;
560 hr = IWbemLocator_ConnectServer(wbem_locator, bstr, NULL, NULL, NULL, 0, NULL, NULL, &wbem_service);
561 IWbemLocator_Release(wbem_locator);
562 SysFreeString(bstr);
563 if(FAILED(hr))
564 return hr;
566 bstr = SysAllocString(L"Win32_Processor");
567 if(!bstr) {
568 IWbemServices_Release(wbem_service);
569 return E_OUTOFMEMORY;
571 hr = IWbemServices_CreateInstanceEnum(wbem_service, bstr, WBEM_FLAG_SYSTEM_ONLY, NULL, &wbem_enum);
572 IWbemServices_Release(wbem_service);
573 SysFreeString(bstr);
574 if(FAILED(hr))
575 return hr;
577 hr = IEnumWbemClassObject_Next(wbem_enum, 1000, 1, &wbem_class, &no);
578 IEnumWbemClassObject_Release(wbem_enum);
579 if(FAILED(hr))
580 return hr;
582 hr = IWbemClassObject_Get(wbem_class, L"NumberOfLogicalProcessors", 0, &cpu_no, NULL, NULL);
583 if(FAILED(hr)) {
584 IWbemClassObject_Release(wbem_class);
585 return hr;
587 hr = IWbemClassObject_Get(wbem_class, L"MaxClockSpeed", 0, &clock_speed, NULL, NULL);
588 if(FAILED(hr)) {
589 IWbemClassObject_Release(wbem_class);
590 return hr;
592 hr = IWbemClassObject_Get(wbem_class, L"Name", 0, &cpu_name, NULL, NULL);
593 IWbemClassObject_Release(wbem_class);
594 if(FAILED(hr))
595 return hr;
597 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%s(%d CPUs), ~%dMHz",
598 V_BSTR(&cpu_name), V_I4(&cpu_no), V_I4(&clock_speed));
599 VariantClear(&cpu_name);
600 VariantClear(&cpu_no);
601 VariantClear(&clock_speed);
603 return add_bstr_property(node, L"szProcessorEnglish", print_buf);
606 static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node)
608 HRESULT hr;
609 MEMORYSTATUSEX msex;
610 OSVERSIONINFOW info;
611 DWORD count, usedpage_mb, availpage_mb;
612 WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200];
613 DWORD_PTR args[2];
615 hr = add_ui4_property(node, L"dwDirectXVersionMajor", 9);
616 if (FAILED(hr))
617 return hr;
619 hr = add_ui4_property(node, L"dwDirectXVersionMinor", 0);
620 if (FAILED(hr))
621 return hr;
623 hr = add_bstr_property(node, L"szDirectXVersionLetter", L"c");
624 if (FAILED(hr))
625 return hr;
627 hr = add_bstr_property(node, L"szDirectXVersionEnglish", L"4.09.0000.0904");
628 if (FAILED(hr))
629 return hr;
631 hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"= \"DirectX 9.0c (4.09.0000.0904)");
632 if (FAILED(hr))
633 return hr;
635 hr = add_bool_property(node, L"bDebug", FALSE);
636 if (FAILED(hr))
637 return hr;
639 hr = add_bool_property(node, L"bNECPC98", FALSE);
640 if (FAILED(hr))
641 return hr;
643 msex.dwLength = sizeof(msex);
644 GlobalMemoryStatusEx(&msex);
646 hr = add_ull_as_bstr_property(node, L"ullPhysicalMemory", msex.ullTotalPhys);
647 if (FAILED(hr))
648 return hr;
650 hr = add_ull_as_bstr_property(node, L"ullUsedPageFile", msex.ullTotalPageFile - msex.ullAvailPageFile);
651 if (FAILED(hr))
652 return hr;
654 hr = add_ull_as_bstr_property(node, L"ullAvailPageFile", msex.ullAvailPageFile);
655 if (FAILED(hr))
656 return hr;
658 hr = add_bool_property(node, L"bNetMeetingRunning", is_netmeeting_running());
659 if (FAILED(hr))
660 return hr;
662 info.dwOSVersionInfoSize = sizeof(info);
663 GetVersionExW(&info);
665 hr = add_ui4_property(node, L"dwOSMajorVersion", info.dwMajorVersion);
666 if (FAILED(hr))
667 return hr;
669 hr = add_ui4_property(node, L"dwOSMinorVersion", info.dwMinorVersion);
670 if (FAILED(hr))
671 return hr;
673 hr = add_ui4_property(node, L"dwOSBuildNumber", info.dwBuildNumber);
674 if (FAILED(hr))
675 return hr;
677 hr = add_ui4_property(node, L"dwOSPlatformID", info.dwPlatformId);
678 if (FAILED(hr))
679 return hr;
681 hr = add_bstr_property(node, L"szCSDVersion", info.szCSDVersion);
682 if (FAILED(hr))
683 return hr;
685 /* FIXME: Roundoff should not be done with truncated division. */
686 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%I64uMB RAM", msex.ullTotalPhys / (1024 * 1024));
687 hr = add_bstr_property(node, L"szPhysicalMemoryEnglish", print_buf);
688 if (FAILED(hr))
689 return hr;
691 usedpage_mb = (DWORD)((msex.ullTotalPageFile - msex.ullAvailPageFile) / (1024 * 1024));
692 availpage_mb = (DWORD)(msex.ullAvailPageFile / (1024 * 1024));
693 LoadStringW(dxdiagn_instance, IDS_PAGE_FILE_FORMAT, localized_pagefile_fmt,
694 ARRAY_SIZE(localized_pagefile_fmt));
695 args[0] = usedpage_mb;
696 args[1] = availpage_mb;
697 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, localized_pagefile_fmt,
698 0, 0, print_buf, ARRAY_SIZE(print_buf), (va_list *)args);
700 hr = add_bstr_property(node, L"szPageFileLocalized", print_buf);
701 if (FAILED(hr))
702 return hr;
704 swprintf(print_buf, ARRAY_SIZE(print_buf), L"%uMB used, %uMB available", usedpage_mb, availpage_mb);
706 hr = add_bstr_property(node, L"szPageFileEnglish", print_buf);
707 if (FAILED(hr))
708 return hr;
710 GetWindowsDirectoryW(buffer, MAX_PATH);
712 hr = add_bstr_property(node, L"szWindowsDir", buffer);
713 if (FAILED(hr))
714 return hr;
716 count = ARRAY_SIZE(computer_name);
717 if (!GetComputerNameW(computer_name, &count))
718 return E_FAIL;
720 hr = add_bstr_property(node, L"szMachineNameLocalized", computer_name);
721 if (FAILED(hr))
722 return hr;
724 hr = add_bstr_property(node, L"szMachineNameEnglish", computer_name);
725 if (FAILED(hr))
726 return hr;
728 hr = add_bstr_property(node, L"szSystemManufacturerEnglish", L"");
729 if (FAILED(hr))
730 return hr;
732 hr = add_bstr_property(node, L"szSystemModelEnglish", L"");
733 if (FAILED(hr))
734 return hr;
736 hr = add_bstr_property(node, L"szBIOSEnglish", L"");
737 if (FAILED(hr))
738 return hr;
740 hr = fill_processor_information(node);
741 if (FAILED(hr))
742 return hr;
744 hr = add_bstr_property(node, L"szSetupParamEnglish", L"Not present");
745 if (FAILED(hr))
746 return hr;
748 hr = add_bstr_property(node, L"szDxDiagVersion", L"");
749 if (FAILED(hr))
750 return hr;
752 hr = fill_language_information(node);
753 if (FAILED(hr))
754 return hr;
756 hr = fill_datetime_information(node);
757 if (FAILED(hr))
758 return hr;
760 hr = fill_os_string_information(node, &info);
761 if (FAILED(hr))
762 return hr;
764 return S_OK;
767 /* The logic from pixelformat_for_depth() in dlls/wined3d/utils.c is reversed. */
768 static DWORD depth_for_pixelformat(D3DFORMAT format)
770 switch (format)
772 case D3DFMT_P8: return 8;
773 case D3DFMT_X1R5G5B5: return 15;
774 case D3DFMT_R5G6B5: return 16;
775 /* This case will fail to distinguish an original bpp of 24. */
776 case D3DFMT_X8R8G8B8: return 32;
777 default:
778 FIXME("Unknown D3DFORMAT %d, returning 32 bpp\n", format);
779 return 32;
783 static BOOL get_texture_memory(GUID *adapter, DWORD *available_mem)
785 IDirectDraw7 *pDirectDraw;
786 HRESULT hr;
787 DDSCAPS2 dd_caps;
789 hr = DirectDrawCreateEx(adapter, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
790 if (SUCCEEDED(hr))
792 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
793 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.dwCaps4 = 0;
794 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, available_mem, NULL);
795 IDirectDraw7_Release(pDirectDraw);
796 if (SUCCEEDED(hr))
797 return TRUE;
800 return FALSE;
803 static const WCHAR *vendor_id_to_manufacturer_string(DWORD vendor_id)
805 unsigned int i;
806 static const struct
808 DWORD id;
809 const WCHAR *name;
811 vendors[] =
813 {0x1002, L"ATI Technologies Inc."},
814 {0x10de, L"NVIDIA"},
815 {0x15ad, L"VMware"},
816 {0x1af4, L"Red Hat"},
817 {0x8086, L"Intel Corporation"},
820 for (i = 0; i < ARRAY_SIZE(vendors); ++i)
822 if (vendors[i].id == vendor_id)
823 return vendors[i].name;
826 FIXME("Unknown PCI vendor ID 0x%04lx.\n", vendor_id);
828 return L"Unknown";
831 static HRESULT fill_display_information_d3d(IDxDiagContainerImpl_Container *node)
833 IDxDiagContainerImpl_Container *display_adapter;
834 HRESULT hr;
835 IDirect3D9 *pDirect3D9;
836 WCHAR buffer[256];
837 UINT index, count;
839 pDirect3D9 = Direct3DCreate9(D3D_SDK_VERSION);
840 if (!pDirect3D9)
841 return E_FAIL;
843 count = IDirect3D9_GetAdapterCount(pDirect3D9);
844 for (index = 0; index < count; index++)
846 D3DADAPTER_IDENTIFIER9 adapter_info;
847 D3DDISPLAYMODE adapter_mode;
848 D3DCAPS9 device_caps;
849 DWORD available_mem = 0;
850 BOOL hardware_accel;
852 swprintf(buffer, ARRAY_SIZE(buffer), L"%u", index);
853 display_adapter = allocate_information_node(buffer);
854 if (!display_adapter)
856 hr = E_OUTOFMEMORY;
857 goto cleanup;
860 add_subcontainer(node, display_adapter);
862 hr = IDirect3D9_GetAdapterIdentifier(pDirect3D9, index, 0, &adapter_info);
863 if (SUCCEEDED(hr))
865 WCHAR driverW[sizeof(adapter_info.Driver)];
866 WCHAR descriptionW[sizeof(adapter_info.Description)];
867 WCHAR devicenameW[sizeof(adapter_info.DeviceName)];
869 MultiByteToWideChar(CP_ACP, 0, adapter_info.Driver, -1, driverW, ARRAY_SIZE(driverW));
870 MultiByteToWideChar(CP_ACP, 0, adapter_info.Description, -1, descriptionW,
871 ARRAY_SIZE(descriptionW));
872 MultiByteToWideChar(CP_ACP, 0, adapter_info.DeviceName, -1, devicenameW,
873 ARRAY_SIZE(devicenameW));
875 hr = add_bstr_property(display_adapter, L"szDriverName", driverW);
876 if (FAILED(hr))
877 goto cleanup;
879 hr = add_bstr_property(display_adapter, L"szDescription", descriptionW);
880 if (FAILED(hr))
881 goto cleanup;
883 hr = add_bstr_property(display_adapter, L"szDeviceName", devicenameW);
884 if (FAILED(hr))
885 goto cleanup;
887 swprintf(buffer, ARRAY_SIZE(buffer), L"%u.%u.%04u.%04u",
888 HIWORD(adapter_info.DriverVersion.HighPart), LOWORD(adapter_info.DriverVersion.HighPart),
889 HIWORD(adapter_info.DriverVersion.LowPart), LOWORD(adapter_info.DriverVersion.LowPart));
891 hr = add_bstr_property(display_adapter, L"szDriverVersion", buffer);
892 if (FAILED(hr))
893 goto cleanup;
895 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.VendorId);
896 hr = add_bstr_property(display_adapter, L"szVendorId", buffer);
897 if (FAILED(hr))
898 goto cleanup;
900 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.DeviceId);
901 hr = add_bstr_property(display_adapter, L"szDeviceId", buffer);
902 if (FAILED(hr))
903 goto cleanup;
905 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%08x", adapter_info.SubSysId);
906 hr = add_bstr_property(display_adapter, L"szSubSysId", buffer);
907 if (FAILED(hr))
908 goto cleanup;
910 swprintf(buffer, ARRAY_SIZE(buffer), L"0x%04x", adapter_info.Revision);
911 hr = add_bstr_property(display_adapter, L"szRevisionId", buffer);
912 if (FAILED(hr))
913 goto cleanup;
915 StringFromGUID2(&adapter_info.DeviceIdentifier, buffer, 39);
916 hr = add_bstr_property(display_adapter, L"szDeviceIdentifier", buffer);
917 if (FAILED(hr))
918 goto cleanup;
920 hr = add_bstr_property(display_adapter, L"szManufacturer",
921 vendor_id_to_manufacturer_string(adapter_info.VendorId));
922 if (FAILED(hr))
923 goto cleanup;
926 hr = IDirect3D9_GetAdapterDisplayMode(pDirect3D9, index, &adapter_mode);
927 if (SUCCEEDED(hr))
929 hr = add_ui4_property(display_adapter, L"dwWidth", adapter_mode.Width);
930 if (FAILED(hr))
931 goto cleanup;
933 hr = add_ui4_property(display_adapter, L"dwHeight", adapter_mode.Height);
934 if (FAILED(hr))
935 goto cleanup;
937 hr = add_ui4_property(display_adapter, L"dwRefreshRate", adapter_mode.RefreshRate);
938 if (FAILED(hr))
939 goto cleanup;
941 hr = add_ui4_property(display_adapter, L"dwBpp", depth_for_pixelformat(adapter_mode.Format));
942 if (FAILED(hr))
943 goto cleanup;
945 swprintf(buffer, ARRAY_SIZE(buffer), L"%d x %d (%d bit) (%dHz)", adapter_mode.Width,
946 adapter_mode.Height, depth_for_pixelformat(adapter_mode.Format),
947 adapter_mode.RefreshRate);
949 hr = add_bstr_property(display_adapter, L"szDisplayModeLocalized", buffer);
950 if (FAILED(hr))
951 goto cleanup;
953 hr = add_bstr_property(display_adapter, L"szDisplayModeEnglish", buffer);
954 if (FAILED(hr))
955 goto cleanup;
958 hr = add_bstr_property(display_adapter, L"szKeyDeviceKey", L"");
959 if (FAILED(hr))
960 goto cleanup;
962 hr = add_bstr_property(display_adapter, L"szKeyDeviceID", L"");
963 if (FAILED(hr))
964 goto cleanup;
966 hr = add_bstr_property(display_adapter, L"szChipType", L"");
967 if (FAILED(hr))
968 goto cleanup;
970 hr = add_bstr_property(display_adapter, L"szDACType", L"");
971 if (FAILED(hr))
972 goto cleanup;
974 hr = add_bstr_property(display_adapter, L"szRevision", L"");
975 if (FAILED(hr))
976 goto cleanup;
978 if (!get_texture_memory(&adapter_info.DeviceIdentifier, &available_mem))
979 WARN("get_texture_memory helper failed\n");
981 swprintf(buffer, ARRAY_SIZE(buffer), L"%.1f MB", available_mem / 1000000.0f);
983 hr = add_bstr_property(display_adapter, L"szDisplayMemoryLocalized", buffer);
984 if (FAILED(hr))
985 goto cleanup;
987 hr = add_bstr_property(display_adapter, L"szDisplayMemoryEnglish", buffer);
988 if (FAILED(hr))
989 goto cleanup;
991 hr = IDirect3D9_GetDeviceCaps(pDirect3D9, index, D3DDEVTYPE_HAL, &device_caps);
992 hardware_accel = SUCCEEDED(hr);
994 hr = add_bool_property(display_adapter, L"b3DAccelerationEnabled", hardware_accel);
995 if (FAILED(hr))
996 goto cleanup;
998 hr = add_bool_property(display_adapter, L"b3DAccelerationExists", hardware_accel);
999 if (FAILED(hr))
1000 goto cleanup;
1002 hr = add_bool_property(display_adapter, L"bDDAccelerationEnabled", hardware_accel);
1003 if (FAILED(hr))
1004 goto cleanup;
1006 hr = add_bool_property(display_adapter, L"bNoHardware", FALSE);
1007 if (FAILED(hr))
1008 goto cleanup;
1010 hr = add_bool_property(display_adapter, L"bCanRenderWindow", TRUE);
1011 if (FAILED(hr))
1012 goto cleanup;
1014 hr = add_bstr_property(display_adapter, L"szMonitorName", L"Generic PnP Monitor");
1015 if (FAILED(hr))
1016 goto cleanup;
1018 hr = add_bstr_property(display_adapter, L"szMonitorMaxRes", L"Failed to get parameter");
1019 if (FAILED(hr))
1020 goto cleanup;
1022 hr = add_bstr_property(display_adapter, L"szDriverAttributes", L"Final Retail");
1023 if (FAILED(hr))
1024 goto cleanup;
1026 hr = add_bstr_property(display_adapter, L"szDriverLanguageEnglish", L"English");
1027 if (FAILED(hr))
1028 goto cleanup;
1030 hr = add_bstr_property(display_adapter, L"szDriverLanguageLocalized", L"English");
1031 if (FAILED(hr))
1032 goto cleanup;
1034 hr = add_bstr_property(display_adapter, L"szDriverDateEnglish", L"1/1/2016 10:00:00");
1035 if (FAILED(hr))
1036 goto cleanup;
1038 hr = add_bstr_property(display_adapter, L"szDriverDateLocalized", L"1/1/2016 10:00:00 AM");
1039 if (FAILED(hr))
1040 goto cleanup;
1042 hr = add_i4_property(display_adapter, L"lDriverSize", 10 * 1024 * 1024);
1043 if (FAILED(hr))
1044 goto cleanup;
1046 hr = add_bstr_property(display_adapter, L"szMiniVdd", L"n/a");
1047 if (FAILED(hr))
1048 goto cleanup;
1050 hr = add_bstr_property(display_adapter, L"szMiniVddDateLocalized", L"n/a");
1051 if (FAILED(hr))
1052 goto cleanup;
1054 hr = add_bstr_property(display_adapter, L"szMiniVddDateEnglish", L"n/a");
1055 if (FAILED(hr))
1056 goto cleanup;
1058 hr = add_i4_property(display_adapter, L"lMiniVddSize", 0);
1059 if (FAILED(hr))
1060 goto cleanup;
1062 hr = add_bstr_property(display_adapter, L"szVdd", L"n/a");
1063 if (FAILED(hr))
1064 goto cleanup;
1066 hr = add_bool_property(display_adapter, L"bDriverBeta", FALSE);
1067 if (FAILED(hr))
1068 goto cleanup;
1070 hr = add_bool_property(display_adapter, L"bDriverDebug", FALSE);
1071 if (FAILED(hr))
1072 goto cleanup;
1074 hr = add_bool_property(display_adapter, L"bDriverSigned", TRUE);
1075 if (FAILED(hr))
1076 goto cleanup;
1078 hr = add_bool_property(display_adapter, L"bDriverSignedValid", TRUE);
1079 if (FAILED(hr))
1080 goto cleanup;
1082 hr = add_bstr_property(display_adapter, L"szDriverSignDate", L"n/a");
1083 if (FAILED(hr))
1084 goto cleanup;
1086 hr = add_ui4_property(display_adapter, L"dwDDIVersion", 11);
1087 if (FAILED(hr))
1088 goto cleanup;
1090 hr = add_bstr_property(display_adapter, L"szDDIVersionEnglish", L"11");
1091 if (FAILED(hr))
1092 goto cleanup;
1094 hr = add_bstr_property(display_adapter, L"szDDIVersionLocalized", L"11");
1095 if (FAILED(hr))
1096 goto cleanup;
1098 hr = add_ui4_property(display_adapter, L"iAdapter", index);
1099 if (FAILED(hr))
1100 goto cleanup;
1102 hr = add_ui4_property(display_adapter, L"dwWHQLLevel", 0);
1103 if (FAILED(hr))
1104 goto cleanup;
1107 hr = S_OK;
1108 cleanup:
1109 IDirect3D9_Release(pDirect3D9);
1110 return hr;
1113 static HRESULT fill_display_information_fallback(IDxDiagContainerImpl_Container *node)
1115 static const WCHAR *empty_properties[] =
1117 L"szDeviceIdentifier", L"szVendorId", L"szDeviceId", L"szKeyDeviceKey",
1118 L"szKeyDeviceID", L"szDriverName", L"szDriverVersion", L"szSubSysId",
1119 L"szRevisionId", L"szManufacturer", L"szChipType", L"szDACType", L"szRevision"
1122 IDxDiagContainerImpl_Container *display_adapter;
1123 HRESULT hr;
1124 IDirectDraw7 *pDirectDraw;
1125 DDSCAPS2 dd_caps;
1126 DISPLAY_DEVICEW disp_dev;
1127 DDSURFACEDESC2 surface_descr;
1128 DWORD tmp;
1129 WCHAR buffer[256];
1131 display_adapter = allocate_information_node(L"0");
1132 if (!display_adapter)
1133 return E_OUTOFMEMORY;
1135 add_subcontainer(node, display_adapter);
1137 disp_dev.cb = sizeof(disp_dev);
1138 if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
1140 hr = add_bstr_property(display_adapter, L"szDeviceName", disp_dev.DeviceName);
1141 if (FAILED(hr))
1142 return hr;
1144 hr = add_bstr_property(display_adapter, L"szDescription", disp_dev.DeviceString);
1145 if (FAILED(hr))
1146 return hr;
1149 /* Silently ignore a failure from DirectDrawCreateEx. */
1150 hr = DirectDrawCreateEx(NULL, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
1151 if (FAILED(hr))
1152 return S_OK;
1154 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
1155 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.dwCaps4 = 0;
1156 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, &tmp, NULL);
1157 if (SUCCEEDED(hr))
1159 swprintf(buffer, ARRAY_SIZE(buffer), L"%.1f MB", tmp / 1000000.0f);
1161 hr = add_bstr_property(display_adapter, L"szDisplayMemoryLocalized", buffer);
1162 if (FAILED(hr))
1163 goto cleanup;
1165 hr = add_bstr_property(display_adapter, L"szDisplayMemoryEnglish", buffer);
1166 if (FAILED(hr))
1167 goto cleanup;
1170 surface_descr.dwSize = sizeof(surface_descr);
1171 hr = IDirectDraw7_GetDisplayMode(pDirectDraw, &surface_descr);
1172 if (SUCCEEDED(hr))
1174 if (surface_descr.dwFlags & DDSD_WIDTH)
1176 hr = add_ui4_property(display_adapter, L"dwWidth", surface_descr.dwWidth);
1177 if (FAILED(hr))
1178 goto cleanup;
1181 if (surface_descr.dwFlags & DDSD_HEIGHT)
1183 hr = add_ui4_property(display_adapter, L"dwHeight", surface_descr.dwHeight);
1184 if (FAILED(hr))
1185 goto cleanup;
1188 if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
1190 hr = add_ui4_property(display_adapter, L"dwBpp",
1191 surface_descr.ddpfPixelFormat.dwRGBBitCount);
1192 if (FAILED(hr))
1193 goto cleanup;
1197 hr = add_ui4_property(display_adapter, L"dwRefreshRate", 60);
1198 if (FAILED(hr))
1199 goto cleanup;
1201 for (tmp = 0; tmp < ARRAY_SIZE(empty_properties); tmp++)
1203 hr = add_bstr_property(display_adapter, empty_properties[tmp], L"");
1204 if (FAILED(hr))
1205 goto cleanup;
1208 hr = S_OK;
1209 cleanup:
1210 IDirectDraw7_Release(pDirectDraw);
1211 return hr;
1214 static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
1216 HRESULT hr;
1218 /* Try to use Direct3D to obtain the required information first. */
1219 hr = fill_display_information_d3d(node);
1220 if (hr != E_FAIL)
1221 return hr;
1223 return fill_display_information_fallback(node);
1226 struct enum_context
1228 IDxDiagContainerImpl_Container *cont;
1229 HRESULT hr;
1230 int index;
1233 static LPWSTR guid_to_string(LPWSTR lpwstr, REFGUID lpcguid)
1235 wsprintfW(lpwstr, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", lpcguid->Data1, lpcguid->Data2,
1236 lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1], lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
1237 lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
1239 return lpwstr;
1242 BOOL CALLBACK dsound_enum(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID context)
1244 struct enum_context *enum_ctx = context;
1245 IDxDiagContainerImpl_Container *device;
1246 WCHAR buffer[256];
1247 const WCHAR *p, *name;
1249 /* the default device is enumerated twice, one time without GUID */
1250 if (!guid) return TRUE;
1252 swprintf(buffer, ARRAY_SIZE(buffer), L"%u", enum_ctx->index);
1253 device = allocate_information_node(buffer);
1254 if (!device)
1256 enum_ctx->hr = E_OUTOFMEMORY;
1257 return FALSE;
1260 add_subcontainer(enum_ctx->cont, device);
1262 guid_to_string(buffer, guid);
1263 enum_ctx->hr = add_bstr_property(device, L"szGuidDeviceID", buffer);
1264 if (FAILED(enum_ctx->hr))
1265 return FALSE;
1267 enum_ctx->hr = add_bstr_property(device, L"szDescription", desc);
1268 if (FAILED(enum_ctx->hr))
1269 return FALSE;
1271 enum_ctx->hr = add_bstr_property(device, L"szDriverPath", module);
1272 if (FAILED(enum_ctx->hr))
1273 return FALSE;
1275 name = module;
1276 if ((p = wcsrchr(name, '\\'))) name = p + 1;
1277 if ((p = wcsrchr(name, '/'))) name = p + 1;
1279 enum_ctx->hr = add_bstr_property(device, L"szDriverName", name);
1280 if (FAILED(enum_ctx->hr))
1281 return FALSE;
1283 enum_ctx->index++;
1284 return TRUE;
1287 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
1289 struct enum_context enum_ctx;
1290 IDxDiagContainerImpl_Container *cont;
1292 cont = allocate_information_node(L"DxDiag_SoundDevices");
1293 if (!cont)
1294 return E_OUTOFMEMORY;
1296 add_subcontainer(node, cont);
1298 enum_ctx.cont = cont;
1299 enum_ctx.hr = S_OK;
1300 enum_ctx.index = 0;
1302 DirectSoundEnumerateW(dsound_enum, &enum_ctx);
1303 if (FAILED(enum_ctx.hr))
1304 return enum_ctx.hr;
1306 cont = allocate_information_node(L"DxDiag_SoundCaptureDevices");
1307 if (!cont)
1308 return E_OUTOFMEMORY;
1310 add_subcontainer(node, cont);
1312 enum_ctx.cont = cont;
1313 enum_ctx.hr = S_OK;
1314 enum_ctx.index = 0;
1316 DirectSoundCaptureEnumerateW(dsound_enum, &enum_ctx);
1317 if (FAILED(enum_ctx.hr))
1318 return enum_ctx.hr;
1320 return S_OK;
1323 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
1325 return S_OK;
1328 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
1330 return S_OK;
1333 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
1335 return S_OK;
1338 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
1340 return S_OK;
1343 static HRESULT fill_file_description(IDxDiagContainerImpl_Container *node, const WCHAR *szFilePath, const WCHAR *szFileName)
1345 HRESULT hr;
1346 WCHAR *szFile;
1347 WCHAR szVersion_v[1024];
1348 DWORD retval, hdl;
1349 void *pVersionInfo = NULL;
1350 BOOL boolret = FALSE;
1351 UINT uiLength;
1352 VS_FIXEDFILEINFO *pFileInfo;
1354 TRACE("Filling container %p for %s in %s\n", node,
1355 debugstr_w(szFileName), debugstr_w(szFilePath));
1357 szFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(szFilePath) +
1358 lstrlenW(szFileName) + 2 /* slash + terminator */));
1359 if (!szFile)
1360 return E_OUTOFMEMORY;
1362 lstrcpyW(szFile, szFilePath);
1363 lstrcatW(szFile, L"\\");
1364 lstrcatW(szFile, szFileName);
1366 retval = GetFileVersionInfoSizeW(szFile, &hdl);
1367 if (retval)
1369 pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
1370 if (!pVersionInfo)
1372 hr = E_OUTOFMEMORY;
1373 goto cleanup;
1376 if (GetFileVersionInfoW(szFile, 0, retval, pVersionInfo) &&
1377 VerQueryValueW(pVersionInfo, L"\\", (void **)&pFileInfo, &uiLength))
1378 boolret = TRUE;
1381 hr = add_bstr_property(node, L"szPath", szFile);
1382 if (FAILED(hr))
1383 goto cleanup;
1385 hr = add_bstr_property(node, L"szName", szFileName);
1386 if (FAILED(hr))
1387 goto cleanup;
1389 hr = add_bool_property(node, L"bExists", boolret);
1390 if (FAILED(hr))
1391 goto cleanup;
1393 if (boolret)
1395 swprintf(szVersion_v, ARRAY_SIZE(szVersion_v), L"%u.%02u.%04u.%04u",
1396 HIWORD(pFileInfo->dwFileVersionMS), LOWORD(pFileInfo->dwFileVersionMS),
1397 HIWORD(pFileInfo->dwFileVersionLS), LOWORD(pFileInfo->dwFileVersionLS));
1399 TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));
1401 hr = add_bstr_property(node, L"szVersion", szVersion_v);
1402 if (FAILED(hr))
1403 goto cleanup;
1405 hr = add_bstr_property(node, L"szAttributes", L"Final Retail");
1406 if (FAILED(hr))
1407 goto cleanup;
1409 hr = add_bstr_property(node, L"szLanguageEnglish", L"English");
1410 if (FAILED(hr))
1411 goto cleanup;
1413 hr = add_ui4_property(node, L"dwFileTimeHigh", pFileInfo->dwFileDateMS);
1414 if (FAILED(hr))
1415 goto cleanup;
1417 hr = add_ui4_property(node, L"dwFileTimeLow", pFileInfo->dwFileDateLS);
1418 if (FAILED(hr))
1419 goto cleanup;
1421 hr = add_bool_property(node, L"bBeta",
1422 ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
1423 if (FAILED(hr))
1424 goto cleanup;
1426 hr = add_bool_property(node, L"bDebug",
1427 ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
1428 if (FAILED(hr))
1429 goto cleanup;
1432 hr = S_OK;
1433 cleanup:
1434 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1435 HeapFree(GetProcessHeap(), 0, szFile);
1437 return hr;
1439 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1441 static const WCHAR dlls[][15] =
1443 L"d3d8.dll",
1444 L"d3d9.dll",
1445 L"ddraw.dll",
1446 L"devenum.dll",
1447 L"dinput8.dll",
1448 L"dinput.dll",
1449 L"dmband.dll",
1450 L"dmcompos.dll",
1451 L"dmime.dll",
1452 L"dmloader.dll",
1453 L"dmscript.dll",
1454 L"dmstyle.dll",
1455 L"dmsynth.dll",
1456 L"dmusic.dll",
1457 L"dplayx.dll",
1458 L"dpnet.dll",
1459 L"dsound.dll",
1460 L"dswave.dll",
1461 L"dxdiagn.dll",
1462 L"quartz.dll"
1465 HRESULT hr;
1466 WCHAR szFilePath[MAX_PATH];
1467 INT i;
1469 GetSystemDirectoryW(szFilePath, MAX_PATH);
1471 for (i = 0; i < ARRAY_SIZE(dlls); i++)
1473 WCHAR szFileID[5];
1474 IDxDiagContainerImpl_Container *file_container;
1476 swprintf(szFileID, ARRAY_SIZE(szFileID), L"%d", i);
1478 file_container = allocate_information_node(szFileID);
1479 if (!file_container)
1480 return E_OUTOFMEMORY;
1482 hr = fill_file_description(file_container, szFilePath, dlls[i]);
1483 if (FAILED(hr))
1485 free_information_tree(file_container);
1486 continue;
1489 add_subcontainer(node, file_container);
1492 return S_OK;
1495 static HRESULT read_property_names(IPropertyBag *pPropBag, VARIANT *friendly_name, VARIANT *clsid_name)
1497 HRESULT hr;
1499 VariantInit(friendly_name);
1500 VariantInit(clsid_name);
1502 hr = IPropertyBag_Read(pPropBag, L"FriendlyName", friendly_name, 0);
1503 if (FAILED(hr))
1504 return hr;
1506 hr = IPropertyBag_Read(pPropBag, L"CLSID", clsid_name, 0);
1507 if (FAILED(hr))
1509 VariantClear(friendly_name);
1510 return hr;
1513 return S_OK;
1516 static HRESULT fill_filter_data_information(IDxDiagContainerImpl_Container *subcont, BYTE *pData, ULONG cb)
1518 HRESULT hr;
1519 IFilterMapper2 *pFileMapper = NULL;
1520 IAMFilterData *pFilterData = NULL;
1521 BYTE *ppRF = NULL;
1522 REGFILTER2 *pRF = NULL;
1523 WCHAR bufferW[10];
1524 ULONG j;
1525 DWORD dwNOutputs = 0;
1526 DWORD dwNInputs = 0;
1528 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
1529 (void **)&pFileMapper);
1530 if (FAILED(hr))
1531 return hr;
1533 hr = IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData);
1534 if (FAILED(hr))
1535 goto cleanup;
1537 hr = IAMFilterData_ParseFilterData(pFilterData, pData, cb, &ppRF);
1538 if (FAILED(hr))
1539 goto cleanup;
1540 pRF = ((REGFILTER2**)ppRF)[0];
1542 swprintf(bufferW, ARRAY_SIZE(bufferW), L"v%d", pRF->dwVersion);
1543 hr = add_bstr_property(subcont, L"szVersion", bufferW);
1544 if (FAILED(hr))
1545 goto cleanup;
1547 if (pRF->dwVersion == 1)
1549 for (j = 0; j < pRF->cPins; j++)
1550 if (pRF->rgPins[j].bOutput)
1551 dwNOutputs++;
1552 else
1553 dwNInputs++;
1555 else if (pRF->dwVersion == 2)
1557 for (j = 0; j < pRF->cPins2; j++)
1558 if (pRF->rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
1559 dwNOutputs++;
1560 else
1561 dwNInputs++;
1564 hr = add_ui4_property(subcont, L"dwInputs", dwNInputs);
1565 if (FAILED(hr))
1566 goto cleanup;
1568 hr = add_ui4_property(subcont, L"dwOutputs", dwNOutputs);
1569 if (FAILED(hr))
1570 goto cleanup;
1572 hr = add_ui4_property(subcont, L"dwMerit", pRF->dwMerit);
1573 if (FAILED(hr))
1574 goto cleanup;
1576 hr = S_OK;
1577 cleanup:
1578 CoTaskMemFree(pRF);
1579 if (pFilterData) IAMFilterData_Release(pFilterData);
1580 if (pFileMapper) IFilterMapper2_Release(pFileMapper);
1582 return hr;
1585 static HRESULT fill_filter_container(IDxDiagContainerImpl_Container *subcont, IMoniker *pMoniker)
1587 HRESULT hr;
1588 IPropertyBag *pPropFilterBag = NULL;
1589 BYTE *pData;
1590 VARIANT friendly_name;
1591 VARIANT clsid_name;
1592 VARIANT v;
1594 VariantInit(&friendly_name);
1595 VariantInit(&clsid_name);
1596 VariantInit(&v);
1598 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void **)&pPropFilterBag);
1599 if (FAILED(hr))
1600 return hr;
1602 hr = read_property_names(pPropFilterBag, &friendly_name, &clsid_name);
1603 if (FAILED(hr))
1604 goto cleanup;
1606 TRACE("Name = %s\n", debugstr_w(V_BSTR(&friendly_name)));
1607 TRACE("CLSID = %s\n", debugstr_w(V_BSTR(&clsid_name)));
1609 hr = add_bstr_property(subcont, L"szName", V_BSTR(&friendly_name));
1610 if (FAILED(hr))
1611 goto cleanup;
1613 hr = add_bstr_property(subcont, L"ClsidFilter", V_BSTR(&clsid_name));
1614 if (FAILED(hr))
1615 goto cleanup;
1617 hr = IPropertyBag_Read(pPropFilterBag, L"FilterData", &v, NULL);
1618 if (FAILED(hr))
1619 goto cleanup;
1621 hr = SafeArrayAccessData(V_ARRAY(&v), (void **)&pData);
1622 if (FAILED(hr))
1623 goto cleanup;
1625 hr = fill_filter_data_information(subcont, pData, V_ARRAY(&v)->rgsabound->cElements);
1626 SafeArrayUnaccessData(V_ARRAY(&v));
1627 if (FAILED(hr))
1628 goto cleanup;
1630 hr = S_OK;
1631 cleanup:
1632 VariantClear(&v);
1633 VariantClear(&clsid_name);
1634 VariantClear(&friendly_name);
1635 if (pPropFilterBag) IPropertyBag_Release(pPropFilterBag);
1637 return hr;
1640 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1642 HRESULT hr;
1643 int i = 0;
1644 ICreateDevEnum *pCreateDevEnum;
1645 IEnumMoniker *pEmCat = NULL;
1646 IMoniker *pMCat = NULL;
1647 IEnumMoniker *pEnum = NULL;
1649 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1650 &IID_ICreateDevEnum, (void **)&pCreateDevEnum);
1651 if (FAILED(hr))
1652 return hr;
1654 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
1655 if (hr != S_OK)
1656 goto cleanup;
1658 while (IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL) == S_OK)
1660 VARIANT vCatName;
1661 VARIANT vCatClsid;
1662 IPropertyBag *pPropBag;
1663 CLSID clsidCat;
1664 IMoniker *pMoniker = NULL;
1666 hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void **)&pPropBag);
1667 if (FAILED(hr))
1669 IMoniker_Release(pMCat);
1670 break;
1673 hr = read_property_names(pPropBag, &vCatName, &vCatClsid);
1674 IPropertyBag_Release(pPropBag);
1675 if (FAILED(hr))
1677 IMoniker_Release(pMCat);
1678 break;
1681 hr = CLSIDFromString(V_BSTR(&vCatClsid), &clsidCat);
1682 if (FAILED(hr))
1684 IMoniker_Release(pMCat);
1685 VariantClear(&vCatClsid);
1686 VariantClear(&vCatName);
1687 break;
1690 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1691 if (hr != S_OK)
1693 IMoniker_Release(pMCat);
1694 VariantClear(&vCatClsid);
1695 VariantClear(&vCatName);
1696 continue;
1699 TRACE("Enumerating class %s\n", debugstr_guid(&clsidCat));
1701 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1703 WCHAR bufferW[10];
1704 IDxDiagContainerImpl_Container *subcont;
1706 swprintf(bufferW, ARRAY_SIZE(bufferW), L"%d", i);
1707 subcont = allocate_information_node(bufferW);
1708 if (!subcont)
1710 hr = E_OUTOFMEMORY;
1711 IMoniker_Release(pMoniker);
1712 break;
1715 hr = add_bstr_property(subcont, L"szCatName", V_BSTR(&vCatName));
1716 if (FAILED(hr))
1718 free_information_tree(subcont);
1719 IMoniker_Release(pMoniker);
1720 break;
1723 hr = add_bstr_property(subcont, L"ClsidCat", V_BSTR(&vCatClsid));
1724 if (FAILED(hr))
1726 free_information_tree(subcont);
1727 IMoniker_Release(pMoniker);
1728 break;
1731 hr = fill_filter_container(subcont, pMoniker);
1732 IMoniker_Release(pMoniker);
1733 if (FAILED(hr))
1735 WARN("Skipping invalid filter\n");
1736 free_information_tree(subcont);
1737 hr = S_OK;
1738 continue;
1741 add_subcontainer(node, subcont);
1742 i++;
1745 IEnumMoniker_Release(pEnum);
1746 IMoniker_Release(pMCat);
1747 VariantClear(&vCatClsid);
1748 VariantClear(&vCatName);
1750 if (FAILED(hr))
1751 break;
1754 cleanup:
1755 if (pEmCat) IEnumMoniker_Release(pEmCat);
1756 ICreateDevEnum_Release(pCreateDevEnum);
1757 return hr;
1760 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1762 return S_OK;
1765 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1767 static const struct
1769 const WCHAR *name;
1770 HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1771 } root_children[] =
1773 {L"DxDiag_SystemInfo", build_systeminfo_tree},
1774 {L"DxDiag_DisplayDevices", build_displaydevices_tree},
1775 {L"DxDiag_DirectSound", build_directsound_tree},
1776 {L"DxDiag_DirectMusic", build_directmusic_tree},
1777 {L"DxDiag_DirectInput", build_directinput_tree},
1778 {L"DxDiag_DirectPlay", build_directplay_tree},
1779 {L"DxDiag_SystemDevices", build_systemdevices_tree},
1780 {L"DxDiag_DirectXFiles", build_directxfiles_tree},
1781 {L"DxDiag_DirectShowFilters", build_directshowfilters_tree},
1782 {L"DxDiag_LogicalDisks", build_logicaldisks_tree},
1785 IDxDiagContainerImpl_Container *info_root;
1786 size_t index;
1788 info_root = allocate_information_node(NULL);
1789 if (!info_root)
1790 return E_OUTOFMEMORY;
1792 for (index = 0; index < ARRAY_SIZE(root_children); index++)
1794 IDxDiagContainerImpl_Container *node;
1795 HRESULT hr;
1797 node = allocate_information_node(root_children[index].name);
1798 if (!node)
1800 free_information_tree(info_root);
1801 return E_OUTOFMEMORY;
1804 hr = root_children[index].initfunc(node);
1805 if (FAILED(hr))
1807 free_information_tree(node);
1808 free_information_tree(info_root);
1809 return hr;
1812 add_subcontainer(info_root, node);
1815 *pinfo_root = info_root;
1816 return S_OK;