1 /* 2 * PROJECT: ReactOS System Control Panel Applet 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/sysdm/smbios.c 5 * PURPOSE: Retrieve device or motherboard name identifier from DMI/SMBIOS 6 * COPYRIGHT: Copyright 2018-2019 Stanislav Motylkov <x86corez@gmail.com> 7 * 8 */ 9 10 #include "precomp.h" 11 12 #include <strsafe.h> 13 #include <udmihelp.h> 14 15 typedef struct GENERIC_NAME 16 { 17 PCWSTR pwName; 18 BOOL bCaseSensitive; 19 BOOL bRemove; 20 } GENERIC_NAME; 21 22 typedef struct VENDOR_LONG_NAME 23 { 24 PCWSTR pwLongName; 25 PCWSTR pwShortName; 26 } VENDOR_LONG_NAME; 27 28 typedef struct REDUNDANT_WORD 29 { 30 PCWSTR pwStr; 31 BOOL bReplaceFirstWord; 32 } REDUNDANT_WORD; 33 34 static 35 BOOL 36 IsPunctuation( 37 _In_ WCHAR chr) 38 { 39 return (chr <= L' ' || chr == L'.' || chr == L','); 40 } 41 42 /* 43 * Trim redundant characters 44 */ 45 static 46 VOID 47 TrimPunctuation( 48 _Inout_ PWSTR pStr) 49 { 50 SIZE_T Length; 51 UINT i = 0; 52 53 if (!pStr) 54 return; 55 56 Length = wcslen(pStr); 57 if (Length == 0) 58 return; 59 60 /* Trim leading characters */ 61 while (i < Length && IsPunctuation(pStr[i])) 62 { 63 i++; 64 } 65 66 if (i > 0) 67 { 68 Length -= i; 69 memmove(pStr, pStr + i, (Length + 1) * sizeof(WCHAR)); 70 } 71 72 /* Trim trailing characters */ 73 while (Length && IsPunctuation(pStr[Length-1])) 74 { 75 pStr[Length-1] = L'\0'; 76 --Length; 77 } 78 } 79 80 /* 81 * Case insensitive variant of wcsstr 82 */ 83 static 84 wchar_t * wcsistr(const wchar_t *s, const wchar_t *b) 85 { 86 wchar_t *x; 87 wchar_t *y; 88 wchar_t *c; 89 x = (wchar_t *)s; 90 while (*x) 91 { 92 if (towlower(*x) == towlower(*b)) 93 { 94 y = x; 95 c = (wchar_t *)b; 96 while (*y && *c && towlower(*y) == towlower(*c)) 97 { 98 c++; 99 y++; 100 } 101 if (!*c) 102 return x; 103 } 104 x++; 105 } 106 return NULL; 107 } 108 109 static 110 wchar_t * wcsistr_plus(const wchar_t *s, wchar_t *b) 111 { 112 wchar_t * result = wcsistr(s, b); 113 UINT len = wcslen(b); 114 // workarounds 115 if (!result && b[len - 1] == L' ' && wcschr(s, L',') != NULL) 116 { 117 b[len - 1] = L','; 118 result = wcsistr(s, b); 119 b[len - 1] = L' '; 120 if (!result) 121 { 122 b[0] = L','; 123 result = wcsistr(s, b); 124 b[0] = L' '; 125 } 126 } 127 if (!result && b[len - 1] == L' ' && wcschr(s, L'(') != NULL) 128 { 129 b[len - 1] = L'('; 130 result = wcsistr(s, b); 131 b[len - 1] = L' '; 132 } 133 if (!result && b[len - 1] == L' ' && wcschr(s, L'_') != NULL) 134 { 135 b[0] = L'_'; 136 result = wcsistr(s, b); 137 b[0] = L' '; 138 } 139 if (!result && b[0] == L' ' && b[len - 1] == L' ' && wcschr(s, L')') != NULL) 140 { 141 b[0] = L')'; 142 result = wcsistr(s, b); 143 if (!result && wcschr(s, L'.')) 144 { 145 b[len - 1] = L'.'; 146 result = wcsistr(s, b); 147 b[len - 1] = L' '; 148 } 149 b[0] = L' '; 150 } 151 return result; 152 } 153 154 /* 155 * Replaces full word with another shorter word 156 */ 157 static 158 VOID wcsrep( 159 _Inout_ PWSTR pwStr, 160 _In_ PCWSTR pwFind, 161 _In_ PCWSTR pwReplace, 162 _In_ BOOL bReplaceFirstWord) 163 { 164 PWSTR pwsStr, pwsFind, pwsReplace, pwsBuf = NULL; 165 SIZE_T lenStr; 166 SIZE_T lenFind; 167 SIZE_T lenReplace; 168 169 if (!pwStr || !pwFind || !pwReplace || 170 wcslen(pwStr) == 0 || 171 wcslen(pwFind) == 0 || 172 wcslen(pwFind) < wcslen(pwReplace)) 173 { 174 return; 175 } 176 lenStr = wcslen(pwStr) + 2 + 1; 177 lenFind = wcslen(pwFind) + 2 + 1; 178 lenReplace = wcslen(pwReplace) + 2 + 1; 179 180 pwsStr = HeapAlloc(GetProcessHeap(), 0, lenStr * sizeof(WCHAR)); 181 if (!pwsStr) 182 { 183 return; 184 } 185 StringCchCopyW(pwsStr, lenStr, L" "); 186 StringCchCatW(pwsStr, lenStr, pwStr); 187 StringCchCatW(pwsStr, lenStr, L" "); 188 189 pwsFind = HeapAlloc(GetProcessHeap(), 0, lenFind * sizeof(WCHAR)); 190 if (!pwsFind) 191 { 192 goto freeStr; 193 } 194 StringCchCopyW(pwsFind, lenFind, L" "); 195 StringCchCatW(pwsFind, lenFind, pwFind); 196 StringCchCatW(pwsFind, lenFind, L" "); 197 198 if (!(pwsBuf = wcsistr_plus(pwsStr, pwsFind))) 199 { 200 goto freeFind; 201 } 202 if (!bReplaceFirstWord && pwsBuf - pwsStr < 2) 203 { 204 goto freeFind; 205 } 206 207 pwsReplace = HeapAlloc(GetProcessHeap(), 0, lenReplace * sizeof(WCHAR)); 208 if (!pwsReplace) 209 { 210 goto freeFind; 211 } 212 StringCchCopyW(pwsReplace, lenReplace, L" "); 213 StringCchCatW(pwsReplace, lenReplace, pwReplace); 214 StringCchCatW(pwsReplace, lenReplace, L" "); 215 216 do 217 { 218 // replace substring 219 memmove(pwsBuf, pwsReplace, (lenReplace - 1) * sizeof(WCHAR)); 220 // shift characters 221 memmove(pwsBuf + lenReplace - (wcslen(pwReplace) > 0 ? 1 : 2), pwsBuf + lenFind - 1, (lenStr - lenFind - (pwsBuf - pwsStr) + 1) * sizeof(WCHAR)); 222 } 223 while ((pwsBuf = wcsistr_plus(pwsStr, pwsFind)) != NULL); 224 225 TrimDmiStringW(pwsStr); 226 StringCchCopyW(pwStr, wcslen(pwStr), pwsStr); 227 228 HeapFree(GetProcessHeap(), 0, pwsReplace); 229 freeFind: 230 HeapFree(GetProcessHeap(), 0, pwsFind); 231 freeStr: 232 HeapFree(GetProcessHeap(), 0, pwsStr); 233 } 234 235 static 236 BOOL IsGenericSystemName(PCWSTR ven, PCWSTR dev, BOOL * bRemove) 237 { 238 static const GENERIC_NAME Vendors[] = 239 { 240 // some ASUS boards 241 { L"To Be Filled By O.E.M.", FALSE, TRUE }, 242 { L"To Be Filled By O.E.M", FALSE, TRUE }, 243 { L"System manufacturer", FALSE, TRUE }, 244 // some Gigabyte boards 245 { L"Default string", TRUE, TRUE }, 246 { L"LTD Delovoy Office", TRUE, FALSE }, 247 { L"Motherboard by ZOTAC", TRUE, FALSE }, 248 // various boards 249 { L"Type2 - Board Vendor Name1", TRUE, TRUE }, 250 { L"DEPO Computers", TRUE, FALSE }, 251 { L"-", TRUE, TRUE }, 252 { L"OEM", TRUE, TRUE }, 253 { L"O.E.M", TRUE, TRUE }, 254 { L"Unknow", TRUE, TRUE }, 255 // distinguish between Oracle and older VirtualBox releases (Sun, etc.) 256 { L"innotek GmbH", TRUE, FALSE }, 257 }; 258 static const GENERIC_NAME Devices[] = 259 { 260 // some ASUS boards 261 { L"To Be Filled By O.E.M.", FALSE, TRUE }, 262 { L"To Be Filled By O.E.M", FALSE, TRUE }, 263 { L"All Series", TRUE, TRUE }, 264 { L"System Product Name", TRUE, TRUE }, 265 { L"System Name", TRUE, TRUE }, 266 // some Gigabyte boards 267 { L"Default string", TRUE, TRUE }, 268 // some MSI boards 269 { L"Please change product name", TRUE, TRUE }, 270 // some Intel boards 271 { L"Computer", TRUE, TRUE }, 272 { L"ChiefRiver Platform", TRUE, FALSE }, 273 { L"OakTrail Platform", TRUE, FALSE }, 274 { L"SharkBay Platform", TRUE, FALSE }, 275 { L"HuronRiver Platform", TRUE, FALSE }, 276 { L"SandyBridge Platform", TRUE, FALSE }, 277 { L"Broadwell Platform", TRUE, FALSE }, 278 { L"Sabine Platform", TRUE, FALSE }, 279 // various boards 280 { L"Base Board Product Name", TRUE, TRUE }, 281 { L"Base Board Version", TRUE, TRUE }, 282 { L"Type2 - Board Product Name1", TRUE, TRUE }, 283 { L"Type2 - Board Version", TRUE, TRUE }, 284 { L"*", TRUE, TRUE }, 285 { L"T", TRUE, TRUE }, 286 { L"GEG", TRUE, TRUE }, 287 { L"N/A", TRUE, TRUE }, 288 { L"---", TRUE, TRUE }, 289 { L"OEM", TRUE, TRUE }, 290 { L"INVA", TRUE, TRUE }, 291 { L"O.E.M", TRUE, TRUE }, 292 { L"DNSNB", TRUE, FALSE }, 293 { L"12345", TRUE, FALSE }, 294 { L"``````", TRUE, TRUE }, 295 { L"Uknown", TRUE, TRUE }, 296 { L"Desktop", FALSE, TRUE }, 297 { L"Invalid", FALSE, TRUE }, 298 { L"Reserved", TRUE, TRUE }, 299 { L"HaierComputer", TRUE, FALSE }, 300 { L"DEPO Computers", TRUE, FALSE }, 301 { L"InsydeH2O EFI BIOS", TRUE, TRUE }, 302 { L"HP All-in-One", TRUE, FALSE }, 303 { L"MP Server", TRUE, FALSE }, 304 { L"0000000000", TRUE, TRUE }, 305 // some Foxconn boards 306 { L"Aquarius Pro, Std, Elt Series", TRUE, FALSE }, 307 // some ASUS server boards 308 { L"Aquarius Server", TRUE, FALSE }, 309 { L"Aquarius Server G2", TRUE, FALSE }, 310 // some Supermicro server boards 311 { L"Super Server", TRUE, FALSE }, 312 // some Positivo devices 313 { L"POSITIVO MOBILE", FALSE, FALSE }, 314 }; 315 BOOL bMatch; 316 UINT i; 317 318 if (bRemove) 319 { 320 *bRemove = FALSE; 321 } 322 for (i = 0; i < _countof(Vendors); i++) 323 { 324 if (!ven) 325 { 326 break; 327 } 328 if (Vendors[i].bCaseSensitive) 329 { 330 bMatch = !wcscmp(ven, Vendors[i].pwName); 331 } 332 else 333 { 334 bMatch = !wcsicmp(ven, Vendors[i].pwName); 335 } 336 if (bMatch) 337 { 338 if (bRemove) 339 { 340 *bRemove = Vendors[i].bRemove; 341 } 342 return TRUE; 343 } 344 } 345 346 for (i = 0; i < _countof(Devices); i++) 347 { 348 if (!dev) 349 { 350 break; 351 } 352 if (Devices[i].bCaseSensitive) 353 { 354 bMatch = !wcscmp(dev, Devices[i].pwName); 355 } 356 else 357 { 358 bMatch = !wcsicmp(dev, Devices[i].pwName); 359 } 360 if (bMatch) 361 { 362 if (bRemove) 363 { 364 *bRemove = Devices[i].bRemove; 365 } 366 return TRUE; 367 } 368 } 369 return FALSE; 370 } 371 372 static 373 void AppendSystemFamily(PWSTR pBuf, SIZE_T cchBuf, PCHAR * DmiStrings, PWSTR dev) 374 { 375 static const PCSTR KnownFamilies[] = 376 { 377 "Eee PC", // ASUS 378 "ThinkPad", // Lenovo 379 "IdeaPad", // Lenovo 380 "IdeaCentre", // Lenovo 381 }; 382 static const PCWSTR Aliases[] = 383 { 384 NULL, 385 NULL, 386 NULL, 387 L"IdeaCenter", 388 }; 389 UINT i; 390 WCHAR wideStr[128]; 391 392 for (i = 0; i < _countof(KnownFamilies); i++) 393 { 394 StringCchPrintfW(wideStr, _countof(wideStr), L"%S", KnownFamilies[i]); 395 396 if (wcsistr(dev, wideStr) == NULL && 397 (!Aliases[i] || wcsistr(dev, Aliases[i]) == NULL) && 398 DmiStrings[SYS_FAMILY] != NULL && 399 !stricmp(DmiStrings[SYS_FAMILY], KnownFamilies[i])) 400 { 401 if (wcslen(pBuf) > 0 && wcslen(dev) > 0) 402 { 403 StringCchCatW(pBuf, cchBuf, L" "); 404 } 405 StringCchCatW(pBuf, cchBuf, wideStr); 406 } 407 } 408 } 409 410 static 411 BOOL TrimNonPrintable(PCHAR DmiString) 412 { 413 PCHAR c = DmiString; 414 if (!c) 415 { 416 return FALSE; 417 } 418 while (*c) 419 { 420 if (*c >= 0x20 && *c <= 0x7e) 421 { 422 c++; 423 } 424 else 425 { 426 *c = 0; 427 return TRUE; 428 } 429 } 430 return FALSE; 431 } 432 433 BOOL GetSystemName(PWSTR pBuf, SIZE_T cchBuf) 434 { 435 static const VENDOR_LONG_NAME LongNames[] = 436 { 437 { L"ASUSTeK", L"ASUS" }, 438 { L"First International Computer", L"FIC" }, 439 { L"Hewlett-Packard", L"HP" }, 440 { L"MICRO-STAR", L"MSI" }, 441 { L"SGI.COM", L"SGI" }, 442 { L"Silicon Graphics International", L"SGI" }, 443 { L"Intel(R) Client Systems", L"Intel" }, 444 { L"InformationComputerSystems", L"ICS" }, 445 { L"CHUWI INNOVATION AND TECHNOLOGY", L"CHUWI" }, 446 { L"http://www.abit.com.tw/", L"ABIT" }, 447 { L"www.abit.com.tw", L"ABIT" }, 448 { L"CASPER BILGISAYAR SISTEMLERI A.S", L"Casper" }, 449 { L"Colorful Technology And Development", L"Colorful" }, 450 { L"Colorful Yu Gong Technology And Development", L"Colorful Yu Gong" }, 451 { L"HaierComputer", L"Haier" }, 452 { L"HELIOS BUSINESS COMPUTER", L"HELIOS" }, 453 { L"Shanghai Zongzhi InfoTech", L"Zongzhi" }, 454 { L"TSING HUA TONGFANG CO.,LTD", L"TSINGHUA TONGFANG" }, 455 { L"Yeston Digital Technology Co.,LTD", L"Yeston" }, 456 }; 457 static const REDUNDANT_WORD RedundantWords[] = 458 { 459 { L"Corporation", FALSE }, 460 { L"Communication", FALSE }, 461 { L"Computer", FALSE }, 462 { L"Computers", FALSE }, 463 { L"Group", FALSE }, 464 { L"Cloud", FALSE }, 465 { L"Center", FALSE }, 466 { L"Systems", FALSE }, 467 { L"Microsystems", FALSE }, 468 { L"Infosystems", FALSE }, 469 { L"Electronics", FALSE }, 470 { L"Electric", FALSE }, 471 { L"Software", FALSE }, 472 { L"Foundation", FALSE }, 473 { L"International", FALSE }, 474 { L"Interantonal", FALSE }, // on purpose (some MSI boards) 475 { L"INTERANTIONAL", FALSE }, // on purpose (some MSI boards) 476 { L"Industrial", FALSE }, 477 { L"Information", FALSE }, 478 { L"Informatica", FALSE }, 479 { L"Technology", FALSE }, 480 { L"Tecohnology", FALSE }, // on purpose (some Gigabyte boards) 481 { L"Technologies", FALSE }, 482 { L"Tecnologia", FALSE }, 483 { L"Limited", FALSE }, 484 { L"Int", FALSE }, 485 { L"Inc", FALSE }, 486 { L"Co", FALSE }, 487 { L"Corp", FALSE }, 488 { L"Crop", FALSE }, 489 { L"Ltd", FALSE }, 490 { L"LTDA", FALSE }, 491 { L"GmbH", FALSE }, 492 { L"S.p.A", FALSE }, 493 { L"A.S.", FALSE }, 494 { L"S.A", FALSE }, 495 { L"S.A.S", FALSE }, 496 { L"S/A", FALSE }, 497 { L"SA", FALSE }, 498 { L"SAS", FALSE }, 499 { L"BV", FALSE }, 500 { L"AG", FALSE }, 501 { L"OOO", TRUE }, 502 { L"CJSC", FALSE }, 503 { L"INT'L", FALSE }, 504 { L"plc", FALSE }, 505 }; 506 PVOID SMBiosBuf; 507 PCHAR DmiStrings[ID_STRINGS_MAX] = { 0 }; 508 WCHAR ven[512], dev[512]; 509 CHAR tmpstr[512]; 510 BOOL bTrimProduct, bTrimFamily, bGenericName, bRemove; 511 UINT i; 512 PWCHAR j; 513 514 SMBiosBuf = LoadSMBiosData(DmiStrings); 515 if (!SMBiosBuf) 516 { 517 return FALSE; 518 } 519 520 TrimNonPrintable(DmiStrings[SYS_VENDOR]); 521 bTrimProduct = TrimNonPrintable(DmiStrings[SYS_PRODUCT]); 522 TrimNonPrintable(DmiStrings[SYS_VERSION]); 523 bTrimFamily = TrimNonPrintable(DmiStrings[SYS_FAMILY]); 524 TrimNonPrintable(DmiStrings[BOARD_VENDOR]); 525 TrimNonPrintable(DmiStrings[BOARD_NAME]); 526 TrimNonPrintable(DmiStrings[BOARD_VERSION]); 527 528 if (bTrimProduct) 529 { 530 if (DmiStrings[SYS_FAMILY] && !bTrimFamily) 531 { 532 DmiStrings[SYS_PRODUCT] = DmiStrings[SYS_FAMILY]; 533 bTrimProduct = FALSE; 534 } 535 } 536 537 GetSMBiosStringW(DmiStrings[SYS_VENDOR], ven, _countof(ven), TRUE); 538 GetSMBiosStringW(DmiStrings[SYS_PRODUCT], dev, _countof(dev), TRUE); 539 bGenericName = IsGenericSystemName(ven, dev, NULL) || bTrimProduct; 540 541 if (wcslen(dev) == 0 || 542 !wcscmp(dev, ven) || 543 bGenericName) 544 { 545 BOOL bGenericVen = FALSE, bGenericDev = (wcslen(dev) == 0 || !wcscmp(dev, ven) || bTrimProduct); 546 547 if (bGenericName && IsGenericSystemName(ven, NULL, &bRemove)) 548 { 549 if (bRemove) 550 { 551 *ven = 0; 552 } 553 bGenericVen = TRUE; 554 } 555 if (bGenericName && IsGenericSystemName(NULL, dev, &bRemove)) 556 { 557 if (bRemove) 558 { 559 *dev = 0; 560 } 561 bGenericDev = TRUE; 562 } 563 // system strings are unusable, use board strings 564 if (DmiStrings[BOARD_VENDOR] != NULL || !bGenericName) 565 { 566 if ((DmiStrings[BOARD_VENDOR] && 567 strlen(DmiStrings[BOARD_VENDOR]) >= 2 && 568 strstr(DmiStrings[BOARD_VENDOR], " ") != DmiStrings[BOARD_VENDOR]) || 569 bGenericVen) 570 { 571 GetSMBiosStringW(DmiStrings[BOARD_VENDOR], ven, _countof(ven), TRUE); 572 } 573 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE); 574 575 if (IsGenericSystemName(ven, NULL, &bRemove) && bRemove) 576 { 577 *ven = 0; 578 } 579 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove) 580 { 581 *dev = 0; 582 583 if (!bGenericDev) 584 { 585 GetSMBiosStringW(DmiStrings[SYS_PRODUCT], dev, _countof(dev), TRUE); 586 } 587 } 588 if (wcslen(dev) == 0 && 589 DmiStrings[SYS_VERSION] != NULL) 590 { 591 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE); 592 593 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove) 594 { 595 *dev = 0; 596 } 597 } 598 if (wcslen(dev) == 0 && 599 DmiStrings[BOARD_VERSION] != NULL) 600 { 601 GetSMBiosStringW(DmiStrings[BOARD_VERSION], dev, _countof(dev), TRUE); 602 603 if (IsGenericSystemName(NULL, dev, &bRemove) && bRemove) 604 { 605 *dev = 0; 606 } 607 } 608 } 609 610 if (wcslen(ven) == 0 && wcslen(dev) == 0) 611 { 612 // board strings are empty, use BIOS vendor string 613 GetSMBiosStringW(DmiStrings[BIOS_VENDOR], ven, _countof(ven), TRUE); 614 } 615 } 616 else 617 { 618 if (wcslen(ven) < 2) 619 { 620 GetSMBiosStringW(DmiStrings[BOARD_VENDOR], ven, _countof(ven), TRUE); 621 622 if (IsGenericSystemName(ven, NULL, &bRemove) && bRemove) 623 { 624 *ven = 0; 625 } 626 } 627 } 628 629 // workaround for LORD ELECTRONICS 630 if (((j = wcsstr(ven, L" ")) != NULL) && (j - ven > 2)) 631 { 632 i = j - ven; 633 if (!wcsncmp(ven + wcslen(ven) - i, ven, i)) 634 { 635 ven[wcslen(ven) - i] = L'\0'; 636 } 637 } 638 639 // make vendor strings shorter 640 for (i = 0; i < _countof(LongNames); i++) 641 { 642 if (wcsstr(dev, LongNames[i].pwLongName) == dev) 643 { 644 // swap ven and dev 645 StringCchCopyW(pBuf, cchBuf, ven); 646 StringCchCopyW(ven, _countof(ven), dev); 647 StringCchCopyW(dev, _countof(dev), pBuf); 648 } 649 wcsrep(ven, LongNames[i].pwLongName, LongNames[i].pwShortName, TRUE); 650 } 651 652 // remove redundant words 653 for (i = 0; i < _countof(RedundantWords); i++) 654 { 655 wcsrep(ven, RedundantWords[i].pwStr, L"", RedundantWords[i].bReplaceFirstWord); 656 } 657 for (i = 0; i < _countof(RedundantWords); i++) 658 { 659 StringCchCopyW(pBuf, cchBuf, RedundantWords[i].pwStr); 660 StringCchCatW(pBuf, cchBuf, L"."); 661 wcsrep(ven, pBuf, L"", RedundantWords[i].bReplaceFirstWord); 662 } 663 664 // workaround for LENOVO notebooks 665 if (!wcsicmp(ven, L"LENOVO")) 666 { 667 StringCchCopyW(ven, _countof(ven), L"Lenovo"); 668 669 if (DmiStrings[SYS_VERSION] != NULL) 670 { 671 if (!strncmp(DmiStrings[SYS_VERSION], "ThinkPad ", 11)) 672 { 673 DmiStrings[SYS_VERSION][8] = L'\0'; 674 } 675 if (wcslen(dev) > 0 && 676 (!strcmp(DmiStrings[SYS_VERSION], "IdeaCentre") || 677 !strcmp(DmiStrings[SYS_VERSION], "ThinkPad"))) 678 { 679 DmiStrings[SYS_FAMILY] = DmiStrings[SYS_VERSION]; 680 DmiStrings[SYS_VERSION] = NULL; 681 } 682 else 683 { 684 StringCchCopyA(tmpstr, _countof(tmpstr), DmiStrings[SYS_VERSION]); 685 _strupr(tmpstr); 686 } 687 } 688 689 if (DmiStrings[SYS_VERSION] != NULL && 690 strcmp(tmpstr, " ") && 691 strcmp(tmpstr, "LENOVO") && 692 strstr(tmpstr, "LENOVO ") == NULL && 693 strstr(tmpstr, "LENOVO PRODUCT") == NULL && 694 strstr(tmpstr, "INVALID") == NULL && 695 strncmp(tmpstr, " ", 3) && 696 strstr(DmiStrings[SYS_VERSION], "Rev ") == NULL && 697 strstr(DmiStrings[SYS_VERSION], "1.") == NULL && 698 wcsistr(dev, L"System ") == NULL && // includes System x and ThinkSystem 699 wcsistr(dev, L"IdeaPad ") == NULL && 700 wcsistr(dev, L"ThinkServer ") == NULL) 701 { 702 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE); 703 } 704 705 if (wcsstr(dev, L"Lenovo-") == dev) 706 { 707 // replace "-" with space 708 dev[6] = L' '; 709 } 710 711 if (!wcscmp(dev, L"Lenovo")) 712 { 713 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE); 714 } 715 } 716 if (!wcscmp(ven, L"IBM") && 717 DmiStrings[SYS_VERSION] != NULL && 718 (strstr(DmiStrings[SYS_VERSION], "ThinkPad ") != NULL || 719 strstr(DmiStrings[SYS_VERSION], "ThinkCentre ") != NULL)) 720 { 721 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE); 722 } 723 724 // workaround for DEXP 725 if (!wcscmp(ven, L"DEXP")) 726 { 727 if (DmiStrings[SYS_PRODUCT] != NULL && 728 DmiStrings[SYS_VERSION] != NULL && 729 (!stricmp(DmiStrings[SYS_PRODUCT], "Tablet PC") || 730 !stricmp(DmiStrings[SYS_PRODUCT], "Notebook") || 731 !stricmp(DmiStrings[SYS_PRODUCT], "Decktop"))) 732 { 733 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE); 734 } 735 } 736 737 // workaround for Razer Blade 738 if (!wcscmp(ven, L"Razer") && !wcscmp(dev, L"Blade")) 739 { 740 if (DmiStrings[SYS_VERSION] != NULL) 741 { 742 StringCchCopyW(ven, _countof(ven), L"Razer Blade"); 743 GetSMBiosStringW(DmiStrings[SYS_VERSION], dev, _countof(dev), TRUE); 744 } 745 } 746 747 // workaround for MSI motherboards 748 if (!wcscmp(ven, L"MSI") && 749 wcsstr(dev, L"MS-") != NULL && 750 DmiStrings[BOARD_NAME] != NULL && 751 strstr(DmiStrings[BOARD_NAME], "(MS-") != NULL) 752 { 753 GetSMBiosStringW(DmiStrings[BOARD_NAME], dev, _countof(dev), TRUE); 754 } 755 if (wcslen(ven) == 0 && 756 wcsstr(dev, L"MS-") == dev) 757 { 758 StringCchCopyW(ven, _countof(ven), L"MSI"); 759 } 760 761 // trim redundant characters 762 TrimPunctuation(ven); 763 TrimPunctuation(dev); 764 765 if (wcsistr(dev, ven) == dev || 766 (!wcscmp(ven, L"ASUS") && wcsstr(dev, L"ASUS") != NULL) || 767 (!wcscmp(ven, L"HP") && wcsstr(dev, L" by HP") != NULL) || 768 (!wcscmp(ven, L"INTEL") && wcsstr(dev, L" INTEL") != NULL)) 769 { 770 // device string contains vendor string, use second only 771 StringCchCopyW(pBuf, cchBuf, dev); 772 } 773 else 774 { 775 if (wcslen(ven) > 0 && wcslen(dev) > 0 && (j = wcschr(dev, L' '))) 776 { 777 // check if vendor string ends with first word of device string 778 i = j - dev; 779 if (wcslen(ven) > i && !_wcsnicmp(ven + wcslen(ven) - i, dev, i)) 780 { 781 ven[wcslen(ven) - i] = L'\0'; 782 TrimPunctuation(ven); 783 } 784 } 785 StringCchCopyW(pBuf, cchBuf, ven); 786 AppendSystemFamily(pBuf, cchBuf, DmiStrings, dev); 787 if (wcslen(pBuf) > 0 && wcslen(dev) > 0) 788 { 789 StringCchCatW(pBuf, cchBuf, L" "); 790 } 791 StringCchCatW(pBuf, cchBuf, dev); 792 } 793 794 FreeSMBiosData(SMBiosBuf); 795 796 return (wcslen(pBuf) > 0); 797 } 798