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.

3848 lines
118 KiB

  1. /*++
  2. Copyright (c) 1995-97 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Install.c
  6. Abstract:
  7. File queue functions
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 18-Nov-96
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include <winsprlp.h>
  14. const TCHAR szWebDirPrefix[] = TEXT("\\web\\printers\\");
  15. const TCHAR szNtPrintInf[] = TEXT("inf\\ntprint.inf");
  16. //
  17. // File queue flags, and structure
  18. //
  19. #define CALLBACK_MEDIA_CHECKED 0x01
  20. #define CALLBACK_SOURCE_SET 0x02
  21. #define CALLBACK_PATH_MODIFIED 0x04
  22. typedef struct _FILE_QUEUE_CONTEXT {
  23. HWND hwnd;
  24. PVOID QueueContext;
  25. LPCTSTR pszSource;
  26. BOOL dwCallbackFlags;
  27. DWORD dwInstallFlags;
  28. LPCTSTR pszFileSrcPath;
  29. TCHAR szInfPath[MAX_PATH];
  30. PLATFORM platform;
  31. DWORD dwVersion;
  32. } FILE_QUEUE_CONTEXT, *PFILE_QUEUE_CONTEXT;
  33. /*
  34. BOOL
  35. SystemCab(
  36. LPCTSTR pszPath
  37. )
  38. {
  39. BOOL bRet = FALSE;
  40. HKEY hKey;
  41. DWORD dwSize, dwType;
  42. TCHAR szCabLocation[MAX_PATH],
  43. szReg[] = TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
  44. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  45. szReg,
  46. 0,
  47. KEY_READ,
  48. &hKey ) ) {
  49. dwSize = sizeof(szCabLocation);
  50. if ( ERROR_SUCCESS == RegQueryValueEx(hKey,
  51. TEXT("DriverCachePath"),
  52. NULL,
  53. &dwType,
  54. (LPBYTE)szCabLocation,
  55. &dwSize) &&
  56. dwType == REG_EXPAND_SZ ) {
  57. bRet = lstrncmpi(szCabLocation, pszPath, lstrlen(pszPath)) == 0;
  58. }
  59. RegCloseKey(hKey);
  60. }
  61. return bRet;
  62. }
  63. */
  64. BOOL
  65. FileExistsOnMedia(
  66. PSOURCE_MEDIA pSourceMedia
  67. )
  68. {
  69. BOOL bRes = FALSE;
  70. TCHAR *pszFile = NULL;
  71. INT cbLength = 0;
  72. INT cbAdditionalSymbolsLen = 0;
  73. DWORD dwLen1 = 0;
  74. DWORD dwLen2 = 0;
  75. LPTSTR p = NULL;
  76. LPTSTR q = NULL;
  77. if ( !pSourceMedia->SourcePath || !*pSourceMedia->SourcePath ||
  78. !pSourceMedia->SourceFile || !*pSourceMedia->SourceFile )
  79. {
  80. goto Cleanup;
  81. }
  82. cbAdditionalSymbolsLen = lstrlen(TEXT("\\")) + lstrlen(TEXT("_")) + 1;
  83. cbLength = lstrlen(pSourceMedia->SourcePath) + lstrlen(pSourceMedia->SourceFile) +
  84. cbAdditionalSymbolsLen;
  85. if (cbLength == cbAdditionalSymbolsLen)
  86. {
  87. goto Cleanup;
  88. }
  89. //
  90. // First check if file is there on source path
  91. //
  92. pszFile = LocalAllocMem(cbLength * sizeof(TCHAR));
  93. if (!pszFile)
  94. {
  95. goto Cleanup;
  96. }
  97. lstrcpy(pszFile, pSourceMedia->SourcePath);
  98. dwLen1 = lstrlen(pszFile);
  99. if ( *(pszFile + (dwLen1-1)) != TEXT('\\') )
  100. {
  101. *(pszFile + dwLen1) = TEXT('\\');
  102. ++dwLen1;
  103. }
  104. lstrcpy(pszFile + dwLen1, pSourceMedia->SourceFile);
  105. dwLen2 = dwLen1 + lstrlen(pSourceMedia->SourceFile);
  106. bRes = FileExists(pszFile);
  107. if (bRes)
  108. {
  109. goto Cleanup;
  110. }
  111. p = lstrchr(pszFile, TEXT('.'));
  112. q = lstrchr(pszFile, TEXT('\\'));
  113. //
  114. // A dot present in filename?
  115. //
  116. if ( q < p )
  117. {
  118. //
  119. // For files with 0, 1, 2 characters after the dot append underscore
  120. //
  121. if ( lstrlen(p) < 4 )
  122. {
  123. *(pszFile + dwLen2) = TEXT('_');
  124. ++dwLen2;
  125. *(pszFile + dwLen2) = TEXT('\0');
  126. }
  127. else
  128. {
  129. //
  130. // If 3+ characters after dot then replace last character with _
  131. // to get the compressed file name
  132. //
  133. *(pszFile + (dwLen2-1)) = TEXT('_');
  134. }
  135. }
  136. else
  137. {
  138. //
  139. // If no dot then replace last character with _ for compressed name
  140. //
  141. *(pszFile + (dwLen2-1)) = TEXT('_');
  142. }
  143. //
  144. // Does the compressed file exist on source path?
  145. //
  146. bRes = FileExists(pszFile);
  147. if (bRes)
  148. {
  149. goto Cleanup;
  150. }
  151. //
  152. // Check for the file in compressed form with $ as the character
  153. //
  154. *(pszFile + (dwLen2-1)) = TEXT('$');
  155. bRes = FileExists(pszFile);
  156. if (bRes)
  157. {
  158. goto Cleanup;
  159. }
  160. if ( !pSourceMedia->Tagfile || !*pSourceMedia->Tagfile )
  161. {
  162. goto Cleanup;
  163. }
  164. //
  165. // Look for tag file
  166. //
  167. lstrcpy(pszFile + dwLen1, pSourceMedia->Tagfile);
  168. bRes = FileExists(pszFile);
  169. Cleanup:
  170. LocalFreeMem(pszFile);
  171. return bRes;
  172. }
  173. UINT
  174. MyQueueCallback(
  175. IN PVOID QueueContext,
  176. IN UINT Notification,
  177. IN UINT_PTR Param1,
  178. IN UINT_PTR Param2
  179. )
  180. {
  181. PFILE_QUEUE_CONTEXT pFileQContext=(PFILE_QUEUE_CONTEXT)QueueContext;
  182. PSOURCE_MEDIA pSourceMedia;
  183. LPTSTR pszPathOut;
  184. PFILEPATHS pFilePaths;
  185. switch (Notification) {
  186. case SPFILENOTIFY_NEEDMEDIA:
  187. pSourceMedia = (PSOURCE_MEDIA)Param1;
  188. pszPathOut = (LPTSTR)Param2;
  189. //
  190. // If pszSource is specified then we have a flat share where
  191. // all the files are available. Setup is looking for the file
  192. // in the sub-directory (ex. ..\i386) based on the layout info.
  193. // We need to tell setup to look in the root directory
  194. //
  195. if ( !(pFileQContext->dwCallbackFlags & CALLBACK_SOURCE_SET) &&
  196. pFileQContext->pszSource &&
  197. lstrcmpi(pFileQContext->pszSource,
  198. pSourceMedia->SourcePath) ) {
  199. lstrcpy(pszPathOut, pFileQContext->pszSource);
  200. pFileQContext->dwCallbackFlags |= CALLBACK_SOURCE_SET;
  201. return FILEOP_NEWPATH;
  202. }
  203. /*
  204. } else if ( (pFileQContext->dwInstallFlags & DRVINST_CABONLY) &&
  205. !SystemCab(pSourceMedia->SourcePath) ) {
  206. return FILEOP_ABORT;
  207. }
  208. if ( pFileQContext->dwInstallFlags & DRVINST_WEBPNP ) {
  209. if ( !pFileQContext->bMediaChecked ) {
  210. pFileQContext->bMediaChecked = TRUE;
  211. return FILEOP_DOIT;
  212. } else
  213. return FILEOP_ABORT;
  214. }
  215. */
  216. //
  217. // If DRVINST_PROMPTLESS is set then we can't allow prompt
  218. //
  219. if ( pFileQContext->dwInstallFlags & DRVINST_PROMPTLESS ) {
  220. if ( !(pFileQContext->dwCallbackFlags & CALLBACK_MEDIA_CHECKED) ) {
  221. pFileQContext->dwCallbackFlags |= CALLBACK_MEDIA_CHECKED;
  222. if ( FileExistsOnMedia(pSourceMedia) )
  223. return FILEOP_DOIT;
  224. }
  225. return FILEOP_ABORT;
  226. }
  227. //
  228. // If we do a non-native platform install and the user points
  229. // to a server CD, the inf will specify a subdir \i386 which is
  230. // correct on an installed machine but not on a CD. Remove that dir
  231. // and try again.
  232. //
  233. if ( (pFileQContext->dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) &&
  234. !(pFileQContext->dwCallbackFlags & CALLBACK_PATH_MODIFIED))
  235. {
  236. LPSTR pCur;
  237. size_t Pos, Len, OverrideLen;
  238. //
  239. // for NT4 installations we have possibly expanded the INF
  240. // from a server CD. Point there if that's the case
  241. //
  242. if ((pFileQContext->dwVersion == 2) &&
  243. (pFileQContext->pszFileSrcPath))
  244. {
  245. Len = _tcslen(pFileQContext->szInfPath);
  246. if (_tcsnicmp(pSourceMedia->SourcePath,
  247. pFileQContext->szInfPath, Len) == 0)
  248. {
  249. _tcscpy(pszPathOut, pFileQContext->pszFileSrcPath);
  250. pFileQContext->dwCallbackFlags |= CALLBACK_PATH_MODIFIED;
  251. return FILEOP_NEWPATH;
  252. }
  253. }
  254. //
  255. // Find the spot where the platform ID begins
  256. //
  257. Pos = Len = _tcslen(pFileQContext->szInfPath);
  258. //
  259. // sanity check
  260. //
  261. if (_tcslen(pSourceMedia->SourcePath) <= Len)
  262. goto Default;
  263. if (pSourceMedia->SourcePath[Len] == _T('\\'))
  264. {
  265. Pos++;
  266. }
  267. OverrideLen = _tcslen(PlatformOverride[pFileQContext->platform].pszName);
  268. if (_tcsnicmp(pSourceMedia->SourcePath,
  269. pFileQContext->szInfPath, Len) == 0 &&
  270. _tcsnicmp(&(pSourceMedia->SourcePath[Pos]),
  271. PlatformOverride[pFileQContext->platform].pszName,
  272. OverrideLen) == 0)
  273. {
  274. _tcscpy(pszPathOut, pFileQContext->szInfPath);
  275. pFileQContext->dwCallbackFlags |= CALLBACK_PATH_MODIFIED;
  276. return FILEOP_NEWPATH;
  277. }
  278. }
  279. goto Default;
  280. case SPFILENOTIFY_STARTCOPY:
  281. pFilePaths = (PFILEPATHS)Param1;
  282. if ( gpszSkipDir &&
  283. !lstrncmpi(gpszSkipDir, pFilePaths->Target, lstrlen(gpszSkipDir)) )
  284. return FILEOP_SKIP;
  285. goto Default;
  286. case SPFILENOTIFY_ENDCOPY:
  287. // Here we set the bMediaChecked flag to FALSE, this is because some OEM drivers
  288. // have more than one media, so we assume NEEDMEDIA,STARTCOPY,ENDCOPY,NEEDMEDIA
  289. // So if we reset the NEEDMEDIA flag after the ENDCOPY, we are OK
  290. //
  291. // Clear the per file flags
  292. //
  293. pFileQContext->dwCallbackFlags &= ~(CALLBACK_MEDIA_CHECKED |
  294. CALLBACK_SOURCE_SET |
  295. CALLBACK_PATH_MODIFIED);
  296. goto Default;
  297. case SPFILENOTIFY_COPYERROR:
  298. pFilePaths = (PFILEPATHS)Param1;
  299. // If there is a copy error happens in webpnp, we force it retry
  300. // the orginal flat directory
  301. if ( pFileQContext->dwInstallFlags & DRVINST_WEBPNP) {
  302. pszPathOut = (LPTSTR)Param2;
  303. // We need to make sure the path used in the copy operation is not as same as we're going
  304. // to replace, otherwise, it will go to indefinite loop.
  305. //
  306. if (lstrncmpi(pFileQContext->pszSource, pFilePaths->Source, lstrlen(pFileQContext->pszSource)) ||
  307. lstrchr (pFilePaths->Source + lstrlen(pFileQContext->pszSource) + 1, TEXT ('\\'))) {
  308. lstrcpy(pszPathOut, pFileQContext->pszSource);
  309. return FILEOP_NEWPATH;
  310. }
  311. }
  312. goto Default;
  313. }
  314. Default:
  315. return SetupDefaultQueueCallback(pFileQContext->QueueContext,
  316. Notification,
  317. Param1,
  318. Param2);
  319. }
  320. VOID
  321. CheckAndEnqueueOneFile(
  322. IN LPCTSTR pszFileName,
  323. IN LPCTSTR pszzDependentFiles, OPTIONAL
  324. IN HSPFILEQ CopyQueue,
  325. IN LPCTSTR pszSourcePath,
  326. IN LPCTSTR pszTargetPath,
  327. IN LPCTSTR pszDiskName, OPTIONAL
  328. IN OUT LPBOOL lpFail
  329. )
  330. /*++
  331. Routine Description:
  332. Ensure that a file is enqueue only once for copying. To do so we check
  333. if the given file name also appears in the list of dependent files and
  334. enqueue it only if it does not.
  335. Arguments:
  336. pszFileName : File name to be checked and enqueued
  337. pszzDependentFiles : Dependent files (multi-sz) list
  338. pszSourcePath : Source directory to look for the files
  339. pszTargetPath : Target directory to copy the files to
  340. pszDiskName : Title of the disk where files are
  341. lpBool : Will be set to TRUE on error
  342. Return Value:
  343. Nothing
  344. --*/
  345. {
  346. LPCTSTR psz;
  347. if ( *lpFail )
  348. return;
  349. //
  350. // If the file also appears as a dependent file do not enqueue it
  351. //
  352. if ( pszzDependentFiles ) {
  353. for ( psz = pszzDependentFiles ; *psz ; psz += lstrlen(psz) + 1 )
  354. if ( !lstrcmpi(pszFileName, psz) )
  355. return;
  356. }
  357. *lpFail = !SetupQueueCopy(
  358. CopyQueue,
  359. pszSourcePath,
  360. NULL, // Path relative to source
  361. pszFileName,
  362. pszDiskName,
  363. NULL, // Source Tag file
  364. pszTargetPath,
  365. NULL, // Target file name
  366. 0); // Copy style flags
  367. }
  368. BOOL
  369. CopyPrinterDriverFiles(
  370. IN LPDRIVER_INFO_6 pDriverInfo6,
  371. IN LPCTSTR pszInfName,
  372. IN LPCTSTR pszSourcePath,
  373. IN LPCTSTR pszDiskName,
  374. IN LPCTSTR pszTargetPath,
  375. IN HWND hwnd,
  376. IN DWORD dwInstallFlags,
  377. IN BOOL bForgetSource
  378. )
  379. /*++
  380. Routine Description:
  381. Copy printer driver files to a specified directory using SetupQueue APIs
  382. Arguments:
  383. pDriverInfo6 : Points to a valid SELECTED_DRV_INFO
  384. szTargetPath : Target directory to copy to
  385. szSourcePath : Source directory to look for the files, if none is
  386. specified will use the one from prev. operation
  387. pszDiskName : Title of the disk where files are
  388. hwnd : Windows handle of current top-level window
  389. bForgetSource : TRUE if the path where driver files were copied from
  390. should not be remembered for future use
  391. Return Value:
  392. TRUE on succes
  393. FALSE else, use GetLastError() to get the error code
  394. --*/
  395. {
  396. HSPFILEQ CopyQueue;
  397. BOOL bFail = FALSE;
  398. DWORD dwOldCount, dwNewCount, dwIndex;
  399. LPTSTR psz, *List = NULL;
  400. FILE_QUEUE_CONTEXT FileQContext;
  401. //
  402. // Valid DriverInfo6
  403. //
  404. if ( !pDriverInfo6 ||
  405. !pDriverInfo6->pDriverPath ||
  406. !pDriverInfo6->pDataFile ||
  407. !pDriverInfo6->pConfigFile )
  408. return FALSE;
  409. //
  410. // If no additions should be made to the source list findout the count
  411. //
  412. if ( bForgetSource ) {
  413. dwOldCount = 0;
  414. if ( !SetupQuerySourceList(SRCLIST_USER | SRCLIST_SYSTEM,
  415. &List, &dwOldCount) ) {
  416. return FALSE;
  417. }
  418. SetupFreeSourceList(&List, dwOldCount);
  419. }
  420. //
  421. // Create a setup file copy queue and initialize setup queue callback
  422. //
  423. ZeroMemory(&FileQContext, sizeof(FileQContext));
  424. FileQContext.hwnd = hwnd;
  425. FileQContext.pszSource = NULL;
  426. FileQContext.dwInstallFlags = dwInstallFlags;
  427. if ( dwInstallFlags & DRVINST_PROGRESSLESS ) {
  428. FileQContext.QueueContext = SetupInitDefaultQueueCallbackEx(
  429. hwnd,
  430. INVALID_HANDLE_VALUE,
  431. 0,
  432. 0,
  433. NULL);
  434. } else {
  435. FileQContext.QueueContext = SetupInitDefaultQueueCallback(hwnd);
  436. }
  437. CopyQueue = SetupOpenFileQueue();
  438. if ( CopyQueue == INVALID_HANDLE_VALUE || !FileQContext.QueueContext )
  439. goto Cleanup;
  440. CheckAndEnqueueOneFile(pDriverInfo6->pDriverPath,
  441. pDriverInfo6->pDependentFiles,
  442. CopyQueue,
  443. pszSourcePath,
  444. pszTargetPath,
  445. pszDiskName,
  446. &bFail);
  447. CheckAndEnqueueOneFile(pDriverInfo6->pDataFile,
  448. pDriverInfo6->pDependentFiles,
  449. CopyQueue,
  450. pszSourcePath,
  451. pszTargetPath,
  452. pszDiskName,
  453. &bFail);
  454. CheckAndEnqueueOneFile(pDriverInfo6->pConfigFile,
  455. pDriverInfo6->pDependentFiles,
  456. CopyQueue,
  457. pszSourcePath,
  458. pszTargetPath,
  459. pszDiskName,
  460. &bFail);
  461. if ( pDriverInfo6->pHelpFile && *pDriverInfo6->pHelpFile )
  462. CheckAndEnqueueOneFile(pDriverInfo6->pHelpFile,
  463. pDriverInfo6->pDependentFiles,
  464. CopyQueue,
  465. pszSourcePath,
  466. pszTargetPath,
  467. pszDiskName,
  468. &bFail);
  469. //
  470. // Add each file in the dependent files field to the setup queue
  471. //
  472. if ( pDriverInfo6->pDependentFiles ) {
  473. for ( psz = pDriverInfo6->pDependentFiles ;
  474. *psz ;
  475. psz += lstrlen(psz) + 1 )
  476. CheckAndEnqueueOneFile(psz,
  477. NULL,
  478. CopyQueue,
  479. pszSourcePath,
  480. pszTargetPath,
  481. pszDiskName,
  482. &bFail);
  483. }
  484. if ( bFail )
  485. goto Cleanup;
  486. {
  487. // Before adding files to the File Queue set the correct Platform/Version
  488. // info for Driver Signing
  489. // Setup the structure for SETUPAPI
  490. SP_ALTPLATFORM_INFO AltPlat_Info;
  491. HINF hInf;
  492. TCHAR CatalogName[ MAX_PATH ];
  493. LPTSTR pszCatalogFile = NULL;
  494. AltPlat_Info.cbSize = sizeof(SP_ALTPLATFORM_INFO);
  495. AltPlat_Info.Platform = VER_PLATFORM_WIN32_WINDOWS;
  496. AltPlat_Info.MajorVersion = 4;
  497. AltPlat_Info.MinorVersion = 0;
  498. AltPlat_Info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
  499. AltPlat_Info.Reserved = 0;
  500. AltPlat_Info.FirstValidatedMajorVersion = AltPlat_Info.MajorVersion;
  501. AltPlat_Info.FirstValidatedMinorVersion = AltPlat_Info.MinorVersion;
  502. if ( CheckForCatalogFileInInf(pszInfName, &pszCatalogFile) && pszCatalogFile )
  503. {
  504. if ( (lstrlen(pszSourcePath)+lstrlen(pszCatalogFile)+2) < MAX_PATH )
  505. {
  506. lstrcpy( CatalogName, pszSourcePath );
  507. lstrcat( CatalogName, TEXT("\\") );
  508. lstrcat( CatalogName, pszCatalogFile );
  509. }
  510. else
  511. {
  512. bFail = TRUE;
  513. }
  514. LocalFreeMem( pszCatalogFile );
  515. pszCatalogFile = CatalogName;
  516. }
  517. if (bFail)
  518. goto Cleanup;
  519. // Now call the Setup API to change the parms on the FileQueue
  520. bFail = !SetupSetFileQueueAlternatePlatform( CopyQueue, &AltPlat_Info, pszCatalogFile );
  521. }
  522. if ( bFail )
  523. goto Cleanup;
  524. bFail = !SetupCommitFileQueue(hwnd,
  525. CopyQueue,
  526. MyQueueCallback,
  527. &FileQContext);
  528. //
  529. // If bForegetSource is set fix source list
  530. //
  531. if ( bForgetSource &&
  532. SetupQuerySourceList(SRCLIST_USER | SRCLIST_SYSTEM,
  533. &List, &dwNewCount) ) {
  534. dwOldCount = dwNewCount - dwOldCount;
  535. if ( dwOldCount < dwNewCount )
  536. for ( dwIndex = 0 ; dwIndex < dwOldCount ; ++dwIndex ) {
  537. SetupRemoveFromSourceList(SRCLIST_SYSIFADMIN,
  538. List[dwIndex]);
  539. }
  540. SetupFreeSourceList(&List, dwNewCount);
  541. }
  542. Cleanup:
  543. if ( CopyQueue != INVALID_HANDLE_VALUE )
  544. SetupCloseFileQueue(CopyQueue);
  545. if ( FileQContext.QueueContext )
  546. SetupTermDefaultQueueCallback(FileQContext.QueueContext);
  547. return !bFail;
  548. }
  549. BOOL
  550. AddPrinterDriverUsingCorrectLevel(
  551. IN LPCTSTR pszServerName,
  552. IN LPDRIVER_INFO_6 pDriverInfo6,
  553. IN DWORD dwAddDrvFlags
  554. )
  555. {
  556. BOOL bReturn;
  557. DWORD dwLevel;
  558. bReturn = AddPrinterDriverEx((LPTSTR)pszServerName,
  559. 6,
  560. (LPBYTE)pDriverInfo6,
  561. dwAddDrvFlags );
  562. for ( dwLevel = 4 ;
  563. !bReturn && GetLastError() == ERROR_INVALID_LEVEL && dwLevel > 1 ;
  564. --dwLevel ) {
  565. //
  566. // Since DRIVER_INFO_2, 3, 4 are subsets of DRIVER_INFO_6 and all fields
  567. // are at the beginning these calls can be made with same buffer
  568. //
  569. bReturn = AddPrinterDriverEx((LPTSTR)pszServerName,
  570. dwLevel,
  571. (LPBYTE)pDriverInfo6,
  572. dwAddDrvFlags);
  573. }
  574. return bReturn;
  575. }
  576. typedef struct _MONITOR_SCAN_INFO {
  577. LPTSTR pszMonitorDll;
  578. LPTSTR pszTargetDir;
  579. BOOL bFound;
  580. } MONITOR_SCAN_INFO, *PMONITOR_SCAN_INFO;
  581. UINT
  582. MonitorCheckCallback(
  583. IN PVOID pContext,
  584. IN UINT Notification,
  585. IN UINT_PTR Param1,
  586. IN UINT_PTR Param2
  587. )
  588. /*++
  589. Routine Description:
  590. This callback routine is to check language monitor dll is getting copied
  591. to system32 directory.
  592. Arguments:
  593. pContext : Gives the MONITOR_SCAN_INFO structure
  594. Notification : Ignored
  595. Param1 : Gives the target file name
  596. Param2 : Ignored
  597. Return Value:
  598. Win32 error code
  599. --*/
  600. {
  601. size_t dwLen;
  602. LPTSTR pszTarget = (LPTSTR)Param1, pszFileName;
  603. PMONITOR_SCAN_INFO pScanInfo = (PMONITOR_SCAN_INFO)pContext;
  604. if ( !pScanInfo->bFound ) {
  605. if ( !(pszFileName = FileNamePart(pszTarget)) )
  606. return ERROR_INVALID_PARAMETER;
  607. if ( !lstrcmpi(pScanInfo->pszMonitorDll, pszFileName) ) {
  608. //
  609. // Length excludes \ (i.e. D:\winnt\system32)
  610. //
  611. dwLen = (size_t)(pszFileName - pszTarget - 1);
  612. if ( !lstrncmpi(pScanInfo->pszTargetDir, pszTarget, dwLen) &&
  613. dwLen == (DWORD) lstrlen(pScanInfo->pszTargetDir) )
  614. pScanInfo->bFound = TRUE;
  615. }
  616. }
  617. return NO_ERROR;
  618. }
  619. BOOL
  620. CheckAndEnqueueMonitorDll(
  621. IN LPCTSTR pszMonitorDll,
  622. IN LPCTSTR pszSource,
  623. IN HSPFILEQ CopyQueue,
  624. IN HINF hInf
  625. )
  626. /*++
  627. Routine Description:
  628. This routine is to check language monitor dll is getting copied to system32
  629. directory. On NT 4.0 we did not list LM as a file to be copied. ntprint.dll
  630. automatically did it. Now we use a DRID for it. But for backward
  631. compatibility this routine is there to get NT 4.0 INFs to work.
  632. Arguments:
  633. pszMonitorDll : Monitor dll to enqueue
  634. pszSource : Source directory to look for files
  635. CopyQueue : File queue
  636. hInf : Printer driver INF file handle
  637. Return Value:
  638. TRUE on success, FALSE else
  639. --*/
  640. {
  641. BOOL bRet = FALSE;
  642. DWORD dwNeeded;
  643. LPTSTR pszPathOnSource = NULL, pszDescription = NULL,
  644. pszTagFile = NULL;
  645. TCHAR szDir[MAX_PATH];
  646. MONITOR_SCAN_INFO ScanInfo;
  647. SP_FILE_COPY_PARAMS FileCopyParams = {0};
  648. if ( !GetSystemDirectory(szDir, SIZECHARS(szDir)) )
  649. goto Cleanup;
  650. ScanInfo.pszMonitorDll = (LPTSTR)pszMonitorDll;
  651. ScanInfo.pszTargetDir = szDir;
  652. ScanInfo.bFound = FALSE;
  653. if ( !SetupScanFileQueue(CopyQueue,
  654. SPQ_SCAN_USE_CALLBACK,
  655. 0,
  656. MonitorCheckCallback,
  657. &ScanInfo,
  658. &dwNeeded) )
  659. goto Cleanup;
  660. if ( !ScanInfo.bFound ) {
  661. pszPathOnSource = (LPTSTR) LocalAllocMem(MAX_PATH * sizeof(TCHAR));
  662. if ( !pszPathOnSource )
  663. goto Cleanup;
  664. //
  665. // This gives which subdirectory to look for. By default in same dir
  666. //
  667. if ( !FindPathOnSource(pszMonitorDll, hInf,
  668. pszPathOnSource, MAX_PATH,
  669. &pszDescription, &pszTagFile) ) {
  670. LocalFreeMem(pszPathOnSource);
  671. pszPathOnSource = NULL;
  672. }
  673. FileCopyParams.cbSize = sizeof( SP_FILE_COPY_PARAMS );
  674. FileCopyParams.QueueHandle = CopyQueue;
  675. FileCopyParams.SourceRootPath = pszSource;
  676. FileCopyParams.SourcePath = pszPathOnSource;
  677. FileCopyParams.SourceFilename = pszMonitorDll;
  678. FileCopyParams.SourceDescription = pszDescription;
  679. FileCopyParams.SourceTagfile = pszTagFile;
  680. FileCopyParams.TargetDirectory = szDir;
  681. FileCopyParams.TargetFilename = NULL;
  682. FileCopyParams.CopyStyle = SP_COPY_NEWER;
  683. FileCopyParams.LayoutInf = hInf;
  684. FileCopyParams.SecurityDescriptor = NULL;
  685. if ( !SetupQueueCopyIndirect(&FileCopyParams) )
  686. {
  687. goto Cleanup;
  688. }
  689. }
  690. bRet = TRUE;
  691. Cleanup:
  692. LocalFreeMem(pszPathOnSource);
  693. LocalFreeMem(pszDescription);
  694. LocalFreeMem(pszTagFile);
  695. return bRet;
  696. }
  697. BOOL
  698. GetWebPageDir(
  699. IN PPSETUP_LOCAL_DATA pLocalData,
  700. OUT TCHAR szDir[MAX_PATH]
  701. )
  702. {
  703. BOOL bRet = FALSE;
  704. DWORD dwLen;
  705. if ( !GetSystemWindowsDirectory(szDir, MAX_PATH) )
  706. goto Done;
  707. dwLen = lstrlen(szDir) + lstrlen(szWebDirPrefix)
  708. + lstrlen(pLocalData->DrvInfo.pszManufacturer)
  709. + lstrlen(pLocalData->DrvInfo.pszModelName)
  710. + 2;
  711. if ( dwLen >= MAX_PATH ) {
  712. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  713. goto Done;
  714. }
  715. lstrcat(szDir, szWebDirPrefix);
  716. lstrcat(szDir, pLocalData->DrvInfo.pszManufacturer);
  717. lstrcat(szDir, TEXT("\\"));
  718. lstrcat(szDir, pLocalData->DrvInfo.pszModelName);
  719. bRet = TRUE;
  720. Done:
  721. return bRet;
  722. }
  723. BOOL
  724. SetTargetDirectories(
  725. IN PPSETUP_LOCAL_DATA pLocalData,
  726. IN PLATFORM platform,
  727. IN LPCTSTR pszServerName,
  728. IN HINF hInf,
  729. IN DWORD dwInstallFlags
  730. )
  731. /*++
  732. Routine Description:
  733. Set all the target directories listed in the INF file for file copy
  734. operations. Also gets the source directory where we should look for
  735. driver files
  736. Arguments:
  737. hDevInfo : Handle to printer device info list
  738. pLocalData : INF parsing information
  739. platform : Gives the platform
  740. pszSource : Source directory to look for files
  741. CopyQueue : File queue
  742. hInf : Printer driver INF file handle
  743. dwInstallFlags : Driver installation flags
  744. Return Value:
  745. TRUE on success, FALSE else
  746. --*/
  747. {
  748. BOOL bRet=FALSE;
  749. DWORD dwNeeded, dwIndex, dwIndex2, dwCount, dwCount2;
  750. INT DRID;
  751. TCHAR szDir[MAX_PATH];
  752. INFCONTEXT InfContext;
  753. if ( (dwCount = SetupGetLineCount(hInf, TEXT("DestinationDirs"))) == -1 )
  754. goto Cleanup;
  755. // Setup the Skip Dir
  756. if ( !SetupSkipDir( platform, pszServerName ) )
  757. goto Cleanup;
  758. //
  759. // Process every line in the DestinationDirs section
  760. //
  761. for ( dwIndex = 0 ; dwIndex < dwCount ; ++dwIndex ) {
  762. if ( !SetupGetLineByIndex(hInf, TEXT("DestinationDirs"),
  763. dwIndex, &InfContext) )
  764. goto Cleanup;
  765. //
  766. // A file could be copied to multiple destination directories
  767. //
  768. if ( (dwCount2 = SetupGetFieldCount(&InfContext)) == -1 )
  769. continue;
  770. for ( dwIndex2 = 1 ; dwIndex2 <= dwCount2 ; ++dwIndex2 ) {
  771. //
  772. // Not all directories are specified with a DRID
  773. // for ex. %ProgramFiles%\%OLD_ICWDIR% could be used
  774. // If DRID is smaller than DIRID_USER setup has predefined
  775. // meaning to it
  776. //
  777. if ( !SetupGetIntField(&InfContext, dwIndex2, &DRID) ||
  778. DRID < DIRID_USER )
  779. continue;
  780. if ( DRID < DIRID_USER )
  781. continue;
  782. dwNeeded = SIZECHARS(szDir);
  783. switch (DRID) {
  784. case PRINTER_DRIVER_DIRECTORY_ID:
  785. if ( !GetPrinterDriverDirectory(
  786. (LPTSTR)pszServerName,
  787. PlatformEnv[platform].pszName,
  788. 1,
  789. (LPBYTE)szDir,
  790. sizeof(szDir),
  791. &dwNeeded) )
  792. {
  793. goto Cleanup;
  794. }
  795. if ( dwInstallFlags & DRVINST_PRIVATE_DIRECTORY )
  796. {
  797. //
  798. // if we have a pnp-ID, and it's an installation of a native driver
  799. // and it's not an inbox driver, make the files stick around for
  800. // pnp-reinstallations, else the user gets prompted over and over again
  801. //
  802. if ((lstrlen(pLocalData->DrvInfo.pszHardwareID) != 0) &&
  803. !(dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) &&
  804. !IsSystemNTPrintInf(pLocalData->DrvInfo.pszInfName))
  805. {
  806. //
  807. // add the pnp-ID to szDir and set flag to not clean up this directory
  808. // this is to get around users getting prompted for pnp-reinstallation
  809. //
  810. AddPnpDirTag( pLocalData->DrvInfo.pszHardwareID, szDir, sizeof(szDir)/sizeof(TCHAR));
  811. pLocalData->Flags |= LOCALDATAFLAG_PNP_DIR_INSTALL;
  812. }
  813. else
  814. {
  815. //
  816. // Add PID\TID to szDir.
  817. // If this fails, add the dir info held in szDir to the DRIVER_INFO struct
  818. // anyway as we'll attempt the install with this.
  819. //
  820. AddDirectoryTag( szDir, sizeof(szDir)/sizeof(TCHAR) );
  821. }
  822. ASSERT(pLocalData);
  823. //
  824. // Change DI6 to have the full szDir path included.
  825. // Can't do anything if this fails, so try finish install anyway.
  826. //
  827. AddDirToDriverInfo( szDir, &(pLocalData->InfInfo.DriverInfo6) );
  828. }
  829. break;
  830. case PRINT_PROC_DIRECTORY_ID:
  831. if ( dwInstallFlags & DRVINST_DRIVERFILES_ONLY ) {
  832. lstrcpy(szDir, gpszSkipDir);
  833. } else if ( !GetPrintProcessorDirectory(
  834. (LPTSTR)pszServerName,
  835. PlatformEnv[platform].pszName,
  836. 1,
  837. (LPBYTE)szDir,
  838. sizeof(szDir),
  839. &dwNeeded) )
  840. goto Cleanup;
  841. break;
  842. case SYSTEM_DIRECTORY_ID_ONLY_FOR_NATIVE_ARCHITECTURE:
  843. if ( !(dwInstallFlags & DRVINST_DRIVERFILES_ONLY) &&
  844. platform == MyPlatform &&
  845. MyName(pszServerName) ) {
  846. if ( !GetSystemDirectory(szDir, dwNeeded) )
  847. goto Cleanup;
  848. } else {
  849. lstrcpy(szDir, gpszSkipDir);
  850. }
  851. break;
  852. case ICM_PROFILE_DIRECTORY_ID:
  853. if ( !GetColorDirectory(pszServerName, szDir, &dwNeeded) )
  854. goto Cleanup;
  855. break;
  856. case WEBPAGE_DIRECTORY_ID:
  857. if ( !GetWebPageDir(pLocalData, szDir) )
  858. goto Cleanup;
  859. break;
  860. default:
  861. //
  862. // This is for any new DRIDs we may add in the future
  863. //
  864. lstrcpy(szDir, gpszSkipDir);
  865. }
  866. if ( !SetupSetDirectoryId(hInf, DRID, szDir) )
  867. goto Cleanup;
  868. }
  869. }
  870. bRet = TRUE;
  871. Cleanup:
  872. return bRet;
  873. }
  874. BOOL
  875. PSetupInstallICMProfiles(
  876. IN LPCTSTR pszServerName,
  877. IN LPCTSTR pszzICMFiles
  878. )
  879. /*++
  880. Routine Description:
  881. Install ICM color profiles associated with a printer driver.
  882. Arguments:
  883. pszServerName : Server name to which we are installing
  884. pszzICMFiles : ICM profiles to install (multi-sz)
  885. Return Value:
  886. TRUE on success, FALSE else
  887. --*/
  888. {
  889. TCHAR szDir[MAX_PATH], *p;
  890. DWORD dwSize, dwNeeded;
  891. BOOL bRet = TRUE;
  892. if ( !pszzICMFiles || !*pszzICMFiles )
  893. return bRet;
  894. dwSize = SIZECHARS(szDir);
  895. dwNeeded = sizeof(szDir);
  896. if ( !GetColorDirectory(pszServerName, szDir, &dwNeeded) )
  897. return FALSE;
  898. dwNeeded /= sizeof(TCHAR);
  899. szDir[dwNeeded-1] = TEXT('\\');
  900. //
  901. // Install and assoicate each profiles from the multi-sz field
  902. //
  903. for ( p = (LPTSTR) pszzICMFiles; bRet && *p ; p += lstrlen(p) + 1 ) {
  904. if ( dwNeeded + lstrlen(p) + 1 > dwSize ) {
  905. ASSERT(dwNeeded + lstrlen(p) + 1 <= dwSize);
  906. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  907. return FALSE;
  908. }
  909. lstrcpy(szDir + dwNeeded, p);
  910. // This function only supports NULL as the servername
  911. // bRet = InstallColorProfile(pszServerName, szDir);
  912. bRet = InstallColorProfile( NULL, szDir);
  913. }
  914. return bRet;
  915. }
  916. BOOL
  917. MonitorRedirectDisable(
  918. IN LPCTSTR pszMonitorDll,
  919. OUT PTCHAR *ppszDir
  920. )
  921. {
  922. BOOL bRet = FALSE;
  923. PTCHAR pszBuffer = NULL;
  924. DWORD dwDirLen = 0;
  925. if( IsInWow64() )
  926. {
  927. pszBuffer = (PTCHAR)LocalAllocMem( MAX_PATH * sizeof( TCHAR ) );
  928. if((pszBuffer != NULL) && GetSystemDirectory(pszBuffer, MAX_PATH))
  929. {
  930. dwDirLen = lstrlen(pszBuffer);
  931. //
  932. // Size of the returned string + size of file name + '\' + terminating null.
  933. //
  934. if( (dwDirLen + lstrlen(pszMonitorDll) + 2) < MAX_PATH )
  935. {
  936. if( *(pszBuffer + dwDirLen-1) != _T('\\') )
  937. {
  938. *(pszBuffer + dwDirLen++) = _T('\\');
  939. *(pszBuffer + dwDirLen) = 0;
  940. }
  941. lstrcat(pszBuffer,pszMonitorDll);
  942. #if !_WIN64
  943. Wow64DisableFilesystemRedirector(pszBuffer);
  944. #endif
  945. bRet = TRUE;
  946. }
  947. }
  948. if (ppszDir != NULL)
  949. {
  950. *ppszDir = pszBuffer;
  951. }
  952. }
  953. return bRet;
  954. }
  955. BOOL
  956. MonitorRedirectEnable(
  957. IN OUT PTCHAR *ppszDir
  958. )
  959. {
  960. BOOL bRet = FALSE;
  961. if( IsInWow64() )
  962. {
  963. //
  964. // This MACRO works on the current thread. Only one file can be disabled for redirection at a time.
  965. //
  966. #if !_WIN64
  967. Wow64EnableFilesystemRedirector();
  968. #endif
  969. }
  970. if ((ppszDir != NULL) && (*ppszDir != NULL))
  971. {
  972. LocalFreeMem( *ppszDir );
  973. *ppszDir = NULL;
  974. bRet = TRUE;
  975. }
  976. return bRet;
  977. }
  978. BOOL
  979. UseUniqueDirectory(
  980. IN LPCTSTR pszServerName
  981. )
  982. /*++
  983. Routine Description:
  984. Determines whether the unique install directory flags should be used or not.
  985. Arguments:
  986. pszServerName - the name of the remote server. NULL means local machine.
  987. Return Value:
  988. TRUE if we are going remote to a whistler or more recent server
  989. or we are installing locally but not in setup.
  990. FALSE else
  991. --*/
  992. {
  993. BOOL bRet = FALSE;
  994. if( pszServerName && *pszServerName )
  995. {
  996. bRet = IsWhistlerOrAbove(pszServerName);
  997. }
  998. else
  999. {
  1000. if( !IsSystemSetupInProgress() )
  1001. {
  1002. bRet = TRUE;
  1003. }
  1004. }
  1005. return bRet;
  1006. }
  1007. DWORD
  1008. PSetupShowBlockedDriverUI(HWND hwnd,
  1009. DWORD BlockingStatus)
  1010. /*++
  1011. Routine Description:
  1012. Throws UI to ask user what to do with a blocked/warned driver
  1013. Arguments:
  1014. hwnd: parent window
  1015. BlockingStatus: the DWORD containing the BSP_* flags that indicate whether driver is blocked
  1016. Return Value:
  1017. New blocking status, the user selection is OR'd. Treats errors as if the user cancelled.
  1018. --*/
  1019. {
  1020. DWORD NewBlockingStatus = BlockingStatus;
  1021. LPTSTR pszTitle = NULL, pszPrompt = NULL;
  1022. switch (BlockingStatus & BSP_BLOCKING_LEVEL_MASK)
  1023. {
  1024. case BSP_PRINTER_DRIVER_WARNED:
  1025. if (BlockingStatus & BSP_INBOX_DRIVER_AVAILABLE)
  1026. {
  1027. pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
  1028. pszPrompt = GetLongStringFromRcFile(IDS_BSP_WARN_WITH_INBOX);
  1029. if (!pszTitle || !pszPrompt)
  1030. {
  1031. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1032. goto Cleanup;
  1033. }
  1034. switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_YESNOCANCEL | MB_ICONWARNING))
  1035. {
  1036. case IDYES:
  1037. NewBlockingStatus |= BSP_PRINTER_DRIVER_PROCEEDED;
  1038. break;
  1039. case IDNO:
  1040. NewBlockingStatus |= BSP_PRINTER_DRIVER_REPLACED;
  1041. break;
  1042. default:
  1043. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1044. break;
  1045. }
  1046. }
  1047. else // warned but not inbox available
  1048. {
  1049. pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
  1050. pszPrompt = GetLongStringFromRcFile(IDS_BSP_WARN_NO_INBOX);
  1051. if (!pszTitle || !pszPrompt)
  1052. {
  1053. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1054. goto Cleanup;
  1055. }
  1056. switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_OKCANCEL | MB_ICONWARNING))
  1057. {
  1058. case IDOK:
  1059. NewBlockingStatus |= BSP_PRINTER_DRIVER_PROCEEDED;
  1060. break;
  1061. default:
  1062. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1063. break;
  1064. }
  1065. }
  1066. break;
  1067. case BSP_PRINTER_DRIVER_BLOCKED:
  1068. if (BlockingStatus & BSP_INBOX_DRIVER_AVAILABLE)
  1069. {
  1070. pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
  1071. pszPrompt = GetLongStringFromRcFile(IDS_BSP_BLOCK_WITH_INBOX);
  1072. if (!pszTitle || !pszPrompt)
  1073. {
  1074. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1075. goto Cleanup;
  1076. }
  1077. switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_OKCANCEL | MB_ICONWARNING))
  1078. {
  1079. case IDOK:
  1080. NewBlockingStatus |= BSP_PRINTER_DRIVER_REPLACED;
  1081. break;
  1082. default:
  1083. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1084. break;
  1085. }
  1086. }
  1087. else // blocked and no inbox available - don't allow installation
  1088. {
  1089. pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_ERROR);
  1090. pszPrompt = GetLongStringFromRcFile(IDS_BSP_BLOCK_NO_INBOX);
  1091. if (!pszTitle || !pszPrompt)
  1092. {
  1093. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1094. goto Cleanup;
  1095. }
  1096. MessageBox(hwnd, pszPrompt, pszTitle, MB_OK | MB_ICONSTOP);
  1097. NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
  1098. }
  1099. break;
  1100. }
  1101. Cleanup:
  1102. if (pszTitle)
  1103. {
  1104. LocalFreeMem(pszTitle);
  1105. }
  1106. if (pszPrompt)
  1107. {
  1108. LocalFreeMem(pszPrompt);
  1109. }
  1110. return NewBlockingStatus;
  1111. }
  1112. DWORD
  1113. InstallDriverFromCurrentInf(
  1114. IN HDEVINFO hDevInfo,
  1115. IN PPSETUP_LOCAL_DATA pLocalData,
  1116. IN HWND hwnd,
  1117. IN PLATFORM platform,
  1118. IN DWORD dwVersion,
  1119. IN LPCTSTR pszServerName,
  1120. IN HSPFILEQ CopyQueue,
  1121. IN PVOID QueueContext,
  1122. IN PSP_FILE_CALLBACK InstallMsgHandler,
  1123. IN DWORD Flags,
  1124. IN LPCTSTR pszSource,
  1125. IN DWORD dwInstallFlags,
  1126. IN DWORD dwAddDrvFlags,
  1127. IN LPCTSTR pszFileSrcPath,
  1128. OUT LPTSTR *ppszNewDriverName,
  1129. OUT PDWORD pBlockingStatus
  1130. )
  1131. {
  1132. HINF hPrinterInf = INVALID_HANDLE_VALUE;
  1133. BOOL bRet = FALSE;
  1134. BOOL bAddMon = FALSE;
  1135. BOOL bKeepMonName = FALSE;
  1136. BOOL bCatInInf = FALSE;
  1137. DWORD dwStatus = EXIT_FAILURE;
  1138. LPTSTR pszMonitorDll,
  1139. psz;
  1140. PSELECTED_DRV_INFO pDrvInfo = &pLocalData->DrvInfo;
  1141. PPARSEINF_INFO pInfInfo = &pLocalData->InfInfo;
  1142. PVOID pDSInfo = NULL; // Holds pointer to the driver signing class that C can't understand.
  1143. FILE_QUEUE_CONTEXT FileQContext;
  1144. //
  1145. // The following are only used during Cleanup
  1146. //
  1147. BOOL bZeroInf = FALSE,
  1148. bCopyInf = FALSE;
  1149. DWORD dwMediaType = SPOST_NONE;
  1150. DWORD dwInstallLE = ERROR_SUCCESS; // We record the LastError in case Cleanup
  1151. // alters it
  1152. LPTSTR pszINFName = NULL; // This will record whether the inf was
  1153. // copied in
  1154. LPTSTR pszNewINFName = NULL; // Hold the name of the inf to be zeroed if necessary
  1155. TCHAR szFullINFName[ MAX_PATH ]; // The Original Inf Name
  1156. TCHAR szFullNewINFName[ MAX_PATH ]; // The fully qualified inf name as copied onto the system.
  1157. HANDLE hDriverFile = INVALID_HANDLE_VALUE;
  1158. LPTSTR pszNewDriverName = NULL;
  1159. DWORD fBlockingStatus = BSP_PRINTER_DRIVER_OK;
  1160. PTCHAR pszDirPtr = NULL;
  1161. DWORD ScanResult = 0;
  1162. //
  1163. // Those below are used to manage the situation when the driver is not signed
  1164. //
  1165. BOOL bIsPersonalOrProfessional = FALSE;
  1166. HANDLE hRestorePointHandle = NULL;
  1167. BOOL bDriverNotInstalled = TRUE;
  1168. BOOL bIsWindows64 = FALSE;
  1169. BOOL bPreviousNames = FALSE;
  1170. DWORD dwOEMInfFileAttrs = 0;
  1171. const DWORD dwGetFileAttrsError = 0xFFFFFFFF;
  1172. szFullINFName[0] = TEXT('\0');
  1173. szFullNewINFName[0] = TEXT('\0');
  1174. //
  1175. // Set the unique directory flags if we are in a situation that uses them.
  1176. //
  1177. if( UseUniqueDirectory(pszServerName) ) {
  1178. dwInstallFlags |= DRVINST_PRIVATE_DIRECTORY;
  1179. dwAddDrvFlags |= APD_COPY_FROM_DIRECTORY;
  1180. }
  1181. //
  1182. // If this is a Windows update install, we need to ensure that all
  1183. // cluster spooler resources get their drivers updated.
  1184. //
  1185. if (dwInstallFlags & DRVINST_WINDOWS_UPDATE)
  1186. {
  1187. dwAddDrvFlags |= APD_COPY_TO_ALL_SPOOLERS;
  1188. pInfInfo->DriverInfo6.cVersion = dwVersion;
  1189. }
  1190. //
  1191. // Open INF file and append layout.inf specified in Version section
  1192. // Layout inf is optional
  1193. //
  1194. hPrinterInf = SetupOpenInfFile(pDrvInfo->pszInfName,
  1195. NULL,
  1196. INF_STYLE_WIN4,
  1197. NULL);
  1198. if ( hPrinterInf == INVALID_HANDLE_VALUE )
  1199. goto Cleanup;
  1200. SetupOpenAppendInfFile(NULL, hPrinterInf, NULL);
  1201. pInfInfo->DriverInfo6.pEnvironment = PlatformEnv[platform].pszName;
  1202. //
  1203. // DI_VCP tells us not to create new file-queue and use user provided one
  1204. //
  1205. if ( !(Flags & DI_NOVCP) ) {
  1206. CopyQueue = SetupOpenFileQueue();
  1207. if ( CopyQueue == INVALID_HANDLE_VALUE )
  1208. goto Cleanup;
  1209. if ( dwInstallFlags & DRVINST_PROGRESSLESS ) {
  1210. QueueContext = SetupInitDefaultQueueCallbackEx(
  1211. hwnd,
  1212. INVALID_HANDLE_VALUE,
  1213. 0,
  1214. 0,
  1215. NULL);
  1216. } else {
  1217. QueueContext = SetupInitDefaultQueueCallback(hwnd);
  1218. }
  1219. InstallMsgHandler = MyQueueCallback;
  1220. ZeroMemory(&FileQContext, sizeof(FileQContext));
  1221. FileQContext.hwnd = hwnd;
  1222. FileQContext.QueueContext = QueueContext;
  1223. FileQContext.dwInstallFlags = dwInstallFlags;
  1224. FileQContext.pszSource = (dwInstallFlags & DRVINST_FLATSHARE)
  1225. ? pszSource : NULL;
  1226. FileQContext.platform = platform;
  1227. FileQContext.dwVersion = dwVersion;
  1228. FileQContext.pszFileSrcPath = pszFileSrcPath;
  1229. if (pDrvInfo->pszInfName)
  1230. {
  1231. _tcscpy(FileQContext.szInfPath, pDrvInfo->pszInfName);
  1232. //
  1233. // Cut off the inf file name
  1234. //
  1235. psz = _tcsrchr(FileQContext.szInfPath, _T('\\'));
  1236. if (psz)
  1237. {
  1238. *psz = 0;
  1239. }
  1240. }
  1241. }
  1242. //
  1243. // Setup the driver signing info.
  1244. //
  1245. if(NULL == (pDSInfo = SetupDriverSigning(hDevInfo, pszServerName,pDrvInfo->pszInfName,
  1246. pszSource, platform, dwVersion, CopyQueue, dwInstallFlags & DRVINST_WEBPNP)))
  1247. {
  1248. goto Cleanup;
  1249. }
  1250. //
  1251. // Find out if the cat was listed in a CatalogFile= entry.
  1252. // This is used in the cleanup.
  1253. //
  1254. bCatInInf = IsCatInInf(pDSInfo);
  1255. //
  1256. // Check if this Driver is from CDM.
  1257. // IF it is pass in the correct MediaType to Setup.
  1258. //
  1259. if ( (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER) || (dwInstallFlags & DRVINST_WINDOWS_UPDATE) )
  1260. dwMediaType = SPOST_URL;
  1261. //
  1262. // For non admins, we install the catalog by calling AddDriverCatalog
  1263. //
  1264. // Do not fail the call when AddDriverCatalog fails
  1265. //
  1266. (void)AddDriverCatalogIfNotAdmin(pszServerName, pDSInfo, pDrvInfo->pszInfName, NULL, dwMediaType, 0);
  1267. //
  1268. // To support same INFs to install both NT and Win95 drivers actual
  1269. // section to install could be different than the one corresponding
  1270. // to the selected driver.
  1271. //
  1272. // SetupSetPlatformOverride tells setup which platform drivers we need
  1273. // from the media
  1274. // Also note setup does not reset PlatformPath override. So we need to
  1275. // call this always
  1276. //
  1277. if ( !ParseInf(hDevInfo, pLocalData, platform, pszServerName, dwInstallFlags) ||
  1278. !SetupSetPlatformPathOverride(PlatformOverride[platform].pszName) ) {
  1279. goto Cleanup;
  1280. }
  1281. // Now do the actual file copies...
  1282. if ( !InstallAllInfSections( pLocalData,
  1283. platform,
  1284. pszServerName,
  1285. CopyQueue,
  1286. pszSource,
  1287. dwInstallFlags,
  1288. hPrinterInf,
  1289. pInfInfo->pszInstallSection ) )
  1290. goto Cleanup;
  1291. //
  1292. // If there is a language monitor make sure it is getting copied to
  1293. // system32. On NT 4 we used to manually queue it to system32
  1294. //
  1295. if ( pInfInfo->DriverInfo6.pMonitorName &&
  1296. platform == MyPlatform &&
  1297. !(dwInstallFlags & DRVINST_DRIVERFILES_ONLY) &&
  1298. !pszServerName)
  1299. {
  1300. //
  1301. // if it's an alternate platform but the platform really is the same (checked above)
  1302. // it's an NT4 driver on an x86 server. In this case install the LM too if not
  1303. // already installed, see XP-bug 416129, else point-and-print from an NT4 client
  1304. // that has the same driver installed locally will delete the LM info from the NT4 driver.
  1305. // The logic is a little twisted: install the monitor if it's not an alternate platform
  1306. // or if it is (within the limits checked above) but no monitor with this name is installed yet.
  1307. //
  1308. if (!(dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) ||
  1309. !IsLanguageMonitorInstalled(pInfInfo->DriverInfo6.pMonitorName))
  1310. {
  1311. pszMonitorDll = pInfInfo->DriverInfo6.pMonitorName +
  1312. lstrlen(pInfInfo->DriverInfo6.pMonitorName) + 1;
  1313. //
  1314. // When we parse the INF we put the monitor dll name after \0
  1315. //
  1316. if ( !CheckAndEnqueueMonitorDll(pszMonitorDll,
  1317. pszSource,
  1318. CopyQueue,
  1319. hPrinterInf) )
  1320. goto Cleanup;
  1321. MonitorRedirectDisable( pszMonitorDll, &pszDirPtr );
  1322. bAddMon = TRUE;
  1323. }
  1324. else
  1325. {
  1326. //
  1327. // we get here if it's an alternate platform driver and the monitor is already installed
  1328. // in this case, don't clean out the monitor name from the driver info 6 below.
  1329. //
  1330. bKeepMonName = TRUE;
  1331. }
  1332. }
  1333. //
  1334. // DI_NOVCP is used for pre-install when the class installer is just
  1335. // supposed to queue the files and return. Printing needs special
  1336. // handling since APIs need to be called. But we will obey the flags
  1337. // as much as possible for those who use it
  1338. //
  1339. if ( Flags & DI_NOVCP ) {
  1340. bRet = TRUE;
  1341. goto Cleanup;
  1342. }
  1343. // We need a Queue Context to actually install files
  1344. if ( !QueueContext )
  1345. goto Cleanup;
  1346. // Check if this is a WebPnP install
  1347. if ( dwInstallFlags & DRVINST_WEBPNP || !(bAddMon || bKeepMonName) )
  1348. {
  1349. //
  1350. // Check to see if there is a Monitor. If so clear out if it is not installed already
  1351. //
  1352. if ( pInfInfo->DriverInfo6.pMonitorName &&
  1353. !IsMonitorInstalled( pInfInfo->DriverInfo6.pMonitorName ) )
  1354. {
  1355. LocalFreeMem( pInfInfo->DriverInfo6.pMonitorName );
  1356. pInfInfo->DriverInfo6.pMonitorName = NULL;
  1357. }
  1358. }
  1359. if (!PruneInvalidFilesIfNotAdmin( hwnd,
  1360. CopyQueue ))
  1361. goto Cleanup;
  1362. //
  1363. // prune files that are already present (correct version etc. checked by signature), ignore return value
  1364. //
  1365. SetupScanFileQueue( CopyQueue,
  1366. (SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE),
  1367. hwnd,
  1368. NULL,
  1369. NULL,
  1370. &ScanResult);
  1371. if (!pszServerName || !lstrlen(pszServerName))
  1372. {
  1373. bIsPersonalOrProfessional = IsProductType( VER_NT_WORKSTATION, VER_EQUAL) == S_OK;
  1374. }
  1375. else
  1376. {
  1377. bIsPersonalOrProfessional = FALSE;
  1378. }
  1379. if (bIsPersonalOrProfessional)
  1380. {
  1381. SetupSetFileQueueFlags( CopyQueue,
  1382. SPQ_FLAG_ABORT_IF_UNSIGNED,
  1383. SPQ_FLAG_ABORT_IF_UNSIGNED );
  1384. }
  1385. if ( !SetupCommitFileQueue(hwnd,
  1386. CopyQueue,
  1387. (PSP_FILE_CALLBACK)InstallMsgHandler,
  1388. (PVOID)&FileQContext) )
  1389. {
  1390. bIsWindows64 = IsInWow64();
  1391. if ((bIsWindows64 == FALSE) && bIsPersonalOrProfessional &&
  1392. (GetLastError() == ERROR_SET_SYSTEM_RESTORE_POINT))
  1393. {
  1394. //
  1395. // Here we have to start a Restore Point because there is
  1396. // something unsigned and this is either a personal or
  1397. // professional.
  1398. //
  1399. hRestorePointHandle = StartSystemRestorePoint( NULL,
  1400. (PCWSTR)(pLocalData->DrvInfo.pszModelName),
  1401. ghInst,
  1402. IDS_BSP_WARN_UNSIGNED_DRIVER );
  1403. //
  1404. // Terminate the default setupapi callback
  1405. //
  1406. SetupTermDefaultQueueCallback( QueueContext );
  1407. QueueContext = NULL;
  1408. //
  1409. // Initialize the QueueContext structure
  1410. //
  1411. if ( dwInstallFlags & DRVINST_PROGRESSLESS )
  1412. {
  1413. QueueContext = SetupInitDefaultQueueCallbackEx(hwnd,
  1414. INVALID_HANDLE_VALUE,
  1415. 0,
  1416. 0,
  1417. NULL);
  1418. }
  1419. else
  1420. {
  1421. QueueContext = SetupInitDefaultQueueCallback(hwnd);
  1422. }
  1423. if (!QueueContext)
  1424. {
  1425. goto Cleanup;
  1426. }
  1427. else
  1428. {
  1429. FileQContext.QueueContext = QueueContext;
  1430. }
  1431. //
  1432. // Reset the flag and call the function again
  1433. //
  1434. SetupSetFileQueueFlags( CopyQueue,
  1435. SPQ_FLAG_ABORT_IF_UNSIGNED,
  1436. 0 );
  1437. if ( !SetupCommitFileQueue(hwnd,
  1438. CopyQueue,
  1439. (PSP_FILE_CALLBACK)InstallMsgHandler,
  1440. (PVOID)&FileQContext) )
  1441. {
  1442. goto Cleanup;
  1443. }
  1444. }
  1445. else
  1446. {
  1447. goto Cleanup;
  1448. }
  1449. }
  1450. //
  1451. // Now that we did the file copy part of install we will do anything
  1452. // else specified in the INF
  1453. //
  1454. if ( !pszServerName && platform == MyPlatform )
  1455. {
  1456. SetupInstallFromInfSection(hwnd,
  1457. hPrinterInf,
  1458. pInfInfo->pszInstallSection,
  1459. SPINST_ALL & (~SPINST_FILES),
  1460. NULL,
  1461. pszSource,
  1462. 0,
  1463. NULL,
  1464. QueueContext,
  1465. hDevInfo,
  1466. pDrvInfo->pDevInfoData);
  1467. }
  1468. if ( bAddMon )
  1469. {
  1470. if( !AddPrintMonitor(pInfInfo->DriverInfo6.pMonitorName, pszMonitorDll) )
  1471. {
  1472. DWORD dwSavedLastError = EXIT_FAILURE;
  1473. //
  1474. // Fix bug 346937: when we can not add monitor, check whether this
  1475. // driver is in printupg. If it is, consider it blocked then and
  1476. // popups a UI asking whether to install the replacement driver.
  1477. //
  1478. // After this point bRet is allways false, we only try to change
  1479. // the error code in last error.
  1480. //
  1481. //
  1482. // Save the last error first
  1483. //
  1484. dwSavedLastError = GetLastError();
  1485. if (BlockedDriverPrintUpgUI(pszServerName,
  1486. &pInfInfo->DriverInfo6,
  1487. dwInstallFlags & DRVINST_PRIVATE_DIRECTORY, // whether use full path
  1488. !(dwInstallFlags & DRVINST_DONT_OFFER_REPLACEMENT), // whether to offer replacement
  1489. !(dwInstallFlags & (DRVINST_NO_WARNING_PROMPT | DRVINST_PROMPTLESS)), // whether to popup UI
  1490. &pszNewDriverName,
  1491. &fBlockingStatus) &&
  1492. (fBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
  1493. {
  1494. SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
  1495. }
  1496. else
  1497. {
  1498. SetLastError(dwSavedLastError); // restore the error code
  1499. }
  1500. goto Cleanup;
  1501. }
  1502. MonitorRedirectEnable( &pszDirPtr );
  1503. }
  1504. //
  1505. // If a print processor is specified in the INF need to install it.
  1506. // For non-native architectur spooler fails this call (for remote case)
  1507. //
  1508. if ( pInfInfo->pszPrintProc &&
  1509. !AddPrintProcessor((LPTSTR)pszServerName,
  1510. PlatformEnv[platform].pszName,
  1511. pInfInfo->pszPrintProc
  1512. + lstrlen(pInfInfo->pszPrintProc) + 1,
  1513. pInfInfo->pszPrintProc) &&
  1514. GetLastError() != ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED &&
  1515. GetLastError() != ERROR_INVALID_ENVIRONMENT )
  1516. {
  1517. goto Cleanup;
  1518. }
  1519. if (IsTheSamePlatform(pszServerName, platform) && IsWhistlerOrAbove(pszServerName))
  1520. {
  1521. bPreviousNames = CheckAndKeepPreviousNames( pszServerName, &pInfInfo->DriverInfo6, platform );
  1522. }
  1523. bRet = AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry(pszServerName,
  1524. &pInfInfo->DriverInfo6,
  1525. dwAddDrvFlags | APD_DONT_SET_CHECKPOINT,
  1526. dwInstallFlags & DRVINST_PRIVATE_DIRECTORY, // whether use full path
  1527. !(dwInstallFlags & DRVINST_DONT_OFFER_REPLACEMENT), // whether to offer replacement
  1528. !(dwInstallFlags & (DRVINST_NO_WARNING_PROMPT | DRVINST_PROMPTLESS)), // whether to popup UI
  1529. &pszNewDriverName,
  1530. &fBlockingStatus) &&
  1531. PSetupInstallICMProfiles(pszServerName, pInfInfo->pszzICMFiles);
  1532. if (bPreviousNames)
  1533. {
  1534. LocalFreeMem( pInfInfo->DriverInfo6.pszzPreviousNames );
  1535. }
  1536. bDriverNotInstalled = FALSE;
  1537. Cleanup:
  1538. dwInstallLE = GetLastError(); // Get the real error message
  1539. if (bAddMon && pszDirPtr)
  1540. {
  1541. MonitorRedirectEnable( &pszDirPtr );
  1542. }
  1543. if ((bIsWindows64 == FALSE) && hRestorePointHandle)
  1544. {
  1545. //
  1546. // Here we have to end the Restore Point because one was
  1547. // started
  1548. //
  1549. EndSystemRestorePoint(hRestorePointHandle, bDriverNotInstalled);
  1550. }
  1551. if (hDriverFile != INVALID_HANDLE_VALUE)
  1552. {
  1553. CloseHandle(hDriverFile);
  1554. }
  1555. //
  1556. // Zero the inf if DI_NOVCP and - either we've fail, it is a Web PNP
  1557. // install. or - this is installing from a non-system ntprint.inf AND
  1558. // there is a cat to be protected. - not yet!!
  1559. //
  1560. bZeroInf = (!bRet || ( dwInstallFlags & DRVINST_WEBPNP )
  1561. || (IsNTPrintInf( pDrvInfo->pszInfName ) && bCatInInf)) &&
  1562. !(Flags & DI_NOVCP);
  1563. //
  1564. // We have to copy the INF if the following conditions are satisfied
  1565. //
  1566. bCopyInf = // bRet is TRUE (the call to AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry succeeded)
  1567. bRet &&
  1568. // and the Installation flags say the INF to be copied
  1569. !(dwInstallFlags & DRVINST_DONOTCOPY_INF) &&
  1570. // and the platform is the same as ours
  1571. platform == MyPlatform &&
  1572. // and the INF it's not the system ntprint.inf (obviously) or
  1573. // it's from WU
  1574. (!IsSystemNTPrintInf(pDrvInfo->pszInfName) || (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER)) &&
  1575. // and DI_NOVCP flag is not set
  1576. !(Flags & DI_NOVCP) &&
  1577. // and this is not Web PnP or there is a cat to protect
  1578. !((dwInstallFlags & DRVINST_WEBPNP) && !bCatInInf) &&
  1579. // and this is not ntprint.inf or there is a cat to protect
  1580. !(IsNTPrintInf( pDrvInfo->pszInfName ) && !bCatInInf);
  1581. //
  1582. // How we have to call SetupCopyOEMInf to take the name of the INF which
  1583. // has been copied on our system when we called SetupCommitFileQueue
  1584. //
  1585. if (!SetupCopyOEMInf(pDrvInfo->pszInfName,
  1586. NULL,
  1587. dwMediaType,
  1588. SP_COPY_REPLACEONLY,
  1589. szFullINFName,
  1590. MAX_PATH,
  1591. NULL,
  1592. &pszINFName) )
  1593. {
  1594. // If we can't find the original name might as well not copy or
  1595. // zero
  1596. if (bZeroInf && !bCopyInf)
  1597. {
  1598. bZeroInf = FALSE;
  1599. }
  1600. }
  1601. else
  1602. {
  1603. if (bZeroInf)
  1604. {
  1605. bCopyInf = FALSE;
  1606. }
  1607. }
  1608. //
  1609. // If we succesfully installed a native architecture driver
  1610. // then is when we copy the OEM INF file and give it a unique name
  1611. //
  1612. if ( bCopyInf )
  1613. {
  1614. //
  1615. // Earlier we used to call CopyOEMInfFileAndGiveUniqueName here
  1616. // Now that Setup API has this and we are going to support CDM
  1617. // we call this setup API
  1618. //
  1619. (VOID)SetupCopyOEMInf(pDrvInfo->pszInfName,
  1620. NULL,
  1621. dwMediaType,
  1622. SP_COPY_NOOVERWRITE,
  1623. szFullNewINFName,
  1624. MAX_PATH,
  1625. NULL,
  1626. &pszNewINFName);
  1627. //
  1628. // If this fails we don't give the proverbial, since the file won't
  1629. // be there
  1630. //
  1631. }
  1632. else
  1633. {
  1634. if (!bZeroInf && !(Flags & DI_NOVCP))
  1635. {
  1636. //
  1637. // We have to remove the INF in the case of unsuccessful installation and ONLY if the DI_NOVCP
  1638. // flag is not set. If the flag is set then we don't have to change the state because the file
  1639. // queue hasn't been commited and the INF just has been already there before the call to our
  1640. // function.
  1641. //
  1642. //
  1643. // Remove the READONLY file attribute if set
  1644. //
  1645. dwOEMInfFileAttrs = GetFileAttributes( szFullINFName );
  1646. if ((dwOEMInfFileAttrs != dwGetFileAttrsError) &&
  1647. (dwOEMInfFileAttrs & FILE_ATTRIBUTE_READONLY))
  1648. {
  1649. dwOEMInfFileAttrs &= ~FILE_ATTRIBUTE_READONLY;
  1650. SetFileAttributes( szFullINFName, dwOEMInfFileAttrs);
  1651. }
  1652. DeleteFile( szFullINFName );
  1653. }
  1654. }
  1655. // Ignore the error message from SetupCopyOEMInf and DeleteFile
  1656. dwStatus = bRet ? ERROR_SUCCESS : dwInstallLE;
  1657. // If the install failed or this was Web Point&Print
  1658. // we may need to get rid of the INF
  1659. if ( bZeroInf )
  1660. {
  1661. // If INFName is different then possibly set to 0 length
  1662. // Or this is ntprint.inf being renamed to OEMx.inf - we want it zeroed.
  1663. if (( pszINFName &&
  1664. (psz=FileNamePart( pDrvInfo->pszInfName )) &&
  1665. lstrcmp( psz, pszINFName ) ) ||
  1666. ( IsNTPrintInf( pDrvInfo->pszInfName ) &&
  1667. bCatInInf &&
  1668. pszNewINFName &&
  1669. (psz=FileNamePart( pDrvInfo->pszInfName )) &&
  1670. lstrcmp( psz, pszINFName ) ) )
  1671. {
  1672. HANDLE hFile;
  1673. //
  1674. // Remove the READONLY file attribute if set
  1675. //
  1676. dwOEMInfFileAttrs = GetFileAttributes(szFullINFName ? szFullINFName : szFullNewINFName);
  1677. if ((dwOEMInfFileAttrs != dwGetFileAttrsError) &&
  1678. (dwOEMInfFileAttrs & FILE_ATTRIBUTE_READONLY))
  1679. {
  1680. dwOEMInfFileAttrs &= ~FILE_ATTRIBUTE_READONLY;
  1681. SetFileAttributes(szFullINFName ? szFullINFName : szFullNewINFName, dwOEMInfFileAttrs);
  1682. }
  1683. // Open the File
  1684. hFile = CreateFile( szFullINFName ? szFullINFName : szFullNewINFName,
  1685. (GENERIC_READ | GENERIC_WRITE),
  1686. ( FILE_SHARE_READ | FILE_SHARE_WRITE ),
  1687. NULL,
  1688. OPEN_EXISTING,
  1689. FILE_ATTRIBUTE_NORMAL,
  1690. NULL );
  1691. // If we opened a file
  1692. if ( hFile != INVALID_HANDLE_VALUE )
  1693. {
  1694. SetFilePointer( hFile, 0, 0, FILE_BEGIN );
  1695. SetEndOfFile( hFile );
  1696. CloseHandle( hFile );
  1697. }
  1698. }
  1699. }
  1700. if ( hPrinterInf != INVALID_HANDLE_VALUE )
  1701. SetupCloseInfFile(hPrinterInf);
  1702. //
  1703. // Free the Driver Signing class.
  1704. //
  1705. if(pDSInfo)
  1706. {
  1707. CleanupDriverSigning(pDSInfo);
  1708. }
  1709. if ( !(Flags & DI_NOVCP) ) {
  1710. //
  1711. // The driver signing code may have associated the queue to the SP_DEVINSTALL_PARAMS.
  1712. // We've finished with this and need to remove the queue from the SP_DEVINSTALL_PARAMS before we delete it.
  1713. //
  1714. SP_DEVINSTALL_PARAMS DevInstallParams = {0};
  1715. DevInstallParams.cbSize = sizeof(DevInstallParams);
  1716. if(SetupDiGetDeviceInstallParams(hDevInfo,
  1717. NULL,
  1718. &DevInstallParams))
  1719. {
  1720. if(DevInstallParams.FileQueue == CopyQueue)
  1721. {
  1722. DevInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
  1723. DevInstallParams.Flags &= ~DI_NOVCP;
  1724. DevInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  1725. SetupDiSetDeviceInstallParams(hDevInfo,
  1726. NULL,
  1727. &DevInstallParams);
  1728. }
  1729. }
  1730. //
  1731. // Now free up the queue.
  1732. //
  1733. if ( CopyQueue != INVALID_HANDLE_VALUE )
  1734. {
  1735. SetupCloseFileQueue(CopyQueue);
  1736. }
  1737. if ( QueueContext )
  1738. {
  1739. SetupTermDefaultQueueCallback(QueueContext);
  1740. }
  1741. if( dwAddDrvFlags & APD_COPY_FROM_DIRECTORY )
  1742. {
  1743. //
  1744. // if this was an installation with a path derived from the Pnp-ID,
  1745. // do not cleanup, else users will get prompted for media when they re-pnp the driver
  1746. //
  1747. if ( ! (pLocalData->Flags & LOCALDATAFLAG_PNP_DIR_INSTALL) )
  1748. {
  1749. CleanupUniqueScratchDirectory( pszServerName, platform );
  1750. }
  1751. }
  1752. else
  1753. {
  1754. CleanupScratchDirectory( pszServerName, platform );
  1755. }
  1756. }
  1757. //
  1758. // Return the new driver name and the blocking flags if they were asked for.
  1759. //
  1760. if (ppszNewDriverName)
  1761. {
  1762. *ppszNewDriverName = pszNewDriverName;
  1763. }
  1764. else if (pszNewDriverName)
  1765. {
  1766. LocalFreeMem(pszNewDriverName);
  1767. }
  1768. if (pBlockingStatus)
  1769. {
  1770. *pBlockingStatus = fBlockingStatus;
  1771. }
  1772. return dwStatus;
  1773. }
  1774. DWORD
  1775. InstallDriverAfterPromptingForInf(
  1776. IN PLATFORM platform,
  1777. IN LPCTSTR pszServerName,
  1778. IN HWND hwnd,
  1779. IN LPCTSTR pszModelName,
  1780. IN DWORD dwVersion,
  1781. IN OUT TCHAR szInfPath[MAX_PATH],
  1782. IN DWORD dwInstallFlags,
  1783. IN DWORD dwAddDrvFlags,
  1784. OUT LPTSTR *ppszNewDriverName
  1785. )
  1786. {
  1787. DWORD dwRet, dwTitleId, dwMediaId;
  1788. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  1789. PPSETUP_LOCAL_DATA pLocalData = NULL;
  1790. LPTSTR pszFileSrcPath = NULL;
  1791. DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
  1792. switch (platform) {
  1793. case PlatformAlpha:
  1794. dwTitleId = IDS_DRIVERS_FOR_NT4_ALPHA;
  1795. break;
  1796. case PlatformX86:
  1797. if( dwVersion == 2 )
  1798. {
  1799. dwTitleId = IDS_DRIVERS_FOR_NT4_X86;
  1800. }
  1801. else
  1802. {
  1803. dwTitleId = IDS_DRIVERS_FOR_X86;
  1804. }
  1805. break;
  1806. case PlatformMIPS:
  1807. dwTitleId = IDS_DRIVERS_FOR_NT4_MIPS;
  1808. break;
  1809. case PlatformPPC:
  1810. dwTitleId = IDS_DRIVERS_FOR_NT4_PPC;
  1811. break;
  1812. case PlatformIA64:
  1813. dwTitleId = IDS_DRIVERS_FOR_IA64;
  1814. break;
  1815. default:
  1816. ASSERT(0);
  1817. return ERROR_INVALID_PARAMETER;
  1818. }
  1819. dwMediaId = IDS_PROMPT_ALT_PLATFORM_DRIVER;
  1820. dwInstallFlags |= DRVINST_ALT_PLATFORM_INSTALL | DRVINST_NO_WARNING_PROMPT;
  1821. hDevInfo = GetInfAndBuildDrivers(hwnd,
  1822. dwTitleId,
  1823. dwMediaId,
  1824. szInfPath,
  1825. dwInstallFlags,
  1826. platform, dwVersion,
  1827. pszModelName,
  1828. &pLocalData,
  1829. &pszFileSrcPath);
  1830. if ( hDevInfo == INVALID_HANDLE_VALUE ) {
  1831. dwRet = GetLastError();
  1832. goto Cleanup;
  1833. }
  1834. //
  1835. // we want the printupg prompt
  1836. //
  1837. dwInstallFlags &= ~DRVINST_NO_WARNING_PROMPT;
  1838. dwRet = InstallDriverFromCurrentInf(hDevInfo,
  1839. pLocalData,
  1840. hwnd,
  1841. platform,
  1842. dwVersion,
  1843. pszServerName,
  1844. INVALID_HANDLE_VALUE,
  1845. NULL,
  1846. NULL,
  1847. 0,
  1848. szInfPath,
  1849. dwInstallFlags,
  1850. dwAddDrvFlags,
  1851. pszFileSrcPath,
  1852. ppszNewDriverName,
  1853. &dwBlockingStatus);
  1854. if (((ERROR_PRINTER_DRIVER_BLOCKED == dwRet) || (ERROR_PRINTER_DRIVER_WARNED == dwRet)) &&
  1855. (ppszNewDriverName && *ppszNewDriverName) &&
  1856. (dwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
  1857. {
  1858. dwRet = InstallReplacementDriver(hwnd,
  1859. pszServerName,
  1860. *ppszNewDriverName,
  1861. platform,
  1862. dwVersion,
  1863. dwInstallFlags,
  1864. dwAddDrvFlags);
  1865. }
  1866. else if (ppszNewDriverName && *ppszNewDriverName)
  1867. {
  1868. LocalFreeMem(*ppszNewDriverName);
  1869. *ppszNewDriverName = NULL;
  1870. }
  1871. Cleanup:
  1872. if (pszFileSrcPath)
  1873. {
  1874. //
  1875. // we did the NT4 copy/expand thing -> delete the expanded inf!
  1876. //
  1877. _tcscat(szInfPath, _T("ntprint.inf"));
  1878. DeleteFile(szInfPath);
  1879. LocalFreeMem(pszFileSrcPath);
  1880. }
  1881. if ( hDevInfo != INVALID_HANDLE_VALUE )
  1882. DestroyOnlyPrinterDeviceInfoList(hDevInfo);
  1883. DestroyLocalData(pLocalData);
  1884. return dwRet;
  1885. }
  1886. const TCHAR gcszNTPrint[] = _TEXT("inf\\ntprint.inf");
  1887. DWORD GetNtprintDotInfPath(LPTSTR pszNTPrintInf, DWORD len)
  1888. {
  1889. DWORD dwLastError = ERROR_INVALID_DATA, dwSize;
  1890. LPTSTR pData;
  1891. //
  1892. // Get %windir%
  1893. // If the return is 0 - the call failed.
  1894. // If the return is greater than MAX_PATH we want to fail as something has managed to change
  1895. // the system dir to longer than MAX_PATH which is invalid.
  1896. //
  1897. dwSize = GetSystemWindowsDirectory( pszNTPrintInf, len );
  1898. if( !dwSize || dwSize > len )
  1899. goto Cleanup;
  1900. //
  1901. // If we don't end in a \ then add one.
  1902. //
  1903. dwSize = _tcslen(pszNTPrintInf);
  1904. pData = &(pszNTPrintInf[ dwSize ]);
  1905. if (*pData != _TEXT('\\') )
  1906. {
  1907. if (dwSize + 1 < len)
  1908. {
  1909. *(pData++) = _TEXT('\\');
  1910. dwSize++;
  1911. }
  1912. }
  1913. *(pData) = 0;
  1914. dwSize += _tcslen( gcszNTPrint ) + 1;
  1915. //
  1916. // If what we've got sums up to a longer string than the allowable length MAX_PATH - fail
  1917. //
  1918. if ( dwSize > len )
  1919. goto Cleanup;
  1920. //
  1921. // Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
  1922. //
  1923. _tcscpy( pData, gcszNTPrint );
  1924. dwLastError = ERROR_SUCCESS;
  1925. Cleanup:
  1926. if (dwLastError != ERROR_SUCCESS)
  1927. {
  1928. //
  1929. // Got here due to some error. Get what the called function set the last error to.
  1930. // If the function set a success, set some error code.
  1931. //
  1932. if ( (dwLastError = GetLastError()) == ERROR_SUCCESS)
  1933. {
  1934. dwLastError = ERROR_INVALID_DATA;
  1935. }
  1936. if (len)
  1937. {
  1938. pszNTPrintInf[0] = 0;
  1939. }
  1940. }
  1941. return dwLastError;
  1942. }
  1943. DWORD
  1944. InstallReplacementDriver(HWND hwnd,
  1945. LPCTSTR pszServerName,
  1946. LPCTSTR pszModelName,
  1947. PLATFORM platform,
  1948. DWORD version,
  1949. DWORD dwInstallFlags,
  1950. DWORD dwAddDrvFlags)
  1951. /*++
  1952. Routine Description:
  1953. Install an inbox replacement driver for blocked/warned drivers.
  1954. Arguments:
  1955. hwnd : parent windows handle.
  1956. pszServerName : Server name to which we are installing
  1957. pszModelName : driver model name to install
  1958. Return Value:
  1959. ERROR_SUCCESS on success, error code otherwise
  1960. --*/
  1961. {
  1962. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  1963. PPSETUP_LOCAL_DATA pLocalData = NULL;
  1964. TCHAR szNtprintDotInf[MAX_PATH];
  1965. DWORD dwLastError;
  1966. if ((dwLastError = GetNtprintDotInfPath(szNtprintDotInf, COUNTOF(szNtprintDotInf))) != ERROR_SUCCESS)
  1967. {
  1968. goto Cleanup;
  1969. }
  1970. if ((hDevInfo = PSetupCreatePrinterDeviceInfoList(NULL)) != INVALID_HANDLE_VALUE &&
  1971. PSetupBuildDriversFromPath(hDevInfo, szNtprintDotInf, TRUE) &&
  1972. PSetupPreSelectDriver(hDevInfo, NULL, pszModelName) &&
  1973. (pLocalData = BuildInternalData(hDevInfo, NULL)) != NULL &&
  1974. ParseInf(hDevInfo, pLocalData, platform, NULL, dwInstallFlags))
  1975. {
  1976. //
  1977. // Don't prompt for blocked or warned drivers.
  1978. //
  1979. dwInstallFlags |= DRVINST_NO_WARNING_PROMPT;
  1980. dwLastError = InstallDriverFromCurrentInf( hDevInfo,
  1981. pLocalData,
  1982. hwnd,
  1983. platform,
  1984. version,
  1985. pszServerName,
  1986. INVALID_HANDLE_VALUE,
  1987. NULL,
  1988. NULL,
  1989. 0,
  1990. szNtprintDotInf,
  1991. dwInstallFlags,
  1992. dwAddDrvFlags,
  1993. NULL,
  1994. NULL,
  1995. NULL);
  1996. }
  1997. else
  1998. {
  1999. dwLastError = GetLastError();
  2000. }
  2001. Cleanup:
  2002. if(pLocalData != NULL)
  2003. {
  2004. PSetupDestroySelectedDriverInfo(pLocalData);
  2005. }
  2006. //
  2007. // Release the driver setup parameter handle.
  2008. //
  2009. if(hDevInfo != INVALID_HANDLE_VALUE)
  2010. {
  2011. PSetupDestroyPrinterDeviceInfoList( hDevInfo );
  2012. }
  2013. return dwLastError;
  2014. }
  2015. DWORD
  2016. InvokeSetup(
  2017. IN HWND hwnd,
  2018. IN LPCTSTR pszOption,
  2019. IN LPCTSTR pszInfFile,
  2020. IN LPCTSTR pszSourcePath,
  2021. IN LPCTSTR pszServerName OPTIONAL
  2022. )
  2023. /*++
  2024. Routine Description:
  2025. Invoke setup to do an install operation associated with an INF.
  2026. Will be used to install drivers from printer.inf, monitors from monitor.inf
  2027. Arguments:
  2028. hwnd : Window handle of current top-level window
  2029. pszOption : Option from the INF file to install
  2030. pszInfFile : Name of the INF file to be used for the setup
  2031. pszSourcePath : Location where the required files are available
  2032. pszServerName : Server to install printer driver on (NULL if local)
  2033. Return Value:
  2034. ERROR_SUCCESS on succesfully installing the driver
  2035. Erro code on failure
  2036. --*/
  2037. {
  2038. TCHAR szAppName[] = TEXT("%s\\SETUP.exe");
  2039. TCHAR szCmd[] = TEXT(" -f -s %s -i %s -c ExternalInstallOption \
  2040. /t STF_LANGUAGE = ENG /t OPTION = \"%s\" \
  2041. /t STF_PRINTSERVER = \"%s\" /t ADDCOPY = YES /t DOCOPY = YES \
  2042. /t DOCONFIG = YES /w %d");
  2043. MSG Msg;
  2044. DWORD dwSize, dwLastError = ERROR_SUCCESS;
  2045. LPTSTR pszSetupExe = NULL;
  2046. LPTSTR pszSetupCmd = NULL;
  2047. TCHAR szSystemPath[MAX_PATH];
  2048. STARTUPINFO StartupInfo;
  2049. PROCESS_INFORMATION ProcessInformation;
  2050. #if defined(_WIN64)
  2051. //
  2052. // Setup.exe must be loaded from the wow64 directory.
  2053. //
  2054. if( (dwSize = GetSystemWindowsDirectory(szSystemPath,SIZECHARS(szSystemPath))))
  2055. {
  2056. if( szSystemPath[dwSize-1] != _TEXT('\\') && dwSize + 1 < SIZECHARS(szSystemPath) )
  2057. {
  2058. szSystemPath[dwSize++] = _TEXT('\\');
  2059. szSystemPath[dwSize] = 0;
  2060. }
  2061. }
  2062. #ifdef UNICODE
  2063. if(dwSize + lstrlen(WOW64_SYSTEM_DIRECTORY_U) + 1 < SIZECHARS(szSystemPath))
  2064. {
  2065. lstrcat( szSystemPath, WOW64_SYSTEM_DIRECTORY_U );
  2066. }
  2067. #else
  2068. if(dwSize + lstrlen(WOW64_SYSTEM_DIRECTORY) + 1 < SIZECHARS(szSystemPath))
  2069. {
  2070. lstrcat( szSystemPath, WOW64_SYSTEM_DIRECTORY );
  2071. }
  2072. #endif // #ifdef UNICODE
  2073. #else
  2074. //
  2075. // Setup.exe is in the system path
  2076. //
  2077. if( (dwSize = GetSystemDirectory(szSystemPath,SIZECHARS(szSystemPath))))
  2078. {
  2079. if( szSystemPath[dwSize-1] != _TEXT('\\') && dwSize + 1 < SIZECHARS(szSystemPath) )
  2080. {
  2081. szSystemPath[dwSize++] = _TEXT('\\');
  2082. szSystemPath[dwSize] = 0;
  2083. }
  2084. }
  2085. #endif // #if defined(_WIN64)
  2086. if ( !pszServerName )
  2087. pszServerName = TEXT("");
  2088. dwSize = lstrlen(pszOption) + 1 + lstrlen(pszSourcePath) + 1 +
  2089. lstrlen(pszServerName) + 1 + lstrlen(pszInfFile) + 1;
  2090. dwSize *= sizeof(TCHAR);
  2091. //
  2092. // 20 for window handle in ASCII
  2093. //
  2094. dwSize += sizeof(szCmd) + 20;
  2095. pszSetupCmd = (LPTSTR) LocalAllocMem(dwSize);
  2096. if ( !pszSetupCmd ) {
  2097. dwLastError = GetLastError();
  2098. goto Cleanup;
  2099. }
  2100. dwSize = (lstrlen(szAppName) + lstrlen(szSystemPath) + 1) * sizeof(TCHAR);
  2101. pszSetupExe = LocalAllocMem( dwSize );
  2102. if ( !pszSetupExe ) {
  2103. dwLastError = GetLastError();
  2104. goto Cleanup;
  2105. }
  2106. //
  2107. // Now print the full path including SETUP.EXE
  2108. //
  2109. wsprintf(pszSetupExe, szAppName, szSystemPath);
  2110. //
  2111. // Now print the command to invoke setup with all the arguments
  2112. //
  2113. wsprintf(pszSetupCmd, szCmd, pszSourcePath, pszInfFile, pszOption,
  2114. pszServerName, hwnd);
  2115. //
  2116. // Invoke setup as a separate process
  2117. //
  2118. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  2119. StartupInfo.cb = sizeof(StartupInfo);
  2120. StartupInfo.wShowWindow = SW_SHOW;
  2121. if ( !CreateProcess(pszSetupExe, pszSetupCmd, NULL, NULL, FALSE, 0, NULL,
  2122. NULL, &StartupInfo, &ProcessInformation) ) {
  2123. dwLastError = GetLastError();
  2124. goto Cleanup;
  2125. }
  2126. EnableWindow (hwnd, FALSE);
  2127. while ( MsgWaitForMultipleObjects(1, (LPHANDLE)&ProcessInformation,
  2128. FALSE, (DWORD)-1, QS_ALLINPUT) ) {
  2129. //
  2130. // This message loop is a duplicate of main
  2131. // message loop with the exception of using
  2132. // PeekMessage instead of waiting inside of
  2133. // GetMessage. Process wait will actually
  2134. // be done in MsgWaitForMultipleObjects api.
  2135. //
  2136. while ( PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE)) {
  2137. TranslateMessage (&Msg);
  2138. DispatchMessage (&Msg);
  2139. }
  2140. }
  2141. //
  2142. // Did setup complete succesfully?
  2143. //
  2144. GetExitCodeProcess(ProcessInformation.hProcess, &dwLastError);
  2145. //
  2146. // Setup.exe magic return codes I found out by trial and error
  2147. //
  2148. if ( dwLastError == 1 )
  2149. SetLastError(dwLastError = ERROR_CANCELLED);
  2150. else if ( dwLastError == 2 )
  2151. SetLastError(dwLastError = ERROR_UNKNOWN_PRINTER_DRIVER);
  2152. else if ( dwLastError )
  2153. SetLastError(dwLastError=(DWORD)STG_E_UNKNOWN);
  2154. CloseHandle (ProcessInformation.hProcess);
  2155. CloseHandle (ProcessInformation.hThread);
  2156. EnableWindow (hwnd, TRUE);
  2157. SetForegroundWindow(hwnd);
  2158. Cleanup:
  2159. LocalFreeMem(pszSetupCmd);
  2160. LocalFreeMem(pszSetupExe);
  2161. return dwLastError;
  2162. }
  2163. DWORD
  2164. InstallNt3xDriver(
  2165. IN HWND hwnd,
  2166. IN LPCTSTR pszDriverName,
  2167. IN PLATFORM platform,
  2168. IN LPCTSTR pszServerName,
  2169. IN OUT LPTSTR pszSourcePath,
  2170. IN LPCTSTR pszDiskName,
  2171. IN DWORD dwInstallFlags
  2172. )
  2173. {
  2174. LPTSTR pszTitle = NULL, pszFormat, pszPrompt = NULL;
  2175. TCHAR szInfPath[MAX_PATH];
  2176. DWORD dwLastError;
  2177. //
  2178. // Build strings to use in the path dialog ..
  2179. //
  2180. pszFormat = GetStringFromRcFile(IDS_DRIVERS_FOR_PLATFORM);
  2181. if ( pszFormat ) {
  2182. pszTitle = LocalAllocMem((lstrlen(pszFormat) + lstrlen(pszDiskName) + 2)
  2183. * sizeof(*pszTitle));
  2184. if ( pszTitle )
  2185. wsprintf(pszTitle, pszFormat, pszDiskName);
  2186. }
  2187. //
  2188. // First see if the inf could be found on our default location
  2189. //
  2190. if ( MAX_PATH >
  2191. lstrlen(pszSourcePath) + lstrlen(TEXT("printer.inf")) + 1 ) {
  2192. lstrcpy(szInfPath, pszSourcePath);
  2193. lstrcat(szInfPath, TEXT("printer.inf"));
  2194. } else {
  2195. SetLastError(dwLastError=ERROR_INSUFFICIENT_BUFFER);
  2196. goto Cleanup;
  2197. }
  2198. if ( !FileExists(szInfPath) ) {
  2199. if ( dwInstallFlags & DRVINST_PROMPTLESS ) {
  2200. dwLastError = ERROR_FILE_NOT_FOUND;
  2201. goto Cleanup;
  2202. }
  2203. //
  2204. // Always just prompt with the CD-ROM path
  2205. //
  2206. GetCDRomDrive(pszSourcePath);
  2207. dwInstallFlags |= DRVINST_ALT_PLATFORM_INSTALL;
  2208. pszPrompt = GetStringFromRcFile(IDS_PROMPT_ALT_PLATFORM_DRIVER);
  2209. if (!pszPrompt)
  2210. {
  2211. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2212. goto Cleanup;
  2213. }
  2214. //
  2215. // Ask the user where the printer.inf, printer driver files reside
  2216. //
  2217. if ( !PSetupGetPathToSearch(hwnd, pszTitle, pszPrompt,
  2218. TEXT("printer.inf"), TRUE, pszSourcePath) ) {
  2219. dwLastError = GetLastError();
  2220. goto Cleanup;
  2221. }
  2222. if ( MAX_PATH >
  2223. lstrlen(pszSourcePath) + lstrlen(TEXT("printer.inf")) + 1 ) {
  2224. lstrcpy(szInfPath, pszSourcePath);
  2225. lstrcat(szInfPath, TEXT("printer.inf"));
  2226. } else {
  2227. SetLastError(dwLastError=ERROR_INSUFFICIENT_BUFFER);
  2228. goto Cleanup;
  2229. }
  2230. }
  2231. dwLastError = InvokeSetup(hwnd,
  2232. pszDriverName,
  2233. szInfPath,
  2234. pszSourcePath,
  2235. pszServerName);
  2236. Cleanup:
  2237. LocalFreeMem(pszPrompt);
  2238. LocalFreeMem(pszTitle);
  2239. LocalFreeMem(pszFormat);
  2240. CleanupScratchDirectory(pszServerName, platform);
  2241. return dwLastError;
  2242. }
  2243. //
  2244. // Paths where we search for the driver files
  2245. //
  2246. SPLPLATFORMINFO szPlatformExtn[] = {
  2247. { TEXT("\\alpha") },
  2248. { TEXT("\\i386") },
  2249. { TEXT("\\mips") },
  2250. { TEXT("\\ppc") },
  2251. { TEXT("") },
  2252. { TEXT("\\ia64") }
  2253. };
  2254. VOID
  2255. GetCDRomDrive(
  2256. TCHAR szDrive[5]
  2257. )
  2258. {
  2259. DWORD dwDrives;
  2260. INT iIndex;
  2261. szDrive[1] = TEXT(':');
  2262. szDrive[2] = TEXT('\\');
  2263. szDrive[3] = TEXT('\0');
  2264. dwDrives = GetLogicalDrives();
  2265. for ( iIndex = 0 ; iIndex < 26 ; ++iIndex )
  2266. if ( dwDrives & (1 << iIndex) ) {
  2267. szDrive[0] = TEXT('A') + iIndex;
  2268. if ( GetDriveType(szDrive) == DRIVE_CDROM )
  2269. goto Done;
  2270. }
  2271. szDrive[0] = TEXT('A');
  2272. Done:
  2273. return;
  2274. }
  2275. BOOL
  2276. BuildPathToPrompt(
  2277. IN HDEVINFO hDevInfo,
  2278. IN PPSETUP_LOCAL_DATA pLocalData,
  2279. IN PLATFORM platform,
  2280. IN DWORD dwVersion,
  2281. IN TCHAR szPathOut[MAX_PATH]
  2282. )
  2283. /*++
  2284. --*/
  2285. {
  2286. LPTSTR pszExtn = TEXT("");
  2287. DWORD dwLen;
  2288. //
  2289. // The CD we installed from OS can have only the following drivers:
  2290. // -- NT5 same platform drivers
  2291. // -- NT4 same platform drivers (only on server CD)
  2292. // -- Win9x drivers (only on server CD)
  2293. //
  2294. if ( (platform == MyPlatform && dwVersion >= 2) ||
  2295. platform == PlatformWin95 ) {
  2296. GetDriverPath(hDevInfo, pLocalData, szPathOut);
  2297. } else {
  2298. GetCDRomDrive(szPathOut);
  2299. }
  2300. if ( dwVersion >= dwThisMajorVersion && platform == MyPlatform )
  2301. return TRUE;
  2302. //
  2303. // append a backslash if needed
  2304. //
  2305. dwLen = lstrlen(szPathOut);
  2306. if (dwLen && (dwLen + 1 < MAX_PATH) && (szPathOut[dwLen-1] != TEXT('\\')))
  2307. {
  2308. szPathOut[dwLen] = TEXT('\\');
  2309. szPathOut[++dwLen] = 0;
  2310. }
  2311. switch (dwVersion) {
  2312. case 0:
  2313. if ( platform == PlatformWin95 )
  2314. pszExtn = TEXT("printers\\Win9X\\");
  2315. //
  2316. // For NT 3.51 and 3.1 we do not include drivers on CD, so
  2317. // nothing to add to the base path
  2318. //
  2319. case 1:
  2320. break;
  2321. case 2:
  2322. if ( platform == PlatformX86 ) // Alpha is now on the NT4.0 CD
  2323. pszExtn = TEXT("printers\\NT4\\");
  2324. break;
  2325. case 3:
  2326. break;
  2327. default:
  2328. ASSERT(dwVersion <= 3);
  2329. SetLastError(ERROR_INVALID_PARAMETER);
  2330. return FALSE;
  2331. }
  2332. if ( dwLen + lstrlen(pszExtn) + lstrlen(szPlatformExtn[platform].pszName) + 1
  2333. > MAX_PATH ) {
  2334. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2335. return FALSE;
  2336. }
  2337. lstrcat(szPathOut, pszExtn);
  2338. //
  2339. // Skip the leading \ of the platform extension as we have one already.
  2340. //
  2341. lstrcat(szPathOut, &(szPlatformExtn[platform].pszName[1]));
  2342. return TRUE;
  2343. }
  2344. DWORD
  2345. PSetupInstallPrinterDriver(
  2346. IN HDEVINFO hDevInfo,
  2347. IN PPSETUP_LOCAL_DATA pLocalData,
  2348. IN LPCTSTR pszDriverName,
  2349. IN PLATFORM platform,
  2350. IN DWORD dwVersion,
  2351. IN LPCTSTR pszServerName,
  2352. IN HWND hwnd,
  2353. IN LPCTSTR pszDiskName,
  2354. IN LPCTSTR pszSource OPTIONAL,
  2355. IN DWORD dwInstallFlags,
  2356. IN DWORD dwAddDrvFlags,
  2357. OUT LPTSTR *ppszNewDriverName
  2358. )
  2359. /*++
  2360. Routine Description:
  2361. Copies all the necessary driver files to the printer driver directory so
  2362. that an AddPrinterDriver call could be made.
  2363. Arguments:
  2364. hDevInfo : Handle to the printer class device information list
  2365. pLocalData : Gives information got by parsing the inf
  2366. pszDriverName : Printer driver name, used only if pLocalData is NULL
  2367. platform : Platform for which drivers need to be installed
  2368. dwVersion : Version of the driver to install
  2369. pszServerName : Server on which driver should be installed
  2370. hwnd : Parent windows handle for UI
  2371. pszDiskName : Disk name for prompting
  2372. pszSource : If provided this is a flat directory having all the files
  2373. dwAddDrvFlags : Flags for AddPrinterDriverEx
  2374. Return Value:
  2375. On succesfully copying files ERROR_SUCCESS, else the error code
  2376. --*/
  2377. {
  2378. BOOL bDeleteLocalData = pLocalData == NULL;
  2379. DWORD dwRet;
  2380. TCHAR szPath[MAX_PATH];
  2381. szPath[0] = 0;
  2382. if ( pszSource && !*pszSource )
  2383. pszSource = NULL;
  2384. if ( pLocalData )
  2385. {
  2386. ASSERT(pLocalData->signature == PSETUP_SIGNATURE && !pszDriverName);
  2387. }
  2388. else
  2389. {
  2390. ASSERT(pszDriverName && *pszDriverName);
  2391. }
  2392. //
  2393. // If FLATSHARE bit is set then a path should be given
  2394. //
  2395. ASSERT( (dwInstallFlags & DRVINST_FLATSHARE) == 0 || pszSource != NULL );
  2396. Retry:
  2397. //
  2398. // If a path is given use it. Otherwise if this is a driver for different
  2399. // version or platform then we determine the path, otherwise let SetupAPI determine the
  2400. // path.
  2401. //
  2402. if ( dwVersion != dwThisMajorVersion || platform != MyPlatform ) {
  2403. // If this is not an NT5 driver and we are asked to get it
  2404. // from the web, then just return.....
  2405. if ( pLocalData &&
  2406. ( pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ) )
  2407. return ERROR_SUCCESS;
  2408. if ( pszSource )
  2409. lstrcpy(szPath, pszSource);
  2410. else if ( !BuildPathToPrompt(hDevInfo,
  2411. pLocalData,
  2412. platform,
  2413. dwVersion,
  2414. szPath) ) {
  2415. if ( (dwRet = GetLastError()) == ERROR_SUCCESS )
  2416. dwRet = STG_E_UNKNOWN;
  2417. return dwRet;
  2418. }
  2419. }
  2420. //
  2421. // For Win95 drivers we need to parse their INFs,
  2422. // For Nt 3x driver we need to call setup
  2423. // For non native environemnt dirvers ask user for path
  2424. //
  2425. if ( platform == PlatformWin95 ) {
  2426. if ( pLocalData ) {
  2427. //
  2428. // Parse the inf as a X86 inf so that we can pick up any
  2429. // previous names entries and use them.
  2430. //
  2431. if ( !ParseInf(hDevInfo, pLocalData, PlatformX86,
  2432. pszServerName, dwInstallFlags) )
  2433. return GetLastError();
  2434. dwRet = InstallWin95Driver(hwnd,
  2435. pLocalData->DrvInfo.pszModelName,
  2436. pLocalData->DrvInfo.pszzPreviousNames,
  2437. (pLocalData->DrvInfo.Flags &
  2438. SDFLAG_PREVNAME_SECTION_FOUND),
  2439. pszServerName,
  2440. szPath,
  2441. pszDiskName,
  2442. dwInstallFlags,
  2443. dwAddDrvFlags);
  2444. } else {
  2445. dwRet = InstallWin95Driver(hwnd,
  2446. pszDriverName,
  2447. NULL,
  2448. TRUE, // Exact model name match only
  2449. pszServerName,
  2450. szPath,
  2451. pszDiskName,
  2452. dwInstallFlags,
  2453. dwAddDrvFlags);
  2454. }
  2455. } else if ( dwVersion < 2 ) {
  2456. dwRet = InstallNt3xDriver(hwnd,
  2457. pLocalData ?
  2458. pLocalData->DrvInfo.pszModelName :
  2459. pszDriverName,
  2460. platform,
  2461. pszServerName,
  2462. szPath,
  2463. pszDiskName,
  2464. dwInstallFlags);
  2465. } else if ( dwVersion != dwThisMajorVersion || platform != MyPlatform ) {
  2466. dwRet = InstallDriverAfterPromptingForInf(
  2467. platform,
  2468. pszServerName,
  2469. hwnd,
  2470. pLocalData ?
  2471. pLocalData->DrvInfo.pszModelName :
  2472. pszDriverName,
  2473. dwVersion,
  2474. szPath,
  2475. dwInstallFlags,
  2476. dwAddDrvFlags,
  2477. ppszNewDriverName);
  2478. } else if ( pLocalData &&
  2479. (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER) ) {
  2480. dwRet = PSetupInstallPrinterDriverFromTheWeb(hDevInfo,
  2481. pLocalData,
  2482. platform,
  2483. pszServerName,
  2484. &OsVersionInfo,
  2485. hwnd,
  2486. pszSource);
  2487. } else {
  2488. if ( !pLocalData )
  2489. {
  2490. pLocalData = PSetupDriverInfoFromName(hDevInfo, pszDriverName);
  2491. }
  2492. if ( pLocalData )
  2493. {
  2494. DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
  2495. dwRet = InstallDriverFromCurrentInf(hDevInfo,
  2496. pLocalData,
  2497. hwnd,
  2498. platform,
  2499. dwVersion,
  2500. pszServerName,
  2501. INVALID_HANDLE_VALUE,
  2502. NULL,
  2503. NULL,
  2504. 0,
  2505. pszSource,
  2506. dwInstallFlags,
  2507. dwAddDrvFlags,
  2508. NULL,
  2509. ppszNewDriverName,
  2510. &dwBlockingStatus);
  2511. if ((ppszNewDriverName && *ppszNewDriverName) &&
  2512. (dwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
  2513. {
  2514. dwRet = InstallReplacementDriver(hwnd,
  2515. pszServerName,
  2516. *ppszNewDriverName,
  2517. platform,
  2518. dwVersion,
  2519. dwInstallFlags,
  2520. dwAddDrvFlags);
  2521. }
  2522. else if (ppszNewDriverName && *ppszNewDriverName)
  2523. {
  2524. LocalFreeMem(*ppszNewDriverName);
  2525. *ppszNewDriverName = NULL;
  2526. }
  2527. }
  2528. else
  2529. {
  2530. dwRet = GetLastError();
  2531. }
  2532. }
  2533. if (
  2534. (dwRet == ERROR_EXE_MACHINE_TYPE_MISMATCH) &&
  2535. !(dwInstallFlags & DRVINST_PROMPTLESS)
  2536. )
  2537. {
  2538. int i;
  2539. TCHAR szTitle[256], szMsg[256];
  2540. LoadString(ghInst,
  2541. IDS_INVALID_DRIVER,
  2542. szTitle,
  2543. SIZECHARS(szTitle));
  2544. LoadString(ghInst,
  2545. IDS_WRONG_ARCHITECTURE,
  2546. szMsg,
  2547. SIZECHARS(szMsg));
  2548. i = MessageBox(hwnd,
  2549. szMsg,
  2550. szTitle,
  2551. MB_RETRYCANCEL | MB_ICONSTOP | MB_DEFBUTTON1 | MB_APPLMODAL);
  2552. if ( i == IDRETRY )
  2553. {
  2554. if ( bDeleteLocalData )
  2555. {
  2556. DestroyLocalData(pLocalData);
  2557. pLocalData = NULL;
  2558. }
  2559. goto Retry;
  2560. }
  2561. else
  2562. {
  2563. SetLastError(dwRet =ERROR_CANCELLED);
  2564. }
  2565. }
  2566. if ( bDeleteLocalData )
  2567. DestroyLocalData(pLocalData);
  2568. return dwRet;
  2569. }
  2570. //
  2571. // SCAN_INFO structure is used with SetupScanFileQueue to find dependent files
  2572. // and ICM files
  2573. //
  2574. typedef struct _SCAN_INFO {
  2575. BOOL bWin95;
  2576. PPSETUP_LOCAL_DATA pLocalData;
  2577. DWORD cchDependentFiles, cchICMFiles;
  2578. DWORD cchDriverDir, cchColorDir;
  2579. LPTSTR p1, p2;
  2580. TCHAR szDriverDir[MAX_PATH], szColorDir[MAX_PATH];
  2581. } SCAN_INFO, *PSCAN_INFO;
  2582. UINT
  2583. DriverInfoCallback(
  2584. IN PVOID pContext,
  2585. IN UINT Notification,
  2586. IN UINT_PTR Param1,
  2587. IN UINT_PTR Param2
  2588. )
  2589. /*++
  2590. Routine Description:
  2591. This callback routine is used with SetupScanFileQueue to findout the
  2592. dependent files and ICM files associated in an INF. All files going to the
  2593. printer driver directory are dependent files in DRIVER_INFO_6, and all
  2594. files goint to the Color directory are ICM files.
  2595. We use SetupScanFileQueue twice. We find the size of the buffers required
  2596. for the multi-sz fields in the first pass. After allocating buffers of size
  2597. found in first pass second pass is used to copy the strings and build the
  2598. multi-sz fields.
  2599. Arguments:
  2600. pContext : Gives the SCAN_INFO structure
  2601. Notification : Ignored
  2602. Param1 : Gives the target file name
  2603. Param2 : Ignored
  2604. Return Value:
  2605. Win32 error code
  2606. --*/
  2607. {
  2608. DWORD dwLen;
  2609. LPTSTR pszTarget = (LPTSTR)Param1, pszFileName;
  2610. PSCAN_INFO pScanInfo = (PSCAN_INFO)pContext;
  2611. LPDRIVER_INFO_6 pDriverInfo6;
  2612. pszFileName = FileNamePart(pszTarget);
  2613. if ( pszFileName )
  2614. {
  2615. dwLen = lstrlen(pszFileName) + 1;
  2616. if ( !lstrncmpi(pszTarget,
  2617. gpszSkipDir,
  2618. lstrlen( gpszSkipDir ) ) )
  2619. goto Done;
  2620. if ( !lstrncmpi(pszTarget,
  2621. pScanInfo->szDriverDir,
  2622. pScanInfo->cchDriverDir) ) {
  2623. pDriverInfo6 = &pScanInfo->pLocalData->InfInfo.DriverInfo6;
  2624. //
  2625. // On NT dependent file list will not include files appearing as
  2626. // other DRIVER_INFO_6 fields
  2627. //
  2628. if ( !pScanInfo->bWin95 &&
  2629. ( !lstrcmpi(pszFileName, pDriverInfo6->pDriverPath) ||
  2630. !lstrcmpi(pszFileName, pDriverInfo6->pConfigFile) ||
  2631. !lstrcmpi(pszFileName, pDriverInfo6->pDataFile) ||
  2632. ( pDriverInfo6->pHelpFile &&
  2633. !lstrcmpi(pszFileName, pDriverInfo6->pHelpFile))) )
  2634. goto Done;
  2635. //
  2636. // If pointer is not NULL this is pass 2
  2637. //
  2638. if ( pScanInfo->p1 ) {
  2639. lstrcpy(pScanInfo->p1, pszFileName);
  2640. pScanInfo->p1 += dwLen;
  2641. } else {
  2642. pScanInfo->cchDependentFiles += dwLen;
  2643. }
  2644. } else if ( !lstrncmpi(pszTarget,
  2645. pScanInfo->szColorDir,
  2646. pScanInfo->cchColorDir) ) {
  2647. //
  2648. // If pointer is not NULL this is pass 2
  2649. //
  2650. if ( pScanInfo->p2 ) {
  2651. lstrcpy(pScanInfo->p2, pszFileName);
  2652. pScanInfo->p2 += dwLen;
  2653. } else {
  2654. pScanInfo->cchICMFiles += dwLen;
  2655. }
  2656. }
  2657. }
  2658. else
  2659. {
  2660. return ERROR_INVALID_PARAMETER;
  2661. }
  2662. Done:
  2663. return NO_ERROR;
  2664. }
  2665. BOOL
  2666. InfGetDependentFilesAndICMFiles(
  2667. IN HDEVINFO hDevInfo,
  2668. IN HINF hInf,
  2669. IN BOOL bWin95,
  2670. IN OUT PPSETUP_LOCAL_DATA pLocalData,
  2671. IN PLATFORM platform,
  2672. IN LPCTSTR pszServerName,
  2673. IN DWORD dwInstallFlags,
  2674. IN LPCTSTR pszSectionNameWithExt,
  2675. IN OUT LPDWORD pcchSize
  2676. )
  2677. /*++
  2678. Routine Description:
  2679. Findout the dependent files for the DRIVER_INFO_6 and the ICM files
  2680. for the selected driver
  2681. This is done by simulating the install operation by create a setup
  2682. queue to do the install operations and scanning the queue to find out
  2683. where files are getting copied to
  2684. Dependent files are those getting copied to driver scratch directory
  2685. without including other DRIVER_INFO_6 fields like pDriverPath. For Win95
  2686. case all files getting copied to the driver directory are dependent files.
  2687. ICM files are those getting copied to the color directory
  2688. Arguments:
  2689. hInf : INF handle
  2690. bWin95 : TRUE if it is a Win95 INF
  2691. pLocalData : INF parsing information
  2692. pszSectionNameWithExt : Section name with extension for install
  2693. pcchSize : Size needed for DRIVER_INFO_6 and strings in it
  2694. Return Value:
  2695. TRUE on success, FALSE on error
  2696. --*/
  2697. {
  2698. BOOL bRet = FALSE;
  2699. DWORD dwResult;
  2700. SCAN_INFO ScanInfo;
  2701. HSPFILEQ ScanQueue = INVALID_HANDLE_VALUE;
  2702. LPTSTR ppszDepFiles = NULL,
  2703. pszzICMFiles = NULL;
  2704. SP_DEVINSTALL_PARAMS StoreDevInstallParams = {0};
  2705. SP_DEVINSTALL_PARAMS DevInstallParams = {0};
  2706. SP_ALTPLATFORM_INFO AltPlat_Info = {0};
  2707. OSVERSIONINFO OSVer = {0};
  2708. ScanInfo.p1 = ScanInfo.p2 = NULL;
  2709. ScanInfo.cchDependentFiles = ScanInfo.cchICMFiles = 0;
  2710. ScanInfo.cchColorDir = sizeof(ScanInfo.szColorDir);
  2711. ScanInfo.cchDriverDir = sizeof(ScanInfo.szDriverDir);
  2712. if ( !GetColorDirectory( pszServerName, ScanInfo.szColorDir, &ScanInfo.cchColorDir) ||
  2713. !GetSystemDirectory(ScanInfo.szDriverDir, ScanInfo.cchDriverDir) ) {
  2714. goto Cleanup;
  2715. }
  2716. //
  2717. // Set ScanInfo.cchColorDir to char count of ScanInfo.szColorDir without \0
  2718. //
  2719. ScanInfo.cchColorDir /= sizeof(TCHAR);
  2720. --ScanInfo.cchColorDir;
  2721. //
  2722. // Win95 INFs tell setup to copy the driver files to system32 directory
  2723. // NT INFs expect install programs to set the target using
  2724. // SetupSetDirectoryId
  2725. //
  2726. if ( bWin95 ) {
  2727. ScanInfo.cchDriverDir = lstrlen(ScanInfo.szDriverDir);
  2728. } else {
  2729. if ( !GetPrinterDriverDirectory((LPTSTR)pszServerName,
  2730. PlatformEnv[platform].pszName,
  2731. 1,
  2732. (LPBYTE)ScanInfo.szDriverDir,
  2733. ScanInfo.cchDriverDir,
  2734. &ScanInfo.cchDriverDir) )
  2735. goto Cleanup;
  2736. //
  2737. // Set ScanInfo.cchDriverDir to char count of ScanInfo.szDriverDir
  2738. // without \0
  2739. //
  2740. ScanInfo.cchDriverDir /= sizeof(TCHAR);
  2741. --ScanInfo.cchDriverDir;
  2742. }
  2743. //
  2744. // Inf MAY refer to another one (like layout.inf)
  2745. //
  2746. SetupOpenAppendInfFile(NULL, hInf, NULL);
  2747. ScanInfo.bWin95 = bWin95;
  2748. ScanInfo.pLocalData = pLocalData;
  2749. ScanQueue = SetupOpenFileQueue();
  2750. if (ScanQueue == INVALID_HANDLE_VALUE)
  2751. {
  2752. goto Cleanup;
  2753. }
  2754. DevInstallParams.cbSize = sizeof(DevInstallParams);
  2755. if(!SetupDiGetDeviceInstallParams(hDevInfo,
  2756. NULL,
  2757. &DevInstallParams))
  2758. {
  2759. goto Cleanup;
  2760. }
  2761. if(!GetOSVersion(pszServerName, &OSVer))
  2762. {
  2763. goto Cleanup;
  2764. }
  2765. //
  2766. // Save the current config...
  2767. //
  2768. memcpy(&StoreDevInstallParams, &DevInstallParams, sizeof(DevInstallParams));
  2769. DevInstallParams.FlagsEx |= DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
  2770. DevInstallParams.Flags |= DI_NOVCP;
  2771. DevInstallParams.FileQueue = ScanQueue;
  2772. AltPlat_Info.cbSize = sizeof(SP_ALTPLATFORM_INFO);
  2773. AltPlat_Info.MajorVersion = OSVer.dwMajorVersion;
  2774. AltPlat_Info.MinorVersion = OSVer.dwMinorVersion;
  2775. AltPlat_Info.Platform = PlatformArch[ platform ][OS_PLATFORM];
  2776. AltPlat_Info.ProcessorArchitecture = (WORD) PlatformArch[ platform ][PROCESSOR_ARCH];
  2777. AltPlat_Info.Reserved = 0;
  2778. AltPlat_Info.FirstValidatedMajorVersion = AltPlat_Info.MajorVersion;
  2779. AltPlat_Info.FirstValidatedMinorVersion = AltPlat_Info.MinorVersion;
  2780. if(!SetupDiSetDeviceInstallParams(hDevInfo,
  2781. NULL,
  2782. &DevInstallParams) ||
  2783. !SetupSetFileQueueAlternatePlatform(ScanQueue,
  2784. &AltPlat_Info,
  2785. NULL))
  2786. {
  2787. goto Cleanup;
  2788. }
  2789. //
  2790. // First pass using SetupScanFileQueue will find the sizes required
  2791. //
  2792. if ( !InstallAllInfSections( pLocalData,
  2793. platform,
  2794. pszServerName,
  2795. ScanQueue,
  2796. NULL,
  2797. dwInstallFlags,
  2798. hInf,
  2799. pszSectionNameWithExt ) ||
  2800. !SetupScanFileQueue(ScanQueue,
  2801. SPQ_SCAN_USE_CALLBACK,
  2802. 0,
  2803. DriverInfoCallback,
  2804. &ScanInfo,
  2805. &dwResult) ) {
  2806. goto Cleanup;
  2807. }
  2808. if ( ScanInfo.cchDependentFiles ) {
  2809. ++ScanInfo.cchDependentFiles;
  2810. ppszDepFiles = (LPTSTR) LocalAllocMem(ScanInfo.cchDependentFiles * sizeof(TCHAR));
  2811. if ( !ppszDepFiles )
  2812. goto Cleanup;
  2813. ScanInfo.p1 = ppszDepFiles;
  2814. }
  2815. if ( ScanInfo.cchICMFiles ) {
  2816. ++ScanInfo.cchICMFiles;
  2817. pszzICMFiles = (LPTSTR) LocalAllocMem(ScanInfo.cchICMFiles * sizeof(TCHAR));
  2818. if ( !pszzICMFiles )
  2819. goto Cleanup;
  2820. ScanInfo.p2 = pszzICMFiles;
  2821. }
  2822. //
  2823. // Second call to SetupScanFileQueue build the actual multi-sz fields
  2824. //
  2825. bRet = SetupScanFileQueue(ScanQueue,
  2826. SPQ_SCAN_USE_CALLBACK,
  2827. 0,
  2828. DriverInfoCallback,
  2829. &ScanInfo,
  2830. &dwResult);
  2831. Cleanup:
  2832. //
  2833. // Save the last error as it may get toasted by the following calls.
  2834. //
  2835. dwResult = GetLastError();
  2836. if ( ScanQueue != INVALID_HANDLE_VALUE )
  2837. {
  2838. DevInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
  2839. DevInstallParams.Flags &= ~DI_NOVCP;
  2840. DevInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  2841. if (!SetupDiSetDeviceInstallParams(hDevInfo, NULL, &DevInstallParams))
  2842. {
  2843. dwResult = (ERROR_SUCCESS == dwResult) ? GetLastError() : dwResult;
  2844. }
  2845. SetupCloseFileQueue(ScanQueue);
  2846. }
  2847. if(StoreDevInstallParams.cbSize == sizeof(DevInstallParams))
  2848. {
  2849. //
  2850. // Reset the HDEVINFO params.
  2851. //
  2852. SetupDiSetDeviceInstallParams(hDevInfo,
  2853. NULL,
  2854. &StoreDevInstallParams);
  2855. }
  2856. if ( bRet ) {
  2857. *pcchSize += ScanInfo.cchDependentFiles;
  2858. pLocalData->InfInfo.DriverInfo6.pDependentFiles = ppszDepFiles;
  2859. pLocalData->InfInfo.pszzICMFiles = pszzICMFiles;
  2860. } else {
  2861. LocalFreeMem(ppszDepFiles);
  2862. LocalFreeMem(pszzICMFiles);
  2863. }
  2864. SetLastError(dwResult);
  2865. return bRet;
  2866. }
  2867. VOID
  2868. DestroyCodedownload(
  2869. PCODEDOWNLOADINFO pCodeDownLoadInfo
  2870. )
  2871. {
  2872. if ( pCodeDownLoadInfo ) {
  2873. pCodeDownLoadInfo->pfnClose(pCodeDownLoadInfo->hConnection);
  2874. if ( pCodeDownLoadInfo->hModule )
  2875. FreeLibrary(pCodeDownLoadInfo->hModule);
  2876. LocalFreeMem(pCodeDownLoadInfo);
  2877. }
  2878. }
  2879. BOOL
  2880. InitCodedownload(
  2881. HWND hwnd
  2882. )
  2883. {
  2884. BOOL bRet = FALSE;
  2885. PCODEDOWNLOADINFO pCDMInfo = NULL;
  2886. EnterCriticalSection(&CDMCritSect);
  2887. // We already have a context & function pointers
  2888. // So reuse them...
  2889. if (gpCodeDownLoadInfo)
  2890. {
  2891. LeaveCriticalSection(&CDMCritSect);
  2892. return TRUE;
  2893. }
  2894. pCDMInfo = (PCODEDOWNLOADINFO) LocalAllocMem(sizeof(CODEDOWNLOADINFO));
  2895. if ( !pCDMInfo )
  2896. goto Cleanup;
  2897. pCDMInfo->hModule = LoadLibraryUsingFullPath(TEXT("cdm.dll"));
  2898. if ( !pCDMInfo->hModule )
  2899. goto Cleanup;
  2900. (FARPROC)pCDMInfo->pfnOpen = GetProcAddress(pCDMInfo->hModule,
  2901. "OpenCDMContext");
  2902. (FARPROC)pCDMInfo->pfnDownload = GetProcAddress(pCDMInfo->hModule,
  2903. "DownloadUpdatedFiles");
  2904. (FARPROC)pCDMInfo->pfnClose = GetProcAddress(pCDMInfo->hModule,
  2905. "CloseCDMContext");
  2906. bRet = pCDMInfo->pfnOpen &&
  2907. pCDMInfo->pfnDownload &&
  2908. pCDMInfo->pfnClose;
  2909. if ( bRet )
  2910. pCDMInfo->hConnection = pCDMInfo->pfnOpen(hwnd);
  2911. Cleanup:
  2912. if ( !bRet ||
  2913. ( pCDMInfo && !pCDMInfo->hConnection ) ) {
  2914. DestroyCodedownload(pCDMInfo);
  2915. pCDMInfo = NULL;
  2916. bRet = FALSE;
  2917. }
  2918. if (bRet)
  2919. gpCodeDownLoadInfo = pCDMInfo;
  2920. LeaveCriticalSection(&CDMCritSect);
  2921. return bRet;
  2922. }
  2923. DWORD
  2924. PSetupInstallPrinterDriverFromTheWeb(
  2925. IN HDEVINFO hDevInfo,
  2926. IN PPSETUP_LOCAL_DATA pLocalData,
  2927. IN PLATFORM platform,
  2928. IN LPCTSTR pszServerName,
  2929. IN LPOSVERSIONINFO pOsVersionInfo,
  2930. IN HWND hwnd,
  2931. IN LPCTSTR pszSource
  2932. )
  2933. {
  2934. BOOL bRet = FALSE;
  2935. DWORD dwLen, dwReturn = ERROR_SUCCESS;
  2936. UINT uNeeded;
  2937. TCHAR szSourceDir[MAX_PATH];
  2938. DOWNLOADINFO DownLoadInfo;
  2939. PPSETUP_LOCAL_DATA pNewLocalData = NULL;
  2940. INT clpFileBufferLength = 0;
  2941. INT cProviderNameLength = 0;
  2942. INT cManufacturerNameLength = 0;
  2943. INT cDriverNameLength = 0;
  2944. ZeroMemory(&DownLoadInfo, sizeof(DownLoadInfo));
  2945. if ( !gpCodeDownLoadInfo )
  2946. goto Cleanup;
  2947. DownLoadInfo.dwDownloadInfoSize = sizeof(DownLoadInfo);
  2948. DownLoadInfo.localid = lcid;
  2949. // dwLen = lstrlen( cszWebNTPrintPkg );
  2950. dwLen = lstrlen(pLocalData->DrvInfo.pszHardwareID);
  2951. //
  2952. // lpHardwareIDs is multi-sz
  2953. //
  2954. if ( !(DownLoadInfo.lpHardwareIDs = LocalAllocMem((dwLen + 2 ) * sizeof(TCHAR))) )
  2955. goto Cleanup;
  2956. // lstrcpy(DownLoadInfo.lpHardwareIDs, cszWebNTPrintPkg );
  2957. lstrcpy( (LPTSTR) DownLoadInfo.lpHardwareIDs, pLocalData->DrvInfo.pszHardwareID);
  2958. CopyMemory(&DownLoadInfo.OSVersionInfo,
  2959. pOsVersionInfo,
  2960. sizeof(OSVERSIONINFO));
  2961. // Assign the correct Processor Architecture to the download
  2962. DownLoadInfo.dwArchitecture = (WORD) PlatformArch[ platform ][PROCESSOR_ARCH];
  2963. DownLoadInfo.lpFile = NULL;
  2964. //
  2965. // Below we have to check if we have valid Provider, Manufacturer, and
  2966. // driver names and if this is the case then we have to prepare a
  2967. // MULTISZ including Provider, Manufacturer, and Driver Names,
  2968. // and to set a pointer to that MULTISZ into DownLoadInfo.lpFile
  2969. //
  2970. if (pLocalData->DrvInfo.pszProvider &&
  2971. pLocalData->DrvInfo.pszManufacturer &&
  2972. pLocalData->DrvInfo.pszModelName)
  2973. {
  2974. cProviderNameLength = lstrlen(pLocalData->DrvInfo.pszProvider);
  2975. if (cProviderNameLength)
  2976. {
  2977. cManufacturerNameLength = lstrlen(pLocalData->DrvInfo.pszManufacturer);
  2978. if (cManufacturerNameLength)
  2979. {
  2980. cDriverNameLength = lstrlen(pLocalData->DrvInfo.pszModelName);
  2981. if (cDriverNameLength)
  2982. {
  2983. clpFileBufferLength = cProviderNameLength + 1 +
  2984. cManufacturerNameLength + 1 +
  2985. cDriverNameLength + 1 +
  2986. 1;
  2987. DownLoadInfo.lpFile = (LPTSTR)LocalAllocMem(clpFileBufferLength * sizeof(TCHAR));
  2988. if (DownLoadInfo.lpFile)
  2989. {
  2990. lstrcpy( (LPTSTR)(DownLoadInfo.lpFile), (LPTSTR)(pLocalData->DrvInfo.pszProvider));
  2991. lstrcpy( (LPTSTR)(DownLoadInfo.lpFile + cProviderNameLength + 1), (LPTSTR)(pLocalData->DrvInfo.pszManufacturer));
  2992. lstrcpy( (LPTSTR)(DownLoadInfo.lpFile + cProviderNameLength + 1 + cManufacturerNameLength + 1), (LPTSTR)(pLocalData->DrvInfo.pszModelName));
  2993. }
  2994. }
  2995. }
  2996. }
  2997. }
  2998. if ( !gpCodeDownLoadInfo->pfnDownload(gpCodeDownLoadInfo->hConnection,
  2999. hwnd,
  3000. &DownLoadInfo,
  3001. szSourceDir,
  3002. SIZECHARS(szSourceDir),
  3003. &uNeeded) )
  3004. goto Cleanup;
  3005. // Now rework install data based on the actual INF
  3006. pNewLocalData = RebuildDeviceInfo( hDevInfo, pLocalData, szSourceDir );
  3007. if ( pNewLocalData == NULL )
  3008. goto Cleanup;
  3009. pNewLocalData->DrvInfo.Flags |= SDFLAG_CDM_DRIVER;
  3010. dwReturn = InstallDriverFromCurrentInf(hDevInfo,
  3011. pNewLocalData,
  3012. hwnd,
  3013. platform,
  3014. dwThisMajorVersion,
  3015. pszServerName,
  3016. INVALID_HANDLE_VALUE,
  3017. NULL,
  3018. NULL,
  3019. 0,
  3020. szSourceDir,
  3021. DRVINST_FLATSHARE | DRVINST_NO_WARNING_PROMPT,
  3022. APD_COPY_NEW_FILES,
  3023. NULL,
  3024. NULL,
  3025. NULL);
  3026. (VOID) DeleteAllFilesInDirectory(szSourceDir, TRUE);
  3027. if ( dwReturn == ERROR_SUCCESS )
  3028. bRet = TRUE;
  3029. Cleanup:
  3030. if ( pNewLocalData )
  3031. DestroyLocalData( pNewLocalData );
  3032. LocalFreeMem((PVOID)DownLoadInfo.lpHardwareIDs);
  3033. LocalFreeMem((PVOID)DownLoadInfo.lpFile);
  3034. CleanupScratchDirectory(pszServerName, platform);
  3035. if ( !bRet && ( dwReturn == ERROR_SUCCESS ) )
  3036. dwReturn = STG_E_UNKNOWN;
  3037. return dwReturn;
  3038. }
  3039. /*++
  3040. Routine Name:
  3041. PSetupInstallInboxDriverSilently
  3042. Routine Description:
  3043. This is used to install inbox drivers silently. The driver must exist in
  3044. ntprint.inf. The inf isn't passed in to make the only code that needs to know
  3045. about ntprint.inf reside in setup.
  3046. Arguments:
  3047. pszDriverName - The driver name that we want to install.
  3048. Return Value:
  3049. BOOL, Last error
  3050. --*/
  3051. DWORD
  3052. PSetupInstallInboxDriverSilently(
  3053. IN LPCTSTR pszDriverName
  3054. )
  3055. {
  3056. DWORD Status = ERROR_SUCCESS;
  3057. TCHAR szInfFile[MAX_PATH];
  3058. Status = pszDriverName ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
  3059. //
  3060. // Get the system directory.
  3061. //
  3062. if (Status == ERROR_SUCCESS)
  3063. {
  3064. Status = GetSystemWindowsDirectory(szInfFile, COUNTOF(szInfFile)) ? ERROR_SUCCESS : GetLastError();
  3065. }
  3066. if (Status == ERROR_SUCCESS)
  3067. {
  3068. Status = StrNCatBuff(szInfFile, COUNTOF(szInfFile), szInfFile, TEXT("\\"), szNtPrintInf, NULL);
  3069. }
  3070. if (Status == ERROR_SUCCESS)
  3071. {
  3072. Status = InstallDriverSilently(szInfFile, pszDriverName, NULL);
  3073. }
  3074. return Status;
  3075. }
  3076. /*++
  3077. Routine Name:
  3078. InstallDriverSilently
  3079. Routine Description:
  3080. Install the given printer driver from the given inf from the optional
  3081. source directory, do not pop up UI and fail if UI would be required.
  3082. Arguments:
  3083. pszInfFile - The inf file to install the driver from.
  3084. pszDriverName - The driver name.
  3085. pszSource - The source installation location.
  3086. Return Value:
  3087. BOOL, Last error
  3088. --*/
  3089. DWORD
  3090. InstallDriverSilently(
  3091. IN LPCTSTR pszInfFile,
  3092. IN LPCTSTR pszDriverName,
  3093. IN LPCTSTR pszSource
  3094. )
  3095. {
  3096. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  3097. DWORD dwInstallFlags = DRVINST_PROGRESSLESS | DRVINST_PROMPTLESS;
  3098. PPSETUP_LOCAL_DATA pData = NULL;
  3099. DWORD Status = ERROR_SUCCESS;
  3100. Status = pszInfFile && pszDriverName ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
  3101. //
  3102. // Ensure that setupapi does not throw any UI
  3103. //
  3104. SetupSetNonInteractiveMode(TRUE);
  3105. if (Status == ERROR_SUCCESS)
  3106. {
  3107. if ((hDevInfo = PSetupCreatePrinterDeviceInfoList(NULL)) != INVALID_HANDLE_VALUE &&
  3108. PSetupBuildDriversFromPath(hDevInfo, pszInfFile, TRUE) &&
  3109. PSetupPreSelectDriver(hDevInfo, NULL, pszDriverName) &&
  3110. (pData = BuildInternalData(hDevInfo, NULL)) != NULL &&
  3111. ParseInf(hDevInfo, pData, MyPlatform, NULL, dwInstallFlags))
  3112. {
  3113. Status = ERROR_SUCCESS;
  3114. }
  3115. else
  3116. {
  3117. //
  3118. // Ensure that if we have a failure the return is shown as such.
  3119. //
  3120. Status = GetLastError();
  3121. Status = Status == ERROR_SUCCESS ? ERROR_INVALID_DATA : Status;
  3122. }
  3123. }
  3124. if (Status == ERROR_SUCCESS)
  3125. {
  3126. //
  3127. // We don't want to launch a vendor setup entry, but vendor setup
  3128. // only gets launch after an AddPrinter call, which we're not doing - just adding drivers here.
  3129. // NOTE: For future if this included Queue creation we WILL have to handle this.
  3130. //
  3131. Status = PSetupInstallPrinterDriver(hDevInfo,
  3132. pData,
  3133. NULL,
  3134. MyPlatform,
  3135. dwThisMajorVersion,
  3136. NULL,
  3137. NULL,
  3138. NULL,
  3139. pszSource,
  3140. dwInstallFlags,
  3141. APD_COPY_NEW_FILES,
  3142. NULL);
  3143. }
  3144. //
  3145. // Switch on setupapi UI again
  3146. //
  3147. SetupSetNonInteractiveMode(FALSE);
  3148. if(pData != NULL)
  3149. {
  3150. PSetupDestroySelectedDriverInfo(pData);
  3151. }
  3152. //
  3153. // Release the driver setup parameter handle.
  3154. //
  3155. if(hDevInfo != INVALID_HANDLE_VALUE)
  3156. {
  3157. PSetupDestroyPrinterDeviceInfoList( hDevInfo );
  3158. }
  3159. return Status;
  3160. }