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