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.

710 lines
22 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: ccdm.cpp
  6. //
  7. // Owner: YanL
  8. //
  9. // Description:
  10. //
  11. // CDM support from the site
  12. //
  13. //=======================================================================
  14. #include "stdafx.h"
  15. #include <winspool.h>
  16. #include <setupapi.h>
  17. #include <wustl.h>
  18. #define LOGGING_LEVEL 1
  19. #include <log.h>
  20. #include <wuv3sys.h>
  21. #include <drvinfo.h>
  22. #include <ccdm.h>
  23. #include <findoem.h>
  24. #include <shlwapi.h>
  25. #include "printers.h"
  26. static DWORD OpenReinstallKey(HKEY* phkeyReinstall);
  27. static DWORD GetReinstallString(LPCTSTR szHwID, tchar_buffer& bchReinstallString);
  28. static DWORD DeleteReinstallKey(LPCTSTR szHwID);
  29. bool DownloadToBuffer(
  30. IN LPCTSTR szPath,
  31. IN CWUDownload *pDownload, //pointer to internet server download class.
  32. IN CDiamond *pDiamond, //pointer to diamond de-compression class.
  33. OUT byte_buffer& bufOut
  34. ) {
  35. byte_buffer bufTmp;
  36. if (!pDownload->MemCopy(szPath, bufTmp))
  37. return false;
  38. if (pDiamond->IsValidCAB(bufTmp))
  39. {
  40. if (!pDiamond->Decompress(bufTmp, bufOut))
  41. return false;
  42. }
  43. else
  44. {
  45. //else the oem table is in uncompressed format.
  46. bufOut << bufTmp;
  47. }
  48. return true;
  49. }
  50. //Note: This method works specifically with a CCdm class. The CCdm class contains
  51. //the returned inventory item array. So if multiple threads are used then
  52. //multiple instances of the CCdm class will be required. This should not ever be a
  53. //problem since we do not ever plan or have any reason to do single instance groveling
  54. //for device drivers.
  55. //This method adds CDM records to an internal CDM inventory list. The CCatalog
  56. //prune method performs the final copy and insertion of these records into the
  57. //final inventory catalog.
  58. void CCdm::CreateInventoryList(
  59. IN CBitmask *pBm, //bitmask to be used to prune the inventory list.
  60. IN CWUDownload *pDownload, //pointer to internet server download class.
  61. IN CDiamond *pDiamond, //pointer to diamond de-compression class.
  62. IN PUID puidCatalog, //puid identifier of catalog where device drivers are stored.
  63. IN PBYTE pOemInfoTable //Pointer OEM info table that OEM detection needs.
  64. ) {
  65. LOG_block("CCdm::CreateInventoryList");
  66. USES_CONVERSION;
  67. // Start
  68. m_iCDMTotalItems = 0;
  69. //check input arguments
  70. if (NULL == pBm || NULL == pDownload || NULL == pDiamond)
  71. {
  72. return;
  73. }
  74. //First prune list based on bitmask
  75. //This is accomplished by anding the appropriate bitmasks to form a global bitmask.
  76. DWORD langid = GetMachineLangDW();
  77. PBYTE pBitmaskBits = pBm->GetClientBits(GetMachinePnPID(pOemInfoTable), langid);
  78. if (NULL == pBitmaskBits)
  79. {
  80. return;
  81. }
  82. {
  83. //Note: a cdm catalog cannot have a 0 puid since that the inventory.plt will
  84. //never have a device driver insertion record. So this function will not be
  85. //called for the inventory.plt catalog.
  86. TCHAR szPath[MAX_PATH];
  87. wsprintf(szPath, _T("%d/inventory.cdm"), puidCatalog);
  88. if (!DownloadToBuffer(szPath, pDownload, pDiamond, m_bufInventory))
  89. throw HRESULT_FROM_WIN32(GetLastError());
  90. }
  91. vector<SCdmItem> aitemUpdates;
  92. /* Regular drivers */ {
  93. CDrvInfoEnum DrvInfoEnum;
  94. auto_pointer<IDrvInfo> pDrvInfo;
  95. while (DrvInfoEnum.GetNextDrvInfo(&pDrvInfo))
  96. {
  97. tchar_buffer bufDeviceInstanceID;
  98. if (!pDrvInfo->GetDeviceInstanceID(bufDeviceInstanceID))
  99. {
  100. LOG_error("!pDrvInfo->GetDeviceInstanceID()");
  101. continue;
  102. }
  103. LOG_block(T2A(bufDeviceInstanceID));
  104. if (pDrvInfo->IsPrinter())
  105. {
  106. LOG_error("!pDrvInfo->IsPrinter()");
  107. continue;
  108. }
  109. tchar_buffer bufHardwareIDs;
  110. if (!pDrvInfo->GetAllHardwareIDs(bufHardwareIDs))
  111. {
  112. LOG_error("!pDrvInfo->GetAllHardwareIDs()");
  113. continue;
  114. }
  115. tchar_buffer bufMatchingDeviceId;
  116. pDrvInfo->GetMatchingDeviceId(bufMatchingDeviceId); // It's OK not to get it
  117. // #ifdef _WUV3TEST
  118. if (pDrvInfo.valid() && pDrvInfo->HasDriver())
  119. {
  120. if (bufMatchingDeviceId.valid())
  121. LOG_out("driver installed on MatchingDeviceId %s", (LPCTSTR)bufMatchingDeviceId);
  122. else
  123. LOG_error("driver installed, but HWID is not available");
  124. }
  125. else
  126. {
  127. if (bufMatchingDeviceId.valid())
  128. LOG_error("driver is not installed, but MatchingDeviceId is %s", (LPCTSTR)bufMatchingDeviceId);
  129. else
  130. LOG_out("no driver installed");
  131. }
  132. // #endif
  133. // Updates
  134. bool fMoreSpecific = true;
  135. for (LPCTSTR szHardwareId = bufHardwareIDs; fMoreSpecific && *szHardwareId; szHardwareId += lstrlen(szHardwareId) + 1)
  136. {
  137. // MatchingDeviceID is the last one to pay attention to
  138. fMoreSpecific = !bufMatchingDeviceId.valid() || 0 != lstrcmpi(szHardwareId, bufMatchingDeviceId);
  139. ULONG ulHashIndex = IsInMap(szHardwareId);
  140. if (-1 == ulHashIndex)
  141. continue;
  142. //else download the server bucket file
  143. byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
  144. FILETIME ftDriverInstalled = {0,0};
  145. if (!fMoreSpecific)
  146. {
  147. // Then it has to have a driver - Matching device ID is set
  148. if (!pDrvInfo->GetDriverDate(ftDriverInstalled))
  149. {
  150. LOG_error("!pDrvInfo->GetDriverDate(ftDriverInstalled)");
  151. break;
  152. }
  153. }
  154. DRIVER_MATCH_INFO DriverMatchInfo;
  155. PUID puid = CDM_FindUpdateInBucket(szHardwareId, fMoreSpecific ? NULL : &ftDriverInstalled, bufBucket, bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
  156. // See if it's being added already
  157. if (0 == puid)
  158. {
  159. LOG_out("CDM_FindUpdateInBucket returns 0");
  160. continue;
  161. }
  162. // something has been found
  163. AddItem(aitemUpdates, puid, bufMatchingDeviceId.valid() ? CDM_UPDATED_DRIVER : CDM_NEW_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer));
  164. break;
  165. }
  166. // Installed
  167. if (bufMatchingDeviceId.valid())
  168. {
  169. LPCTSTR szHardwareId = bufMatchingDeviceId;
  170. tchar_buffer bchReinstallString;
  171. if (NO_ERROR != GetReinstallString(szHardwareId, bchReinstallString))
  172. {
  173. LOG_out("No reinstall string for %s", szHardwareId);
  174. continue;
  175. }
  176. ULONG ulHashIndex = IsInMap(szHardwareId);
  177. if (-1 == ulHashIndex)
  178. continue;
  179. //else download the server bucket file
  180. byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
  181. DRIVER_MATCH_INFO DriverMatchInfo;
  182. PUID puid = CDM_FindInstalledInBucket(pDrvInfo, szHardwareId, bufBucket,
  183. bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
  184. // See if it's being added already
  185. if (0 == puid)
  186. {
  187. LOG_out("CDM_FindInstalledInBucket returns 0");
  188. continue;
  189. }
  190. // something has been found
  191. AddItem(aitemUpdates, puid, CDM_CURRENT_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer));
  192. }
  193. } // while (DrvInfoEnum.GetNextDrvInfo(&pDrvInfo))
  194. }
  195. /* Printer drivers */ {
  196. CPrinterDriverInfoArray ainfo;
  197. for(DWORD dwDriverIdx = 0; dwDriverIdx < ainfo.GetNumDrivers(); dwDriverIdx ++)
  198. {
  199. LPDRIVER_INFO_6 pinfo = ainfo.GetDriverInfo(dwDriverIdx);
  200. if (NULL == pinfo)
  201. continue;
  202. tchar_buffer bufHardwareID;
  203. if (!ainfo.GetHardwareID(pinfo, bufHardwareID))
  204. continue;
  205. ULONG ulHashIndex = IsInMap(bufHardwareID);
  206. if (-1 == ulHashIndex)
  207. continue;
  208. //else download the server bucket file
  209. byte_buffer& bufBucket = ReadBucketFile(pDownload, pDiamond, puidCatalog, ulHashIndex);
  210. DRIVER_MATCH_INFO DriverMatchInfo;
  211. PUID puid = CDM_FindUpdateInBucket(bufHardwareID, &(pinfo->ftDriverDate), bufBucket,
  212. bufBucket.size(), pBitmaskBits, &DriverMatchInfo);
  213. if (0 == puid)
  214. {
  215. LOG_out("CDM_FindInstalledInBucket returns 0");
  216. continue;
  217. }
  218. AddItem(aitemUpdates, puid, CDM_UPDATED_DRIVER, A2T(DriverMatchInfo.pszHardwareID), A2T(DriverMatchInfo.pszDriverVer), pinfo->pName, ainfo.GetArchitecture(pinfo));
  219. }
  220. }
  221. //Do converson
  222. AddInventoryRecords(aitemUpdates);
  223. }
  224. // Check if given PNPID is current hash table mapping.
  225. //if PnpID is in hash table then return index
  226. ULONG CCdm::IsInMap(
  227. IN LPCTSTR pHwID //hardware id to be retrieved
  228. ) {
  229. LOG_block("CCdm::IsInMap");
  230. // check if the member variable m_bufInventory is not NULL and the input argument is not NULL
  231. if (NULL == (PCDM_HASHTABLE)(LPBYTE)m_bufInventory || NULL == pHwID)
  232. {
  233. return -1;
  234. }
  235. PCDM_HASHTABLE pHashTable = (PCDM_HASHTABLE)(LPBYTE)m_bufInventory;
  236. ULONG ulTableEntry = CDM_HwID2Hash(pHwID, pHashTable->hdr.iTableSize);
  237. if(GETBIT(pHashTable->pData, ulTableEntry))
  238. {
  239. LOG_out("%s (hash %d) is found", pHwID, ulTableEntry);
  240. return ulTableEntry;
  241. }
  242. LOG_out("%s (hash %d) is not found", pHwID, ulTableEntry);
  243. return -1;
  244. }
  245. //Reads and initializes a compressed CDM bucket file from an internet server.
  246. //Returnes the array index where the bucket file is stored.
  247. byte_buffer& CCdm::ReadBucketFile(
  248. IN CWUDownload *pDownload, //pointer to internet server download class.
  249. IN CDiamond *pDiamond, //pointer to diamond de-compression class.
  250. IN PUID puidCatalog, //PUID id of catalog for which cdm hash table is to be retrieved.
  251. IN ULONG ulHashIndex //Hash table index of bucket file to be retrieved
  252. ) {
  253. LOG_block("CCdm::ReadBucketFile");
  254. // If it there return it
  255. for(int i = 0; i < m_aBuckets.size(); i ++)
  256. {
  257. if (ulHashIndex == m_aBuckets[i].first)
  258. return m_aBuckets[i].second;
  259. }
  260. // download it
  261. byte_buffer bufBucket;
  262. {
  263. TCHAR szPath[MAX_PATH];
  264. wsprintf(szPath, _T("%d/%d.bkf"), puidCatalog, ulHashIndex);
  265. if (!DownloadToBuffer(szPath, pDownload, pDiamond, bufBucket))
  266. throw HRESULT_FROM_WIN32(GetLastError());
  267. }
  268. m_aBuckets.push_back(my_pair(ulHashIndex, bufBucket));
  269. return m_aBuckets[m_aBuckets.size() - 1].second;
  270. }
  271. PINVENTORY_ITEM CCdm::ConvertCDMItem(
  272. int index //Index of cdm record to be converted
  273. ) {
  274. if ( index < 0 || index >= m_iCDMTotalItems )
  275. return NULL;
  276. // this is a no-op, we just hand off the existing pointer
  277. return m_items[index];
  278. }
  279. // add detected item to a list
  280. void CCdm::AddItem(
  281. vector<SCdmItem>& acdmItem,
  282. PUID puid,
  283. enumDriverDisposition fDisposition,
  284. LPCTSTR szHardwareId,
  285. LPCTSTR szDriverVer,
  286. LPCTSTR szPrinterDriverName /*= NULL*/,
  287. LPCTSTR szArchitecture /*= NULL*/
  288. ) {
  289. LOG_block("CCdm::AddItem");
  290. LOG_out("%s PUID = %d, HardwareId = %s", szPrinterDriverName ? _T("Prt") : _T("Dev"), puid, szHardwareId);
  291. // First check if this puid is included
  292. bool fNew = true;
  293. for (int nItem = 0; nItem < acdmItem.size(); nItem ++)
  294. {
  295. if ((acdmItem[nItem].puid == puid) && (acdmItem[nItem].fInstallState == fDisposition))
  296. {
  297. fNew = false;
  298. break;
  299. }
  300. }
  301. if (fNew)
  302. { // new item;
  303. LOG_out("Adding as a new item");
  304. acdmItem.push_back(SCdmItem());
  305. SCdmItem& item = acdmItem.back();
  306. item.puid = puid;
  307. item.fInstallState = fDisposition;
  308. item.sDriverVer = szDriverVer;
  309. if (szArchitecture)
  310. item.sArchitecture = szArchitecture;
  311. if (szPrinterDriverName)
  312. item.sPrinterDriverName = szPrinterDriverName;
  313. item.bufHardwareIDs.resize(lstrlen(szHardwareId) + 2);
  314. if(!item.bufHardwareIDs.valid())
  315. return; //out of memory
  316. lstrcpy(item.bufHardwareIDs, szHardwareId);
  317. ((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 2] = 0;
  318. ((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 1] = 0;
  319. }
  320. else
  321. {
  322. SCdmItem& item = acdmItem[nItem];
  323. // check if Hardware ID is already included
  324. for (LPCTSTR szCurHardwareId = acdmItem[nItem].bufHardwareIDs; *szCurHardwareId; szCurHardwareId += lstrlen(szCurHardwareId) + 1)
  325. {
  326. if (0 == lstrcmpi(szCurHardwareId, szHardwareId))
  327. {
  328. // Got It
  329. LOG_out("Already present");
  330. return;
  331. }
  332. }
  333. LOG_out("Appending hardware ID");
  334. int cnOldSize = item.bufHardwareIDs.size();
  335. item.bufHardwareIDs.resize(cnOldSize + lstrlen(szHardwareId) + 1);
  336. if(!item.bufHardwareIDs.valid())
  337. return; //out of memory
  338. lstrcpy((LPTSTR)item.bufHardwareIDs + cnOldSize - 1, szHardwareId);
  339. ((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 2] = 0;
  340. ((LPTSTR)item.bufHardwareIDs)[item.bufHardwareIDs.size() - 1] = 0;
  341. }
  342. }
  343. //This function is used to create a CDM inventory record. This record is initialized with
  344. //the CDM bucket information.
  345. void CCdm::AddInventoryRecords(
  346. vector<SCdmItem>& acdmItem
  347. ) {
  348. LOG_block("CCdm::AddInventoryRecords");
  349. for (int nItem = 0; nItem < acdmItem.size(); nItem ++)
  350. {
  351. PINVENTORY_ITEM pItem = 0;
  352. try
  353. {
  354. //allocate and initialize a new catalog item
  355. //note that this memory is never freed by this class
  356. //We rely on the fact that this pointer is going to be
  357. //handed off (in ConvertCDMItem()) and someone else will free it.
  358. pItem = (PINVENTORY_ITEM)V3_malloc(sizeof(INVENTORY_ITEM) + sizeof(WU_INV_FIXED) + sizeof(WU_VARIABLE_FIELD));
  359. //we need to set these up by the inventory catalog copy and insert routine.
  360. pItem->pd = NULL;
  361. //first setup the fixed part of the inventory item
  362. pItem->pf = (PWU_INV_FIXED)(((PBYTE)pItem) + sizeof(INVENTORY_ITEM));
  363. //We need to fix the record type here as it has to be correct before it is
  364. //inserted into the inventory list.
  365. if (acdmItem[nItem].sPrinterDriverName.length())
  366. { //printer
  367. pItem->pf->d.type = SECTION_RECORD_TYPE_PRINTER;
  368. pItem->recordType = WU_TYPE_RECORD_TYPE_PRINTER;
  369. }
  370. else
  371. { // pnp device
  372. pItem->pf->d.type = SECTION_RECORD_TYPE_DRIVER_RECORD;
  373. pItem->recordType = WU_TYPE_CDM_RECORD; //Corporate catalog device driver
  374. }
  375. pItem->pf->d.puid = acdmItem[nItem].puid;
  376. pItem->pf->d.flags = 0;
  377. pItem->pf->d.link = 0;
  378. //set up the state of the item. This used to take place in ConvertCDMItem()
  379. //initialize and store the internal item state structure
  380. pItem->ps = (PWU_INV_STATE)V3_malloc(sizeof(WU_INV_STATE));
  381. //translate the internal CDM item states to the public WUV3IS item
  382. //states.
  383. switch (acdmItem[nItem].fInstallState)
  384. {
  385. case CDM_NEW_DRIVER:
  386. pItem->ps->state = WU_ITEM_STATE_INSTALL;
  387. break;
  388. case CDM_UPDATED_DRIVER:
  389. pItem->ps->state = WU_ITEM_STATE_UPDATE;
  390. break;
  391. case CDM_CURRENT_DRIVER:
  392. pItem->ps->state = WU_ITEM_STATE_CURRENT;
  393. break;
  394. default:
  395. pItem->ps->state = WU_ITEM_STATE_UNKNOWN;
  396. };
  397. pItem->ps->bChecked = FALSE;
  398. pItem->ps->bHidden = FALSE;
  399. pItem->ps->dwReason = WU_STATE_REASON_NONE;
  400. //setup the variable part of the item. In the main catalog inventory case this
  401. //is all that we need to do. In the case of the corporate catalog we will need
  402. //to add one more variable field. This field is the CDM bucket hashIndex id.
  403. //This allows the corporate catalog to perform defered detection on device
  404. //driver records.
  405. //We need to add the ending variable size record since the list needs to
  406. //be initialized before AddVariableSizeField() will work.
  407. pItem->pv = (PWU_VARIABLE_FIELD)((PBYTE)pItem + sizeof(INVENTORY_ITEM) + sizeof(WU_INV_FIXED));
  408. pItem->pv->id = WU_VARIABLE_END;
  409. pItem->pv->len = sizeof(WU_VARIABLE_FIELD);
  410. //Add in the needed variable field items. (Note: Only variable detection
  411. //items are placed in the catalog inventory list to mimimize download size).
  412. PWU_VARIABLE_FIELD pVf = CreateVariableField(WU_CDM_HARDWARE_ID, (PBYTE)(LPTSTR)acdmItem[nItem].bufHardwareIDs,
  413. acdmItem[nItem].bufHardwareIDs.size() * sizeof(TCHAR));
  414. AddVariableSizeField(&pItem, pVf);
  415. V3_free(pVf);
  416. pVf = CreateVariableField(WU_VARIABLE_DRIVERVER, (PBYTE)(LPTSTR)acdmItem[nItem].sDriverVer.c_str(),
  417. (acdmItem[nItem].sDriverVer.length() + 1) * sizeof(TCHAR));
  418. AddVariableSizeField(&pItem, pVf);
  419. V3_free(pVf);
  420. if (CDM_CURRENT_DRIVER == acdmItem[nItem].fInstallState)
  421. {
  422. pVf = CreateVariableField(WU_KEY_UNINSTALLKEY, (PBYTE)"Yes", 4); // Just to say that uninstall key is present
  423. AddVariableSizeField(&pItem, pVf);
  424. V3_free(pVf);
  425. }
  426. if ( acdmItem[nItem].sPrinterDriverName.length() )
  427. {
  428. pVf = CreateVariableField(WU_CDM_DRIVER_NAME, (PBYTE)(LPTSTR)acdmItem[nItem].sPrinterDriverName.c_str(),
  429. (acdmItem[nItem].sPrinterDriverName.length() + 1) * sizeof(TCHAR));
  430. AddVariableSizeField(&pItem, pVf);
  431. V3_free(pVf);
  432. }
  433. if ( acdmItem[nItem].sArchitecture.length() )
  434. {
  435. pVf = CreateVariableField(WU_CDM_PRINTER_DRIVER_ARCH, (PBYTE)(LPTSTR)acdmItem[nItem].sArchitecture.c_str(),
  436. (acdmItem[nItem].sArchitecture.length() + 1) * sizeof(TCHAR));
  437. AddVariableSizeField(&pItem, pVf);
  438. V3_free(pVf);
  439. }
  440. }
  441. catch(HRESULT hr)
  442. {
  443. if ( pItem )
  444. {
  445. V3_free(pItem);
  446. pItem = 0;
  447. }
  448. }
  449. if (pItem)
  450. m_items[m_iCDMTotalItems++] = pItem;
  451. }
  452. }
  453. //This function installs a driver on Windows NT.
  454. //The active function that is called on NT to install a device driver resides in newdev.dll
  455. //Its prototype is:
  456. //BOOL
  457. //InstallWindowsUpdateDriver(
  458. // HWND hwndParent,
  459. // LPCWSTR HardwareId,
  460. // LPCWSTR InfPathName,
  461. // LPCWSTR DisplayName,
  462. // BOOL Force,
  463. // BOOL Backup,
  464. // PDWORD pReboot
  465. // )
  466. //This API takes a HardwareID. Newdev will cycle through all devices that match this hardware ID
  467. //and install the specified driver on them all.
  468. //It also takes a BOOL value Backup which specifies whether or not to backup the current drivers.
  469. // Note that newdev will only backup the drivers once if we find multiple matches for the HardwareID.
  470. static DWORD InstallNT(
  471. EDriverStatus eds,
  472. LPCTSTR szHwIDs,
  473. LPCTSTR szInfPathName,
  474. LPCTSTR szDisplayName,
  475. PDWORD pReboot
  476. ) {
  477. LOG_block("InstallNT");
  478. USES_CONVERSION;
  479. typedef BOOL (*PFN_InstallWindowsUpdateDriver)(HWND hwndParent, LPCWSTR HardwareId, LPCWSTR InfPathName, LPCWSTR DisplayName, BOOL Force, BOOL Backup, PDWORD pReboot);
  480. // Load newdev.dll and get pointer to our function
  481. auto_hlib hlib = LoadLibrary(_T("newdev.dll"));
  482. return_error_if_false(hlib.valid());
  483. PFN_InstallWindowsUpdateDriver pfnInstallWindowsUpdateDriver = (PFN_InstallWindowsUpdateDriver)GetProcAddress(hlib,"InstallWindowsUpdateDriver");
  484. return_error_if_false(pfnInstallWindowsUpdateDriver);
  485. // make sure the hardware ID's are aligned
  486. LPCTSTR szTempHwIDs;
  487. TSTR_ALIGNED_STACK_COPY(&szTempHwIDs, szHwIDs);
  488. szHwIDs = szTempHwIDs;
  489. // walk through Hardware IDs
  490. DWORD dwRebootFinal = 0;
  491. for (LPCTSTR szHwID = szHwIDs; *szHwID; szHwID += lstrlen(szHwID) + 1)
  492. {
  493. tchar_buffer bchInfPathName;
  494. if (edsBackup == eds)
  495. { // Old INF name is in the registry
  496. return_if_error(GetReinstallString(szHwID, bchInfPathName));
  497. TCHAR* ptr = _tcsrchr((LPCTSTR)bchInfPathName, _T('\\'));
  498. if (ptr)
  499. *ptr = 0; // cut file title
  500. }
  501. else
  502. {
  503. bchInfPathName.resize(lstrlen(szInfPathName) + 1);
  504. return_error_if_false(bchInfPathName.valid());
  505. lstrcpy(bchInfPathName, szInfPathName);
  506. }
  507. BOOL fForce = edsNew != eds;
  508. BOOL fBackup = edsNew == eds;
  509. LOG_out("InstallWindowsUpdateDriver(%s, %s, %s, fForce=%d, fBackup=%d)",
  510. szHwID, (LPCTSTR)bchInfPathName, szDisplayName, fForce, fBackup);
  511. DWORD dwReboot = 0;
  512. BOOL bRc = (pfnInstallWindowsUpdateDriver)(GetActiveWindow(),
  513. T2W((LPTSTR)szHwID), T2W(bchInfPathName), T2W((LPTSTR)szDisplayName), fForce, fBackup, &dwReboot);
  514. DWORD dwError = GetLastError();
  515. LOG_out("InstallWindowsUpdateDriver() returns %d, LastError = %d, need reboot = %d", bRc, dwError, dwReboot);
  516. if ( !bRc )
  517. {
  518. if (NO_ERROR == dwError)
  519. dwError = SPAPI_E_DI_DONT_INSTALL;
  520. return dwError;
  521. }
  522. // cleanup
  523. if ( edsBackup == eds )
  524. {
  525. DeleteReinstallKey(szHwID);
  526. // Delete directory
  527. DeleteNode(bchInfPathName);
  528. // Remove empty directory tree
  529. do
  530. {
  531. //remove *.*
  532. TCHAR* psz = _tcsrchr((LPTSTR)bchInfPathName, _T('\\'));
  533. if (NULL == psz)
  534. break;
  535. *psz = 0;
  536. } while (RemoveDirectory(bchInfPathName));
  537. }
  538. if (dwReboot)
  539. dwRebootFinal = 1;
  540. }
  541. *pReboot = dwRebootFinal;
  542. return NO_ERROR;
  543. }
  544. void CdmInstallDriver(BOOL bWindowsNT, EDriverStatus eds, LPCTSTR szHwIDs, LPCTSTR szInfPathName, LPCTSTR szDisplayName, PDWORD pReboot)
  545. {
  546. DWORD dwError = InstallNT(eds, szHwIDs, szInfPathName, szDisplayName, pReboot);
  547. if (NO_ERROR != dwError )
  548. {
  549. throw HRESULT_FROM_WIN32(dwError);
  550. }
  551. }
  552. //
  553. //We need to create a unique backup directory for this device, so we will
  554. // use the unique Hardware ID to come up with this unique directory.
  555. //Basically I will replace all of the illegal file/registry characters
  556. // \/:*?"<>| with # (for 98) , for NT will only do this with \
  557. //
  558. static void HwID2Key(LPCTSTR szHwID, tchar_buffer& bufKey)
  559. {
  560. static TCHAR szIllegal[] = _T("\\/:*?\"<>|");
  561. if (IsWindowsNT())
  562. szIllegal[1] = 0;
  563. bufKey.resize(ua_lstrlen(szHwID) + 1);
  564. if (!bufKey.valid())
  565. return; // out of memory
  566. // use the macro to copy unligned strings
  567. ua_tcscpy(bufKey, szHwID);
  568. for (TCHAR* pch = bufKey; *pch; pch ++)
  569. {
  570. if (_tcschr(szIllegal, *pch) != NULL)
  571. *pch = _T('#');
  572. }
  573. }
  574. static DWORD RegQueryValueBuf(HKEY hKey, LPCTSTR szValue, tchar_buffer& buf)
  575. {
  576. DWORD dwSize = 0;
  577. DWORD dwError = RegQueryValueEx(hKey, szValue, NULL, NULL, NULL, &dwSize);
  578. if (NO_ERROR != dwError)
  579. return dwError;
  580. buf.resize(dwSize/sizeof(TCHAR));
  581. if (!buf.valid())
  582. return ERROR_OUTOFMEMORY;
  583. return RegQueryValueEx(hKey, szValue, NULL, NULL, (LPBYTE)(LPTSTR)buf, &dwSize);
  584. }
  585. static DWORD OpenReinstallKey(HKEY* phkeyReinstall)
  586. {
  587. return RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Reinstall"),
  588. 0, KEY_ALL_ACCESS, phkeyReinstall);
  589. }
  590. static DWORD GetReinstallString(LPCTSTR szHwID, tchar_buffer& bchReinstallString)
  591. {
  592. auto_hkey hkeyReinstall;
  593. DWORD dwError = OpenReinstallKey(&hkeyReinstall);
  594. if (NO_ERROR != dwError)
  595. return dwError;
  596. tchar_buffer bufKey;
  597. HwID2Key(szHwID, bufKey);
  598. auto_hkey hkeyHwID;
  599. dwError = RegOpenKeyEx(hkeyReinstall, bufKey, 0, KEY_READ, &hkeyHwID);
  600. if (NO_ERROR != dwError)
  601. return dwError;
  602. return RegQueryValueBuf(hkeyHwID, _T("ReinstallString"), bchReinstallString);
  603. }
  604. static DWORD DeleteReinstallKey(LPCTSTR szHwID)
  605. {
  606. LOG_block("DeleteReinstallKey");
  607. auto_hkey hkeyReinstall;
  608. return_if_error(OpenReinstallKey(&hkeyReinstall));
  609. tchar_buffer bufKey;
  610. HwID2Key(szHwID, bufKey);
  611. return_if_error(RegDeleteKey(hkeyReinstall, bufKey));
  612. return NO_ERROR;
  613. }