Leaked source code of windows server 2003
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.

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