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.

1508 lines
39 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Win9x.c
  6. Abstract:
  7. Routines to pre-migrate Win9x to NT
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 02-Jan-1996
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. //
  14. // This data structure is used to keep track of printer drivers installed on
  15. // Win9x and their NT names
  16. //
  17. typedef struct _DRIVER_INFO_9X {
  18. struct _DRIVER_INFO_9X *pNext;
  19. LPSTR pszWin95Name;
  20. LPSTR pszNtName;
  21. } DRIVER_INFO_9X, *PDRIVER_INFO_9X;
  22. UPGRADABLE_LIST UpgradableMonitors[] = { {"Local Port"}, { NULL } };
  23. DWORD dwNetPrinters = 0;
  24. DWORD dwSharedPrinters = 0;
  25. CHAR szRegPrefix[] = "HKLM\\System\\CurrentControlSet\\Control\\Print\\";
  26. CHAR szRegPrefixOnly[] = "System\\CurrentControlSet\\control\\Print\\Printers";
  27. CHAR cszPrinterID[] = "PrinterID";
  28. CHAR cszWinPrint[] = "winprint";
  29. CHAR cszRaw[] = "RAW";
  30. //
  31. // the following drivers need not be warned or upgraded, they're handled by
  32. // the fax folks. The names are not localized.
  33. //
  34. CHAR *pcszIgnoredDrivers[] = {
  35. "Microsoft Shared Fax Driver",
  36. "Microsoft Fax Client",
  37. NULL
  38. };
  39. BOOL
  40. IsIgnoredDriver(LPCSTR pszDriverName)
  41. {
  42. DWORD i;
  43. for (i=0; pcszIgnoredDrivers[i] != NULL; i++)
  44. {
  45. if (!strcmp(pcszIgnoredDrivers[i], pszDriverName))
  46. {
  47. return TRUE;
  48. }
  49. }
  50. return FALSE;
  51. }
  52. BOOL
  53. SearchRegTreeForPrinterId(
  54. IN DWORD dwPrinterId,
  55. IN LPCSTR pszRegRoot,
  56. IN LPSTR pszBuf,
  57. IN DWORD cchBufLen
  58. )
  59. /*++
  60. Routine Description:
  61. This routine searchs a given registry tree of DevNodes for a given
  62. printer id.
  63. Arguments:
  64. dwPrinterId : Unique printer id we are searching for
  65. pszRegRoot : Registry path relative to HKLM
  66. pszBuf : Buffer to fill the registry key path on success
  67. cchBufLen : size of key buffer in characters
  68. Return Value:
  69. TRUE on success, FALSE else
  70. --*/
  71. {
  72. BOOL bFound = FALSE;
  73. DWORD dwLen, dwIndex, dwDontCare, dwId, dwSize;
  74. HKEY hKey, hSubKey;
  75. LPSTR pszCur;
  76. DWORD dwLastError;
  77. //
  78. // Copy the registry path
  79. //
  80. dwLen = strlen(pszRegRoot) + 1;
  81. if ( dwLen + 1 > cchBufLen )
  82. return FALSE;
  83. if ( ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  84. pszRegRoot,
  85. 0,
  86. KEY_READ,
  87. &hKey) )
  88. return FALSE;
  89. strcpy(pszBuf, pszRegRoot);
  90. pszCur = pszBuf + dwLen;
  91. *(pszCur-1) = '\\';
  92. *pszCur = 0;
  93. //
  94. // Walk thru each devnode looking for a matching PrinterId
  95. //
  96. for ( dwIndex = 0, dwSize = cchBufLen - dwLen ;
  97. !bFound &&
  98. !RegEnumKeyExA(hKey, dwIndex, pszCur, &dwSize,
  99. NULL, NULL, NULL, NULL) &&
  100. !RegOpenKeyExA(hKey, pszCur, 0, KEY_READ, &hSubKey) ;
  101. ++dwIndex, dwSize = cchBufLen - dwLen ) {
  102. dwSize = sizeof(dwId);
  103. if ( ERROR_SUCCESS == RegQueryValueExA(hSubKey,
  104. cszPrinterID,
  105. 0,
  106. &dwDontCare,
  107. (LPBYTE)&dwId,
  108. &dwSize) ) {
  109. if ( dwId == dwPrinterId ) {
  110. bFound = TRUE;
  111. dwLen = strlen(pszBuf);
  112. if ( dwLen + 2 < cchBufLen )
  113. strcpy(pszBuf + dwLen, "\"");
  114. }
  115. } else {
  116. bFound = SearchRegTreeForPrinterId(dwPrinterId,
  117. pszBuf,
  118. pszBuf,
  119. cchBufLen);
  120. if ( !bFound ) {
  121. strcpy(pszBuf, pszRegRoot);
  122. pszCur = pszBuf + dwLen;
  123. *(pszCur-1) = '\\';
  124. *pszCur = 0;
  125. }
  126. }
  127. RegCloseKey(hSubKey);
  128. }
  129. RegCloseKey(hKey);
  130. return bFound;
  131. }
  132. DWORD
  133. GetPrinterId(
  134. LPSTR pszPrinterName
  135. )
  136. /*++
  137. Routine Description:
  138. Given a printer id finds the printer id from PrinterDriverData.
  139. Call to GetPrinterData screws up migration dll local data for unknown
  140. reasons. So now we access the registry directly
  141. Arguments:
  142. pszPrinterName : Printer name to get id for
  143. Return Value:
  144. 0 on failure else PrinterID from registry is returned
  145. --*/
  146. {
  147. CHAR szKey[MAX_PATH];
  148. HKEY hKey;
  149. DWORD dwId = 0, dwType, dwSize;
  150. if ( strlen(szRegPrefixOnly) + strlen(pszPrinterName)
  151. + strlen("PrinterDriverData")
  152. + 3 > MAX_PATH )
  153. return dwId;
  154. sprintf(szKey, "%s\\%s\\PrinterDriverData", szRegPrefixOnly, pszPrinterName);
  155. if ( ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  156. szKey,
  157. 0,
  158. KEY_READ,
  159. &hKey) ) {
  160. dwSize = sizeof(dwId);
  161. if ( ERROR_SUCCESS != RegQueryValueExA(hKey,
  162. cszPrinterID,
  163. 0,
  164. &dwType,
  165. (LPBYTE)&dwId,
  166. &dwSize) )
  167. dwId = 0;
  168. RegCloseKey(hKey);
  169. }
  170. return dwId;
  171. }
  172. BOOL
  173. RegPathFromPrinter(
  174. IN LPSTR pszPrinterName,
  175. OUT LPSTR szKeyBuffer,
  176. IN DWORD cchKeyBufLen
  177. )
  178. /*++
  179. Routine Description:
  180. This routine returns the registry path of the DevNode for a printer.
  181. This should be marked as Handled or as Incompatible in the migrate.inf
  182. to report to the user
  183. Arguments:
  184. pszPrinterName : Printer name
  185. szKeyBuffer : Buffer to fill in the registry path
  186. cchKeyBufLen : Length of key buffer in characters
  187. Return Value:
  188. TRUE on success, FALSE else
  189. --*/
  190. {
  191. DWORD dwPrinterId, dwLen;
  192. CHAR szHeader[] = "\"HKLM\\";
  193. CHAR szRegPrinterPrefix[] = "Printers\\";
  194. //
  195. // Add "HKLM\ at the beginning and "\" at the end
  196. //
  197. dwLen = strlen(szHeader);
  198. if ( dwLen + 1 > cchKeyBufLen )
  199. return FALSE;
  200. strcpy(szKeyBuffer, szHeader);
  201. //
  202. // If a printer id is found then there is a DevNode list that
  203. // registry path, otherwise return spooler registry path
  204. //
  205. if ( dwPrinterId = GetPrinterId(pszPrinterName) ) {
  206. return SearchRegTreeForPrinterId(dwPrinterId,
  207. "Enum\\Root\\printer",
  208. szKeyBuffer + dwLen,
  209. cchKeyBufLen - dwLen) ||
  210. SearchRegTreeForPrinterId(dwPrinterId,
  211. "Enum\\LPTENUM",
  212. szKeyBuffer + dwLen,
  213. cchKeyBufLen - dwLen) ||
  214. SearchRegTreeForPrinterId(dwPrinterId,
  215. "Enum\\IRDA",
  216. szKeyBuffer + dwLen,
  217. cchKeyBufLen - dwLen);
  218. } else {
  219. dwLen = strlen(szRegPrefix) + strlen(szRegPrinterPrefix)
  220. + strlen(pszPrinterName) + 3;
  221. if ( dwLen >= cchKeyBufLen )
  222. return FALSE;
  223. szKeyBuffer[0] = '"';
  224. strcpy(szKeyBuffer + 1, szRegPrefix);
  225. strcat(szKeyBuffer, szRegPrinterPrefix);
  226. strcat(szKeyBuffer, pszPrinterName);
  227. strcat(szKeyBuffer, "\"");
  228. return TRUE;
  229. }
  230. return FALSE;
  231. }
  232. LONG
  233. CALLBACK
  234. Initialize9x(
  235. IN LPCSTR pszWorkingDir,
  236. IN LPCSTR pszSourceDir,
  237. LPVOID Reserved
  238. )
  239. /*++
  240. Routine Description:
  241. This is an export for setup to call during the report phase.
  242. This is the first function called on the migration DLL.
  243. Arguments:
  244. pszWorkingDir : Gives the working directory assigned for printing
  245. pszSourceDir : Source location for NT distribution files
  246. Reserved : Leave it alone
  247. Return Value:
  248. Win32 error code
  249. --*/
  250. {
  251. POEM_UPGRADE_INFO pOemUpgradeInfo;
  252. BOOL bFail = TRUE;
  253. UpgradeData.pszDir = AllocStrA(pszWorkingDir);
  254. UpgradeData.pszSourceA = AllocStrA(pszSourceDir);
  255. UpgradeData.pszSourceW = NULL;
  256. bFail = UpgradeData.pszDir == NULL ||
  257. UpgradeData.pszSourceA == NULL;
  258. return bFail ? GetLastError() : ERROR_SUCCESS;
  259. }
  260. LONG
  261. CALLBACK
  262. MigrateUser9x(
  263. IN HWND hwndParent,
  264. IN LPCSTR pszUnattendFile,
  265. IN HKEY hUserRegKey,
  266. IN LPCSTR pszUserName,
  267. LPVOID Reserved
  268. )
  269. /*++
  270. Routine Description:
  271. Process per user settings
  272. Arguments:
  273. Return Value:
  274. None
  275. --*/
  276. {
  277. //
  278. // Nothing to do
  279. //
  280. return ERROR_SUCCESS;
  281. }
  282. VOID
  283. DestroyDriverInfo9xList(
  284. IN PDRIVER_INFO_9X pDriverInfo9x
  285. )
  286. /*++
  287. Routine Description:
  288. Free memory for the driver entries in DRIVER_INFO_9X linked list
  289. Arguments:
  290. pDriverInfo9x : Beginning of the linked list
  291. Return Value:
  292. None
  293. --*/
  294. {
  295. PDRIVER_INFO_9X pNext;
  296. while ( pDriverInfo9x ) {
  297. pNext = pDriverInfo9x->pNext;
  298. FreeMem(pDriverInfo9x);
  299. pDriverInfo9x = pNext;
  300. }
  301. }
  302. PDRIVER_INFO_9X
  303. AllocateDriverInfo9x(
  304. IN LPSTR pszNtName,
  305. IN LPSTR pszWin95Name,
  306. IN OUT LPBOOL pbFail
  307. )
  308. /*++
  309. Routine Description:
  310. Allocate memory and create a DRIVER_INFO_9X structure
  311. Arguments:
  312. pszNtName : NT printer driver model name. This could be NULL if no
  313. matching entry is found on ntprint.inf
  314. pszWin95Name : Win95 printer driver name
  315. pbFail : Set on an error -- no more processing needed
  316. Return Value:
  317. Returns pointer to the allocated DRIVER_INFO_9X structure. Memory is also
  318. allocated for the strings
  319. --*/
  320. {
  321. PDRIVER_INFO_9X pInfo;
  322. DWORD cbSize;
  323. LPSTR pszEnd;
  324. if ( *pbFail )
  325. return NULL;
  326. cbSize = strlen(pszWin95Name) + 1;
  327. if ( pszNtName )
  328. cbSize += strlen(pszNtName) + 1;
  329. cbSize *= sizeof(CHAR);
  330. cbSize += sizeof(DRIVER_INFO_9X);
  331. if ( pInfo = AllocMem(cbSize) ) {
  332. pszEnd = (LPBYTE) pInfo + cbSize;
  333. if ( pszNtName ) {
  334. pszEnd -= strlen(pszNtName) + 1;
  335. strcpy(pszEnd, pszNtName);
  336. pInfo->pszNtName = pszEnd;
  337. }
  338. pszEnd -= strlen(pszWin95Name) + 1;
  339. strcpy(pszEnd, pszWin95Name);
  340. pInfo->pszWin95Name = pszEnd;
  341. } else {
  342. *pbFail = TRUE;
  343. }
  344. return pInfo;
  345. }
  346. LPSTR
  347. FindNtModelNameFromWin95Name(
  348. IN OUT HDEVINFO hDevInfo,
  349. IN HINF hNtInf,
  350. IN HINF hUpgInf,
  351. IN LPCSTR pszWin95Name,
  352. IN OUT LPBOOL pbFail
  353. )
  354. /*++
  355. Routine Description:
  356. This routine finds the NT printer driver model name from the Win9x name
  357. Rules followed:
  358. 1. If a name mapping is used in prtupg9x.inf use it
  359. 2. Else just use the Win95 as it is
  360. Arguments:
  361. hDevInfo : Printer device class list. Has all drivers from NT built
  362. hNtInf : Handle to the NT ntprint.inf
  363. hUpgInfo : Handle to prtupg9x.inf
  364. DiskSpaceList : Handle to disk space list. Add driver files to this
  365. pszWin95Name : Windows 95 printer driver name
  366. pbFail : Set on an error -- no more processing needed
  367. Return Value:
  368. Pointer to the NT printer driver name. Memory is allocated and caller has
  369. to free it
  370. --*/
  371. {
  372. BOOL bFound = FALSE;
  373. DWORD dwIndex, dwNeeded;
  374. CHAR szNtName[LINE_LEN];
  375. INFCONTEXT InfContext;
  376. SP_DRVINFO_DATA_A DrvInfoData;
  377. PSP_DRVINFO_DETAIL_DATA_A pDrvInfoDetailData = NULL;
  378. if ( *pbFail )
  379. return NULL;
  380. //
  381. // See in prtupg9x.inf to see if the driver has a different name on NT
  382. //
  383. if ( SetupFindFirstLineA(hUpgInf,
  384. "Printer Driver Mapping",
  385. pszWin95Name,
  386. &InfContext) ) {
  387. //
  388. // If for some reason we could not get NT name we will still continue
  389. // with other driver models
  390. //
  391. if ( !SetupGetStringField(&InfContext,
  392. 1,
  393. szNtName,
  394. sizeof(szNtName)/sizeof(szNtName[0]),
  395. NULL) )
  396. return NULL;
  397. } else {
  398. //
  399. // If there is no mapping in the upgrade inf then look for Win95 name
  400. // in ntprint.inf
  401. //
  402. if ( strlen(pszWin95Name) > LINE_LEN - 1 )
  403. return NULL;
  404. strcpy(szNtName, pszWin95Name);
  405. }
  406. //
  407. // NOTE only for beta2
  408. // DrvInfoData.cbSize = sizeof(DrvInfoData);
  409. DrvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_V1);
  410. for ( dwIndex = 0 ;
  411. SetupDiEnumDriverInfoA(hDevInfo,
  412. NULL,
  413. SPDIT_CLASSDRIVER,
  414. dwIndex,
  415. &DrvInfoData);
  416. ++dwIndex ) {
  417. if ( !_strcmpi(DrvInfoData.Description, szNtName) ) {
  418. bFound = TRUE;
  419. break;
  420. }
  421. }
  422. if ( !bFound )
  423. return NULL;
  424. //
  425. // Now that we found a driver for the device on NT we need to calculate
  426. // the disk space required
  427. //
  428. if ( ( !SetupDiGetDriverInfoDetailA(hDevInfo,
  429. NULL,
  430. &DrvInfoData,
  431. NULL,
  432. 0,
  433. &dwNeeded) &&
  434. GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  435. !(pDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA_A)AllocMem(dwNeeded)) )
  436. return NULL;
  437. pDrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
  438. if ( !SetupDiGetDriverInfoDetailA(hDevInfo,
  439. NULL,
  440. &DrvInfoData,
  441. pDrvInfoDetailData,
  442. dwNeeded,
  443. &dwNeeded) ) {
  444. FreeMem(pDrvInfoDetailData);
  445. return NULL;
  446. }
  447. //
  448. // NOTE should we subtract the Win95 driver size since we do not need it
  449. //
  450. FreeMem(pDrvInfoDetailData);
  451. return AllocStrA(szNtName);
  452. }
  453. VOID
  454. WriteFileToBeDeletedInInf(
  455. IN LPCSTR pszInfName,
  456. IN LPCSTR pszFileName
  457. )
  458. /*++
  459. Routine Description:
  460. Writes a file which is to be deleted on migration to NT in the migrate.inf
  461. Arguments:
  462. pszInfName : Full path to the migrate.inf
  463. pszFileName : Fully qualified filename to be deleted
  464. Return Value:
  465. None
  466. --*/
  467. {
  468. CHAR szString[MAX_PATH+2];
  469. szString[0] = '"';
  470. if ( GetSystemDirectoryA(szString + 1, SIZECHARS(szString)-2) ) {
  471. strcat(szString, "\\");
  472. strcat(szString, pszFileName);
  473. strcat(szString, "\"");
  474. WritePrivateProfileStringA("Moved", szString, "", pszInfName);
  475. }
  476. }
  477. VOID
  478. WriteRegistryEntryHandled(
  479. IN LPCSTR pszInfName,
  480. IN LPCSTR pszRegEntry
  481. )
  482. /*++
  483. Routine Description:
  484. Writes a registry entry which is being handled by printer upgrade code in
  485. migrate.inf. Setup looks at these entries across all mig dlls to see what
  486. componnets can't be upgraded.
  487. Arguments:
  488. pszInfName : Full path to the migrate.inf
  489. pszRegEntry : Fully qualified registry entry which is handled
  490. Return Value:
  491. None
  492. --*/
  493. {
  494. WritePrivateProfileStringA("Handled", pszRegEntry, "\"Registry\"", pszInfName);
  495. }
  496. BOOL
  497. IsAnICMFile(
  498. IN LPCSTR pszFileName
  499. )
  500. {
  501. DWORD dwLen = strlen(pszFileName);
  502. LPCSTR psz = pszFileName + dwLen - 4;
  503. if ( dwLen > 3 && (!_strcmpi(psz, ".ICM") || !_strcmpi(psz, ".ICC")) )
  504. return TRUE;
  505. return FALSE;
  506. }
  507. VOID
  508. LogDriverEntry(
  509. IN LPCSTR pszInfName,
  510. IN LPDRIVER_INFO_3A pDriverInfo3,
  511. IN BOOL bUpgradable
  512. )
  513. /*++
  514. Routine Description:
  515. Log information about a printer driver in the migrate.inf.
  516. Write all printer driver files to be deleted. Also if a matching NT
  517. driver is found write the driver as handled.
  518. Arguments:
  519. pszInfName : Full path to the migrate.inf
  520. pDriverInfo3 : Pointer to DRIVER_INFO_3A of the driver
  521. bUpgradable : If TRUE a matching NT driver is found
  522. Return Value:
  523. None
  524. --*/
  525. {
  526. CHAR szRegDrvPrefix[] = "Environments\\Windows 4.0\\Drivers\\";
  527. LPSTR psz;
  528. DWORD dwLen;
  529. //
  530. // Write each driver file as to be deleted
  531. //
  532. for ( psz = pDriverInfo3->pDependentFiles ;
  533. psz && *psz ;
  534. psz += strlen(psz) + 1) {
  535. //
  536. // ICM migration dll will handle color profiles
  537. //
  538. if ( IsAnICMFile(psz) )
  539. continue;
  540. WriteFileToBeDeletedInInf(pszInfName, psz);
  541. }
  542. //
  543. // If a matching NT driver entry is found make an entry to indicate the
  544. // driver will be upgraded against the registry entry name'
  545. //
  546. if ( !bUpgradable )
  547. return;
  548. dwLen = strlen(szRegPrefix) + strlen(szRegDrvPrefix)
  549. + strlen(pDriverInfo3->pName) + 3;
  550. if ( !(psz = AllocMem(dwLen * sizeof(CHAR))) )
  551. return;
  552. *psz = '"';
  553. strcpy(psz + 1, szRegPrefix);
  554. strcat(psz, szRegDrvPrefix);
  555. strcat(psz, pDriverInfo3->pName);
  556. strcat(psz, "\"");
  557. WriteRegistryEntryHandled(pszInfName, psz);
  558. FreeMem(psz);
  559. }
  560. VOID
  561. LogMonitorEntry(
  562. IN LPCSTR pszInfName,
  563. IN LPMONITOR_INFO_1A pMonitorInfo1,
  564. IN BOOL bUpgradable
  565. )
  566. /*++
  567. Routine Description:
  568. Log information about a print monitor in the migrate.inf. Write the
  569. monitor.dll to be deleted. Also if the monitor will be upgraded write
  570. it in the handled section
  571. Arguments:
  572. pszInfName : Full path to the migrate.inf
  573. pMonitorInfo1 : Pointer to MONITOR_INFO_1A of the monitor
  574. bUpgradable : If TRUE a matching NT driver is found
  575. Return Value:
  576. None
  577. --*/
  578. {
  579. CHAR szRegMonPrefix[] = "Monitors\\";
  580. LPSTR psz;
  581. DWORD dwLen;
  582. //
  583. // If a matching NT driver entry is found make an entry to indicate the
  584. // driver will be upgraded against the registry entry name'
  585. //
  586. if ( !bUpgradable )
  587. return;
  588. dwLen = strlen(szRegPrefix) + strlen(szRegMonPrefix)
  589. + strlen(pMonitorInfo1->pName) + 3;
  590. if ( !(psz = AllocMem(dwLen * sizeof(CHAR))) )
  591. return;
  592. *psz = '"';
  593. strcpy(psz + 1, szRegPrefix);
  594. strcat(psz, szRegMonPrefix);
  595. strcat(psz, pMonitorInfo1->pName);
  596. strcat(psz, "\"");
  597. WriteRegistryEntryHandled(pszInfName, psz);
  598. FreeMem(psz);
  599. }
  600. VOID
  601. LogPrinterEntry(
  602. IN LPCSTR pszInfName,
  603. IN LPPRINTER_INFO_2A pPrinterInfo2,
  604. IN BOOL bUpgradable
  605. )
  606. /*++
  607. Routine Description:
  608. Log information about a printer in the migrate.inf.
  609. If the printer will be upgraded write it in the handled section.
  610. Otherwise we will write a incompatibility message.
  611. Arguments:
  612. pszInfName : Full path to the migrate.inf
  613. pPrinterInfo2 : Pointer to PRINTER_INFO_2A of the printer
  614. bUpgradable : If TRUE printer will be migrated, else not
  615. Return Value:
  616. None
  617. --*/
  618. {
  619. CHAR szRegPath[MAX_PATH], szPrefix[] = "\\Hardware\\";
  620. LPSTR psz, psz2, psz3;
  621. DWORD dwLen;
  622. if ( !RegPathFromPrinter(pPrinterInfo2->pPrinterName,
  623. szRegPath,
  624. MAX_PATH) ) {
  625. return;
  626. }
  627. if ( bUpgradable ) {
  628. WriteRegistryEntryHandled(pszInfName, szRegPath);
  629. } else {
  630. dwLen = strlen(pPrinterInfo2->pPrinterName) + strlen(szPrefix) + 3;
  631. psz2 = AllocMem(dwLen * sizeof(CHAR));
  632. if ( psz2 ) {
  633. sprintf(psz2, "%s%s", szPrefix, pPrinterInfo2->pPrinterName);
  634. WritePrivateProfileStringA(psz2,
  635. szRegPath,
  636. "\"Registry\"",
  637. pszInfName);
  638. if ( psz = GetStringFromRcFileA(IDS_PRINTER_CANT_MIGRATE) ) {
  639. dwLen = strlen(psz) + strlen(psz2);
  640. if ( psz3 = AllocMem(dwLen * sizeof(CHAR)) ) {
  641. sprintf(psz3, psz, pPrinterInfo2->pPrinterName);
  642. WritePrivateProfileStringA("Incompatible Messages",
  643. psz2,
  644. psz3,
  645. pszInfName);
  646. FreeMem(psz3);
  647. }
  648. FreeMem(psz);
  649. }
  650. FreeMem(psz2);
  651. }
  652. }
  653. }
  654. VOID
  655. ProcessPrinterDrivers(
  656. IN HANDLE hFile,
  657. IN LPCSTR pszInfName,
  658. IN HWND hwnd,
  659. OUT PDRIVER_INFO_9X *ppDriverInfo9x,
  660. IN OUT LPBOOL pbFail
  661. )
  662. /*++
  663. Routine Description:
  664. Process printer drivers for upgrade
  665. Arguments:
  666. hFile : Handle to print9x.txt. Printing configuration
  667. info is written here for use on NT side
  668. pszInfName : Inf name to log upgrade info
  669. hwnd : Parent window handle for any UI
  670. DiskSpaceList : Handle to disk space list to queue up file operations
  671. ppDriverInfo9x : On return gives the list of printer drivers and
  672. their Nt names
  673. pbFail : Set on an error -- no more processing needed
  674. Return Value:
  675. None
  676. --*/
  677. {
  678. LPBYTE pBuf = NULL;
  679. DWORD dwNeeded, dwReturned;
  680. LPSTR psz, pszNtModelName;
  681. HDEVINFO hDevInfo;
  682. HINF hUpgInf, hNtInf;
  683. LPDRIVER_INFO_3A pDriverInfo3;
  684. PDRIVER_INFO_9X pCur;
  685. hDevInfo = hUpgInf = hNtInf = INVALID_HANDLE_VALUE;
  686. //
  687. // Get the list of drivers installed from spooler
  688. if ( *pbFail ||
  689. EnumPrinterDriversA(NULL,
  690. NULL,
  691. 3,
  692. NULL,
  693. 0,
  694. &dwNeeded,
  695. &dwReturned) ) {
  696. if ( !*pbFail )
  697. WriteToFile(hFile, pbFail, "[PrinterDrivers]\n");
  698. goto Cleanup;
  699. }
  700. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  701. !(pBuf = AllocMem(dwNeeded)) ||
  702. !EnumPrinterDriversA(NULL,
  703. NULL,
  704. 3,
  705. pBuf,
  706. dwNeeded,
  707. &dwNeeded,
  708. &dwReturned) ) {
  709. *pbFail = TRUE;
  710. goto Cleanup;
  711. }
  712. InitDriverMapping(&hDevInfo, &hNtInf, &hUpgInf, pbFail);
  713. //
  714. // For each driver ...
  715. // If we find a suitable NT driver name write it to file
  716. // else write Win95 name with a * at the beginning of the line
  717. // to tell this can't be upgraded (but log error on NT)
  718. //
  719. WriteToFile(hFile, pbFail, "[PrinterDrivers]\n");
  720. for ( dwNeeded = 0, pDriverInfo3 = (LPDRIVER_INFO_3A)pBuf ;
  721. dwNeeded < dwReturned ;
  722. ++dwNeeded, ++pDriverInfo3 ) {
  723. if (IsIgnoredDriver(pDriverInfo3->pName))
  724. {
  725. continue;
  726. }
  727. pszNtModelName = FindNtModelNameFromWin95Name(hDevInfo,
  728. hNtInf,
  729. hUpgInf,
  730. pDriverInfo3->pName,
  731. pbFail);
  732. if ( !(pCur = AllocateDriverInfo9x(pszNtModelName,
  733. pDriverInfo3->pName,
  734. pbFail)) ) {
  735. FreeMem(pszNtModelName);
  736. goto Cleanup;
  737. }
  738. //
  739. // Add the info in the linked lise
  740. //
  741. if ( *ppDriverInfo9x )
  742. pCur->pNext = *ppDriverInfo9x;
  743. *ppDriverInfo9x = pCur;
  744. //
  745. // If pszNtModelName is NULL we could not decide which driver to
  746. // install
  747. //
  748. if ( pszNtModelName ) {
  749. LogDriverEntry(pszInfName, pDriverInfo3, TRUE);
  750. WriteString(hFile, pbFail, pszNtModelName);
  751. } else {
  752. LogDriverEntry(pszInfName, pDriverInfo3, FALSE);
  753. WriteString(hFile, pbFail, pDriverInfo3->pName);
  754. }
  755. FreeMem(pszNtModelName);
  756. }
  757. Cleanup:
  758. WriteToFile(hFile, pbFail, "\n");
  759. //
  760. // Close all the inf since we do not need them
  761. //
  762. CleanupDriverMapping(&hDevInfo, &hNtInf, &hUpgInf);
  763. FreeMem(pBuf);
  764. }
  765. VOID
  766. FixupPrinterInfo2(
  767. LPPRINTER_INFO_2A pPrinterInfo2
  768. )
  769. /*++
  770. Routine Description:
  771. Fixup the PRINTER_INFO_2 we got from Win95 spooler before writing to the
  772. text file so that AddPrinter will be ok on NT side
  773. Arguments:
  774. pPrinterInfo2 : Points to the PRINTER_INFO_2
  775. Return Value:
  776. None
  777. --*/
  778. {
  779. //
  780. // Default datatype is always RAW
  781. //
  782. pPrinterInfo2->pDatatype = cszRaw;
  783. //
  784. // Only print processor for in-box drivers is winprint
  785. //
  786. pPrinterInfo2->pPrintProcessor = cszWinPrint;
  787. //
  788. // Remove the enable bidi bit. NT driver may or may not have a LM
  789. // If it does AddPrinter on NT automatically enables bidi
  790. //
  791. pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  792. //
  793. // Remove the work-offline bit. It makes no sense to carry it over.
  794. // With network printers this is a big problem because Win2K does not set
  795. // work offline, and UI does not allow user to disable it if set.
  796. //
  797. pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_WORK_OFFLINE;
  798. //
  799. // Ignore Win9x separator page
  800. //
  801. pPrinterInfo2->pSepFile = NULL;
  802. //
  803. // We will ignore PRINTER_STATUS_PENDING_DELETION and still add it on NT
  804. //
  805. }
  806. VOID
  807. ProcessPrinters(
  808. IN HANDLE hFile,
  809. IN HANDLE hFile2,
  810. IN LPCSTR pszInfName,
  811. IN PDRIVER_INFO_9X pDriverInfo9x,
  812. IN OUT LPBOOL pbFail
  813. )
  814. /*++
  815. Routine Description:
  816. Process printers for upgrade
  817. Arguments:
  818. hFile : Handle to print9x.txt. Printing configuration
  819. info is written here for use on NT side
  820. hFile2 : Handle to netwkprn.txt
  821. pDriverInfo9x : Gives the list of drivers and corresponding NT drivers
  822. pbFail : Set on an error -- no more processing needed
  823. Return Value:
  824. None
  825. --*/
  826. {
  827. LPBYTE pBuf1 = NULL;
  828. BOOL bFirst = TRUE, bFound;
  829. DWORD dwLevel, dwNeeded, dwPrinters, dwSize, dwIndex;
  830. LPPRINTER_INFO_2A pPrinterInfo2;
  831. PDRIVER_INFO_9X pCur;
  832. PUPGRADABLE_LIST pUpg;
  833. LPSTR pWinIniPorts = NULL, psz;
  834. //
  835. // Get the list of printers installed from spooler
  836. //
  837. if ( *pbFail ||
  838. EnumPrintersA(PRINTER_ENUM_LOCAL,
  839. NULL,
  840. 2,
  841. NULL,
  842. 0,
  843. &dwNeeded,
  844. &dwPrinters) ) {
  845. if ( !*pbFail )
  846. WriteToFile(hFile, pbFail, "[Ports]\n\n[Printers]\n");
  847. goto Cleanup;
  848. }
  849. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  850. !(pBuf1 = AllocMem(dwNeeded)) ||
  851. !EnumPrintersA(PRINTER_ENUM_LOCAL,
  852. NULL,
  853. 2,
  854. pBuf1,
  855. dwNeeded,
  856. &dwNeeded,
  857. &dwPrinters) ) {
  858. *pbFail = TRUE;
  859. goto Cleanup;
  860. }
  861. //
  862. // Extract all the used local ports
  863. //
  864. WriteToFile(hFile, pbFail, "[Ports]\n");
  865. for ( dwNeeded = 0, pPrinterInfo2 = (LPPRINTER_INFO_2A)pBuf1 ;
  866. dwNeeded < dwPrinters ;
  867. ++dwNeeded, ++pPrinterInfo2 )
  868. {
  869. DWORD i;
  870. //
  871. // check for ignored drivers
  872. //
  873. if (IsIgnoredDriver(pPrinterInfo2->pDriverName))
  874. {
  875. continue;
  876. }
  877. //
  878. // Point-and-print printers are processed through netwkprn.txt
  879. //
  880. if (pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_NETWORK)
  881. {
  882. continue;
  883. }
  884. //
  885. // check whether portname has been processed already
  886. //
  887. for (i = 0; i < dwNeeded; i++ )
  888. {
  889. if (strcmp(pPrinterInfo2->pPortName, (((LPPRINTER_INFO_2A)pBuf1)+i)->pPortName) == 0)
  890. {
  891. break;
  892. }
  893. }
  894. if (i < dwNeeded)
  895. {
  896. DebugMsg("Port with multiple attached printers skipped");
  897. continue;
  898. }
  899. //
  900. // if the printers is a FILE, LPT*: or COM*: port do nothing
  901. //
  902. if (_strnicmp(pPrinterInfo2->pPortName, "FILE:", 5) == 0)
  903. {
  904. DebugMsg("FILE: port skipped");
  905. continue;
  906. }
  907. if ((_strnicmp(pPrinterInfo2->pPortName, "COM", 3) == 0) ||
  908. (_strnicmp(pPrinterInfo2->pPortName, "LPT", 3) == 0) )
  909. {
  910. LPSTR psz = pPrinterInfo2->pPortName + 3;
  911. if (isdigit(*psz))
  912. {
  913. do
  914. {
  915. psz++;
  916. } while ( isdigit(*psz) );
  917. if (*psz == ':')
  918. {
  919. DebugMsg("Local port COMx:/LPTx skipped");
  920. continue;
  921. }
  922. }
  923. }
  924. //
  925. // check whether the port is listed in win.ini - if so, it's a local port that needs to be migrated
  926. // if not, it's a third-party port that won't be migrated - warn !
  927. //
  928. //
  929. // retrieve the win.ini section on ports only once
  930. //
  931. if (!pWinIniPorts)
  932. {
  933. DWORD dwBufSize = 32767; // this is the max. size acc. to MSDN
  934. pWinIniPorts = AllocMem(dwBufSize);
  935. if (!pWinIniPorts)
  936. {
  937. *pbFail = TRUE;
  938. goto Cleanup;
  939. }
  940. GetProfileSection("Ports", pWinIniPorts, dwBufSize);
  941. }
  942. //
  943. // search for the current port within the section, note that the entry is in the form
  944. // <portname>=
  945. // so I need to skip the = at the end
  946. //
  947. for (psz = pWinIniPorts; *psz ; psz += strlen(psz) + 1)
  948. {
  949. if (_strnicmp(pPrinterInfo2->pPortName, psz, strlen(pPrinterInfo2->pPortName)) == 0)
  950. {
  951. break;
  952. }
  953. }
  954. if (!*psz)
  955. {
  956. //
  957. // not found - this printer queue will not be migrated !
  958. //
  959. LogPrinterEntry(pszInfName, pPrinterInfo2, FALSE);
  960. }
  961. else
  962. {
  963. //
  964. // found - write the entry for it to allow creation of the port on the NT side
  965. //
  966. WriteToFile(hFile, pbFail, "PortName: ");
  967. WriteString(hFile, pbFail, pPrinterInfo2->pPortName);
  968. }
  969. }
  970. //
  971. // Write the PRINTER_INFO_2 in the print95.txt file
  972. //
  973. WriteToFile(hFile, pbFail, "\n[Printers]\n");
  974. WriteToFile(hFile2, pbFail, "[Printers]\n");
  975. for ( dwNeeded = 0, pPrinterInfo2 = (LPPRINTER_INFO_2A)pBuf1 ;
  976. dwNeeded < dwPrinters ;
  977. ++dwNeeded, ++pPrinterInfo2 ) {
  978. //
  979. // check for ignored drivers
  980. //
  981. if (IsIgnoredDriver(pPrinterInfo2->pDriverName))
  982. {
  983. continue;
  984. }
  985. FixupPrinterInfo2(pPrinterInfo2);
  986. //
  987. // Find the driver name from the installed drivers on Win9x and get
  988. // the NT driver name
  989. //
  990. for ( pCur = pDriverInfo9x ;
  991. pCur && _strcmpi(pCur->pszWin95Name, pPrinterInfo2->pDriverName) ;
  992. pCur = pCur->pNext )
  993. ;
  994. if ( !pCur ) {
  995. ASSERT(pCur != NULL);
  996. *pbFail = TRUE;
  997. goto Cleanup;
  998. }
  999. //
  1000. // Pass the NT driver name here. If it is not NULL that gets written
  1001. // to the file, we won't need Win9x driver name on NT. If can't find
  1002. // an NT driver we will just write the Win9x driver name. It will be
  1003. // useful for error loggging
  1004. //
  1005. if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_NETWORK ) {
  1006. ++dwNetPrinters;
  1007. WritePrinterInfo2(hFile2, pPrinterInfo2, pCur->pszNtName, pbFail);
  1008. } else {
  1009. //
  1010. // If the printer is shared write it to network printer file too
  1011. // since it needs to be shared when user logs in for the first time
  1012. //
  1013. if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  1014. ++dwSharedPrinters;
  1015. WritePrinterInfo2(hFile2, pPrinterInfo2, pCur->pszNtName, pbFail);
  1016. pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  1017. }
  1018. WritePrinterInfo2(hFile, pPrinterInfo2, pCur->pszNtName, pbFail);
  1019. }
  1020. //
  1021. // Now see if this printer is going to disappear on NT:
  1022. // Check if an NT driver is found
  1023. //
  1024. LogPrinterEntry(pszInfName, pPrinterInfo2, pCur->pszNtName != NULL);
  1025. }
  1026. Cleanup:
  1027. if (pWinIniPorts)
  1028. {
  1029. FreeMem(pWinIniPorts);
  1030. }
  1031. WriteToFile(hFile, pbFail, "\n");
  1032. FreeMem(pBuf1);
  1033. }
  1034. VOID
  1035. ProcessPrintMonitors(
  1036. IN LPCSTR pszInfName
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. Process print monitors for upgrade.
  1041. We just look for monitors which are not in the list of upgradable monitors
  1042. and add to the unupgradable list so that we can warn the user
  1043. Arguments:
  1044. pszInfName : Inf name to log upgrade info
  1045. Return Value:
  1046. None
  1047. --*/
  1048. {
  1049. LPBYTE pBuf = NULL;
  1050. DWORD dwCount, dwNeeded, dwReturned;
  1051. LPSTR psz;
  1052. LPMONITOR_INFO_1A pMonitorInfo1;
  1053. PUPGRADABLE_LIST pUpg;
  1054. BOOL bFound;
  1055. if ( EnumMonitorsA(NULL,
  1056. 1,
  1057. NULL,
  1058. 0,
  1059. &dwNeeded,
  1060. &dwReturned) ||
  1061. GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  1062. !(pBuf = AllocMem(dwNeeded)) ||
  1063. !EnumMonitorsA(NULL,
  1064. 1,
  1065. pBuf,
  1066. dwNeeded,
  1067. &dwNeeded,
  1068. &dwReturned) ) {
  1069. goto Cleanup;
  1070. }
  1071. for ( dwNeeded = dwCount = 0, pMonitorInfo1 = (LPMONITOR_INFO_1A)pBuf ;
  1072. dwCount < dwReturned ;
  1073. ++dwCount, ++pMonitorInfo1 ) {
  1074. for ( pUpg = UpgradableMonitors, bFound = FALSE ;
  1075. pUpg->pszName ; ++pUpg ) {
  1076. if ( !strcmp(pMonitorInfo1->pName, pUpg->pszName) ) {
  1077. bFound = TRUE;
  1078. break;
  1079. }
  1080. }
  1081. LogMonitorEntry(pszInfName, pMonitorInfo1, bFound);
  1082. }
  1083. Cleanup:
  1084. FreeMem(pBuf);
  1085. }
  1086. LONG
  1087. CALLBACK
  1088. MigrateSystem9x(
  1089. IN HWND hwndParent,
  1090. IN LPCSTR pszUnattendFile,
  1091. LPVOID Reserved
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Process system setttings for printing. This does all the work for printing
  1096. upgrade
  1097. Arguments:
  1098. hwndParent : Parent window for any UI
  1099. pszUnattendFile : Pointer to unattend file
  1100. pqwDiskSpace : On return gives the additional disk space needed on NT
  1101. Return Value:
  1102. Win32 error code
  1103. --*/
  1104. {
  1105. BOOL bFail = FALSE;
  1106. DWORD dwRet;
  1107. HANDLE hFile, hFile2;
  1108. CHAR szFile[MAX_PATH], szInfName[MAX_PATH];
  1109. PDRIVER_INFO_9X pDriverInfo9x = NULL;
  1110. #if DBG
  1111. CHAR szFile2[MAX_PATH];
  1112. #endif
  1113. wsprintfA(szFile, "%s\\%s", UpgradeData.pszDir, "print95.txt");
  1114. wsprintfA(szInfName, "%s\\%s", UpgradeData.pszDir, "migrate.inf");
  1115. hFile = CreateFileA(szFile,
  1116. GENERIC_WRITE,
  1117. 0,
  1118. NULL,
  1119. CREATE_ALWAYS,
  1120. FILE_ATTRIBUTE_NORMAL,
  1121. NULL);
  1122. wsprintfA(szFile, "%s\\%s", UpgradeData.pszDir, szNetprnFile);
  1123. hFile2 = CreateFileA(szFile,
  1124. GENERIC_WRITE,
  1125. 0,
  1126. NULL,
  1127. CREATE_ALWAYS,
  1128. FILE_ATTRIBUTE_NORMAL,
  1129. NULL);
  1130. if ( hFile == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE ) {
  1131. bFail = TRUE;
  1132. goto Cleanup;
  1133. }
  1134. ProcessPrinterDrivers(hFile,
  1135. szInfName,
  1136. hwndParent,
  1137. &pDriverInfo9x,
  1138. &bFail);
  1139. ProcessPrintMonitors(szInfName);
  1140. ProcessPrinters(hFile,
  1141. hFile2,
  1142. szInfName,
  1143. pDriverInfo9x,
  1144. &bFail);
  1145. //
  1146. // If no network, shared printers found remove netwkprn.txt since it will be
  1147. // empty
  1148. //
  1149. if ( dwNetPrinters == 0 && dwSharedPrinters == 0 ) {
  1150. CloseHandle(hFile2);
  1151. hFile2 = INVALID_HANDLE_VALUE;
  1152. DeleteFileA(szFile);
  1153. }
  1154. Cleanup:
  1155. if ( hFile != INVALID_HANDLE_VALUE )
  1156. CloseHandle(hFile);
  1157. if ( hFile2 != INVALID_HANDLE_VALUE )
  1158. CloseHandle(hFile2);
  1159. DestroyDriverInfo9xList(pDriverInfo9x);
  1160. #if DBG
  1161. //
  1162. // Make a copy in temp dir on debug builds so that if we messed up the
  1163. // upgrade we can figure out what went wrong.
  1164. // Setup deletes the working directory.
  1165. //
  1166. if ( GetTempPathA(SIZECHARS(szFile2), szFile2) ) {
  1167. wsprintfA(szFile, "%s\\%s", UpgradeData.pszDir, "print95.txt");
  1168. strcat(szFile2, "print95.txt");
  1169. CopyFileA(szFile, szFile2, FALSE);
  1170. }
  1171. #endif
  1172. dwRet = bFail ? GetLastError() : ERROR_SUCCESS;
  1173. if ( bFail && dwRet == ERROR_SUCCESS )
  1174. dwRet = STG_E_UNKNOWN;
  1175. if ( bFail )
  1176. DebugMsg("MigrateSystem9x failed with %d", dwRet);
  1177. return dwRet;
  1178. }
  1179. //
  1180. // The following are to make sure if setup changes the header file they
  1181. // first tell me (otherwise they will break build of this)
  1182. //
  1183. P_INITIALIZE_9X pfnInitialize9x = Initialize9x;
  1184. P_MIGRATE_USER_9X pfnMigrateUser9x = MigrateUser9x;
  1185. P_MIGRATE_SYSTEM_9X pfnMigrateSystem9x = MigrateSystem9x;