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.

583 lines
15 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Network.c
  6. Abstract:
  7. Routines to migrate Win95 network printers to NT via using RunOnce entries
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 18-Aug-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. BOOL bDoNetPrnUpgrade = FALSE;
  14. LPSTR pszNetPrnEntry = NULL;
  15. CHAR szSpool[] = "\\spool\\";
  16. CHAR szMigDll[] = "migrate.dll";
  17. CHAR szRunOnceCount[] = "RunOnceCount";
  18. CHAR szRunOnceCountPath[] = "System\\CurrentControlSet\\control\\Print";
  19. CHAR szRunOnceRegistryPath[] = "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
  20. //
  21. // This is stored in the registry so when network printer upgrade using
  22. // RunOnce key is tries enough times without success we can delete files
  23. //
  24. #define MIN_NETWORK_PRN_RETRIES 5
  25. DWORD dwRunOnceCount = 0;
  26. LPSTR
  27. GetRunOnceValueToSet(
  28. )
  29. /*++
  30. --*/
  31. {
  32. CHAR szPath[MAX_PATH];
  33. DWORD dwLen, dwSize;
  34. LPSTR pszRet = NULL;
  35. dwSize = sizeof(szPath)/sizeof(szPath[0]);
  36. if ( !(dwLen = GetFileNameInSpoolDir(szPath, dwSize, szMigDll)) )
  37. goto Done;
  38. //
  39. // Now build up the RunOnce key which will be set for each user
  40. //
  41. dwSize = strlen("rundll32.exe") + dwLen +
  42. + strlen("ProcessWin9xNetworkPrinters") + 4;
  43. if ( pszRet = AllocMem(dwSize * sizeof(CHAR)) )
  44. StringCchPrintfA(pszRet, dwSize,
  45. "rundll32.exe %s,ProcessWin9xNetworkPrinters",
  46. szPath);
  47. Done:
  48. return pszRet;
  49. }
  50. VOID
  51. SetupNetworkPrinterUpgrade(
  52. IN LPCSTR pszWorkingDir
  53. )
  54. /*++
  55. Routine Description:
  56. This is called during InitializeSystemNT to setup the upgrade of network
  57. printers
  58. Arguments:
  59. pszWorkingDir : Gives the working directory assigned for printing
  60. Return Value:
  61. None
  62. If everything was setup right bDoNetPrnUpgrade is TRUE, and pszNetPrnEntry
  63. is the value to set in per user registry for RunOnce
  64. --*/
  65. {
  66. CHAR szSource[MAX_PATH], szTarget[MAX_PATH];
  67. DWORD dwSize, dwLen;
  68. //
  69. // First check if the source paths is ok
  70. //
  71. dwLen = strlen(szNetprnFile);
  72. dwSize = sizeof(szTarget)/sizeof(szTarget[0]);
  73. if ( strlen(pszWorkingDir) + dwLen + 2 > dwSize )
  74. return;
  75. //
  76. // Need to make a copy of migrate.dll and netwkprn.txt to
  77. // the %windir%\system32\spool directory
  78. //
  79. StringCchPrintfA(szSource, SIZECHARS(szSource), "%s\\%s", pszWorkingDir, szNetprnFile);
  80. if ( !GetFileNameInSpoolDir(szTarget, dwSize, szNetprnFile) ||
  81. !CopyFileA(szSource, szTarget, FALSE) )
  82. return;
  83. if (!MakeACopyOfMigrateDll( pszWorkingDir ))
  84. {
  85. return;
  86. }
  87. bDoNetPrnUpgrade = (pszNetPrnEntry = GetRunOnceValueToSet()) != NULL;
  88. }
  89. VOID
  90. WriteRunOnceCount(
  91. )
  92. /*++
  93. Routine Description:
  94. This routine is called to write the number of times we need to try the
  95. network printer upgrade
  96. Arguments:
  97. None
  98. Return Value:
  99. None
  100. --*/
  101. {
  102. HKEY hKey;
  103. DWORD dwSize;
  104. if ( dwRunOnceCount == 0 )
  105. return;
  106. //
  107. // We will try number of user + MIN_NETWORK_PRN_RETRIES till we succeed
  108. //
  109. dwRunOnceCount += MIN_NETWORK_PRN_RETRIES;
  110. if ( ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  111. szRunOnceCountPath,
  112. 0,
  113. KEY_WRITE,
  114. &hKey) )
  115. return;
  116. dwSize = sizeof(dwRunOnceCount);
  117. RegSetValueExA(hKey,
  118. szRunOnceCount,
  119. 0,
  120. REG_DWORD,
  121. (LPBYTE)&dwRunOnceCount,
  122. dwSize);
  123. RegCloseKey(hKey);
  124. }
  125. BOOL
  126. ProcessNetPrnUpgradeForUser(
  127. HKEY hKeyUser
  128. )
  129. /*++
  130. Routine Description:
  131. This is called during MigrateUserNT to handle network printer upgrade
  132. for the user
  133. Arguments:
  134. hKeyUser : Handle to the user registry key
  135. Return Value:
  136. Return TRUE on success, and FALSE else
  137. --*/
  138. {
  139. HKEY hKey = NULL;
  140. DWORD dwLastError;
  141. dwLastError = RegCreateKeyExA(hKeyUser,
  142. szRunOnceRegistryPath,
  143. 0,
  144. NULL,
  145. REG_OPTION_NON_VOLATILE,
  146. KEY_ALL_ACCESS,
  147. NULL,
  148. &hKey,
  149. NULL);
  150. if ( dwLastError == ERROR_SUCCESS ) {
  151. dwLastError = RegSetValueExA(hKey,
  152. "Printing Migration",
  153. 0,
  154. REG_SZ,
  155. pszNetPrnEntry,
  156. ( strlen(pszNetPrnEntry) + 1 )
  157. * sizeof(CHAR));
  158. #ifdef VERBOSE
  159. if ( dwLastError == ERROR_SUCCESS )
  160. DebugMsg("Wrote %s to %s", pszNetPrnEntry, szRunOnceRegistryPath);
  161. #endif
  162. }
  163. if ( hKey )
  164. RegCloseKey(hKey);
  165. if ( dwLastError ) {
  166. SetLastError(dwLastError);
  167. return FALSE;
  168. }
  169. return TRUE;
  170. }
  171. VOID
  172. DecrementRunOnceCount(
  173. IN DWORD dwDiff,
  174. IN BOOL bResetRunOnceForUser
  175. )
  176. /*++
  177. Routine Description:
  178. Called after once network printer upgrade is called when user logged in,
  179. so we can decrement the retry count
  180. When ref count reaches 0 we then we can delete the files
  181. Arguments:
  182. dwDiff : Value by which ref count should be decremented
  183. bResetRunOnceForUser : We need to set RunOnce key again for the user
  184. Return Value:
  185. None
  186. --*/
  187. {
  188. HKEY hKey;
  189. DWORD dwSize, dwCount, dwType;
  190. CHAR szPath[MAX_PATH];
  191. if ( ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  192. szRunOnceCountPath,
  193. 0,
  194. KEY_ALL_ACCESS,
  195. &hKey) )
  196. return;
  197. dwSize = sizeof(dwCount);
  198. if ( ERROR_SUCCESS == RegQueryValueExA(hKey, szRunOnceCount, 0, &dwType,
  199. (LPBYTE)&dwCount, &dwSize) ) {
  200. dwCount -= dwDiff;
  201. if ( dwCount ) {
  202. RegSetValueExA(hKey,
  203. szRunOnceCount,
  204. 0,
  205. REG_DWORD,
  206. (LPBYTE)&dwCount,
  207. dwSize);
  208. if ( bResetRunOnceForUser &&
  209. (pszNetPrnEntry = GetRunOnceValueToSet()) ) {
  210. ProcessNetPrnUpgradeForUser(HKEY_CURRENT_USER);
  211. FreeMem(pszNetPrnEntry);
  212. pszNetPrnEntry = NULL;
  213. #ifdef VERBOSE
  214. DebugMsg("Processing network/shared printers failed. Will try next time user logs in.");
  215. #endif
  216. }
  217. } else {
  218. dwSize = sizeof(szPath)/sizeof(szPath[0]);
  219. RegDeleteValueA(hKey, szRunOnceCount);
  220. if ( GetFileNameInSpoolDir(szPath, dwSize, szMigDll) )
  221. DeleteFileA(szPath);
  222. if ( GetFileNameInSpoolDir(szPath, dwSize, szNetprnFile) )
  223. DeleteFileA(szPath);
  224. DebugMsg("Giving up on setting network/shared printers");
  225. }
  226. }
  227. RegCloseKey(hKey);
  228. }
  229. BOOL
  230. AddNetworkPrinter(
  231. IN LPPRINTER_INFO_2A pPrinterInfo2
  232. )
  233. /*++
  234. Routine Description:
  235. This is called to add a windows 9x network printer. We will first try to
  236. make a conenction and if that fails we will add a masq. printer
  237. Arguments:
  238. pPrinterInfo2 : Pointer to printer info 2 of the printer
  239. Return Value:
  240. TRUE on success, FALSE else
  241. --*/
  242. {
  243. BOOL bRet = FALSE;
  244. LPSTR pszName, psz;
  245. HANDLE hPrinter = NULL;
  246. pszName = pPrinterInfo2->pPortName;
  247. if ( !OpenPrinterA(pszName, &hPrinter, NULL) ) {
  248. if ( psz = ErrorMsg() ) {
  249. DebugMsg("OpenPrinter failed for %s. %s", pszName, psz);
  250. FreeMem(psz);
  251. psz = NULL;
  252. }
  253. goto Done;
  254. }
  255. //
  256. // Try to make a printer connection. If that fails with some error
  257. // other than unknown driver create a masq printer
  258. //
  259. if ( AddPrinterConnectionA(pszName) ) {
  260. if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DEFAULT )
  261. SetDefaultPrinterA(pszName);
  262. bRet = TRUE;
  263. goto Done;
  264. }
  265. if ( GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER ) {
  266. if ( psz = ErrorMsg() ) {
  267. DebugMsg("AddPrinterConnection failed for %s. %s", pszName, psz);
  268. FreeMem(psz);
  269. psz = NULL;
  270. }
  271. goto Done;
  272. }
  273. ClosePrinter(hPrinter);
  274. //
  275. // Masc. printers should have port name, printer name both saying
  276. // \\server\share. Otherwise printui gets confused and does not refresh
  277. // server status correctly (this is since printui has to poll for masc.
  278. // printers)
  279. //
  280. // So we need to fixup PrinterInfo2 temporarily
  281. //
  282. psz = pPrinterInfo2->pPrinterName;
  283. pPrinterInfo2->pPrinterName = pPrinterInfo2->pPortName;
  284. if ( hPrinter = AddPrinterA(NULL, 2, (LPBYTE)pPrinterInfo2) ) {
  285. if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DEFAULT )
  286. SetDefaultPrinterA(pPrinterInfo2->pPrinterName);
  287. pPrinterInfo2->pPrinterName = psz;
  288. bRet = TRUE;
  289. goto Done;
  290. }
  291. pPrinterInfo2->pPrinterName = psz;
  292. if ( psz = ErrorMsg() ) {
  293. DebugMsg("AddPrinterA failed for %s. %s", pszName, psz);
  294. FreeMem(psz);
  295. psz = NULL;
  296. }
  297. Done:
  298. if ( hPrinter )
  299. ClosePrinter(hPrinter);
  300. return bRet;
  301. }
  302. BOOL
  303. SharePrinter(
  304. IN LPSTR pszPrinterName
  305. )
  306. /*++
  307. Routine Description:
  308. This is called to share a printer when the user logs in for the first time
  309. to NT. Printers can not be shared during GUI setup because we are not on
  310. the network yet.
  311. Arguments:
  312. pszPrinterName : Printer name
  313. Return Value:
  314. TRUE on success, FALSE else
  315. --*/
  316. {
  317. BOOL bRet = FALSE;
  318. DWORD dwNeeded;
  319. HANDLE hPrinter = NULL;
  320. LPBYTE pBuf = NULL;
  321. LPSTR psz;
  322. PRINTER_DEFAULTS PrinterDflts = { NULL, NULL, PRINTER_ALL_ACCESS };
  323. if ( !OpenPrinterA(pszPrinterName, &hPrinter, &PrinterDflts) ) {
  324. if ( psz = ErrorMsg() ) {
  325. DebugMsg("OpenPrinterA failed for %s. %s", pszPrinterName, psz);
  326. FreeMem(psz);
  327. psz = NULL;
  328. }
  329. goto Cleanup;
  330. }
  331. GetPrinterA(hPrinter, 2, NULL, 0, &dwNeeded);
  332. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  333. !(pBuf = AllocMem(dwNeeded)) ||
  334. !GetPrinterA(hPrinter, 2, pBuf, dwNeeded, &dwNeeded) ) {
  335. if ( psz = ErrorMsg() ) {
  336. DebugMsg("GetPrinterA failed for %s. %s", pszPrinterName, psz);
  337. FreeMem(psz);
  338. psz = NULL;
  339. }
  340. goto Cleanup;
  341. }
  342. ((LPPRINTER_INFO_2A)pBuf)->Attributes |= PRINTER_ATTRIBUTE_SHARED;
  343. bRet = SetPrinterA(hPrinter, 2, pBuf, 0);
  344. if ( !bRet && (psz = ErrorMsg()) ) {
  345. DebugMsg("OpenPrinterA failed for %s. %s", pszPrinterName, psz);
  346. FreeMem(psz);
  347. psz = NULL;
  348. }
  349. Cleanup:
  350. if ( hPrinter )
  351. ClosePrinter(hPrinter);
  352. FreeMem(pBuf);
  353. return bRet;
  354. }
  355. VOID
  356. ProcessWin9xNetworkPrinters(
  357. )
  358. /*++
  359. Routine Description:
  360. This is called the first time the user logs in to create network printer
  361. connections/masq printers.
  362. Reads the Win9x printing configuration we stored in the text file
  363. so that printing components can be upgraded
  364. Arguments:
  365. ppPrinterNode : Gives the list of netowrk printers on Win9x
  366. Return Value:
  367. TRUE on succesfully reading the config information, FALSE else
  368. --*/
  369. {
  370. BOOL bFail = FALSE, bSuccess = TRUE;
  371. HANDLE hFile = INVALID_HANDLE_VALUE;
  372. CHAR c, szFile[MAX_PATH], szLine[2*MAX_PATH];
  373. DWORD dwSize, dwLen;
  374. PRINTER_INFO_2A PrinterInfo2;
  375. #ifdef VERBOSE
  376. DebugMsg("ProcessWin9xNetworkPrinters called");
  377. #endif
  378. //
  379. // If file is not found quit
  380. //
  381. dwSize = sizeof(szFile)/sizeof(szFile[0]);
  382. if ( !GetFileNameInSpoolDir(szFile, dwSize, szNetprnFile) ) {
  383. DebugMsg("ProcessWin9xNetworkPrinters: GetFileNameInSpoolDir failed\n");
  384. goto Cleanup;
  385. }
  386. hFile = CreateFileA(szFile,
  387. GENERIC_READ,
  388. FILE_SHARE_READ,
  389. NULL,
  390. OPEN_EXISTING,
  391. FILE_ATTRIBUTE_NORMAL |
  392. FILE_FLAG_SEQUENTIAL_SCAN,
  393. NULL);
  394. if ( hFile == INVALID_HANDLE_VALUE ) {
  395. DebugMsg("ProcessWin9xNetworkPrinters: CreateFile failed with %d for %s",
  396. GetLastError(), szLine);
  397. goto Cleanup;
  398. }
  399. //
  400. // Read the printer info
  401. //
  402. if ( My_fgets(szLine, dwSize, hFile) == NULL ||
  403. strncmp(szLine, "[Printers]", strlen("[Printers]")) )
  404. goto Cleanup;
  405. do {
  406. c = (CHAR) My_fgetc(hFile);
  407. if ( c == EOF || c == '\n' )
  408. break; // Normal exit
  409. if ( c != 'S' || !My_ungetc(hFile) )
  410. goto Cleanup;
  411. ZeroMemory(&PrinterInfo2, sizeof(PrinterInfo2));
  412. ReadPrinterInfo2(hFile, &PrinterInfo2, &bFail);
  413. if ( bFail )
  414. goto Cleanup;
  415. //
  416. // If this was a network printer on Win9x it needs to be added as a
  417. // connection or as a masc printer
  418. //
  419. if ( PrinterInfo2.Attributes & PRINTER_ATTRIBUTE_NETWORK ) {
  420. if ( !AddNetworkPrinter(&PrinterInfo2) && bSuccess )
  421. bSuccess = FALSE;
  422. } else if ( PrinterInfo2.Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  423. if ( !SharePrinter(PrinterInfo2.pPrinterName) && bSuccess )
  424. bSuccess = FALSE;
  425. }
  426. } while ( !bFail );
  427. Cleanup:
  428. if ( hFile != INVALID_HANDLE_VALUE )
  429. CloseHandle(hFile);
  430. if ( bSuccess && !bFail )
  431. DecrementRunOnceCount(MIN_NETWORK_PRN_RETRIES, FALSE);
  432. else
  433. DecrementRunOnceCount(1, TRUE);
  434. }