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

897 lines
25 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: cdmi.cpp
  6. //
  7. // Description:
  8. //
  9. // Functions exported by IUEngine.dll for use by CDM.DLL
  10. //
  11. // InternalDetFilesDownloaded
  12. // InternalDownloadGetUpdatedFiles
  13. // InternalDownloadUpdatedFiles
  14. // InternalFindMatchingDriver
  15. // InternalLogDriverNotFound
  16. // InternalQueryDetectionFiles
  17. //
  18. //=======================================================================
  19. #include "iuengine.h"
  20. #include "cdmp.h"
  21. #include <setupapi.h>
  22. #include <cfgmgr32.h>
  23. #include <shlwapi.h>
  24. #include <shellapi.h>
  25. #include <wininet.h>
  26. #include <osdet.h>
  27. #include <fileutil.h>
  28. #include "iuxml.h"
  29. #include <wuiutest.h>
  30. const CHAR SZ_APW_LIST[] = "Downloading printer list for Add Printer Wizard";
  31. const CHAR SZ_FIND_MATCH[] = "Finding matching driver";
  32. const CHAR SZ_OPENING_HS[] = "Opening Help and Support with: ";
  33. void WINAPI InternalDetFilesDownloaded(
  34. IN HANDLE hConnection
  35. )
  36. {
  37. LOG_Block("InternalDetFilesDownloaded");
  38. //
  39. // NOTE: This function is only used by WinME to expand the
  40. // V3 buckets.cab (see commented out code below) and has no use
  41. // in V4 (IU) but remains for backwards compatibility of the export API.
  42. //
  43. LOG_ErrorMsg(E_NOTIMPL);
  44. }
  45. // Win 98 entry point
  46. // This function allows Windows 98 to call the same entry points as NT.
  47. // The function returns TRUE if the download succeeds and FALSE if it
  48. // does not.
  49. //
  50. // Win 98 DOWNLOADINFO
  51. // typedef struct _DOWNLOADINFOWIN98
  52. // {
  53. // DWORD dwDownloadInfoSize; // size of this structure - validate param (not validated in V3)
  54. // LPTSTR lpHardwareIDs; // multi_sz list of Hardware PnP IDs - only use first string
  55. // LPTSTR lpCompatIDs; // multi_sz list of compatible IDs - never used
  56. // LPTSTR lpFile; // File name (string) - never used
  57. // OSVERSIONINFO OSVersionInfo; //OSVERSIONINFO from GetVersionEx() - never used
  58. // DWORD dwFlags; //Flags - never used
  59. // DWORD dwClientID; //Client ID - never used
  60. // } DOWNLOADINFOWIN98, *PDOWNLOADINFOWIN98;
  61. //
  62. // typedef struct _DOWNLOADINFO {
  63. // DWORD dwDownloadInfoSize;
  64. // LPCWSTR lpHardwareIDs; - copied from DOWNLOADINFOWIN98 using T2OLE()
  65. // LPCWSTR lpDeviceInstanceID; - in V3, match was sometimes found and this was filled in
  66. // - but for IU we just let InternalDownloadUpdatedFiles do it all
  67. // LPCWSTR lpFile;
  68. // OSVERSIONINFOW OSVersionInfo;
  69. // DWORD dwArchitecture; - set to PROCESSOR_ARCHITECTURE_UNKNOWN per V3 code
  70. // DWORD dwFlags;
  71. // DWORD dwClientID;
  72. // LCID localid; - not set in V3
  73. // } DOWNLOADINFO, *PDOWNLOADINFO;
  74. BOOL InternalDownloadGetUpdatedFiles(
  75. IN PDOWNLOADINFOWIN98 pDownloadInfoWin98, //The win98 download info structure is
  76. //slightly different that the NT version
  77. //so this function handles conversion.
  78. IN OUT LPTSTR lpDownloadPath, //returned Download path to the downloaded
  79. //cab files.
  80. IN UINT uSize //size of passed in download path buffer.
  81. ) {
  82. USES_IU_CONVERSION;
  83. LOG_Block("InternalDownloadGetUpdatedFiles");
  84. if (NULL == pDownloadInfoWin98 ||
  85. NULL == pDownloadInfoWin98->lpHardwareIDs ||
  86. sizeof(DOWNLOADINFOWIN98) != pDownloadInfoWin98->dwDownloadInfoSize)
  87. {
  88. LOG_ErrorMsg(E_INVALIDARG);
  89. return FALSE;
  90. }
  91. HRESULT hr;
  92. BOOL fOK = FALSE;
  93. DOWNLOADINFO info;
  94. ZeroMemory(&info, sizeof(info));
  95. info.dwDownloadInfoSize = sizeof(DOWNLOADINFO);
  96. info.dwArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  97. //
  98. // NOTE: In V3 sources, we only use the _first_ HWID in the Multi_SZ pDownloadInfoWin98->lpHardwareIDs
  99. // and compare that against all enumerated hardware IDs.
  100. // In IU, this compare will be done in InternalDownloadUpdatedFiles, so we just pass through
  101. // the HWID
  102. //
  103. // Prefast - using too much stack, so move HWIDBuff to heap
  104. LPWSTR pwszHWIDBuff = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, HWID_LEN);
  105. if (NULL != pwszHWIDBuff)
  106. {
  107. // buffer size obtained from HeapAlloc call above.
  108. hr = StringCbCopyExW(pwszHWIDBuff, HWID_LEN, T2OLE(pDownloadInfoWin98->lpHardwareIDs),
  109. NULL, NULL, MISTSAFE_STRING_FLAGS);
  110. if (FAILED(hr))
  111. {
  112. SafeHeapFree(pwszHWIDBuff);
  113. LOG_ErrorMsg(hr);
  114. return FALSE;
  115. }
  116. info.lpHardwareIDs = pwszHWIDBuff;
  117. WCHAR wszbufPath[MAX_PATH];
  118. UINT uRequiredSize;
  119. //
  120. // We no longer have context handles, so just pass 1 to make InternalDownloadUpdatedFiles happy.
  121. //
  122. fOK = InternalDownloadUpdatedFiles((HANDLE) 1, NULL, &info, wszbufPath,
  123. uSize * (sizeof(WCHAR)/sizeof(TCHAR)), &uRequiredSize);
  124. }
  125. else
  126. {
  127. LOG_ErrorMsg(E_OUTOFMEMORY);
  128. }
  129. if (fOK)
  130. {
  131. hr = StringCbCopyEx(lpDownloadPath, uSize, OLE2T(pwszHWIDBuff),
  132. NULL, NULL, MISTSAFE_STRING_FLAGS | STRSAFE_NO_TRUNCATION);
  133. if (FAILED(hr))
  134. fOK = FALSE;
  135. }
  136. SafeHeapFree(pwszHWIDBuff);
  137. return fOK;
  138. }
  139. //This function downloads the specified CDM package. The hConnection handle must have
  140. //been returned from the OpenCDMContext() API.
  141. //
  142. //This function Returns TRUE if download is successful GetLastError() will return
  143. //the error code indicating the reason that the call failed.
  144. BOOL WINAPI InternalDownloadUpdatedFiles(
  145. IN HANDLE hConnection, //Connection handle from OpenCDMContext() API.
  146. IN HWND hwnd, //Window handle for call context
  147. IN PDOWNLOADINFO pDownloadInfo, //download information structure describing
  148. //package to be read from server
  149. OUT LPWSTR lpDownloadPath, //local computer directory location of the
  150. //downloaded files
  151. IN UINT uSize, // Not Used (we require the buffer to be a WCHAR buffer
  152. // MAX_PATH characters long)
  153. OUT PUINT /*puRequiredSize*/ // Not used (we don't validate uSize - see comments inline)
  154. ) {
  155. USES_IU_CONVERSION;
  156. LOG_Block("InternalDownloadUpdatedFiles");
  157. TCHAR szDownloadPathTmp[MAX_PATH];
  158. BSTR bstrXmlCatalog = NULL;
  159. HRESULT hr = S_OK;
  160. BOOL fPlist = FALSE;
  161. if (NULL == g_pCDMEngUpdate)
  162. {
  163. SetLastError(ERROR_OUTOFMEMORY);
  164. return FALSE;
  165. }
  166. //
  167. // Reset Quit Event in case client retries after a SetOperationMode
  168. //
  169. ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
  170. // Since all current platforms call DownloadUpdatedFiles with MAX_PATH TCHARS, we will just
  171. // require MAX_PATH for all callers.
  172. //
  173. // UNFORTUNATELY, NewDev passes up uSize in bytes and the Printer folks pass us characters,
  174. // so there is no way to validate this parameter. In addition, we won't bother validating
  175. // puRequiredSize since we never use it (would be return chars or bytes?)
  176. if (NULL == pDownloadInfo || NULL == lpDownloadPath || NULL == hConnection)
  177. {
  178. SetLastError(ERROR_INVALID_PARAMETER);
  179. return FALSE;
  180. }
  181. if (g_pCDMEngUpdate->m_fOfflineMode)
  182. {
  183. SetLastError(ERROR_REM_NOT_LIST);
  184. return FALSE;
  185. }
  186. //
  187. // Check to see if this is a printer catalog request. Note: 3FBF5B30-DEB4-11D1-AC97-00A0C903492B
  188. // is not defined in any system or private headers and is copied from
  189. // \\index2\ntsrc\printscan\print\spooler\splsetup\util.c (or equiv.)
  190. //
  191. // Only the first string passed in lpHardwareIDs is relevant to this test
  192. fPlist = ( NULL != pDownloadInfo->lpHardwareIDs &&
  193. CSTR_EQUAL == CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE,
  194. L"3FBF5B30-DEB4-11D1-AC97-00A0C903492B", -1, pDownloadInfo->lpHardwareIDs, -1)
  195. );
  196. OSVERSIONINFO osVersionInfo;
  197. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFO));
  198. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  199. if (!GetVersionEx(&osVersionInfo))
  200. {
  201. Win32MsgSetHrGotoCleanup(GetLastError());
  202. }
  203. //
  204. // Only support printers for Win2K up & WinME
  205. //
  206. if ( fPlist &&
  207. !( ( // Win2K (NT 5.0) up
  208. (VER_PLATFORM_WIN32_NT == osVersionInfo.dwPlatformId) &&
  209. (4 < osVersionInfo.dwMajorVersion)
  210. )
  211. ||
  212. ( // WinME (or higher)
  213. (VER_PLATFORM_WIN32_WINDOWS == osVersionInfo.dwPlatformId) &&
  214. (90 <= osVersionInfo.dwMinorVersion)
  215. )
  216. )
  217. )
  218. {
  219. CleanUpIfFailedAndSetHrMsg(E_NOTIMPL);
  220. }
  221. hr = GetPackage(fPlist ? GET_PRINTER_INFS : DOWNLOAD_DRIVER,
  222. pDownloadInfo, szDownloadPathTmp, ARRAYSIZE(szDownloadPathTmp), &bstrXmlCatalog);
  223. if (FAILED(hr))
  224. {
  225. lpDownloadPath[0] = 0;
  226. //
  227. // Map an HRESULT to a WIN32 error value
  228. // Note: This assumes that WIN32 errors fall in the range -32k to 32k,
  229. // same as HRESULT_FROM_WIN32 that packaged them into HRESULT.
  230. //
  231. SetLastError(hr & 0x0000FFFF);
  232. goto CleanUp;
  233. }
  234. else
  235. {
  236. // The comment above says that different callers pass in different types
  237. // of values for uSize, so the function assumes that the buffer is MAX_PATH.
  238. // Attempting to find out if we can force callers into this function to
  239. // do the right thing. For now, assume buffer is MAX_PATH.
  240. hr = StringCchCopyExW(lpDownloadPath, MAX_PATH, T2OLE(szDownloadPathTmp),
  241. NULL, NULL, MISTSAFE_STRING_FLAGS);
  242. if (FAILED(hr))
  243. {
  244. SetLastError(HRESULT_CODE(hr));
  245. goto CleanUp;
  246. }
  247. LOG_Driver(_T("Downloaded files for %s located at %S"), pDownloadInfo->lpHardwareIDs, lpDownloadPath);
  248. goto CleanUp;
  249. }
  250. CleanUp:
  251. SysFreeString(bstrXmlCatalog);
  252. if (fPlist)
  253. {
  254. if (SUCCEEDED(hr))
  255. {
  256. LogMessage(SZ_APW_LIST);
  257. }
  258. else
  259. {
  260. LogError(hr, SZ_APW_LIST);
  261. }
  262. }
  263. else
  264. {
  265. if (SUCCEEDED(hr))
  266. {
  267. LogMessage("Downloaded driver for %ls at %ls", pDownloadInfo->lpHardwareIDs, lpDownloadPath);
  268. }
  269. else
  270. {
  271. LogError(hr, "Driver download failed for %ls", pDownloadInfo->lpHardwareIDs);
  272. }
  273. }
  274. return SUCCEEDED(hr);
  275. }
  276. BOOL WINAPI InternalFindMatchingDriver(
  277. IN HANDLE hConnection,
  278. IN PDOWNLOADINFO pDownloadInfo,
  279. OUT PWUDRIVERINFO pWuDriverInfo
  280. ) {
  281. LOG_Block("InternalFindMatchingDriver");
  282. BSTR bstrXmlCatalog = NULL;
  283. BSTR bstrHWID = NULL;
  284. BSTR bstrDisplayName = NULL;
  285. BSTR bstrDriverName = NULL;
  286. BSTR bstrMfgName = NULL;
  287. BSTR bstrDriverProvider = NULL;
  288. BSTR bstrDriverVer = NULL;
  289. BSTR bstrArchitecture = NULL;
  290. HRESULT hr = S_OK;
  291. CXmlCatalog* pCatalog = NULL;
  292. HANDLE_NODE hCatalogItem;
  293. HANDLE_NODE hProvider;
  294. HANDLE_NODELIST hItemList;
  295. HANDLE_NODELIST hProviderList;
  296. BOOL fIsPrinter;
  297. if (NULL == g_pCDMEngUpdate)
  298. {
  299. SetLastError(ERROR_OUTOFMEMORY);
  300. return FALSE;
  301. }
  302. //
  303. // Reset Quit Event in case client retries after a SetOperationMode
  304. //
  305. ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
  306. if (NULL == pDownloadInfo || NULL == pWuDriverInfo || NULL == hConnection)
  307. {
  308. SetLastError(ERROR_INVALID_PARAMETER);
  309. return FALSE;
  310. }
  311. if (g_pCDMEngUpdate->m_fOfflineMode)
  312. {
  313. SetLastError(ERROR_REM_NOT_LIST);
  314. return FALSE;
  315. }
  316. CleanUpFailedAllocSetHrMsg(pCatalog = (CXmlCatalog*) new CXmlCatalog);
  317. //
  318. // Get the catalog XML
  319. //
  320. CleanUpIfFailedAndSetHr(GetPackage(GET_CATALOG_XML, pDownloadInfo, NULL, 0, &bstrXmlCatalog));
  321. //
  322. // Load the XML and get the <item/> list and node of first item (only one in CDM case)
  323. //
  324. CleanUpIfFailedAndSetHr(pCatalog->LoadXMLDocument(bstrXmlCatalog, g_pCDMEngUpdate->m_fOfflineMode));
  325. hProviderList = pCatalog->GetFirstProvider(&hProvider);
  326. if (HANDLE_NODELIST_INVALID == hProviderList || HANDLE_NODE_INVALID == hProvider)
  327. {
  328. hr = S_FALSE;
  329. goto CleanUp;
  330. }
  331. hItemList = pCatalog->GetFirstItem(hProvider, &hCatalogItem);
  332. if (HANDLE_NODELIST_INVALID == hItemList || HANDLE_NODE_INVALID == hProvider)
  333. {
  334. hr = S_FALSE;
  335. goto CleanUp;
  336. }
  337. //
  338. // Populate pWuDriverInfo with data from the catalog
  339. //
  340. CleanUpIfFailedAndSetHr(pCatalog->GetDriverInfoEx(hCatalogItem,
  341. &fIsPrinter,
  342. &bstrHWID,
  343. &bstrDriverVer,
  344. &bstrDisplayName,
  345. &bstrDriverName,
  346. &bstrDriverProvider,
  347. &bstrMfgName,
  348. &bstrArchitecture));
  349. hr = StringCchCopyExW(pWuDriverInfo->wszHardwareID,
  350. ARRAYSIZE(pWuDriverInfo->wszHardwareID),
  351. bstrHWID,
  352. NULL, NULL, MISTSAFE_STRING_FLAGS);
  353. if (FAILED(hr))
  354. goto CleanUp;
  355. hr = StringCchCopyExW(pWuDriverInfo->wszDescription,
  356. ARRAYSIZE(pWuDriverInfo->wszDescription),
  357. bstrDisplayName,
  358. NULL, NULL, MISTSAFE_STRING_FLAGS);
  359. if (FAILED(hr))
  360. goto CleanUp;
  361. //
  362. // Convert from ISO to DriverVer date format
  363. //
  364. // DriverVer: "mm-dd-yyyy" <--> ISO 8601: "yyyy-mm-dd"
  365. // index: 0123456789 0123456789
  366. //
  367. if (ARRAYSIZE(pWuDriverInfo->wszDriverVer) >= 11 &&
  368. SysStringLen(bstrDriverVer) == 10)
  369. {
  370. pWuDriverInfo->wszDriverVer[0] = bstrDriverVer[5];
  371. pWuDriverInfo->wszDriverVer[1] = bstrDriverVer[6];
  372. pWuDriverInfo->wszDriverVer[2] = L'-';
  373. pWuDriverInfo->wszDriverVer[3] = bstrDriverVer[8];
  374. pWuDriverInfo->wszDriverVer[4] = bstrDriverVer[9];
  375. pWuDriverInfo->wszDriverVer[5] = L'-';
  376. pWuDriverInfo->wszDriverVer[6] = bstrDriverVer[0];
  377. pWuDriverInfo->wszDriverVer[7] = bstrDriverVer[1];
  378. pWuDriverInfo->wszDriverVer[8] = bstrDriverVer[2];
  379. pWuDriverInfo->wszDriverVer[9] = bstrDriverVer[3];
  380. pWuDriverInfo->wszDriverVer[10] = L'\0';
  381. }
  382. else
  383. {
  384. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  385. goto CleanUp;
  386. }
  387. if(fIsPrinter)
  388. {
  389. hr = StringCchCopyExW(pWuDriverInfo->wszMfgName,
  390. ARRAYSIZE(pWuDriverInfo->wszMfgName),
  391. bstrMfgName,
  392. NULL, NULL, MISTSAFE_STRING_FLAGS);
  393. if (FAILED(hr))
  394. goto CleanUp;
  395. hr = StringCchCopyExW(pWuDriverInfo->wszProviderName,
  396. ARRAYSIZE(pWuDriverInfo->wszProviderName),
  397. bstrDriverProvider,
  398. NULL, NULL, MISTSAFE_STRING_FLAGS);
  399. if (FAILED(hr))
  400. goto CleanUp;
  401. }
  402. CleanUp:
  403. if (S_OK == hr)
  404. {
  405. LogMessage("Found matching driver for %ls, %ls, %ls", bstrHWID, bstrDisplayName, bstrDriverVer);
  406. }
  407. else
  408. {
  409. if (S_FALSE == hr)
  410. {
  411. if (pDownloadInfo->lpDeviceInstanceID)
  412. {
  413. LogMessage("Didn't find matching driver for %ls", pDownloadInfo->lpDeviceInstanceID);
  414. }
  415. else if (pDownloadInfo->lpHardwareIDs)
  416. {
  417. LogMessage("Didn't find matching driver for %ls", pDownloadInfo->lpHardwareIDs);
  418. }
  419. else
  420. {
  421. LogMessage("Didn't find matching driver");
  422. }
  423. }
  424. else // error happened
  425. {
  426. if (pDownloadInfo->lpDeviceInstanceID)
  427. {
  428. LogError(hr, "%s for %ls", SZ_FIND_MATCH, pDownloadInfo->lpDeviceInstanceID);
  429. }
  430. else if (pDownloadInfo->lpHardwareIDs)
  431. {
  432. LogError(hr, "%s for %ls", SZ_FIND_MATCH, pDownloadInfo->lpHardwareIDs);
  433. }
  434. else
  435. {
  436. LogError(hr, SZ_FIND_MATCH);
  437. }
  438. }
  439. }
  440. SysFreeString(bstrXmlCatalog);
  441. SysFreeString(bstrHWID);
  442. SysFreeString(bstrDisplayName);
  443. SysFreeString(bstrDriverName);
  444. SysFreeString(bstrMfgName);
  445. SysFreeString(bstrDriverProvider);
  446. SysFreeString(bstrDriverVer);
  447. SysFreeString(bstrArchitecture);
  448. if (NULL != pCatalog)
  449. {
  450. delete pCatalog;
  451. }
  452. return SUCCEEDED(hr);
  453. }
  454. // supports offline logging
  455. // hConnection NOT used at all
  456. // no network connection or osdet.dll needed for languauge, SKU, platform detection
  457. void WINAPI InternalLogDriverNotFound(
  458. IN HANDLE hConnection,
  459. IN LPCWSTR lpDeviceInstanceID,
  460. IN DWORD dwFlags // dwFlags could be either 0 or BEGINLOGFLAG from NEWDEV
  461. ) {
  462. USES_IU_CONVERSION;
  463. LOG_Block("InternalLogDriverNotFound");
  464. #if !(defined(_UNICODE) || defined(UNICODE))
  465. LOG_ErrorMsg(E_NOTIMPL);
  466. return;
  467. #else
  468. HRESULT hr = E_FAIL;
  469. DWORD dwBytes;
  470. TCHAR* pszBuff = NULL;
  471. ULONG ulLength;
  472. DWORD dwDeviceCount = 0;
  473. DWORD dwRank = 0;
  474. TCHAR szUniqueFilename[MAX_PATH] = _T("");
  475. DWORD dwWritten;
  476. DEVINST devinst;
  477. bool fXmlFileError = false;
  478. HANDLE hFile = NULL;
  479. BSTR bstrXmlSystemSpec = NULL;
  480. BSTR bstrThisID = NULL;
  481. HANDLE_NODE hDevices = HANDLE_NODE_INVALID;
  482. static CDeviceInstanceIdArray apszDIID; //device instance id list
  483. LPWSTR pDIID = NULL; //Device Instance ID
  484. CXmlSystemSpec xmlSpec;
  485. if (NULL == g_pCDMEngUpdate)
  486. {
  487. SetLastError(ERROR_OUTOFMEMORY);
  488. return;
  489. }
  490. //
  491. // Reset Quit Event in case client retries after a SetOperationMode
  492. //
  493. ResetEvent(g_pCDMEngUpdate->m_evtNeedToQuit);
  494. //
  495. // Only allow BEGINLOGFLAG or no flags
  496. //
  497. if (!(0 == dwFlags || BEGINLOGFLAG == dwFlags))
  498. {
  499. LOG_ErrorMsg(E_INVALIDARG);
  500. return;
  501. }
  502. //
  503. // If no flags, then lpDeviceInstanceID must be valid
  504. //
  505. if (0 == dwFlags && NULL == lpDeviceInstanceID)
  506. {
  507. LOG_ErrorMsg(E_INVALIDARG);
  508. return;
  509. }
  510. LogMessage("Started process to regester driver not found with Help Center. Not completing this process may not be error.");
  511. IU_PLATFORM_INFO iuPlatformInfo;
  512. //
  513. // We need iuPlatformInfo for both <platform> and <devices> elements
  514. // NOTE: iuPlatformInfo is initialized by DetectClientIUPlatform, and BSTRs must be
  515. // freed in CleanUp (don't just there before this call).
  516. //
  517. CleanUpIfFailedAndSetHr(DetectClientIUPlatform(&iuPlatformInfo));
  518. //
  519. // Should only be called on Whistler up except CHK builds can run on Win2K
  520. //
  521. if ( !( (VER_PLATFORM_WIN32_NT == iuPlatformInfo.osVersionInfoEx.dwPlatformId) &&
  522. (4 < iuPlatformInfo.osVersionInfoEx.dwMajorVersion) &&
  523. (0 < iuPlatformInfo.osVersionInfoEx.dwMinorVersion) ) )
  524. {
  525. LOG_Driver(_T("Should only be called on Whistler or greater"));
  526. CleanUpIfFailedAndSetHr(E_NOTIMPL);
  527. }
  528. if (NULL != lpDeviceInstanceID)
  529. {
  530. LOG_Driver(_T("DeviceInstanceID is %s"), lpDeviceInstanceID);
  531. //
  532. // Add the DeviceInstanceID to the list
  533. //
  534. if (-1 == apszDIID.Add(lpDeviceInstanceID))
  535. {
  536. goto CleanUp;
  537. }
  538. }
  539. if (0 == (dwFlags & BEGINLOGFLAG) || 0 == apszDIID.Size())
  540. {
  541. // not last log request or nothing to log
  542. LOG_Driver(_T("Won't log to hardware_XXX.xml until we get BEGINLOGFLAG when we have cached at least 1 HWID"));
  543. return;
  544. }
  545. ////////////////////////////////////////////
  546. // ELSE, WRITE XML FILE and call HelpCenter
  547. ////////////////////////////////////////////
  548. hr = OpenUniqueFileName(szUniqueFilename, ARRAYSIZE(szUniqueFilename), hFile);
  549. if (S_OK != hr)
  550. {
  551. fXmlFileError = true;
  552. goto CleanUp;
  553. }
  554. //
  555. // Write Unicode Header
  556. //
  557. if (0 == WriteFile(hFile, (LPCVOID) &UNICODEHDR, ARRAYSIZE(UNICODEHDR), &dwWritten, NULL))
  558. {
  559. SetHrMsgAndGotoCleanUp(GetLastError());
  560. }
  561. //
  562. // Add Platform
  563. //
  564. CleanUpIfFailedAndSetHr(AddPlatformClass(xmlSpec, iuPlatformInfo));
  565. //
  566. // Add OS Locale information
  567. //
  568. CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, FALSE));
  569. //
  570. // Initialize pszBuff to one NULL character
  571. //
  572. CleanUpFailedAllocSetHrMsg(pszBuff = (TCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR)));
  573. for (int i = 0; i < apszDIID.Size(); i++)
  574. {
  575. TCHAR* pszTemp;
  576. pDIID = apszDIID[i];
  577. //
  578. // NTBUG9#151928 - Log both hardware and compatible IDs of the device that matches lpDeviceInstanceID
  579. //
  580. LOG_Driver(_T("Log device instance with id %s"), pDIID);
  581. //
  582. // NOTE: We will ignore MatchingDeviceID's since we won't be called by DevMgr unless there is no installed
  583. // driver. This will allow test harnesses to call this function with valid DeviceInstanceIDs for the
  584. // test client to generate XML.
  585. //
  586. if (CR_SUCCESS == CM_Locate_DevNodeW(&devinst, (LPWSTR) pDIID, 0))
  587. {
  588. dwRank = 0;
  589. //
  590. // Open a <device> element
  591. //
  592. BSTR bstrDeviceInstance = SysAllocString(pDIID);
  593. CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(bstrDeviceInstance, -1, NULL, NULL, NULL, &hDevices));
  594. SafeSysFreeString(bstrDeviceInstance);
  595. //
  596. // Log all the hardware IDs
  597. //
  598. ulLength = 0;
  599. if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, NULL, &ulLength, 0))
  600. {
  601. CleanUpFailedAllocSetHrMsg(pszTemp = (TCHAR*) HeapReAlloc(GetProcessHeap(), 0, (LPVOID) pszBuff, ulLength));
  602. pszBuff = pszTemp;
  603. if (CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_HARDWAREID, NULL, pszBuff, &ulLength, 0))
  604. {
  605. for (TCHAR* pszThisID = pszBuff; *pszThisID; pszThisID += (lstrlen(pszThisID) + 1))
  606. {
  607. dwDeviceCount++;
  608. LOG_Driver(_T("<hwid/>: %s, rank: %d"), pszThisID, dwRank);
  609. bstrThisID = T2BSTR(pszThisID);
  610. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, FALSE, dwRank++, bstrThisID, NULL));
  611. SafeSysFreeString(bstrThisID);
  612. }
  613. }
  614. }
  615. //
  616. // Log all the compatible IDs
  617. //
  618. ulLength = 0;
  619. if (CR_BUFFER_SMALL == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, NULL, &ulLength, 0))
  620. {
  621. CleanUpFailedAllocSetHrMsg(pszTemp = (TCHAR*) HeapReAlloc(GetProcessHeap(), 0, (LPVOID) pszBuff, ulLength));
  622. pszBuff = pszTemp;
  623. if (CR_SUCCESS == CM_Get_DevNode_Registry_Property(devinst, CM_DRP_COMPATIBLEIDS, NULL, pszBuff, &ulLength, 0))
  624. {
  625. for (TCHAR* pszThisID = pszBuff; *pszThisID; pszThisID += (lstrlen(pszThisID) + 1))
  626. {
  627. dwDeviceCount++;
  628. LOG_Driver(_T("<compid/>: %s, rank: %d"), pszThisID, dwRank);
  629. bstrThisID = T2BSTR(pszThisID);
  630. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hDevices, TRUE, dwRank++, bstrThisID, NULL));
  631. SafeSysFreeString(bstrThisID);
  632. }
  633. }
  634. }
  635. if (HANDLE_NODE_INVALID != hDevices)
  636. {
  637. xmlSpec.SafeCloseHandleNode(hDevices);
  638. }
  639. }
  640. }
  641. //
  642. // Write the XML to the file
  643. //
  644. if (SUCCEEDED(xmlSpec.GetSystemSpecBSTR(&bstrXmlSystemSpec)))
  645. {
  646. if (0 == WriteFile(hFile, (LPCVOID) OLE2T(bstrXmlSystemSpec),
  647. lstrlenW(bstrXmlSystemSpec) * sizeof(TCHAR), &dwWritten, NULL))
  648. {
  649. SetHrMsgAndGotoCleanUp(GetLastError());
  650. }
  651. }
  652. else
  653. {
  654. fXmlFileError = true;
  655. }
  656. CleanUp:
  657. SysFreeString(iuPlatformInfo.bstrOEMManufacturer);
  658. SysFreeString(iuPlatformInfo.bstrOEMModel);
  659. SysFreeString(iuPlatformInfo.bstrOEMSupportURL);
  660. if (NULL != hFile)
  661. {
  662. CloseHandle(hFile);
  663. }
  664. SafeSysFreeString(bstrXmlSystemSpec);
  665. SafeSysFreeString(bstrThisID);
  666. //
  667. // We've already written everything in list, init so we can start over
  668. //
  669. apszDIID.FreeAll();
  670. SafeHeapFree(pszBuff);
  671. //
  672. // Open Help Center only if we have valid xml and one or more devices
  673. //
  674. if (!fXmlFileError && 0 < dwDeviceCount)
  675. {
  676. DWORD dwLen;
  677. LPTSTR pszSECommand = NULL; // INTERNET_MAX_URL_LENGTH
  678. //
  679. // Allocate buffers
  680. //
  681. pszBuff = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  682. if (NULL == pszBuff)
  683. {
  684. LOG_ErrorMsg(E_OUTOFMEMORY);
  685. DeleteFile(szUniqueFilename);
  686. return;
  687. }
  688. pszSECommand = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
  689. if (NULL == pszSECommand)
  690. {
  691. LOG_ErrorMsg(E_OUTOFMEMORY);
  692. SafeHeapFree(pszBuff);
  693. DeleteFile(szUniqueFilename);
  694. return;
  695. }
  696. //
  697. // Manually canonicalize second '?' in base string as excaped "%3F"
  698. //
  699. const static TCHAR tszBase[] =
  700. _T("hcp://services/layout/xml?definition=hcp://system/dfs/viewmode.xml&topic=hcp://system/dfs/uplddrvinfo.htm%3F");
  701. LOG_Driver(_T("Filename: %s"), szUniqueFilename);
  702. //
  703. // Canonicalize the filename once (i.e. ' ' -> %20) into pszBuff
  704. //
  705. dwLen = INTERNET_MAX_URL_LENGTH;
  706. if (!InternetCanonicalizeUrl(szUniqueFilename, pszBuff, &dwLen, 0))
  707. {
  708. LOG_ErrorMsg(GetLastError());
  709. SafeHeapFree(pszBuff);
  710. SafeHeapFree(pszSECommand);
  711. DeleteFile(szUniqueFilename);
  712. return;
  713. }
  714. LOG_Driver(_T("Filename canonicalized once: %s"), pszBuff);
  715. //
  716. // Concatinate canonicalized filename on to end of base reusing tszBuff1
  717. //
  718. // We don't need to check length since we know length of tszBase + MAX_PATH canonicalized
  719. // string won't exceed INTERNET_MAX_URL_LENGTH;
  720. //
  721. // pszSECommand was allocated to be INTERNET_MAX_URL_LENGTH TCHARs above.
  722. hr = StringCchPrintfEx(pszSECommand, INTERNET_MAX_URL_LENGTH,
  723. NULL, NULL, MISTSAFE_STRING_FLAGS,
  724. _T("%s%s"), tszBase, pszBuff);
  725. if (SUCCEEDED(hr))
  726. {
  727. LOG_Driver(_T("Opening HelpCenter via Shell Execute: \"%s\""), (LPCTSTR) pszSECommand);
  728. #if defined(UNICODE) || defined(_UNICODE)
  729. LogMessage("%s\"%S\"", SZ_OPENING_HS, pszSECommand);
  730. #else
  731. LogMessage("%s\"%s\"", SZ_OPENING_HS, pszSECommand);
  732. #endif
  733. //
  734. // Call HelpCenter
  735. //
  736. ShellExecute(NULL, NULL, pszSECommand, NULL, NULL, SW_SHOWNORMAL);
  737. }
  738. else
  739. {
  740. LOG_ErrorMsg(hr);
  741. }
  742. SafeHeapFree(pszBuff);
  743. SafeHeapFree(pszSECommand);
  744. return;
  745. }
  746. else
  747. {
  748. //
  749. // Remove the generated file
  750. //
  751. LOG_Driver(_T("fXmlFileError was true or no devices were added - deleting %s"), szUniqueFilename);
  752. DeleteFile(szUniqueFilename);
  753. }
  754. return;
  755. #endif // UNICODE is defined
  756. }
  757. //
  758. // Currently, this function is not implemented for Whistler or IU (called by V3 AU on WinME
  759. // to support offline driver cache).
  760. //
  761. int WINAPI InternalQueryDetectionFiles(
  762. IN HANDLE /* hConnection */,
  763. IN void* /* pCallbackParam */,
  764. IN PFN_QueryDetectionFilesCallback /* pCallback */
  765. ) {
  766. LOG_Block("InternalQueryDetectionFiles");
  767. LOG_ErrorMsg(E_NOTIMPL);
  768. return 0;
  769. }
  770. void InternalSetGlobalOfflineFlag(BOOL fOfflineMode)
  771. {
  772. //
  773. // Called once exclusively by CDM. This property is used
  774. // to maintain backwards compatibility with the XPClient
  775. // V4 version of CDM (single-instance design). See also
  776. // the comments in the exported ShutdownThreads function.
  777. //
  778. // Unfortunately, we can't report errors to CDM, but we check the
  779. // global before dereferencing (except here which has an HRESULT).
  780. //
  781. if (SUCCEEDED(CreateGlobalCDMEngUpdateInstance()))
  782. {
  783. g_pCDMEngUpdate->m_fOfflineMode = fOfflineMode;
  784. }
  785. }