Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
12 KiB

  1. /*** findoem.cpp - OEM detection interface
  2. *
  3. * Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * Author: Yan Leshinsky (YanL)
  6. * Created 10/08/98
  7. *
  8. * MODIFICATION HISTORY
  9. */
  10. //#define _WIN32_WINNT 0x0400
  11. #include <comdef.h>
  12. #include <windows.h>
  13. #include <ole2.h>
  14. #include <stdlib.h>
  15. #include <wbemcli.h>
  16. #include <tchar.h>
  17. #include <atlconv.h>
  18. #include <wustl.h>
  19. #include "cdmlibp.h"
  20. // Smart pointers
  21. _COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
  22. _COM_SMARTPTR_TYPEDEF(IWbemServices, __uuidof(IWbemServices));
  23. _COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
  24. _COM_SMARTPTR_TYPEDEF(IWbemClassObject, __uuidof(IWbemClassObject));
  25. // hardcodes - not defined in any header
  26. const CLSID CLSID_WbemLocator = {0x4590f811,0x1d3a,0x11d0,{0x89,0x1f,0x00,0xaa,0x00,0x4b,0x2e,0x24}};
  27. #include "try_catch.h"
  28. #include "findoem.h"
  29. #define BYTEOF(d,i) (((BYTE *)&(d))[i])
  30. /*** That will let me to include file into queryoem and avoid having additional dll
  31. */
  32. extern HMODULE GetModule();
  33. /*** Local function prototypes
  34. */
  35. static void UseOeminfoIni(POEMINFO pOemInfo);
  36. static void UseWBEM(POEMINFO pOemInfo);
  37. static bool ReadFromReg(POEMINFO pOemInfo);
  38. static void SaveToReg(POEMINFO pOemInfo);
  39. /*** Registry access
  40. */
  41. static const TCHAR REGSTR_KEY_OEMINFO[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\OemInfo");
  42. static const TCHAR REGSTR_VAL_MASK[] = _T("Mask");
  43. static const TCHAR REGSTR_VAL_ACPIOEM[] = _T("AcpiOem");
  44. static const TCHAR REGSTR_VAL_ACPIPRODUCT[] = _T("AcpiProduct");
  45. static const TCHAR REGSTR_VAL_SMBOEM[] = _T("SmbOem");
  46. static const TCHAR REGSTR_VAL_SMBPRODUCT[] = _T("SmbProduct");
  47. static const TCHAR REGSTR_VAL_PNPOEMID[] = _T("PnpOemId");
  48. static const TCHAR REGSTR_VAL_INIOEM[] = _T("IniOem");
  49. static const TCHAR REGSTR_VAL_WBEMOEM[] = _T("WbemOem");
  50. static const TCHAR REGSTR_VAL_WBEMPRODUCT[] = _T("WbemProduct");
  51. static const TCHAR REGSTR_VAL_OEMINFO_VER[] = _T("OemInfoVersion"); // used to determine if we need to nuke old values
  52. //
  53. // Increment REG_CURRENT_OEM_VER whenever you need to force override of
  54. // old values written to the OemInfo key. Doesn't need to change for each
  55. // new control version.
  56. //
  57. #define REG_CURRENT_OEM_VER 1
  58. /*** GetMachinePnPID - Find IDs corresponding to Make and Model code
  59. *
  60. * ENTRY
  61. * PSZ szTable
  62. * Table format is
  63. *
  64. * |##| ... |##|00|##|##|##|##|
  65. * | | | |
  66. * OEM Model \0 PnP ID
  67. *
  68. * |00|00|00|00|
  69. * | |
  70. * 00000
  71. *
  72. * EXIT
  73. * PnP ID or 0
  74. */
  75. DWORD GetMachinePnPID(PBYTE pbTable)
  76. {
  77. USES_CONVERSION;
  78. LPTSTR sz = (LPTSTR)DetectMachineID();
  79. LPSTR szMnM = T2A(sz);
  80. if (NULL == szMnM)
  81. {
  82. return 0;
  83. }
  84. while (*pbTable)
  85. {
  86. PDWORD pId = (PDWORD)(pbTable + strlen((LPSTR)pbTable) + 1); // Skip code position on IDs
  87. if (0 == strcmp((LPSTR)pbTable, szMnM))
  88. return *pId;
  89. pbTable = (PBYTE)(pId + 1); // Skip last 0
  90. }
  91. return 0;
  92. }
  93. /*** DetectMachineID - Gather all available machine OEM and model information nad return ID
  94. *
  95. * EXIT
  96. * returns ID
  97. */
  98. LPCTSTR DetectMachineID(bool fAlwaysDetectAndDontSave /*= false*/)
  99. {
  100. OEMINFO oi;
  101. GetOemInfo(&oi, fAlwaysDetectAndDontSave);
  102. return MakeAndModel(&oi);
  103. }
  104. /*** MakeAndModel - Return ID for a machine
  105. *
  106. * ENTRY
  107. * POEMINFO pOemInfo
  108. *
  109. * EXIT
  110. * returns ID
  111. */
  112. LPCTSTR MakeAndModel(POEMINFO pOemInfo)
  113. {
  114. static TCHAR szMnM[256];
  115. #ifdef _WUV3TEST
  116. auto_hkey hkey;
  117. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUV3TEST, 0, KEY_READ, &hkey)) {
  118. DWORD dwLangID = 0;
  119. DWORD dwSize = sizeof(szMnM);
  120. if (NO_ERROR == RegQueryValueEx(hkey, _T("MachineID"), 0, 0, (LPBYTE)szMnM, &dwSize))
  121. {
  122. return szMnM;
  123. }
  124. }
  125. #endif
  126. szMnM[0] = 0;
  127. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  128. {
  129. lstrcpy(szMnM, pOemInfo->szWbemOem);
  130. lstrcat(szMnM, _T(" "));
  131. lstrcat(szMnM, pOemInfo->szWbemProduct);
  132. lstrcat(szMnM, _T(";"));
  133. }
  134. else if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  135. {
  136. lstrcat(szMnM, pOemInfo->szIniOem);
  137. lstrcat(szMnM, _T(";"));
  138. }
  139. return szMnM;
  140. }
  141. /*** GetOemInfo - Gather all available machine OEM and model information
  142. *
  143. * ENTRY
  144. * POEMINFO pOemInfo
  145. *
  146. * EXIT
  147. * POEMINFO pOemInfo
  148. * All fields that aren't available will be filled with 0
  149. * returns NULL
  150. */
  151. void GetOemInfo(POEMINFO pOemInfo, bool fAlwaysDetectAndDontSave /*= false*/)
  152. {
  153. // Worst case:
  154. memset(pOemInfo, 0, sizeof(OEMINFO));
  155. // Do detection if necessary or requested
  156. if (fAlwaysDetectAndDontSave || ! ReadFromReg(pOemInfo))
  157. {
  158. UseWBEM(pOemInfo);
  159. UseOeminfoIni(pOemInfo);
  160. // Save info to the registry
  161. if (!fAlwaysDetectAndDontSave)
  162. {
  163. SaveToReg(pOemInfo);
  164. }
  165. }
  166. }
  167. /***LP IsValidStringID - check if string ID is valid
  168. *
  169. * ENTRY
  170. * pszID pOemInfo-> Pnp ID string
  171. *
  172. * EXIT-SUCCESS
  173. * returns TRUE
  174. * EXIT-FAILURE
  175. * returns FALSE
  176. */
  177. BOOL IsValidStringID(PSZ pszID)
  178. {
  179. return (strlen(pszID) == 7) &&
  180. isupper(pszID[0]) && isupper(pszID[1]) && isupper(pszID[2]) &&
  181. isxdigit(pszID[3]) && isxdigit(pszID[4]) && isxdigit(pszID[5]) && isxdigit(pszID[6]);
  182. } //IsValidStringID
  183. /***LP NumericID - convert string ID to numeric ID
  184. *
  185. * ENTRY
  186. * psz pOemInfo-> PnP ID string
  187. *
  188. * EXIT
  189. * returns numeric ID
  190. */
  191. DWORD NumericID(PSZ psz)
  192. {
  193. DWORD dwID;
  194. WORD wVenID;
  195. int i;
  196. for (i = 0, wVenID = 0; i < 3; ++i)
  197. {
  198. wVenID <<= 5;
  199. wVenID |= (psz[i] - 0x40) & 0x1f;
  200. }
  201. dwID = strtoul(&psz[3], NULL, 16);
  202. dwID = ((dwID & 0x00ff) << 8) | ((dwID & 0xff00) >> 8);
  203. dwID <<= 16;
  204. dwID |= (wVenID & 0x00ff) << 8;
  205. dwID |= (wVenID & 0xff00) >> 8;
  206. return dwID;
  207. } //NumericID
  208. /***LP StringID - convert numeric ID to string ID
  209. *
  210. * ENTRY
  211. * dwID - numeric PnP ID
  212. *
  213. * EXIT
  214. * returns string ID
  215. */
  216. PSZ StringID(DWORD dwID)
  217. {
  218. static char szID[8];
  219. WORD wVenID;
  220. int i;
  221. wVenID = (WORD)(((dwID & 0x00ff) << 8) | ((dwID & 0xff00) >> 8));
  222. wVenID <<= 1;
  223. for (i = 0; i < 3; ++i)
  224. {
  225. szID[i] = (char)(((wVenID & 0xf800) >> 11) + 0x40);
  226. wVenID <<= 5;
  227. }
  228. wVenID = HIWORD(dwID);
  229. wVenID = (WORD)(((wVenID & 0x00ff) << 8) | ((wVenID & 0xff00) >> 8));
  230. for (i = 6; i > 2; --i)
  231. {
  232. szID[i] = (char)(wVenID & 0x000F);
  233. if(szID[i] > 9)
  234. {
  235. szID[i] += 0x37; // 'A' - 0xA for digits A to F
  236. }
  237. else
  238. {
  239. szID[i] += 0x30; // '0' for digits 0 to 9
  240. }
  241. wVenID >>= 4;
  242. }
  243. return szID;
  244. } //StringID
  245. /*** UseOeminfoIni - get OemInfo from OEMINFO.INI
  246. *
  247. * ENTRY
  248. * POEMINFO pOemInfo
  249. *
  250. * EXIT
  251. * POEMINFO pOemInfo
  252. * All fields that aren't available will be filled with 0
  253. * returns NULL
  254. */
  255. void UseOeminfoIni(POEMINFO pOemInfo)
  256. {
  257. USES_CONVERSION;
  258. static const TCHAR szFile[] = _T("OEMINFO.INI");
  259. static const TCHAR szSection[] = _T("General");
  260. static const TCHAR szKey[] = _T("Manufacturer");
  261. TCHAR szPath[MAX_PATH];
  262. // WU Bug# 11921 -- OEMINFO.INI is in system directory not Windows directory
  263. if (GetSystemDirectory(szPath, sizeOfArray(szPath)) > 0)
  264. {
  265. // check for "c:\"
  266. if (szPath[lstrlen(szPath)-1] != '\\')
  267. {
  268. lstrcat(szPath, _T("\\"));
  269. }
  270. lstrcat(szPath, szFile);
  271. GetPrivateProfileString(szSection, szKey, _T(""),
  272. pOemInfo->szIniOem, sizeOfArray(pOemInfo->szIniOem), szPath);
  273. if (lstrlen(pOemInfo->szIniOem))
  274. {
  275. pOemInfo->dwMask |= OEMINFO_INI_PRESENT;
  276. }
  277. }
  278. }
  279. /*** UseWBEM - Get info through WBEM access
  280. *
  281. * ENTRY
  282. * POEMINFO pOemInfo
  283. *
  284. * EXIT
  285. * POEMINFO pOemInfo
  286. * All fields that aren't available will be filled with 0
  287. * returns NULL
  288. */
  289. void UseWBEM(POEMINFO pOemInfo)
  290. {
  291. try_block
  292. {
  293. USES_CONVERSION;
  294. // Create Locator
  295. IWbemLocatorPtr pWbemLocator;
  296. throw_hr(pWbemLocator.CreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER));
  297. // Get services
  298. IWbemServicesPtr pWbemServices;
  299. throw_hr(pWbemLocator->ConnectServer(bstr_t(L"\\\\.\\root\\cimv2"), NULL, NULL, 0L, 0L, NULL, NULL, &pWbemServices));
  300. throw_hr(CoSetProxyBlanket(pWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  301. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE));
  302. // Create enumerator
  303. IEnumWbemClassObjectPtr pEnum;
  304. throw_hr(pWbemServices->CreateInstanceEnum(bstr_t(L"Win32_ComputerSystem"), 0, NULL, &pEnum));
  305. throw_hr(CoSetProxyBlanket(pEnum, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  306. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE));
  307. // Get our object now
  308. ULONG uReturned = 1;
  309. IWbemClassObjectPtr pObject;
  310. throw_hr(pEnum->Next(
  311. 6000, // timeout in two seconds
  312. 1, // return just one storage device
  313. &pObject, // pointer to storage device
  314. &uReturned)); // number obtained: one or zero
  315. variant_t var;
  316. throw_hr(pObject->Get(L"Manufacturer", 0L, &var, NULL, NULL));
  317. if (VT_BSTR == var.vt)
  318. {
  319. lstrcpy(pOemInfo->szWbemOem, W2T(var.bstrVal));
  320. }
  321. throw_hr(pObject->Get(L"Model", 0L, &var, NULL, NULL));
  322. if (VT_BSTR == var.vt)
  323. {
  324. lstrcpy(pOemInfo->szWbemProduct, W2T(var.bstrVal));
  325. }
  326. if (0 != lstrlen(pOemInfo->szWbemOem) || 0 != lstrlen(pOemInfo->szWbemProduct))
  327. {
  328. pOemInfo->dwMask |= OEMINFO_WBEM_PRESENT;
  329. }
  330. } catch_all;
  331. }
  332. /*** ReadFromReg - read OEMINFO from registry
  333. *
  334. * ENTRY
  335. * POEMINFO pOemInfo
  336. *
  337. * EXIT
  338. * true if info is present
  339. * false otherwise
  340. */
  341. bool ReadFromReg(POEMINFO pOemInfo)
  342. {
  343. DWORD dwVersion = 0;
  344. //read registry first
  345. auto_hkey hkeyOemInfo;
  346. if (NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_KEY_OEMINFO, 0, KEY_READ, &hkeyOemInfo))
  347. {
  348. DWORD dwCount = sizeof(pOemInfo->dwMask);
  349. RegQueryValueEx(hkeyOemInfo, REGSTR_VAL_MASK, 0, 0, (LPBYTE)&(pOemInfo->dwMask), &dwCount);
  350. //
  351. // ***** WU Bug# 11921 *****
  352. //
  353. //
  354. // No bits set requires detection
  355. //
  356. if(!pOemInfo->dwMask)
  357. return false;
  358. //
  359. // If an older version of the detection wrote the OemInfo return false to force detection.
  360. // This value is written starting with 1 around August 2000 for the Classic control.
  361. //
  362. dwCount = sizeof(dwVersion);
  363. if (NO_ERROR == RegQueryValueEx(hkeyOemInfo, REGSTR_VAL_OEMINFO_VER, 0, 0, (LPBYTE)&dwVersion, &dwCount))
  364. {
  365. if(REG_CURRENT_OEM_VER > dwVersion)
  366. return false;
  367. }
  368. else
  369. {
  370. return false;
  371. }
  372. //
  373. // ***** end WU Bug *****
  374. //
  375. if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  376. {
  377. dwCount = sizeof(pOemInfo->szIniOem);
  378. RegQueryValueEx(hkeyOemInfo, REGSTR_VAL_INIOEM, 0, 0, (LPBYTE)&(pOemInfo->szIniOem), &dwCount);
  379. }
  380. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  381. {
  382. dwCount = sizeof(pOemInfo->szWbemOem);
  383. RegQueryValueEx(hkeyOemInfo, REGSTR_VAL_WBEMOEM, 0, 0, (LPBYTE)&(pOemInfo->szWbemOem), &dwCount);
  384. dwCount = sizeof(pOemInfo->szWbemProduct);
  385. RegQueryValueEx(hkeyOemInfo, REGSTR_VAL_WBEMPRODUCT, 0, 0, (LPBYTE)&(pOemInfo->szWbemProduct), &dwCount);
  386. }
  387. return true;
  388. }
  389. else
  390. {
  391. return false;
  392. }
  393. }
  394. /*** SaveToReg - Save OEMINFO
  395. *
  396. * ENTRY
  397. * POEMINFO pOemInfo
  398. *
  399. * EXIT
  400. * none
  401. */
  402. void SaveToReg(POEMINFO pOemInfo)
  403. {
  404. DWORD dwDisp;
  405. DWORD dwVersion = REG_CURRENT_OEM_VER;
  406. auto_hkey hkeyOemInfo;
  407. if (NO_ERROR == RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_KEY_OEMINFO, 0, NULL,
  408. REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hkeyOemInfo, &dwDisp))
  409. {
  410. RegSetValueEx(hkeyOemInfo, REGSTR_VAL_MASK, 0, REG_DWORD, (LPBYTE)&(pOemInfo->dwMask), sizeof(pOemInfo->dwMask));
  411. //
  412. // Write the current version so future controls can check version of detection that wrote this key.
  413. // WU RAID # 11921
  414. //
  415. RegSetValueEx(hkeyOemInfo, REGSTR_VAL_OEMINFO_VER, 0, REG_DWORD, (LPBYTE)&dwVersion, sizeof(dwVersion));
  416. if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  417. {
  418. RegSetValueEx(hkeyOemInfo, REGSTR_VAL_INIOEM, 0, REG_SZ,
  419. (LPBYTE)&(pOemInfo->szIniOem), (lstrlen(pOemInfo->szIniOem) + 1) * sizeof(TCHAR));
  420. }
  421. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  422. {
  423. RegSetValueEx(hkeyOemInfo, REGSTR_VAL_WBEMOEM, 0, REG_SZ,
  424. (LPBYTE)&(pOemInfo->szWbemOem),(lstrlen(pOemInfo->szWbemOem) + 1) * sizeof(TCHAR));
  425. RegSetValueEx(hkeyOemInfo, REGSTR_VAL_WBEMPRODUCT, 0, REG_SZ,
  426. (LPBYTE)&(pOemInfo->szWbemProduct), (lstrlen(pOemInfo->szWbemProduct) + 1) * sizeof(TCHAR));
  427. }
  428. }
  429. }