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 Stanislav Motylkov <x86corez@gmail.com>
16 typedef struct GENERIC_NAME
22 typedef struct VENDOR_LONG_NAME
28 typedef struct REDUNDANT_WORD
31 BOOL bReplaceFirstWord
;
39 return (chr
<= L
' ' || chr
== L
'.' || chr
== L
',');
43 * Trim redundant characters
56 Length
= wcslen(pStr
);
60 /* Trim leading characters */
61 while (i
< Length
&& IsPunctuation(pStr
[i
]))
69 memmove(pStr
, pStr
+ i
, (Length
+ 1) * sizeof(WCHAR
));
72 /* Trim trailing characters */
73 while (Length
&& IsPunctuation(pStr
[Length
-1]))
75 pStr
[Length
-1] = L
'\0';
81 * Case insensitive variant of wcsstr
84 wchar_t * wcsistr(const wchar_t *s
, const wchar_t *b
)
92 if (towlower(*x
) == towlower(*b
))
96 while (*y
&& *c
&& towlower(*y
) == towlower(*c
))
110 wchar_t * wcsistr_plus(const wchar_t *s
, wchar_t *b
)
112 wchar_t * result
= wcsistr(s
, b
);
113 UINT len
= wcslen(b
);
115 if (!result
&& b
[len
- 1] == L
' ' && wcschr(s
, L
',') != NULL
)
118 result
= wcsistr(s
, b
);
123 result
= wcsistr(s
, b
);
127 if (!result
&& b
[len
- 1] == L
' ' && wcschr(s
, L
'(') != NULL
)
130 result
= wcsistr(s
, b
);
133 if (!result
&& b
[len
- 1] == L
' ' && wcschr(s
, L
'_') != NULL
)
136 result
= wcsistr(s
, b
);
139 if (!result
&& b
[0] == L
' ' && b
[len
- 1] == L
' ' && wcschr(s
, L
')') != NULL
)
142 result
= wcsistr(s
, b
);
149 * Replaces full word with another shorter word
155 _In_ PCWSTR pwReplace
,
156 _In_ BOOL bReplaceFirstWord
)
158 PWSTR pwsStr
, pwsFind
, pwsReplace
, pwsBuf
= NULL
;
163 if (!pwStr
|| !pwFind
|| !pwReplace
||
164 wcslen(pwStr
) == 0 ||
165 wcslen(pwFind
) == 0 ||
166 wcslen(pwFind
) < wcslen(pwReplace
))
170 lenStr
= wcslen(pwStr
) + 2 + 1;
171 lenFind
= wcslen(pwFind
) + 2 + 1;
172 lenReplace
= wcslen(pwReplace
) + 2 + 1;
174 pwsStr
= HeapAlloc(GetProcessHeap(), 0, lenStr
* sizeof(WCHAR
));
179 StringCchCopyW(pwsStr
, lenStr
, L
" ");
180 StringCchCatW(pwsStr
, lenStr
, pwStr
);
181 StringCchCatW(pwsStr
, lenStr
, L
" ");
183 pwsFind
= HeapAlloc(GetProcessHeap(), 0, lenFind
* sizeof(WCHAR
));
188 StringCchCopyW(pwsFind
, lenFind
, L
" ");
189 StringCchCatW(pwsFind
, lenFind
, pwFind
);
190 StringCchCatW(pwsFind
, lenFind
, L
" ");
192 if (!(pwsBuf
= wcsistr_plus(pwsStr
, pwsFind
)))
196 if (!bReplaceFirstWord
&& pwsBuf
- pwsStr
< 2)
201 pwsReplace
= HeapAlloc(GetProcessHeap(), 0, lenReplace
* sizeof(WCHAR
));
206 StringCchCopyW(pwsReplace
, lenReplace
, L
" ");
207 StringCchCatW(pwsReplace
, lenReplace
, pwReplace
);
208 StringCchCatW(pwsReplace
, lenReplace
, L
" ");
213 memmove(pwsBuf
, pwsReplace
, (lenReplace
- 1) * sizeof(WCHAR
));
215 memmove(pwsBuf
+ lenReplace
- (wcslen(pwReplace
) > 0 ? 1 : 2), pwsBuf
+ lenFind
- 1, (lenStr
- lenFind
- (pwsBuf
- pwsStr
) + 1) * sizeof(WCHAR
));
217 while ((pwsBuf
= wcsistr_plus(pwsStr
, pwsFind
)) != NULL
);
219 TrimDmiStringW(pwsStr
);
220 StringCchCopyW(pwStr
, wcslen(pwStr
), pwsStr
);
222 HeapFree(GetProcessHeap(), 0, pwsReplace
);
224 HeapFree(GetProcessHeap(), 0, pwsFind
);
226 HeapFree(GetProcessHeap(), 0, pwsStr
);
230 BOOL
IsGenericSystemName(PCWSTR ven
, PCWSTR dev
)
232 static const GENERIC_NAME Vendors
[] =
234 { L
"To Be Filled By O.E.M.", FALSE
}, // some ASUS boards
235 { L
"System manufacturer", TRUE
}, // some ASUS boards
236 { L
"Default string", TRUE
}, // some Gigabyte boards
237 { L
"LTD Delovoy Office", TRUE
}, // some Gigabyte boards
238 { L
"O.E.M", TRUE
}, // some AMD boards
239 { L
"DEPO Computers", TRUE
}, // various boards
241 static const GENERIC_NAME Devices
[] =
243 { L
"To Be Filled By O.E.M.", FALSE
}, // some ASUS boards
244 { L
"All Series", TRUE
}, // some ASUS boards
245 { L
"System Product Name", TRUE
}, // some ASUS boards
246 { L
"Default string", TRUE
}, // some Gigabyte boards
247 { L
"Please change product name", TRUE
}, // some MSI boards
248 { L
"Computer", TRUE
}, // some Intel boards
249 { L
"ChiefRiver Platform", TRUE
}, // some Intel boards
250 { L
"SharkBay Platform", TRUE
}, // some Intel boards
251 { L
"HuronRiver Platform", TRUE
}, // some Intel boards
252 { L
"SandyBridge Platform", TRUE
}, // some Intel boards
253 { L
"Broadwell Platform", TRUE
}, // some LG boards
254 { L
"Sabine Platform", TRUE
}, // some AMD boards
255 { L
"O.E.M", TRUE
}, // some AMD boards
256 { L
"*", TRUE
}, // various boards
257 { L
"GEG", TRUE
}, // various boards
258 { L
"OEM", TRUE
}, // various boards
259 { L
"DEPO Computers", TRUE
}, // various boards
260 { L
"Aquarius Pro, Std, Elt Series", TRUE
}, // some Foxconn boards
261 { L
"Aquarius Server", TRUE
}, // some ASUS server boards
262 { L
"Aquarius Server G2", TRUE
}, // some ASUS server boards
263 { L
"Super Server", TRUE
}, // some Supermicro server boards
264 { L
"POSITIVO MOBILE", FALSE
}, // some Positivo devices
269 for (i
= 0; i
< _countof(Vendors
); i
++)
275 if (Vendors
[i
].bCaseSensitive
)
277 bMatch
= !wcscmp(ven
, Vendors
[i
].pwName
);
281 bMatch
= !wcsicmp(ven
, Vendors
[i
].pwName
);
289 for (i
= 0; i
< _countof(Devices
); i
++)
295 if (Devices
[i
].bCaseSensitive
)
297 bMatch
= !wcscmp(dev
, Devices
[i
].pwName
);
301 bMatch
= !wcsicmp(dev
, Devices
[i
].pwName
);
312 void AppendSystemFamily(PWSTR pBuf
, SIZE_T cchBuf
, PCHAR
* DmiStrings
, PWSTR dev
)
314 static const PCSTR KnownFamilies
[] =
318 "IdeaCentre", // Lenovo
320 static const PCWSTR Aliases
[] =
329 for (i
= 0; i
< _countof(KnownFamilies
); i
++)
331 StringCchPrintfW(wideStr
, _countof(wideStr
), L
"%S", KnownFamilies
[i
]);
333 if (wcsistr(dev
, wideStr
) == NULL
&&
334 (!Aliases
[i
] || wcsistr(dev
, Aliases
[i
]) == NULL
) &&
335 !stricmp(DmiStrings
[SYS_FAMILY
], KnownFamilies
[i
]))
337 if (wcslen(pBuf
) > 0 && wcslen(dev
) > 0)
339 StringCchCatW(pBuf
, cchBuf
, L
" ");
341 StringCchCatW(pBuf
, cchBuf
, wideStr
);
346 BOOL
GetSystemName(PWSTR pBuf
, SIZE_T cchBuf
)
348 static const VENDOR_LONG_NAME LongNames
[] =
350 { L
"ASUSTeK", L
"ASUS" },
351 { L
"First International Computer", L
"FIC" },
352 { L
"Hewlett-Packard", L
"HP" },
353 { L
"MICRO-STAR", L
"MSI" },
354 { L
"SGI.COM", L
"SGI" },
355 { L
"Silicon Graphics International", L
"SGI" },
356 { L
"InformationComputerSystems", L
"ICS" },
357 { L
"CHUWI INNOVATION AND TECHNOLOGY", L
"CHUWI" },
358 { L
"http://www.abit.com.tw/", L
"ABIT" },
359 { L
"www.abit.com.tw", L
"ABIT" },
360 { L
"Colorful Technology And Development", L
"Colorful" },
361 { L
"HaierComputer", L
"Haier" },
363 static const REDUNDANT_WORD RedundantWords
[] =
365 { L
"Corporation", FALSE
},
366 { L
"Computer", FALSE
},
367 { L
"Computers", FALSE
},
370 { L
"Center", FALSE
},
371 { L
"Systems", FALSE
},
372 { L
"Microsystems", FALSE
},
373 { L
"Infosystems", FALSE
},
374 { L
"Electronics", FALSE
},
375 { L
"Electric", FALSE
},
376 { L
"Software", FALSE
},
377 { L
"International", FALSE
},
378 { L
"Interantonal", FALSE
}, // on purpose (some MSI boards)
379 { L
"Industrial", FALSE
},
380 { L
"Information", FALSE
},
381 { L
"Technology", FALSE
},
382 { L
"Tecohnology", FALSE
}, // on purpose (some Gigabyte boards)
383 { L
"Technologies", FALSE
},
384 { L
"Limited", FALSE
},
404 PCHAR DmiStrings
[ID_STRINGS_MAX
] = { 0 };
405 WCHAR ven
[512], dev
[512];
410 SMBiosBuf
= LoadSMBiosData(DmiStrings
);
416 GetSMBiosStringW(DmiStrings
[SYS_VENDOR
], ven
, _countof(ven
), TRUE
);
417 GetSMBiosStringW(DmiStrings
[SYS_PRODUCT
], dev
, _countof(dev
), TRUE
);
418 bGenericName
= IsGenericSystemName(ven
, dev
);
420 if (wcslen(dev
) == 0 ||
424 // system strings are unusable, use board strings
425 if (DmiStrings
[BOARD_VENDOR
] != NULL
|| !bGenericName
)
427 if ((DmiStrings
[BOARD_VENDOR
] &&
428 strlen(DmiStrings
[BOARD_VENDOR
]) >= 2 &&
429 strstr(DmiStrings
[BOARD_VENDOR
], " ") != DmiStrings
[BOARD_VENDOR
]) ||
430 IsGenericSystemName(ven
, NULL
))
432 GetSMBiosStringW(DmiStrings
[BOARD_VENDOR
], ven
, _countof(ven
), TRUE
);
434 GetSMBiosStringW(DmiStrings
[BOARD_NAME
], dev
, _countof(dev
), TRUE
);
436 if (IsGenericSystemName(ven
, NULL
))
440 if (IsGenericSystemName(NULL
, dev
))
444 if (wcslen(dev
) == 0 &&
445 DmiStrings
[SYS_VERSION
] != NULL
)
447 GetSMBiosStringW(DmiStrings
[SYS_VERSION
], dev
, _countof(dev
), TRUE
);
449 if (IsGenericSystemName(NULL
, dev
))
454 if (wcslen(dev
) == 0 &&
455 DmiStrings
[BOARD_VERSION
] != NULL
)
457 GetSMBiosStringW(DmiStrings
[BOARD_VERSION
], dev
, _countof(dev
), TRUE
);
459 if (IsGenericSystemName(NULL
, dev
))
466 if (wcslen(ven
) == 0 && wcslen(dev
) == 0)
468 // board strings are empty, use BIOS vendor string
469 GetSMBiosStringW(DmiStrings
[BIOS_VENDOR
], ven
, _countof(ven
), TRUE
);
476 GetSMBiosStringW(DmiStrings
[BOARD_VENDOR
], ven
, _countof(ven
), TRUE
);
478 if (IsGenericSystemName(ven
, NULL
))
485 // workaround for LORD ELECTRONICS
486 if (((j
= wcsstr(ven
, L
" ")) != NULL
) && (j
- ven
> 2))
489 if (!wcsncmp(ven
+ wcslen(ven
) - i
, ven
, i
))
491 ven
[wcslen(ven
) - i
] = L
'\0';
495 // make vendor strings shorter
496 for (i
= 0; i
< _countof(LongNames
); i
++)
498 wcsrep(ven
, LongNames
[i
].pwLongName
, LongNames
[i
].pwShortName
, TRUE
);
501 // remove redundant words
502 for (i
= 0; i
< _countof(RedundantWords
); i
++)
504 wcsrep(ven
, RedundantWords
[i
].pwStr
, L
"", RedundantWords
[i
].bReplaceFirstWord
);
506 for (i
= 0; i
< _countof(RedundantWords
); i
++)
508 StringCchCopyW(pBuf
, cchBuf
, RedundantWords
[i
].pwStr
);
509 StringCchCatW(pBuf
, cchBuf
, L
".");
510 wcsrep(ven
, pBuf
, L
"", RedundantWords
[i
].bReplaceFirstWord
);
513 // workaround for LENOVO notebooks
514 if (!wcscmp(ven
, L
"LENOVO"))
516 StringCchCopyW(ven
, _countof(ven
), L
"Lenovo");
518 if (stricmp(DmiStrings
[SYS_VERSION
], "Lenovo") &&
519 stricmp(DmiStrings
[SYS_VERSION
], "Lenovo Product") &&
520 stricmp(DmiStrings
[SYS_VERSION
], " ") &&
521 _strnicmp(DmiStrings
[SYS_VERSION
], " ", 3) &&
522 wcsistr(dev
, L
"IdeaPad ") == NULL
&&
523 wcsistr(dev
, L
"ThinkServer ") == NULL
)
525 GetSMBiosStringW(DmiStrings
[SYS_VERSION
], dev
, _countof(dev
), TRUE
);
528 if (wcsstr(dev
, L
"Lenovo-") == dev
)
530 // replace "-" with space
534 if (!wcscmp(dev
, L
"Lenovo"))
536 GetSMBiosStringW(DmiStrings
[BOARD_NAME
], dev
, _countof(dev
), TRUE
);
539 if (!wcscmp(ven
, L
"IBM") &&
540 DmiStrings
[SYS_VERSION
] != NULL
&&
541 strstr(DmiStrings
[SYS_VERSION
], "ThinkPad ") != NULL
)
543 GetSMBiosStringW(DmiStrings
[SYS_VERSION
], dev
, _countof(dev
), TRUE
);
546 // workaround for DEXP
547 if (!wcscmp(ven
, L
"DEXP"))
549 if (!stricmp(DmiStrings
[SYS_PRODUCT
], "Tablet PC")
550 && DmiStrings
[SYS_VERSION
] != NULL
)
552 GetSMBiosStringW(DmiStrings
[SYS_VERSION
], dev
, _countof(dev
), TRUE
);
556 // workaround for Razer Blade
557 if (!wcscmp(ven
, L
"Razer") && !wcscmp(dev
, L
"Blade"))
559 if (DmiStrings
[SYS_VERSION
] != NULL
)
561 StringCchCopyW(ven
, _countof(ven
), L
"Razer Blade");
562 GetSMBiosStringW(DmiStrings
[SYS_VERSION
], dev
, _countof(dev
), TRUE
);
566 // workaround for MSI motherboards
567 if (!wcscmp(ven
, L
"MSI") &&
568 wcsstr(dev
, L
"MS-") != NULL
&&
569 DmiStrings
[BOARD_NAME
] != NULL
&&
570 strstr(DmiStrings
[BOARD_NAME
], "(MS-") != NULL
)
572 GetSMBiosStringW(DmiStrings
[BOARD_NAME
], dev
, _countof(dev
), TRUE
);
574 if (wcslen(ven
) == 0 &&
575 wcsstr(dev
, L
"MS-") == dev
)
577 StringCchCopyW(ven
, _countof(ven
), L
"MSI");
580 // trim redundant characters
581 TrimPunctuation(ven
);
582 TrimPunctuation(dev
);
584 if (wcsistr(dev
, ven
) == dev
||
585 (!wcscmp(ven
, L
"ASUS") && wcsstr(dev
, L
"ASUS") != NULL
) ||
586 (!wcscmp(ven
, L
"HP") && wcsstr(dev
, L
" by HP") != NULL
))
588 // device string contains vendor string, use second only
589 StringCchCopyW(pBuf
, cchBuf
, dev
);
593 StringCchCopyW(pBuf
, cchBuf
, ven
);
594 AppendSystemFamily(pBuf
, cchBuf
, DmiStrings
, dev
);
595 if (wcslen(pBuf
) > 0 && wcslen(dev
) > 0)
597 StringCchCatW(pBuf
, cchBuf
, L
" ");
599 StringCchCatW(pBuf
, cchBuf
, dev
);
602 FreeSMBiosData(SMBiosBuf
);
604 return (wcslen(pBuf
) > 0);