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
583 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Network.c
|
|
|
|
Abstract:
|
|
|
|
Routines to migrate Win95 network printers to NT via using RunOnce entries
|
|
|
|
Author:
|
|
|
|
Muhunthan Sivapragasam (MuhuntS) 18-Aug-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOL bDoNetPrnUpgrade = FALSE;
|
|
LPSTR pszNetPrnEntry = NULL;
|
|
CHAR szSpool[] = "\\spool\\";
|
|
CHAR szMigDll[] = "migrate.dll";
|
|
CHAR szRunOnceCount[] = "RunOnceCount";
|
|
CHAR szRunOnceCountPath[] = "System\\CurrentControlSet\\control\\Print";
|
|
CHAR szRunOnceRegistryPath[] = "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
|
|
//
|
|
// This is stored in the registry so when network printer upgrade using
|
|
// RunOnce key is tries enough times without success we can delete files
|
|
//
|
|
#define MIN_NETWORK_PRN_RETRIES 5
|
|
DWORD dwRunOnceCount = 0;
|
|
|
|
|
|
LPSTR
|
|
GetRunOnceValueToSet(
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
CHAR szPath[MAX_PATH];
|
|
DWORD dwLen, dwSize;
|
|
LPSTR pszRet = NULL;
|
|
|
|
dwSize = sizeof(szPath)/sizeof(szPath[0]);
|
|
|
|
if ( !(dwLen = GetFileNameInSpoolDir(szPath, dwSize, szMigDll)) )
|
|
goto Done;
|
|
|
|
//
|
|
// Now build up the RunOnce key which will be set for each user
|
|
//
|
|
dwSize = strlen("rundll32.exe") + dwLen +
|
|
+ strlen("ProcessWin9xNetworkPrinters") + 4;
|
|
|
|
if ( pszRet = AllocMem(dwSize * sizeof(CHAR)) )
|
|
StringCchPrintfA(pszRet, dwSize,
|
|
"rundll32.exe %s,ProcessWin9xNetworkPrinters",
|
|
szPath);
|
|
Done:
|
|
return pszRet;
|
|
}
|
|
|
|
|
|
VOID
|
|
SetupNetworkPrinterUpgrade(
|
|
IN LPCSTR pszWorkingDir
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is called during InitializeSystemNT to setup the upgrade of network
|
|
printers
|
|
|
|
Arguments:
|
|
pszWorkingDir : Gives the working directory assigned for printing
|
|
|
|
Return Value:
|
|
None
|
|
|
|
If everything was setup right bDoNetPrnUpgrade is TRUE, and pszNetPrnEntry
|
|
is the value to set in per user registry for RunOnce
|
|
|
|
--*/
|
|
{
|
|
CHAR szSource[MAX_PATH], szTarget[MAX_PATH];
|
|
DWORD dwSize, dwLen;
|
|
|
|
//
|
|
// First check if the source paths is ok
|
|
//
|
|
dwLen = strlen(szNetprnFile);
|
|
|
|
dwSize = sizeof(szTarget)/sizeof(szTarget[0]);
|
|
|
|
if ( strlen(pszWorkingDir) + dwLen + 2 > dwSize )
|
|
return;
|
|
|
|
//
|
|
// Need to make a copy of migrate.dll and netwkprn.txt to
|
|
// the %windir%\system32\spool directory
|
|
//
|
|
StringCchPrintfA(szSource, SIZECHARS(szSource), "%s\\%s", pszWorkingDir, szNetprnFile);
|
|
if ( !GetFileNameInSpoolDir(szTarget, dwSize, szNetprnFile) ||
|
|
!CopyFileA(szSource, szTarget, FALSE) )
|
|
return;
|
|
|
|
if (!MakeACopyOfMigrateDll( pszWorkingDir ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
bDoNetPrnUpgrade = (pszNetPrnEntry = GetRunOnceValueToSet()) != NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
WriteRunOnceCount(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is called to write the number of times we need to try the
|
|
network printer upgrade
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize;
|
|
|
|
if ( dwRunOnceCount == 0 )
|
|
return;
|
|
|
|
//
|
|
// We will try number of user + MIN_NETWORK_PRN_RETRIES till we succeed
|
|
//
|
|
dwRunOnceCount += MIN_NETWORK_PRN_RETRIES;
|
|
|
|
if ( ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
szRunOnceCountPath,
|
|
0,
|
|
KEY_WRITE,
|
|
&hKey) )
|
|
return;
|
|
|
|
dwSize = sizeof(dwRunOnceCount);
|
|
RegSetValueExA(hKey,
|
|
szRunOnceCount,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwRunOnceCount,
|
|
dwSize);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ProcessNetPrnUpgradeForUser(
|
|
HKEY hKeyUser
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is called during MigrateUserNT to handle network printer upgrade
|
|
for the user
|
|
|
|
Arguments:
|
|
hKeyUser : Handle to the user registry key
|
|
|
|
Return Value:
|
|
Return TRUE on success, and FALSE else
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwLastError;
|
|
|
|
dwLastError = RegCreateKeyExA(hKeyUser,
|
|
szRunOnceRegistryPath,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
NULL);
|
|
|
|
if ( dwLastError == ERROR_SUCCESS ) {
|
|
|
|
dwLastError = RegSetValueExA(hKey,
|
|
"Printing Migration",
|
|
0,
|
|
REG_SZ,
|
|
pszNetPrnEntry,
|
|
( strlen(pszNetPrnEntry) + 1 )
|
|
* sizeof(CHAR));
|
|
|
|
#ifdef VERBOSE
|
|
if ( dwLastError == ERROR_SUCCESS )
|
|
DebugMsg("Wrote %s to %s", pszNetPrnEntry, szRunOnceRegistryPath);
|
|
#endif
|
|
}
|
|
|
|
if ( hKey )
|
|
RegCloseKey(hKey);
|
|
|
|
if ( dwLastError ) {
|
|
|
|
SetLastError(dwLastError);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
DecrementRunOnceCount(
|
|
IN DWORD dwDiff,
|
|
IN BOOL bResetRunOnceForUser
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Called after once network printer upgrade is called when user logged in,
|
|
so we can decrement the retry count
|
|
|
|
When ref count reaches 0 we then we can delete the files
|
|
Arguments:
|
|
dwDiff : Value by which ref count should be decremented
|
|
bResetRunOnceForUser : We need to set RunOnce key again for the user
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize, dwCount, dwType;
|
|
CHAR szPath[MAX_PATH];
|
|
|
|
if ( ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
szRunOnceCountPath,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKey) )
|
|
return;
|
|
|
|
dwSize = sizeof(dwCount);
|
|
if ( ERROR_SUCCESS == RegQueryValueExA(hKey, szRunOnceCount, 0, &dwType,
|
|
(LPBYTE)&dwCount, &dwSize) ) {
|
|
|
|
dwCount -= dwDiff;
|
|
if ( dwCount ) {
|
|
|
|
RegSetValueExA(hKey,
|
|
szRunOnceCount,
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwCount,
|
|
dwSize);
|
|
|
|
if ( bResetRunOnceForUser &&
|
|
(pszNetPrnEntry = GetRunOnceValueToSet()) ) {
|
|
|
|
ProcessNetPrnUpgradeForUser(HKEY_CURRENT_USER);
|
|
FreeMem(pszNetPrnEntry);
|
|
pszNetPrnEntry = NULL;
|
|
|
|
#ifdef VERBOSE
|
|
DebugMsg("Processing network/shared printers failed. Will try next time user logs in.");
|
|
#endif
|
|
}
|
|
|
|
} else {
|
|
|
|
dwSize = sizeof(szPath)/sizeof(szPath[0]);
|
|
RegDeleteValueA(hKey, szRunOnceCount);
|
|
|
|
if ( GetFileNameInSpoolDir(szPath, dwSize, szMigDll) )
|
|
DeleteFileA(szPath);
|
|
|
|
if ( GetFileNameInSpoolDir(szPath, dwSize, szNetprnFile) )
|
|
DeleteFileA(szPath);
|
|
|
|
DebugMsg("Giving up on setting network/shared printers");
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
BOOL
|
|
AddNetworkPrinter(
|
|
IN LPPRINTER_INFO_2A pPrinterInfo2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is called to add a windows 9x network printer. We will first try to
|
|
make a conenction and if that fails we will add a masq. printer
|
|
|
|
Arguments:
|
|
pPrinterInfo2 : Pointer to printer info 2 of the printer
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPSTR pszName, psz;
|
|
HANDLE hPrinter = NULL;
|
|
|
|
pszName = pPrinterInfo2->pPortName;
|
|
|
|
if ( !OpenPrinterA(pszName, &hPrinter, NULL) ) {
|
|
|
|
if ( psz = ErrorMsg() ) {
|
|
|
|
DebugMsg("OpenPrinter failed for %s. %s", pszName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Try to make a printer connection. If that fails with some error
|
|
// other than unknown driver create a masq printer
|
|
//
|
|
if ( AddPrinterConnectionA(pszName) ) {
|
|
|
|
if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DEFAULT )
|
|
SetDefaultPrinterA(pszName);
|
|
bRet = TRUE;
|
|
goto Done;
|
|
}
|
|
|
|
if ( GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER ) {
|
|
|
|
if ( psz = ErrorMsg() ) {
|
|
|
|
DebugMsg("AddPrinterConnection failed for %s. %s", pszName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
goto Done;
|
|
}
|
|
|
|
ClosePrinter(hPrinter);
|
|
|
|
//
|
|
// Masc. printers should have port name, printer name both saying
|
|
// \\server\share. Otherwise printui gets confused and does not refresh
|
|
// server status correctly (this is since printui has to poll for masc.
|
|
// printers)
|
|
//
|
|
// So we need to fixup PrinterInfo2 temporarily
|
|
//
|
|
psz = pPrinterInfo2->pPrinterName;
|
|
pPrinterInfo2->pPrinterName = pPrinterInfo2->pPortName;
|
|
|
|
if ( hPrinter = AddPrinterA(NULL, 2, (LPBYTE)pPrinterInfo2) ) {
|
|
|
|
if ( pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DEFAULT )
|
|
SetDefaultPrinterA(pPrinterInfo2->pPrinterName);
|
|
|
|
pPrinterInfo2->pPrinterName = psz;
|
|
bRet = TRUE;
|
|
goto Done;
|
|
}
|
|
|
|
pPrinterInfo2->pPrinterName = psz;
|
|
|
|
if ( psz = ErrorMsg() ) {
|
|
|
|
DebugMsg("AddPrinterA failed for %s. %s", pszName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
|
|
Done:
|
|
if ( hPrinter )
|
|
ClosePrinter(hPrinter);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SharePrinter(
|
|
IN LPSTR pszPrinterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is called to share a printer when the user logs in for the first time
|
|
to NT. Printers can not be shared during GUI setup because we are not on
|
|
the network yet.
|
|
|
|
Arguments:
|
|
pszPrinterName : Printer name
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwNeeded;
|
|
HANDLE hPrinter = NULL;
|
|
LPBYTE pBuf = NULL;
|
|
LPSTR psz;
|
|
PRINTER_DEFAULTS PrinterDflts = { NULL, NULL, PRINTER_ALL_ACCESS };
|
|
|
|
if ( !OpenPrinterA(pszPrinterName, &hPrinter, &PrinterDflts) ) {
|
|
|
|
if ( psz = ErrorMsg() ) {
|
|
|
|
DebugMsg("OpenPrinterA failed for %s. %s", pszPrinterName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
GetPrinterA(hPrinter, 2, NULL, 0, &dwNeeded);
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(pBuf = AllocMem(dwNeeded)) ||
|
|
!GetPrinterA(hPrinter, 2, pBuf, dwNeeded, &dwNeeded) ) {
|
|
|
|
if ( psz = ErrorMsg() ) {
|
|
|
|
DebugMsg("GetPrinterA failed for %s. %s", pszPrinterName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
((LPPRINTER_INFO_2A)pBuf)->Attributes |= PRINTER_ATTRIBUTE_SHARED;
|
|
|
|
bRet = SetPrinterA(hPrinter, 2, pBuf, 0);
|
|
|
|
if ( !bRet && (psz = ErrorMsg()) ) {
|
|
|
|
DebugMsg("OpenPrinterA failed for %s. %s", pszPrinterName, psz);
|
|
FreeMem(psz);
|
|
psz = NULL;
|
|
}
|
|
|
|
Cleanup:
|
|
if ( hPrinter )
|
|
ClosePrinter(hPrinter);
|
|
FreeMem(pBuf);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
VOID
|
|
ProcessWin9xNetworkPrinters(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is called the first time the user logs in to create network printer
|
|
connections/masq printers.
|
|
Reads the Win9x printing configuration we stored in the text file
|
|
so that printing components can be upgraded
|
|
|
|
Arguments:
|
|
ppPrinterNode : Gives the list of netowrk printers on Win9x
|
|
|
|
Return Value:
|
|
TRUE on succesfully reading the config information, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bFail = FALSE, bSuccess = TRUE;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
CHAR c, szFile[MAX_PATH], szLine[2*MAX_PATH];
|
|
DWORD dwSize, dwLen;
|
|
PRINTER_INFO_2A PrinterInfo2;
|
|
|
|
#ifdef VERBOSE
|
|
DebugMsg("ProcessWin9xNetworkPrinters called");
|
|
#endif
|
|
//
|
|
// If file is not found quit
|
|
//
|
|
dwSize = sizeof(szFile)/sizeof(szFile[0]);
|
|
if ( !GetFileNameInSpoolDir(szFile, dwSize, szNetprnFile) ) {
|
|
|
|
DebugMsg("ProcessWin9xNetworkPrinters: GetFileNameInSpoolDir failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
hFile = CreateFileA(szFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
|
|
DebugMsg("ProcessWin9xNetworkPrinters: CreateFile failed with %d for %s",
|
|
GetLastError(), szLine);
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Read the printer info
|
|
//
|
|
if ( My_fgets(szLine, dwSize, hFile) == NULL ||
|
|
strncmp(szLine, "[Printers]", strlen("[Printers]")) )
|
|
goto Cleanup;
|
|
|
|
do {
|
|
|
|
c = (CHAR) My_fgetc(hFile);
|
|
|
|
if ( c == EOF || c == '\n' )
|
|
break; // Normal exit
|
|
|
|
if ( c != 'S' || !My_ungetc(hFile) )
|
|
goto Cleanup;
|
|
|
|
ZeroMemory(&PrinterInfo2, sizeof(PrinterInfo2));
|
|
|
|
ReadPrinterInfo2(hFile, &PrinterInfo2, &bFail);
|
|
|
|
if ( bFail )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// If this was a network printer on Win9x it needs to be added as a
|
|
// connection or as a masc printer
|
|
//
|
|
if ( PrinterInfo2.Attributes & PRINTER_ATTRIBUTE_NETWORK ) {
|
|
|
|
if ( !AddNetworkPrinter(&PrinterInfo2) && bSuccess )
|
|
bSuccess = FALSE;
|
|
} else if ( PrinterInfo2.Attributes & PRINTER_ATTRIBUTE_SHARED ) {
|
|
|
|
if ( !SharePrinter(PrinterInfo2.pPrinterName) && bSuccess )
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
} while ( !bFail );
|
|
|
|
|
|
Cleanup:
|
|
|
|
if ( hFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle(hFile);
|
|
|
|
if ( bSuccess && !bFail )
|
|
DecrementRunOnceCount(MIN_NETWORK_PRN_RETRIES, FALSE);
|
|
else
|
|
DecrementRunOnceCount(1, TRUE);
|
|
}
|