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.

2009 lines
59 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: cdmp.cpp
  6. //
  7. // Description:
  8. //
  9. // CDM auxiliary functions
  10. //
  11. // called by DownloadUpdatedFiles()
  12. // GetDownloadPath
  13. //
  14. // called by InternalLogDriverNotFound()
  15. // OpenUniqueFileName
  16. //
  17. //=======================================================================
  18. #include <iuengine.h>
  19. #include <shlwapi.h>
  20. #include <ras.h>
  21. #include <tchar.h>
  22. #include <winver.h>
  23. #include <download.h>
  24. #include <wininet.h>
  25. #include <fileutil.h>
  26. #include "iuxml.h"
  27. #include <wuiutest.h>
  28. #include <StringUtil.h>
  29. #include <cdm.h>
  30. #include "cdmp.h"
  31. #include "schemamisc.h"
  32. #include <safefile.h>
  33. const DWORD MAX_INF_STRING = 512; // From DDK docs "General Syntax Rules for INF Files" section
  34. const OLECHAR szXmlClientInfo[] = L"<clientInfo xmlns=\"x-schema:http://schemas.windowsupdate.com/iu/clientInfo.xml\" clientName=\"CDM\" />";
  35. const OLECHAR szXmlPrinterCatalogQuery[] = L"<query><dObjQueryV1 procedure=\"printercatalog\"></dObjQueryV1></query>";
  36. const OLECHAR szXmlDriverDownloadQuery[] = L"<query><dObjQueryV1 procedure=\"driverupdates\"></dObjQueryV1></query>";
  37. /////////////////////////////////////////////////////////////////////////////
  38. // CXmlDownloadResult
  39. class CXmlDownloadResult : public CIUXml
  40. {
  41. public:
  42. CXmlDownloadResult();
  43. ~CXmlDownloadResult();
  44. HRESULT LoadXMLDocumentItemStatusList(BSTR bstrXml);
  45. //
  46. // Expose m_pItemNodeList so it can be used directly
  47. //
  48. IXMLDOMNodeList* m_pItemStatusNodeList;
  49. private:
  50. IXMLDOMDocument* m_pDocResultItems;
  51. };
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CXmlDownloadResult
  54. /////////////////////////////////////////////////////////////////////////////
  55. CXmlDownloadResult::CXmlDownloadResult()
  56. : m_pDocResultItems(NULL), m_pItemStatusNodeList(NULL)
  57. {
  58. }
  59. CXmlDownloadResult::~CXmlDownloadResult()
  60. {
  61. SafeReleaseNULL(m_pDocResultItems);
  62. SafeReleaseNULL(m_pItemStatusNodeList);
  63. }
  64. /////////////////////////////////////////////////////////////////////////////
  65. // LoadXMLDocumentItemStatusList()
  66. //
  67. // Load an XML Document from string and create the list of items
  68. //
  69. // Calls to Download produce return status in the following (example) XML format:
  70. //
  71. // <?xml version="1.0"?>
  72. // <items xmlns="x-schema:http://schemas.windowsupdate.com/iu/resultschema.xml">
  73. // <itemStatus xmlns="">
  74. // <identity name="nvidia.569">nvidia.569
  75. // <publisherName>nvidia</publisherName>
  76. // </identity>
  77. // <downloadStatus value="COMPLETE" errorCode="100"/>
  78. // </itemStatus>
  79. // </items>
  80. //
  81. // We expose m_pItemNodeList so it can be used directly to retrieve the value
  82. // attribute of the <downloadStatus /> item.
  83. //
  84. // NOTE: for CDM there will only be one item downloaded at a time, so the list
  85. // will only contain a single <itemStatus/> element.
  86. //
  87. /////////////////////////////////////////////////////////////////////////////
  88. HRESULT CXmlDownloadResult::LoadXMLDocumentItemStatusList(BSTR bstrXml)
  89. {
  90. LOG_Block("CXmlDownloadResult::LoadXMLDocumentItemStatusList");
  91. HRESULT hr = S_OK;
  92. BSTR bstrAllDocumentItems = NULL;
  93. if (NULL == bstrXml || m_pDocResultItems || m_pItemStatusNodeList)
  94. {
  95. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  96. }
  97. CleanUpIfFailedAndSetHr(LoadXMLDoc(bstrXml, &m_pDocResultItems));
  98. //
  99. // Get a list of all <itemStatus/> elements anywhere in the document
  100. //
  101. if (NULL == (bstrAllDocumentItems = SysAllocString(L"//itemStatus")))
  102. {
  103. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  104. }
  105. if (NULL == (m_pItemStatusNodeList = FindDOMNodeList(m_pDocResultItems, bstrAllDocumentItems)))
  106. {
  107. CleanUpIfFailedAndSetHr(E_FAIL);
  108. }
  109. CleanUp:
  110. SysFreeString(bstrAllDocumentItems);
  111. return hr;
  112. }
  113. /////////////////////////////////////////////////////////////////////////////
  114. // CXmlPrinterCatalogList
  115. class CXmlPrinterCatalogList : public CIUXml
  116. {
  117. public:
  118. CXmlPrinterCatalogList();
  119. ~CXmlPrinterCatalogList();
  120. HRESULT LoadXMLDocumentAndGetCompHWList(BSTR bstrXml);
  121. //
  122. // Expose m_pCompHWNodeList so it can be used directly
  123. //
  124. IXMLDOMNodeList* m_pCompHWNodeList;
  125. private:
  126. IXMLDOMDocument* m_pDocCatalogItems;
  127. };
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CXmlPrinterCatalogList
  130. /////////////////////////////////////////////////////////////////////////////
  131. CXmlPrinterCatalogList::CXmlPrinterCatalogList()
  132. : m_pDocCatalogItems(NULL), m_pCompHWNodeList(NULL)
  133. {
  134. }
  135. CXmlPrinterCatalogList::~CXmlPrinterCatalogList()
  136. {
  137. SafeReleaseNULL(m_pDocCatalogItems);
  138. SafeReleaseNULL(m_pCompHWNodeList);
  139. }
  140. /////////////////////////////////////////////////////////////////////////////
  141. // LoadXMLDocumentAndGetCompHWList()
  142. //
  143. // Load an XML Document from string and create the list of
  144. // <compatibleHardware/> elements.
  145. //
  146. // "printercatalog" SOAP queries sent via GetManifest return a list of
  147. // all printers for the given platform in the following format (validates against
  148. // http://schemas.windowsupdate.com/iu/catalogschema.xml) having the following
  149. // characteristics:
  150. //
  151. // * <catalog clientType="CONSUMER">
  152. // * Only a single <provider> with <identity name="printerCatalog">printerCatalog</identity>
  153. // * returned <platform/> is not used by CDM
  154. // * <item/> identity and <platform> are likewise ignored by CDM
  155. // * Under item/detection/compatibleHardware/device the driverName, driverProvider, mfgName,
  156. // and driverVer attributes, as well as hwid string are extracted and used to build
  157. // printer INF files.
  158. // * Algorithms in this class take advantage of the fact that driverProvider attributes
  159. // are serialized (e.g. grouped in order by driverProvider), however this is not a requirement.
  160. // * Note that <item/> elements can contain more than one <compatibleHardware/> element,
  161. // but the complete list of <compatibleHardware/> elements provides all printers in
  162. // the given catalog
  163. //
  164. // Sample start of a "printerCatalog" catalog:
  165. // ------------------------------------------
  166. // <?xml version="1.0" ?>
  167. // - <catalog clientType="CONSUMER">
  168. // - <provider>
  169. // <identity name="printerCatalog">printerCatalog</identity>
  170. // <platform>ver_platform_win32_nt.5.0.x86.en</platform>
  171. // + <item installable="1">
  172. // <identity name="hp.3">hp.3</identity>
  173. // - <detection>
  174. // - <compatibleHardware>
  175. // - <device isPrinter="1">
  176. // <printerInfo driverName="HP PSC 500" driverProvider="Hewlett-Packard Co." mfgName="HP" />
  177. // <hwid rank="0" driverVer="1999-12-14">DOT4PRT\HEWLETT-PACKARDPSC_59784</hwid>
  178. // </device>
  179. // </compatibleHardware>
  180. // - <compatibleHardware>
  181. // ... etc.
  182. // </detection>
  183. // </item>
  184. // + <item installable="1">
  185. // ... etc.
  186. //
  187. //
  188. // Likewise, driver information for requested PnP drivers is returned in catalog
  189. // items.
  190. //
  191. /////////////////////////////////////////////////////////////////////////////
  192. HRESULT CXmlPrinterCatalogList::LoadXMLDocumentAndGetCompHWList(BSTR bstrXml)
  193. {
  194. LOG_Block("CXmlPrinterCatalogList::LoadXMLDocumentAndGetCompHWList");
  195. HRESULT hr = S_OK;
  196. BSTR bstrAllDocumentItems = NULL;
  197. if (NULL == bstrXml || m_pDocCatalogItems || m_pCompHWNodeList)
  198. {
  199. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  200. }
  201. CleanUpIfFailedAndSetHr(LoadXMLDoc(bstrXml, &m_pDocCatalogItems));
  202. //
  203. // Get a list of all <item/> elements anywhere in the document
  204. //
  205. if (NULL == (bstrAllDocumentItems = SysAllocString(L"//compatibleHardware")))
  206. {
  207. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  208. }
  209. if (NULL == (m_pCompHWNodeList = FindDOMNodeList(m_pDocCatalogItems, bstrAllDocumentItems)))
  210. {
  211. CleanUpIfFailedAndSetHr(E_FAIL);
  212. }
  213. CleanUp:
  214. SysFreeString(bstrAllDocumentItems);
  215. return hr;
  216. }
  217. ///////////////////////////////////////////////////////////////////
  218. //
  219. // Locally defined LPTSTR array - dynamically expands
  220. //
  221. ///////////////////////////////////////////////////////////////////
  222. #define NUM_DIIDPTR_ALLOC 10
  223. CDeviceInstanceIdArray::CDeviceInstanceIdArray()
  224. : m_ppszDIID(NULL), m_nCount(0), m_nPointers(0)
  225. {
  226. }
  227. CDeviceInstanceIdArray::~CDeviceInstanceIdArray()
  228. {
  229. LOG_Block("CDeviceInstanceIdArray::~CDeviceInstanceIdArray");
  230. FreeAll();
  231. //
  232. // Free the array of LPTSTRs
  233. //
  234. SafeHeapFree(m_ppszDIID);
  235. m_nPointers = 0;
  236. }
  237. void CDeviceInstanceIdArray::FreeAll()
  238. {
  239. LOG_Block("CDeviceInstanceIdArray::Free");
  240. if (NULL != m_ppszDIID && 0 < m_nCount)
  241. {
  242. //
  243. // Free the strings
  244. //
  245. for (int i = 0; i < m_nCount; i++)
  246. {
  247. SafeHeapFree(*(m_ppszDIID+i));
  248. }
  249. m_nCount = 0;
  250. }
  251. }
  252. int CDeviceInstanceIdArray::Add(LPCWSTR pszDIID)
  253. {
  254. HRESULT hr;
  255. LPWSTR pszIDtoAdd = NULL;
  256. DWORD cch;
  257. LOG_Block("CDeviceInstanceIdArray::Add");
  258. if (NULL == pszDIID)
  259. {
  260. LOG_ErrorMsg(E_INVALIDARG);
  261. return -1;
  262. }
  263. //
  264. // Allocate or realloc space for NUM_DIIDPTR_ALLOC LPSTRs
  265. //
  266. if (NULL == m_ppszDIID)
  267. {
  268. m_ppszDIID = (LPWSTR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR) * NUM_DIIDPTR_ALLOC);
  269. if(NULL == m_ppszDIID)
  270. {
  271. LOG_ErrorMsg(E_OUTOFMEMORY);
  272. return -1;
  273. }
  274. m_nPointers = NUM_DIIDPTR_ALLOC;
  275. }
  276. else if (m_nCount == m_nPointers)
  277. {
  278. //
  279. // We've used all our allocated pointers, realloc more
  280. //
  281. LPWSTR* ppTempDIID;
  282. //
  283. // Increase number of pointers currently allocated by NUM_DIIDPTR_ALLOC
  284. //
  285. ppTempDIID = (LPWSTR*) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_ppszDIID,
  286. (sizeof(LPWSTR) * (m_nPointers + NUM_DIIDPTR_ALLOC)) );
  287. if(NULL == ppTempDIID)
  288. {
  289. LOG_ErrorMsg(E_OUTOFMEMORY);
  290. return -1;
  291. }
  292. m_ppszDIID = ppTempDIID;
  293. m_nPointers += NUM_DIIDPTR_ALLOC;
  294. }
  295. //
  296. // Alloc memory for to hold the DIID and copy it
  297. //
  298. cch = (lstrlenW(pszDIID) + 1);
  299. if (NULL == (pszIDtoAdd = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, cch * sizeof(WCHAR))))
  300. {
  301. LOG_ErrorMsg(E_OUTOFMEMORY);
  302. goto CleanUp;
  303. }
  304. hr = StringCchCopyExW(pszIDtoAdd, cch, pszDIID, NULL, NULL, MISTSAFE_STRING_FLAGS);
  305. if (FAILED(hr))
  306. {
  307. HeapFree(GetProcessHeap(), 0, pszIDtoAdd);
  308. pszIDtoAdd = NULL;
  309. goto CleanUp;
  310. }
  311. *(m_ppszDIID+m_nCount) = pszIDtoAdd;
  312. m_nCount++;
  313. CleanUp:
  314. if (NULL == pszIDtoAdd)
  315. {
  316. return -1;
  317. }
  318. else
  319. {
  320. #if defined(_UNICODE) || defined(UNICODE)
  321. LOG_Driver(_T("%s added to list"), pszIDtoAdd);
  322. #else
  323. LOG_Driver(_T("%S added to list"), pszIDtoAdd);
  324. #endif
  325. return m_nCount - 1;
  326. }
  327. }
  328. LPWSTR CDeviceInstanceIdArray::operator[](int index)
  329. {
  330. LOG_Block("CDeviceInstanceIdArray::operator[]");
  331. if (0 > index || m_nCount < index + 1)
  332. {
  333. LOG_ErrorMsg(E_INVALIDARG);
  334. return NULL;
  335. }
  336. return *(m_ppszDIID+index);
  337. }
  338. ///////////////////////////////////////////////////////////////////
  339. // Gets a path to the directory that cdm.dll has copied the install cabs to
  340. // and returns the length of the path.
  341. // Note: The input buffer must be at least MAX_PATH size.
  342. HRESULT GetDownloadPath(
  343. IN BSTR bstrXmlCatalog, // Catalog we passed to Download (only contains one item)
  344. IN BSTR bstrXmlDownloadedItems,
  345. IN OUT LPTSTR lpDownloadPath, // Local directory where extracted files were placed.
  346. IN OUT DWORD cchDownloadPath
  347. )
  348. {
  349. USES_IU_CONVERSION;
  350. LOG_Block("GetDownloadPath");
  351. HRESULT hr = S_OK;
  352. BSTR bstrDownloadPath = NULL;
  353. BSTR bstrItem = NULL;
  354. CXmlItems* pxmlDownloadedItems = NULL;
  355. CXmlCatalog catalog;
  356. HANDLE_NODE hCatalogItem;
  357. HANDLE_NODE hProvider;
  358. HANDLE_NODELIST hItemList;
  359. HANDLE_NODELIST hProviderList;
  360. if (NULL == bstrXmlCatalog || NULL == lpDownloadPath || NULL == bstrXmlDownloadedItems || 0 == cchDownloadPath)
  361. {
  362. CleanUpIfFailedAndSetHr(E_INVALIDARG);
  363. }
  364. lpDownloadPath[0] = _T('\0');
  365. //
  366. // Load the XML and get the <item/> list and node of first item (only one in CDM case)
  367. //
  368. CleanUpIfFailedAndSetHr(catalog.LoadXMLDocument(bstrXmlCatalog, g_pCDMEngUpdate->m_fOfflineMode));
  369. hProviderList = catalog.GetFirstProvider(&hProvider);
  370. if (HANDLE_NODELIST_INVALID == hProviderList || HANDLE_NODE_INVALID == hProvider)
  371. {
  372. CleanUpIfFailedAndSetHr(E_INVALIDARG);
  373. }
  374. hItemList = catalog.GetFirstItem(hProvider, &hCatalogItem);
  375. if (HANDLE_NODELIST_INVALID == hItemList || HANDLE_NODE_INVALID == hProvider)
  376. {
  377. CleanUpIfFailedAndSetHr(E_FAIL);
  378. }
  379. //
  380. // Construct CXmlItems for read
  381. //
  382. CleanUpFailedAllocSetHrMsg(pxmlDownloadedItems = new CXmlItems(TRUE));
  383. CleanUpIfFailedAndMsg(pxmlDownloadedItems->LoadXMLDocument(bstrXmlDownloadedItems));
  384. hr = pxmlDownloadedItems->GetItemDownloadPath(&catalog, hCatalogItem, &bstrDownloadPath);
  385. if (NULL == bstrDownloadPath)
  386. {
  387. LOG_Driver(_T("Failed to get Item Download Path from ReturnSchema"));
  388. if (SUCCEEDED(hr))
  389. hr = E_FAIL;
  390. goto CleanUp;
  391. }
  392. hr = StringCchCopyEx(lpDownloadPath, cchDownloadPath, OLE2T(bstrDownloadPath),
  393. NULL, NULL, MISTSAFE_STRING_FLAGS);
  394. if (FAILED(hr))
  395. goto CleanUp;
  396. CleanUp:
  397. if (pxmlDownloadedItems)
  398. {
  399. delete pxmlDownloadedItems;
  400. }
  401. SysFreeString(bstrDownloadPath);
  402. SysFreeString(bstrItem);
  403. return hr;
  404. }
  405. // called by InternalDriverNotFound(...)
  406. // Find a file name not used so far into which hardware xml information will be inserted
  407. // The file name will be in format hardware_xxx.xml where xxx is in range [1..MAX_INDEX_TO_SEARCH]
  408. // The position file found last time is remembered and new search will start from the next position
  409. // Caller is supposed to close handle and delete file
  410. // pszFilePath IN OUT : allocated and freed by caller. Buffer to store unique file name found: MUST be MAX_PATH
  411. // hFile OUT : store a handle to the opened file
  412. //return S_OK if Unique File Name found
  413. //return E_INVALIDARG if buffer pointer is NULL (must be called with MAX_PATH length buffer)
  414. //return E_FAIL if all qualified file names already taken
  415. HRESULT OpenUniqueFileName(
  416. IN OUT LPTSTR pszFilePath,
  417. IN DWORD cchFilePath,
  418. OUT HANDLE &hFile
  419. )
  420. {
  421. LOG_Block("OpenUniqueFileName");
  422. static DWORD dwFileIndex = 1;
  423. int nCount = 0;
  424. const TCHAR FILENAME[] = _T("Hardware_");
  425. const TCHAR FILEEXT[] = _T("xml");
  426. TCHAR szDirPath[MAX_PATH + 1];
  427. HRESULT hr;
  428. if (NULL == pszFilePath || 0 == cchFilePath)
  429. {
  430. LOG_ErrorMsg(E_INVALIDARG);
  431. return E_INVALIDARG;
  432. }
  433. pszFilePath[0] = _T('\0');
  434. GetIndustryUpdateDirectory(szDirPath);
  435. LOG_Out(_T("Directory to search unique file names: %s"), szDirPath);
  436. hFile = INVALID_HANDLE_VALUE;
  437. do
  438. {
  439. hr = StringCchPrintfEx(pszFilePath, cchFilePath, NULL, NULL, MISTSAFE_STRING_FLAGS,
  440. _T("%s%s%d.%s"), szDirPath, FILENAME, dwFileIndex, FILEEXT);
  441. if (FAILED(hr))
  442. {
  443. LOG_ErrorMsg(hr);
  444. return hr;
  445. }
  446. hFile = CreateFile(pszFilePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, NULL);
  447. if (INVALID_HANDLE_VALUE == hFile)
  448. {
  449. //
  450. // Could test for ERROR_FILE_EXISTS == dwErr (expected) and bail on other errors indicating
  451. // a more serious problem, however this return isn't doc'ed in the JAN 2001 SDK, and the
  452. // documented ERROR_ALREADY_EXISTS applies instead to CREATE_ALWAYS or OPEN_ALWAYS.
  453. //
  454. LOG_Out(_T("%s already exists"), pszFilePath);
  455. dwFileIndex ++;
  456. nCount ++;
  457. if (dwFileIndex > MAX_INDEX_TO_SEARCH)
  458. {
  459. dwFileIndex = 1;
  460. }
  461. }
  462. else
  463. {
  464. break; //first available file name found
  465. }
  466. }while(nCount < MAX_INDEX_TO_SEARCH );
  467. if (nCount == MAX_INDEX_TO_SEARCH )
  468. {
  469. LOG_Out(_T("All %d file names have been taken"), nCount);
  470. LOG_ErrorMsg(E_FAIL);
  471. return E_FAIL;
  472. }
  473. LOG_Out(_T("Unique file name %s opened for GENERIC_WRITE using CreateFile"), pszFilePath);
  474. dwFileIndex++; //next time skip file name found this time
  475. if (dwFileIndex > MAX_INDEX_TO_SEARCH)
  476. {
  477. //
  478. // Start again at the beginning - maybe one of earlier files has been deleted by HelpCenter...
  479. //
  480. dwFileIndex = 1;
  481. }
  482. return S_OK;
  483. }
  484. HRESULT WriteInfHeader(LPCTSTR pszProvider, HANDLE& hFile)
  485. {
  486. LOG_Block("WriteInfHeader");
  487. const TCHAR HEADER_START[] =
  488. _T("[Version]\r\n")
  489. _T("Signature=\"$Windows NT$\"\r\n")
  490. _T("Provider=%PRTPROV%\r\n")
  491. _T("ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318}\r\n")
  492. _T("Class=Printer\r\nCatalogFile=webntprn.cat\r\n")
  493. _T("\r\n")
  494. _T("[ClassInstall32.NT]\r\n")
  495. _T("AddReg=printer_class_addreg\r\n")
  496. _T("\r\n")
  497. _T("[printer_class_addreg]\r\n")
  498. _T("HKR,,,,%%PrinterClassName%%\r\n")
  499. _T("HKR,,Icon,,\"-4\"\r\n")
  500. _T("HKR,,Installer32,,\"ntprint.dll,ClassInstall32\"\r\n")
  501. _T("HKR,,NoDisplayClass,,1\r\n")
  502. _T("HKR,,EnumPropPages32,,\"printui.dll,PrinterPropPageProvider\"\r\n")
  503. _T("\r\n")
  504. _T("[Strings]\r\n")
  505. _T("PRTPROV=\"");
  506. const TCHAR HEADER_END[] =
  507. _T("\"\r\n")
  508. _T("PrinterClassName=\"Printer\"\r\n")
  509. _T("\r\n");
  510. HRESULT hr = S_OK;
  511. DWORD dwWritten;
  512. if (NULL == pszProvider || hFile == INVALID_HANDLE_VALUE)
  513. {
  514. LOG_ErrorMsg(E_INVALIDARG);
  515. return E_INVALIDARG;
  516. }
  517. #if defined(_UNICODE) || defined(UNICODE)
  518. //
  519. // Write Unicode Header
  520. //
  521. if (0 == WriteFile(hFile, (LPCVOID) &UNICODEHDR, sizeof(UNICODEHDR), &dwWritten, NULL))
  522. {
  523. SetHrMsgAndGotoCleanUp(GetLastError());
  524. }
  525. #endif
  526. //
  527. // Write the first part of INF header
  528. //
  529. if (0 == WriteFile(hFile, HEADER_START, sizeof(HEADER_START) - sizeof(TCHAR), &dwWritten, NULL))
  530. {
  531. SetHrMsgAndGotoCleanUp(GetLastError());
  532. }
  533. //
  534. // Write the provider string
  535. //
  536. if (0 == WriteFile(hFile, (LPCVOID) pszProvider, lstrlen(pszProvider) * sizeof(TCHAR), &dwWritten, NULL))
  537. {
  538. SetHrMsgAndGotoCleanUp(GetLastError());
  539. }
  540. //
  541. // Write the remainder of the INF header
  542. //
  543. if (0 == WriteFile(hFile, HEADER_END, sizeof(HEADER_END) - sizeof(TCHAR), &dwWritten, NULL))
  544. {
  545. SetHrMsgAndGotoCleanUp(GetLastError());
  546. }
  547. CleanUp:
  548. if (FAILED(hr) && INVALID_HANDLE_VALUE != hFile)
  549. {
  550. CloseHandle(hFile);
  551. hFile = INVALID_HANDLE_VALUE;
  552. }
  553. return hr;
  554. }
  555. //
  556. // pszFilePath must be >= MAX_PATH characters
  557. //
  558. HRESULT OpenUniqueProviderInfName(
  559. IN LPCTSTR szDirPath,
  560. IN LPCTSTR pszProvider,
  561. IN OUT LPTSTR pszFilePath,
  562. IN DWORD cchFilePath,
  563. OUT HANDLE &hFile
  564. )
  565. {
  566. LOG_Block("OpenUniqueProviderInfName");
  567. const TCHAR FILEROOT[] = _T("PList_");
  568. const TCHAR FILEEXT[] = _T("inf");
  569. DWORD dwErr;
  570. HRESULT hr;
  571. hFile = INVALID_HANDLE_VALUE;
  572. if (NULL == pszFilePath || NULL == pszProvider || NULL == szDirPath || 0 == cchFilePath)
  573. {
  574. LOG_ErrorMsg(E_INVALIDARG);
  575. return E_INVALIDARG;
  576. }
  577. pszFilePath[0] = _T('\0');
  578. hr = StringCchPrintfEx(pszFilePath, cchFilePath, NULL, NULL, MISTSAFE_STRING_FLAGS,
  579. _T("%s%s%s.%s"), szDirPath, FILEROOT, pszProvider, FILEEXT);
  580. if (FAILED(hr))
  581. {
  582. LOG_ErrorMsg(hr);
  583. pszFilePath[0] = _T('\0');
  584. return hr;
  585. }
  586. //
  587. // Try to open an existing INF of this name. If this fails try to create then init the file.
  588. //
  589. hFile = CreateFile(pszFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  590. OPEN_EXISTING, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, NULL);
  591. if (INVALID_HANDLE_VALUE == hFile)
  592. {
  593. hFile = CreateFile(pszFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  594. CREATE_NEW, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, NULL);
  595. if (INVALID_HANDLE_VALUE == hFile)
  596. {
  597. dwErr = GetLastError();
  598. LOG_ErrorMsg(dwErr);
  599. pszFilePath[0] = _T('\0');
  600. return HRESULT_FROM_WIN32(dwErr);
  601. }
  602. //
  603. // Write the INF "Header" information to the new file
  604. //
  605. if (FAILED( hr = WriteInfHeader(pszProvider, hFile)))
  606. {
  607. pszFilePath[0] = _T('\0');
  608. return hr;
  609. }
  610. }
  611. return S_OK;
  612. }
  613. HRESULT OfferThisPrinterDriver(
  614. DRIVER_INFO_6* paDriverInfo6, // array of DRIVER_INFO_6 structs for installed printer drivers
  615. DWORD dwDriverInfoCount, // count of structs in paDriverInfo6 array
  616. IXMLDOMNode* pCompHWNode, // <compatibleHardware> node from catalog
  617. BOOL* pfOfferDriver, // [OUT] If TRUE offer this driver - remainder of outputs are valid
  618. VARIANT& vDriverName, // [OUT]
  619. VARIANT& vDriverVer, // [OUT]
  620. VARIANT& vDriverProvider, // [OUT]
  621. VARIANT& vMfgName, // [OUT]
  622. BSTR* pbstrHwidText) // [OUT]
  623. {
  624. USES_IU_CONVERSION;
  625. LOG_Block("OfferThisPrinterDriver");
  626. HRESULT hr = S_OK;
  627. IXMLDOMNode* pDriverNameNode = NULL;
  628. IXMLDOMNode* pDriverProviderNode = NULL;
  629. IXMLDOMNode* pMfgNameNode = NULL;
  630. IXMLDOMNode* pPInfoNode = NULL;
  631. IXMLDOMNode* pHwidNode = NULL;
  632. IXMLDOMNode* pDriverVerNode = NULL;
  633. IXMLDOMNamedNodeMap* pAttribMap = NULL;
  634. LPCTSTR pszCompareHwid = NULL;
  635. #if !(defined(_UNICODE) || defined(UNICODE))
  636. //
  637. // We need to special-case ANSI since we can't use pointers into pbstrHwidText, which is wide
  638. //
  639. TCHAR szHwid[MAX_INF_STRING + 1];
  640. #endif
  641. if (
  642. NULL == pCompHWNode ||
  643. NULL == pfOfferDriver ||
  644. NULL == pbstrHwidText)
  645. {
  646. CleanUpIfFailedAndSetHrMsg(E_INVALIDARG);
  647. }
  648. VariantInit(&vDriverName);
  649. VariantInit(&vDriverVer);
  650. VariantInit(&vDriverProvider);
  651. VariantInit(&vMfgName);
  652. *pfOfferDriver = TRUE;
  653. *pbstrHwidText = NULL;
  654. //
  655. // Get the first <printerInfo/> node of the item (we expect at least one else fail)
  656. //
  657. CleanUpIfFailedAndSetHrMsg(pCompHWNode->selectSingleNode(KEY_CDM_PINFO, &pPInfoNode));
  658. //
  659. // 517297 Ignore non-printer HWIDs in OfferThisPrinterDriver
  660. //
  661. // We may get device nodes that are not marked isPrinter="1" and do not have the <printerInfo/>
  662. // element. We don't offer these device nodes, but it is not an error.
  663. //
  664. if (NULL == pPInfoNode)
  665. {
  666. //
  667. // Change S_FALSE back to S_OK, but don't offer this device
  668. //
  669. hr = S_OK;
  670. *pfOfferDriver = FALSE;
  671. goto CleanUp;
  672. }
  673. CleanUpIfFailedAndSetHrMsg(pPInfoNode->get_attributes(&pAttribMap));
  674. if (NULL == pAttribMap) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  675. //
  676. // suck out the printerInfo attributes
  677. //
  678. CleanUpIfFailedAndSetHrMsg(pAttribMap->getNamedItem(KEY_DRIVERNAME, &pDriverNameNode));
  679. if (NULL == pDriverNameNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  680. CleanUpIfFailedAndSetHrMsg(pAttribMap->getNamedItem(KEY_DRIVERPROVIDER, &pDriverProviderNode));
  681. if (NULL == pDriverProviderNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  682. CleanUpIfFailedAndSetHrMsg(pAttribMap->getNamedItem(KEY_MFGNAME, &pMfgNameNode));
  683. if (NULL == pMfgNameNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  684. //
  685. // pAttribMap will be reused later, free it here
  686. //
  687. SafeReleaseNULL(pAttribMap);
  688. CleanUpIfFailedAndSetHrMsg(pDriverNameNode->get_nodeValue(&vDriverName));
  689. CleanUpIfFailedAndSetHrMsg(pDriverProviderNode->get_nodeValue(&vDriverProvider));
  690. CleanUpIfFailedAndSetHrMsg(pMfgNameNode->get_nodeValue(&vMfgName));
  691. if (VT_BSTR != vDriverName.vt || VT_BSTR != vDriverProvider.vt || VT_BSTR != vMfgName.vt)
  692. {
  693. CleanUpIfFailedAndSetHrMsg(E_FAIL);
  694. }
  695. //
  696. // Get the first <hwid/> node of the item (we expect at least one else fail)
  697. //
  698. CleanUpIfFailedAndSetHrMsg(pCompHWNode->selectSingleNode(KEY_CDM_HWIDPATH, &pHwidNode));
  699. if (NULL == pHwidNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  700. CleanUpIfFailedAndSetHrMsg(pHwidNode->get_attributes(&pAttribMap));
  701. if (NULL == pAttribMap) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  702. //
  703. // suck out the DriverVer attribute
  704. //
  705. CleanUpIfFailedAndSetHrMsg(pAttribMap->getNamedItem(KEY_DRIVERVER, &pDriverVerNode));
  706. if (NULL == pDriverVerNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  707. CleanUpIfFailedAndSetHrMsg(pDriverVerNode->get_nodeValue(&vDriverVer));
  708. if (VT_BSTR != vDriverVer.vt)
  709. {
  710. CleanUpIfFailedAndSetHrMsg(E_FAIL);
  711. }
  712. //
  713. // Get the <hwid/> text
  714. //
  715. // NOTE: Each item is restricted to a single <hwid/> element due to INF syntax,
  716. // however our catalog schema doesn't make similar restrictions and currently our
  717. // backend doesn't distinguish between <hwid/> and <compid/> values, so it is
  718. // possible we could get more than one <hwid/> returned. For the purpose of
  719. // generating INFs for Add Printer Wizard, any <hwid/> from the CAB will do.
  720. //
  721. CleanUpIfFailedAndSetHrMsg(pHwidNode->get_text(pbstrHwidText));
  722. #if !(defined(_UNICODE) || defined(UNICODE))
  723. hr = StringCchCopyEx(szHwid, ARRAYSIZE(szHwid), OLE2T(*pbstrHwidText),
  724. NULL, NULL, MISTSAFE_STRING_FLAGS);
  725. if (FAILED(hr))
  726. {
  727. LOG_ErrorMsg(hr);
  728. goto CleanUp;
  729. }
  730. LOG_Driver(_T("Got \"%s\" from XML for compare to DRIVER_INFO_6."), szHwid);
  731. #else
  732. LOG_Driver(_T("Got \"%s\" from XML for compare to DRIVER_INFO_6."), *pbstrHwidText);
  733. #endif
  734. if (NULL == paDriverInfo6 || 0 == dwDriverInfoCount)
  735. {
  736. LOG_Driver(_T("WARNING: We're missing information (maybe no installed printer drivers), so we won't prune"));
  737. goto CleanUp;
  738. }
  739. #if !(defined(_UNICODE) || defined(UNICODE))
  740. pszCompareHwid = szHwid;
  741. #else
  742. pszCompareHwid = (LPCTSTR) *pbstrHwidText;
  743. #endif
  744. for (DWORD dwCount = 0; dwCount < dwDriverInfoCount; dwCount++)
  745. {
  746. if (NULL == (paDriverInfo6 + dwCount)->pszHardwareID)
  747. {
  748. continue;
  749. }
  750. //
  751. // Use case-insensitive compares (paDriverInfo6 is different case from pszCompareHwid)
  752. //
  753. if (0 != lstrcmpi(pszCompareHwid, (paDriverInfo6 + dwCount)->pszHardwareID))
  754. {
  755. continue;
  756. }
  757. //
  758. // Else we have a hardware match - check the other attributes for exact match
  759. //
  760. if (0 != lstrcmpi(OLE2T(vDriverName.bstrVal), (paDriverInfo6 + dwCount)->pName) ||
  761. 0 != lstrcmpi(OLE2T(vDriverProvider.bstrVal), (paDriverInfo6 + dwCount)->pszProvider) ||
  762. 0 != lstrcmpi(OLE2T(vMfgName.bstrVal), (paDriverInfo6 + dwCount)->pszMfgName))
  763. {
  764. //
  765. LOG_Driver(_T("Prune this driver: it doesn't match all the attributes of the installed driver"));
  766. *pfOfferDriver = FALSE;
  767. goto CleanUp;
  768. }
  769. //
  770. // The driver matches, but make sure it has a newer DriverVer than the installed driver
  771. //
  772. LOG_Driver(_T("Driver item in catalog is compatible with installed driver"));
  773. SYSTEMTIME systemTime;
  774. if (0 == FileTimeToSystemTime((CONST FILETIME*) &((paDriverInfo6 + dwCount)->ftDriverDate), &systemTime))
  775. {
  776. Win32MsgSetHrGotoCleanup(GetLastError());
  777. }
  778. //
  779. // Convert to ISO ISO 8601 prefered format (yyyy-mm-dd) so we can string compare with catalog BSTR
  780. //
  781. WCHAR wszDriverVer[11];
  782. hr = StringCchPrintfExW(wszDriverVer, ARRAYSIZE(wszDriverVer), NULL, NULL, MISTSAFE_STRING_FLAGS,
  783. L"%04d-%02d-%02d", systemTime.wYear, systemTime.wMonth, systemTime.wDay);
  784. if (FAILED(hr))
  785. {
  786. LOG_ErrorMsg(hr);
  787. goto CleanUp;
  788. }
  789. if (0 < lstrcmpW(vDriverVer.bstrVal, wszDriverVer))
  790. {
  791. LOG_Driver(_T("WU DriverVer (%s) is > installed (%s)"), vDriverVer.bstrVal, wszDriverVer);
  792. *pfOfferDriver = TRUE;
  793. goto CleanUp;
  794. }
  795. else
  796. {
  797. LOG_Driver(_T("Prune this driver: WU DriverVer (%s) is <= installed (%s)"), vDriverVer.bstrVal, wszDriverVer);
  798. *pfOfferDriver = FALSE;
  799. #if defined(__WUIUTEST)
  800. // DriverVer Override for ==
  801. HKEY hKey;
  802. int error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WUIUTEST, 0, KEY_READ, &hKey);
  803. if (ERROR_SUCCESS == error)
  804. {
  805. DWORD dwSize = sizeof(DWORD);
  806. DWORD dwValue;
  807. error = RegQueryValueEx(hKey, REGVAL_ALLOW_EQUAL_DRIVERVER, 0, 0, (LPBYTE) &dwValue, &dwSize);
  808. if (ERROR_SUCCESS == error && 1 == dwValue)
  809. {
  810. //
  811. // If DriverVers are equal (we already installed a driver from WU, allow it anyway
  812. //
  813. if (0 == lstrcmpW(vDriverVer.bstrVal, wszDriverVer))
  814. {
  815. *pfOfferDriver = TRUE;
  816. LOG_Driver(_T("WU DriverVer (%s) is = installed (%s), WUIUTEST override and offer"), vDriverVer.bstrVal, wszDriverVer);
  817. }
  818. }
  819. RegCloseKey(hKey);
  820. }
  821. #endif
  822. goto CleanUp;
  823. }
  824. }
  825. CleanUp:
  826. if (FAILED(hr))
  827. {
  828. if (NULL != pfOfferDriver)
  829. {
  830. *pfOfferDriver = FALSE;
  831. }
  832. if (NULL != pbstrHwidText)
  833. {
  834. SafeSysFreeString(*pbstrHwidText);
  835. }
  836. VariantClear(&vDriverName);
  837. VariantClear(&vDriverVer);
  838. VariantClear(&vDriverProvider);
  839. VariantClear(&vMfgName);
  840. }
  841. SafeReleaseNULL(pDriverNameNode);
  842. SafeReleaseNULL(pDriverProviderNode);
  843. SafeReleaseNULL(pMfgNameNode);
  844. SafeReleaseNULL(pPInfoNode);
  845. SafeReleaseNULL(pHwidNode);
  846. SafeReleaseNULL(pDriverVerNode);
  847. SafeReleaseNULL(pAttribMap);
  848. return hr;
  849. }
  850. HRESULT GetInstalledPrinterDriverInfo(const OSVERSIONINFO* pOsVersionInfo, DRIVER_INFO_6** ppaDriverInfo6, DWORD* pdwDriverInfoCount)
  851. {
  852. LOG_Block("GetInstalledPrinterDriverInfo");
  853. HRESULT hr = S_OK;
  854. DWORD dwBytesNeeded;
  855. if (NULL == pOsVersionInfo || NULL == ppaDriverInfo6 || NULL == pdwDriverInfoCount)
  856. {
  857. LOG_ErrorMsg(E_INVALIDARG);
  858. return E_INVALIDARG;
  859. }
  860. *pdwDriverInfoCount = 0;
  861. *ppaDriverInfo6 = NULL;
  862. LPTSTR pszEnvironment;
  863. if (VER_PLATFORM_WIN32_WINDOWS == pOsVersionInfo->dwPlatformId)
  864. {
  865. //
  866. // Don't pass an environment string for Win9x
  867. //
  868. pszEnvironment = NULL;
  869. }
  870. else if (5 <= pOsVersionInfo->dwMajorVersion && 1 <= pOsVersionInfo->dwMinorVersion)
  871. {
  872. //
  873. // Use EPD_ALL_LOCAL_AND_CLUSTER only on Whistler and up
  874. //
  875. pszEnvironment = EPD_ALL_LOCAL_AND_CLUSTER;
  876. }
  877. else
  878. {
  879. //
  880. // From V3 sources (hard-coded for NT)
  881. //
  882. pszEnvironment = _T("all");
  883. }
  884. if(!EnumPrinterDrivers(NULL, pszEnvironment, 6, NULL, 0, &dwBytesNeeded, pdwDriverInfoCount))
  885. {
  886. if (ERROR_INSUFFICIENT_BUFFER != GetLastError() || (0 == dwBytesNeeded))
  887. {
  888. LOG_Driver(_T("No printer drivers enumerated"));
  889. }
  890. else
  891. {
  892. //
  893. // Allocate the requested buffer
  894. //
  895. CleanUpFailedAllocSetHrMsg(*ppaDriverInfo6 = (DRIVER_INFO_6*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded));
  896. //
  897. // Fill in DRIVER_INFO_6 array
  898. //
  899. if (!EnumPrinterDrivers(NULL, pszEnvironment, 6, (LPBYTE) *ppaDriverInfo6, dwBytesNeeded, &dwBytesNeeded, pdwDriverInfoCount))
  900. {
  901. Win32MsgSetHrGotoCleanup(GetLastError());
  902. }
  903. LOG_Driver(_T("%d printer drivers found"), *pdwDriverInfoCount);
  904. //
  905. // Validate the driver elements for each printer driver.
  906. //
  907. for (DWORD dwCount = 0; dwCount < *pdwDriverInfoCount; dwCount++)
  908. {
  909. if ( NULL == (*ppaDriverInfo6 + dwCount)->pszHardwareID
  910. || NULL == (*ppaDriverInfo6 + dwCount)->pszProvider
  911. || NULL == (*ppaDriverInfo6 + dwCount)->pszMfgName
  912. || NULL == (*ppaDriverInfo6 + dwCount)->pName )
  913. {
  914. LOG_Driver(_T("Skiping driver with incomplete ID info: set pszHardwareID = NULL"));
  915. //
  916. // We use pszHardwareID == NULL to invalidate incomplete entry
  917. //
  918. (*ppaDriverInfo6 + dwCount)->pszHardwareID = NULL;
  919. continue;
  920. }
  921. }
  922. }
  923. }
  924. CleanUp:
  925. if (FAILED(hr))
  926. {
  927. SafeHeapFree(*ppaDriverInfo6);
  928. *ppaDriverInfo6 = NULL;
  929. *pdwDriverInfoCount = 0;
  930. }
  931. return hr;
  932. }
  933. //
  934. // Build and write to disk Printer INFs constructed from printer items available
  935. // on this platform. Also prunes printer drivers that would conflict with installed
  936. // drivers (e.g. Unidriver vs. Monolithic, etc.).
  937. //
  938. HRESULT PruneAndBuildPrinterINFs(BSTR bstrXmlPrinterCatalog, LPTSTR lpDownloadPath, DWORD cchDownloadPath, DRIVER_INFO_6* paDriverInfo6, DWORD dwDriverInfoCount)
  939. {
  940. USES_IU_CONVERSION;
  941. LOG_Block("PruneAndBuildPrinterINFs");
  942. HRESULT hr;
  943. HANDLE hFile = INVALID_HANDLE_VALUE;
  944. const TCHAR SZ_PLISTDIR[] = _T("CDMPlist\\");
  945. DWORD dwWritten;
  946. LONG lLength;
  947. VARIANT vDriverName;
  948. VARIANT vDriverVer;
  949. VARIANT vDriverProvider;
  950. VARIANT vMfgName;
  951. VariantInit(&vDriverName);
  952. VariantInit(&vDriverVer);
  953. VariantInit(&vDriverProvider);
  954. VariantInit(&vMfgName);
  955. BOOL fOfferDriver = FALSE;
  956. BSTR bstrHwidText = NULL;
  957. IXMLDOMNode* pCompHWNode = NULL;
  958. LPTSTR pszInfDirPath = NULL;
  959. LPTSTR pszInfFilePath = NULL;
  960. LPOLESTR pwszDriverProvider = NULL;
  961. LPTSTR pszMfgName = NULL;
  962. LPTSTR pszDriverName = NULL;
  963. LPTSTR pszInstallSection = NULL;
  964. CXmlPrinterCatalogList xmlItemList;
  965. if (NULL == bstrXmlPrinterCatalog || NULL == lpDownloadPath || 0 == cchDownloadPath)
  966. {
  967. LOG_ErrorMsg(E_INVALIDARG);
  968. return E_INVALIDARG;
  969. }
  970. lpDownloadPath[0] = _T('\0');
  971. //
  972. // Dynamically allocate buffers (PreFast warning 831: This function uses 5884 bytes of stack,
  973. // consider moving some data to heap.)
  974. //
  975. pszInfDirPath = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(TCHAR));
  976. pszInfFilePath = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(TCHAR));
  977. pwszDriverProvider = (LPOLESTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_INF_STRING * sizeof(OLECHAR));
  978. pszMfgName = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_INF_STRING * sizeof(TCHAR));
  979. pszDriverName = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_INF_STRING * sizeof(TCHAR));
  980. pszInstallSection = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_INF_STRING * sizeof(TCHAR));
  981. if (NULL == pszInfDirPath ||
  982. NULL == pszInfFilePath ||
  983. NULL == pwszDriverProvider ||
  984. NULL == pszMfgName ||
  985. NULL == pszDriverName ||
  986. NULL == pszInstallSection )
  987. {
  988. SetHrMsgAndGotoCleanUp(E_OUTOFMEMORY);
  989. }
  990. //
  991. // Create the directory for the INFs after deleting any existing directory
  992. //
  993. GetIndustryUpdateDirectory((LPTSTR) pszInfDirPath);
  994. if ((MAX_PATH) < (lstrlen(pszInfDirPath) + ARRAYSIZE(SZ_PLISTDIR) + 1))
  995. {
  996. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  997. }
  998. // pszInfDirPath was alloced to be MAX_PATH above
  999. hr = PathCchAppend(pszInfDirPath, MAX_PATH, SZ_PLISTDIR);
  1000. if (FAILED(hr))
  1001. {
  1002. LOG_ErrorMsg(hr);
  1003. goto CleanUp;
  1004. }
  1005. //
  1006. // Delete any existing INFs and recreate the directory - we'll get fresh content
  1007. //
  1008. LOG_Driver(_T("SafeDeleteFolderAndContents: %s"), pszInfDirPath);
  1009. (void) SafeDeleteFolderAndContents(pszInfDirPath, SDF_DELETE_READONLY_FILES | SDF_CONTINUE_IF_ERROR);
  1010. hr = CreateDirectoryAndSetACLs(pszInfDirPath, TRUE);
  1011. CleanUpIfFailedAndMsg(hr);
  1012. //
  1013. // Load the XML and get the <compatibleHardware/> list and number of items
  1014. //
  1015. // NOTE: each <compatibleHardware/> element contains a single unique driver.
  1016. // In the event we get duplicates with different driverVer's we really don't care
  1017. // as the last one will overright the previous instances and Add Printer Wizard
  1018. // doesn't look at driverVer (we prune if it's too old).
  1019. //
  1020. CleanUpIfFailedAndSetHr(xmlItemList.LoadXMLDocumentAndGetCompHWList(bstrXmlPrinterCatalog));
  1021. CleanUpIfFailedAndSetHrMsg(xmlItemList.m_pCompHWNodeList->get_length(&lLength));
  1022. for (LONG l = 0; l < lLength; l++)
  1023. {
  1024. //
  1025. // Get the next <item/> node from list
  1026. //
  1027. CleanUpIfFailedAndSetHrMsg(xmlItemList.m_pCompHWNodeList->nextNode(&pCompHWNode));
  1028. if (NULL == pCompHWNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1029. //
  1030. // Check the driver against installed printer drivers for compatibility and prune if
  1031. // incompatible or DriverVer <= installed DriverVer.
  1032. //
  1033. CleanUpIfFailedAndSetHr(OfferThisPrinterDriver(paDriverInfo6, dwDriverInfoCount, pCompHWNode, &fOfferDriver, \
  1034. vDriverName, vDriverVer, vDriverProvider, vMfgName, &bstrHwidText));
  1035. SafeReleaseNULL(pCompHWNode);
  1036. if (!fOfferDriver)
  1037. {
  1038. LOG_Driver(_T("Pruning hwid = %s, driverVer = %s, driverName = %s, driverProvider = %s, driverMfgr = %s"),\
  1039. OLE2T(bstrHwidText), OLE2T(vDriverVer.bstrVal), \
  1040. OLE2T(vDriverName.bstrVal), OLE2T(vDriverProvider.bstrVal), OLE2T(vMfgName.bstrVal) );
  1041. VariantClear(&vDriverName);
  1042. VariantClear(&vDriverVer);
  1043. VariantClear(&vDriverProvider);
  1044. VariantClear(&vMfgName);
  1045. SafeSysFreeString(bstrHwidText);
  1046. continue;
  1047. }
  1048. LOG_Driver(_T("Adding hwid = %s, driverVer = %s, driverName = %s, driverProvider = %s, driverMfgr = %s to INF"),\
  1049. OLE2T(bstrHwidText), OLE2T(vDriverVer.bstrVal), \
  1050. OLE2T(vDriverName.bstrVal), OLE2T(vDriverProvider.bstrVal), OLE2T(vMfgName.bstrVal) );
  1051. if (0 != lstrcmpiW(pwszDriverProvider, vDriverProvider.bstrVal))
  1052. {
  1053. // pwszDriverProvider was alloced to be MAX_INF_STRING * sizeof(OLECHAR) above.
  1054. hr = StringCchCopyExW(pwszDriverProvider, MAX_INF_STRING, vDriverProvider.bstrVal,
  1055. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1056. CleanUpIfFailedAndSetHr(hr);
  1057. //
  1058. // Open pszInfFilePath and initialize with "header" an INF file based on pwszDriverProvider.
  1059. // If it already exists, just open it (and return existing pszInfFilePath)
  1060. //
  1061. // pszInfFilePath is allocated to be MAX_PATH above.
  1062. CleanUpIfFailedAndSetHr(OpenUniqueProviderInfName(pszInfDirPath, OLE2T(pwszDriverProvider), pszInfFilePath, MAX_PATH, hFile));
  1063. //
  1064. // Once the file is initialized, we don't need to keep it open
  1065. //
  1066. CloseHandle(hFile);
  1067. hFile = INVALID_HANDLE_VALUE;
  1068. }
  1069. //
  1070. // Write the mfgName in the [Manufacturer] section, for example
  1071. // [Manufacturer]
  1072. // "Ricoh"="Ricoh"
  1073. //
  1074. // ISSUE-2001/02/05-waltw Could optimize by caching last known name like provider above...
  1075. // pszMfgName is alloced to be MAX_INF_STRING characters above
  1076. hr = StringCchPrintfEx(pszMfgName, MAX_INF_STRING, NULL, NULL, MISTSAFE_STRING_FLAGS,
  1077. _T("\"%s\""), (LPCTSTR) OLE2T(vMfgName.bstrVal));
  1078. CleanUpIfFailedAndSetHr(hr);
  1079. if (0 == WritePrivateProfileString(_T("Manufacturer"), pszMfgName, pszMfgName, pszInfFilePath))
  1080. {
  1081. Win32MsgSetHrGotoCleanup(GetLastError());
  1082. }
  1083. // pszDriverName is alloced to be MAX_INF_STRING characters above
  1084. hr = StringCchPrintfEx(pszDriverName, MAX_INF_STRING, NULL, NULL, MISTSAFE_STRING_FLAGS,
  1085. _T("\"%s\""), OLE2T(vDriverName.bstrVal));
  1086. CleanUpIfFailedAndSetHr(hr);
  1087. // pszInstallSection is alloced to be MAX_INF_STRING characters above
  1088. hr = StringCchPrintfEx(pszInstallSection, MAX_INF_STRING, NULL, NULL, MISTSAFE_STRING_FLAGS,
  1089. _T("InstallSection,\"%s\""), OLE2T(bstrHwidText));
  1090. CleanUpIfFailedAndSetHr(hr);
  1091. //
  1092. // Write printer item in [mfgName] section, for example:
  1093. // [RICOH]
  1094. // "RICOH Aficio 850 PCL 6"=InstallSection,"LPTENUM\RICOHAFICIO_850F1B7"
  1095. if (0 == WritePrivateProfileString(OLE2T(vMfgName.bstrVal), pszDriverName, pszInstallSection, pszInfFilePath))
  1096. {
  1097. Win32MsgSetHrGotoCleanup(GetLastError());
  1098. }
  1099. VariantClear(&vDriverName);
  1100. VariantClear(&vDriverVer);
  1101. VariantClear(&vDriverProvider);
  1102. VariantClear(&vMfgName);
  1103. SafeSysFreeString(bstrHwidText);
  1104. }
  1105. CleanUp:
  1106. if(SUCCEEDED(hr))
  1107. {
  1108. hr = StringCchCopyEx(lpDownloadPath, cchDownloadPath, pszInfDirPath,
  1109. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1110. if (FAILED(hr))
  1111. {
  1112. lpDownloadPath[0] = _T('\0');
  1113. LOG_ErrorMsg(hr);
  1114. }
  1115. }
  1116. if (INVALID_HANDLE_VALUE != hFile)
  1117. {
  1118. CloseHandle(hFile);
  1119. hFile = INVALID_HANDLE_VALUE;
  1120. }
  1121. VariantClear(&vDriverName);
  1122. VariantClear(&vDriverVer);
  1123. VariantClear(&vDriverProvider);
  1124. VariantClear(&vMfgName);
  1125. SafeHeapFree(pszInfDirPath);
  1126. SafeHeapFree(pszInfFilePath);
  1127. SafeHeapFree(pwszDriverProvider);
  1128. SafeHeapFree(pszMfgName);
  1129. SafeHeapFree(pszDriverName);
  1130. SafeHeapFree(pszInstallSection);
  1131. SafeSysFreeString(bstrHwidText);
  1132. SafeReleaseNULL(pCompHWNode);
  1133. return hr;
  1134. }
  1135. BOOL HwidMatchesDeviceInfo(HDEVINFO hDevInfoSet, SP_DEVINFO_DATA deviceInfoData, LPCTSTR pszHardwareID)
  1136. {
  1137. LOG_Block("HwidMatchesDeviceInfo");
  1138. HRESULT hr = S_OK;
  1139. LPTSTR pszMultiHwid = NULL;
  1140. LPTSTR pszMultiCompid = NULL;
  1141. LPTSTR pszTemp;
  1142. //
  1143. // Get the Hardware and Compatible Multi-SZ strings so we can prune printer devices before commiting to XML.
  1144. //
  1145. CleanUpIfFailedAndSetHr(GetMultiSzDevRegProp(hDevInfoSet, &deviceInfoData, SPDRP_HARDWAREID, &pszMultiHwid));
  1146. CleanUpIfFailedAndSetHr(GetMultiSzDevRegProp(hDevInfoSet, &deviceInfoData, SPDRP_COMPATIBLEIDS, &pszMultiCompid));
  1147. //
  1148. // Do we have a match with an enumerated device HWID or Compatible ID?
  1149. //
  1150. if (NULL != pszMultiHwid)
  1151. {
  1152. for(pszTemp = pszMultiHwid; *pszTemp; pszTemp += (lstrlen(pszTemp) + 1))
  1153. {
  1154. if (0 == lstrcmpi(pszTemp, pszHardwareID))
  1155. {
  1156. LOG_Driver(_T("This deviceInfoData matches HWID %s"), pszHardwareID);
  1157. goto CleanUp;
  1158. }
  1159. }
  1160. }
  1161. if (NULL != pszMultiCompid)
  1162. {
  1163. for(pszTemp = pszMultiCompid; *pszTemp; pszTemp += (lstrlen(pszTemp) + 1))
  1164. {
  1165. if (0 == lstrcmpi(pszTemp, pszHardwareID))
  1166. {
  1167. LOG_Driver(_T("This deviceInfoData matches HWID %s"), pszHardwareID);
  1168. goto CleanUp;
  1169. }
  1170. }
  1171. }
  1172. //
  1173. // We didn't find a match
  1174. //
  1175. LOG_Driver(_T("Failed to find a matching HWID or Printer ID for %s"), pszHardwareID);
  1176. hr = E_FAIL;
  1177. CleanUp:
  1178. SafeHeapFree(pszMultiHwid);
  1179. SafeHeapFree(pszMultiCompid);
  1180. return (SUCCEEDED(hr));
  1181. }
  1182. // This function is called to download the actual package.
  1183. //
  1184. // If this function is successfull then it returns S_OK. If the case of a
  1185. // failure this function returns an error code.
  1186. HRESULT GetPackage(
  1187. IN ENUM_GETPKG eFunction, // Function to be performed by GetPackage
  1188. IN PDOWNLOADINFO pDownloadInfo, // DownloadInformation structure describing package to be read from server
  1189. OUT LPTSTR lpDownloadPath, // Pointer to local directory on the client computer system
  1190. // where the downloaded files are to be stored. NOTE: OK to pass NULL if
  1191. // GET_CATALOG_XML == eFunction.
  1192. IN DWORD cchDownloadPath,
  1193. OUT BSTR* pbstrXmlCatalog // On SUCCESS, catalog is always allocated - caller must call SysFreeString()
  1194. )
  1195. {
  1196. USES_IU_CONVERSION;
  1197. LOG_Block("GetPackage");
  1198. HRESULT hr;
  1199. BSTR bstrXmlSystemSpec = NULL;
  1200. BSTR bstrXmlClientInfo = NULL;
  1201. BSTR bstrXmlQuery = NULL;
  1202. BSTR bstrXmlDownloadedItems = NULL;
  1203. BSTR bstrDownloadStatus = NULL;
  1204. BSTR bstrStatusValue = NULL;
  1205. BSTR bstrProvider = NULL;
  1206. BSTR bstrMfgName = NULL;
  1207. BSTR bstrName = NULL;
  1208. BSTR bstrHardwareID = NULL;
  1209. BSTR bstrDriverVer = NULL;
  1210. IU_PLATFORM_INFO iuPlatformInfo;
  1211. HDEVINFO hDevInfoSet = INVALID_HANDLE_VALUE;
  1212. SP_DEVINFO_DATA devInfoData;
  1213. DRIVER_INFO_6* paDriverInfo6 = NULL;
  1214. DWORD dwDriverInfoCount = 0;
  1215. LPCTSTR pszHardwareID = NULL; // pDownloadInfo LPCWSTR converted to ANSI (automatically freed by IU_CONVERSION)
  1216. // OR just points to LPCWSTR pDownloadInfo->lpHardwareIDs or ->lpDeviceInstanceID
  1217. DWORD dwDeviceIndex;
  1218. BOOL fHwidMatchesInstalledPrinter = FALSE;
  1219. BOOL fAPWNewPrinter = FALSE;
  1220. HANDLE_NODE hPrinterDevNode = HANDLE_NODE_INVALID;
  1221. HANDLE_NODE hDevices = HANDLE_NODE_INVALID;
  1222. DWORD dwCount;
  1223. CXmlSystemSpec xmlSpec;
  1224. CXmlDownloadResult xmlItemStatusList;
  1225. IXMLDOMNode* pItemStatus = NULL;
  1226. IXMLDOMNode* pStatusNode = NULL;
  1227. IXMLDOMNode* pValueNode = NULL;
  1228. IXMLDOMNamedNodeMap* pAttribMap = NULL;
  1229. VARIANT vStatusValue;
  1230. LPTSTR pszMatchingID = NULL;
  1231. LPTSTR pszDriverVer= NULL;
  1232. //
  1233. // Initialize variant before any possible jump to CleanUp (BUG: 467098)
  1234. //
  1235. VariantInit(&vStatusValue);
  1236. if (NULL == pDownloadInfo ||
  1237. (NULL == lpDownloadPath && GET_CATALOG_XML != eFunction) ||
  1238. NULL == pbstrXmlCatalog ||
  1239. NULL == g_pCDMEngUpdate)
  1240. {
  1241. hr = E_INVALIDARG;
  1242. return E_INVALIDARG;
  1243. }
  1244. if (NULL != lpDownloadPath && cchDownloadPath > 0)
  1245. {
  1246. lpDownloadPath[0] = _T('\0');
  1247. }
  1248. *pbstrXmlCatalog = NULL;
  1249. //
  1250. // Get iuPlatformInfo, but remember to clean up BSTRs on function exit
  1251. //
  1252. CleanUpIfFailedAndSetHr(DetectClientIUPlatform(&iuPlatformInfo));
  1253. //
  1254. // Get array of DRIVER_INFO_6 holding info on installed printer drivers. Only allocates and returns
  1255. // memory for appropriate platforms that have printer drivers already installed.
  1256. //
  1257. CleanUpIfFailedAndSetHr(GetInstalledPrinterDriverInfo((OSVERSIONINFO*) &iuPlatformInfo.osVersionInfoEx, &paDriverInfo6, &dwDriverInfoCount));
  1258. //
  1259. // Build common bstrXmlClientInfo and parts of bstrXmlSystemSpec
  1260. //
  1261. if (NULL == (bstrXmlClientInfo = SysAllocString((OLECHAR*) &szXmlClientInfo)))
  1262. {
  1263. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  1264. }
  1265. //
  1266. // Add Computer System
  1267. //
  1268. CleanUpIfFailedAndSetHr(AddComputerSystemClass(xmlSpec));
  1269. //
  1270. // Add Platform
  1271. //
  1272. CleanUpIfFailedAndSetHr(AddPlatformClass(xmlSpec, iuPlatformInfo));
  1273. //
  1274. // Add OS & USER Locale information
  1275. //
  1276. CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, FALSE));
  1277. CleanUpIfFailedAndSetHr(AddLocaleClass(xmlSpec, TRUE));
  1278. //
  1279. // If GET_PRINTER_INFS, we are retrieving a list of supported printers (V3 PLIST format) rather than a driver
  1280. //
  1281. switch (eFunction)
  1282. {
  1283. case GET_PRINTER_INFS:
  1284. {
  1285. CleanUpFailedAllocSetHrMsg(bstrXmlQuery = SysAllocString(szXmlPrinterCatalogQuery));
  1286. CleanUpIfFailedAndSetHr(xmlSpec.GetSystemSpecBSTR(&bstrXmlSystemSpec));
  1287. //
  1288. // GetManifest will ResetEvent, so check before calling
  1289. //
  1290. if (WaitForSingleObject(g_pCDMEngUpdate->m_evtNeedToQuit, 0) == WAIT_OBJECT_0)
  1291. {
  1292. CleanUpIfFailedAndSetHrMsg(E_ABORT);
  1293. }
  1294. CleanUpIfFailedAndSetHrMsg(g_pCDMEngUpdate->GetManifest(bstrXmlClientInfo, bstrXmlSystemSpec, bstrXmlQuery, FLAG_USE_COMPRESSION, pbstrXmlCatalog));
  1295. LOG_XmlBSTR(*pbstrXmlCatalog);
  1296. //
  1297. // Now, convert the returned pbstrXmlCatalog to an inf file per provider and write to a temporary location
  1298. //
  1299. CleanUpIfFailedAndSetHr(PruneAndBuildPrinterINFs(*pbstrXmlCatalog, lpDownloadPath, cchDownloadPath, paDriverInfo6, dwDriverInfoCount));
  1300. break;
  1301. }
  1302. case DOWNLOAD_DRIVER:
  1303. case GET_CATALOG_XML:
  1304. {
  1305. //
  1306. // Put either the Hardware & Compatible ID from the DeviceInstanceID or printer info from DRIVER_INFO_6
  1307. // or <hwid> passed by APW into a systemspec to pass to server with driver query.
  1308. //
  1309. if (NULL != pDownloadInfo->lpDeviceInstanceID)
  1310. {
  1311. if (INVALID_HANDLE_VALUE == (hDevInfoSet = (HDEVINFO)SetupDiCreateDeviceInfoList(NULL, NULL)))
  1312. {
  1313. Win32MsgSetHrGotoCleanup(GetLastError());
  1314. }
  1315. //
  1316. // This is the Device Instance ID for an installed hardware device
  1317. //
  1318. ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
  1319. devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1320. #if !(defined(_UNICODE) || defined(UNICODE))
  1321. // OK to cast away const-ness since OLE2T copies string for ANSI
  1322. pszHardwareID = OLE2T(const_cast<LPWSTR>(pDownloadInfo->lpDeviceInstanceID));
  1323. CleanUpFailedAllocSetHrMsg(pszHardwareID);
  1324. #else
  1325. pszHardwareID = pDownloadInfo->lpDeviceInstanceID;
  1326. #endif
  1327. if (!SetupDiOpenDeviceInfo(hDevInfoSet, pszHardwareID, 0, 0, &devInfoData))
  1328. {
  1329. Win32MsgSetHrGotoCleanup(GetLastError());
  1330. }
  1331. }
  1332. else if (NULL != pDownloadInfo->lpHardwareIDs)
  1333. {
  1334. // one hardware id for a package - either printers or w9x if we cannot find device instance ID
  1335. // if architecture is not the same as current archtecture we need to prefix it
  1336. SYSTEM_INFO sysInfo;
  1337. GetSystemInfo(&sysInfo);
  1338. if (pDownloadInfo->dwArchitecture != (DWORD) sysInfo.wProcessorArchitecture)
  1339. {
  1340. // Supporting PRINT_ENVIRONMENT_INTEL and PRINT_ENVIRONMENT_ALPHA prefixes
  1341. // was V3 legacy functionality that was never used (originally intended to
  1342. // support installation of non-native architecture drivers on print servers).
  1343. // Since this feature isn't required or expected by the print team for
  1344. // Windows Update functionality, we simply retain the compare as a sanity
  1345. // check in case one of our clients forgets this.
  1346. SetHrMsgAndGotoCleanUp(E_NOTIMPL);
  1347. }
  1348. #if !(defined(_UNICODE) || defined(UNICODE))
  1349. // OK to cast away const-ness since OLE2T copies string for ANSI
  1350. pszHardwareID = OLE2T(const_cast<LPWSTR>(pDownloadInfo->lpHardwareIDs));
  1351. CleanUpFailedAllocSetHrMsg(pszHardwareID);
  1352. #else
  1353. pszHardwareID = pDownloadInfo->lpHardwareIDs;
  1354. #endif
  1355. //
  1356. // First see if we can match an installed printer driver HWID to the pszHardwareID
  1357. //
  1358. for (dwCount = 0; dwCount < dwDriverInfoCount; dwCount++)
  1359. {
  1360. if (NULL == (paDriverInfo6 + dwCount)->pszHardwareID)
  1361. {
  1362. LOG_Driver(_T("Skipping NULL printer driver index %d"), dwCount);
  1363. continue;
  1364. }
  1365. //
  1366. // Use case-insensitive compares (paDriverInfo6 is different case from pszHardwareID)
  1367. //
  1368. if (0 != lstrcmpi(pszHardwareID, (paDriverInfo6 + dwCount)->pszHardwareID))
  1369. {
  1370. continue;
  1371. }
  1372. LOG_Driver(_T("Found match with an installed printer driver dwCount = %d"), dwCount);
  1373. fHwidMatchesInstalledPrinter = TRUE;
  1374. break;
  1375. }
  1376. if (!fHwidMatchesInstalledPrinter)
  1377. {
  1378. LOG_Driver(_T("Didn't find an installed printer driver with a matching HWID, enumerating the PnP IDs..."));
  1379. //
  1380. // We couldn't find a matching installed printer, so now
  1381. // enumerate all the PnP IDs and try to find a matching node to
  1382. // add to the system spec
  1383. //
  1384. if (INVALID_HANDLE_VALUE == (hDevInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES)))
  1385. {
  1386. Win32MsgSetHrGotoCleanup(GetLastError());
  1387. }
  1388. ZeroMemory(&devInfoData, sizeof(SP_DEVINFO_DATA));
  1389. devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1390. BOOL fRet;
  1391. dwDeviceIndex = 0;
  1392. while (fRet = SetupDiEnumDeviceInfo(hDevInfoSet, dwDeviceIndex++, &devInfoData))
  1393. {
  1394. //
  1395. // Find a matching ID (could spit out Device Instance ID using SetupDiGetDeviceInstanceId for debug)
  1396. //
  1397. if (HwidMatchesDeviceInfo(hDevInfoSet, devInfoData, pszHardwareID))
  1398. {
  1399. break;
  1400. }
  1401. }
  1402. if (!fRet)
  1403. {
  1404. //
  1405. // We hit the end of the list without finding a match
  1406. //
  1407. if (ERROR_NO_MORE_ITEMS == GetLastError())
  1408. {
  1409. LOG_Driver(_T("Couldn't find a matching device instance enumerating the PnP devices - must be APW request for new printer"));
  1410. fAPWNewPrinter = TRUE;
  1411. }
  1412. else
  1413. {
  1414. Win32MsgSetHrGotoCleanup(GetLastError());
  1415. }
  1416. }
  1417. }
  1418. }
  1419. else
  1420. {
  1421. SetHrMsgAndGotoCleanUp(E_INVALIDARG);
  1422. }
  1423. //
  1424. // We either found a matching printer driver or PnP device instance - add it to the system spec.
  1425. // if DriverVer > installed DriverVer - for printer we have additional requirements
  1426. //
  1427. //
  1428. if (fHwidMatchesInstalledPrinter)
  1429. {
  1430. //
  1431. // Open a <device> element to write the printer info
  1432. //
  1433. bstrProvider = T2BSTR((paDriverInfo6 + dwCount)->pszProvider);
  1434. bstrMfgName = T2BSTR((paDriverInfo6 + dwCount)->pszMfgName);
  1435. bstrName = T2BSTR((paDriverInfo6 + dwCount)->pName);
  1436. CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(NULL, 1, bstrProvider, \
  1437. bstrMfgName, bstrName, &hPrinterDevNode));
  1438. SafeSysFreeString(bstrProvider);
  1439. SafeSysFreeString(bstrMfgName);
  1440. SafeSysFreeString(bstrName);
  1441. //
  1442. // Convert ftDriverDate to ISO 8601 prefered format (yyyy-mm-dd)
  1443. //
  1444. SYSTEMTIME systemTime;
  1445. if (0 == FileTimeToSystemTime((CONST FILETIME*) &((paDriverInfo6 + dwCount)->ftDriverDate), &systemTime))
  1446. {
  1447. LOG_Error(_T("FileTimeToSystemTime failed:"));
  1448. LOG_ErrorMsg(GetLastError());
  1449. SetHrAndGotoCleanUp(HRESULT_FROM_WIN32(GetLastError()));
  1450. }
  1451. TCHAR szDriverVer[11];
  1452. hr = StringCchPrintfEx(szDriverVer, ARRAYSIZE(szDriverVer), NULL, NULL, MISTSAFE_STRING_FLAGS,
  1453. _T("%04d-%02d-%02d"), systemTime.wYear, systemTime.wMonth, systemTime.wDay);
  1454. if (FAILED(hr))
  1455. {
  1456. LOG_ErrorMsg(hr);
  1457. goto CleanUp;
  1458. }
  1459. // Always rank 0 and never fIsCompatible
  1460. bstrHardwareID = T2BSTR((paDriverInfo6 + dwCount)->pszHardwareID);
  1461. bstrDriverVer = T2BSTR(szDriverVer);
  1462. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hPrinterDevNode, FALSE, 0, \
  1463. bstrHardwareID, bstrDriverVer));
  1464. SafeSysFreeString(bstrHardwareID);
  1465. SafeSysFreeString(bstrDriverVer);
  1466. xmlSpec.SafeCloseHandleNode(hPrinterDevNode);
  1467. #if defined(DBG)
  1468. //
  1469. // Need to copy strings to non-const for OLE2T conversion (ANSI)
  1470. //
  1471. TCHAR szbufHardwareID[MAX_PATH];
  1472. TCHAR szbufDriverName[MAX_PATH];
  1473. TCHAR szbufDriverProvider[MAX_PATH];
  1474. TCHAR szbufMfgName[MAX_PATH];
  1475. hr = StringCchCopyEx(szbufHardwareID, ARRAYSIZE(szbufHardwareID),
  1476. (paDriverInfo6 + dwCount)->pszHardwareID,
  1477. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1478. if (FAILED(hr))
  1479. {
  1480. LOG_ErrorMsg(hr);
  1481. goto CleanUp;
  1482. }
  1483. hr = StringCchCopyEx(szbufDriverName, ARRAYSIZE(szbufDriverName),
  1484. (paDriverInfo6 + dwCount)->pName,
  1485. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1486. if (FAILED(hr))
  1487. {
  1488. LOG_ErrorMsg(hr);
  1489. goto CleanUp;
  1490. }
  1491. hr = StringCchCopyEx(szbufDriverProvider, ARRAYSIZE(szbufDriverProvider),
  1492. (paDriverInfo6 + dwCount)->pszProvider,
  1493. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1494. if (FAILED(hr))
  1495. {
  1496. LOG_ErrorMsg(hr);
  1497. goto CleanUp;
  1498. }
  1499. hr = StringCchCopyEx(szbufMfgName, ARRAYSIZE(szbufMfgName),
  1500. (paDriverInfo6 + dwCount)->pszMfgName,
  1501. NULL, NULL, MISTSAFE_STRING_FLAGS);
  1502. if (FAILED(hr))
  1503. {
  1504. LOG_ErrorMsg(hr);
  1505. goto CleanUp;
  1506. }
  1507. LOG_Driver(_T("Offering Printer hwid = %s, driverVer = %s, driverName = %s, driverProvider = %s, driverMfgr = %s"),\
  1508. (LPTSTR) szbufHardwareID, (LPTSTR) szDriverVer, \
  1509. (LPTSTR) szbufDriverName, (LPCWSTR) szbufDriverProvider, \
  1510. (LPTSTR) szbufMfgName );
  1511. #endif
  1512. }
  1513. else if (fAPWNewPrinter)
  1514. {
  1515. if (NULL == pDownloadInfo->lpFile)
  1516. {
  1517. //
  1518. // We need to "fake" a <hwid/> element with the ID passed in. User is trying to install
  1519. // a printer driver picked in the Add Printer Wizard that doesn't already exist on the
  1520. // system.
  1521. //
  1522. DWORD dwRank;
  1523. dwRank = 0;
  1524. CleanUpIfFailedAndSetHr(AddIDToXml(pszHardwareID, xmlSpec, SPDRP_HARDWAREID, dwRank, hDevices, NULL, NULL));
  1525. if (HANDLE_NODE_INVALID != hDevices)
  1526. {
  1527. xmlSpec.SafeCloseHandleNode(hDevices);
  1528. }
  1529. }
  1530. else
  1531. {
  1532. //
  1533. // 516376 Changes required in CDM to fix the APW <-> CDM bug found for multi-Provider scenario
  1534. //
  1535. // APW will pass a MULTI-SZ string containing (in this order) the following strings in the
  1536. // previously unused lpFile member of DOWNLOADINFO if it wishes to specify provider.
  1537. //
  1538. // This string is not required (for convenience and backwards compatibility) but
  1539. // if the lpFile member passed to CDM is non-NULL, it must contain all three strings
  1540. // as follows:
  1541. // String 1: driver provider
  1542. // String 2: manufacturer name
  1543. // String 3: driver name
  1544. #if !(defined(_UNICODE) || defined(UNICODE))
  1545. //
  1546. // We will never support this functionality on Win9x
  1547. //
  1548. CleanUpIfFailedAndSetHr(E_NOTIMPL);
  1549. #else
  1550. LPCWSTR pszProvider = pDownloadInfo->lpFile;
  1551. int nLenProvider = lstrlen(pszProvider);
  1552. if (NULL == pszProvider + nLenProvider + 1)
  1553. {
  1554. CleanUpIfFailedAndSetHr(E_INVALIDARG);
  1555. }
  1556. LPCWSTR pszMfgName = pszProvider + nLenProvider + 1;
  1557. int nLenMfgName = lstrlen(pszMfgName);
  1558. if (NULL == pszMfgName + nLenMfgName + 1)
  1559. {
  1560. CleanUpIfFailedAndSetHr(E_INVALIDARG);
  1561. }
  1562. LPCWSTR pszDriverName = pszMfgName + nLenMfgName + 1;
  1563. //
  1564. // Open a <device> element to write the printer info
  1565. //
  1566. bstrProvider = SysAllocString(pszProvider);
  1567. bstrMfgName = SysAllocString(pszMfgName);
  1568. bstrName = SysAllocString(pszDriverName);
  1569. if (NULL == bstrProvider || NULL == bstrMfgName || NULL == bstrName)
  1570. {
  1571. CleanUpIfFailedAndSetHr(E_OUTOFMEMORY);
  1572. }
  1573. CleanUpIfFailedAndSetHr(xmlSpec.AddDevice(NULL, 1, bstrProvider, \
  1574. bstrMfgName, bstrName, &hPrinterDevNode));
  1575. SafeSysFreeString(bstrProvider);
  1576. SafeSysFreeString(bstrMfgName);
  1577. SafeSysFreeString(bstrName);
  1578. // Always rank 0 and never fIsCompatible and no driverVer
  1579. CleanUpFailedAllocSetHrMsg(bstrHardwareID = SysAllocString(pszHardwareID));
  1580. CleanUpIfFailedAndSetHr(xmlSpec.AddHWID(hPrinterDevNode, FALSE, 0, \
  1581. bstrHardwareID));
  1582. SafeSysFreeString(bstrHardwareID);
  1583. xmlSpec.SafeCloseHandleNode(hPrinterDevNode);
  1584. #endif
  1585. }
  1586. }
  1587. else
  1588. {
  1589. //
  1590. // Get DriverVer for the PnP ID and check that offered driver is greater using the
  1591. // hDevInfoSet and devInfoData matched above while enumerating
  1592. //
  1593. CleanUpIfFailedAndSetHr(GetMatchingDeviceID(hDevInfoSet, &devInfoData, &pszMatchingID, &pszDriverVer));
  1594. //
  1595. // Add <device/> we matched and want to download to XML
  1596. //
  1597. CleanUpIfFailedAndSetHr(AddPrunedDevRegProps(hDevInfoSet, &devInfoData, xmlSpec, \
  1598. pszMatchingID, pszDriverVer, paDriverInfo6, dwDriverInfoCount, FALSE));
  1599. }
  1600. //
  1601. // Get the query string
  1602. //
  1603. CleanUpFailedAllocSetHrMsg(bstrXmlQuery = SysAllocString(szXmlDriverDownloadQuery));
  1604. //
  1605. // Get the bstrXmlSystemSpec
  1606. //
  1607. CleanUpIfFailedAndSetHr(xmlSpec.GetSystemSpecBSTR(&bstrXmlSystemSpec));
  1608. LOG_XmlBSTR(bstrXmlSystemSpec);
  1609. //
  1610. // GetManifest will ResetEvent, so check before calling
  1611. //
  1612. if (WaitForSingleObject(g_pCDMEngUpdate->m_evtNeedToQuit, 0) == WAIT_OBJECT_0)
  1613. {
  1614. CleanUpIfFailedAndSetHrMsg(E_ABORT);
  1615. }
  1616. //
  1617. // Call GetManifest to see if the server has anything that matches our system spec
  1618. //
  1619. CleanUpIfFailedAndSetHrMsg(g_pCDMEngUpdate->GetManifest(bstrXmlClientInfo, bstrXmlSystemSpec, bstrXmlQuery, \
  1620. FLAG_USE_COMPRESSION, pbstrXmlCatalog));
  1621. LOG_XmlBSTR( *pbstrXmlCatalog);
  1622. //
  1623. // If we are just getting the catalog we're done
  1624. //
  1625. if (GET_CATALOG_XML == eFunction)
  1626. {
  1627. break;
  1628. }
  1629. //
  1630. // Download will ResetEvent, so check before calling
  1631. //
  1632. if (WaitForSingleObject(g_pCDMEngUpdate->m_evtNeedToQuit, 0) == WAIT_OBJECT_0)
  1633. {
  1634. CleanUpIfFailedAndSetHrMsg(E_ABORT);
  1635. }
  1636. //
  1637. // Call Download passing it the catalog we got from GetManifest
  1638. //
  1639. CleanUpIfFailedAndSetHrMsg(g_pCDMEngUpdate->Download(bstrXmlClientInfo, *pbstrXmlCatalog, NULL, 0, NULL, NULL, &bstrXmlDownloadedItems));
  1640. LOG_XmlBSTR(bstrXmlDownloadedItems);
  1641. //
  1642. // Verify that the package was downloaded
  1643. //
  1644. CleanUpIfFailedAndSetHr(xmlItemStatusList.LoadXMLDocumentItemStatusList(bstrXmlDownloadedItems));
  1645. //
  1646. // Get the first [only] item in the list
  1647. //
  1648. CleanUpIfFailedAndSetHr(xmlItemStatusList.m_pItemStatusNodeList->nextNode(&pItemStatus));
  1649. if (NULL == pItemStatus) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1650. //
  1651. // Get the first <downloadStatus/> node of the statusItem (we expect at least one else fail)
  1652. //
  1653. if (NULL == (bstrDownloadStatus = SysAllocString(L"downloadStatus")))
  1654. {
  1655. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  1656. }
  1657. CleanUpIfFailedAndSetHrMsg(pItemStatus->selectSingleNode(bstrDownloadStatus, &pStatusNode));
  1658. if (NULL == pStatusNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1659. CleanUpIfFailedAndSetHr(pStatusNode->get_attributes(&pAttribMap));
  1660. if (NULL == pAttribMap) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1661. //
  1662. // suck out the <downloadStatus/> value attributes
  1663. //
  1664. if (NULL == (bstrStatusValue = SysAllocString((OLECHAR*) L"value")))
  1665. {
  1666. CleanUpIfFailedAndSetHrMsg(E_OUTOFMEMORY);
  1667. }
  1668. CleanUpIfFailedAndSetHrMsg(pAttribMap->getNamedItem(bstrStatusValue, &pValueNode));
  1669. if (NULL == pValueNode) CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1670. CleanUpIfFailedAndSetHrMsg(pValueNode->get_nodeValue(&vStatusValue));
  1671. if (VT_BSTR != vStatusValue.vt)
  1672. {
  1673. CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1674. }
  1675. if (0 != lstrcmpW((LPWSTR) vStatusValue.bstrVal, L"COMPLETE"))
  1676. {
  1677. CleanUpIfFailedAndSetHrMsg(E_FAIL);
  1678. }
  1679. //
  1680. // Now copy the path to the buffer we were passed
  1681. //
  1682. CleanUpIfFailedAndSetHr(GetDownloadPath(*pbstrXmlCatalog, bstrXmlDownloadedItems, lpDownloadPath, cchDownloadPath));
  1683. //
  1684. // DecompressFolderCabs may return S_FALSE if it didn't find a cab to decompress...
  1685. //
  1686. hr = DecompressFolderCabs(lpDownloadPath);
  1687. if (S_OK != hr)
  1688. {
  1689. CleanUpIfFailedAndSetHr(E_FAIL);
  1690. }
  1691. break;
  1692. }
  1693. default:
  1694. {
  1695. CleanUpIfFailedAndSetHr(E_INVALIDARG);
  1696. break;
  1697. }
  1698. } // switch (eFunction)
  1699. CleanUp:
  1700. if (INVALID_HANDLE_VALUE != hDevInfoSet)
  1701. {
  1702. SetupDiDestroyDeviceInfoList(hDevInfoSet);
  1703. }
  1704. if (HANDLE_NODE_INVALID != hPrinterDevNode)
  1705. {
  1706. xmlSpec.SafeCloseHandleNode(hPrinterDevNode);
  1707. }
  1708. if (HANDLE_NODE_INVALID != hDevices)
  1709. {
  1710. xmlSpec.SafeCloseHandleNode(hDevices);
  1711. }
  1712. SafeReleaseNULL(pItemStatus);
  1713. SafeReleaseNULL(pStatusNode);
  1714. SafeReleaseNULL(pValueNode);
  1715. SafeReleaseNULL(pAttribMap);
  1716. SafeHeapFree(paDriverInfo6);
  1717. SafeHeapFree(pszMatchingID);
  1718. SafeHeapFree(pszDriverVer);
  1719. VariantClear(&vStatusValue);
  1720. SysFreeString(bstrXmlSystemSpec);
  1721. SysFreeString(bstrXmlClientInfo);
  1722. SysFreeString(bstrXmlQuery);
  1723. SysFreeString(bstrXmlDownloadedItems);
  1724. SysFreeString(bstrDownloadStatus);
  1725. SysFreeString(bstrStatusValue);
  1726. SysFreeString(bstrProvider);
  1727. SysFreeString(bstrMfgName);
  1728. SysFreeString(bstrName);
  1729. SysFreeString(bstrHardwareID);
  1730. SysFreeString(bstrDriverVer);
  1731. SysFreeString(iuPlatformInfo.bstrOEMManufacturer);
  1732. SysFreeString(iuPlatformInfo.bstrOEMModel);
  1733. SysFreeString(iuPlatformInfo.bstrOEMSupportURL);
  1734. if (FAILED(hr))
  1735. {
  1736. SafeSysFreeString(*pbstrXmlCatalog);
  1737. }
  1738. return hr;
  1739. }