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.

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