shlwapi/tests: Add some tests for memory stream.
[wine.git] / dlls / dxdiagn / provider.c
blobec30574b840c684306eb243d0462c89ce2373b79
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
23 #include "config.h"
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "dxdiag_private.h"
29 #include "wine/unicode.h"
30 #include "winver.h"
31 #include "objidl.h"
32 #include "uuids.h"
33 #include "vfw.h"
34 #include "mmddk.h"
35 #include "d3d9.h"
36 #include "strmif.h"
37 #include "initguid.h"
38 #include "wine/fil_data.h"
39 #include "psapi.h"
40 #include "wbemcli.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
46 static const WCHAR szEmpty[] = {0};
48 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root);
49 static void free_information_tree(IDxDiagContainerImpl_Container *node);
51 static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
52 static const WCHAR szDeviceName[] = {'s','z','D','e','v','i','c','e','N','a','m','e',0};
53 static const WCHAR szKeyDeviceID[] = {'s','z','K','e','y','D','e','v','i','c','e','I','D',0};
54 static const WCHAR szKeyDeviceKey[] = {'s','z','K','e','y','D','e','v','i','c','e','K','e','y',0};
55 static const WCHAR szVendorId[] = {'s','z','V','e','n','d','o','r','I','d',0};
56 static const WCHAR szDeviceId[] = {'s','z','D','e','v','i','c','e','I','d',0};
57 static const WCHAR szDeviceIdentifier[] = {'s','z','D','e','v','i','c','e','I','d','e','n','t','i','f','i','e','r',0};
58 static const WCHAR dwWidth[] = {'d','w','W','i','d','t','h',0};
59 static const WCHAR dwHeight[] = {'d','w','H','e','i','g','h','t',0};
60 static const WCHAR dwBpp[] = {'d','w','B','p','p',0};
61 static const WCHAR szDisplayMemoryLocalized[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','L','o','c','a','l','i','z','e','d',0};
62 static const WCHAR szDisplayMemoryEnglish[] = {'s','z','D','i','s','p','l','a','y','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
63 static const WCHAR szDisplayModeLocalized[] = {'s','z','D','i','s','p','l','a','y','M','o','d','e','L','o','c','a','l','i','z','e','d',0};
64 static const WCHAR szDisplayModeEnglish[] = {'s','z','D','i','s','p','l','a','y','M','o','d','e','E','n','g','l','i','s','h',0};
65 static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
66 static const WCHAR szDriverVersion[] = {'s','z','D','r','i','v','e','r','V','e','r','s','i','o','n',0};
67 static const WCHAR szSubSysId[] = {'s','z','S','u','b','S','y','s','I','d',0};
68 static const WCHAR szRevisionId[] = {'s','z','R','e','v','i','s','i','o','n','I','d',0};
69 static const WCHAR dwRefreshRate[] = {'d','w','R','e','f','r','e','s','h','R','a','t','e',0};
70 static const WCHAR szManufacturer[] = {'s','z','M','a','n','u','f','a','c','t','u','r','e','r',0};
71 static const WCHAR szChipType[] = {'s','z','C','h','i','p','T','y','p','e',0};
72 static const WCHAR szDACType[] = {'s','z','D','A','C','T','y','p','e',0};
73 static const WCHAR szRevision[] = {'s','z','R','e','v','i','s','i','o','n',0};
74 static const WCHAR szMonitorName[] = {'s','z','M','o','n','i','t','o','r','N','a','m','e',0};
75 static const WCHAR szMonitorMaxRes[] = {'s','z','M','o','n','i','t','o','r','M','a','x','R','e','s',0};
76 static const WCHAR szDriverAttributes[] = {'s','z','D','r','i','v','e','r','A','t','t','r','i','b','u','t','e','s',0};
77 static const WCHAR szDriverLanguageEnglish[] = {'s','z','D','r','i','v','e','r','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
78 static const WCHAR szDriverLanguageLocalized[] = {'s','z','D','r','i','v','e','r','L','a','n','g','u','a','g','e','L','o','c','a','l','i','z','e','d',0};
79 static const WCHAR szDriverDateEnglish[] = {'s','z','D','r','i','v','e','r','D','a','t','e','E','n','g','l','i','s','h',0};
80 static const WCHAR szDriverDateLocalized[] = {'s','z','D','r','i','v','e','r','D','a','t','e','L','o','c','a','l','i','z','e','d',0};
81 static const WCHAR lDriverSize[] = {'l','D','r','i','v','e','r','S','i','z','e',0};
82 static const WCHAR szMiniVdd[] = {'s','z','M','i','n','i','V','d','d',0};
83 static const WCHAR szMiniVddDateLocalized[] = {'s','z','M','i','n','i','V','d','d','D','a','t','e','L','o','c','a','l','i','z','e','d',0};
84 static const WCHAR szMiniVddDateEnglish[] = {'s','z','M','i','n','i','V','d','d','D','a','t','e','E','n','g','l','i','s','h',0};
85 static const WCHAR lMiniVddSize[] = {'l','M','i','n','i','V','d','d','S','i','z','e',0};
86 static const WCHAR szVdd[] = {'s','z','V','d','d',0};
87 static const WCHAR bCanRenderWindow[] = {'b','C','a','n','R','e','n','d','e','r','W','i','n','d','o','w',0};
88 static const WCHAR bDriverBeta[] = {'b','D','r','i','v','e','r','B','e','t','a',0};
89 static const WCHAR bDriverDebug[] = {'b','D','r','i','v','e','r','D','e','b','u','g',0};
90 static const WCHAR bDriverSigned[] = {'b','D','r','i','v','e','r','S','i','g','n','e','d',0};
91 static const WCHAR bDriverSignedValid[] = {'b','D','r','i','v','e','r','S','i','g','n','e','d','V','a','l','i','d',0};
92 static const WCHAR szDriverSignDate[] = {'s','z','D','r','i','v','e','r','S','i','g','n','D','a','t','e',0};
93 static const WCHAR dwDDIVersion[] = {'d','w','D','D','I','V','e','r','s','i','o','n',0};
94 static const WCHAR szDDIVersionEnglish[] = {'s','z','D','D','I','V','e','r','s','i','o','n','E','n','g','l','i','s','h',0};
95 static const WCHAR szDDIVersionLocalized[] = {'s','z','D','D','I','V','e','r','s','i','o','n','L','o','c','a','l','i','z','e','d',0};
96 static const WCHAR iAdapter[] = {'i','A','d','a','p','t','e','r',0};
97 static const WCHAR dwWHQLLevel[] = {'d','w','W','H','Q','L','L','e','v','e','l',0};
99 struct IDxDiagProviderImpl
101 IDxDiagProvider IDxDiagProvider_iface;
102 LONG ref;
103 BOOL init;
104 DXDIAG_INIT_PARAMS params;
105 IDxDiagContainerImpl_Container *info_root;
108 static inline IDxDiagProviderImpl *impl_from_IDxDiagProvider(IDxDiagProvider *iface)
110 return CONTAINING_RECORD(iface, IDxDiagProviderImpl, IDxDiagProvider_iface);
113 /* IDxDiagProvider IUnknown parts follow: */
114 static HRESULT WINAPI IDxDiagProviderImpl_QueryInterface(IDxDiagProvider *iface, REFIID riid,
115 void **ppobj)
117 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
119 if (!ppobj) return E_INVALIDARG;
121 if (IsEqualGUID(riid, &IID_IUnknown)
122 || IsEqualGUID(riid, &IID_IDxDiagProvider)) {
123 IUnknown_AddRef(iface);
124 *ppobj = This;
125 return S_OK;
128 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
129 *ppobj = NULL;
130 return E_NOINTERFACE;
133 static ULONG WINAPI IDxDiagProviderImpl_AddRef(IDxDiagProvider *iface)
135 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
136 ULONG refCount = InterlockedIncrement(&This->ref);
138 TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
140 DXDIAGN_LockModule();
142 return refCount;
145 static ULONG WINAPI IDxDiagProviderImpl_Release(IDxDiagProvider *iface)
147 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
148 ULONG refCount = InterlockedDecrement(&This->ref);
150 TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
152 if (!refCount) {
153 free_information_tree(This->info_root);
154 HeapFree(GetProcessHeap(), 0, This);
157 DXDIAGN_UnlockModule();
159 return refCount;
162 /* IDxDiagProvider Interface follow: */
163 static HRESULT WINAPI IDxDiagProviderImpl_Initialize(IDxDiagProvider *iface,
164 DXDIAG_INIT_PARAMS *pParams)
166 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
167 HRESULT hr;
169 TRACE("(%p,%p)\n", iface, pParams);
171 if (NULL == pParams) {
172 return E_POINTER;
174 if (pParams->dwSize != sizeof(DXDIAG_INIT_PARAMS) ||
175 pParams->dwDxDiagHeaderVersion != DXDIAG_DX9_SDK_VERSION) {
176 return E_INVALIDARG;
179 if (!This->info_root)
181 hr = build_information_tree(&This->info_root);
182 if (FAILED(hr))
183 return hr;
186 This->init = TRUE;
187 memcpy(&This->params, pParams, pParams->dwSize);
188 return S_OK;
191 static HRESULT WINAPI IDxDiagProviderImpl_GetRootContainer(IDxDiagProvider *iface,
192 IDxDiagContainer **ppInstance)
194 IDxDiagProviderImpl *This = impl_from_IDxDiagProvider(iface);
196 TRACE("(%p,%p)\n", iface, ppInstance);
198 if (FALSE == This->init) {
199 return CO_E_NOTINITIALIZED;
202 return DXDiag_CreateDXDiagContainer(&IID_IDxDiagContainer, This->info_root,
203 &This->IDxDiagProvider_iface, (void **)ppInstance);
206 static const IDxDiagProviderVtbl DxDiagProvider_Vtbl =
208 IDxDiagProviderImpl_QueryInterface,
209 IDxDiagProviderImpl_AddRef,
210 IDxDiagProviderImpl_Release,
211 IDxDiagProviderImpl_Initialize,
212 IDxDiagProviderImpl_GetRootContainer
215 HRESULT DXDiag_CreateDXDiagProvider(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
216 IDxDiagProviderImpl* provider;
218 TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
220 *ppobj = NULL;
221 if (punkOuter) return CLASS_E_NOAGGREGATION;
223 provider = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDxDiagProviderImpl));
224 if (NULL == provider) return E_OUTOFMEMORY;
225 provider->IDxDiagProvider_iface.lpVtbl = &DxDiagProvider_Vtbl;
226 provider->ref = 0; /* will be inited with QueryInterface */
227 return IDxDiagProviderImpl_QueryInterface(&provider->IDxDiagProvider_iface, riid, ppobj);
230 static void free_property_information(IDxDiagContainerImpl_Property *prop)
232 VariantClear(&prop->vProp);
233 HeapFree(GetProcessHeap(), 0, prop->propName);
234 HeapFree(GetProcessHeap(), 0, prop);
237 static void free_information_tree(IDxDiagContainerImpl_Container *node)
239 IDxDiagContainerImpl_Container *ptr, *cursor2;
241 if (!node)
242 return;
244 HeapFree(GetProcessHeap(), 0, node->contName);
246 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &node->subContainers, IDxDiagContainerImpl_Container, entry)
248 IDxDiagContainerImpl_Property *prop, *prop_cursor2;
250 LIST_FOR_EACH_ENTRY_SAFE(prop, prop_cursor2, &ptr->properties, IDxDiagContainerImpl_Property, entry)
252 list_remove(&prop->entry);
253 free_property_information(prop);
256 list_remove(&ptr->entry);
257 free_information_tree(ptr);
260 HeapFree(GetProcessHeap(), 0, node);
263 static IDxDiagContainerImpl_Container *allocate_information_node(const WCHAR *name)
265 IDxDiagContainerImpl_Container *ret;
267 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
268 if (!ret)
269 return NULL;
271 if (name)
273 ret->contName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
274 if (!ret->contName)
276 HeapFree(GetProcessHeap(), 0, ret);
277 return NULL;
279 strcpyW(ret->contName, name);
282 list_init(&ret->subContainers);
283 list_init(&ret->properties);
285 return ret;
288 static IDxDiagContainerImpl_Property *allocate_property_information(const WCHAR *name)
290 IDxDiagContainerImpl_Property *ret;
292 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
293 if (!ret)
294 return NULL;
296 ret->propName = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(*name));
297 if (!ret->propName)
299 HeapFree(GetProcessHeap(), 0, ret);
300 return NULL;
302 strcpyW(ret->propName, name);
304 return ret;
307 static inline void add_subcontainer(IDxDiagContainerImpl_Container *node, IDxDiagContainerImpl_Container *subCont)
309 list_add_tail(&node->subContainers, &subCont->entry);
310 ++node->nSubContainers;
313 static inline HRESULT add_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, const WCHAR *str)
315 IDxDiagContainerImpl_Property *prop;
316 BSTR bstr;
318 prop = allocate_property_information(propName);
319 if (!prop)
320 return E_OUTOFMEMORY;
322 bstr = SysAllocString(str);
323 if (!bstr)
325 free_property_information(prop);
326 return E_OUTOFMEMORY;
329 V_VT(&prop->vProp) = VT_BSTR;
330 V_BSTR(&prop->vProp) = bstr;
332 list_add_tail(&node->properties, &prop->entry);
333 ++node->nProperties;
335 return S_OK;
338 static inline HRESULT add_ui4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, DWORD data)
340 IDxDiagContainerImpl_Property *prop;
342 prop = allocate_property_information(propName);
343 if (!prop)
344 return E_OUTOFMEMORY;
346 V_VT(&prop->vProp) = VT_UI4;
347 V_UI4(&prop->vProp) = data;
349 list_add_tail(&node->properties, &prop->entry);
350 ++node->nProperties;
352 return S_OK;
355 static inline HRESULT add_i4_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, LONG data)
357 IDxDiagContainerImpl_Property *prop;
359 prop = allocate_property_information(propName);
360 if (!prop)
361 return E_OUTOFMEMORY;
363 V_VT(&prop->vProp) = VT_I4;
364 V_I4(&prop->vProp) = data;
366 list_add_tail(&node->properties, &prop->entry);
367 ++node->nProperties;
369 return S_OK;
372 static inline HRESULT add_bool_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, BOOL data)
374 IDxDiagContainerImpl_Property *prop;
376 prop = allocate_property_information(propName);
377 if (!prop)
378 return E_OUTOFMEMORY;
380 V_VT(&prop->vProp) = VT_BOOL;
381 V_BOOL(&prop->vProp) = data ? VARIANT_TRUE : VARIANT_FALSE;
383 list_add_tail(&node->properties, &prop->entry);
384 ++node->nProperties;
386 return S_OK;
389 static inline HRESULT add_ull_as_bstr_property(IDxDiagContainerImpl_Container *node, const WCHAR *propName, ULONGLONG data )
391 IDxDiagContainerImpl_Property *prop;
392 HRESULT hr;
394 prop = allocate_property_information(propName);
395 if (!prop)
396 return E_OUTOFMEMORY;
398 V_VT(&prop->vProp) = VT_UI8;
399 V_UI8(&prop->vProp) = data;
401 hr = VariantChangeType(&prop->vProp, &prop->vProp, 0, VT_BSTR);
402 if (FAILED(hr))
404 free_property_information(prop);
405 return hr;
408 list_add_tail(&node->properties, &prop->entry);
409 ++node->nProperties;
411 return S_OK;
414 /* Copied from programs/taskkill/taskkill.c. */
415 static DWORD *enumerate_processes(DWORD *list_count)
417 DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes;
419 pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes);
420 if (!pid_list)
421 return NULL;
423 for (;;)
425 DWORD *realloc_list;
427 if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes))
429 HeapFree(GetProcessHeap(), 0, pid_list);
430 return NULL;
433 /* EnumProcesses can't signal an insufficient buffer condition, so the
434 * only way to possibly determine whether a larger buffer is required
435 * is to see whether the written number of bytes is the same as the
436 * buffer size. If so, the buffer will be reallocated to twice the
437 * size. */
438 if (alloc_bytes != needed_bytes)
439 break;
441 alloc_bytes *= 2;
442 realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes);
443 if (!realloc_list)
445 HeapFree(GetProcessHeap(), 0, pid_list);
446 return NULL;
448 pid_list = realloc_list;
451 *list_count = needed_bytes / sizeof(*pid_list);
452 return pid_list;
455 /* Copied from programs/taskkill/taskkill.c. */
456 static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars)
458 HANDLE process;
459 HMODULE module;
460 DWORD required_size;
462 process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
463 if (!process)
464 return FALSE;
466 if (!EnumProcessModules(process, &module, sizeof(module), &required_size))
468 CloseHandle(process);
469 return FALSE;
472 if (!GetModuleBaseNameW(process, module, buf, chars))
474 CloseHandle(process);
475 return FALSE;
478 CloseHandle(process);
479 return TRUE;
482 /* dxdiagn's detection scheme is simply to look for a process called conf.exe. */
483 static BOOL is_netmeeting_running(void)
485 static const WCHAR conf_exe[] = {'c','o','n','f','.','e','x','e',0};
487 DWORD list_count;
488 DWORD *pid_list = enumerate_processes(&list_count);
490 if (pid_list)
492 DWORD i;
493 WCHAR process_name[MAX_PATH];
495 for (i = 0; i < list_count; i++)
497 if (get_process_name_from_pid(pid_list[i], process_name, ARRAY_SIZE(process_name)) &&
498 !lstrcmpW(conf_exe, process_name))
500 HeapFree(GetProcessHeap(), 0, pid_list);
501 return TRUE;
504 HeapFree(GetProcessHeap(), 0, pid_list);
507 return FALSE;
510 static HRESULT fill_language_information(IDxDiagContainerImpl_Container *node)
512 static const WCHAR regional_setting_engW[] = {'R','e','g','i','o','n','a','l',' ','S','e','t','t','i','n','g',0};
513 static const WCHAR languages_fmtW[] = {'%','s',' ','(','%','s',':',' ','%','s',')',0};
514 static const WCHAR szLanguagesLocalized[] = {'s','z','L','a','n','g','u','a','g','e','s','L','o','c','a','l','i','z','e','d',0};
515 static const WCHAR szLanguagesEnglish[] = {'s','z','L','a','n','g','u','a','g','e','s','E','n','g','l','i','s','h',0};
517 WCHAR system_lang[80], regional_setting[100], user_lang[80], language_str[300];
518 HRESULT hr;
520 /* szLanguagesLocalized */
521 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SNATIVELANGNAME, system_lang, ARRAY_SIZE(system_lang));
522 LoadStringW(dxdiagn_instance, IDS_REGIONAL_SETTING, regional_setting, ARRAY_SIZE(regional_setting));
523 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SNATIVELANGNAME, user_lang, ARRAY_SIZE(user_lang));
525 snprintfW(language_str, ARRAY_SIZE(language_str), languages_fmtW, system_lang, regional_setting,
526 user_lang);
528 hr = add_bstr_property(node, szLanguagesLocalized, language_str);
529 if (FAILED(hr))
530 return hr;
532 /* szLanguagesEnglish */
533 GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, system_lang, ARRAY_SIZE(system_lang));
534 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, user_lang, ARRAY_SIZE(user_lang));
536 snprintfW(language_str, ARRAY_SIZE(language_str), languages_fmtW, system_lang,
537 regional_setting_engW, user_lang);
539 hr = add_bstr_property(node, szLanguagesEnglish, language_str);
540 if (FAILED(hr))
541 return hr;
543 return S_OK;
546 static HRESULT fill_datetime_information(IDxDiagContainerImpl_Container *node)
548 static const WCHAR date_fmtW[] = {'M','\'','/','\'','d','\'','/','\'','y','y','y','y',0};
549 static const WCHAR time_fmtW[] = {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
550 static const WCHAR datetime_fmtW[] = {'%','s',',',' ','%','s',0};
551 static const WCHAR szTimeLocalized[] = {'s','z','T','i','m','e','L','o','c','a','l','i','z','e','d',0};
552 static const WCHAR szTimeEnglish[] = {'s','z','T','i','m','e','E','n','g','l','i','s','h',0};
554 SYSTEMTIME curtime;
555 WCHAR date_str[80], time_str[80], datetime_str[200];
556 HRESULT hr;
558 GetLocalTime(&curtime);
560 GetTimeFormatW(LOCALE_NEUTRAL, 0, &curtime, time_fmtW, time_str, ARRAY_SIZE(time_str));
562 /* szTimeLocalized */
563 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &curtime, NULL, date_str, ARRAY_SIZE(date_str));
565 snprintfW(datetime_str, ARRAY_SIZE(datetime_str), datetime_fmtW, date_str, time_str);
567 hr = add_bstr_property(node, szTimeLocalized, datetime_str);
568 if (FAILED(hr))
569 return hr;
571 /* szTimeEnglish */
572 GetDateFormatW(LOCALE_NEUTRAL, 0, &curtime, date_fmtW, date_str, ARRAY_SIZE(date_str));
574 snprintfW(datetime_str, ARRAY_SIZE(datetime_str), datetime_fmtW, date_str, time_str);
576 hr = add_bstr_property(node, szTimeEnglish, datetime_str);
577 if (FAILED(hr))
578 return hr;
580 return S_OK;
583 static HRESULT fill_os_string_information(IDxDiagContainerImpl_Container *node, OSVERSIONINFOW *info)
585 static const WCHAR winxpW[] = {'W','i','n','d','o','w','s',' ','X','P',' ','P','r','o','f','e','s','s','i','o','n','a','l',0};
586 static const WCHAR szOSLocalized[] = {'s','z','O','S','L','o','c','a','l','i','z','e','d',0};
587 static const WCHAR szOSExLocalized[] = {'s','z','O','S','E','x','L','o','c','a','l','i','z','e','d',0};
588 static const WCHAR szOSExLongLocalized[] = {'s','z','O','S','E','x','L','o','n','g','L','o','c','a','l','i','z','e','d',0};
589 static const WCHAR szOSEnglish[] = {'s','z','O','S','E','n','g','l','i','s','h',0};
590 static const WCHAR szOSExEnglish[] = {'s','z','O','S','E','x','E','n','g','l','i','s','h',0};
591 static const WCHAR szOSExLongEnglish[] = {'s','z','O','S','E','x','L','o','n','g','E','n','g','l','i','s','h',0};
593 static const WCHAR *prop_list[] = {szOSLocalized, szOSExLocalized, szOSExLongLocalized,
594 szOSEnglish, szOSExEnglish, szOSExLongEnglish};
596 size_t i;
597 HRESULT hr;
599 /* FIXME: OS detection should be performed, and localized OS strings
600 * should contain translated versions of the "build" phrase. */
601 for (i = 0; i < ARRAY_SIZE(prop_list); i++)
603 hr = add_bstr_property(node, prop_list[i], winxpW);
604 if (FAILED(hr))
605 return hr;
608 return S_OK;
611 static HRESULT fill_processor_information(IDxDiagContainerImpl_Container *node)
613 static const WCHAR szProcessorEnglish[] = {'s','z','P','r','o','c','e','s','s','o','r','E','n','g','l','i','s','h',0};
615 static const WCHAR cimv2W[] = {'\\','\\','.','\\','r','o','o','t','\\','c','i','m','v','2',0};
616 static const WCHAR proc_classW[] = {'W','i','n','3','2','_','P','r','o','c','e','s','s','o','r',0};
617 static const WCHAR nameW[] = {'N','a','m','e',0};
618 static const WCHAR max_clock_speedW[] = {'M','a','x','C','l','o','c','k','S','p','e','e','d',0};
619 static const WCHAR cpu_noW[] = {'N','u','m','b','e','r','O','f','L','o','g','i','c','a','l','P','r','o','c','e','s','s','o','r','s',0};
621 static const WCHAR processor_fmtW[] = {'%','s','(','%','d',' ','C','P','U','s',')',',',' ','~','%','d','M','H','z',0};
623 IWbemLocator *wbem_locator;
624 IWbemServices *wbem_service;
625 IWbemClassObject *wbem_class;
626 IEnumWbemClassObject *wbem_enum;
627 VARIANT cpu_name, cpu_no, clock_speed;
628 WCHAR print_buf[200];
629 BSTR bstr;
630 ULONG no;
631 HRESULT hr;
633 hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (void**)&wbem_locator);
634 if(FAILED(hr))
635 return hr;
637 bstr = SysAllocString(cimv2W);
638 if(!bstr) {
639 IWbemLocator_Release(wbem_locator);
640 return E_OUTOFMEMORY;
642 hr = IWbemLocator_ConnectServer(wbem_locator, bstr, NULL, NULL, NULL, 0, NULL, NULL, &wbem_service);
643 IWbemLocator_Release(wbem_locator);
644 SysFreeString(bstr);
645 if(FAILED(hr))
646 return hr;
648 bstr = SysAllocString(proc_classW);
649 if(!bstr) {
650 IWbemServices_Release(wbem_service);
651 return E_OUTOFMEMORY;
653 hr = IWbemServices_CreateInstanceEnum(wbem_service, bstr, WBEM_FLAG_SYSTEM_ONLY, NULL, &wbem_enum);
654 IWbemServices_Release(wbem_service);
655 SysFreeString(bstr);
656 if(FAILED(hr))
657 return hr;
659 hr = IEnumWbemClassObject_Next(wbem_enum, 1000, 1, &wbem_class, &no);
660 IEnumWbemClassObject_Release(wbem_enum);
661 if(FAILED(hr))
662 return hr;
664 hr = IWbemClassObject_Get(wbem_class, cpu_noW, 0, &cpu_no, NULL, NULL);
665 if(FAILED(hr)) {
666 IWbemClassObject_Release(wbem_class);
667 return hr;
669 hr = IWbemClassObject_Get(wbem_class, max_clock_speedW, 0, &clock_speed, NULL, NULL);
670 if(FAILED(hr)) {
671 IWbemClassObject_Release(wbem_class);
672 return hr;
674 hr = IWbemClassObject_Get(wbem_class, nameW, 0, &cpu_name, NULL, NULL);
675 IWbemClassObject_Release(wbem_class);
676 if(FAILED(hr))
677 return hr;
679 sprintfW(print_buf, processor_fmtW, V_BSTR(&cpu_name), V_I4(&cpu_no), V_I4(&clock_speed));
680 VariantClear(&cpu_name);
681 VariantClear(&cpu_no);
682 VariantClear(&clock_speed);
684 return add_bstr_property(node, szProcessorEnglish, print_buf);
687 static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node)
689 static const WCHAR dwDirectXVersionMajor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','a','j','o','r',0};
690 static const WCHAR dwDirectXVersionMinor[] = {'d','w','D','i','r','e','c','t','X','V','e','r','s','i','o','n','M','i','n','o','r',0};
691 static const WCHAR szDirectXVersionLetter[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','e','t','t','e','r',0};
692 static const WCHAR szDirectXVersionLetter_v[] = {'c',0};
693 static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
694 static const WCHAR bNECPC98[] = {'b','N','E','C','P','C','9','8',0};
695 static const WCHAR szDirectXVersionEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','E','n','g','l','i','s','h',0};
696 static const WCHAR szDirectXVersionEnglish_v[] = {'4','.','0','9','.','0','0','0','0','.','0','9','0','4',0};
697 static const WCHAR szDirectXVersionLongEnglish[] = {'s','z','D','i','r','e','c','t','X','V','e','r','s','i','o','n','L','o','n','g','E','n','g','l','i','s','h',0};
698 static const WCHAR szDirectXVersionLongEnglish_v[] = {'=',' ','"','D','i','r','e','c','t','X',' ','9','.','0','c',' ','(','4','.','0','9','.','0','0','0','0','.','0','9','0','4',')',0};
699 static const WCHAR ullPhysicalMemory[] = {'u','l','l','P','h','y','s','i','c','a','l','M','e','m','o','r','y',0};
700 static const WCHAR ullUsedPageFile[] = {'u','l','l','U','s','e','d','P','a','g','e','F','i','l','e',0};
701 static const WCHAR ullAvailPageFile[] = {'u','l','l','A','v','a','i','l','P','a','g','e','F','i','l','e',0};
702 static const WCHAR bNetMeetingRunning[] = {'b','N','e','t','M','e','e','t','i','n','g','R','u','n','n','i','n','g',0};
703 static const WCHAR szWindowsDir[] = {'s','z','W','i','n','d','o','w','s','D','i','r',0};
704 static const WCHAR dwOSMajorVersion[] = {'d','w','O','S','M','a','j','o','r','V','e','r','s','i','o','n',0};
705 static const WCHAR dwOSMinorVersion[] = {'d','w','O','S','M','i','n','o','r','V','e','r','s','i','o','n',0};
706 static const WCHAR dwOSBuildNumber[] = {'d','w','O','S','B','u','i','l','d','N','u','m','b','e','r',0};
707 static const WCHAR dwOSPlatformID[] = {'d','w','O','S','P','l','a','t','f','o','r','m','I','D',0};
708 static const WCHAR szCSDVersion[] = {'s','z','C','S','D','V','e','r','s','i','o','n',0};
709 static const WCHAR szPhysicalMemoryEnglish[] = {'s','z','P','h','y','s','i','c','a','l','M','e','m','o','r','y','E','n','g','l','i','s','h',0};
710 static const WCHAR szPageFileLocalized[] = {'s','z','P','a','g','e','F','i','l','e','L','o','c','a','l','i','z','e','d',0};
711 static const WCHAR szPageFileEnglish[] = {'s','z','P','a','g','e','F','i','l','e','E','n','g','l','i','s','h',0};
712 static const WCHAR szMachineNameLocalized[] = {'s','z','M','a','c','h','i','n','e','N','a','m','e','L','o','c','a','l','i','z','e','d',0};
713 static const WCHAR szMachineNameEnglish[] = {'s','z','M','a','c','h','i','n','e','N','a','m','e','E','n','g','l','i','s','h',0};
714 static const WCHAR szSystemManufacturerEnglish[] = {'s','z','S','y','s','t','e','m','M','a','n','u','f','a','c','t','u','r','e','r','E','n','g','l','i','s','h',0};
715 static const WCHAR szSystemModelEnglish[] = {'s','z','S','y','s','t','e','m','M','o','d','e','l','E','n','g','l','i','s','h',0};
716 static const WCHAR szBIOSEnglish[] = {'s','z','B','I','O','S','E','n','g','l','i','s','h',0};
717 static const WCHAR szSetupParamEnglish[] = {'s','z','S','e','t','u','p','P','a','r','a','m','E','n','g','l','i','s','h',0};
718 static const WCHAR szDxDiagVersion[] = {'s','z','D','x','D','i','a','g','V','e','r','s','i','o','n',0};
720 static const WCHAR notpresentW[] = {'N','o','t',' ','p','r','e','s','e','n','t',0};
722 static const WCHAR pagefile_fmtW[] = {'%','u','M','B',' ','u','s','e','d',',',' ','%','u','M','B',' ','a','v','a','i','l','a','b','l','e',0};
723 static const WCHAR physmem_fmtW[] = {'%','u','M','B',' ','R','A','M',0};
725 HRESULT hr;
726 MEMORYSTATUSEX msex;
727 OSVERSIONINFOW info;
728 DWORD count, usedpage_mb, availpage_mb;
729 WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200];
730 DWORD_PTR args[2];
732 hr = add_ui4_property(node, dwDirectXVersionMajor, 9);
733 if (FAILED(hr))
734 return hr;
736 hr = add_ui4_property(node, dwDirectXVersionMinor, 0);
737 if (FAILED(hr))
738 return hr;
740 hr = add_bstr_property(node, szDirectXVersionLetter, szDirectXVersionLetter_v);
741 if (FAILED(hr))
742 return hr;
744 hr = add_bstr_property(node, szDirectXVersionEnglish, szDirectXVersionEnglish_v);
745 if (FAILED(hr))
746 return hr;
748 hr = add_bstr_property(node, szDirectXVersionLongEnglish, szDirectXVersionLongEnglish_v);
749 if (FAILED(hr))
750 return hr;
752 hr = add_bool_property(node, bDebug, FALSE);
753 if (FAILED(hr))
754 return hr;
756 hr = add_bool_property(node, bNECPC98, FALSE);
757 if (FAILED(hr))
758 return hr;
760 msex.dwLength = sizeof(msex);
761 GlobalMemoryStatusEx(&msex);
763 hr = add_ull_as_bstr_property(node, ullPhysicalMemory, msex.ullTotalPhys);
764 if (FAILED(hr))
765 return hr;
767 hr = add_ull_as_bstr_property(node, ullUsedPageFile, msex.ullTotalPageFile - msex.ullAvailPageFile);
768 if (FAILED(hr))
769 return hr;
771 hr = add_ull_as_bstr_property(node, ullAvailPageFile, msex.ullAvailPageFile);
772 if (FAILED(hr))
773 return hr;
775 hr = add_bool_property(node, bNetMeetingRunning, is_netmeeting_running());
776 if (FAILED(hr))
777 return hr;
779 info.dwOSVersionInfoSize = sizeof(info);
780 GetVersionExW(&info);
782 hr = add_ui4_property(node, dwOSMajorVersion, info.dwMajorVersion);
783 if (FAILED(hr))
784 return hr;
786 hr = add_ui4_property(node, dwOSMinorVersion, info.dwMinorVersion);
787 if (FAILED(hr))
788 return hr;
790 hr = add_ui4_property(node, dwOSBuildNumber, info.dwBuildNumber);
791 if (FAILED(hr))
792 return hr;
794 hr = add_ui4_property(node, dwOSPlatformID, info.dwPlatformId);
795 if (FAILED(hr))
796 return hr;
798 hr = add_bstr_property(node, szCSDVersion, info.szCSDVersion);
799 if (FAILED(hr))
800 return hr;
802 /* FIXME: Roundoff should not be done with truncated division. */
803 snprintfW(print_buf, ARRAY_SIZE(print_buf), physmem_fmtW,
804 (DWORD)(msex.ullTotalPhys / (1024 * 1024)));
805 hr = add_bstr_property(node, szPhysicalMemoryEnglish, print_buf);
806 if (FAILED(hr))
807 return hr;
809 usedpage_mb = (DWORD)((msex.ullTotalPageFile - msex.ullAvailPageFile) / (1024 * 1024));
810 availpage_mb = (DWORD)(msex.ullAvailPageFile / (1024 * 1024));
811 LoadStringW(dxdiagn_instance, IDS_PAGE_FILE_FORMAT, localized_pagefile_fmt,
812 ARRAY_SIZE(localized_pagefile_fmt));
813 args[0] = usedpage_mb;
814 args[1] = availpage_mb;
815 FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, localized_pagefile_fmt,
816 0, 0, print_buf, ARRAY_SIZE(print_buf), (__ms_va_list*)args);
818 hr = add_bstr_property(node, szPageFileLocalized, print_buf);
819 if (FAILED(hr))
820 return hr;
822 snprintfW(print_buf, ARRAY_SIZE(print_buf), pagefile_fmtW, usedpage_mb, availpage_mb);
824 hr = add_bstr_property(node, szPageFileEnglish, print_buf);
825 if (FAILED(hr))
826 return hr;
828 GetWindowsDirectoryW(buffer, MAX_PATH);
830 hr = add_bstr_property(node, szWindowsDir, buffer);
831 if (FAILED(hr))
832 return hr;
834 count = ARRAY_SIZE(computer_name);
835 if (!GetComputerNameW(computer_name, &count))
836 return E_FAIL;
838 hr = add_bstr_property(node, szMachineNameLocalized, computer_name);
839 if (FAILED(hr))
840 return hr;
842 hr = add_bstr_property(node, szMachineNameEnglish, computer_name);
843 if (FAILED(hr))
844 return hr;
846 hr = add_bstr_property(node, szSystemManufacturerEnglish, szEmpty);
847 if (FAILED(hr))
848 return hr;
850 hr = add_bstr_property(node, szSystemModelEnglish, szEmpty);
851 if (FAILED(hr))
852 return hr;
854 hr = add_bstr_property(node, szBIOSEnglish, szEmpty);
855 if (FAILED(hr))
856 return hr;
858 hr = fill_processor_information(node);
859 if (FAILED(hr))
860 return hr;
862 hr = add_bstr_property(node, szSetupParamEnglish, notpresentW);
863 if (FAILED(hr))
864 return hr;
866 hr = add_bstr_property(node, szDxDiagVersion, szEmpty);
867 if (FAILED(hr))
868 return hr;
870 hr = fill_language_information(node);
871 if (FAILED(hr))
872 return hr;
874 hr = fill_datetime_information(node);
875 if (FAILED(hr))
876 return hr;
878 hr = fill_os_string_information(node, &info);
879 if (FAILED(hr))
880 return hr;
882 return S_OK;
885 /* The logic from pixelformat_for_depth() in dlls/wined3d/utils.c is reversed. */
886 static DWORD depth_for_pixelformat(D3DFORMAT format)
888 switch (format)
890 case D3DFMT_P8: return 8;
891 case D3DFMT_X1R5G5B5: return 15;
892 case D3DFMT_R5G6B5: return 16;
893 /* This case will fail to distinguish an original bpp of 24. */
894 case D3DFMT_X8R8G8B8: return 32;
895 default:
896 FIXME("Unknown D3DFORMAT %d, returning 32 bpp\n", format);
897 return 32;
901 static BOOL get_texture_memory(GUID *adapter, DWORD *available_mem)
903 IDirectDraw7 *pDirectDraw;
904 HRESULT hr;
905 DDSCAPS2 dd_caps;
907 hr = DirectDrawCreateEx(adapter, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
908 if (SUCCEEDED(hr))
910 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
911 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.u1.dwCaps4 = 0;
912 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, available_mem, NULL);
913 IDirectDraw7_Release(pDirectDraw);
914 if (SUCCEEDED(hr))
915 return TRUE;
918 return FALSE;
921 static const WCHAR *vendor_id_to_manufacturer_string(DWORD vendor_id)
923 static const WCHAR atiW[] = {'A','T','I',' ','T','e','c','h','n','o','l','o','g','i','e','s',' ','I','n','c','.',0};
924 static const WCHAR nvidiaW[] = {'N','V','I','D','I','A',0};
925 static const WCHAR intelW[] = {'I','n','t','e','l',' ','C','o','r','p','o','r','a','t','i','o','n',0};
926 static const WCHAR unknownW[] = {'U','n','k','n','o','w','n',0};
928 /* Enumeration copied from dlls/wined3d/wined3d_private.h and slightly modified. */
929 enum pci_vendor
931 HW_VENDOR_AMD = 0x1002,
932 HW_VENDOR_NVIDIA = 0x10de,
933 HW_VENDOR_INTEL = 0x8086,
936 switch (vendor_id)
938 case HW_VENDOR_AMD:
939 return atiW;
940 case HW_VENDOR_NVIDIA:
941 return nvidiaW;
942 case HW_VENDOR_INTEL:
943 return intelW;
944 default:
945 FIXME("Unknown PCI vendor ID 0x%04x\n", vendor_id);
946 return unknownW;
950 static HRESULT fill_display_information_d3d(IDxDiagContainerImpl_Container *node)
952 IDxDiagContainerImpl_Container *display_adapter;
953 HRESULT hr;
954 IDirect3D9 *pDirect3D9;
955 WCHAR buffer[256];
956 UINT index, count;
958 pDirect3D9 = Direct3DCreate9(D3D_SDK_VERSION);
959 if (!pDirect3D9)
960 return E_FAIL;
962 count = IDirect3D9_GetAdapterCount(pDirect3D9);
963 for (index = 0; index < count; index++)
965 static const WCHAR adapterid_fmtW[] = {'%','u',0};
966 static const WCHAR driverversion_fmtW[] = {'%','u','.','%','u','.','%','0','4','u','.','%','0','4','u',0};
967 static const WCHAR id_fmtW[] = {'0','x','%','0','4','x',0};
968 static const WCHAR subsysid_fmtW[] = {'0','x','%','0','8','x',0};
969 static const WCHAR mem_fmt[] = {'%','.','1','f',' ','M','B',0};
970 static const WCHAR b3DAccelerationExists[] = {'b','3','D','A','c','c','e','l','e','r','a','t','i','o','n','E','x','i','s','t','s',0};
971 static const WCHAR b3DAccelerationEnabled[] = {'b','3','D','A','c','c','e','l','e','r','a','t','i','o','n','E','n','a','b','l','e','d',0};
972 static const WCHAR bDDAccelerationEnabled[] = {'b','D','D','A','c','c','e','l','e','r','a','t','i','o','n','E','n','a','b','l','e','d',0};
973 static const WCHAR bNoHardware[] = {'b','N','o','H','a','r','d','w','a','r','e',0};
974 static const WCHAR mode_fmtW[] = {'%','d',' ','x',' ','%','d',' ','(','%','d',' ','b','i','t',')',' ','(','%','d','H','z',')',0};
975 static const WCHAR gernericPNPMonitorW[] = {'G','e','n','e','r','i','c',' ','P','n','P',' ','M','o','n','i','t','o','r',0};
976 static const WCHAR failedToGetParameterW[] = {'F','a','i','l','e','d',' ','t','o',' ','g','e','t',' ','p','a','r','a','m','e','t','e','r',0};
977 static const WCHAR driverAttributesW[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
978 static const WCHAR englishW[] = {'E','n','g','l','i','s','h',0};
979 static const WCHAR driverDateEnglishW[] = {'1','/','1','/','2','0','1','6',' ','1','0',':','0','0',':','0','0',0};
980 static const WCHAR driverDateLocalW[] = {'1','/','1','/','2','0','1','6',' ','1','0',':','0','0',':','0','0',' ','A','M',0};
981 static const WCHAR naW[] = {'n','/','a',0};
982 static const WCHAR ddi11W[] = {'1','1',0};
984 D3DADAPTER_IDENTIFIER9 adapter_info;
985 D3DDISPLAYMODE adapter_mode;
986 D3DCAPS9 device_caps;
987 DWORD available_mem = 0;
988 BOOL hardware_accel;
990 snprintfW(buffer, ARRAY_SIZE(buffer), adapterid_fmtW, index);
991 display_adapter = allocate_information_node(buffer);
992 if (!display_adapter)
994 hr = E_OUTOFMEMORY;
995 goto cleanup;
998 add_subcontainer(node, display_adapter);
1000 hr = IDirect3D9_GetAdapterIdentifier(pDirect3D9, index, 0, &adapter_info);
1001 if (SUCCEEDED(hr))
1003 WCHAR driverW[sizeof(adapter_info.Driver)];
1004 WCHAR descriptionW[sizeof(adapter_info.Description)];
1005 WCHAR devicenameW[sizeof(adapter_info.DeviceName)];
1007 MultiByteToWideChar(CP_ACP, 0, adapter_info.Driver, -1, driverW, ARRAY_SIZE(driverW));
1008 MultiByteToWideChar(CP_ACP, 0, adapter_info.Description, -1, descriptionW,
1009 ARRAY_SIZE(descriptionW));
1010 MultiByteToWideChar(CP_ACP, 0, adapter_info.DeviceName, -1, devicenameW,
1011 ARRAY_SIZE(devicenameW));
1013 hr = add_bstr_property(display_adapter, szDriverName, driverW);
1014 if (FAILED(hr))
1015 goto cleanup;
1017 hr = add_bstr_property(display_adapter, szDescription, descriptionW);
1018 if (FAILED(hr))
1019 goto cleanup;
1021 hr = add_bstr_property(display_adapter, szDeviceName, devicenameW);
1022 if (FAILED(hr))
1023 goto cleanup;
1025 snprintfW(buffer, ARRAY_SIZE(buffer), driverversion_fmtW,
1026 HIWORD(adapter_info.DriverVersion.u.HighPart), LOWORD(adapter_info.DriverVersion.u.HighPart),
1027 HIWORD(adapter_info.DriverVersion.u.LowPart), LOWORD(adapter_info.DriverVersion.u.LowPart));
1029 hr = add_bstr_property(display_adapter, szDriverVersion, buffer);
1030 if (FAILED(hr))
1031 goto cleanup;
1033 snprintfW(buffer, ARRAY_SIZE(buffer), id_fmtW, adapter_info.VendorId);
1034 hr = add_bstr_property(display_adapter, szVendorId, buffer);
1035 if (FAILED(hr))
1036 goto cleanup;
1038 snprintfW(buffer, ARRAY_SIZE(buffer), id_fmtW, adapter_info.DeviceId);
1039 hr = add_bstr_property(display_adapter, szDeviceId, buffer);
1040 if (FAILED(hr))
1041 goto cleanup;
1043 snprintfW(buffer, ARRAY_SIZE(buffer), subsysid_fmtW, adapter_info.SubSysId);
1044 hr = add_bstr_property(display_adapter, szSubSysId, buffer);
1045 if (FAILED(hr))
1046 goto cleanup;
1048 snprintfW(buffer, ARRAY_SIZE(buffer), id_fmtW, adapter_info.Revision);
1049 hr = add_bstr_property(display_adapter, szRevisionId, buffer);
1050 if (FAILED(hr))
1051 goto cleanup;
1053 StringFromGUID2(&adapter_info.DeviceIdentifier, buffer, 39);
1054 hr = add_bstr_property(display_adapter, szDeviceIdentifier, buffer);
1055 if (FAILED(hr))
1056 goto cleanup;
1058 hr = add_bstr_property(display_adapter, szManufacturer, vendor_id_to_manufacturer_string(adapter_info.VendorId));
1059 if (FAILED(hr))
1060 goto cleanup;
1063 hr = IDirect3D9_GetAdapterDisplayMode(pDirect3D9, index, &adapter_mode);
1064 if (SUCCEEDED(hr))
1066 hr = add_ui4_property(display_adapter, dwWidth, adapter_mode.Width);
1067 if (FAILED(hr))
1068 goto cleanup;
1070 hr = add_ui4_property(display_adapter, dwHeight, adapter_mode.Height);
1071 if (FAILED(hr))
1072 goto cleanup;
1074 hr = add_ui4_property(display_adapter, dwRefreshRate, adapter_mode.RefreshRate);
1075 if (FAILED(hr))
1076 goto cleanup;
1078 hr = add_ui4_property(display_adapter, dwBpp, depth_for_pixelformat(adapter_mode.Format));
1079 if (FAILED(hr))
1080 goto cleanup;
1082 snprintfW(buffer, ARRAY_SIZE(buffer), mode_fmtW, adapter_mode.Width, adapter_mode.Height,
1083 depth_for_pixelformat(adapter_mode.Format), adapter_mode.RefreshRate);
1085 hr = add_bstr_property(display_adapter, szDisplayModeLocalized, buffer);
1086 if (FAILED(hr))
1087 goto cleanup;
1089 hr = add_bstr_property(display_adapter, szDisplayModeEnglish, buffer);
1090 if (FAILED(hr))
1091 goto cleanup;
1094 hr = add_bstr_property(display_adapter, szKeyDeviceKey, szEmpty);
1095 if (FAILED(hr))
1096 goto cleanup;
1098 hr = add_bstr_property(display_adapter, szKeyDeviceID, szEmpty);
1099 if (FAILED(hr))
1100 goto cleanup;
1102 hr = add_bstr_property(display_adapter, szChipType, szEmpty);
1103 if (FAILED(hr))
1104 goto cleanup;
1106 hr = add_bstr_property(display_adapter, szDACType, szEmpty);
1107 if (FAILED(hr))
1108 goto cleanup;
1110 hr = add_bstr_property(display_adapter, szRevision, szEmpty);
1111 if (FAILED(hr))
1112 goto cleanup;
1114 if (!get_texture_memory(&adapter_info.DeviceIdentifier, &available_mem))
1115 WARN("get_texture_memory helper failed\n");
1117 snprintfW(buffer, ARRAY_SIZE(buffer), mem_fmt, available_mem / 1000000.0f);
1119 hr = add_bstr_property(display_adapter, szDisplayMemoryLocalized, buffer);
1120 if (FAILED(hr))
1121 goto cleanup;
1123 hr = add_bstr_property(display_adapter, szDisplayMemoryEnglish, buffer);
1124 if (FAILED(hr))
1125 goto cleanup;
1127 hr = IDirect3D9_GetDeviceCaps(pDirect3D9, index, D3DDEVTYPE_HAL, &device_caps);
1128 hardware_accel = SUCCEEDED(hr);
1130 hr = add_bool_property(display_adapter, b3DAccelerationEnabled, hardware_accel);
1131 if (FAILED(hr))
1132 goto cleanup;
1134 hr = add_bool_property(display_adapter, b3DAccelerationExists, hardware_accel);
1135 if (FAILED(hr))
1136 goto cleanup;
1138 hr = add_bool_property(display_adapter, bDDAccelerationEnabled, hardware_accel);
1139 if (FAILED(hr))
1140 goto cleanup;
1142 hr = add_bool_property(display_adapter, bNoHardware, FALSE);
1143 if (FAILED(hr))
1144 goto cleanup;
1146 hr = add_bool_property(display_adapter, bCanRenderWindow, TRUE);
1147 if (FAILED(hr))
1148 goto cleanup;
1150 hr = add_bstr_property(display_adapter, szMonitorName, gernericPNPMonitorW);
1151 if (FAILED(hr))
1152 goto cleanup;
1154 hr = add_bstr_property(display_adapter, szMonitorMaxRes, failedToGetParameterW);
1155 if (FAILED(hr))
1156 goto cleanup;
1158 hr = add_bstr_property(display_adapter, szDriverAttributes, driverAttributesW);
1159 if (FAILED(hr))
1160 goto cleanup;
1162 hr = add_bstr_property(display_adapter, szDriverLanguageEnglish, englishW);
1163 if (FAILED(hr))
1164 goto cleanup;
1166 hr = add_bstr_property(display_adapter, szDriverLanguageLocalized, englishW);
1167 if (FAILED(hr))
1168 goto cleanup;
1170 hr = add_bstr_property(display_adapter, szDriverDateEnglish, driverDateEnglishW);
1171 if (FAILED(hr))
1172 goto cleanup;
1174 hr = add_bstr_property(display_adapter, szDriverDateLocalized, driverDateLocalW);
1175 if (FAILED(hr))
1176 goto cleanup;
1178 hr = add_i4_property(display_adapter, lDriverSize, 10 * 1024 * 1024);
1179 if (FAILED(hr))
1180 goto cleanup;
1182 hr = add_bstr_property(display_adapter, szMiniVdd, naW);
1183 if (FAILED(hr))
1184 goto cleanup;
1186 hr = add_bstr_property(display_adapter, szMiniVddDateLocalized, naW);
1187 if (FAILED(hr))
1188 goto cleanup;
1190 hr = add_bstr_property(display_adapter, szMiniVddDateEnglish, naW);
1191 if (FAILED(hr))
1192 goto cleanup;
1194 hr = add_i4_property(display_adapter, lMiniVddSize, 0);
1195 if (FAILED(hr))
1196 goto cleanup;
1198 hr = add_bstr_property(display_adapter, szVdd, naW);
1199 if (FAILED(hr))
1200 goto cleanup;
1202 hr = add_bool_property(display_adapter, bDriverBeta, FALSE);
1203 if (FAILED(hr))
1204 goto cleanup;
1206 hr = add_bool_property(display_adapter, bDriverDebug, FALSE);
1207 if (FAILED(hr))
1208 goto cleanup;
1210 hr = add_bool_property(display_adapter, bDriverSigned, TRUE);
1211 if (FAILED(hr))
1212 goto cleanup;
1214 hr = add_bool_property(display_adapter, bDriverSignedValid, TRUE);
1215 if (FAILED(hr))
1216 goto cleanup;
1218 hr = add_bstr_property(display_adapter, szDriverSignDate, naW);
1219 if (FAILED(hr))
1220 goto cleanup;
1222 hr = add_ui4_property(display_adapter, dwDDIVersion, 11);
1223 if (FAILED(hr))
1224 goto cleanup;
1226 hr = add_bstr_property(display_adapter, szDDIVersionEnglish, ddi11W);
1227 if (FAILED(hr))
1228 goto cleanup;
1230 hr = add_bstr_property(display_adapter, szDDIVersionLocalized, ddi11W);
1231 if (FAILED(hr))
1232 goto cleanup;
1234 hr = add_ui4_property(display_adapter, iAdapter, index);
1235 if (FAILED(hr))
1236 goto cleanup;
1238 hr = add_ui4_property(display_adapter, dwWHQLLevel, 0);
1239 if (FAILED(hr))
1240 goto cleanup;
1243 hr = S_OK;
1244 cleanup:
1245 IDirect3D9_Release(pDirect3D9);
1246 return hr;
1249 static HRESULT fill_display_information_fallback(IDxDiagContainerImpl_Container *node)
1251 static const WCHAR szAdapterID[] = {'0',0};
1252 static const WCHAR *empty_properties[] = {szDeviceIdentifier, szVendorId, szDeviceId,
1253 szKeyDeviceKey, szKeyDeviceID, szDriverName,
1254 szDriverVersion, szSubSysId, szRevisionId,
1255 szManufacturer, szChipType, szDACType, szRevision};
1257 IDxDiagContainerImpl_Container *display_adapter;
1258 HRESULT hr;
1259 IDirectDraw7 *pDirectDraw;
1260 DDSCAPS2 dd_caps;
1261 DISPLAY_DEVICEW disp_dev;
1262 DDSURFACEDESC2 surface_descr;
1263 DWORD tmp;
1264 WCHAR buffer[256];
1266 display_adapter = allocate_information_node(szAdapterID);
1267 if (!display_adapter)
1268 return E_OUTOFMEMORY;
1270 add_subcontainer(node, display_adapter);
1272 disp_dev.cb = sizeof(disp_dev);
1273 if (EnumDisplayDevicesW( NULL, 0, &disp_dev, 0 ))
1275 hr = add_bstr_property(display_adapter, szDeviceName, disp_dev.DeviceName);
1276 if (FAILED(hr))
1277 return hr;
1279 hr = add_bstr_property(display_adapter, szDescription, disp_dev.DeviceString);
1280 if (FAILED(hr))
1281 return hr;
1284 /* Silently ignore a failure from DirectDrawCreateEx. */
1285 hr = DirectDrawCreateEx(NULL, (void **)&pDirectDraw, &IID_IDirectDraw7, NULL);
1286 if (FAILED(hr))
1287 return S_OK;
1289 dd_caps.dwCaps = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
1290 dd_caps.dwCaps2 = dd_caps.dwCaps3 = dd_caps.u1.dwCaps4 = 0;
1291 hr = IDirectDraw7_GetAvailableVidMem(pDirectDraw, &dd_caps, &tmp, NULL);
1292 if (SUCCEEDED(hr))
1294 static const WCHAR mem_fmt[] = {'%','.','1','f',' ','M','B',0};
1296 snprintfW(buffer, ARRAY_SIZE(buffer), mem_fmt, tmp / 1000000.0f);
1298 hr = add_bstr_property(display_adapter, szDisplayMemoryLocalized, buffer);
1299 if (FAILED(hr))
1300 goto cleanup;
1302 hr = add_bstr_property(display_adapter, szDisplayMemoryEnglish, buffer);
1303 if (FAILED(hr))
1304 goto cleanup;
1307 surface_descr.dwSize = sizeof(surface_descr);
1308 hr = IDirectDraw7_GetDisplayMode(pDirectDraw, &surface_descr);
1309 if (SUCCEEDED(hr))
1311 if (surface_descr.dwFlags & DDSD_WIDTH)
1313 hr = add_ui4_property(display_adapter, dwWidth, surface_descr.dwWidth);
1314 if (FAILED(hr))
1315 goto cleanup;
1318 if (surface_descr.dwFlags & DDSD_HEIGHT)
1320 hr = add_ui4_property(display_adapter, dwHeight, surface_descr.dwHeight);
1321 if (FAILED(hr))
1322 goto cleanup;
1325 if (surface_descr.dwFlags & DDSD_PIXELFORMAT)
1327 hr = add_ui4_property(display_adapter, dwBpp, surface_descr.u4.ddpfPixelFormat.u1.dwRGBBitCount);
1328 if (FAILED(hr))
1329 goto cleanup;
1333 hr = add_ui4_property(display_adapter, dwRefreshRate, 60);
1334 if (FAILED(hr))
1335 goto cleanup;
1337 for (tmp = 0; tmp < ARRAY_SIZE(empty_properties); tmp++)
1339 hr = add_bstr_property(display_adapter, empty_properties[tmp], szEmpty);
1340 if (FAILED(hr))
1341 goto cleanup;
1344 hr = S_OK;
1345 cleanup:
1346 IDirectDraw7_Release(pDirectDraw);
1347 return hr;
1350 static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
1352 HRESULT hr;
1354 /* Try to use Direct3D to obtain the required information first. */
1355 hr = fill_display_information_d3d(node);
1356 if (hr != E_FAIL)
1357 return hr;
1359 return fill_display_information_fallback(node);
1362 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
1364 static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
1365 static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e','D','e','v','i','c','e','s',0};
1367 IDxDiagContainerImpl_Container *cont;
1369 cont = allocate_information_node(DxDiag_SoundDevices);
1370 if (!cont)
1371 return E_OUTOFMEMORY;
1373 add_subcontainer(node, cont);
1375 cont = allocate_information_node(DxDiag_SoundCaptureDevices);
1376 if (!cont)
1377 return E_OUTOFMEMORY;
1379 add_subcontainer(node, cont);
1381 return S_OK;
1384 static HRESULT build_directmusic_tree(IDxDiagContainerImpl_Container *node)
1386 return S_OK;
1389 static HRESULT build_directinput_tree(IDxDiagContainerImpl_Container *node)
1391 return S_OK;
1394 static HRESULT build_directplay_tree(IDxDiagContainerImpl_Container *node)
1396 return S_OK;
1399 static HRESULT build_systemdevices_tree(IDxDiagContainerImpl_Container *node)
1401 return S_OK;
1404 static HRESULT fill_file_description(IDxDiagContainerImpl_Container *node, const WCHAR *szFilePath, const WCHAR *szFileName)
1406 static const WCHAR szSlashSep[] = {'\\',0};
1407 static const WCHAR szPath[] = {'s','z','P','a','t','h',0};
1408 static const WCHAR szName[] = {'s','z','N','a','m','e',0};
1409 static const WCHAR szVersion[] = {'s','z','V','e','r','s','i','o','n',0};
1410 static const WCHAR szAttributes[] = {'s','z','A','t','t','r','i','b','u','t','e','s',0};
1411 static const WCHAR szLanguageEnglish[] = {'s','z','L','a','n','g','u','a','g','e','E','n','g','l','i','s','h',0};
1412 static const WCHAR dwFileTimeHigh[] = {'d','w','F','i','l','e','T','i','m','e','H','i','g','h',0};
1413 static const WCHAR dwFileTimeLow[] = {'d','w','F','i','l','e','T','i','m','e','L','o','w',0};
1414 static const WCHAR bBeta[] = {'b','B','e','t','a',0};
1415 static const WCHAR bDebug[] = {'b','D','e','b','u','g',0};
1416 static const WCHAR bExists[] = {'b','E','x','i','s','t','s',0};
1418 /* Values */
1419 static const WCHAR szFinal_Retail_v[] = {'F','i','n','a','l',' ','R','e','t','a','i','l',0};
1420 static const WCHAR szEnglish_v[] = {'E','n','g','l','i','s','h',0};
1421 static const WCHAR szVersionFormat[] = {'%','u','.','%','0','2','u','.','%','0','4','u','.','%','0','4','u',0};
1423 HRESULT hr;
1424 WCHAR *szFile;
1425 WCHAR szVersion_v[1024];
1426 DWORD retval, hdl;
1427 void *pVersionInfo = NULL;
1428 BOOL boolret = FALSE;
1429 UINT uiLength;
1430 VS_FIXEDFILEINFO *pFileInfo;
1432 TRACE("Filling container %p for %s in %s\n", node,
1433 debugstr_w(szFileName), debugstr_w(szFilePath));
1435 szFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(szFilePath) +
1436 lstrlenW(szFileName) + 2 /* slash + terminator */));
1437 if (!szFile)
1438 return E_OUTOFMEMORY;
1440 lstrcpyW(szFile, szFilePath);
1441 lstrcatW(szFile, szSlashSep);
1442 lstrcatW(szFile, szFileName);
1444 retval = GetFileVersionInfoSizeW(szFile, &hdl);
1445 if (retval)
1447 pVersionInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, retval);
1448 if (!pVersionInfo)
1450 hr = E_OUTOFMEMORY;
1451 goto cleanup;
1454 if (GetFileVersionInfoW(szFile, 0, retval, pVersionInfo) &&
1455 VerQueryValueW(pVersionInfo, szSlashSep, (void **)&pFileInfo, &uiLength))
1456 boolret = TRUE;
1459 hr = add_bstr_property(node, szPath, szFile);
1460 if (FAILED(hr))
1461 goto cleanup;
1463 hr = add_bstr_property(node, szName, szFileName);
1464 if (FAILED(hr))
1465 goto cleanup;
1467 hr = add_bool_property(node, bExists, boolret);
1468 if (FAILED(hr))
1469 goto cleanup;
1471 if (boolret)
1473 snprintfW(szVersion_v, ARRAY_SIZE(szVersion_v), szVersionFormat,
1474 HIWORD(pFileInfo->dwFileVersionMS), LOWORD(pFileInfo->dwFileVersionMS),
1475 HIWORD(pFileInfo->dwFileVersionLS), LOWORD(pFileInfo->dwFileVersionLS));
1477 TRACE("Found version as (%s)\n", debugstr_w(szVersion_v));
1479 hr = add_bstr_property(node, szVersion, szVersion_v);
1480 if (FAILED(hr))
1481 goto cleanup;
1483 hr = add_bstr_property(node, szAttributes, szFinal_Retail_v);
1484 if (FAILED(hr))
1485 goto cleanup;
1487 hr = add_bstr_property(node, szLanguageEnglish, szEnglish_v);
1488 if (FAILED(hr))
1489 goto cleanup;
1491 hr = add_ui4_property(node, dwFileTimeHigh, pFileInfo->dwFileDateMS);
1492 if (FAILED(hr))
1493 goto cleanup;
1495 hr = add_ui4_property(node, dwFileTimeLow, pFileInfo->dwFileDateLS);
1496 if (FAILED(hr))
1497 goto cleanup;
1499 hr = add_bool_property(node, bBeta, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
1500 if (FAILED(hr))
1501 goto cleanup;
1503 hr = add_bool_property(node, bDebug, ((pFileInfo->dwFileFlags & pFileInfo->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
1504 if (FAILED(hr))
1505 goto cleanup;
1508 hr = S_OK;
1509 cleanup:
1510 HeapFree(GetProcessHeap(), 0, pVersionInfo);
1511 HeapFree(GetProcessHeap(), 0, szFile);
1513 return hr;
1515 static HRESULT build_directxfiles_tree(IDxDiagContainerImpl_Container *node)
1517 static const WCHAR dlls[][15] =
1519 {'d','3','d','8','.','d','l','l',0},
1520 {'d','3','d','9','.','d','l','l',0},
1521 {'d','d','r','a','w','.','d','l','l',0},
1522 {'d','e','v','e','n','u','m','.','d','l','l',0},
1523 {'d','i','n','p','u','t','8','.','d','l','l',0},
1524 {'d','i','n','p','u','t','.','d','l','l',0},
1525 {'d','m','b','a','n','d','.','d','l','l',0},
1526 {'d','m','c','o','m','p','o','s','.','d','l','l',0},
1527 {'d','m','i','m','e','.','d','l','l',0},
1528 {'d','m','l','o','a','d','e','r','.','d','l','l',0},
1529 {'d','m','s','c','r','i','p','t','.','d','l','l',0},
1530 {'d','m','s','t','y','l','e','.','d','l','l',0},
1531 {'d','m','s','y','n','t','h','.','d','l','l',0},
1532 {'d','m','u','s','i','c','.','d','l','l',0},
1533 {'d','p','l','a','y','x','.','d','l','l',0},
1534 {'d','p','n','e','t','.','d','l','l',0},
1535 {'d','s','o','u','n','d','.','d','l','l',0},
1536 {'d','s','w','a','v','e','.','d','l','l',0},
1537 {'d','x','d','i','a','g','n','.','d','l','l',0},
1538 {'q','u','a','r','t','z','.','d','l','l',0}
1541 HRESULT hr;
1542 WCHAR szFilePath[MAX_PATH];
1543 INT i;
1545 GetSystemDirectoryW(szFilePath, MAX_PATH);
1547 for (i = 0; i < ARRAY_SIZE(dlls); i++)
1549 static const WCHAR szFormat[] = {'%','d',0};
1551 WCHAR szFileID[5];
1552 IDxDiagContainerImpl_Container *file_container;
1554 snprintfW(szFileID, ARRAY_SIZE(szFileID), szFormat, i);
1556 file_container = allocate_information_node(szFileID);
1557 if (!file_container)
1558 return E_OUTOFMEMORY;
1560 hr = fill_file_description(file_container, szFilePath, dlls[i]);
1561 if (FAILED(hr))
1563 free_information_tree(file_container);
1564 continue;
1567 add_subcontainer(node, file_container);
1570 return S_OK;
1573 static HRESULT read_property_names(IPropertyBag *pPropBag, VARIANT *friendly_name, VARIANT *clsid_name)
1575 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
1576 static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
1578 HRESULT hr;
1580 VariantInit(friendly_name);
1581 VariantInit(clsid_name);
1583 hr = IPropertyBag_Read(pPropBag, wszFriendlyName, friendly_name, 0);
1584 if (FAILED(hr))
1585 return hr;
1587 hr = IPropertyBag_Read(pPropBag, wszClsidName, clsid_name, 0);
1588 if (FAILED(hr))
1590 VariantClear(friendly_name);
1591 return hr;
1594 return S_OK;
1597 static HRESULT fill_filter_data_information(IDxDiagContainerImpl_Container *subcont, BYTE *pData, ULONG cb)
1599 static const WCHAR szVersionW[] = {'s','z','V','e','r','s','i','o','n',0};
1600 static const WCHAR dwInputs[] = {'d','w','I','n','p','u','t','s',0};
1601 static const WCHAR dwOutputs[] = {'d','w','O','u','t','p','u','t','s',0};
1602 static const WCHAR dwMeritW[] = {'d','w','M','e','r','i','t',0};
1603 static const WCHAR szVersionFormat[] = {'v','%','d',0};
1605 HRESULT hr;
1606 IFilterMapper2 *pFileMapper = NULL;
1607 IAMFilterData *pFilterData = NULL;
1608 BYTE *ppRF = NULL;
1609 REGFILTER2 *pRF = NULL;
1610 WCHAR bufferW[10];
1611 ULONG j;
1612 DWORD dwNOutputs = 0;
1613 DWORD dwNInputs = 0;
1615 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2,
1616 (void **)&pFileMapper);
1617 if (FAILED(hr))
1618 return hr;
1620 hr = IFilterMapper2_QueryInterface(pFileMapper, &IID_IAMFilterData, (void **)&pFilterData);
1621 if (FAILED(hr))
1622 goto cleanup;
1624 hr = IAMFilterData_ParseFilterData(pFilterData, pData, cb, (BYTE **)&ppRF);
1625 if (FAILED(hr))
1626 goto cleanup;
1627 pRF = ((REGFILTER2**)ppRF)[0];
1629 snprintfW(bufferW, ARRAY_SIZE(bufferW), szVersionFormat, pRF->dwVersion);
1630 hr = add_bstr_property(subcont, szVersionW, bufferW);
1631 if (FAILED(hr))
1632 goto cleanup;
1634 if (pRF->dwVersion == 1)
1636 for (j = 0; j < pRF->u.s1.cPins; j++)
1637 if (pRF->u.s1.rgPins[j].bOutput)
1638 dwNOutputs++;
1639 else
1640 dwNInputs++;
1642 else if (pRF->dwVersion == 2)
1644 for (j = 0; j < pRF->u.s2.cPins2; j++)
1645 if (pRF->u.s2.rgPins2[j].dwFlags & REG_PINFLAG_B_OUTPUT)
1646 dwNOutputs++;
1647 else
1648 dwNInputs++;
1651 hr = add_ui4_property(subcont, dwInputs, dwNInputs);
1652 if (FAILED(hr))
1653 goto cleanup;
1655 hr = add_ui4_property(subcont, dwOutputs, dwNOutputs);
1656 if (FAILED(hr))
1657 goto cleanup;
1659 hr = add_ui4_property(subcont, dwMeritW, pRF->dwMerit);
1660 if (FAILED(hr))
1661 goto cleanup;
1663 hr = S_OK;
1664 cleanup:
1665 CoTaskMemFree(pRF);
1666 if (pFilterData) IAMFilterData_Release(pFilterData);
1667 if (pFileMapper) IFilterMapper2_Release(pFileMapper);
1669 return hr;
1672 static HRESULT fill_filter_container(IDxDiagContainerImpl_Container *subcont, IMoniker *pMoniker)
1674 static const WCHAR szName[] = {'s','z','N','a','m','e',0};
1675 static const WCHAR ClsidFilterW[] = {'C','l','s','i','d','F','i','l','t','e','r',0};
1676 static const WCHAR wszFilterDataName[] = {'F','i','l','t','e','r','D','a','t','a',0};
1678 HRESULT hr;
1679 IPropertyBag *pPropFilterBag = NULL;
1680 BYTE *pData;
1681 VARIANT friendly_name;
1682 VARIANT clsid_name;
1683 VARIANT v;
1685 VariantInit(&friendly_name);
1686 VariantInit(&clsid_name);
1687 VariantInit(&v);
1689 hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (void **)&pPropFilterBag);
1690 if (FAILED(hr))
1691 return hr;
1693 hr = read_property_names(pPropFilterBag, &friendly_name, &clsid_name);
1694 if (FAILED(hr))
1695 goto cleanup;
1697 TRACE("Name = %s\n", debugstr_w(V_BSTR(&friendly_name)));
1698 TRACE("CLSID = %s\n", debugstr_w(V_BSTR(&clsid_name)));
1700 hr = add_bstr_property(subcont, szName, V_BSTR(&friendly_name));
1701 if (FAILED(hr))
1702 goto cleanup;
1704 hr = add_bstr_property(subcont, ClsidFilterW, V_BSTR(&clsid_name));
1705 if (FAILED(hr))
1706 goto cleanup;
1708 hr = IPropertyBag_Read(pPropFilterBag, wszFilterDataName, &v, NULL);
1709 if (FAILED(hr))
1710 goto cleanup;
1712 hr = SafeArrayAccessData(V_ARRAY(&v), (void **)&pData);
1713 if (FAILED(hr))
1714 goto cleanup;
1716 hr = fill_filter_data_information(subcont, pData, V_ARRAY(&v)->rgsabound->cElements);
1717 SafeArrayUnaccessData(V_ARRAY(&v));
1718 if (FAILED(hr))
1719 goto cleanup;
1721 hr = S_OK;
1722 cleanup:
1723 VariantClear(&v);
1724 VariantClear(&clsid_name);
1725 VariantClear(&friendly_name);
1726 if (pPropFilterBag) IPropertyBag_Release(pPropFilterBag);
1728 return hr;
1731 static HRESULT build_directshowfilters_tree(IDxDiagContainerImpl_Container *node)
1733 static const WCHAR szCatName[] = {'s','z','C','a','t','N','a','m','e',0};
1734 static const WCHAR ClsidCatW[] = {'C','l','s','i','d','C','a','t',0};
1735 static const WCHAR szIdFormat[] = {'%','d',0};
1737 HRESULT hr;
1738 int i = 0;
1739 ICreateDevEnum *pCreateDevEnum;
1740 IEnumMoniker *pEmCat = NULL;
1741 IMoniker *pMCat = NULL;
1742 IEnumMoniker *pEnum = NULL;
1744 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1745 &IID_ICreateDevEnum, (void **)&pCreateDevEnum);
1746 if (FAILED(hr))
1747 return hr;
1749 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &CLSID_ActiveMovieCategories, &pEmCat, 0);
1750 if (FAILED(hr))
1751 goto cleanup;
1753 while (IEnumMoniker_Next(pEmCat, 1, &pMCat, NULL) == S_OK)
1755 VARIANT vCatName;
1756 VARIANT vCatClsid;
1757 IPropertyBag *pPropBag;
1758 CLSID clsidCat;
1759 IMoniker *pMoniker = NULL;
1761 hr = IMoniker_BindToStorage(pMCat, NULL, NULL, &IID_IPropertyBag, (void **)&pPropBag);
1762 if (FAILED(hr))
1764 IMoniker_Release(pMCat);
1765 break;
1768 hr = read_property_names(pPropBag, &vCatName, &vCatClsid);
1769 IPropertyBag_Release(pPropBag);
1770 if (FAILED(hr))
1772 IMoniker_Release(pMCat);
1773 break;
1776 hr = CLSIDFromString(V_BSTR(&vCatClsid), &clsidCat);
1777 if (FAILED(hr))
1779 IMoniker_Release(pMCat);
1780 VariantClear(&vCatClsid);
1781 VariantClear(&vCatName);
1782 break;
1785 hr = ICreateDevEnum_CreateClassEnumerator(pCreateDevEnum, &clsidCat, &pEnum, 0);
1786 if (hr != S_OK)
1788 IMoniker_Release(pMCat);
1789 VariantClear(&vCatClsid);
1790 VariantClear(&vCatName);
1791 continue;
1794 TRACE("Enumerating class %s\n", debugstr_guid(&clsidCat));
1796 while (IEnumMoniker_Next(pEnum, 1, &pMoniker, NULL) == S_OK)
1798 WCHAR bufferW[10];
1799 IDxDiagContainerImpl_Container *subcont;
1801 snprintfW(bufferW, ARRAY_SIZE(bufferW), szIdFormat, i);
1802 subcont = allocate_information_node(bufferW);
1803 if (!subcont)
1805 hr = E_OUTOFMEMORY;
1806 IMoniker_Release(pMoniker);
1807 break;
1810 hr = add_bstr_property(subcont, szCatName, V_BSTR(&vCatName));
1811 if (FAILED(hr))
1813 free_information_tree(subcont);
1814 IMoniker_Release(pMoniker);
1815 break;
1818 hr = add_bstr_property(subcont, ClsidCatW, V_BSTR(&vCatClsid));
1819 if (FAILED(hr))
1821 free_information_tree(subcont);
1822 IMoniker_Release(pMoniker);
1823 break;
1826 hr = fill_filter_container(subcont, pMoniker);
1827 IMoniker_Release(pMoniker);
1828 if (FAILED(hr))
1830 WARN("Skipping invalid filter\n");
1831 free_information_tree(subcont);
1832 hr = S_OK;
1833 continue;
1836 add_subcontainer(node, subcont);
1837 i++;
1840 IEnumMoniker_Release(pEnum);
1841 IMoniker_Release(pMCat);
1842 VariantClear(&vCatClsid);
1843 VariantClear(&vCatName);
1845 if (FAILED(hr))
1846 break;
1849 cleanup:
1850 if (pEmCat) IEnumMoniker_Release(pEmCat);
1851 ICreateDevEnum_Release(pCreateDevEnum);
1852 return hr;
1855 static HRESULT build_logicaldisks_tree(IDxDiagContainerImpl_Container *node)
1857 return S_OK;
1860 static HRESULT build_information_tree(IDxDiagContainerImpl_Container **pinfo_root)
1862 static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
1863 static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
1864 static const WCHAR DxDiag_DirectSound[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d',0};
1865 static const WCHAR DxDiag_DirectMusic[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','M','u','s','i','c',0};
1866 static const WCHAR DxDiag_DirectInput[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','I','n','p','u','t',0};
1867 static const WCHAR DxDiag_DirectPlay[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','P','l','a','y',0};
1868 static const WCHAR DxDiag_SystemDevices[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','D','e','v','i','c','e','s',0};
1869 static const WCHAR DxDiag_DirectXFiles[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','X','F','i','l','e','s',0};
1870 static const WCHAR DxDiag_DirectShowFilters[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','h','o','w','F','i','l','t','e','r','s',0};
1871 static const WCHAR DxDiag_LogicalDisks[] = {'D','x','D','i','a','g','_','L','o','g','i','c','a','l','D','i','s','k','s',0};
1873 static const struct
1875 const WCHAR *name;
1876 HRESULT (*initfunc)(IDxDiagContainerImpl_Container *);
1877 } root_children[] =
1879 {DxDiag_SystemInfo, build_systeminfo_tree},
1880 {DxDiag_DisplayDevices, build_displaydevices_tree},
1881 {DxDiag_DirectSound, build_directsound_tree},
1882 {DxDiag_DirectMusic, build_directmusic_tree},
1883 {DxDiag_DirectInput, build_directinput_tree},
1884 {DxDiag_DirectPlay, build_directplay_tree},
1885 {DxDiag_SystemDevices, build_systemdevices_tree},
1886 {DxDiag_DirectXFiles, build_directxfiles_tree},
1887 {DxDiag_DirectShowFilters, build_directshowfilters_tree},
1888 {DxDiag_LogicalDisks, build_logicaldisks_tree},
1891 IDxDiagContainerImpl_Container *info_root;
1892 size_t index;
1894 info_root = allocate_information_node(NULL);
1895 if (!info_root)
1896 return E_OUTOFMEMORY;
1898 for (index = 0; index < ARRAY_SIZE(root_children); index++)
1900 IDxDiagContainerImpl_Container *node;
1901 HRESULT hr;
1903 node = allocate_information_node(root_children[index].name);
1904 if (!node)
1906 free_information_tree(info_root);
1907 return E_OUTOFMEMORY;
1910 hr = root_children[index].initfunc(node);
1911 if (FAILED(hr))
1913 free_information_tree(node);
1914 free_information_tree(info_root);
1915 return hr;
1918 add_subcontainer(info_root, node);
1921 *pinfo_root = info_root;
1922 return S_OK;