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