Leaked source code of windows server 2003
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.

1232 lines
31 KiB

  1. /*** findoem.cpp - OEM detection interface
  2. *
  3. * Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * Author: Yan Leshinsky (YanL)
  6. * Created 10/08/98
  7. *
  8. * MODIFICATION HISTORY
  9. * 10/07/2000 waltw Ripped out auto_hkey, auto_hfile, auto_hlib, _com_ptr_t (_COM_SMARTPTR_TYPEDEF),
  10. * bstr_t, variant_t, & exceptions. Converted to generic text mappings
  11. * (Unicode or ANSI compile)
  12. * 11/02/2000 waltw Stub out VxD functions for Unicode builds and ia64 ANSI builds.
  13. */
  14. #define _WIN32_DCOM // so we can attempt to call CoInitializeSecurity
  15. #include <comdef.h>
  16. #include <tchar.h>
  17. #include <windows.h>
  18. #include <objbase.h>
  19. #include <ole2.h>
  20. #include<MISTSAFE.h>
  21. // #define __IUENGINE_USES_ATL_
  22. #if defined(__IUENGINE_USES_ATL_)
  23. #include <atlbase.h>
  24. #define USES_IU_CONVERSION USES_CONVERSION
  25. #else
  26. #include <MemUtil.h>
  27. #endif
  28. #include <logging.h>
  29. #include <iucommon.h>
  30. #include <wuiutest.h>
  31. #include <wbemcli.h>
  32. #include <wubios.h>
  33. #include <osdet.h>
  34. #include <wusafefn.h>
  35. //
  36. // Do we really want a VxD?
  37. //
  38. #if defined(IA64) || defined(_IA64_) || defined(UNICODE) || defined(_UNICODE)
  39. // It's gone...
  40. #define NUKE_VXD 1
  41. #else
  42. // We still have friends on Win9x platforms
  43. #define NUKE_VXD 0
  44. #endif
  45. // hardcodes - not defined in any header
  46. const CLSID CLSID_WbemLocator = {0x4590f811,0x1d3a,0x11d0,{0x89,0x1f,0x00,0xaa,0x00,0x4b,0x2e,0x24}};
  47. #if NUKE_VXD == 0
  48. const TCHAR WUBIOS_VXD_NAME[] = {_T("\\\\.\\WUBIOS.VXD")};
  49. #endif
  50. #define BYTEOF(d,i) (((BYTE *)&(d))[i])
  51. // used in UseVxD()
  52. HINSTANCE g_hinst;
  53. /*** Local function prototypes
  54. */
  55. static void UseOeminfoIni(POEMINFO pOemInfo);
  56. static void UseAcpiReg(POEMINFO pOemInfo);
  57. static void UseWBEM(POEMINFO pOemInfo);
  58. static void UseVxD(POEMINFO pOemInfo);
  59. static bool ReadFromReg(POEMINFO pOemInfo);
  60. static void SaveToReg(POEMINFO pOemInfo);
  61. /*** Registry access
  62. */
  63. static const TCHAR REGSTR_KEY_OEMINFO[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\OemInfo");
  64. static const TCHAR REGSTR_VAL_MASK[] = _T("Mask");
  65. static const TCHAR REGSTR_VAL_ACPIOEM[] = _T("AcpiOem");
  66. static const TCHAR REGSTR_VAL_ACPIPRODUCT[] = _T("AcpiProduct");
  67. static const TCHAR REGSTR_VAL_SMBOEM[] = _T("SmbOem");
  68. static const TCHAR REGSTR_VAL_SMBPRODUCT[] = _T("SmbProduct");
  69. static const TCHAR REGSTR_VAL_PNPOEMID[] = _T("PnpOemId");
  70. static const TCHAR REGSTR_VAL_INIOEM[] = _T("IniOem");
  71. static const TCHAR REGSTR_VAL_WBEMOEM[] = _T("WbemOem");
  72. static const TCHAR REGSTR_VAL_WBEMPRODUCT[] = _T("WbemProduct");
  73. static const TCHAR REGSTR_VAL_OEMINFO_VER[] = _T("OemInfoVersion"); // used to determine if we need to nuke old values
  74. static const TCHAR REGSTR_VAL_SUPPORTURL[] = _T("OemSupportURL");
  75. //
  76. // forward declarations
  77. //
  78. HRESULT GetOemInfo(POEMINFO pOemInfo, bool fAlwaysDetectAndDontSave = false);
  79. BSTR StringID(DWORD dwID);
  80. //
  81. // Increment REG_CURRENT_OEM_VER whenever you need to force override of
  82. // old values written to the OemInfo key. Doesn't need to change for each
  83. // new control version.
  84. //
  85. // History: No version - original controls
  86. // Version 1 - WUV3 when OEM functions first fixed Aug. 2000
  87. // Version 2 - IU control
  88. #define REG_CURRENT_OEM_VER 2
  89. // Based on V3 MakeAndModel
  90. // Note that for OEMINFO_PNP_PRESENT or
  91. // OEMINFO_INI_PRESENT the model BSTR is an empty string.
  92. HRESULT GetOemBstrs(BSTR& bstrManufacturer, BSTR& bstrModel, BSTR& bstrSupportURL)
  93. {
  94. USES_IU_CONVERSION;
  95. LOG_Block("GetOemBstrs");
  96. if(NULL != bstrManufacturer || NULL != bstrModel || NULL != bstrSupportURL)
  97. {
  98. // BSTRs must be NULL on entry
  99. LOG_ErrorMsg(E_INVALIDARG);
  100. return E_INVALIDARG;
  101. }
  102. // Collect all the data possible, but always prefer in the following order
  103. // Win98 WinME NT4 Win2k/WinXP
  104. // -----------------------------------------
  105. // WBEM/WMI 1 1 1 1
  106. // SMBIOS/DMI 3 3 // wubios.vxd
  107. // ACPI 2 2 2 // UseAcpiReg or wubios.vxd
  108. // PNP 4 4 // wubios.vxd
  109. // OEMInfo.ini 5 5 2
  110. //
  111. // Move OEMINFO to heap per Prefast warning 831: GetOemBstrs uses 5792 bytes
  112. // of stack, consider moving some data to heap.
  113. //
  114. POEMINFO pOemInfo = NULL;
  115. HRESULT hr;
  116. pOemInfo = (POEMINFO) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OEMINFO));
  117. if (NULL == pOemInfo)
  118. {
  119. LOG_ErrorMsg(E_OUTOFMEMORY);
  120. return E_OUTOFMEMORY;
  121. }
  122. //
  123. // Fill in the pOemInfo struct.
  124. //
  125. if (SUCCEEDED(hr = GetOemInfo(pOemInfo)))
  126. {
  127. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  128. {
  129. bstrManufacturer = SysAllocString(T2OLE(pOemInfo->szWbemOem));
  130. bstrModel = SysAllocString(T2OLE(pOemInfo->szWbemProduct));
  131. }
  132. // NTRAID#NTBUG9-248906-2000/12/13-waltw IU: Improve OEM detection and reporting.
  133. // prefer SMBIOS over ACPI, and always try to report OEM support URL.
  134. else if (pOemInfo->dwMask & OEMINFO_SMB_PRESENT)
  135. {
  136. bstrManufacturer = SysAllocString(T2OLE(pOemInfo->szSmbOem));
  137. bstrModel = SysAllocString(T2OLE(pOemInfo->szSmbProduct));
  138. }
  139. else if (pOemInfo->dwMask & OEMINFO_ACPI_PRESENT)
  140. {
  141. bstrManufacturer = SysAllocString(T2OLE(pOemInfo->szAcpiOem));
  142. bstrModel = SysAllocString(T2OLE(pOemInfo->szAcpiProduct));
  143. }
  144. else if (pOemInfo->dwMask & OEMINFO_PNP_PRESENT)
  145. {
  146. bstrManufacturer = StringID(pOemInfo->dwPnpOemId);
  147. bstrModel = SysAllocString(T2OLE(_T(""))); // empty BSTR
  148. }
  149. else if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  150. {
  151. bstrManufacturer = SysAllocString(T2OLE(pOemInfo->szIniOem));
  152. bstrModel = SysAllocString(T2OLE(_T(""))); // empty BSTR
  153. }
  154. //
  155. // Always return the OEMSupportURL if available
  156. //
  157. if (0 < lstrlen(pOemInfo->szIniOemSupportUrl))
  158. {
  159. bstrSupportURL = SysAllocString(T2OLE(pOemInfo->szIniOemSupportUrl));
  160. }
  161. else
  162. {
  163. bstrSupportURL = SysAllocString(T2OLE(_T(""))); // empty BSTR
  164. }
  165. //
  166. // Manufacturer and Model are optional (if !pOemInfo->dwMask)
  167. //
  168. if ( (pOemInfo->dwMask && (NULL == bstrManufacturer || NULL == bstrModel)) ||
  169. NULL == bstrSupportURL )
  170. {
  171. SafeSysFreeString(bstrManufacturer);
  172. SafeSysFreeString(bstrModel);
  173. SafeSysFreeString(bstrSupportURL);
  174. LOG_ErrorMsg(E_OUTOFMEMORY);
  175. hr = E_OUTOFMEMORY;
  176. }
  177. }
  178. SafeHeapFree(pOemInfo);
  179. return hr;
  180. }
  181. /*** GetOemInfo - Gather all available machine OEM and model information
  182. *
  183. * ENTRY
  184. * POEMINFO pOemInfo
  185. *
  186. * EXIT
  187. * POEMINFO pOemInfo
  188. * All fields that aren't available will be filled with 0
  189. *
  190. */
  191. HRESULT GetOemInfo(POEMINFO pOemInfo, bool fAlwaysDetectAndDontSave /*= false*/)
  192. {
  193. LOG_Block("GetOemInfo");
  194. HRESULT hr;
  195. if (!pOemInfo)
  196. {
  197. LOG_Error(_T("E_INVALIDARG"));
  198. SetHrAndGotoCleanUp(E_INVALIDARG);
  199. }
  200. // Worst case:
  201. ZeroMemory(pOemInfo, sizeof(OEMINFO));
  202. // Do detection if necessary or requested
  203. if (fAlwaysDetectAndDontSave || ! ReadFromReg(pOemInfo))
  204. {
  205. //
  206. // Always attempt to get strings from oeminfo.ini, if present
  207. //
  208. UseOeminfoIni(pOemInfo);
  209. OSVERSIONINFO osvi;
  210. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  211. if (GetVersionEx(&osvi))
  212. {
  213. if (VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId)
  214. {
  215. UseWBEM(pOemInfo);
  216. UseVxD(pOemInfo);
  217. }
  218. else if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)
  219. {
  220. if (4 < osvi.dwMajorVersion)
  221. {
  222. // Win2k and higher
  223. UseWBEM(pOemInfo);
  224. UseAcpiReg(pOemInfo);
  225. }
  226. else
  227. {
  228. UseWBEM(pOemInfo);
  229. }
  230. }
  231. // Save info to the registry
  232. if (!fAlwaysDetectAndDontSave)
  233. {
  234. SaveToReg(pOemInfo);
  235. }
  236. }
  237. else
  238. {
  239. LOG_Driver(_T("GetVersionEx:"));
  240. Win32MsgSetHrGotoCleanup(GetLastError());
  241. }
  242. }
  243. //
  244. // Manufacturer and Model are now optional (RAID#337879 IU: can't get latest IU controls
  245. // to work with IU site) so it is OK to return with no information
  246. //
  247. return S_OK;
  248. CleanUp:
  249. //
  250. // Only used for returning errors
  251. //
  252. return hr;
  253. }
  254. /***LP StringID - convert numeric ID to string ID
  255. *
  256. * ENTRY
  257. * dwID - numeric PnP ID
  258. *
  259. * EXIT
  260. * returns string ID
  261. */
  262. BSTR StringID(DWORD dwID)
  263. {
  264. LOG_Block("StringID");
  265. USES_IU_CONVERSION;
  266. TCHAR szID[8];
  267. WORD wVenID;
  268. int i;
  269. wVenID = (WORD)(((dwID & 0x00ff) << 8) | ((dwID & 0xff00) >> 8));
  270. wVenID <<= 1;
  271. for (i = 0; i < 3; ++i)
  272. {
  273. szID[i] = (TCHAR)(((wVenID & 0xf800) >> 11) + 0x40);
  274. wVenID <<= 5;
  275. }
  276. wVenID = HIWORD(dwID);
  277. wVenID = (WORD)(((wVenID & 0x00ff) << 8) | ((wVenID & 0xff00) >> 8));
  278. for (i = 6; i > 2; --i)
  279. {
  280. szID[i] = (TCHAR)(wVenID & 0x000F);
  281. if(szID[i] > 9)
  282. {
  283. szID[i] += 0x37; // 'A' - 0xA for digits A to F
  284. }
  285. else
  286. {
  287. szID[i] += 0x30; // '0' for digits 0 to 9
  288. }
  289. wVenID >>= 4;
  290. }
  291. return SysAllocString(T2OLE(szID));
  292. } //StringID
  293. /*** UseOeminfoIni - get OemInfo from OEMINFO.INI
  294. *
  295. * ENTRY
  296. * POEMINFO pOemInfo
  297. *
  298. * EXIT
  299. * POEMINFO pOemInfo
  300. * All fields that aren't available will be filled with 0
  301. * returns NULL
  302. */
  303. void UseOeminfoIni(POEMINFO pOemInfo)
  304. {
  305. LOG_Block("UseOeminfoIni");
  306. static const TCHAR szFile[] = _T("OEMINFO.INI");
  307. static const TCHAR szSection[] = _T("General");
  308. static const TCHAR szKey[] = _T("Manufacturer");
  309. static const TCHAR szSupportURL[] = _T("SupportURL");
  310. HRESULT hr=S_OK;
  311. TCHAR szPath[MAX_PATH + 1];
  312. // OEMINFO.INI is in system directory
  313. if (GetSystemDirectory(szPath, ARRAYSIZE(szPath)) > 0)
  314. {
  315. hr=PathCchAppend(szPath,ARRAYSIZE(szPath),szFile);
  316. if(FAILED(hr))
  317. {
  318. LOG_ErrorMsg(HRESULT_CODE(hr));
  319. return;
  320. }
  321. GetPrivateProfileString(szSection, szKey, _T(""),
  322. pOemInfo->szIniOem, ARRAYSIZE(pOemInfo->szIniOem), szPath);
  323. if (lstrlen(pOemInfo->szIniOem))
  324. {
  325. pOemInfo->dwMask |= OEMINFO_INI_PRESENT;
  326. LOG_Driver(_T("Set OEMINFO_INI_PRESENT bit"));
  327. }
  328. //
  329. // We'll use szIniOemSupportUrl any time we can get it, but don't need to set flag
  330. //
  331. GetPrivateProfileString(szSection, szSupportURL, _T(""),
  332. pOemInfo->szIniOemSupportUrl, ARRAYSIZE(pOemInfo->szIniOemSupportUrl), szPath);
  333. }
  334. }
  335. /*** UseAcpiReg - get OemInfo from the registry
  336. *
  337. * Structure of the registry will be:
  338. * HKEY_LOCAL_MACHINE\Hardware\ACPI\<TableSig>\<OEMID>\<TableID>\<TableRev>
  339. *
  340. * ENTRY
  341. * POEMINFO pOemInfo
  342. *
  343. * EXIT
  344. * POEMINFO pOemInfo
  345. * All fields that aren't available will be filled with 0
  346. * returns NULL
  347. */
  348. void UseAcpiReg(POEMINFO pOemInfo)
  349. {
  350. LOG_Block("UseAcpiReg");
  351. static const TCHAR szRSDT[] = _T("Hardware\\ACPI\\DSDT");
  352. HKEY hKeyTable;
  353. LONG lRet;
  354. if (NO_ERROR ==(lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRSDT, 0, MAXIMUM_ALLOWED, &hKeyTable)))
  355. {
  356. if (NO_ERROR == (lRet = RegEnumKey(hKeyTable, 0, pOemInfo->szAcpiOem, sizeof(pOemInfo->szAcpiOem)/sizeof(TCHAR))))
  357. {
  358. HKEY hKeyOEM;
  359. if (NO_ERROR == (lRet = RegOpenKeyEx(hKeyTable, pOemInfo->szAcpiOem, 0, MAXIMUM_ALLOWED, &hKeyOEM)))
  360. {
  361. if (NO_ERROR == (lRet = RegEnumKey(hKeyOEM, 0, pOemInfo->szAcpiProduct, sizeof(pOemInfo->szAcpiProduct)/sizeof(TCHAR))))
  362. {
  363. pOemInfo->dwMask |= OEMINFO_ACPI_PRESENT;
  364. LOG_Driver(_T("Set OEMINFO_ACPI_PRESENT bit"));
  365. }
  366. else
  367. {
  368. LOG_Error(_T("RegEnumKey:"));
  369. LOG_ErrorMsg(lRet);
  370. }
  371. RegCloseKey(hKeyOEM);
  372. }
  373. else
  374. {
  375. LOG_Error(_T("RegOpenKeyEx:"));
  376. LOG_ErrorMsg(lRet);
  377. }
  378. }
  379. else
  380. {
  381. LOG_Error(_T("RegEnumKey:"));
  382. LOG_ErrorMsg(lRet);
  383. }
  384. RegCloseKey(hKeyTable);
  385. }
  386. else
  387. {
  388. LOG_Error(_T("RegOpenKeyEx:"));
  389. LOG_ErrorMsg(lRet);
  390. }
  391. }
  392. /*** UseWBEM - Get info through WBEM access
  393. *
  394. * ENTRY
  395. * POEMINFO pOemInfo
  396. *
  397. * EXIT
  398. * POEMINFO pOemInfo
  399. * All fields that aren't available will be filled with 0
  400. * returns NULL
  401. */
  402. void UseWBEM(POEMINFO pOemInfo)
  403. {
  404. LOG_Block("UseWBEM");
  405. USES_IU_CONVERSION;
  406. IWbemLocator* pWbemLocator = NULL;
  407. IWbemServices* pWbemServices = NULL;
  408. IEnumWbemClassObject* pEnum = NULL;
  409. IWbemClassObject* pObject = NULL;
  410. BSTR bstrNetworkResource = NULL;
  411. BSTR bstrComputerSystem = NULL;
  412. VARIANT var;
  413. VariantInit(&var);
  414. HRESULT hr;
  415. if (NULL == pOemInfo)
  416. return;
  417. // Create Locator
  418. if (FAILED(hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*) &pWbemLocator)))
  419. {
  420. LOG_Error(_T("CoCreateInstance returned 0x%08x in UseWBEM"), hr);
  421. goto CleanUp;
  422. }
  423. // Get services
  424. if (bstrNetworkResource = SysAllocString(L"\\\\.\\root\\cimv2"))
  425. {
  426. if (FAILED(pWbemLocator->ConnectServer(bstrNetworkResource, NULL, NULL, 0L, 0L, NULL, NULL, &pWbemServices)))
  427. {
  428. LOG_Error(_T("pWbemLocator->ConnectServer returned 0x%08x in UseWBEM"), hr);
  429. goto CleanUp;
  430. }
  431. if (FAILED(hr = CoSetProxyBlanket(pWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  432. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)))
  433. {
  434. LOG_Error(_T("CoSetProxyBlanket returned 0x%08x in UseWBEM"), hr);
  435. goto CleanUp;
  436. }
  437. // Create enumerator
  438. if (bstrComputerSystem = SysAllocString(L"Win32_ComputerSystem"))
  439. {
  440. if (FAILED(hr = pWbemServices->CreateInstanceEnum(bstrComputerSystem, 0, NULL, &pEnum)))
  441. {
  442. goto CleanUp;
  443. }
  444. if (FAILED(CoSetProxyBlanket(pEnum, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  445. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)))
  446. {
  447. goto CleanUp;
  448. }
  449. // Get our object now
  450. ULONG uReturned = 1;
  451. hr = pEnum->Next(
  452. 6000, // timeout in six seconds
  453. 1, // return just one storage device
  454. &pObject, // pointer to storage device
  455. &uReturned); // number obtained: one or zero
  456. //
  457. // 569939 Need to verify IEnumWbemClassObject::Next uReturned value
  458. //
  459. if (FAILED(hr) || 0 == uReturned || NULL == pObject)
  460. {
  461. goto CleanUp;
  462. }
  463. if (FAILED(hr = pObject->Get(L"Manufacturer", 0L, &var, NULL, NULL)))
  464. {
  465. goto CleanUp;
  466. }
  467. if (VT_BSTR == var.vt)
  468. {
  469. lstrcpyn(pOemInfo->szWbemOem, OLE2T(var.bstrVal), ARRAYSIZE(pOemInfo->szWbemOem));
  470. }
  471. //
  472. // 569968 Call VariantClear before line 549 to prevent leak of BSTR
  473. //
  474. VariantClear(&var);
  475. if (FAILED(hr = pObject->Get(L"Model", 0L, &var, NULL, NULL)))
  476. {
  477. goto CleanUp;
  478. }
  479. if (VT_BSTR == var.vt)
  480. {
  481. lstrcpyn(pOemInfo->szWbemProduct, OLE2T(var.bstrVal), ARRAYSIZE(pOemInfo->szWbemProduct));
  482. }
  483. if (0 != lstrlen(pOemInfo->szWbemOem) || 0 != lstrlen(pOemInfo->szWbemProduct))
  484. {
  485. pOemInfo->dwMask |= OEMINFO_WBEM_PRESENT;
  486. LOG_Driver(_T("Set OEMINFO_WBEM_PRESENT"));
  487. }
  488. }
  489. else
  490. {
  491. LOG_Error(_T("SysAllocString failed in UseWBEM"));
  492. }
  493. }
  494. CleanUp:
  495. SafeReleaseNULL(pWbemLocator);
  496. SafeReleaseNULL(pWbemServices);
  497. SafeReleaseNULL(pEnum);
  498. SafeReleaseNULL(pObject);
  499. SysFreeString(bstrNetworkResource);
  500. SysFreeString(bstrComputerSystem);
  501. if (VT_EMPTY != var.vt)
  502. VariantClear(&var);
  503. return;
  504. }
  505. /*** Calls to wubios.vxd
  506. */
  507. class CWubiosVxD
  508. {
  509. public:
  510. bool Init(HMODULE hModuleGlobal);
  511. PBYTE GetAcpiTable(DWORD dwTabSig);
  512. PBYTE GetSmbTable(DWORD dwTableType);
  513. DWORD GetPnpOemId();
  514. CWubiosVxD();
  515. ~CWubiosVxD();
  516. private:
  517. HANDLE m_hVxD;
  518. TCHAR m_szVxdPath[MAX_PATH + 1];
  519. };
  520. CWubiosVxD::CWubiosVxD()
  521. {
  522. LOG_Block("CWubiosVxD::CWubiosVxD");
  523. m_hVxD = INVALID_HANDLE_VALUE;
  524. m_szVxdPath[0] = _T('\0');
  525. }
  526. CWubiosVxD::~CWubiosVxD()
  527. {
  528. LOG_Block("CWubiosVxD::~CWubiosVxD");
  529. if (INVALID_HANDLE_VALUE != m_hVxD)
  530. {
  531. CloseHandle(m_hVxD);
  532. }
  533. if (0 != lstrlen(m_szVxdPath))
  534. {
  535. DeleteFile(m_szVxdPath);
  536. }
  537. }
  538. /***LP CWubiosVxD::Init - Loads VxD
  539. *
  540. * ENTRY
  541. * none
  542. *
  543. * EXIT
  544. * path
  545. */
  546. bool CWubiosVxD::Init(HMODULE hModuleGlobal)
  547. {
  548. LOG_Block("CWubiosVxD::Init");
  549. #if NUKE_VXD == 1
  550. LOG_Error(_T("Not supported"));
  551. return false;
  552. #else
  553. bool fRet = false;
  554. HMODULE hModule = NULL;
  555. HRSRC hrscVxd = 0;
  556. HGLOBAL hRes = 0;
  557. PBYTE pImage = NULL;
  558. DWORD dwResSize = 0;
  559. DWORD dwWritten = 0;
  560. DWORD dwVersion = ~WUBIOS_VERSION;
  561. HANDLE hfile = INVALID_HANDLE_VALUE;
  562. TCHAR szMyFileName[MAX_PATH + 1];
  563. HRESULT hr=S_OK;
  564. // Init
  565. if (0 == GetSystemDirectory(m_szVxdPath, ARRAYSIZE(m_szVxdPath)))
  566. {
  567. LOG_ErrorMsg(GetLastError());
  568. goto CleanUp;
  569. }
  570. hr=PathCchAppend(m_szVxdPath,ARRAYSIZE(m_szVxdPath),_T("\\wubios.vxd"));
  571. if(FAILED(hr))
  572. {
  573. LOG_ErrorMsg(HRESULT_CODE(hr));
  574. goto CleanUp;
  575. }
  576. if (0 == GetModuleFileName(hModuleGlobal, szMyFileName, ARRAYSIZE(szMyFileName)))
  577. {
  578. LOG_ErrorMsg(GetLastError());
  579. goto CleanUp;
  580. }
  581. hModule = LoadLibraryEx(szMyFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
  582. if (INVALID_HANDLE_VALUE == hModule)
  583. {
  584. LOG_ErrorMsg(GetLastError());
  585. goto CleanUp;
  586. }
  587. // Get Vxd from resource and save it
  588. hrscVxd = FindResource(hModule, _T("WUBIOS"), RT_VXD);
  589. if (0 == hrscVxd)
  590. {
  591. LOG_ErrorMsg(GetLastError());
  592. goto CleanUp;
  593. }
  594. if (0 == (hRes = LoadResource(hModule, hrscVxd)))
  595. {
  596. LOG_ErrorMsg(GetLastError());
  597. goto CleanUp;
  598. }
  599. pImage = (PBYTE) LockResource(hRes);
  600. if (NULL == pImage)
  601. {
  602. LOG_Error(_T("LockResource failed"));
  603. goto CleanUp;
  604. }
  605. dwResSize = SizeofResource(hModule, hrscVxd);
  606. if (0 == dwResSize)
  607. {
  608. LOG_ErrorMsg(GetLastError());
  609. goto CleanUp;
  610. }
  611. hfile = CreateFile(m_szVxdPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  612. if (INVALID_HANDLE_VALUE == hfile)
  613. {
  614. LOG_ErrorMsg(GetLastError());
  615. goto CleanUp;
  616. }
  617. else
  618. {
  619. LOG_Driver(_T("Success: CreateFile \"%s\""), m_szVxdPath);
  620. }
  621. if (0 == WriteFile(hfile, pImage, dwResSize, &dwWritten, NULL))
  622. {
  623. LOG_ErrorMsg(GetLastError());
  624. goto CleanUp;
  625. }
  626. if (0 == CloseHandle(hfile))
  627. {
  628. LOG_ErrorMsg(GetLastError());
  629. goto CleanUp;
  630. }
  631. hfile = INVALID_HANDLE_VALUE;
  632. if (dwWritten != dwResSize)
  633. {
  634. LOG_Error(_T("WriteFile wrote %d bytes to \"%s\", should be %d"), dwWritten, m_szVxdPath, dwResSize);
  635. goto CleanUp;
  636. }
  637. // Load Vxd
  638. if (INVALID_HANDLE_VALUE != (m_hVxD = CreateFile(WUBIOS_VXD_NAME, 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL)))
  639. {
  640. // Check version
  641. if (DeviceIoControl(m_hVxD, WUBIOCTL_GET_VERSION, NULL, 0, &dwVersion, sizeof(dwVersion), NULL, NULL))
  642. {
  643. if (dwVersion == WUBIOS_VERSION)
  644. {
  645. fRet = true;
  646. }
  647. else
  648. {
  649. LOG_Error(_T("Wrong VxD Version"));
  650. CloseHandle(m_hVxD);
  651. m_hVxD = INVALID_HANDLE_VALUE;
  652. goto CleanUp;
  653. }
  654. }
  655. else
  656. {
  657. LOG_ErrorMsg(GetLastError());
  658. goto CleanUp;
  659. }
  660. }
  661. else
  662. {
  663. LOG_ErrorMsg(GetLastError());
  664. goto CleanUp;
  665. }
  666. CleanUp:
  667. if (INVALID_HANDLE_VALUE != hfile)
  668. CloseHandle(hfile);
  669. if (hModule)
  670. FreeLibrary(hModule);
  671. return fRet;
  672. #endif // NUKE_VXD
  673. }
  674. /***LP CWubiosVxD::GetAcpiTable - Get table
  675. *
  676. * ENTRY
  677. * m_hVxD - VxD handle
  678. * dwTabSig - table signature
  679. *
  680. * EXIT-SUCCESS
  681. * returns pointer to table
  682. * EXIT-FAILURE
  683. * returns NULL
  684. */
  685. PBYTE CWubiosVxD::GetAcpiTable(DWORD dwTabSig)
  686. {
  687. LOG_Block("CWubiosVxD::GetAcpiTable");
  688. PBYTE pb = NULL;
  689. #if NUKE_VXD == 1
  690. LOG_Error(_T("Not supported"));
  691. #else
  692. ACPITABINFO TabInfo;
  693. TabInfo.dwTabSig = dwTabSig;
  694. if (INVALID_HANDLE_VALUE == m_hVxD)
  695. {
  696. LOG_Error(_T("INVALID_HANDLE_VALUE == m_hVxD"));
  697. return NULL;
  698. }
  699. if (DeviceIoControl(m_hVxD, WUBIOCTL_GET_ACPI_TABINFO, NULL, 0, &TabInfo, sizeof(TabInfo), NULL, NULL))
  700. {
  701. if (pb = (PBYTE) HeapAlloc(GetProcessHeap(), 0, TabInfo.dh.Length))
  702. {
  703. if (0 == DeviceIoControl(m_hVxD, WUBIOCTL_GET_ACPI_TABLE,
  704. (PVOID)TabInfo.dwPhyAddr, 0, pb,TabInfo.dh.Length, NULL, NULL))
  705. {
  706. SafeHeapFree(pb);
  707. LOG_Error(_T("Second DeviceIoControl:"));
  708. LOG_ErrorMsg(GetLastError());
  709. return NULL;
  710. }
  711. }
  712. else
  713. {
  714. LOG_ErrorMsg(E_OUTOFMEMORY);
  715. }
  716. }
  717. else
  718. {
  719. LOG_Error(_T("First DeviceIoControl:"));
  720. LOG_ErrorMsg(GetLastError());
  721. }
  722. #endif // NUKE_VXD
  723. return pb;
  724. }//GetAcpiTable
  725. /***LP CWubiosVxD::GetSmbTable - Get table
  726. *
  727. * ENTRY
  728. * dwTableType - table type
  729. *
  730. * EXIT-SUCCESS
  731. * returns pointer to table
  732. * EXIT-FAILURE
  733. * returns NULL
  734. */
  735. PBYTE CWubiosVxD::GetSmbTable(DWORD dwTableType)
  736. {
  737. LOG_Block("CWubiosVxD::GetSmbTable");
  738. PBYTE pb = NULL;
  739. #if NUKE_VXD == 1
  740. LOG_Error(_T("Not supported"));
  741. #else
  742. if (INVALID_HANDLE_VALUE == m_hVxD)
  743. {
  744. LOG_Error(_T("m_hVxD invalid"));
  745. return NULL;
  746. }
  747. DWORD dwMaxSize = 0;
  748. if (DeviceIoControl(m_hVxD, WUBIOCTL_GET_SMB_STRUCTSIZE, NULL, 0, &dwMaxSize, sizeof(dwMaxSize), NULL, NULL) && dwMaxSize)
  749. {
  750. if (pb = (PBYTE) HeapAlloc(GetProcessHeap(), 0, dwMaxSize))
  751. {
  752. if (0 == DeviceIoControl(m_hVxD, WUBIOCTL_GET_SMB_STRUCT,
  753. (PVOID)dwTableType, 0, pb, dwMaxSize, NULL, NULL))
  754. {
  755. SafeHeapFree(pb);
  756. LOG_Error(_T("Second DeviceIoControl:"));
  757. LOG_ErrorMsg(GetLastError());
  758. return NULL;
  759. }
  760. }
  761. else
  762. {
  763. LOG_Error(_T("HeapAlloc failed"));
  764. }
  765. }
  766. else
  767. {
  768. LOG_Error(_T("First DeviceIoControl:"));
  769. LOG_ErrorMsg(GetLastError());
  770. }
  771. #endif // NUKE_VXD
  772. return pb;
  773. }// GetSmbTable
  774. /***LP CWubiosVxD::GetPnpOemId - Do it
  775. *
  776. * ENTRY
  777. * none
  778. *
  779. * EXIT
  780. * path
  781. */
  782. DWORD CWubiosVxD::GetPnpOemId()
  783. {
  784. LOG_Block("CWubiosVxD::GetPnpOemId");
  785. #if NUKE_VXD == 1
  786. LOG_Error(_T("Not supported"));
  787. return 0;
  788. #else
  789. // PnP last
  790. DWORD dwOemId = 0;
  791. if (INVALID_HANDLE_VALUE == m_hVxD)
  792. {
  793. LOG_Error(_T("m_hVxD invalid"));
  794. return 0;
  795. }
  796. if (0 == DeviceIoControl(m_hVxD, WUBIOCTL_GET_PNP_OEMID, NULL, 0,
  797. &dwOemId, sizeof(dwOemId), NULL, NULL))
  798. {
  799. // make sure it didn't mess with the size on error
  800. dwOemId = 0;
  801. LOG_Error(_T("DeviceIoControl:"));
  802. LOG_ErrorMsg(GetLastError());
  803. }
  804. return dwOemId;
  805. #endif // NUKE_VXD
  806. }
  807. /*** UseVxD - Get bios info from it
  808. *
  809. * ENTRY
  810. * POEMINFO pOemInfo
  811. *
  812. * EXIT
  813. * POEMINFO pOemInfo
  814. * All fields that aren't available will be filled with 0
  815. * returns NULL
  816. */
  817. void UseVxD(POEMINFO pOemInfo)
  818. {
  819. HRESULT hr=S_OK;
  820. LOG_Block("CWubiosVxD::UseVxD");
  821. #if NUKE_VXD == 1
  822. LOG_Error(_T("Not supported"));
  823. return;
  824. #else
  825. USES_IU_CONVERSION;
  826. CWubiosVxD vxd;
  827. if(false == vxd.Init(g_hinst))
  828. return;
  829. // ISSUE-2000/10/10-waltw I don't have a machine to test vxd.GetAcpiTable on...
  830. // ACPI first
  831. PDESCRIPTION_HEADER pHeader = (PDESCRIPTION_HEADER)vxd.GetAcpiTable(DSDT_SIGNATURE);
  832. if (NULL != pHeader)
  833. {
  834. memcpy(pOemInfo->szAcpiOem, pHeader->OEMID, sizeof(pHeader->OEMID));
  835. memcpy(pOemInfo->szAcpiProduct, pHeader->OEMTableID, sizeof(pHeader->OEMTableID));
  836. HeapFree(GetProcessHeap(), 0, pHeader);
  837. pOemInfo->dwMask |= OEMINFO_ACPI_PRESENT;
  838. LOG_Driver(_T("Set OEMINFO_ACPI_PRESENT bit"));
  839. }
  840. // SMBIOS second
  841. PSMBIOSSYSINFO pTable = (PSMBIOSSYSINFO)vxd.GetSmbTable(SMBIOS_SYSTEM_INFO_TABLE);
  842. if (NULL != pTable)
  843. {
  844. // Search counter
  845. int cnStrs = max(pTable->bManufacturer, pTable->bProductName);
  846. char* sz = (char*)pTable + pTable->bLength;
  847. for (int i = 1; i <= cnStrs && sz; i ++)
  848. {
  849. if (pTable->bManufacturer == i)
  850. {
  851. hr=StringCchCopyEx(pOemInfo->szSmbOem,ARRAYSIZE(pOemInfo->szSmbOem),A2T(sz),NULL,NULL,MISTSAFE_STRING_FLAGS);
  852. if(FAILED(hr))
  853. {
  854. LOG_ErrorMsg(HRESULT_CODE(hr));
  855. return;
  856. }
  857. }
  858. else if (pTable->bProductName == i)
  859. {
  860. hr=StringCchCopyEx(pOemInfo->szSmbProduct,ARRAYSIZE(pOemInfo->szSmbProduct),A2T(sz),NULL,NULL,MISTSAFE_STRING_FLAGS);
  861. if(FAILED(hr))
  862. {
  863. LOG_ErrorMsg(HRESULT_CODE(hr));
  864. return;
  865. }
  866. }
  867. sz += strlen(sz) + 1;
  868. }
  869. pOemInfo->dwMask |= OEMINFO_SMB_PRESENT;
  870. SafeHeapFree(pTable);
  871. LOG_Driver(_T("Set OEMINFO_SMB_PRESENT bit"));
  872. }
  873. // ISSUE-2000/10/10-waltw I don't have a machine to test vxd.GetPnpOemId on...
  874. // PnP last
  875. pOemInfo->dwPnpOemId = vxd.GetPnpOemId();
  876. if (pOemInfo->dwPnpOemId != 0)
  877. {
  878. pOemInfo->dwMask |= OEMINFO_PNP_PRESENT;
  879. LOG_Driver(_T("Set OEMINFO_PNP_PRESENT bit"));
  880. }
  881. #endif // NUKE_VXD
  882. }
  883. /*** ReadFromReg - read OEMINFO from registry
  884. *
  885. * ENTRY
  886. * POEMINFO pOemInfo
  887. *
  888. * EXIT
  889. * true if info is present
  890. * false otherwise
  891. */
  892. bool ReadFromReg(POEMINFO pOemInfo)
  893. {
  894. LOG_Block("ReadFromReg");
  895. DWORD dwVersion = 0;
  896. bool fReturn = false;
  897. bool fRegKeyOpened = false;
  898. LONG lReg;
  899. //read registry first
  900. HKEY hKeyOemInfo;
  901. HRESULT hr;
  902. int cchValueSize;
  903. if (NULL == pOemInfo)
  904. {
  905. return false;
  906. }
  907. if (NO_ERROR == (lReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_KEY_OEMINFO, 0, KEY_READ, &hKeyOemInfo)))
  908. {
  909. fRegKeyOpened = true;
  910. DWORD dwCount = sizeof(pOemInfo->dwMask);
  911. if (ERROR_SUCCESS != RegQueryValueEx(hKeyOemInfo, REGSTR_VAL_MASK, 0, 0, (LPBYTE)&(pOemInfo->dwMask), &dwCount))
  912. {
  913. goto CleanUp;
  914. }
  915. //
  916. // ***** WU Bug# 11921 *****
  917. //
  918. //
  919. // No bits set requires detection
  920. //
  921. if(!pOemInfo->dwMask)
  922. {
  923. LOG_Error(_T("No pOemInfo->dwMask bits set in ReadFromReg"));
  924. goto CleanUp;
  925. }
  926. //
  927. // If an older version of the detection wrote the OemInfo return false to force detection.
  928. // This value is written starting with 1 around August 2000 for the Classic control.
  929. //
  930. dwCount = sizeof(dwVersion);
  931. if (NO_ERROR == (lReg = RegQueryValueEx(hKeyOemInfo, REGSTR_VAL_OEMINFO_VER, 0, 0, (LPBYTE)&dwVersion, &dwCount)))
  932. {
  933. if(REG_CURRENT_OEM_VER > dwVersion)
  934. {
  935. LOG_Error(_T("REG_CURRENT_OEM_VER > %lu in Registry"), dwVersion);
  936. goto CleanUp;
  937. }
  938. }
  939. else
  940. {
  941. Win32MsgSetHrGotoCleanup(lReg);
  942. }
  943. //
  944. // ***** end WU Bug *****
  945. //
  946. if (pOemInfo->dwMask & OEMINFO_ACPI_PRESENT)
  947. {
  948. cchValueSize = ARRAYSIZE(pOemInfo->szAcpiOem);
  949. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_ACPIOEM, pOemInfo->szAcpiOem, cchValueSize, &cchValueSize));
  950. cchValueSize = ARRAYSIZE(pOemInfo->szAcpiProduct);
  951. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_ACPIPRODUCT, pOemInfo->szAcpiProduct, cchValueSize, &cchValueSize));
  952. }
  953. if (pOemInfo->dwMask & OEMINFO_SMB_PRESENT)
  954. {
  955. cchValueSize = ARRAYSIZE(pOemInfo->szSmbOem);
  956. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_SMBOEM, pOemInfo->szSmbOem, cchValueSize, &cchValueSize));
  957. cchValueSize = ARRAYSIZE(pOemInfo->szSmbProduct);
  958. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_SMBPRODUCT, pOemInfo->szSmbProduct, cchValueSize, &cchValueSize));
  959. }
  960. if (pOemInfo->dwMask & OEMINFO_PNP_PRESENT)
  961. {
  962. dwCount = sizeof(pOemInfo->dwPnpOemId);
  963. if (NO_ERROR != (lReg = RegQueryValueEx(hKeyOemInfo, REGSTR_VAL_PNPOEMID, 0, 0, (LPBYTE)&(pOemInfo->dwPnpOemId), &dwCount)))
  964. goto CleanUp;
  965. }
  966. if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  967. {
  968. cchValueSize = ARRAYSIZE(pOemInfo->szIniOem);
  969. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_INIOEM, pOemInfo->szIniOem, cchValueSize, &cchValueSize));
  970. }
  971. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  972. {
  973. cchValueSize = ARRAYSIZE(pOemInfo->szWbemOem);
  974. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_WBEMOEM, pOemInfo->szWbemOem, cchValueSize, &cchValueSize));
  975. cchValueSize = ARRAYSIZE(pOemInfo->szWbemProduct);
  976. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_WBEMPRODUCT, pOemInfo->szWbemProduct, cchValueSize, &cchValueSize));
  977. }
  978. //
  979. // Always try to get the OEM Support URL, but don't bail if we don't have it.
  980. //
  981. cchValueSize = ARRAYSIZE(pOemInfo->szIniOemSupportUrl);
  982. (void) SafeRegQueryStringValueCch(hKeyOemInfo, REGSTR_VAL_SUPPORTURL, pOemInfo->szIniOemSupportUrl, cchValueSize, &cchValueSize);
  983. //
  984. // We got everything we had a dwMask bit set for - drop through to CleanUp
  985. //
  986. fReturn = true;
  987. }
  988. else
  989. {
  990. LOG_ErrorMsg(lReg);
  991. goto CleanUp;
  992. }
  993. CleanUp:
  994. if (true == fRegKeyOpened)
  995. {
  996. RegCloseKey(hKeyOemInfo);
  997. }
  998. return fReturn;
  999. }
  1000. /*** SaveToReg - Save OEMINFO
  1001. *
  1002. * ENTRY
  1003. * POEMINFO pOemInfo
  1004. *
  1005. * EXIT
  1006. * none
  1007. */
  1008. void SaveToReg(POEMINFO pOemInfo)
  1009. {
  1010. LOG_Block("SaveToReg");
  1011. DWORD dwDisp;
  1012. DWORD dwVersion = REG_CURRENT_OEM_VER;
  1013. LONG lReg;
  1014. HKEY hKey;
  1015. //
  1016. // Nuke the existing key (it has no subkeys)
  1017. //
  1018. if (NO_ERROR != (lReg = RegDeleteKey(HKEY_LOCAL_MACHINE, REGSTR_KEY_OEMINFO)))
  1019. {
  1020. //
  1021. // Log error but don't bail - it may not have existed before
  1022. //
  1023. LOG_Driver(_T("Optional RegDeleteKey:"));
  1024. LOG_ErrorMsg(lReg);
  1025. }
  1026. if (NO_ERROR == (lReg = RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_KEY_OEMINFO, 0, NULL,
  1027. REG_OPTION_NON_VOLATILE, KEY_WRITE, 0, &hKey, &dwDisp)))
  1028. {
  1029. //
  1030. // Ignore errors from RegSetValueEx - we check for errors in ReadFromReg
  1031. //
  1032. RegSetValueEx(hKey, REGSTR_VAL_MASK, 0, REG_DWORD, (LPBYTE)&(pOemInfo->dwMask), sizeof(pOemInfo->dwMask));
  1033. //
  1034. // Write the current version so future controls can check version of detection that wrote this key.
  1035. // WU RAID # 11921
  1036. //
  1037. RegSetValueEx(hKey, REGSTR_VAL_OEMINFO_VER, 0, REG_DWORD, (LPBYTE)&dwVersion, sizeof(dwVersion));
  1038. if (pOemInfo->dwMask & OEMINFO_ACPI_PRESENT)
  1039. {
  1040. RegSetValueEx(hKey, REGSTR_VAL_ACPIOEM, 0, REG_SZ, (LPBYTE)&(pOemInfo->szAcpiOem), (lstrlen(pOemInfo->szAcpiOem) + 1) * sizeof(TCHAR));
  1041. RegSetValueEx(hKey, REGSTR_VAL_ACPIPRODUCT, 0, REG_SZ, (LPBYTE)&(pOemInfo->szAcpiProduct), (lstrlen(pOemInfo->szAcpiProduct) + 1) * sizeof(TCHAR));
  1042. }
  1043. if (pOemInfo->dwMask & OEMINFO_SMB_PRESENT)
  1044. {
  1045. RegSetValueEx(hKey, REGSTR_VAL_SMBOEM, 0, REG_SZ, (LPBYTE)&(pOemInfo->szSmbOem), (lstrlen(pOemInfo->szSmbOem) + 1) * sizeof(TCHAR));
  1046. RegSetValueEx(hKey, REGSTR_VAL_SMBPRODUCT, 0, REG_SZ, (LPBYTE)&(pOemInfo->szSmbProduct), (lstrlen(pOemInfo->szSmbProduct) + 1) * sizeof(TCHAR));
  1047. }
  1048. if (pOemInfo->dwMask & OEMINFO_PNP_PRESENT)
  1049. {
  1050. RegSetValueEx(hKey, REGSTR_VAL_PNPOEMID, 0, REG_DWORD, (LPBYTE)&(pOemInfo->dwPnpOemId), sizeof(pOemInfo->dwPnpOemId));
  1051. }
  1052. if (pOemInfo->dwMask & OEMINFO_INI_PRESENT)
  1053. {
  1054. RegSetValueEx(hKey, REGSTR_VAL_INIOEM, 0, REG_SZ, (LPBYTE)&(pOemInfo->szIniOem), (lstrlen(pOemInfo->szIniOem) + 1) * sizeof(TCHAR));
  1055. }
  1056. if (pOemInfo->dwMask & OEMINFO_WBEM_PRESENT)
  1057. {
  1058. RegSetValueEx(hKey, REGSTR_VAL_WBEMOEM, 0, REG_SZ, (LPBYTE)&(pOemInfo->szWbemOem), (lstrlen(pOemInfo->szWbemOem) + 1) * sizeof(TCHAR));
  1059. RegSetValueEx(hKey, REGSTR_VAL_WBEMPRODUCT, 0, REG_SZ, (LPBYTE)&(pOemInfo->szWbemProduct), (lstrlen(pOemInfo->szWbemProduct) + 1) * sizeof(TCHAR));
  1060. }
  1061. //
  1062. // Always save REGSTR_VAL_SUPPORTURL if we have it
  1063. //
  1064. int nUrlLen = lstrlen(pOemInfo->szIniOemSupportUrl);
  1065. if (0 < nUrlLen)
  1066. {
  1067. RegSetValueEx(hKey, REGSTR_VAL_SUPPORTURL, 0, REG_SZ, (LPBYTE)&(pOemInfo->szIniOemSupportUrl), (nUrlLen + 1) * sizeof(TCHAR));
  1068. }
  1069. RegCloseKey(hKey);
  1070. }
  1071. else
  1072. {
  1073. LOG_Error(_T("RegCreateKeyEx returned 0x%08x in SaveToReg"), lReg);
  1074. }
  1075. }