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