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.

2154 lines
61 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: sysspec.cpp
  6. //
  7. // Description:
  8. //
  9. // Implementation for the GetSystemSpec() function
  10. //
  11. //=======================================================================
  12. #include "iuengine.h"
  13. #include "iuxml.h"
  14. #include <iucommon.h>
  15. #include <comdef.h>
  16. #include <osdet.h>
  17. #include <setupapi.h>
  18. #include <regstr.h>
  19. #include <winspool.h> // for DRIVER_INFO_6
  20. #include "cdmp.h" // for GetInstalledPrinterDriverInfo()
  21. #include <shlwapi.h>
  22. #include <safereg.h>
  23. #include <safefile.h>
  24. #include <safefunc.h>
  25. #include <wusafefn.h>
  26. //
  27. // Specify a V1 structure passed to SetupDiBuildDriverInfoList
  28. // so we will work on NT4/Win9x and don't need to
  29. // fill in the extra V2 data on Win2K up
  30. //
  31. #define USE_SP_DRVINFO_DATA_V1 1
  32. //
  33. // Constants
  34. //
  35. const TCHAR SZ_WIN32_NT[] = _T("VER_PLATFORM_WIN32_NT");
  36. const TCHAR SZ_WIN32_WINDOWS[] = _T("VER_PLATFORM_WIN32_WINDOWS");
  37. const CHAR SZ_GET_SYSTEM_SPEC[] = "Determining machine configuration";
  38. #if defined(_X86_) || defined(i386)
  39. const TCHAR SZ_PROCESSOR[] = _T("x86");
  40. #else // defined(_IA64_) || defined(IA64)
  41. const TCHAR SZ_PROCESSOR[] = _T("ia64");
  42. #endif
  43. const TCHAR SZ_SUITE_SMALLBUSINESS[] = _T("VER_SUITE_SMALLBUSINESS");
  44. const TCHAR SZ_SUITE_ENTERPRISE[] = _T("VER_SUITE_ENTERPRISE");
  45. const TCHAR SZ_SUITE_BACKOFFICE[] = _T("VER_SUITE_BACKOFFICE");
  46. const TCHAR SZ_SUITE_COMMUNICATIONS[] = _T("VER_SUITE_COMMUNICATIONS");
  47. const TCHAR SZ_SUITE_TERMINAL[] = _T("VER_SUITE_TERMINAL");
  48. const TCHAR SZ_SUITE_SMALLBUSINESS_RESTRICTED[] = _T("VER_SUITE_SMALLBUSINESS_RESTRICTED");
  49. const TCHAR SZ_SUITE_EMBEDDEDNT[] = _T("VER_SUITE_EMBEDDEDNT");
  50. const TCHAR SZ_SUITE_DATACENTER[] = _T("VER_SUITE_DATACENTER");
  51. const TCHAR SZ_SUITE_SINGLEUSERTS[] = _T("VER_SUITE_SINGLEUSERTS");
  52. const TCHAR SZ_SUITE_PERSONAL[] = _T("VER_SUITE_PERSONAL");
  53. const TCHAR SZ_SUITE_BLADE[] = _T("VER_SUITE_BLADE");
  54. const TCHAR SZ_NT_WORKSTATION[] = _T("VER_NT_WORKSTATION");
  55. const TCHAR SZ_NT_DOMAIN_CONTROLLER[] = _T("VER_NT_DOMAIN_CONTROLLER");
  56. const TCHAR SZ_NT_SERVER[] = _T("VER_NT_SERVER");
  57. const TCHAR SZ_AMPERSAND[] = _T("&");
  58. const TCHAR SZ_LICDLL[]=_T("licdll.dll");
  59. LPCSTR lpszIVLK_GetEncPID = (LPCSTR)227;
  60. typedef HRESULT (WINAPI *PFUNCGetEncryptedPID)(OUT BYTE **ppbPid,OUT DWORD *pcbPid);
  61. //
  62. // DriverVer in schema uses ISO 8601 prefered format (yyyy-mm-dd)
  63. //
  64. const TCHAR SZ_UNKNOWN_DRIVERVER[] = _T("0000-00-00");
  65. #define SIZEOF_DRIVERVER sizeof(SZ_UNKNOWN_DRIVERVER)
  66. #define TCHARS_IN_DRIVERVER (ARRAYSIZE(SZ_UNKNOWN_DRIVERVER) - 1)
  67. //forward declaration for the function which gets the PID
  68. HRESULT GetSystemPID(BSTR &bstrPID);
  69. HRESULT BinaryToString(BYTE *lpBinary,DWORD dwLength,LPWSTR lpString,DWORD *pdwLength);
  70. //
  71. // Helper functions
  72. //
  73. HRESULT GetMultiSzDevRegProp(HDEVINFO hDevInfoSet, PSP_DEVINFO_DATA pDevInfoData, DWORD dwProperty, LPTSTR* ppMultiSZ)
  74. {
  75. LOG_Block("GetMultiSzDevRegProp");
  76. HRESULT hr = S_OK;
  77. ULONG ulSize = 0;
  78. if (INVALID_HANDLE_VALUE == hDevInfoSet || NULL == pDevInfoData || NULL == ppMultiSZ)
  79. {
  80. LOG_ErrorMsg(E_INVALIDARG);
  81. return E_INVALIDARG;
  82. }
  83. *ppMultiSZ = NULL;
  84. //
  85. // Several different errors may be set depending on the size/existance of the property,
  86. // but these aren't errors for us, we only care about filling in the buffer if the
  87. // property exists
  88. //
  89. (void) SetupDiGetDeviceRegistryProperty(hDevInfoSet, pDevInfoData, dwProperty, NULL, NULL, 0, &ulSize);
  90. if (0 < ulSize)
  91. {
  92. //
  93. // Create a zero initialized buffer 4 bytes (two Unicode characters) longer than we think we need
  94. // to protect ourselves from incorrect results returned by SetupDiGetDeviceRegistryProperties on
  95. // some platforms. In addition, Win98 requires at least one character more than what it returned
  96. // in ulSize, so we just make it 8 bytes over and pass four of them as an extra-sized buffer.
  97. //
  98. CleanUpFailedAllocSetHrMsg(*ppMultiSZ = (TCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize + 8));
  99. //
  100. // Get the actual hardware/compatible IDs (but don't tell SetupDiXxx about the extra four bytes of buffer)
  101. //
  102. if (!SetupDiGetDeviceRegistryProperty(hDevInfoSet, pDevInfoData, dwProperty, NULL, (LPBYTE) *ppMultiSZ, ulSize + 4, NULL))
  103. {
  104. DWORD dwError = GetLastError();
  105. LOG_Driver(_T("Informational: SetupDiGetDeviceRegistryProperty failed: 0x%08x"), dwError);
  106. if (ERROR_NO_SUCH_DEVINST == dwError || ERROR_INVALID_REG_PROPERTY == dwError || ERROR_INSUFFICIENT_BUFFER == dwError)
  107. {
  108. //
  109. // Return valid errors
  110. //
  111. SetHrAndGotoCleanUp(HRESULT_FROM_WIN32(dwError));
  112. }
  113. //
  114. // Some devices don't have the registry info we are looking for, so exit with default S_OK
  115. //
  116. goto CleanUp;
  117. }
  118. }
  119. CleanUp:
  120. if (FAILED(hr))
  121. {
  122. SafeHeapFree(*ppMultiSZ);
  123. }
  124. return hr;
  125. }
  126. HRESULT AddIDToXml(LPCTSTR pszMultiSZ, CXmlSystemSpec& xmlSpec, DWORD dwProperty,
  127. DWORD& dwRank, HANDLE_NODE& hDevices, LPCTSTR pszMatchingID, LPCTSTR pszDriverVer)
  128. {
  129. LOG_Block("AddIDToXml");
  130. HRESULT hr = S_OK;
  131. BSTR bstrMultiSZ = NULL;
  132. BSTR bstrDriverVer = NULL;
  133. if (NULL == pszMultiSZ)
  134. {
  135. LOG_ErrorMsg(E_INVALIDARG);
  136. return E_INVALIDARG;
  137. }
  138. //
  139. // Open a <device> element if necessary (don't reopen for compatible IDs)
  140. //
  141. if (HANDLE_NODE_INVALID == hDevices)
  142. {
  143. CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(NULL, -1, NULL, NULL, NULL, &hDevices));
  144. }
  145. for (NULL ; *pszMultiSZ; pszMultiSZ += (lstrlen(pszMultiSZ) + 1))
  146. {
  147. if ( NULL != pszMatchingID
  148. && NULL != pszDriverVer
  149. && 0 == lstrcmpi(pszMultiSZ, pszMatchingID) )
  150. {
  151. LOG_Driver(_T("ID: %s Match: %s, rank: %d, DriverVer: %s"), pszMultiSZ, pszMatchingID, dwRank, pszDriverVer);
  152. CleanUpFailedAllocSetHrMsg(bstrMultiSZ = T2BSTR(pszMultiSZ));
  153. CleanUpFailedAllocSetHrMsg(bstrDriverVer = T2BSTR(pszDriverVer));
  154. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, (SPDRP_COMPATIBLEIDS == dwProperty), dwRank++, bstrMultiSZ, bstrDriverVer));
  155. SafeSysFreeString(bstrMultiSZ);
  156. SafeSysFreeString(bstrDriverVer);
  157. //
  158. // We found the ID with the driver installed - don't pass any of lower rank up
  159. //
  160. hr = S_FALSE;
  161. break;
  162. }
  163. else
  164. {
  165. LOG_Driver(_T("ID: %s, rank: %d"), pszMultiSZ, dwRank);
  166. CleanUpFailedAllocSetHrMsg(bstrMultiSZ = T2BSTR(pszMultiSZ));
  167. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, (SPDRP_COMPATIBLEIDS == dwProperty), dwRank++, bstrMultiSZ, NULL));
  168. SafeSysFreeString(bstrMultiSZ);
  169. }
  170. }
  171. CleanUp:
  172. SysFreeString(bstrMultiSZ);
  173. SysFreeString(bstrDriverVer);
  174. return hr;
  175. }
  176. HRESULT DoesHwidMatchPrinter(
  177. DRIVER_INFO_6* paDriverInfo6, // array of DRIVER_INFO_6 structs for installed printer drivers
  178. DWORD dwDriverInfoCount, // count of structs in paDriverInfo6 array
  179. LPCTSTR pszMultiSZ, // Hardware or Compatible MultiSZ to compare with installed printer drivers
  180. BOOL* pfHwidMatchesInstalledPrinter) // [OUT] set TRUE if we match an installed printer driver
  181. {
  182. LOG_Block("DoesHwidMatchPrinter");
  183. HRESULT hr = S_OK;
  184. if (NULL == pfHwidMatchesInstalledPrinter || NULL == pszMultiSZ)
  185. {
  186. LOG_ErrorMsg(E_INVALIDARG);
  187. return E_INVALIDARG;
  188. }
  189. *pfHwidMatchesInstalledPrinter = FALSE;
  190. if (NULL == paDriverInfo6 || 0 == dwDriverInfoCount)
  191. {
  192. LOG_Driver(_T("WARNING: We're missing printer information (maybe no installed printer drivers), so we won't prune"));
  193. goto CleanUp;
  194. }
  195. for (NULL; *pszMultiSZ; pszMultiSZ += (lstrlen(pszMultiSZ) + 1))
  196. {
  197. for (DWORD dwCount = 0; dwCount < dwDriverInfoCount; dwCount++)
  198. {
  199. if (NULL == (paDriverInfo6 + dwCount)->pszHardwareID)
  200. {
  201. continue;
  202. }
  203. //
  204. // Use case-insensitive compares (paDriverInfo6 is different case from bstrHwidTxtTemp)
  205. //
  206. if (0 == lstrcmpi(pszMultiSZ, (paDriverInfo6 + dwCount)->pszHardwareID))
  207. {
  208. LOG_Driver(_T("HWID (%s) matches an installed printer driver"), pszMultiSZ);
  209. *pfHwidMatchesInstalledPrinter = TRUE;
  210. goto CleanUp;
  211. }
  212. }
  213. }
  214. CleanUp:
  215. return hr;
  216. }
  217. HRESULT AddPrunedDevRegProps(HDEVINFO hDevInfoSet,
  218. PSP_DEVINFO_DATA pDevInfoData,
  219. CXmlSystemSpec& xmlSpec,
  220. LPTSTR pszMatchingID,
  221. LPTSTR pszDriverVer,
  222. DRIVER_INFO_6* paDriverInfo6, // OK if this is NULL (no installed printer drivers)
  223. DWORD dwDriverInfoCount,
  224. BOOL fIsSysSpecCall) // Called by GetSystemSpec and GetPackage, with slightly different behavior
  225. {
  226. LOG_Block("AddPrunedDevRegProps");
  227. HRESULT hr = S_OK;
  228. LPTSTR pszMultiHwid = NULL;
  229. LPTSTR pszMultiCompid = NULL;
  230. DWORD dwRank = 0;
  231. HANDLE_NODE hDevices = HANDLE_NODE_INVALID;
  232. BOOL fHwidMatchesInstalledPrinter = FALSE;
  233. //
  234. // Get the Hardware and Compatible Multi-SZ strings so we can prune printer devices before commiting to XML.
  235. //
  236. // Note that GetMultiSzDevRegProp may return S_OK and a NULL *ppMultiSZ if the SRDP doesn't exist.
  237. //
  238. CleanUpIfFailedAndSetHr(GetMultiSzDevRegProp(hDevInfoSet, pDevInfoData, SPDRP_HARDWAREID, &pszMultiHwid));
  239. CleanUpIfFailedAndSetHr(GetMultiSzDevRegProp(hDevInfoSet, pDevInfoData, SPDRP_COMPATIBLEIDS, &pszMultiCompid));
  240. if (fIsSysSpecCall)
  241. {
  242. //
  243. // We prune this device if a HWID or CompID matches a HWID of an installed printer since we
  244. // must avoid offering a driver that may conflict with one if the installed printer drivers.
  245. // Other code will write <device isPrinter="1" /> elements to the system spec XML to be used in
  246. // offering printer drivers. NOTE, if there is no printer driver currently installed for the given
  247. // HWID we will just offer the driver based on the PnP match.
  248. //
  249. if (NULL != pszMultiHwid)
  250. {
  251. CleanUpIfFailedAndSetHr(DoesHwidMatchPrinter(paDriverInfo6, dwDriverInfoCount, pszMultiHwid, &fHwidMatchesInstalledPrinter));
  252. if(fHwidMatchesInstalledPrinter)
  253. {
  254. goto CleanUp;
  255. }
  256. }
  257. if (NULL != pszMultiCompid)
  258. {
  259. CleanUpIfFailedAndSetHr(DoesHwidMatchPrinter(paDriverInfo6, dwDriverInfoCount, pszMultiCompid, &fHwidMatchesInstalledPrinter));
  260. if(fHwidMatchesInstalledPrinter)
  261. {
  262. goto CleanUp;
  263. }
  264. }
  265. }
  266. //
  267. // Add the Hardware and Compatible IDs to XML
  268. //
  269. if (NULL != pszMultiHwid)
  270. {
  271. CleanUpIfFailedAndSetHr(AddIDToXml(pszMultiHwid, xmlSpec, SPDRP_HARDWAREID, dwRank, hDevices, pszMatchingID, pszDriverVer));
  272. }
  273. //
  274. // Skip compatible IDs if we don't have any or already found a match (hr == S_FALSE)
  275. //
  276. if (NULL != pszMultiCompid && hr == S_OK)
  277. {
  278. CleanUpIfFailedAndSetHr(AddIDToXml(pszMultiCompid, xmlSpec, SPDRP_COMPATIBLEIDS, dwRank, hDevices, pszMatchingID, pszDriverVer));
  279. }
  280. CleanUp:
  281. SafeHeapFree(pszMultiHwid);
  282. SafeHeapFree(pszMultiCompid);
  283. if (HANDLE_NODE_INVALID != hDevices)
  284. {
  285. xmlSpec.SafeCloseHandleNode(hDevices);
  286. }
  287. return hr;
  288. }
  289. static HRESULT DriverVerToIso8601(LPTSTR * ppszDriverVer)
  290. {
  291. LOG_Block("DriverVerToIso8601");
  292. HRESULT hr = S_OK;
  293. TCHAR pszDVTemp[TCHARS_IN_DRIVERVER + 1];
  294. LPTSTR pszMonth = pszDVTemp;
  295. LPTSTR pszDay = NULL;
  296. LPTSTR pszYear = NULL;
  297. //
  298. // buffer: pszDVTemp *ppszDriverVer
  299. // DriverVer: "[m]m-[d]d-yyyy" or "[m]m/[d]d/yyyy" --> ISO 8601: "yyyy-mm-dd"
  300. // index: 01 234567 0123456789
  301. // 0 12 3 456789 ,,, etc,
  302. //
  303. if (NULL == ppszDriverVer || NULL == *ppszDriverVer)
  304. {
  305. LOG_ErrorMsg(E_INVALIDARG);
  306. return E_INVALIDARG;
  307. }
  308. int nInLength = lstrlen(*ppszDriverVer);
  309. if (nInLength < TCHARS_IN_DRIVERVER - 2 || nInLength > TCHARS_IN_DRIVERVER)
  310. {
  311. LOG_ErrorMsg(E_INVALIDARG);
  312. (*ppszDriverVer)[0] = _T('\0');
  313. return E_INVALIDARG;
  314. }
  315. // Make sure *ppszDriverVer is large enough for ISO 8601
  316. //
  317. // **** It is VERY IMPORTANT that NO FAILURE CASE with an error of E_INVALIDARG go from before this ****
  318. // **** size check to the CleanUp section below. ****
  319. //
  320. if (ARRAYSIZE(pszDVTemp) > nInLength)
  321. {
  322. // if the size of this alloc is changed from SIZEOF_DRIVERVER, the StringCbCopy call below will need to be
  323. // changd appropriately as well.
  324. LPTSTR pszTemp = (LPTSTR) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (LPVOID) *ppszDriverVer, SIZEOF_DRIVERVER);
  325. if (NULL == pszTemp)
  326. {
  327. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  328. }
  329. *ppszDriverVer = pszTemp;
  330. }
  331. LOG_Driver(_T("In: \"%s\""), *ppszDriverVer);
  332. if ((_T('-') == (*ppszDriverVer)[4] || _T('/') == (*ppszDriverVer)[4]) &&
  333. (_T('-') == (*ppszDriverVer)[7] || _T('/') == (*ppszDriverVer)[7]))
  334. {
  335. //
  336. // It's probably already a valid ISO date, so do nothing
  337. //
  338. SetHrMsgAndGotoCleanUp(S_FALSE);
  339. }
  340. //
  341. // Unfortunately, DriverDate under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class (Win2K)
  342. // in the registry doesn't *always* pad the mm and dd fields with _T('0') for single digit months and days,
  343. // so we have to do this the hard way. But watch out - there's more. Win98SE (and maybe more)
  344. // pad with spaces, so we also have to change spaces to _T('0').
  345. //
  346. //
  347. // Copy to pszDVTemp
  348. //
  349. hr = StringCchCopyEx(pszDVTemp, ARRAYSIZE(pszDVTemp), *ppszDriverVer,
  350. NULL, NULL, MISTSAFE_STRING_FLAGS);
  351. CleanUpIfFailedAndSetHrMsg(hr);
  352. //
  353. // Find end of month, start of day
  354. //
  355. int i;
  356. for (i = 0; i < 3; i++)
  357. {
  358. if (_T('-') == pszMonth[i] || _T('/') == pszMonth[i])
  359. {
  360. pszMonth[i] = 0;
  361. pszDay = &pszMonth[i+1];
  362. break;
  363. }
  364. else if (_T(' ') == pszMonth[i])
  365. {
  366. pszMonth[i] = _T('0');
  367. }
  368. else if (!(_T('0') <= pszMonth[i] && _T('9') >= pszMonth[i]))
  369. {
  370. //
  371. // non-decimal characters other than _T('/') and "-"
  372. //
  373. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  374. }
  375. }
  376. if (NULL == pszDay || 0 == pszMonth[0])
  377. {
  378. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  379. }
  380. //
  381. // Find end of day, start of year
  382. //
  383. for (i = 0; i < 3; i++)
  384. {
  385. if (_T('-') == pszDay[i] || _T('/') == pszDay[i])
  386. {
  387. pszDay[i] = 0;
  388. pszYear = &pszDay[i+1];
  389. break;
  390. }
  391. else if (' ' == pszDay[i])
  392. {
  393. pszDay[i] = _T('0');
  394. }
  395. else if (!(_T('0') <= pszDay[i] && _T('9') >= pszDay[i]))
  396. {
  397. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  398. }
  399. }
  400. if (NULL == pszYear || 0 == pszDay[0])
  401. {
  402. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  403. }
  404. //
  405. // Verify year is four decimal digits
  406. //
  407. for (i = 0; i < 4 ; i++)
  408. {
  409. if (!(_T('0') <= pszYear[i] && _T('9') >= pszYear[i]) || _T('\0') == pszYear[i])
  410. {
  411. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  412. }
  413. }
  414. //
  415. // Copy back "yyyy" to start of string
  416. //
  417. hr = StringCbCopyEx(*ppszDriverVer, SIZEOF_DRIVERVER, pszYear,
  418. NULL, NULL, MISTSAFE_STRING_FLAGS);
  419. CleanUpIfFailedAndSetHrMsg(hr);
  420. //
  421. // Copy month and pad if necessary
  422. //
  423. if (2 == lstrlen(pszMonth))
  424. {
  425. (*ppszDriverVer)[5] = pszMonth[0];
  426. (*ppszDriverVer)[6] = pszMonth[1];
  427. }
  428. else
  429. {
  430. (*ppszDriverVer)[5] = _T('0');
  431. (*ppszDriverVer)[6] = pszMonth[0];
  432. }
  433. //
  434. // Copy day and pad if necessary
  435. //
  436. //
  437. if (2 == lstrlen(pszDay))
  438. {
  439. (*ppszDriverVer)[8] = pszDay[0];
  440. (*ppszDriverVer)[9] = pszDay[1];
  441. }
  442. else
  443. {
  444. (*ppszDriverVer)[8] = _T('0');
  445. (*ppszDriverVer)[9] = pszDay[0];
  446. }
  447. // Add back the field separators: _T('-')
  448. //
  449. (*ppszDriverVer)[4] = _T('-');
  450. (*ppszDriverVer)[7] = _T('-');
  451. //
  452. // NULL terminate string
  453. //
  454. (*ppszDriverVer)[10] = _T('\0');
  455. CleanUp:
  456. //
  457. // If we got garbage in, copy default date to *ppszDriverVer and return S_FALSE
  458. //
  459. if (E_INVALIDARG == hr)
  460. {
  461. // This is safe to do because we know that this function calls HeapReAlloc
  462. // on this buffer if it is too small above.
  463. (void) StringCbCopyEx(*ppszDriverVer, SIZEOF_DRIVERVER, SZ_UNKNOWN_DRIVERVER,
  464. NULL, NULL, MISTSAFE_STRING_FLAGS);
  465. hr = S_FALSE;
  466. }
  467. LOG_Driver(_T("Out: \"%s\""), *ppszDriverVer);
  468. return hr;
  469. }
  470. static HRESULT GetFirstStringField(HINF hInf, LPCTSTR szSection, LPCTSTR szKey, LPTSTR szValue, DWORD dwcValueTCHARs)
  471. {
  472. LOG_Block("GetFirstStringField");
  473. INFCONTEXT ctx;
  474. HRESULT hr = S_OK;
  475. if (INVALID_HANDLE_VALUE == hInf ||
  476. NULL == szSection ||
  477. NULL == szKey ||
  478. NULL == szValue ||
  479. 0 == dwcValueTCHARs )
  480. {
  481. LOG_ErrorMsg(E_INVALIDARG);
  482. return E_INVALIDARG;
  483. }
  484. *szValue = _T('\0');
  485. if (0 == SetupFindFirstLine(hInf, szSection, szKey, &ctx))
  486. {
  487. LOG_Error(_T("SetupFindFirstLine"));
  488. Win32MsgSetHrGotoCleanup(GetLastError());
  489. }
  490. if (0 == SetupGetStringField(&ctx, 1, szValue, dwcValueTCHARs, NULL))
  491. {
  492. LOG_Error(_T("SetupGetStringField"));
  493. Win32MsgSetHrGotoCleanup(GetLastError());
  494. }
  495. CleanUp:
  496. if (FAILED(hr))
  497. {
  498. *szValue = _T('\0');
  499. }
  500. return hr;
  501. }
  502. HRESULT GetPropertyFromSetupDi(HDEVINFO hDevInfoSet, SP_DEVINFO_DATA devInfoData, ULONG ulProperty, LPTSTR* ppszProperty)
  503. {
  504. LOG_Block("GetPropertyFromSetupDi");
  505. HRESULT hr = S_OK;
  506. ULONG ulSize = 0;
  507. if (INVALID_HANDLE_VALUE == hDevInfoSet || NULL == ppszProperty)
  508. {
  509. LOG_ErrorMsg(E_INVALIDARG);
  510. return E_INVALIDARG;
  511. }
  512. *ppszProperty = NULL;
  513. if (!SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfoData, ulProperty, NULL, NULL, 0, &ulSize))
  514. {
  515. if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
  516. {
  517. LOG_Error(_T("SetupDiGetDeviceRegistryProperty"));
  518. Win32MsgSetHrGotoCleanup(GetLastError());
  519. }
  520. }
  521. if (0 == ulSize)
  522. {
  523. LOG_Error(_T("SetupDiGetDeviceRegistryProperty returned zero size"));
  524. SetHrAndGotoCleanUp(E_FAIL);
  525. }
  526. // Win98 has a bug when requesting SPDRP_HARDWAREID
  527. // NTBUG9#182680 We make this big enough to always have a Unicode double-null at the end
  528. // so that we don't fault if the reg value isn't correctly terminated. Don't tell SetupDiXxxx
  529. // about all eight extra bytes.
  530. ulSize += 8;
  531. // NTBUG9#182680 zero the buffer so we don't get random garbage - REG_MULTI_SZ isn't always double-null terminated
  532. CleanUpFailedAllocSetHrMsg(*ppszProperty = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize));
  533. if (!SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfoData, ulProperty, NULL, (LPBYTE)*ppszProperty, ulSize - 4 , NULL))
  534. {
  535. LOG_Error(_T("SetupDiGetDeviceRegistryProperty"));
  536. Win32MsgSetHrGotoCleanup(GetLastError());
  537. }
  538. CleanUp:
  539. if (FAILED(hr))
  540. {
  541. SafeHeapFree(*ppszProperty);
  542. }
  543. return hr;
  544. }
  545. HRESULT GetPropertyFromSetupDiReg(HDEVINFO hDevInfoSet, SP_DEVINFO_DATA devInfoData, LPCTSTR szProperty, LPTSTR *ppszData)
  546. {
  547. LOG_Block("GetPropertyFromSetupDiReg");
  548. int cchValueSize = 0;
  549. HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
  550. HRESULT hr = S_OK;
  551. if (INVALID_HANDLE_VALUE == hDevInfoSet || NULL == szProperty || NULL == ppszData)
  552. {
  553. LOG_ErrorMsg(E_INVALIDARG);
  554. return E_INVALIDARG;
  555. }
  556. *ppszData = NULL;
  557. //
  558. // Open a software, or driver, registry key for the device. This key is located in the Class branch.
  559. //
  560. if (INVALID_HANDLE_VALUE == (hKey = SetupDiOpenDevRegKey(hDevInfoSet, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ)))
  561. {
  562. LOG_Error(_T("SetupDiOpenDevRegKey"));
  563. Win32MsgSetHrGotoCleanup(GetLastError());
  564. }
  565. hr = SafeRegQueryStringValueCch(hKey, szProperty, NULL, 0, &cchValueSize);
  566. if (REG_E_MORE_DATA != hr || 0 == cchValueSize)
  567. {
  568. CleanUpIfFailedAndSetHrMsg(hr);
  569. }
  570. //
  571. // Sanity check size of data in registry
  572. //
  573. if (MAX_INF_STRING_LEN < cchValueSize)
  574. {
  575. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  576. }
  577. //
  578. // Add extra character of zero'ed memory for safety
  579. //
  580. CleanUpFailedAllocSetHrMsg(*ppszData = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (cchValueSize + 1) * sizeof(TCHAR)));
  581. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hKey, szProperty, *ppszData, cchValueSize, &cchValueSize));
  582. CleanUp:
  583. if (INVALID_HANDLE_VALUE != hKey)
  584. {
  585. RegCloseKey(hKey);
  586. }
  587. if (FAILED(hr))
  588. {
  589. SafeHeapFree(*ppszData);
  590. }
  591. return hr;
  592. }
  593. static HRESULT DriverVerFromInf(HINF hInf, LPTSTR pszMfg, LPTSTR pszDescription, LPTSTR* ppszDriverVer)
  594. {
  595. LOG_Block("DriverVerFromInf");
  596. HRESULT hr;
  597. TCHAR szDeviceSec[MAX_PATH + 1];
  598. TCHAR szValue[MAX_PATH + 1];
  599. TCHAR szInstallSec[MAX_PATH + 1];
  600. if (INVALID_HANDLE_VALUE == hInf ||
  601. NULL == pszMfg ||
  602. NULL == pszDescription ||
  603. NULL == ppszDriverVer )
  604. {
  605. LOG_ErrorMsg(E_INVALIDARG);
  606. return E_INVALIDARG;
  607. }
  608. ZeroMemory(szDeviceSec , sizeof(szDeviceSec));
  609. ZeroMemory(szValue , sizeof(szValue));
  610. ZeroMemory(szInstallSec , sizeof(szInstallSec));
  611. *ppszDriverVer = NULL;
  612. //
  613. // Lie about buffer size so we are always NULL terminated
  614. //
  615. CleanUpIfFailedAndSetHr(GetFirstStringField(hInf, _T("Manufacturer"), pszMfg, szDeviceSec, ARRAYSIZE(szDeviceSec) - 1)); // Driver section
  616. CleanUpIfFailedAndSetHr(GetFirstStringField(hInf, szDeviceSec, pszDescription, szInstallSec, ARRAYSIZE(szInstallSec) - 1)); // Install section
  617. CleanUpIfFailedAndSetHr(GetFirstStringField(hInf, szInstallSec, _T("DriverVer"), szValue, ARRAYSIZE(szValue) - 1)); // DriverVer
  618. CleanUp:
  619. if (FAILED(hr))
  620. {
  621. //
  622. // if we didn't get it from the "Manufacturer" section, try the "Version" section
  623. //
  624. hr = GetFirstStringField(hInf, _T("Version"), _T("DriverVer"), szValue, MAX_PATH);
  625. }
  626. if (SUCCEEDED(hr))
  627. {
  628. if (NULL != ppszDriverVer)
  629. {
  630. DWORD cch = (lstrlen(szValue) + 1);
  631. if (NULL == (*ppszDriverVer = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, cch * sizeof(TCHAR))))
  632. {
  633. LOG_ErrorMsg(E_OUTOFMEMORY);
  634. hr = E_OUTOFMEMORY;
  635. }
  636. else
  637. {
  638. // Convert to ISO 8601 format
  639. hr = StringCchCopyEx(*ppszDriverVer, cch, szValue, NULL, NULL, MISTSAFE_STRING_FLAGS);
  640. if (FAILED(hr))
  641. {
  642. LOG_ErrorMsg(hr);
  643. }
  644. else
  645. {
  646. hr = DriverVerToIso8601(ppszDriverVer);
  647. }
  648. if (FAILED(hr))
  649. {
  650. SafeHeapFree(*ppszDriverVer);
  651. }
  652. }
  653. }
  654. }
  655. return hr;
  656. }
  657. inline bool IsDriver(LPCTSTR szFile)
  658. {
  659. #if defined(DBG)
  660. if (NULL == szFile)
  661. {
  662. return false;
  663. }
  664. #endif
  665. LPCTSTR szExt = PathFindExtension(szFile);
  666. if (NULL == szExt)
  667. {
  668. return false;
  669. }
  670. static const TCHAR* aszExt[] = {
  671. _T(".sys"),
  672. _T(".dll"),
  673. _T(".drv"),
  674. _T(".vxd"),
  675. };
  676. for(int i = 0; i < ARRAYSIZE(aszExt); i ++)
  677. {
  678. if(0 == lstrcmpi(aszExt[i], szExt))
  679. return true;
  680. }
  681. return false;
  682. }
  683. static UINT CALLBACK FileQueueScanCallback(
  684. IN PVOID pContext, // setup api context
  685. IN UINT ulNotification, // notification message
  686. IN UINT_PTR ulParam1, // extra notification message information 1
  687. IN UINT_PTR /*Param2*/ ) // extra notification message information 2
  688. {
  689. LOG_Block("FileQueueScanCallback");
  690. HRESULT hr;
  691. if (NULL == pContext || 0 == ulParam1)
  692. {
  693. LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
  694. return ERROR_INVALID_PARAMETER;
  695. }
  696. if (SPFILENOTIFY_QUEUESCAN == ulNotification)
  697. {
  698. PFILETIME pftDateLatest = (PFILETIME)pContext;
  699. LPCTSTR szFile = (LPCTSTR)ulParam1;
  700. // Is this a binary
  701. if (IsDriver(szFile))
  702. {
  703. HANDLE hFile = INVALID_HANDLE_VALUE;
  704. if (SUCCEEDED(hr = SafeCreateFile(&hFile, 0, szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)))
  705. {
  706. FILETIME ft;
  707. if (GetFileTime(hFile, NULL, NULL, &ft))
  708. {
  709. #if defined(DBG)
  710. SYSTEMTIME st;
  711. if (FileTimeToSystemTime(&ft, &st))
  712. {
  713. LOG_Out(_T("%s : %04d-%02d-%02d"), szFile, (int)st.wYear, (int)st.wMonth, (int)st.wDay);
  714. }
  715. #endif
  716. if (CompareFileTime(pftDateLatest, &ft) < 0)
  717. *pftDateLatest = ft;
  718. }
  719. else
  720. {
  721. LOG_Error(_T("GetFileTime %s"), szFile);
  722. LOG_ErrorMsg(GetLastError());
  723. }
  724. CloseHandle(hFile);
  725. }
  726. else
  727. {
  728. LOG_Error(_T("SafeCreateFile %s:"), szFile);
  729. LOG_ErrorMsg(hr);
  730. }
  731. }
  732. else
  733. {
  734. LOG_Out(_T("%s: not a driver"), szFile);
  735. }
  736. }
  737. return NO_ERROR;
  738. }
  739. static HRESULT LatestDriverFileTime(HDEVINFO hDevInfoSet, SP_DEVINFO_DATA devInfoData, LPTSTR pszMfg,
  740. LPTSTR pszDescription, LPTSTR pszProvider, LPCTSTR pszInfFile, LPTSTR* ppszDriverVer)
  741. {
  742. LOG_Block("LatestDriverFileTime");
  743. HRESULT hr = S_OK;
  744. FILETIME ftDate = {0,0};
  745. HSPFILEQ hspfileq = INVALID_HANDLE_VALUE;
  746. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  747. if (INVALID_HANDLE_VALUE == hDevInfoSet ||
  748. NULL == pszMfg ||
  749. NULL == pszDescription ||
  750. NULL == pszProvider ||
  751. NULL == pszInfFile ||
  752. NULL == ppszDriverVer )
  753. {
  754. LOG_ErrorMsg(E_INVALIDARG);
  755. return E_INVALIDARG;
  756. }
  757. ZeroMemory(&DeviceInstallParams, sizeof(SP_DEVINSTALL_PARAMS));
  758. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  759. *ppszDriverVer = NULL;
  760. if (!SetupDiGetDeviceInstallParams(hDevInfoSet, &devInfoData, &DeviceInstallParams))
  761. {
  762. LOG_Error(_T("SetupDiGetDeviceInstallParams"));
  763. Win32MsgSetHrGotoCleanup(GetLastError());
  764. }
  765. hr = StringCchCopyEx(DeviceInstallParams.DriverPath, ARRAYSIZE(DeviceInstallParams.DriverPath),
  766. pszInfFile,
  767. NULL, NULL, MISTSAFE_STRING_FLAGS);
  768. CleanUpIfFailedAndSetHrMsg(hr);
  769. DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
  770. if (!SetupDiSetDeviceInstallParams(hDevInfoSet, &devInfoData, &DeviceInstallParams))
  771. {
  772. LOG_Error(_T("SetupDiSetDeviceInstallParams"));
  773. Win32MsgSetHrGotoCleanup(GetLastError());
  774. }
  775. //Now build a class driver list from this INF.
  776. if (!SetupDiBuildDriverInfoList(hDevInfoSet, &devInfoData, SPDIT_CLASSDRIVER))
  777. {
  778. LOG_Error(_T("SetupDiBuildDriverInfoList"));
  779. Win32MsgSetHrGotoCleanup(GetLastError());
  780. }
  781. //Prepare driver info struct
  782. SP_DRVINFO_DATA DriverInfoData;
  783. ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
  784. DriverInfoData.cbSize = sizeof(DriverInfoData);
  785. DriverInfoData.DriverType = SPDIT_CLASSDRIVER;
  786. DriverInfoData.Reserved = 0;
  787. hr = StringCchCopyEx(DriverInfoData.MfgName, ARRAYSIZE(DriverInfoData.MfgName), pszMfg,
  788. NULL, NULL, MISTSAFE_STRING_FLAGS);
  789. CleanUpIfFailedAndSetHrMsg(hr);
  790. hr = StringCchCopyEx(DriverInfoData.Description, ARRAYSIZE(DriverInfoData.Description), pszDescription,
  791. NULL, NULL, MISTSAFE_STRING_FLAGS);
  792. CleanUpIfFailedAndSetHrMsg(hr);
  793. hr = StringCchCopyEx(DriverInfoData.ProviderName, ARRAYSIZE(DriverInfoData.ProviderName), pszProvider,
  794. NULL, NULL, MISTSAFE_STRING_FLAGS);
  795. CleanUpIfFailedAndSetHrMsg(hr);
  796. if (!SetupDiSetSelectedDriver(hDevInfoSet, &devInfoData, (SP_DRVINFO_DATA*)&DriverInfoData))
  797. {
  798. Win32MsgSetHrGotoCleanup(GetLastError());
  799. }
  800. if (INVALID_HANDLE_VALUE == (hspfileq = SetupOpenFileQueue()))
  801. {
  802. Win32MsgSetHrGotoCleanup(GetLastError());
  803. }
  804. // Set custom queue to device install params
  805. if (!SetupDiGetDeviceInstallParams(hDevInfoSet, &devInfoData, &DeviceInstallParams))
  806. {
  807. Win32MsgSetHrGotoCleanup(GetLastError());
  808. }
  809. DeviceInstallParams.FileQueue = hspfileq;
  810. DeviceInstallParams.Flags |= DI_NOVCP;
  811. if (!SetupDiSetDeviceInstallParams(hDevInfoSet, &devInfoData, &DeviceInstallParams))
  812. {
  813. Win32MsgSetHrGotoCleanup(GetLastError());
  814. }
  815. if (!SetupDiInstallDriverFiles(hDevInfoSet, &devInfoData))
  816. {
  817. Win32MsgSetHrGotoCleanup(GetLastError());
  818. }
  819. // Parse the queue
  820. DWORD dwScanResult;
  821. if (!SetupScanFileQueue(hspfileq, SPQ_SCAN_USE_CALLBACK, NULL, (PSP_FILE_CALLBACK)FileQueueScanCallback, &ftDate, &dwScanResult))
  822. {
  823. Win32MsgSetHrGotoCleanup(GetLastError());
  824. }
  825. SYSTEMTIME st;
  826. if (!FileTimeToSystemTime(&ftDate, &st))
  827. {
  828. Win32MsgSetHrGotoCleanup(GetLastError());
  829. }
  830. if (1990 > st.wYear)
  831. {
  832. //
  833. // Didn't enumerate any files, or files had bogus dates. Return an error so
  834. // we will fallback on default "0000-00-00"
  835. //
  836. hr = E_NOTIMPL;
  837. LOG_ErrorMsg(hr);
  838. goto CleanUp;
  839. }
  840. #if defined(DBG)
  841. LOG_Out(_T("%s - %s %04d-%02d-%02d"), pszMfg, pszDescription, (int)st.wYear, (int)st.wMonth, (int)st.wDay);
  842. #endif
  843. CleanUpFailedAllocSetHrMsg(*ppszDriverVer = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, SIZEOF_DRIVERVER));
  844. // ISO 8601 prefered format (yyyy-mm-dd)
  845. hr = StringCbPrintfEx(*ppszDriverVer, SIZEOF_DRIVERVER, NULL, NULL, MISTSAFE_STRING_FLAGS,
  846. _T("%04d-%02d-%02d"), (int)st.wYear, (int)st.wMonth, (int)st.wDay);
  847. CleanUpIfFailedAndSetHrMsg(hr);
  848. CleanUp:
  849. if (INVALID_HANDLE_VALUE != hspfileq)
  850. {
  851. SetupCloseFileQueue(hspfileq);
  852. }
  853. if (FAILED(hr))
  854. {
  855. SafeHeapFree(*ppszDriverVer);
  856. }
  857. return hr;
  858. }
  859. //
  860. // Called if we don't get driver date from registry
  861. //
  862. static HRESULT GetDriverDateFromInf(HKEY hDevRegKey, HDEVINFO hDevInfoSet, SP_DEVINFO_DATA devInfoData, LPTSTR* ppszDriverVer)
  863. {
  864. LOG_Block("GetDriverDateFromInf");
  865. HRESULT hr;
  866. UINT nRet;
  867. HINF hInf = INVALID_HANDLE_VALUE;
  868. LPTSTR pszMfg = NULL;
  869. LPTSTR pszDescription = NULL;
  870. LPTSTR pszProvider = NULL;
  871. TCHAR szInfName[MAX_PATH + 2];
  872. int cchValueSize;
  873. if (INVALID_HANDLE_VALUE == hDevInfoSet || (HKEY)INVALID_HANDLE_VALUE == hDevRegKey || NULL == ppszDriverVer)
  874. {
  875. LOG_ErrorMsg(E_INVALIDARG);
  876. return E_INVALIDARG;
  877. }
  878. *ppszDriverVer = NULL;
  879. //
  880. // Get INF File name from registry, but lie about size to make sure we are NULL terminated
  881. //
  882. ZeroMemory(szInfName, sizeof(szInfName));
  883. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_INFPATH, szInfName, ARRAYSIZE(szInfName)-1, &cchValueSize));
  884. //
  885. // Verify the file name ends with ".inf"
  886. //
  887. if (CSTR_EQUAL != WUCompareStringI(&szInfName[lstrlen(szInfName) - 4], _T(".inf")))
  888. {
  889. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  890. }
  891. //
  892. // Look for szInfName in %windir%\inf\ or %windir%\inf\other\
  893. //
  894. TCHAR szInfFile[MAX_PATH + 1];
  895. nRet = GetWindowsDirectory(szInfFile, ARRAYSIZE(szInfFile));
  896. if (0 == nRet || ARRAYSIZE(szInfFile) < nRet)
  897. {
  898. Win32MsgSetHrGotoCleanup(GetLastError());
  899. }
  900. hr = PathCchAppend(szInfFile, ARRAYSIZE(szInfFile), _T("inf"));
  901. CleanUpIfFailedAndSetHrMsg(hr);
  902. hr = PathCchAppend(szInfFile, ARRAYSIZE(szInfFile), szInfName);
  903. CleanUpIfFailedAndSetHrMsg(hr);
  904. if (INVALID_HANDLE_VALUE == (hInf = SetupOpenInfFile(szInfFile, NULL, INF_STYLE_WIN4, NULL)))
  905. {
  906. nRet = GetWindowsDirectory(szInfFile, ARRAYSIZE(szInfFile));
  907. if (0 == nRet || ARRAYSIZE(szInfFile) < nRet)
  908. {
  909. Win32MsgSetHrGotoCleanup(GetLastError());
  910. }
  911. hr = PathCchAppend(szInfFile, ARRAYSIZE(szInfFile), _T("inf\\other"));
  912. CleanUpIfFailedAndSetHrMsg(hr);
  913. hr = PathCchAppend(szInfFile, ARRAYSIZE(szInfFile), szInfName);
  914. CleanUpIfFailedAndSetHrMsg(hr);
  915. if (INVALID_HANDLE_VALUE == (hInf = SetupOpenInfFile(szInfFile, NULL, INF_STYLE_WIN4, NULL)))
  916. {
  917. LOG_Driver(_T("SetupOpenInfFile %s"), szInfFile);
  918. Win32MsgSetHrGotoCleanup(GetLastError());
  919. }
  920. }
  921. // first try to get it from inf
  922. CleanUpIfFailedAndSetHr(GetPropertyFromSetupDi(hDevInfoSet, devInfoData, SPDRP_MFG, &pszMfg));
  923. CleanUpIfFailedAndSetHr(GetPropertyFromSetupDi(hDevInfoSet, devInfoData, SPDRP_DEVICEDESC, &pszDescription));
  924. if (SUCCEEDED(hr = DriverVerFromInf(hInf, pszMfg, pszDescription, ppszDriverVer)))
  925. {
  926. goto CleanUp;
  927. }
  928. //
  929. // Try enumerating the files as last resort
  930. //
  931. CleanUpIfFailedAndSetHr(GetPropertyFromSetupDiReg(hDevInfoSet, devInfoData, REGSTR_VAL_PROVIDER_NAME, &pszProvider));
  932. hr = LatestDriverFileTime(hDevInfoSet, devInfoData, pszMfg, pszDescription, pszProvider, szInfFile, ppszDriverVer);
  933. CleanUp:
  934. if (INVALID_HANDLE_VALUE != hInf)
  935. {
  936. SetupCloseInfFile(hInf);
  937. }
  938. SafeHeapFree(pszMfg);
  939. SafeHeapFree(pszDescription);
  940. SafeHeapFree(pszProvider);
  941. if (FAILED(hr))
  942. {
  943. SafeHeapFree(*ppszDriverVer);
  944. }
  945. return hr;
  946. }
  947. /////////////////////////////////////////////////////////////////////////////
  948. // Add Classes helper functionality for GetSystemSpec() and CDM functions
  949. /////////////////////////////////////////////////////////////////////////////
  950. HRESULT AddComputerSystemClass(CXmlSystemSpec& xmlSpec)
  951. {
  952. USES_IU_CONVERSION;
  953. LOG_Block("AddComputerSystemClass");
  954. HRESULT hr;
  955. BSTR bstrDrive = NULL;
  956. BSTR bstrPID = NULL;
  957. PIU_DRIVEINFO pDriveInfo = NULL;
  958. DWORD dwNumDrives;
  959. IU_PLATFORM_INFO iuPlatformInfo;
  960. ZeroMemory( &iuPlatformInfo, sizeof(iuPlatformInfo));
  961. CleanUpIfFailedAndSetHr( DetectClientIUPlatform(&iuPlatformInfo) );
  962. if( 4 < iuPlatformInfo.osVersionInfoEx.dwMajorVersion )
  963. {
  964. BOOL bPid = TRUE;
  965. if(5 == iuPlatformInfo.osVersionInfoEx.dwMajorVersion)
  966. {
  967. if( 1 > iuPlatformInfo.osVersionInfoEx.dwMinorVersion)
  968. bPid = FALSE;
  969. else if(1 == iuPlatformInfo.osVersionInfoEx.dwMinorVersion)
  970. {
  971. if(1 > iuPlatformInfo.osVersionInfoEx.wServicePackMajor)
  972. bPid = FALSE;
  973. }
  974. }
  975. if(bPid)
  976. GetSystemPID(bstrPID);
  977. //Note: Return value is not checked because
  978. //Any failure to get the PID is not considered as a failure on the GetSystemSpec method
  979. //If the pid attribute is missing on the supported platforms it is still considered as
  980. //an invalid pid case and no items will be returned in the catalog from the server
  981. //if there is any error bstrPID will be null and it will not be added to
  982. //the systemspec xml
  983. }
  984. //CleanUpIfFailedAndSetHr(GetOemBstrs(bstrManufacturer, bstrModel, bstrOEMSupportURL));
  985. // NTRAID#NTBUG9-277070-2001/01/12-waltw IUpdate methods should return
  986. // HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED) when Windows Update is disabled
  987. // Just pass -1 to AddComputerSystem()
  988. CleanUpIfFailedAndSetHr(xmlSpec.AddComputerSystem(iuPlatformInfo.bstrOEMManufacturer, iuPlatformInfo.bstrOEMModel,
  989. iuPlatformInfo.bstrOEMSupportURL, IsAdministrator(), IsWindowsUpdateDisabled(), IsAutoUpdateEnabled(), bstrPID));
  990. CleanUpIfFailedAndSetHr(GetLocalFixedDriveInfo(&dwNumDrives, &pDriveInfo));
  991. for (DWORD i = 0; i < dwNumDrives; i++)
  992. {
  993. CleanUpFailedAllocSetHrMsg(bstrDrive = SysAllocString(T2OLE((&pDriveInfo[i])->szDriveStr)));
  994. CleanUpIfFailedAndSetHr(xmlSpec.AddDriveSpace(bstrDrive, (&pDriveInfo[i])->iKBytes));
  995. SafeSysFreeString(bstrDrive);
  996. }
  997. CleanUp:
  998. SafeHeapFree(pDriveInfo);
  999. SysFreeString(bstrDrive);
  1000. SysFreeString(bstrPID);
  1001. return hr;
  1002. }
  1003. HRESULT AddRegKeyClass(CXmlSystemSpec& xmlSpec)
  1004. {
  1005. LOG_Block("AddRegKeysClass");
  1006. HRESULT hr = S_OK;
  1007. LONG lRet;
  1008. HKEY hkSoftware;
  1009. TCHAR szSoftware[MAX_PATH];
  1010. DWORD dwcSoftware;
  1011. DWORD dwIndex = 0;
  1012. FILETIME ftLastWriteTime;
  1013. BSTR bstrSoftware = NULL;
  1014. BOOL fRegKeyOpened = FALSE;
  1015. if (ERROR_SUCCESS != (lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE"), 0, KEY_READ, &hkSoftware)))
  1016. {
  1017. Win32MsgSetHrGotoCleanup(lRet);
  1018. }
  1019. else
  1020. {
  1021. fRegKeyOpened = TRUE;
  1022. }
  1023. do
  1024. {
  1025. dwcSoftware = MAX_PATH;
  1026. if (ERROR_SUCCESS != (lRet = (RegEnumKeyEx(hkSoftware, dwIndex++, szSoftware, &dwcSoftware, NULL, NULL, NULL, &ftLastWriteTime))))
  1027. {
  1028. if (ERROR_NO_MORE_ITEMS == lRet)
  1029. {
  1030. break;
  1031. }
  1032. else
  1033. {
  1034. LOG_ErrorMsg(lRet);
  1035. hr = HRESULT_FROM_WIN32(lRet);
  1036. break;
  1037. }
  1038. }
  1039. CleanUpFailedAllocSetHrMsg(bstrSoftware = T2BSTR(szSoftware));
  1040. CleanUpIfFailedAndSetHr(xmlSpec.AddReg(bstrSoftware));
  1041. SafeSysFreeString(bstrSoftware);
  1042. } while (ERROR_SUCCESS == lRet);
  1043. CleanUp:
  1044. SysFreeString(bstrSoftware);
  1045. if (TRUE == fRegKeyOpened)
  1046. {
  1047. RegCloseKey(hkSoftware);
  1048. }
  1049. return hr;
  1050. }
  1051. HRESULT AddPlatformClass(CXmlSystemSpec& xmlSpec, IU_PLATFORM_INFO iuPlatformInfo)
  1052. {
  1053. USES_IU_CONVERSION;
  1054. LOG_Block("AddPlatformClass");
  1055. HRESULT hr;
  1056. BSTR bstrTemp = NULL;
  1057. // NOTE: we never expect to be called on Win32s
  1058. const TCHAR* pszPlatformName = (VER_PLATFORM_WIN32_NT == iuPlatformInfo.osVersionInfoEx.dwPlatformId)
  1059. ? SZ_WIN32_NT : SZ_WIN32_WINDOWS;
  1060. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(pszPlatformName));
  1061. CleanUpIfFailedAndSetHr(xmlSpec.AddPlatform(bstrTemp));
  1062. SafeSysFreeString(bstrTemp);
  1063. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_PROCESSOR));
  1064. CleanUpIfFailedAndSetHr(xmlSpec.AddProcessor(bstrTemp));
  1065. SafeSysFreeString(bstrTemp);
  1066. hr = xmlSpec.AddVersion( iuPlatformInfo.osVersionInfoEx.dwMajorVersion,
  1067. iuPlatformInfo.osVersionInfoEx.dwMinorVersion,
  1068. iuPlatformInfo.osVersionInfoEx.dwBuildNumber,
  1069. (sizeof(OSVERSIONINFOEX) == iuPlatformInfo.osVersionInfoEx.dwOSVersionInfoSize)
  1070. ? iuPlatformInfo.osVersionInfoEx.wServicePackMajor : 0,
  1071. (sizeof(OSVERSIONINFOEX) == iuPlatformInfo.osVersionInfoEx.dwOSVersionInfoSize)
  1072. ? iuPlatformInfo.osVersionInfoEx.wServicePackMinor : 0
  1073. );
  1074. CleanUpIfFailedAndSetHr(hr);
  1075. //
  1076. // If we can, add Suite and Product Type
  1077. //
  1078. if (sizeof(OSVERSIONINFOEX) == iuPlatformInfo.osVersionInfoEx.dwOSVersionInfoSize)
  1079. {
  1080. //
  1081. // Add all suites
  1082. //
  1083. if (VER_SUITE_SMALLBUSINESS & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1084. {
  1085. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_SMALLBUSINESS));
  1086. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1087. SafeSysFreeString(bstrTemp);
  1088. }
  1089. if (VER_SUITE_ENTERPRISE & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1090. {
  1091. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_ENTERPRISE));
  1092. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1093. SafeSysFreeString(bstrTemp);
  1094. }
  1095. if (VER_SUITE_BACKOFFICE & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1096. {
  1097. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_BACKOFFICE));
  1098. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1099. SafeSysFreeString(bstrTemp);
  1100. }
  1101. if (VER_SUITE_COMMUNICATIONS & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1102. {
  1103. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_COMMUNICATIONS));
  1104. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1105. SafeSysFreeString(bstrTemp);
  1106. }
  1107. if (VER_SUITE_TERMINAL & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1108. {
  1109. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_TERMINAL));
  1110. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1111. SafeSysFreeString(bstrTemp);
  1112. }
  1113. if (VER_SUITE_SMALLBUSINESS_RESTRICTED & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1114. {
  1115. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_SMALLBUSINESS_RESTRICTED));
  1116. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1117. SafeSysFreeString(bstrTemp);
  1118. }
  1119. if (VER_SUITE_EMBEDDEDNT & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1120. {
  1121. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_EMBEDDEDNT));
  1122. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1123. SafeSysFreeString(bstrTemp);
  1124. }
  1125. if (VER_SUITE_DATACENTER & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1126. {
  1127. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_DATACENTER));
  1128. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1129. SafeSysFreeString(bstrTemp);
  1130. }
  1131. if (VER_SUITE_SINGLEUSERTS & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1132. {
  1133. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_SINGLEUSERTS));
  1134. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1135. SafeSysFreeString(bstrTemp);
  1136. }
  1137. if (VER_SUITE_PERSONAL & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1138. {
  1139. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_PERSONAL));
  1140. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1141. SafeSysFreeString(bstrTemp);
  1142. }
  1143. if (VER_SUITE_BLADE & iuPlatformInfo.osVersionInfoEx.wSuiteMask)
  1144. {
  1145. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_SUITE_BLADE));
  1146. CleanUpIfFailedAndSetHr(xmlSpec.AddSuite(bstrTemp));
  1147. SafeSysFreeString(bstrTemp);
  1148. }
  1149. //
  1150. // Add Product Type
  1151. //
  1152. if (VER_NT_WORKSTATION == iuPlatformInfo.osVersionInfoEx.wProductType)
  1153. {
  1154. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_NT_WORKSTATION));
  1155. CleanUpIfFailedAndSetHr(xmlSpec.AddProductType(bstrTemp));
  1156. SafeSysFreeString(bstrTemp);
  1157. }
  1158. else if (VER_NT_DOMAIN_CONTROLLER == iuPlatformInfo.osVersionInfoEx.wProductType)
  1159. {
  1160. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_NT_DOMAIN_CONTROLLER));
  1161. CleanUpIfFailedAndSetHr(xmlSpec.AddProductType(bstrTemp));
  1162. SafeSysFreeString(bstrTemp);
  1163. }
  1164. else if (VER_NT_SERVER == iuPlatformInfo.osVersionInfoEx.wProductType)
  1165. {
  1166. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(SZ_NT_SERVER));
  1167. CleanUpIfFailedAndSetHr(xmlSpec.AddProductType(bstrTemp));
  1168. SafeSysFreeString(bstrTemp);
  1169. }
  1170. // else skip - there's a new one defined we don't know about
  1171. }
  1172. CleanUp:
  1173. SysFreeString(bstrTemp);
  1174. return hr;
  1175. }
  1176. HRESULT AddLocaleClass(CXmlSystemSpec& xmlSpec, BOOL fIsUser)
  1177. {
  1178. LOG_Block("AddLocaleClass");
  1179. HRESULT hr;
  1180. BSTR bstrTemp = NULL;
  1181. HANDLE_NODE hLocale = HANDLE_NODE_INVALID;
  1182. TCHAR szLang[256] = _T(""); // Usually ISO format five characters + NULL (en-US) but note exceptions
  1183. // such as "el_IBM"
  1184. CleanUpFailedAllocSetHrMsg(bstrTemp = SysAllocString(fIsUser ? L"USER" : L"OS"));
  1185. CleanUpIfFailedAndSetHr(xmlSpec.AddLocale(bstrTemp, &hLocale));
  1186. SafeSysFreeString(bstrTemp);
  1187. LookupLocaleString((LPTSTR) szLang, ARRAYSIZE(szLang), fIsUser ? TRUE : FALSE);
  1188. CleanUpFailedAllocSetHrMsg(bstrTemp = T2BSTR(szLang));
  1189. CleanUpIfFailedAndSetHr(xmlSpec.AddLanguage(hLocale, bstrTemp));
  1190. SafeSysFreeString(bstrTemp);
  1191. xmlSpec.SafeCloseHandleNode(hLocale);
  1192. CleanUp:
  1193. if (HANDLE_NODE_INVALID != hLocale)
  1194. {
  1195. xmlSpec.SafeCloseHandleNode(hLocale);
  1196. }
  1197. SysFreeString(bstrTemp);
  1198. return hr;
  1199. }
  1200. ////////////////////////////////////////////////////////////////////////////////////////
  1201. //
  1202. // NOTE: Caller must clean up heap allocations made for *ppszMatchingID and *ppszDriverVer
  1203. //
  1204. ////////////////////////////////////////////////////////////////////////////////////////
  1205. HRESULT GetMatchingDeviceID(HDEVINFO hDevInfoSet, PSP_DEVINFO_DATA pDevInfoData, LPTSTR* ppszMatchingID, LPTSTR* ppszDriverVer)
  1206. {
  1207. LOG_Block("GetMatchingDeviceID");
  1208. HKEY hDevRegKey = (HKEY) INVALID_HANDLE_VALUE;
  1209. HRESULT hr = S_OK;
  1210. if (NULL == ppszMatchingID || NULL == ppszDriverVer)
  1211. {
  1212. LOG_ErrorMsg(E_INVALIDARG);
  1213. return E_INVALIDARG;
  1214. }
  1215. OSVERSIONINFOEX verInfoEx;
  1216. ZeroMemory(&verInfoEx, sizeof(verInfoEx));
  1217. *ppszMatchingID = NULL;
  1218. *ppszDriverVer = NULL;
  1219. //
  1220. // Get the MatchingDeviceID and DriverDate (succeedes only if driver is already installed)
  1221. //
  1222. if (INVALID_HANDLE_VALUE == (hDevRegKey = SetupDiOpenDevRegKey(hDevInfoSet, pDevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ)))
  1223. {
  1224. LOG_Driver(_T("Optional SetupDiOpenDevRegKey returned INVALID_HANDLE_VALUE"));
  1225. }
  1226. else
  1227. {
  1228. int cchValueSize = 0;
  1229. hr = SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_MATCHINGDEVID, NULL, 0, &cchValueSize);
  1230. if (REG_E_MORE_DATA != hr || 0 == cchValueSize)
  1231. {
  1232. LOG_Driver(_T("Driver doesn't have a matching ID"));
  1233. //
  1234. // This is not an error
  1235. //
  1236. hr = S_OK;
  1237. }
  1238. else
  1239. {
  1240. //
  1241. // Sanity check size of data in registry
  1242. //
  1243. if (MAX_INF_STRING_LEN < cchValueSize)
  1244. {
  1245. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  1246. }
  1247. //
  1248. // MatchingDeviceID
  1249. //
  1250. // Add extra character of zero'ed memory for safety
  1251. //
  1252. CleanUpFailedAllocSetHrMsg(*ppszMatchingID = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (cchValueSize + 1) * sizeof(TCHAR)));
  1253. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_MATCHINGDEVID, *ppszMatchingID, cchValueSize, &cchValueSize));
  1254. //
  1255. // We got the matching ID, now do our best to get DriverVer (prefer from registry)
  1256. //
  1257. hr = SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_DRIVERDATE, NULL, 0, &cchValueSize);
  1258. if (REG_E_MORE_DATA != hr || 0 == cchValueSize)
  1259. {
  1260. LOG_Error(_T("No DRIVERDATE registry key, search the INF"));
  1261. //
  1262. // Search the INF and driver files for a date
  1263. //
  1264. if (FAILED(hr = GetDriverDateFromInf(hDevRegKey, hDevInfoSet, *pDevInfoData, ppszDriverVer)))
  1265. {
  1266. //
  1267. // Use a default driver date
  1268. //
  1269. CleanUpFailedAllocSetHrMsg(*ppszDriverVer = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SIZEOF_DRIVERVER));
  1270. hr = StringCbCopyEx(*ppszDriverVer, SIZEOF_DRIVERVER, SZ_UNKNOWN_DRIVERVER,
  1271. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1272. CleanUpIfFailedAndSetHrMsg(hr);
  1273. }
  1274. }
  1275. else
  1276. {
  1277. //
  1278. // Sanity check size of data in registry
  1279. //
  1280. if (MAX_INF_STRING_LEN < cchValueSize)
  1281. {
  1282. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  1283. }
  1284. //
  1285. // Get the driver date from the registry
  1286. //
  1287. // Add extra character of zero'ed memory for safety
  1288. //
  1289. CleanUpFailedAllocSetHrMsg(*ppszDriverVer = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (cchValueSize + 1) * sizeof(TCHAR)));
  1290. CleanUpIfFailedAndSetHrMsg(SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_DRIVERDATE, *ppszDriverVer, cchValueSize, &cchValueSize));
  1291. //
  1292. // Convert to ISO 8601 format
  1293. //
  1294. CleanUpIfFailedAndSetHr(DriverVerToIso8601(ppszDriverVer));
  1295. #if defined(_UNICODE) || defined(UNICODE)
  1296. //
  1297. // 645161 Driver Ver Version to be returned to driver query.asp for WUPM 1.2 Release Timeframe
  1298. //
  1299. // Optionally add DriverVer version to date. NOTE: We don't attempt this unless we were able to get
  1300. // the DriverVer date via REGSTR_VAL_DRIVERDATE. Also, this is done only for WinXP SP1 up.
  1301. //
  1302. verInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1303. if (GetVersionEx((LPOSVERSIONINFO) &verInfoEx))
  1304. {
  1305. if (VER_PLATFORM_WIN32_NT == verInfoEx.dwPlatformId
  1306. && (
  1307. 5 < verInfoEx.dwMajorVersion // Longhorn
  1308. || (5 == verInfoEx.dwMajorVersion && 1 < verInfoEx.dwMinorVersion) // .NET Server
  1309. || (5 == verInfoEx.dwMajorVersion && 1 == verInfoEx.dwMinorVersion
  1310. && 0 < verInfoEx.wServicePackMajor) // WinXP with SP1 or greater
  1311. )
  1312. )
  1313. {
  1314. //
  1315. // Attempt to get the version, but fail isn't an error
  1316. //
  1317. cchValueSize = 0;
  1318. HRESULT hrVer = SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_DRIVERVERSION, NULL, 0, &cchValueSize);
  1319. if (REG_E_MORE_DATA != hrVer || 0 == cchValueSize)
  1320. {
  1321. LOG_Out(_T("No DRIVERVERSION registry key (optional)"));
  1322. }
  1323. else
  1324. {
  1325. TCHAR szTempVersion[MAX_INF_STRING_LEN];
  1326. //
  1327. // Sanity check size of data in registry
  1328. //
  1329. if (MAX_INF_STRING_LEN > cchValueSize)
  1330. {
  1331. if (S_OK == SafeRegQueryStringValueCch(hDevRegKey, REGSTR_VAL_DRIVERVERSION, (LPTSTR) szTempVersion, cchValueSize, &cchValueSize))
  1332. {
  1333. LPTSTR pszOldDriverVer = *ppszDriverVer;
  1334. int nDate = lstrlen(*ppszDriverVer);
  1335. //
  1336. // Original DriverVer date + DriverVer Version + "|" + NULL
  1337. //
  1338. int nDriverDateAndVer = (nDate + cchValueSize + 2) * sizeof(TCHAR);
  1339. *ppszDriverVer = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nDriverDateAndVer);
  1340. if (NULL == *ppszDriverVer)
  1341. {
  1342. //
  1343. // Log the error, but return the DriverVer date without version appended
  1344. //
  1345. LOG_ErrorMsg(ERROR_NOT_ENOUGH_MEMORY);
  1346. *ppszDriverVer = pszOldDriverVer;
  1347. }
  1348. else
  1349. {
  1350. if (SUCCEEDED(hrVer = StringCchPrintf(*ppszDriverVer, nDriverDateAndVer, _T("%s|%s"), pszOldDriverVer, (LPTSTR) szTempVersion)))
  1351. {
  1352. SafeHeapFree(pszOldDriverVer);
  1353. }
  1354. else
  1355. {
  1356. //
  1357. // Restore original DriverVer date and free new alloc
  1358. //
  1359. LOG_ErrorMsg(hrVer);
  1360. SafeHeapFree(*ppszDriverVer);
  1361. *ppszDriverVer = pszOldDriverVer;
  1362. }
  1363. }
  1364. }
  1365. }
  1366. }
  1367. }
  1368. }
  1369. #endif
  1370. }
  1371. }
  1372. }
  1373. CleanUp:
  1374. if (INVALID_HANDLE_VALUE != hDevRegKey)
  1375. {
  1376. RegCloseKey(hDevRegKey);
  1377. }
  1378. if (FAILED(hr))
  1379. {
  1380. SafeHeapFree(*ppszMatchingID);
  1381. SafeHeapFree(*ppszDriverVer);
  1382. }
  1383. return hr;
  1384. }
  1385. HRESULT AddDevicesClass(CXmlSystemSpec& xmlSpec, IU_PLATFORM_INFO iuPlatformInfo, BOOL fIsSysSpecCall)
  1386. {
  1387. USES_IU_CONVERSION;
  1388. LOG_Block("AddDevicesClass");
  1389. HRESULT hr = E_NOTIMPL;
  1390. LONG lRet;
  1391. BSTR bstrProvider = NULL;
  1392. BSTR bstrMfgName = NULL;
  1393. BSTR bstrName = NULL;
  1394. BSTR bstrHardwareID = NULL;
  1395. BSTR bstrDriverVer = NULL;
  1396. DWORD dwDeviceIndex = 0;
  1397. HDEVINFO hDevInfoSet = INVALID_HANDLE_VALUE;
  1398. HANDLE_NODE hPrinterDevNode = HANDLE_NODE_INVALID;
  1399. SP_DEVINFO_DATA devInfoData;
  1400. LPTSTR pszMatchingID = NULL;
  1401. LPTSTR pszDriverVer= NULL;
  1402. DRIVER_INFO_6* paDriverInfo6 = NULL;
  1403. DWORD dwDriverInfoCount = 0;
  1404. //
  1405. // We only enumerate drivers on Win2K up or Win98 up
  1406. //
  1407. if ( ( (VER_PLATFORM_WIN32_NT == iuPlatformInfo.osVersionInfoEx.dwPlatformId) &&
  1408. (4 < iuPlatformInfo.osVersionInfoEx.dwMajorVersion)
  1409. )
  1410. ||
  1411. ( (VER_PLATFORM_WIN32_WINDOWS == iuPlatformInfo.osVersionInfoEx.dwPlatformId) &&
  1412. ( (4 < iuPlatformInfo.osVersionInfoEx.dwMajorVersion) ||
  1413. ( (4 == iuPlatformInfo.osVersionInfoEx.dwMajorVersion) &&
  1414. (0 < iuPlatformInfo.osVersionInfoEx.dwMinorVersion) ) )
  1415. )
  1416. )
  1417. {
  1418. //
  1419. // Get array of DRIVER_INFO_6 holding info on installed printer drivers. Only allocates and returns
  1420. // memory for appropriate platforms that have printer drivers already installed.
  1421. //
  1422. CleanUpIfFailedAndSetHr(GetInstalledPrinterDriverInfo((OSVERSIONINFO*) &iuPlatformInfo.osVersionInfoEx, &paDriverInfo6, &dwDriverInfoCount));
  1423. if (INVALID_HANDLE_VALUE == (hDevInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES)))
  1424. {
  1425. LOG_Error(_T("SetupDiGetClassDevs failed: 0x%08x"), GetLastError());
  1426. return HRESULT_FROM_WIN32(GetLastError());
  1427. }
  1428. ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
  1429. devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1430. while (SetupDiEnumDeviceInfo(hDevInfoSet, dwDeviceIndex++, &devInfoData))
  1431. {
  1432. //
  1433. // 656449 Controls Stops if it incounters a malformed Driver Date
  1434. //
  1435. // Just skip instances where getting the DriverVer returns an error
  1436. //
  1437. if SUCCEEDED(GetMatchingDeviceID(hDevInfoSet, &devInfoData, &pszMatchingID, &pszDriverVer))
  1438. {
  1439. //
  1440. // Write the Hardware & Compatible IDs to XML
  1441. //
  1442. CleanUpIfFailedAndSetHr(AddPrunedDevRegProps(hDevInfoSet, &devInfoData, xmlSpec, pszMatchingID, \
  1443. pszDriverVer, paDriverInfo6, dwDriverInfoCount, fIsSysSpecCall));
  1444. }
  1445. SafeHeapFree(pszMatchingID);
  1446. SafeHeapFree(pszDriverVer);
  1447. }
  1448. if (ERROR_NO_MORE_ITEMS != GetLastError())
  1449. {
  1450. Win32MsgSetHrGotoCleanup(GetLastError());
  1451. }
  1452. //
  1453. // Get the Printer "Hardware IDs" for Win2K up (already checked dwMajorVersion) & WinME
  1454. //
  1455. if (NULL != paDriverInfo6 && 0 != dwDriverInfoCount)
  1456. {
  1457. //
  1458. // Add the driver elements for each printer driver.
  1459. //
  1460. for (DWORD dwCount = 0; dwCount < dwDriverInfoCount; dwCount++)
  1461. {
  1462. if ( NULL == (paDriverInfo6 + dwCount)->pszHardwareID)
  1463. {
  1464. LOG_Driver(_T("Skiping driver with incomplete ID info"));
  1465. continue;
  1466. }
  1467. //
  1468. // Open a <device> element to write the printer info
  1469. //
  1470. CleanUpFailedAllocSetHrMsg(bstrProvider = T2BSTR((paDriverInfo6 + dwCount)->pszProvider));
  1471. CleanUpFailedAllocSetHrMsg(bstrMfgName = T2BSTR((paDriverInfo6 + dwCount)->pszMfgName));
  1472. CleanUpFailedAllocSetHrMsg(bstrName = T2BSTR((paDriverInfo6 + dwCount)->pName));
  1473. CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(NULL, 1, bstrProvider, bstrMfgName, bstrName, &hPrinterDevNode));
  1474. //
  1475. // Convert ftDriverDate to ISO 8601 prefered format (yyyy-mm-dd)
  1476. //
  1477. SYSTEMTIME systemTime;
  1478. if (0 == FileTimeToSystemTime(&((paDriverInfo6 + dwCount)->ftDriverDate), &systemTime))
  1479. {
  1480. LOG_Error(_T("FileTimeToSystemTime failed:"));
  1481. LOG_ErrorMsg(GetLastError());
  1482. SetHrAndGotoCleanUp(HRESULT_FROM_WIN32(GetLastError()));
  1483. }
  1484. TCHAR szDriverVer[11];
  1485. hr = StringCchPrintfEx(szDriverVer, ARRAYSIZE(szDriverVer), NULL, NULL, MISTSAFE_STRING_FLAGS,
  1486. _T("%04d-%02d-%02d"), systemTime.wYear, systemTime.wMonth, systemTime.wDay);
  1487. if (FAILED(hr))
  1488. {
  1489. LOG_Error(_T("wsprintf failed:"));
  1490. LOG_ErrorMsg(GetLastError());
  1491. SetHrAndGotoCleanUp(HRESULT_FROM_WIN32(GetLastError()));
  1492. }
  1493. // Always rank 0 and never fIsCompatible
  1494. CleanUpFailedAllocSetHrMsg(bstrHardwareID = T2BSTR((paDriverInfo6 + dwCount)->pszHardwareID));
  1495. CleanUpFailedAllocSetHrMsg(bstrDriverVer = T2BSTR(szDriverVer));
  1496. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hPrinterDevNode, FALSE, 0, bstrHardwareID, bstrDriverVer));
  1497. xmlSpec.SafeCloseHandleNode(hPrinterDevNode);
  1498. //
  1499. // 514009 Apparent memory leak in getting info - Getsystemspec increases memory
  1500. // consumption as follows - approximately 32 Kb when successfully called with all
  1501. // class types (also approximately 8 Kb on failed call to get iexplorer server context)
  1502. //
  1503. // T2BSTR macro calls SysAllocString()
  1504. //
  1505. SafeSysFreeString(bstrProvider);
  1506. SafeSysFreeString(bstrMfgName);
  1507. SafeSysFreeString(bstrName);
  1508. SafeSysFreeString(bstrHardwareID);
  1509. SafeSysFreeString(bstrDriverVer);
  1510. }
  1511. }
  1512. }
  1513. CleanUp:
  1514. if (INVALID_HANDLE_VALUE != hDevInfoSet)
  1515. {
  1516. if (0 == SetupDiDestroyDeviceInfoList(hDevInfoSet))
  1517. {
  1518. LOG_Driver(_T("Warning: SetupDiDestroyDeviceInfoList failed: 0x%08x"), GetLastError());
  1519. }
  1520. }
  1521. if (HANDLE_NODE_INVALID != hPrinterDevNode)
  1522. {
  1523. xmlSpec.SafeCloseHandleNode(hPrinterDevNode);
  1524. }
  1525. SafeHeapFree(pszMatchingID);
  1526. SafeHeapFree(pszDriverVer);
  1527. SafeHeapFree(paDriverInfo6);
  1528. SysFreeString(bstrProvider);
  1529. SysFreeString(bstrMfgName);
  1530. SysFreeString(bstrName);
  1531. SysFreeString(bstrHardwareID);
  1532. SysFreeString(bstrDriverVer);
  1533. return hr;
  1534. }
  1535. /////////////////////////////////////////////////////////////////////////////
  1536. // GetSystemSpec()
  1537. //
  1538. // Gets the basic system specs.
  1539. // Input:
  1540. // bstrXmlClasses - a list of requested classes in xml format, NULL BSTR if all.
  1541. // For example:
  1542. // <?xml version=\"1.0\"?>
  1543. // <classes xmlns=\"file://\\kingbird\winupddev\Slm\src\Specs\v4\systeminfoclassschema.xml\">
  1544. // <computerSystem/>
  1545. // <regKeys/>
  1546. // <platform/>
  1547. // <locale/>
  1548. // <devices/>
  1549. // </classes>
  1550. // Where all of the classes are optional.
  1551. //
  1552. // Return:
  1553. // pbstrXmlDetectionResult - the detection result in xml format.
  1554. /////////////////////////////////////////////////////////////////////////////
  1555. HRESULT WINAPI CEngUpdate::GetSystemSpec(BSTR bstrXmlClasses, DWORD dwFlags, BSTR *pbstrXmlDetectionResult)
  1556. {
  1557. USES_IU_CONVERSION;
  1558. LOG_Block("GetSystemSpec");
  1559. //
  1560. // By default we return all <classes/>
  1561. //
  1562. DWORD dwClasses = (COMPUTERSYSTEM | REGKEYS | PLATFORM | LOCALE | DEVICES);
  1563. HRESULT hr = S_OK;
  1564. IU_PLATFORM_INFO iuPlatformInfo;
  1565. CXmlSystemSpec xmlSpec;
  1566. if (NULL == pbstrXmlDetectionResult)
  1567. {
  1568. LOG_ErrorMsg(E_INVALIDARG);
  1569. return E_INVALIDARG;
  1570. }
  1571. *pbstrXmlDetectionResult = NULL;
  1572. //
  1573. // We have to init iuPlatformInfo (redundant) because we may goto CleanUp before calling DetectClientIUPlatform
  1574. //
  1575. ZeroMemory(&iuPlatformInfo, sizeof(iuPlatformInfo));
  1576. // Set Global Offline Flag - checked by XML Classes to disable Validation (schemas are on the net)
  1577. if (dwFlags & FLAG_OFFLINE_MODE)
  1578. {
  1579. m_fOfflineMode = TRUE;
  1580. }
  1581. else
  1582. {
  1583. m_fOfflineMode = FALSE;
  1584. }
  1585. //
  1586. // 494519 A call to GetSystemSpec with bstrXmlClasses that is less then 10 character suceeds, weather it is valid or invalid XML.
  1587. //
  1588. // If client passes us anything it must be well formed [and possibly valid] XML
  1589. //
  1590. // But, allow BSTRs of length 0 to be treated the same as a NULL BSTR
  1591. // (497059 A call to GetSystemSpec with bstrXmlClasses equal
  1592. // to empty string fails.)
  1593. //
  1594. if (NULL != bstrXmlClasses && SysStringLen(bstrXmlClasses) > 0)
  1595. {
  1596. CXmlSystemClass xmlClass;
  1597. if (FAILED(hr = xmlClass.LoadXMLDocument(bstrXmlClasses, m_fOfflineMode)))
  1598. {
  1599. //
  1600. // They probably passed us invalid XML
  1601. //
  1602. goto CleanUp;
  1603. }
  1604. dwClasses = xmlClass.GetClasses();
  1605. }
  1606. //
  1607. // Add the ComputerSystem node
  1608. //
  1609. if (dwClasses & COMPUTERSYSTEM)
  1610. {
  1611. CleanUpIfFailedAndSetHr(AddComputerSystemClass(xmlSpec));
  1612. }
  1613. //
  1614. // Enumerate and add the Software RegKey elements
  1615. //
  1616. if (dwClasses & REGKEYS)
  1617. {
  1618. CleanUpIfFailedAndSetHr(AddRegKeyClass(xmlSpec));
  1619. }
  1620. //
  1621. // We need iuPlatformInfo for both <platform> and <devices> elements
  1622. //
  1623. if (dwClasses & (PLATFORM | DEVICES))
  1624. {
  1625. CleanUpIfFailedAndSetHr(DetectClientIUPlatform(&iuPlatformInfo));
  1626. }
  1627. //
  1628. // Add Platform
  1629. //
  1630. if (dwClasses & PLATFORM)
  1631. {
  1632. CleanUpIfFailedAndSetHr(AddPlatformClass(xmlSpec, iuPlatformInfo));
  1633. }
  1634. //
  1635. // Add Locale information
  1636. //
  1637. if (dwClasses & LOCALE)
  1638. {
  1639. //
  1640. // OS locale
  1641. //
  1642. CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, FALSE));
  1643. //
  1644. // USER locale
  1645. //
  1646. CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, TRUE));
  1647. }
  1648. //
  1649. // Add devices
  1650. //
  1651. if (dwClasses & DEVICES)
  1652. {
  1653. CleanUpIfFailedAndSetHr(AddDevicesClass(xmlSpec, iuPlatformInfo, TRUE));
  1654. }
  1655. CleanUp:
  1656. //
  1657. // Only return S_OK for success (S_FALSE sometimes drops through from above)
  1658. //
  1659. if (S_FALSE == hr)
  1660. {
  1661. hr = S_OK;
  1662. }
  1663. if (SUCCEEDED(hr))
  1664. {
  1665. //
  1666. // Return the spec as a BSTR
  1667. //
  1668. hr = xmlSpec.GetSystemSpecBSTR(pbstrXmlDetectionResult);
  1669. }
  1670. if (SUCCEEDED(hr))
  1671. {
  1672. LogMessage(SZ_GET_SYSTEM_SPEC);
  1673. }
  1674. else
  1675. {
  1676. LogError(hr, SZ_GET_SYSTEM_SPEC);
  1677. //
  1678. // If the DOM allocates but returns error, we will leak, but
  1679. // this is safer than calling SysFreeString()
  1680. //
  1681. *pbstrXmlDetectionResult = NULL;
  1682. }
  1683. SysFreeString(iuPlatformInfo.bstrOEMManufacturer);
  1684. SysFreeString(iuPlatformInfo.bstrOEMModel);
  1685. SysFreeString(iuPlatformInfo.bstrOEMSupportURL);
  1686. return hr;
  1687. }
  1688. // Function name : GetSystemPID
  1689. // Description : This method basically obtaing the encrypted version of the System PID
  1690. // This method also converts the binary blob in to string format
  1691. // Return type : HRESULT
  1692. // Argument : BSTR &bstrPID --containg the hex encoded string
  1693. // author :a-vikuma
  1694. HRESULT GetSystemPID(BSTR &bstrPID)
  1695. {
  1696. LOG_Block("GetSystemPID");
  1697. HRESULT hr = S_OK;
  1698. HMODULE hLicDll = NULL;
  1699. PFUNCGetEncryptedPID pPIDEncrProc = NULL;
  1700. BYTE *pByte = NULL;
  1701. DWORD dwLen = 0;
  1702. LPWSTR lpszData = NULL;
  1703. if(bstrPID)
  1704. {
  1705. bstrPID = NULL;
  1706. }
  1707. //load the pid encryption library
  1708. hLicDll = LoadLibraryFromSystemDir(SZ_LICDLL);
  1709. if (!hLicDll)
  1710. {
  1711. hr = HRESULT_FROM_WIN32(GetLastError());
  1712. goto CleanUp;
  1713. }
  1714. //get the pointer to GetEncryptedPID method
  1715. pPIDEncrProc = (PFUNCGetEncryptedPID)GetProcAddress(hLicDll, lpszIVLK_GetEncPID);
  1716. if (!pPIDEncrProc)
  1717. {
  1718. hr = HRESULT_FROM_WIN32(GetLastError());
  1719. goto CleanUp;
  1720. }
  1721. CleanUpIfFailedAndSetHrMsg(pPIDEncrProc(&pByte, &dwLen));
  1722. DWORD dwSize = 0;
  1723. //convert the binary stream to string format
  1724. //initially get the length for the string buffer
  1725. CleanUpIfFailedAndSetHrMsg(BinaryToString(pByte, dwLen, lpszData, &dwSize));
  1726. //allocate memory
  1727. CleanUpFailedAllocSetHrMsg( lpszData = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize*sizeof(WCHAR)));
  1728. //get the binary blob in string format
  1729. CleanUpIfFailedAndSetHrMsg(BinaryToString(pByte, dwLen, lpszData, &dwSize));
  1730. //convert the LPWSTR to a BSTR
  1731. CleanUpFailedAllocSetHrMsg(bstrPID = SysAllocString(lpszData));
  1732. CleanUp:
  1733. if(hLicDll)
  1734. FreeLibrary(hLicDll);
  1735. SafeHeapFree(lpszData);
  1736. //LocalFree can take nulls. So not checked if pByte is null
  1737. LocalFree(pByte);
  1738. if(FAILED(hr))
  1739. {
  1740. SysFreeString(bstrPID);
  1741. bstrPID = NULL;
  1742. }
  1743. return hr;
  1744. }
  1745. // Function name : HexEncode
  1746. // Description : This is a helper function to convert a binary stream in to string format
  1747. // Return type : DWORD
  1748. // Argument : IN BYTE const *pbIn
  1749. // Argument : DWORD cbIn
  1750. // Argument : WCHAR *pchOut
  1751. // Argument : DWORD *pcchOut
  1752. DWORD HexEncode(IN BYTE const *pbIn, DWORD cbIn, WCHAR *pchOut, DWORD *pcchOut)
  1753. {
  1754. WCHAR *pszsep;
  1755. WCHAR *psznl;
  1756. DWORD nCount;
  1757. DWORD cbremain;
  1758. DWORD cchOut = 0;
  1759. //each byte needs two characters for encoding
  1760. DWORD cch = 2;
  1761. WCHAR *pch = pchOut;
  1762. DWORD dwErr = ERROR_INSUFFICIENT_BUFFER;
  1763. DWORD dwRem = *pcchOut;
  1764. HRESULT hr = S_OK;
  1765. for (nCount = 0; nCount < cbIn; nCount ++)
  1766. {
  1767. if (NULL != pchOut)
  1768. {
  1769. if (cchOut + cch + 1 > *pcchOut)
  1770. {
  1771. goto ErrorReturn;
  1772. }
  1773. hr = StringCchPrintfW(pch, dwRem, L"%02x", pbIn[nCount]);
  1774. if(FAILED(hr))
  1775. {
  1776. dwErr = HRESULT_CODE(hr);
  1777. goto ErrorReturn;
  1778. }
  1779. pch += cch;
  1780. dwRem -= cch;
  1781. }
  1782. cchOut += cch;
  1783. }
  1784. if (NULL != pchOut)
  1785. {
  1786. *pch = L'\0';
  1787. }
  1788. *pcchOut = cchOut+1;
  1789. dwErr = ERROR_SUCCESS;
  1790. ErrorReturn:
  1791. return(dwErr);
  1792. }
  1793. // Function name : BinaryToString
  1794. // Description : This function converts a binary stream in to a string format
  1795. // Return type : HRESULT
  1796. // Argument : BYTE *lpBinary --The binary stream
  1797. // Argument : DWORD dwLength --The length of the stream
  1798. // Argument : LPWSTR lpString --Pointer to the string which contains the converted encoded data on return
  1799. // If this parameter is NULL the DWORD pointed ny pdwLength parameter contains to the size of the buffer needed to hold
  1800. // the encoded data
  1801. // Argument : DWORD *pdwLength --pointer to the zise of the string buffer in no of characters
  1802. HRESULT BinaryToString(BYTE *lpBinary, DWORD dwLength, LPWSTR lpString, DWORD *pdwLength)
  1803. {
  1804. HRESULT hr = S_OK;
  1805. if(!lpBinary || !pdwLength)
  1806. return E_INVALIDARG;
  1807. DWORD dwStatus = HexEncode(lpBinary, dwLength, lpString, pdwLength);
  1808. if(ERROR_SUCCESS != dwStatus)
  1809. {
  1810. hr = HRESULT_FROM_WIN32(dwStatus);
  1811. }
  1812. return hr;
  1813. }