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