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.

2155 lines
64 KiB

  1. /*++
  2. Copyright (c) 1995-97 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Ntprint.c
  6. Abstract:
  7. Ntprint.dll main functions
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 02-Jan-1996
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "splcom.h"
  14. #include "regstr.h"
  15. HINSTANCE ghInst;
  16. DWORD dwThisMajorVersion = 3;
  17. PCODEDOWNLOADINFO gpCodeDownLoadInfo = NULL;
  18. HANDLE hPrintui = NULL;
  19. DWORD (*dwfnPnPInterface)(
  20. IN EPnPFunctionCode Function,
  21. IN TParameterBlock *pParameterBlock
  22. ) = NULL;
  23. TCHAR cszMicrosoft[] = TEXT("Microsoft");
  24. TCHAR cszPrinter[] = TEXT("Printer");
  25. TCHAR cszPortName[] = TEXT("PortName");
  26. TCHAR cszPnPKey[] = TEXT("PnPData");
  27. TCHAR cszDeviceInstanceId[] = TEXT("DeviceInstanceId");
  28. TCHAR cszHardwareID[] = TEXT("HardwareID");
  29. TCHAR cszManufacturer[] = TEXT("Manufacturer");
  30. TCHAR cszOEMUrl[] = TEXT("OEM URL");
  31. TCHAR cszProcessAlways[] = TEXT(".ProcessPerPnpInstance");
  32. TCHAR cszRunDll32[] = TEXT("rundll32.exe");
  33. TCHAR cszBestDriverInbox[] = TEXT("InstallInboxDriver");
  34. const DWORD dwFourMinutes = 240000;
  35. OSVERSIONINFO OsVersionInfo;
  36. LCID lcid;
  37. #define MAX_PRINTER_NAME MAX_PATH
  38. MODULE_DEBUG_INIT(DBG_WARN|DBG_ERROR, DBG_ERROR);
  39. BOOL
  40. DllMain(
  41. IN HINSTANCE hInst,
  42. IN DWORD dwReason,
  43. IN LPVOID lpRes
  44. )
  45. /*++
  46. Routine Description:
  47. Dll entry point.
  48. Arguments:
  49. Return Value:
  50. --*/
  51. {
  52. UNREFERENCED_PARAMETER(lpRes);
  53. switch( dwReason ){
  54. case DLL_PROCESS_ATTACH:
  55. ghInst = hInst;
  56. if( !bSplLibInit(NULL))
  57. {
  58. DBGMSG( DBG_WARN,
  59. ( "DllEntryPoint: Failed to init SplLib %d\n", GetLastError( )));
  60. return FALSE;
  61. }
  62. DisableThreadLibraryCalls(hInst);
  63. OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
  64. if ( !GetVersionEx(&OsVersionInfo) )
  65. return FALSE;
  66. lcid = GetUserDefaultLCID();
  67. InitializeCriticalSection(&CDMCritSect);
  68. InitializeCriticalSection(&SkipCritSect);
  69. if(IsInWow64())
  70. {
  71. //
  72. // 32-bit code running on Win64 -> set platform appropriately
  73. //
  74. MyPlatform = PlatformIA64;
  75. }
  76. break;
  77. case DLL_PROCESS_DETACH:
  78. if ( hPrintui )
  79. FreeLibrary(hPrintui);
  80. DeleteCriticalSection(&CDMCritSect);
  81. // Cleanup and CDM Context created by windows update.
  82. DestroyCodedownload( gpCodeDownLoadInfo );
  83. gpCodeDownLoadInfo = NULL;
  84. CleanupSkipDir();
  85. vSplLibFree();
  86. break;
  87. default:
  88. return FALSE;
  89. }
  90. return TRUE;
  91. }
  92. BOOL
  93. LoadAndInitializePrintui(
  94. VOID
  95. )
  96. /*++
  97. Routine Description:
  98. Check the refcount on printui, load it on 0 and increment the refcount.
  99. Arguments:
  100. None
  101. Return Value:
  102. TRUE on success, FALSE on error
  103. --*/
  104. {
  105. LPTSTR szDll =
  106. #ifdef UNICODE
  107. TEXT("printui.dll");
  108. #else
  109. TEXT("printuia.dll");
  110. #endif
  111. if ( hPrintui ) {
  112. return TRUE;
  113. }
  114. if ( hPrintui = LoadLibraryUsingFullPath(szDll) ) {
  115. if ( (FARPROC)dwfnPnPInterface = GetProcAddress(hPrintui,
  116. "PnPInterface") ) {
  117. return TRUE;
  118. } else {
  119. FreeLibrary(hPrintui);
  120. hPrintui = NULL;
  121. }
  122. }
  123. return FALSE;
  124. }
  125. BOOL
  126. PSetupAssociateICMProfiles(
  127. IN LPCTSTR pszzICMFiles,
  128. IN LPCTSTR pszPrinterName
  129. )
  130. /*++
  131. Routine Description:
  132. Install ICM color profiles for a printer driver and associate it with
  133. the printer name given
  134. Arguments:
  135. pszzICMFiles : Multi-sz field giving ICM profile names
  136. pszPrinterName : Printer name
  137. Return Value:
  138. None
  139. --*/
  140. {
  141. TCHAR szDir[MAX_PATH], *p;
  142. DWORD dwSize, dwNeeded;
  143. dwSize = SIZECHARS(szDir);
  144. dwNeeded = sizeof(szDir);
  145. if ( !GetColorDirectory(NULL, szDir, &dwNeeded) )
  146. return FALSE;
  147. dwNeeded /= sizeof(TCHAR);
  148. szDir[dwNeeded-1] = TEXT('\\');
  149. //
  150. // Install and assoicate each profiles from the multi-sz field
  151. //
  152. for ( p = (LPTSTR)pszzICMFiles; *p ; p += lstrlen(p) + 1 ) {
  153. if ( dwNeeded + lstrlen(p) + 1 > dwSize ) {
  154. ASSERT(dwNeeded + lstrlen(p) + 1 <= dwSize);
  155. continue;
  156. }
  157. lstrcpy(szDir + dwNeeded, p);
  158. //
  159. // We do not need the right server name here since ICM should send it
  160. // to the right server
  161. //
  162. if ( !AssociateColorProfileWithDevice(NULL, szDir, pszPrinterName) )
  163. return FALSE;
  164. }
  165. return TRUE;
  166. }
  167. DWORD
  168. GetPlugAndPlayInfo(
  169. IN HDEVINFO hDevInfo,
  170. IN PSP_DEVINFO_DATA pDevInfoData,
  171. IN PPSETUP_LOCAL_DATA pLocalData
  172. )
  173. /*++
  174. Routine Description:
  175. Get necessary PnP info LPT enumerator would have setup in the config
  176. manager registry
  177. Arguments:
  178. hDevInfo : Handle to the printer class device information list
  179. pDevInfoData : Pointer to the device info element for the printer
  180. pLocalData : Gives installation data
  181. Return Value:
  182. TRUE on success, FALSE else.
  183. --*/
  184. {
  185. HKEY hKey = NULL;
  186. TCHAR buf[MAX_PATH];
  187. DWORD dwType, dwSize, dwReturn;
  188. PNP_INFO PnPInfo;
  189. ASSERT( !(pLocalData->Flags & VALID_PNP_INFO) );
  190. ZeroMemory(&PnPInfo, sizeof(PnPInfo));
  191. //
  192. // Look in the devnode for the printer created to get the port name and
  193. // the device instance id
  194. //
  195. if ( dwReturn = CM_Open_DevNode_Key(pDevInfoData->DevInst, KEY_READ, 0,
  196. RegDisposition_OpenExisting, &hKey,
  197. CM_REGISTRY_HARDWARE) )
  198. goto Cleanup;
  199. dwSize = sizeof(buf);
  200. if ( dwReturn = RegQueryValueEx(hKey, cszPortName, NULL, &dwType,
  201. (LPBYTE)&buf, &dwSize) ) {
  202. if ( dwReturn == ERROR_FILE_NOT_FOUND )
  203. dwReturn = ERROR_UNKNOWN_PORT;
  204. goto Cleanup;
  205. }
  206. if ( !(PnPInfo.pszPortName = AllocStr(buf)) ) {
  207. dwReturn = GetLastError();
  208. goto Cleanup;
  209. }
  210. //
  211. // This can't be bigger than MAX_DEVICE_ID_LEN so it is ok
  212. //
  213. if ( !SetupDiGetDeviceInstanceId(hDevInfo,
  214. pDevInfoData,
  215. buf,
  216. SIZECHARS(buf),
  217. NULL) ) {
  218. dwReturn = GetLastError();
  219. goto Cleanup;
  220. }
  221. if ( !(PnPInfo.pszDeviceInstanceId = AllocStr(buf)) ) {
  222. dwReturn = GetLastError();
  223. goto Cleanup;
  224. }
  225. Cleanup:
  226. if ( dwReturn == ERROR_SUCCESS ) {
  227. CopyMemory(&pLocalData->PnPInfo, &PnPInfo, sizeof(PnPInfo));
  228. pLocalData->Flags |= VALID_PNP_INFO;
  229. } else {
  230. FreeStructurePointers((LPBYTE)&PnPInfo, PnPInfoOffsets, FALSE);
  231. }
  232. if ( hKey )
  233. RegCloseKey(hKey);
  234. return dwReturn;
  235. }
  236. BOOL
  237. PrinterGoingToPort(
  238. IN LPPRINTER_INFO_2 pPrinterInfo2,
  239. IN LPCTSTR pszPortName
  240. )
  241. /*++
  242. Routine Description:
  243. Find out if a printer is going to a port (it may go to other ports also)
  244. Arguments:
  245. pPrinterInfo2 : Gives the PRINTER_INFO_2 for the print queue
  246. pszPortName : The port name
  247. Return Value:
  248. If the print queue is going to the port TRUE, else FALSE
  249. --*/
  250. {
  251. LPTSTR pszStr1 = pPrinterInfo2->pPortName, pszStr2;
  252. //
  253. // Port names are returned comma separated by spooler; and there are blanks
  254. //
  255. while ( pszStr2 = lstrchr(pszStr1, sComma) ) {
  256. *pszStr2 = sZero;
  257. ++pszStr2;
  258. if ( !lstrcmpi(pszPortName, pszStr1) )
  259. return TRUE;
  260. pszStr1 = pszStr2;
  261. //
  262. // Skip spaces
  263. //
  264. while ( *pszStr1 == TEXT(' ') )
  265. ++pszStr1;
  266. }
  267. if ( !lstrcmpi(pszPortName, pszStr1) )
  268. return TRUE;
  269. return FALSE;
  270. }
  271. BOOL
  272. SetPnPInfoForPrinter(
  273. IN HANDLE hPrinter,
  274. IN LPCTSTR pszDeviceInstanceId,
  275. IN LPCTSTR pszHardwareID,
  276. IN LPCTSTR pszManufacturer,
  277. IN LPCTSTR pszOEMUrl
  278. )
  279. /*++
  280. Routine Description:
  281. Set registry values in the PnPInfo subkey
  282. Arguments:
  283. hPrinter : Printer handle
  284. pszDeviceInstanceId : DeviceInstance Id
  285. pszHardwareID : Device PnP or Compat Id
  286. pszManufacturer : Manufacturer (from the inf)
  287. pszOEMUrl : Manufacturer URL (from the inf)
  288. Return Value:
  289. TRUE on success, FALSE else.
  290. --*/
  291. {
  292. DWORD dwLastError = ERROR_SUCCESS;
  293. if ( pszDeviceInstanceId && *pszDeviceInstanceId)
  294. dwLastError = SetPrinterDataEx(hPrinter,
  295. cszPnPKey,
  296. cszDeviceInstanceId,
  297. REG_SZ,
  298. (LPBYTE)pszDeviceInstanceId,
  299. (lstrlen(pszDeviceInstanceId) + 1)
  300. * sizeof(TCHAR));
  301. if ( dwLastError == ERROR_SUCCESS && pszHardwareID && *pszHardwareID )
  302. dwLastError = SetPrinterDataEx(hPrinter,
  303. cszPnPKey,
  304. cszHardwareID,
  305. REG_SZ,
  306. (LPBYTE)pszHardwareID,
  307. (lstrlen(pszHardwareID) + 1)
  308. * sizeof(TCHAR));
  309. if ( dwLastError == ERROR_SUCCESS && pszManufacturer && *pszManufacturer )
  310. dwLastError = SetPrinterDataEx(hPrinter,
  311. cszPnPKey,
  312. cszManufacturer,
  313. REG_SZ,
  314. (LPBYTE)pszManufacturer,
  315. (lstrlen(pszManufacturer) + 1)
  316. * sizeof(TCHAR));
  317. if ( dwLastError == ERROR_SUCCESS && pszOEMUrl && *pszOEMUrl )
  318. dwLastError = SetPrinterDataEx(hPrinter,
  319. cszPnPKey,
  320. cszOEMUrl,
  321. REG_SZ,
  322. (LPBYTE)pszOEMUrl,
  323. (lstrlen(pszOEMUrl) + 1)
  324. * sizeof(TCHAR));
  325. if ( dwLastError ) {
  326. SetLastError(dwLastError);
  327. return FALSE;
  328. }
  329. return TRUE;
  330. }
  331. BOOL
  332. PrinterInfo2s(
  333. OUT LPPRINTER_INFO_2 *ppPI2,
  334. OUT LPDWORD pdwReturned
  335. )
  336. /*++
  337. Routine Description:
  338. Does an EnumPrinter and returns a list of PRINTER_INFO_2s of all local
  339. printers. Caller should free the pointer.
  340. Arguments:
  341. ppPI2 : Points to PRINTER_INFO_2s on return
  342. pdwReturned : Tells how many PRINTER_INFO_2s are returned
  343. Return Value:
  344. TRUE on success, FALSE else
  345. --*/
  346. {
  347. BOOL bRet = FALSE;
  348. DWORD dwNeeded = 0x1000;
  349. LPBYTE pBuf;
  350. if ( !(pBuf = LocalAllocMem(dwNeeded)) )
  351. goto Cleanup;
  352. if ( !EnumPrinters(PRINTER_ENUM_LOCAL,
  353. NULL,
  354. 2,
  355. pBuf,
  356. dwNeeded,
  357. &dwNeeded,
  358. pdwReturned) ) {
  359. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  360. goto Cleanup;
  361. LocalFreeMem(pBuf);
  362. if ( !(pBuf = LocalAllocMem(dwNeeded)) ||
  363. !EnumPrinters(PRINTER_ENUM_LOCAL,
  364. NULL,
  365. 2,
  366. pBuf,
  367. dwNeeded,
  368. &dwNeeded,
  369. pdwReturned) ) {
  370. goto Cleanup;
  371. }
  372. }
  373. bRet = TRUE;
  374. Cleanup:
  375. if ( bRet ) {
  376. *ppPI2 = (LPPRINTER_INFO_2)pBuf;
  377. } else {
  378. if ( pBuf )
  379. LocalFreeMem(pBuf);
  380. *ppPI2 = NULL;
  381. *pdwReturned = 0;
  382. }
  383. return bRet;
  384. }
  385. BOOL
  386. DuplicateDevice(
  387. IN PPSETUP_LOCAL_DATA pLocalData
  388. )
  389. /*++
  390. Routine Description:
  391. Find out if a PnP reported printer is already installed
  392. Arguments:
  393. pLocalData : Gives installation data
  394. Return Value:
  395. If the printer is already install TRUE, else FALSE
  396. --*/
  397. {
  398. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  399. LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
  400. BOOL bReturn = FALSE;
  401. DWORD dwReturned, dwNeeded;
  402. HANDLE hPrinter;
  403. LPTSTR pszDriverName = pLocalData->DrvInfo.pszModelName,
  404. pszPortName = pLocalData->PnPInfo.pszPortName;
  405. ASSERT( (pLocalData->Flags & VALID_PNP_INFO) &&
  406. (pLocalData->Flags & VALID_INF_INFO) );
  407. if ( !PrinterInfo2s(&p, &dwReturned) )
  408. goto Cleanup;
  409. //
  410. // If there is a local printer using the same driver and going to the
  411. // same port then it is a duplicate
  412. //
  413. for ( dwNeeded = 0, pPrinterInfo2 = p ;
  414. dwNeeded < dwReturned ;
  415. ++dwNeeded, pPrinterInfo2++ ) {
  416. if ( !lstrcmpi(pszDriverName, pPrinterInfo2->pDriverName) &&
  417. PrinterGoingToPort(pPrinterInfo2, pszPortName) )
  418. break; // for loop
  419. }
  420. if ( dwNeeded == dwReturned )
  421. goto Cleanup;
  422. bReturn = TRUE;
  423. if ( bReturn ) {
  424. if ( OpenPrinter(pPrinterInfo2->pPrinterName,
  425. &hPrinter,
  426. &PrinterDefault) ) {
  427. //
  428. // If it fails can't help
  429. //
  430. (VOID)SetPnPInfoForPrinter(hPrinter,
  431. pLocalData->PnPInfo.pszDeviceInstanceId,
  432. pLocalData->DrvInfo.pszHardwareID,
  433. pLocalData->DrvInfo.pszManufacturer,
  434. pLocalData->DrvInfo.pszOEMUrl);
  435. ClosePrinter(hPrinter);
  436. }
  437. }
  438. Cleanup:
  439. LocalFreeMem(p);
  440. return bReturn;
  441. }
  442. BOOL
  443. PrinterPnPDataSame(
  444. IN LPTSTR pszDeviceInstanceId,
  445. IN LPTSTR pszPrinterName
  446. )
  447. /*
  448. Routine Description:
  449. Find out if a PnP printer has been installed with different driver name.
  450. We need to associate the queue previously used with this new driver as
  451. pnp says it's the new best driver for the device.
  452. Arguments:
  453. pszDeviceInstanceId : Gives the device ID instance string of the pnped device.
  454. pszPrinterName : The name of the printer to compare the device instance ID to.
  455. Return Value:
  456. If printer's pnp data holds the same device instance ID as the passed ID returns TRUE, else FALSE.
  457. */
  458. {
  459. BOOL bRet = FALSE;
  460. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  461. HANDLE hPrinter;
  462. DWORD dwNeeded;
  463. TCHAR szPrnId[MAX_DEVICE_ID_LEN];
  464. if( pszPrinterName && pszDeviceInstanceId ) {
  465. if ( OpenPrinter(pszPrinterName,
  466. &hPrinter,
  467. &PrinterDefault) ) {
  468. if ( ERROR_SUCCESS == GetPrinterDataEx(hPrinter,
  469. cszPnPKey,
  470. cszDeviceInstanceId,
  471. &dwNeeded,
  472. (LPBYTE)szPrnId,
  473. sizeof(szPrnId),
  474. &dwNeeded) &&
  475. !lstrcmp(szPrnId, pszDeviceInstanceId) ) {
  476. bRet = TRUE;
  477. }
  478. ClosePrinter(hPrinter);
  479. }
  480. }
  481. return bRet;
  482. }
  483. BOOL
  484. NewDriverForInstalledDevice(
  485. IN PPSETUP_LOCAL_DATA pLocalData,
  486. OUT LPTSTR pszPrinterName
  487. )
  488. /*++
  489. Routine Description:
  490. Find out if a PnP printer has been installed with different driver name.
  491. We need to associate the queue previously used with this new driver as
  492. pnp says it's the new best driver for the device.
  493. Arguments:
  494. pLocalData : Gives installation data
  495. pszPrinterName : Gives the printer name to return and use.
  496. Return Value:
  497. If a printer is already installed which uses another driver TRUE, else FALSE
  498. --*/
  499. {
  500. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  501. LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
  502. BOOL bReturn = FALSE;
  503. DWORD dwReturned, dwNeeded;
  504. HANDLE hPrinter;
  505. LPTSTR pszPortName = pLocalData->PnPInfo.pszPortName;
  506. LPTSTR pszDeviceInstanceId = pLocalData->PnPInfo.pszDeviceInstanceId;
  507. ASSERT( (pLocalData->Flags & VALID_PNP_INFO) &&
  508. (pLocalData->Flags & VALID_INF_INFO) );
  509. if ( !PrinterInfo2s(&p, &dwReturned) )
  510. goto Cleanup;
  511. //
  512. // If there is a printer going to that same port and with the same pnp
  513. // info, then it has been reinstalled with a newer driver.
  514. //
  515. for ( dwNeeded = 0, pPrinterInfo2 = p ;
  516. dwNeeded < dwReturned ;
  517. ++dwNeeded, pPrinterInfo2++ ) {
  518. if ( PrinterGoingToPort(pPrinterInfo2, pszPortName) &&
  519. PrinterPnPDataSame(pszDeviceInstanceId, pPrinterInfo2->pPrinterName) ) {
  520. break; // for loop
  521. }
  522. }
  523. if ( dwNeeded == dwReturned ) {
  524. //
  525. // We didn't find anything...
  526. //
  527. goto Cleanup;
  528. }
  529. if ( OpenPrinter(pPrinterInfo2->pPrinterName,
  530. &hPrinter,
  531. &PrinterDefault) ) {
  532. pPrinterInfo2->pDriverName = pLocalData->DrvInfo.pszModelName;
  533. if( SetPrinter( hPrinter, 2, (LPBYTE)pPrinterInfo2, 0 ) ) {
  534. lstrcpyn( pszPrinterName, pPrinterInfo2->pPrinterName, MAX_PRINTER_NAME );
  535. bReturn = TRUE;
  536. }
  537. ClosePrinter(hPrinter);
  538. }
  539. Cleanup:
  540. if( p ) {
  541. LocalFreeMem(p);
  542. }
  543. return bReturn;
  544. }
  545. VOID
  546. CallVendorDll(
  547. IN PPSETUP_LOCAL_DATA pLocalData,
  548. IN LPCTSTR pszPrinterName,
  549. IN HWND hwnd
  550. )
  551. /*++
  552. Routine Description:
  553. A VendorSetup was specified in the INF. Call the dll with the name of the
  554. printer just created
  555. Arguments:
  556. pLocalData : Gives installation data
  557. pszPrinterName : Name of the printer which got installed
  558. hwnd : Window handle for any UI
  559. Return Value:
  560. If the printer is already install TRUE, else FALSE
  561. --*/
  562. {
  563. TCHAR szCmd[MAX_PATH];
  564. SHELLEXECUTEINFO ShellExecInfo;
  565. TCHAR *pszExecutable = NULL;
  566. TCHAR *pszParams = NULL;
  567. LPTSTR pszVendorSetup = pLocalData->InfInfo.pszVendorSetup;
  568. INT cParamsLength = 0;
  569. INT cLength = 0;
  570. if (IsSystemSetupInProgress())
  571. {
  572. goto Cleanup;
  573. }
  574. ASSERT(pLocalData->Flags & VALID_INF_INFO);
  575. cParamsLength = lstrlen(pszVendorSetup) + lstrlen(pszPrinterName) + 4;
  576. pszParams = LocalAllocMem(cParamsLength * sizeof(TCHAR));
  577. if (!pszParams)
  578. {
  579. goto Cleanup;
  580. }
  581. wsprintf(pszParams, TEXT("%s \"%s\""), pszVendorSetup, pszPrinterName);
  582. GetSystemDirectory( szCmd, SIZECHARS(szCmd) );
  583. cLength = lstrlen( szCmd ) + lstrlen( cszRunDll32 ) + 2;
  584. pszExecutable = LocalAllocMem( cLength * sizeof(TCHAR) );
  585. if (!pszExecutable)
  586. {
  587. goto Cleanup;
  588. }
  589. lstrcpy(pszExecutable, szCmd);
  590. cLength = lstrlen( pszExecutable );
  591. if (*(pszExecutable + (cLength - 1)) != TEXT('\\'))
  592. {
  593. lstrcat( pszExecutable, TEXT("\\"));
  594. }
  595. lstrcat(pszExecutable, cszRunDll32 );
  596. ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo));
  597. ShellExecInfo.cbSize = sizeof(ShellExecInfo);
  598. ShellExecInfo.hwnd = hwnd;
  599. ShellExecInfo.lpFile = pszExecutable;
  600. ShellExecInfo.nShow = SW_SHOWNORMAL;
  601. ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  602. ShellExecInfo.lpParameters = pszParams;
  603. //
  604. // Call run32dll and wait for the vendor dll to return before proceeding
  605. //
  606. if ( ShellExecuteEx(&ShellExecInfo) && ShellExecInfo.hProcess ) {
  607. WaitForSingleObject(ShellExecInfo.hProcess, dwFourMinutes );
  608. CloseHandle(ShellExecInfo.hProcess);
  609. }
  610. Cleanup:
  611. LocalFreeMem(pszExecutable);
  612. LocalFreeMem(pszParams);
  613. return;
  614. }
  615. BOOL
  616. SetPackageName (
  617. IN HDEVINFO hDevInfo,
  618. IN PSP_DEVINFO_DATA pDevInfoData
  619. )
  620. {
  621. SP_WINDOWSUPDATE_PARAMS WinUpParams;
  622. //
  623. // Get current SelectDevice parameters, and then set the fields
  624. // we wanted changed from default
  625. //
  626. WinUpParams.ClassInstallHeader.cbSize = sizeof(WinUpParams.ClassInstallHeader);
  627. WinUpParams.ClassInstallHeader.InstallFunction = DIF_GETWINDOWSUPDATEINFO;
  628. if ( !SetupDiGetClassInstallParams( hDevInfo,
  629. pDevInfoData,
  630. &WinUpParams.ClassInstallHeader,
  631. sizeof(WinUpParams),
  632. NULL) )
  633. {
  634. return FALSE;
  635. }
  636. lstrcpy( WinUpParams.PackageId, cszWebNTPrintPkg );
  637. WinUpParams.CDMContext = gpCodeDownLoadInfo->hConnection;
  638. if ( !SetupDiSetClassInstallParams( hDevInfo,
  639. pDevInfoData,
  640. (PSP_CLASSINSTALL_HEADER) &WinUpParams,
  641. sizeof(WinUpParams) ) )
  642. {
  643. return FALSE;
  644. }
  645. return TRUE;
  646. }
  647. DWORD
  648. ProcessPerInstanceAddRegSections(
  649. IN HDEVINFO hDevInfo,
  650. IN PSP_DEVINFO_DATA pDevInfoData,
  651. IN PPSETUP_LOCAL_DATA pLocalData
  652. )
  653. /*++
  654. Routine Description:
  655. Processes the AddReg section for this printer that is marked as to process per instance of this
  656. device
  657. Arguments:
  658. hDevInfo : Handle to the printer class device information list
  659. pDevInfoData : Pointer to the device info element for the printer
  660. pLocalData : Pointer to the print setup local data
  661. Return Value:
  662. Win 32 error code
  663. --*/
  664. {
  665. DWORD dwReturn;
  666. HINF hPrinterInf;
  667. TCHAR *pszSection = NULL;
  668. dwReturn = StrCatAlloc(&pszSection, pLocalData->InfInfo.pszInstallSection, cszProcessAlways, NULL);
  669. if (dwReturn != ERROR_SUCCESS)
  670. {
  671. goto Done;
  672. }
  673. hPrinterInf = SetupOpenInfFile(pLocalData->DrvInfo.pszInfName,
  674. NULL,
  675. INF_STYLE_WIN4,
  676. NULL);
  677. if (hPrinterInf != INVALID_HANDLE_VALUE)
  678. {
  679. //
  680. // Ignore return value - it doesn't make much sense to fail the install here
  681. //
  682. if (!SetupInstallFromInfSection(NULL,
  683. hPrinterInf,
  684. pszSection,
  685. SPINST_REGISTRY,
  686. NULL,
  687. NULL,
  688. 0,
  689. NULL,
  690. NULL,
  691. hDevInfo,
  692. pDevInfoData))
  693. {
  694. DBGMSG( DBG_ERROR,("ProcessPerInstanceAddRegSections: SetupInstallFromInfSection failed: %d\n", GetLastError( )));
  695. }
  696. SetupCloseInfFile(hPrinterInf);
  697. }
  698. else
  699. {
  700. DBGMSG( DBG_ERROR,("ProcessPerInstanceAddRegSections: SetupOpenInfFile %s failed: %d\n", pLocalData->DrvInfo.pszInfName, GetLastError( )));
  701. }
  702. Done:
  703. FreeSplMem(pszSection);
  704. return dwReturn;
  705. }
  706. DWORD
  707. ClassInstall_SelectDevice(
  708. IN HDEVINFO hDevInfo,
  709. IN PSP_DEVINFO_DATA pDevInfoData
  710. )
  711. /*++
  712. Routine Description:
  713. This function handles the class installer entry point for DIF_SELECTDEVICE
  714. Arguments:
  715. hDevInfo : Handle to the printer class device information list
  716. pDevInfoData : Pointer to the device info element for the printer
  717. Return Value:
  718. Win 32 error code
  719. --*/
  720. {
  721. return SetSelectDevParams(hDevInfo, pDevInfoData, FALSE, NULL) &&
  722. SetDevInstallParams(hDevInfo, pDevInfoData, NULL)
  723. ? ERROR_DI_DO_DEFAULT
  724. : GetLastError();
  725. }
  726. DWORD
  727. ClassInstall_InstallDevice(
  728. IN HDEVINFO hDevInfo,
  729. IN PSP_DEVINFO_DATA pDevInfoData,
  730. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  731. )
  732. /*++
  733. Routine Description:
  734. This function handles the class installer entry point for DIF_INSTALLDEVICE
  735. Arguments:
  736. hDevInfo : Handle to the printer class device information list
  737. pDevInfoData : Pointer to the device info element for the printer
  738. pDevInstallParam : Pointer to the device install structure
  739. Return Value:
  740. Win 32 error code
  741. --*/
  742. {
  743. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  744. PPSETUP_LOCAL_DATA pLocalData = NULL;
  745. TPrinterInstall TPrnInstData;
  746. TParameterBlock TParm;
  747. TCHAR szPrinterName[MAX_PRINTER_NAME];
  748. HANDLE hPrinter = NULL;
  749. DWORD dwReturn;
  750. SP_DRVINFO_DATA DrvInfoData = {0};
  751. if ( !pDevInfoData ) {
  752. return ERROR_INVALID_PARAMETER;
  753. }
  754. //
  755. // check whether this is the NULL driver - we get that request if we fail DIF_ALLOW_INSTALL.
  756. // If the DI_FLAGSEX_SETFAILEDINSTALL we must succeed. In this case call the default class installer
  757. // to do it's thing, then set the REINSTALL flag on the devnode so on first boot
  758. // they will try to reinstall the device
  759. //
  760. DrvInfoData.cbSize = sizeof(DrvInfoData);
  761. if (
  762. !SetupDiGetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData) &&
  763. (ERROR_NO_DRIVER_SELECTED == GetLastError()) &&
  764. IsSystemSetupInProgress() &&
  765. (pDevInstallParams->FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
  766. )
  767. {
  768. DWORD dwConfigFlags = 0, cbRequiredSize =0, dwDataType = REG_DWORD;
  769. //
  770. // run the default class installer
  771. //
  772. if (SetupDiInstallDevice(hDevInfo, pDevInfoData))
  773. {
  774. //
  775. // now set the appropriate config flags
  776. //
  777. dwReturn = SetupDiGetDeviceRegistryProperty(hDevInfo,
  778. pDevInfoData,
  779. SPDRP_CONFIGFLAGS,
  780. &dwDataType,
  781. (PBYTE) &dwConfigFlags,
  782. sizeof(dwConfigFlags),
  783. &cbRequiredSize) ?
  784. (REG_DWORD == dwDataType ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER)
  785. : GetLastError();
  786. if (ERROR_SUCCESS == dwReturn)
  787. {
  788. dwConfigFlags |= CONFIGFLAG_REINSTALL; // to make setupapi reinstall this on first boot
  789. dwConfigFlags &= ~CONFIGFLAG_FAILEDINSTALL; // per LonnyM's request in order not to screw up anything setupapi-internal
  790. dwReturn = SetupDiSetDeviceRegistryProperty(hDevInfo,
  791. pDevInfoData,
  792. SPDRP_CONFIGFLAGS,
  793. (PBYTE) &dwConfigFlags,
  794. sizeof(dwConfigFlags)) ?
  795. ERROR_SUCCESS : GetLastError();
  796. }
  797. }
  798. else
  799. {
  800. dwReturn = GetLastError();
  801. }
  802. //
  803. // don't go through the normal cleanup path that would munge the error code to
  804. // DI_DO_DEFAULT - we have already called the default class installer and it would
  805. // clean out the flags we've set.
  806. //
  807. return dwReturn;
  808. }
  809. //
  810. //
  811. // Parse the inf and also get PnP info from config manger registry
  812. //
  813. if ( !(pLocalData = BuildInternalData(hDevInfo, pDevInfoData)) ||
  814. !ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0) ) {
  815. dwReturn = GetLastError();
  816. goto Done;
  817. }
  818. if ( dwReturn = ProcessPerInstanceAddRegSections(hDevInfo, pDevInfoData, pLocalData)) {
  819. goto Done;
  820. }
  821. if ( dwReturn = GetPlugAndPlayInfo(hDevInfo, pDevInfoData, pLocalData) ) {
  822. goto Done;
  823. }
  824. //
  825. // Install printer driver if FORCECOPY is set or if the driver is not
  826. // available and it is ok to put up ui
  827. //
  828. if ( (pDevInstallParams->Flags & DI_FORCECOPY) ||
  829. DRIVER_MODEL_INSTALLED_AND_IDENTICAL !=
  830. PSetupIsTheDriverFoundInInfInstalled(NULL,
  831. pLocalData,
  832. MyPlatform,
  833. KERNEL_MODE_DRIVER_VERSION) ) {
  834. if ( pDevInstallParams->Flags & DI_NOFILECOPY ) {
  835. dwReturn = ERROR_UNKNOWN_PRINTER_DRIVER;
  836. goto Done;
  837. }
  838. dwReturn = InstallDriverFromCurrentInf(hDevInfo,
  839. pLocalData,
  840. pDevInstallParams->hwndParent,
  841. MyPlatform,
  842. dwThisMajorVersion,
  843. NULL,
  844. pDevInstallParams->FileQueue,
  845. pDevInstallParams->InstallMsgHandlerContext,
  846. pDevInstallParams->InstallMsgHandler,
  847. pDevInstallParams->Flags,
  848. NULL,
  849. DRVINST_NO_WARNING_PROMPT,
  850. APD_COPY_NEW_FILES,
  851. NULL,
  852. NULL,
  853. NULL);
  854. if ( dwReturn != ERROR_SUCCESS )
  855. goto Done;
  856. }
  857. //
  858. // If the printer is already installed nothing to do
  859. //
  860. if ( DuplicateDevice(pLocalData) ) {
  861. dwReturn = ERROR_SUCCESS;
  862. goto Done;
  863. }
  864. if( !NewDriverForInstalledDevice(pLocalData, (LPTSTR)&szPrinterName) ) {
  865. if ( !LoadAndInitializePrintui() ) {
  866. dwReturn = GetLastError();
  867. goto Done;
  868. }
  869. TPrnInstData.cbSize = sizeof(TPrinterInstall);
  870. TPrnInstData.pszServerName = NULL;
  871. TPrnInstData.pszDriverName = pLocalData->DrvInfo.pszModelName;
  872. TPrnInstData.pszPortName = pLocalData->PnPInfo.pszPortName;
  873. TPrnInstData.pszPrinterNameBuffer = szPrinterName;
  874. TPrnInstData.cchPrinterName = SIZECHARS(szPrinterName);
  875. TParm.pPrinterInstall = &TPrnInstData;
  876. if ( dwReturn = dwfnPnPInterface(kPrinterInstall, &TParm) )
  877. goto Done;
  878. } else {
  879. dwReturn = ERROR_SUCCESS;
  880. }
  881. //
  882. // Set the device instance id with spooler
  883. //
  884. if ( OpenPrinter(szPrinterName, &hPrinter, &PrinterDefault) ) {
  885. (VOID)SetPnPInfoForPrinter(hPrinter,
  886. pLocalData->PnPInfo.pszDeviceInstanceId,
  887. pLocalData->DrvInfo.pszHardwareID,
  888. pLocalData->DrvInfo.pszManufacturer,
  889. pLocalData->DrvInfo.pszOEMUrl);
  890. }
  891. //
  892. // If a vendor dll is given we need to call into it
  893. //
  894. if ( pLocalData->InfInfo.pszVendorSetup )
  895. CallVendorDll(pLocalData, szPrinterName, pDevInstallParams->hwndParent);
  896. //
  897. // If ICM files need to installed and associated do it
  898. //
  899. if ( pLocalData->InfInfo.pszzICMFiles )
  900. (VOID)PSetupAssociateICMProfiles(pLocalData->InfInfo.pszzICMFiles,
  901. szPrinterName);
  902. Done:
  903. if ( hPrinter )
  904. ClosePrinter(hPrinter);
  905. DestroyLocalData(pLocalData);
  906. //
  907. // On everything going smoothly we want setup to whatever it needs to do
  908. // to make PnP system happy so that the devnode is marked as configured
  909. // But we do not want them to copy files again
  910. //
  911. if ( dwReturn == ERROR_SUCCESS ) {
  912. pDevInstallParams->Flags |= DI_NOFILECOPY;
  913. SetupDiSetDeviceInstallParams(hDevInfo,
  914. pDevInfoData,
  915. pDevInstallParams);
  916. dwReturn = ERROR_DI_DO_DEFAULT;
  917. }
  918. return dwReturn;
  919. }
  920. DWORD
  921. ClassInstall_DestroyWizardData(
  922. IN HDEVINFO hDevInfo,
  923. IN PSP_DEVINFO_DATA pDevInfoData,
  924. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  925. )
  926. /*++
  927. Routine Description:
  928. This function handles the class installer entry point for DIF_DESTROYWIZARDDATA
  929. Arguments:
  930. hDevInfo : Handle to the printer class device information list
  931. pDevInfoData : Pointer to the device info element for the printer
  932. pDevInstallParam : Pointer to the device install structure
  933. Return Value:
  934. Win 32 error code
  935. --*/
  936. {
  937. SP_INSTALLWIZARD_DATA InstallWizData;
  938. TDestroyWizard TDestroyWsd;
  939. TParameterBlock TParams;
  940. DWORD dwReturn;
  941. ASSERT(hPrintui && dwfnPnPInterface);
  942. InstallWizData.ClassInstallHeader.cbSize
  943. = sizeof(InstallWizData.ClassInstallHeader);
  944. if ( !SetupDiGetClassInstallParams(hDevInfo,
  945. pDevInfoData,
  946. &InstallWizData.ClassInstallHeader,
  947. sizeof(InstallWizData),
  948. NULL) ||
  949. InstallWizData.ClassInstallHeader.InstallFunction != DIF_DESTROYWIZARDDATA ) {
  950. return ERROR_DI_DO_DEFAULT;
  951. }
  952. TDestroyWsd.cbSize = sizeof(TDestroyWsd);
  953. TDestroyWsd.pszServerName = NULL;
  954. TDestroyWsd.pData = &InstallWizData;
  955. TDestroyWsd.pReferenceData = (PVOID)pDevInstallParams->ClassInstallReserved;
  956. TParams.pDestroyWizard = &TDestroyWsd;
  957. dwReturn = dwfnPnPInterface(kDestroyWizardData, &TParams);
  958. return dwReturn;
  959. }
  960. DWORD
  961. ClassInstall_InstallWizard(
  962. IN HDEVINFO hDevInfo,
  963. IN PSP_DEVINFO_DATA pDevInfoData,
  964. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  965. )
  966. /*++
  967. Routine Description:
  968. This function handles the class installer entry point for DIF_INSTALLWIZARD
  969. Arguments:
  970. hDevInfo : Handle to the printer class device information list
  971. pDevInfoData : Pointer to the device info element for the printer
  972. pDevInstallParam : Pointer to the device install structure
  973. Return Value:
  974. Win 32 error code
  975. --*/
  976. {
  977. SP_INSTALLWIZARD_DATA InstallWizData;
  978. TInstallWizard TInstWzd;
  979. TParameterBlock TParams;
  980. DWORD dwReturn;
  981. InstallWizData.ClassInstallHeader.cbSize
  982. = sizeof(InstallWizData.ClassInstallHeader);
  983. if ( !SetupDiGetClassInstallParams(hDevInfo,
  984. pDevInfoData,
  985. &InstallWizData.ClassInstallHeader,
  986. sizeof(InstallWizData),
  987. NULL) ||
  988. InstallWizData.ClassInstallHeader.InstallFunction != DIF_INSTALLWIZARD ) {
  989. return ERROR_DI_DO_DEFAULT;
  990. }
  991. if ( !LoadAndInitializePrintui() )
  992. return GetLastError();
  993. TInstWzd.cbSize = sizeof(TInstWzd);
  994. TInstWzd.pszServerName = NULL;
  995. TInstWzd.pData = &InstallWizData;
  996. TInstWzd.pReferenceData = (PVOID)pDevInstallParams->ClassInstallReserved;
  997. TParams.pInstallWizard = &TInstWzd;
  998. if ( dwReturn = dwfnPnPInterface(kInstallWizard, &TParams) )
  999. goto Cleanup;
  1000. if ( !SetupDiSetClassInstallParams(hDevInfo,
  1001. pDevInfoData,
  1002. &InstallWizData.ClassInstallHeader,
  1003. sizeof(InstallWizData)) ) {
  1004. dwReturn = GetLastError();
  1005. }
  1006. pDevInstallParams->ClassInstallReserved = (LPARAM)TInstWzd.pReferenceData;
  1007. if ( !SetupDiSetDeviceInstallParams(hDevInfo,
  1008. pDevInfoData,
  1009. pDevInstallParams) ) {
  1010. dwReturn = GetLastError();
  1011. }
  1012. Cleanup:
  1013. if ( dwReturn != ERROR_SUCCESS ) {
  1014. ClassInstall_DestroyWizardData(hDevInfo,
  1015. pDevInfoData,
  1016. pDevInstallParams);
  1017. }
  1018. return dwReturn;
  1019. }
  1020. DWORD
  1021. ClassInstall_InstallDeviceFiles(
  1022. IN HDEVINFO hDevInfo,
  1023. IN PSP_DEVINFO_DATA pDevInfoData,
  1024. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  1025. )
  1026. /*++
  1027. Routine Description:
  1028. This function handles the class installer entry point for DIF_INSTALLDEVICEFILES
  1029. Arguments:
  1030. hDevInfo : Handle to the printer class device information list
  1031. pDevInfoData : Pointer to the device info element for the printer
  1032. pDevInstallParam : Pointer to the device install structure
  1033. Return Value:
  1034. Win 32 error code
  1035. --*/
  1036. {
  1037. PPSETUP_LOCAL_DATA pLocalData;
  1038. DWORD dwReturn;
  1039. if ( pLocalData = BuildInternalData(hDevInfo, pDevInfoData) )
  1040. {
  1041. dwReturn = InstallDriverFromCurrentInf(hDevInfo,
  1042. pLocalData,
  1043. pDevInstallParams->hwndParent,
  1044. MyPlatform,
  1045. dwThisMajorVersion,
  1046. NULL,
  1047. pDevInstallParams->FileQueue,
  1048. pDevInstallParams->InstallMsgHandlerContext,
  1049. pDevInstallParams->InstallMsgHandler,
  1050. pDevInstallParams->Flags,
  1051. NULL,
  1052. DRVINST_NO_WARNING_PROMPT,
  1053. APD_COPY_NEW_FILES,
  1054. NULL,
  1055. NULL,
  1056. NULL);
  1057. DestroyLocalData(pLocalData);
  1058. }
  1059. else
  1060. {
  1061. dwReturn = GetLastError();
  1062. }
  1063. return dwReturn;
  1064. }
  1065. DWORD
  1066. ClassInstall_RemoveDevice(
  1067. IN HDEVINFO hDevInfo,
  1068. IN PSP_DEVINFO_DATA pDevInfoData,
  1069. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. This function handles the class installer entry point for DIF_REMOVEDEVICE
  1074. Arguments:
  1075. hDevInfo : Handle to the printer class device information list
  1076. pDevInfoData : Pointer to the device info element for the printer
  1077. pDevInstallParam : Pointer to the device install structure
  1078. Return Value:
  1079. Win 32 error code
  1080. --*/
  1081. {
  1082. DWORD dwRet = ERROR_SUCCESS, dwIndex, dwCount, dwNeeded;
  1083. HANDLE hPrinter;
  1084. LPPRINTER_INFO_2 pPrinterInfo2, pBuf = NULL;
  1085. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  1086. TCHAR szDevId[MAX_DEVICE_ID_LEN], szPrnId[MAX_DEVICE_ID_LEN];
  1087. if ( !SetupDiGetDeviceInstanceId(hDevInfo,
  1088. pDevInfoData,
  1089. szDevId,
  1090. SIZECHARS(szDevId),
  1091. NULL) ||
  1092. !PrinterInfo2s(&pBuf, &dwCount) )
  1093. return GetLastError();
  1094. for ( dwIndex = 0, pPrinterInfo2 = pBuf ;
  1095. dwIndex < dwCount ;
  1096. ++dwIndex, ++pPrinterInfo2 ) {
  1097. if ( !OpenPrinter(pPrinterInfo2->pPrinterName,
  1098. &hPrinter,
  1099. &PrinterDefault) )
  1100. continue;
  1101. if ( ERROR_SUCCESS == GetPrinterDataEx(hPrinter,
  1102. cszPnPKey,
  1103. cszDeviceInstanceId,
  1104. &dwNeeded,
  1105. (LPBYTE)szPrnId,
  1106. sizeof(szPrnId),
  1107. &dwNeeded) &&
  1108. !lstrcmp(szPrnId, szDevId) ) {
  1109. dwRet = DeletePrinter(hPrinter) ? ERROR_SUCCESS : GetLastError();
  1110. ClosePrinter(hPrinter);
  1111. goto Done;
  1112. }
  1113. ClosePrinter(hPrinter);
  1114. }
  1115. //
  1116. // If we did not find the printer with spooler let setup do whatever they
  1117. // want to. Note even if a printer failed to install they can call us to
  1118. // remove it when Uninstall is selected from DevMan
  1119. //
  1120. dwRet = ERROR_DI_DO_DEFAULT;
  1121. Done:
  1122. LocalFreeMem(pBuf);
  1123. return dwRet;
  1124. }
  1125. DWORD
  1126. ClassInstall_DriverInfo(
  1127. IN HDEVINFO hDevInfo,
  1128. IN PSP_DEVINFO_DATA pDevInfoData,
  1129. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. This function handles the class installer entry point for DIF_DRIVERINFO
  1134. This is a class installer entry point specific to printer class installer.
  1135. Arguments:
  1136. hDevInfo : Handle to the printer class device information list
  1137. pDevInfoData : Pointer to the device info element for the printer
  1138. pDevInstallParam : Pointer to the device install structure
  1139. Return Value:
  1140. Win 32 error code
  1141. --*/
  1142. {
  1143. PPRINTER_CLASSINSTALL_INFO pClassInstallInfo;
  1144. PPSETUP_LOCAL_DATA pLocalData;
  1145. DWORD dwReturn;
  1146. //
  1147. // PRINTER_CLASSINSTALL_INFO could expand in the future
  1148. //
  1149. pClassInstallInfo = (PPRINTER_CLASSINSTALL_INFO)
  1150. pDevInstallParams->ClassInstallReserved;
  1151. if ( !pClassInstallInfo ||
  1152. pClassInstallInfo->cbSize < sizeof(PRINTER_CLASSINSTALL_INFO) ) {
  1153. return ERROR_INVALID_PARAMETER;
  1154. }
  1155. if ( pClassInstallInfo->dwLevel != 2 &&
  1156. pClassInstallInfo->dwLevel != 3 &&
  1157. pClassInstallInfo->dwLevel != 4 )
  1158. return ERROR_INVALID_LEVEL;
  1159. if ( !(pLocalData = BuildInternalData(hDevInfo, pDevInfoData)) ||
  1160. !ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0) ) {
  1161. dwReturn = GetLastError();
  1162. goto Done;
  1163. }
  1164. *pClassInstallInfo->pcbNeeded = pLocalData->InfInfo.cbDriverInfo6;
  1165. if ( pClassInstallInfo->cbBufSize < *pClassInstallInfo->pcbNeeded ) {
  1166. dwReturn = ERROR_INSUFFICIENT_BUFFER;
  1167. goto Done;
  1168. }
  1169. PackDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
  1170. (LPDRIVER_INFO_6)pClassInstallInfo->pBuf,
  1171. pLocalData->InfInfo.cbDriverInfo6);
  1172. dwReturn = ERROR_SUCCESS;
  1173. Done:
  1174. DestroyLocalData(pLocalData);
  1175. return dwReturn;
  1176. }
  1177. BOOL
  1178. FindDriver(
  1179. IN HDEVINFO hDevInfo,
  1180. IN PSP_DEVINFO_DATA pDevInfoData,
  1181. OUT PSP_DRVINFO_DATA pDrvInfoData
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. Gets the DeviceInstanceId for the pnp device and searches through all installed printer's pnp data to see if
  1186. this device has already been installed. This will only be called if no device has been selected and we're
  1187. being asked to install a NULL driver.
  1188. If there is a printer installed for this instance, get it's driver info and put the driver, mfg and provider names
  1189. into the pDrvInfoData structure to return.
  1190. Arguments:
  1191. hDevInfo - passed in from pnp.
  1192. pDevInfoData - passed in from pnp.
  1193. pDrvInfoData - will return with the relevant driver information to search for to install.
  1194. --*/
  1195. {
  1196. TCHAR szDeviceInstanceId[MAX_DEVICE_ID_LEN];
  1197. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  1198. BOOL bRet = FALSE;
  1199. DWORD dwReturned,
  1200. dwIndex,
  1201. dwNeeded = 0;
  1202. LPPRINTER_INFO_2 p = NULL,
  1203. pPrinterInfo2;
  1204. LPDRIVER_INFO_6 lpDriverInfo6 = NULL;
  1205. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  1206. if( !pDrvInfoData || pDrvInfoData->cbSize != sizeof(SP_DRVINFO_DATA) ) {
  1207. goto Cleanup;
  1208. }
  1209. if ( !SetupDiGetDeviceInstanceId(hDevInfo,
  1210. pDevInfoData,
  1211. szDeviceInstanceId,
  1212. SIZECHARS(szDeviceInstanceId),
  1213. NULL) ) {
  1214. goto Cleanup;
  1215. }
  1216. if ( !PrinterInfo2s(&p, &dwReturned) )
  1217. goto Cleanup;
  1218. //
  1219. // If there is a printer going to that same port and with the same pnp
  1220. // info, then it has been reinstalled with a newer driver.
  1221. //
  1222. for ( dwIndex = 0, pPrinterInfo2 = p ;
  1223. dwIndex < dwReturned ;
  1224. ++dwIndex, pPrinterInfo2++ ) {
  1225. if ( PrinterPnPDataSame(szDeviceInstanceId, pPrinterInfo2->pPrinterName) )
  1226. {
  1227. //
  1228. // Get a DRIVER_INFO_6 for the installed driver.
  1229. //
  1230. if( OpenPrinter(pPrinterInfo2->pPrinterName, &hPrinter, &PrinterDefault) ) {
  1231. if( !GetPrinterDriver( hPrinter,
  1232. PlatformEnv[MyPlatform].pszName,
  1233. 6,
  1234. (LPBYTE)lpDriverInfo6,
  1235. dwNeeded,
  1236. &dwNeeded) ) {
  1237. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  1238. NULL == ( lpDriverInfo6 = LocalAllocMem( dwNeeded ) ) ||
  1239. !GetPrinterDriver( hPrinter,
  1240. PlatformEnv[MyPlatform].pszName,
  1241. 6,
  1242. (LPBYTE)lpDriverInfo6,
  1243. dwNeeded,
  1244. &dwNeeded) ) {
  1245. ClosePrinter( hPrinter );
  1246. goto Cleanup;
  1247. }
  1248. }
  1249. //
  1250. // We have some info, so clear the pDrvInfoData and set it up.
  1251. //
  1252. ZeroMemory( pDrvInfoData, sizeof(SP_DRVINFO_DATA) );
  1253. pDrvInfoData->cbSize = sizeof(SP_DRVINFO_DATA);
  1254. pDrvInfoData->DriverType = SPDIT_CLASSDRIVER;
  1255. //
  1256. // We have the DRIVER_INFO_6 - now get the Driver, Mfg and Provider names from the struct
  1257. // to use as the install info.
  1258. //
  1259. lstrcpyn( pDrvInfoData->Description, lpDriverInfo6->pName, LINE_LEN );
  1260. lstrcpyn( pDrvInfoData->MfgName, lpDriverInfo6->pszMfgName, LINE_LEN );
  1261. lstrcpyn( pDrvInfoData->ProviderName, lpDriverInfo6->pszProvider, LINE_LEN );
  1262. ClosePrinter( hPrinter );
  1263. bRet = TRUE;
  1264. goto Cleanup;
  1265. }
  1266. }
  1267. }
  1268. Cleanup:
  1269. if( p ) {
  1270. LocalFreeMem( p );
  1271. }
  1272. if( lpDriverInfo6 ) {
  1273. LocalFreeMem( lpDriverInfo6 );
  1274. }
  1275. return bRet;
  1276. }
  1277. DWORD
  1278. ClassInstall_SelectBestCompatDrv(
  1279. IN HDEVINFO hDevInfo,
  1280. IN PSP_DEVINFO_DATA pDevInfoData,
  1281. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. This function handles the class installer entry point for
  1286. DIF_SELECTBESTCOMPATDRV.
  1287. We try to handle the broken OEM models which return same PnP id for
  1288. multiple devices. For that we do the following:
  1289. 1. If only one compatible driver has been found by setup we got
  1290. nothing to do. We ask setup to do the default since this is a good
  1291. devive.
  1292. 2. If multiple drivers are found we do the following:
  1293. 2.1 What is the port this printer is attached to
  1294. 2.2 Find list of printers installed currently
  1295. 2.3 If we have a printer going to the port the PnP printer is
  1296. attached to AND the driver for that printer is one of the
  1297. compatible drivers then we got nothing to do. User has already
  1298. manually installed it.
  1299. Arguments:
  1300. hDevInfo : Handle to the printer class device information list
  1301. pDevInfoData : Pointer to the device info element for the printer
  1302. pDevInstallParam : Pointer to the device install structure
  1303. Return Value:
  1304. Win 32 error code
  1305. --*/
  1306. {
  1307. BOOL bFound = FALSE, Rank0IHVMatchFound = FALSE;
  1308. HKEY hKey = NULL;
  1309. DWORD dwReturn = ERROR_DI_DO_DEFAULT, dwRank0Matches;
  1310. DWORD dwSize, dwType, dwIndex1, dwIndex2, dwReturned;
  1311. SP_DRVINFO_DATA DrvInfoData;
  1312. TCHAR szPortName[MAX_PATH];
  1313. LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
  1314. SP_DRVINSTALL_PARAMS DrvInstData;
  1315. LPTSTR pszModelName = NULL;
  1316. PSP_DRVINFO_DETAIL_DATA pDetailData;
  1317. DWORD dwDetailDataSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  1318. //
  1319. // Allocate pDetailData on the heap, it's quite chunky
  1320. //
  1321. pDetailData = LocalAllocMem(dwDetailDataSize);
  1322. if ( !pDetailData )
  1323. {
  1324. goto Done;
  1325. }
  1326. //
  1327. // If we do not have more than 1 compatible driver do default
  1328. // Note: API uses 0 based index.
  1329. //
  1330. for ( dwIndex1 = dwRank0Matches = 0 ; ; ++dwIndex1 ) {
  1331. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1332. if ( !SetupDiEnumDriverInfo(hDevInfo, pDevInfoData, SPDIT_COMPATDRIVER,
  1333. dwIndex1, &DrvInfoData) )
  1334. break;
  1335. DrvInstData.cbSize = sizeof(DrvInstData);
  1336. if ( SetupDiGetDriverInstallParams(hDevInfo,
  1337. pDevInfoData,
  1338. &DrvInfoData,
  1339. &DrvInstData))
  1340. {
  1341. if (DrvInstData.Rank < 0x1000 )
  1342. {
  1343. if (!pszModelName)
  1344. {
  1345. pszModelName = AllocStr( DrvInfoData.Description );
  1346. ++dwRank0Matches;
  1347. }
  1348. else if ( lstrcmpi( pszModelName, DrvInfoData.Description ) )
  1349. {
  1350. ++dwRank0Matches;
  1351. }
  1352. }
  1353. //
  1354. // Check for whether this match is in ntprint.inf. If so, set flag to prefer other drivers
  1355. //
  1356. ZeroMemory(pDetailData, dwDetailDataSize);
  1357. pDetailData->cbSize = dwDetailDataSize;
  1358. //
  1359. // check whether it's ntprint.inf
  1360. // function may return insufficient buffer if it couldn't stuff all the
  1361. // hardware IDs at the end of the structure.
  1362. //
  1363. if ((SetupDiGetDriverInfoDetail(hDevInfo,
  1364. pDevInfoData,
  1365. &DrvInfoData,
  1366. pDetailData,
  1367. dwDetailDataSize,
  1368. NULL)) ||
  1369. (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
  1370. {
  1371. SetLastError(ERROR_SUCCESS);
  1372. if (IsSystemNTPrintInf( pDetailData->InfFileName ) )
  1373. {
  1374. DrvInstData.Flags |= DNF_BASIC_DRIVER;
  1375. SetupDiSetDriverInstallParams(hDevInfo,
  1376. pDevInfoData,
  1377. &DrvInfoData,
  1378. &DrvInstData);
  1379. }
  1380. else if (DrvInstData.Rank < 0x1000 )
  1381. {
  1382. Rank0IHVMatchFound = TRUE;
  1383. }
  1384. }
  1385. }
  1386. }
  1387. //
  1388. // Free the memory if allocated
  1389. //
  1390. LocalFreeMem( pszModelName );
  1391. LocalFreeMem( pDetailData );
  1392. if ( dwRank0Matches <= 1 )
  1393. goto Done;
  1394. //
  1395. // Look in the devnode of the printer for the port name
  1396. //
  1397. dwSize = sizeof(szPortName);
  1398. if ( ERROR_SUCCESS != CM_Open_DevNode_Key(pDevInfoData->DevInst, KEY_READ,
  1399. 0, RegDisposition_OpenExisting,
  1400. &hKey, CM_REGISTRY_HARDWARE) ||
  1401. ERROR_SUCCESS != RegQueryValueEx(hKey, cszPortName, NULL, &dwType,
  1402. (LPBYTE)&szPortName, &dwSize) )
  1403. goto Done;
  1404. if ( !PrinterInfo2s(&p, &dwReturned) )
  1405. goto Done;
  1406. //
  1407. // If there is a local printer using a driver with rank-0 match and
  1408. // going to the same port then it is a duplicate
  1409. //
  1410. for ( dwIndex1 = 0, pPrinterInfo2 = p ;
  1411. dwIndex1 < dwReturned ;
  1412. ++dwIndex1, pPrinterInfo2++ ) {
  1413. if ( !PrinterGoingToPort(pPrinterInfo2, szPortName) )
  1414. continue;
  1415. dwIndex2 = 0;
  1416. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1417. while ( SetupDiEnumDriverInfo(hDevInfo, pDevInfoData,
  1418. SPDIT_COMPATDRIVER, dwIndex2,
  1419. &DrvInfoData) ) {
  1420. DrvInstData.cbSize = sizeof(DrvInstData);
  1421. if ( SetupDiGetDriverInstallParams(hDevInfo,
  1422. pDevInfoData,
  1423. &DrvInfoData,
  1424. &DrvInstData) &&
  1425. DrvInstData.Rank < 0x1000 &&
  1426. !lstrcmpi(DrvInfoData.Description,
  1427. pPrinterInfo2->pDriverName) ) {
  1428. bFound = TRUE;
  1429. break;
  1430. }
  1431. ++dwIndex2;
  1432. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1433. }
  1434. if ( bFound )
  1435. break;
  1436. }
  1437. //
  1438. // If we found a manually installed printer which matches one of the
  1439. // compatible drivers that is what we want to install
  1440. //
  1441. if ( bFound ) {
  1442. //
  1443. // This means newdev will choose this as the driver to install
  1444. //
  1445. if ( SetupDiSetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData) )
  1446. dwReturn = ERROR_SUCCESS;
  1447. }
  1448. else if (!Rank0IHVMatchFound)
  1449. {
  1450. //
  1451. // We did not find a printer. So bump up the rank of all drivers
  1452. // to force newdev to ask the user to select a driver
  1453. //
  1454. dwIndex2 = 0;
  1455. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1456. while ( SetupDiEnumDriverInfo(hDevInfo, pDevInfoData,
  1457. SPDIT_COMPATDRIVER, dwIndex2,
  1458. &DrvInfoData) ) {
  1459. DrvInstData.cbSize = sizeof(DrvInstData);
  1460. if ( SetupDiGetDriverInstallParams(hDevInfo,
  1461. pDevInfoData,
  1462. &DrvInfoData,
  1463. &DrvInstData) &&
  1464. DrvInstData.Rank < 0x1000 ) {
  1465. DrvInstData.Rank += 0x1000;
  1466. SetupDiSetDriverInstallParams(hDevInfo,
  1467. pDevInfoData,
  1468. &DrvInfoData,
  1469. &DrvInstData);
  1470. }
  1471. ++dwIndex2;
  1472. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1473. }
  1474. }
  1475. Done:
  1476. LocalFreeMem(p);
  1477. if ( hKey )
  1478. RegCloseKey(hKey);
  1479. return dwReturn;
  1480. }
  1481. DWORD
  1482. StoreDriverTypeInDevnode(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfoData)
  1483. {
  1484. SP_DRVINFO_DATA DrvInfoData = {0};
  1485. DWORD dwRet = ERROR_SUCCESS;
  1486. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1487. if (SetupDiGetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData))
  1488. {
  1489. DWORD dwDetailDataSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  1490. SP_DRVINSTALL_PARAMS DrvInstData = {0};
  1491. DrvInstData.cbSize = sizeof(DrvInstData);
  1492. if ( SetupDiGetDriverInstallParams(hDevInfo,
  1493. pDevInfoData,
  1494. &DrvInfoData,
  1495. &DrvInstData))
  1496. {
  1497. HKEY hKey;
  1498. DWORD InstallInboxDriver;
  1499. InstallInboxDriver = (DrvInstData.Flags & DNF_BASIC_DRIVER) ? 1 : 0;
  1500. hKey = SetupDiOpenDevRegKey(hDevInfo, pDevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_WRITE);
  1501. if (hKey != INVALID_HANDLE_VALUE)
  1502. {
  1503. dwRet = RegSetValueEx(hKey, cszBestDriverInbox, 0, REG_DWORD, (LPBYTE) &InstallInboxDriver, sizeof(InstallInboxDriver));
  1504. RegCloseKey(hKey);
  1505. }
  1506. else
  1507. {
  1508. dwRet = GetLastError();
  1509. }
  1510. }
  1511. else
  1512. {
  1513. dwRet = GetLastError();
  1514. }
  1515. }
  1516. else
  1517. {
  1518. dwRet = GetLastError();
  1519. }
  1520. return dwRet;
  1521. }
  1522. DWORD
  1523. ClassInstall_AllowInstall(
  1524. IN HDEVINFO hDevInfo,
  1525. IN PSP_DEVINFO_DATA pDevInfoData,
  1526. IN PSP_DEVINSTALL_PARAMS pDevInstallParams
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. This function handles the class installer entry point for
  1531. DIF_ALLOW_INSTALL.
  1532. Do not allow PnP installs during GUI setup portion of system upgrade
  1533. Do not allow install of INFs using VendorSetup if QUIETINSTALL bit is set
  1534. Arguments:
  1535. hDevInfo : Handle to the printer class device information list
  1536. pDevInfoData : Pointer to the device info element for the printer
  1537. pDevInstallParam : Pointer to the device install structure
  1538. Return Value:
  1539. Win 32 error code
  1540. --*/
  1541. {
  1542. DWORD dwReturn = ERROR_DI_DO_DEFAULT;
  1543. PPSETUP_LOCAL_DATA pLocalData;
  1544. if ( pDevInstallParams->Flags & DI_QUIETINSTALL ) {
  1545. //
  1546. // During system setup no PnP install of printers because there ain't no spooler
  1547. // check that the spooler is running - failing this will punt to client-side installation
  1548. // which should happen at a point in time where the spooler actually is running - we don't
  1549. // want to stall system startup until the spooler is up (think USB mouse...)
  1550. //
  1551. if (IsSystemSetupInProgress() ||
  1552. !IsSpoolerRunning()) {
  1553. //
  1554. // store the type (inbox or not) in the devnode. This fails if this is a clean install
  1555. // but it doesn't matter because we only need it for drivers that have been installed
  1556. // before upgrade.
  1557. // We use it to determine later on whether to clear the CONFIGFLAG_REINSTALL
  1558. // or not. We don't want to clear it if the best driver is inbox so we'll install it
  1559. // on first boot.
  1560. //
  1561. StoreDriverTypeInDevnode(hDevInfo, pDevInfoData);
  1562. dwReturn = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1563. goto Done;
  1564. }
  1565. if ( (pLocalData = BuildInternalData(hDevInfo, pDevInfoData)) &&
  1566. ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0) ) {
  1567. if ( pLocalData->InfInfo.pszVendorSetup &&
  1568. *pLocalData->InfInfo.pszVendorSetup )
  1569. dwReturn = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1570. } else {
  1571. if ( (dwReturn = GetLastError()) == ERROR_SUCCESS )
  1572. dwReturn = ERROR_INVALID_PARAMETER;
  1573. }
  1574. }
  1575. Done:
  1576. return dwReturn;
  1577. }
  1578. DWORD
  1579. ClassInstall32(
  1580. IN DI_FUNCTION InstallFunction,
  1581. IN HDEVINFO hDevInfo,
  1582. IN PSP_DEVINFO_DATA pDevInfoData
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. This is the printer class installer entry point for SetupDiCallClassInstaller calls
  1587. Arguments:
  1588. InstallFunction : The function being called
  1589. hDevInfo : Handle to the printer class device information list
  1590. pDevInfoData : Pointer to the device info element for the printer
  1591. Return Value:
  1592. Win 32 error code
  1593. --*/
  1594. {
  1595. SP_DEVINSTALL_PARAMS DevInstallParams;
  1596. DWORD dwReturn = ERROR_DI_DO_DEFAULT;
  1597. DevInstallParams.cbSize = sizeof(DevInstallParams);
  1598. if ( !SetupDiGetDeviceInstallParams(hDevInfo,
  1599. pDevInfoData,
  1600. &DevInstallParams) ) {
  1601. dwReturn = GetLastError();
  1602. goto Done;
  1603. }
  1604. switch (InstallFunction) {
  1605. case DIF_SELECTDEVICE:
  1606. dwReturn = ClassInstall_SelectDevice(hDevInfo, pDevInfoData);
  1607. break;
  1608. case DIF_INSTALLDEVICE:
  1609. dwReturn = ClassInstall_InstallDevice(hDevInfo,
  1610. pDevInfoData,
  1611. &DevInstallParams);
  1612. break;
  1613. case DIF_DRIVERINFO:
  1614. dwReturn = ClassInstall_DriverInfo(hDevInfo,
  1615. pDevInfoData,
  1616. &DevInstallParams);
  1617. break;
  1618. case DIF_INSTALLWIZARD:
  1619. dwReturn = ClassInstall_InstallWizard(hDevInfo,
  1620. pDevInfoData,
  1621. &DevInstallParams);
  1622. break;
  1623. case DIF_DESTROYWIZARDDATA:
  1624. dwReturn = ClassInstall_DestroyWizardData(hDevInfo,
  1625. pDevInfoData,
  1626. &DevInstallParams);
  1627. break;
  1628. case DIF_INSTALLDEVICEFILES:
  1629. dwReturn = ClassInstall_InstallDeviceFiles(hDevInfo,
  1630. pDevInfoData,
  1631. &DevInstallParams);
  1632. break;
  1633. case DIF_REMOVE:
  1634. dwReturn = ClassInstall_RemoveDevice(hDevInfo,
  1635. pDevInfoData,
  1636. &DevInstallParams);
  1637. break;
  1638. case DIF_GETWINDOWSUPDATEINFO:
  1639. if ( !InitCodedownload(HWND_DESKTOP) )
  1640. dwReturn = GetLastError();
  1641. else
  1642. {
  1643. if ( SetPackageName(hDevInfo, pDevInfoData) )
  1644. dwReturn = NO_ERROR;
  1645. else
  1646. dwReturn = GetLastError();
  1647. }
  1648. break;
  1649. case DIF_SELECTBESTCOMPATDRV:
  1650. dwReturn = ClassInstall_SelectBestCompatDrv(hDevInfo,
  1651. pDevInfoData,
  1652. &DevInstallParams);
  1653. break;
  1654. case DIF_ALLOW_INSTALL:
  1655. dwReturn = ClassInstall_AllowInstall(hDevInfo,
  1656. pDevInfoData,
  1657. &DevInstallParams);
  1658. break;
  1659. case DIF_DESTROYPRIVATEDATA:
  1660. case DIF_MOVEDEVICE:
  1661. default:
  1662. break;
  1663. }
  1664. Done:
  1665. return dwReturn;
  1666. }
  1667. BOOL
  1668. PSetupProcessPrinterAdded(
  1669. IN HDEVINFO hDevInfo,
  1670. IN PPSETUP_LOCAL_DATA pLocalData,
  1671. IN LPCTSTR pszPrinterName,
  1672. IN HWND hwnd
  1673. )
  1674. {
  1675. BOOL bRet = FALSE;
  1676. HANDLE hPrinter = NULL;
  1677. PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
  1678. bRet = OpenPrinter((LPTSTR)pszPrinterName, &hPrinter, &PrinterDefault) &&
  1679. SetPnPInfoForPrinter(hPrinter,
  1680. pLocalData->PnPInfo.pszDeviceInstanceId,
  1681. pLocalData->DrvInfo.pszHardwareID,
  1682. pLocalData->DrvInfo.pszManufacturer,
  1683. pLocalData->DrvInfo.pszOEMUrl);
  1684. //
  1685. // If a vendor dll is given we need to call into it
  1686. //
  1687. if ( pLocalData->InfInfo.pszVendorSetup )
  1688. CallVendorDll(pLocalData, pszPrinterName, hwnd);
  1689. if ( pLocalData->InfInfo.pszzICMFiles )
  1690. (VOID)PSetupAssociateICMProfiles(pLocalData->InfInfo.pszzICMFiles,
  1691. pszPrinterName);
  1692. if ( hPrinter )
  1693. ClosePrinter(hPrinter);
  1694. return bRet;
  1695. }