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.
 
 
 
 
 
 

1430 lines
35 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
All rights reserved.
Module Name:
Nt.c
Abstract:
Routines to migrate Win95 printing components to NT
Author:
Muhunthan Sivapragasam (MuhuntS) 02-Jan-1996
Revision History:
--*/
#include "precomp.h"
//
// Data structures to gather info from the text files created on Win95 to
// store the printing configuration
//
typedef struct _DRIVER_NODE {
struct _DRIVER_NODE *pNext;
DRIVER_INFO_1A DrvInfo1;
PPSETUP_LOCAL_DATA pLocalData;
BOOL bCantAdd;
} DRIVER_NODE, *PDRIVER_NODE;
typedef struct _PRINTER_NODE {
struct _PRINTER_NODE *pNext;
PRINTER_INFO_2A PrinterInfo2;
} PRINTER_NODE, *PPRINTER_NODE;
typedef struct _PORT_NODE {
struct _PORT_NODE *pNext;
LPSTR pPortName;
} PORT_NODE, *PPORT_NODE;
LPSTR pszDefaultPrinterString = NULL;
PPRINTER_NODE pDefPrinter = NULL;
//
// They kill the migration dll if it does not finish in 3 minutes.
// To prevent that I need to set this handle atleast every 3 mins
//
HANDLE hAlive = NULL;
//
// We want to lazy load ntprint.dll and mscms.dll.
// Note : If we link to them our DLL will not run on Win9x
//
struct {
HMODULE hNtPrint;
pfPSetupCreatePrinterDeviceInfoList pfnCreatePrinterDeviceInfoList;
pfPSetupDestroyPrinterDeviceInfoList pfnDestroyPrinterDeviceInfoList;
pfPSetupBuildDriversFromPath pfnBuildDriversFromPath;
pfPSetupDriverInfoFromName pfnDriverInfoFromName;
pfPSetupDestroySelectedDriverInfo pfnDestroySelectedDriverInfo;
pfPSetupGetLocalDataField pfnGetLocalDataField;
pfPSetupFreeDrvField pfnFreeDrvField;
pfPSetupProcessPrinterAdded pfnProcessPrinterAdded;
pfPSetupInstallICMProfiles pfnInstallICMProfiles;
pfPSetupAssociateICMProfiles pfnAssociateICMProfiles;
} LAZYLOAD_INFO;
VOID
FreePrinterNode(
IN PPRINTER_NODE pPrinterNode
)
/*++
Routine Description:
Free the memory allocated for a PRINTER_NODE element and strings in it
Arguments:
pPrinterNode : Points to the structure to free memory
Return Value:
None
--*/
{
FreePrinterInfo2Strings(&pPrinterNode->PrinterInfo2);
FreeMem(pPrinterNode);
}
VOID
FreePrinterNodeList(
IN PPRINTER_NODE pPrinterNode
)
/*++
Routine Description:
Free the memory allocated for elements in the PRINTER_NODE linked list
Arguments:
pPrinterNode : Points to the head of linked list to free memory
Return Value:
None
--*/
{
PPRINTER_NODE pNext;
while ( pPrinterNode ) {
pNext = pPrinterNode->pNext;
FreePrinterNode(pPrinterNode);
pPrinterNode = pNext;
}
}
VOID
FreeDriverNode(
IN PDRIVER_NODE pDriverNode
)
/*++
Routine Description:
Free the memory allocated for a DRIVER_NODE element and fields in it
Arguments:
pDriverNode : Points to the structure to free memory
Return Value:
None
--*/
{
if ( pDriverNode->pLocalData )
LAZYLOAD_INFO.pfnDestroySelectedDriverInfo(pDriverNode->pLocalData);
FreeMem(pDriverNode->DrvInfo1.pName);
FreeMem(pDriverNode);
}
VOID
FreeDriverNodeList(
IN PDRIVER_NODE pDriverNode
)
/*++
Routine Description:
Free the memory allocated for elements in the PDRIVER_NODE linked list
Arguments:
pDriverNode : Points to the head of linked list to free memory
Return Value:
None
--*/
{
PDRIVER_NODE pNext;
while ( pDriverNode ) {
pNext = pDriverNode->pNext;
FreeDriverNode(pDriverNode);
pDriverNode = pNext;
}
}
VOID
FreePortNode(
IN PPORT_NODE pPortNode
)
/*++
Routine Description:
Free the memory allocated for a PORT_NODE element and fields in it
Arguments:
PPORT_NODE : Points to the structure to free memory
Return Value:
None
--*/
{
if (pPortNode->pPortName)
{
FreeMem(pPortNode->pPortName);
}
FreeMem(pPortNode);
}
VOID
FreePortNodeList(
IN PPORT_NODE pPortNode
)
/*++
Routine Description:
Free the memory allocated for elements in the PORT_NODE linked list
Arguments:
pPortNode : Points to the head of linked list to free memory
Return Value:
None
--*/
{
PPORT_NODE pNext;
while ( pPortNode ) {
pNext = pPortNode->pNext;
FreePortNode(pPortNode);
pPortNode = pNext;
}
}
PPSETUP_LOCAL_DATA
FindLocalDataForDriver(
IN PDRIVER_NODE pDriverList,
IN LPSTR pszDriverName
)
/*++
Routine Description:
Find the local data for a given driver name from the list
Arguments:
Return Value:
Valid PPSETUP_LOCAL_DATA on success, else NULL
--*/
{
while ( pDriverList ) {
if ( !_strcmpi(pszDriverName, pDriverList->DrvInfo1.pName) )
return pDriverList->pLocalData;
pDriverList = pDriverList->pNext;
}
return NULL;
}
BOOL
InitLazyLoadInfo(
VOID
)
/*++
Routine Description:
Initializes the LAZYLOAD_INFO structure with LoadLibrary & GetProcAddress
Arguments:
None
Return Value:
TRUE on success, FALSE else
--*/
{
if ( LAZYLOAD_INFO.hNtPrint = LoadLibraryUsingFullPathA("ntprint.dll") ) {
(FARPROC)LAZYLOAD_INFO.pfnCreatePrinterDeviceInfoList
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupCreatePrinterDeviceInfoList");
(FARPROC)LAZYLOAD_INFO.pfnDestroyPrinterDeviceInfoList
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupDestroyPrinterDeviceInfoList");
(FARPROC)LAZYLOAD_INFO.pfnBuildDriversFromPath
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupBuildDriversFromPath");
(FARPROC)LAZYLOAD_INFO.pfnDriverInfoFromName
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupDriverInfoFromName");
(FARPROC)LAZYLOAD_INFO.pfnDestroySelectedDriverInfo
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupDestroySelectedDriverInfo");
(FARPROC)LAZYLOAD_INFO.pfnGetLocalDataField
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupGetLocalDataField");
(FARPROC)LAZYLOAD_INFO.pfnFreeDrvField
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupFreeDrvField");
(FARPROC)LAZYLOAD_INFO.pfnProcessPrinterAdded
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupProcessPrinterAdded");
(FARPROC)LAZYLOAD_INFO.pfnInstallICMProfiles
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupInstallICMProfiles");
(FARPROC)LAZYLOAD_INFO.pfnAssociateICMProfiles
= GetProcAddress(LAZYLOAD_INFO.hNtPrint,
"PSetupAssociateICMProfiles");
if ( LAZYLOAD_INFO.pfnCreatePrinterDeviceInfoList &&
LAZYLOAD_INFO.pfnDestroyPrinterDeviceInfoList &&
LAZYLOAD_INFO.pfnBuildDriversFromPath &&
LAZYLOAD_INFO.pfnDriverInfoFromName &&
LAZYLOAD_INFO.pfnDestroySelectedDriverInfo &&
LAZYLOAD_INFO.pfnGetLocalDataField &&
LAZYLOAD_INFO.pfnFreeDrvField &&
LAZYLOAD_INFO.pfnProcessPrinterAdded &&
LAZYLOAD_INFO.pfnInstallICMProfiles &&
LAZYLOAD_INFO.pfnAssociateICMProfiles ) {
#ifdef VERBOSE
DebugMsg("Succesfully loaded Ntprint.dll");
#endif
return TRUE;
}
}
if ( LAZYLOAD_INFO.hNtPrint )
{
FreeLibrary(LAZYLOAD_INFO.hNtPrint);
LAZYLOAD_INFO.hNtPrint = NULL;
}
return FALSE;
}
VOID
DeleteWin95Files(
)
/*++
Routine Description:
Read the migrate.inf and delete the files which are not needed on NT.
Arguments:
None
Return Value:
None
--*/
{
HINF hInf;
CHAR szPath[MAX_PATH];
LONG Count, Index;
INFCONTEXT InfContext;
sprintf(szPath, "%s\\%s", UpgradeData.pszDir, "migrate.inf");
hInf = SetupOpenInfFileA(szPath, NULL, INF_STYLE_WIN4, NULL);
if ( hInf == INVALID_HANDLE_VALUE )
return;
//
// We will only do the deleting part here. Files which are handled by
// the core migration dll do not have a destination directory since we
// are recreating the printing environment from scratch
//
if ( (Count = SetupGetLineCountA(hInf, "Moved")) != -1 ) {
for ( Index = 0 ; Index < Count ; ++Index ) {
if ( SetupGetLineByIndexA(hInf, "Moved", Index, &InfContext) &&
SetupGetStringFieldA(&InfContext, 0, szPath,
SIZECHARS(szPath), NULL) )
DeleteFileA(szPath);
}
}
SetupCloseInfFile(hInf);
}
BOOL
ReadWin9xPrintConfig(
IN OUT PDRIVER_NODE *ppDriverNode,
IN OUT PPRINTER_NODE *ppPrinterNode,
IN OUT PPORT_NODE *ppPortNode
)
/*++
Routine Description:
Reads the Win9x printing configuration we stored in the text file
so that printing components can be upgraded
Arguments:
ppDriverNode : Gives the list of drivers on Win9x
ppPrinterNode : Gives the list of printers on Win9x
Return Value:
TRUE on successfully reading the config information, FALSE else
--*/
{
BOOL bFail = FALSE, bRet = FALSE;
HANDLE hFile;
CHAR c, szLine[2*MAX_PATH];
DWORD dwCount, dwIndex, dwSize;
PDRIVER_NODE pDrv = NULL;
PPRINTER_NODE pPrn;
PPORT_NODE pPort;
sprintf(szLine, "%s\\%s", UpgradeData.pszDir, "print95.txt");
hFile = CreateFileA(szLine,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if ( hFile == INVALID_HANDLE_VALUE )
goto Cleanup;
dwSize = sizeof(szLine)/sizeof(szLine[0]);
//
// First we have the drivers
//
if ( My_fgets(szLine, dwSize, hFile) == NULL ||
strncmp(szLine, "[PrinterDrivers]", strlen("[PrinterDrivers]")) )
goto Cleanup;
do {
//
// Skip blanks
//
do {
c = (CHAR) My_fgetc(hFile);
} while ( c == ' ');
//
// If we hit EOF it is an error. Configuration was not written properly
// If we hit a new-line then we are at the end of the section
//
if ( c == EOF )
goto Cleanup;
else if ( c == '\n' )
break; // This is the normal exit from the do loop
if ( isdigit(c) ) {
//
// Put the string lengh digit back
//
if ( !My_ungetc(hFile) )
goto Cleanup;
}
if ( !(pDrv = AllocMem(sizeof(DRIVER_NODE))) )
goto Cleanup;
ReadString(hFile, "", &pDrv->DrvInfo1.pName, FALSE, &bFail);
if ( bFail ) {
FreeDriverNode(pDrv);
goto Cleanup;
}
pDrv->pNext = *ppDriverNode;
*ppDriverNode = pDrv;
} while ( !bFail );
//
// Now we have port info
//
if ( My_fgets(szLine, dwSize, hFile) == NULL ||
strncmp(szLine, "[Ports]", strlen("[Ports]")) )
goto Cleanup;
do {
//
// Skip blanks
//
do {
c = (CHAR) My_fgetc(hFile);
} while ( isspace(c) && c != '\n' );
//
// EOF can happen if no ports and no printers, else it's an error
//
if ( c == EOF)
{
if (!pDrv)
{
bRet = TRUE;
}
goto Cleanup;
}
//
// a blank line means the end of the port info section
//
if (c == '\n')
break;
if ( c != 'P' || !My_ungetc(hFile) )
goto Cleanup;
//
// Create port node
//
if ( !(pPort = AllocMem(sizeof(PORT_NODE))) )
{
goto Cleanup;
}
ReadString(hFile, "PortName:", &pPort->pPortName, FALSE, &bFail);
if (bFail)
{
FreePortNode(pPort);
goto Cleanup;
}
pPort->pNext = *ppPortNode;
*ppPortNode = pPort;
} while ( !bFail );
//
// Now we have 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;
if ( !(pPrn = AllocMem(sizeof(PRINTER_NODE))) )
goto Cleanup;
ReadPrinterInfo2(hFile, &pPrn->PrinterInfo2, &bFail);
if ( bFail ) {
FreePrinterNode(pPrn);
goto Cleanup;
}
pPrn->pNext = *ppPrinterNode;
*ppPrinterNode = pPrn;
} while ( !bFail );
bRet = TRUE;
Cleanup:
if ( hFile != INVALID_HANDLE_VALUE )
CloseHandle(hFile);
return bRet && !bFail;
}
BOOL
CheckAndAddMonitor(
IN LPDRIVER_INFO_6W pDrvInfo6
)
/*++
Routine Description:
Check if there is a language monitor associated with the given driver
and add it.
Arguments:
Return Value:
TRUE on success, FALSE on failure
None
--*/
{
MONITOR_INFO_2W MonitorInfo2;
LPWSTR psz = pDrvInfo6->pMonitorName;
LPSTR pszStr;
if ( psz && *psz ) {
MonitorInfo2.pName = psz;
MonitorInfo2.pEnvironment = NULL;
MonitorInfo2.pDLLName = (LPWSTR) (psz+wcslen(psz)+1);
//
// Add is succesful, or monitor is already installed?
//
if ( AddMonitorW(NULL, 2, (LPBYTE) &MonitorInfo2) ||
GetLastError() == ERROR_PRINT_MONITOR_ALREADY_INSTALLED ) {
return TRUE;
} else {
if ( pszStr = ErrorMsg() ) {
LogError(LogSevError, IDS_ADDMONITOR_FAILED,
psz, pszStr);
FreeMem(pszStr);
}
return FALSE;
}
}
return TRUE;
}
VOID
KeepAliveThread(
HANDLE hRunning
)
/*++
Routine Description:
Printing migration may take a long time depending on number of printers and
how long spooler takes to return. To inform setup that we are still alive
I need to set a named event atleast once every 3 minutes
Arguments:
hRunning : When this gets closed we know processing is done
Return Value:
None
--*/
{
//
// Every 30 seconds set the global event telling we are still alive
//
do {
SetEvent(hAlive);
} while ( WAIT_TIMEOUT == WaitForSingleObject(hRunning, 1000*30) );
CloseHandle(hAlive);
hAlive = NULL;
}
VOID
UpgradePrinterDrivers(
IN PDRIVER_NODE pDriverNode,
IN HDEVINFO hDevInfo,
IN OUT LPBOOL pbFail
)
/*++
Routine Description:
Upgrades printer drivers by doing the file copy operations and calling
AddPrinterDriver on spooler
Arguments:
pUpgradableDrvNode : List of drivers to upgrade
pbFail : Set on an error -- no more processing needed
Return Value:
None
--*/
{
BOOL bDriverToUpgrade = FALSE;
LPWSTR pszDriverW, pszICMW;
LPSTR pszDriverA, pszStr;
PDRIVER_NODE pCur;
DRIVER_FIELD DrvField;
//
// Set device install parameters so ntprint.dll will just queue up the
// driver files and return without doing the copy. We will commit the
// file queue at the end
//
if ( !InitFileCopyOnNT(hDevInfo) ) {
*pbFail = TRUE;
goto Cleanup;
}
//
// Now for each printer driver call ntprint.dll to queue up the driver files
// If it fails log an error
//
for ( pCur = pDriverNode ; pCur ; pCur = pCur->pNext ) {
pszDriverA = pCur->DrvInfo1.pName;
if ( (pszDriverW = AllocStrWFromStrA(pszDriverA)) &&
(pCur->pLocalData = LAZYLOAD_INFO.pfnDriverInfoFromName(
hDevInfo, (LPSTR)pszDriverW)) &&
SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
hDevInfo,
NULL) ) {
bDriverToUpgrade = TRUE;
} else {
pCur->bCantAdd = TRUE;
}
FreeMem(pszDriverW);
}
if ( !bDriverToUpgrade )
goto Cleanup;
#ifdef VERBOSE
DebugMsg("Starting file copy ...");
#endif
//
// Now commit the file queue to copy the files
//
if ( !CommitFileQueueToCopyFiles(hDevInfo) ) {
*pbFail = TRUE;
if ( pszStr = ErrorMsg() ) {
LogError(LogSevError, IDS_DRIVERS_UPGRADE_FAILED, pszStr);
FreeMem(pszStr);
}
goto Cleanup;
}
#ifdef VERBOSE
DebugMsg("... files copied successfully");
#endif
//
// Now call spooler to install the printer driver. Also install the
// ICM profiles associated with the printer driver
//
for ( pCur = pDriverNode ; pCur ; pCur = pCur->pNext ) {
//
// We already logged an error if bCantAdd is TRUE
//
if ( pCur->bCantAdd )
continue;
DrvField.Index = DRV_INFO_6;
DrvField.pDriverInfo4 = NULL;
if ( !LAZYLOAD_INFO.pfnGetLocalDataField(pCur->pLocalData,
PlatformX86,
&DrvField) ||
!CheckAndAddMonitor((LPDRIVER_INFO_6W) DrvField.pDriverInfo6) ||
!AddPrinterDriverW(NULL,
6,
(LPBYTE)DrvField.pDriverInfo6) ) {
if ( pszStr = ErrorMsg() ) {
LogError(LogSevError, IDS_ADDDRIVER_FAILED, pCur->DrvInfo1.pName, pszStr);
FreeMem(pszStr);
}
}
LAZYLOAD_INFO.pfnFreeDrvField(&DrvField);
DrvField.Index = ICM_FILES;
DrvField.pszzICMFiles = NULL;
if ( !LAZYLOAD_INFO.pfnGetLocalDataField(pCur->pLocalData,
PlatformX86,
&DrvField) ) {
continue;
}
if ( DrvField.pszzICMFiles )
LAZYLOAD_INFO.pfnInstallICMProfiles(NULL,
DrvField.pszzICMFiles);
LAZYLOAD_INFO.pfnFreeDrvField(&DrvField);
}
Cleanup:
return;
}
PSECURITY_DESCRIPTOR
GetSecurityDescriptor(
IN LPCSTR pszUser
)
/*++
Routine Description:
Get the users security
Arguments:
pszUser : sub key under HKEY_USER
Return Value:
NULL on error, else a valid SECURITY_DESCRIPTOR.
Memory is allocated in the heap and caller should free it.
--*/
{
HKEY hKey = NULL;
DWORD dwSize;
PSECURITY_DESCRIPTOR pSD = NULL;
if ( RegOpenKeyExA(HKEY_USERS,
pszUser,
0,
KEY_READ|KEY_WRITE,
&hKey) ||
RegGetKeySecurity(hKey,
DACL_SECURITY_INFORMATION,
NULL,
&dwSize) != ERROR_INSUFFICIENT_BUFFER ||
!(pSD = (PSECURITY_DESCRIPTOR) AllocMem(dwSize)) ||
RegGetKeySecurity(hKey,
DACL_SECURITY_INFORMATION,
pSD,
&dwSize) ) {
if ( hKey )
RegCloseKey(hKey);
FreeMem(pSD);
pSD = NULL;
}
return pSD;
}
typedef BOOL (WINAPI *P_XCV_DATA_W)(
IN HANDLE hXcv,
IN PCWSTR pszDataName,
IN PBYTE pInputData,
IN DWORD cbInputData,
OUT PBYTE pOutputData,
IN DWORD cbOutputData,
OUT PDWORD pcbOutputNeeded,
OUT PDWORD pdwStatus
);
BOOL
AddLocalPort(
IN LPSTR pPortName
)
/*++
Routine Description:
Adds a local port
Arguments:
pPortName : Name of the local port to add
Return Value:
FALSE if a port can't be added.
--*/
{
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, SERVER_ACCESS_ADMINISTER};
HANDLE hXcvMon = NULL;
BOOL bReturn = FALSE;
if (OpenPrinterA(",XcvMonitor Local Port", &hXcvMon, &PrinterDefault))
{
DWORD cbOutputNeeded = 0;
DWORD Status = NO_ERROR;
WCHAR *pUnicodePortName = NULL;
P_XCV_DATA_W pXcvData = NULL;
HMODULE hWinSpool = NULL;
//
// if I implib-link to XcvData, loading the migrate.dll on Win9x will fail !
//
hWinSpool = LoadLibraryUsingFullPathA("winspool.drv");
if (!hWinSpool)
{
DebugMsg("LoadLibrary on winspool.drv failed");
goto Done;
}
pXcvData = (P_XCV_DATA_W) GetProcAddress(hWinSpool, "XcvDataW");
if (!pXcvData)
{
DebugMsg("GetProcAddress on winspool.drv failed");
goto Done;
}
pUnicodePortName = AllocStrWFromStrA(pPortName);
if (pUnicodePortName)
{
bReturn = (*pXcvData)(hXcvMon,
L"AddPort",
(LPBYTE) pUnicodePortName,
(wcslen(pUnicodePortName) +1) * sizeof(WCHAR),
NULL,
0,
&cbOutputNeeded,
&Status
);
FreeMem(pUnicodePortName);
}
Done:
if (hWinSpool)
{
FreeLibrary(hWinSpool);
}
ClosePrinter(hXcvMon);
}
return bReturn;
}
VOID
UpgradePrinters(
IN PPRINTER_NODE pPrinterNode,
IN PDRIVER_NODE pDriverNode,
IN PPORT_NODE *ppPortNode,
IN HDEVINFO hDevInfo
)
/*++
Routine Description:
Upgrade printers on NT
Arguments:
pPrinterNode : Gives the list giving information about the printers
which existed on Win9x
Return Value:
None
--*/
{
DWORD dwLen, dwLastError;
LPSTR pszStr, pszPrinterNameA;
LPWSTR pszPrinterNameW;
HANDLE hPrinter;
DRIVER_FIELD DrvField;
PPSETUP_LOCAL_DATA pLocalData;
PPORT_NODE pCurPort, pPrevPort = NULL;
DWORD dwSize;
LPSTR pszVendorSetupA = NULL;
for ( ; pPrinterNode ; pPrinterNode = pPrinterNode->pNext ) {
pszPrinterNameA = pPrinterNode->PrinterInfo2.pPrinterName;
//
// check whether this printer uses a non-standard local file port
//
for (pCurPort = *ppPortNode; pCurPort != NULL; pPrevPort = pCurPort, pCurPort = pCurPort->pNext)
{
if (lstrcmpi(pPrinterNode->PrinterInfo2.pPortName, pCurPort->pPortName) == 0)
{
//
// Create the port
//
AddLocalPort(pCurPort->pPortName);
//
// remove it from the list
//
if (pCurPort == *ppPortNode)
{
*ppPortNode = pCurPort->pNext;
}
else
{
pPrevPort->pNext = pCurPort->pNext;
}
FreePortNode(pCurPort);
break;
}
}
hPrinter = AddPrinterA(NULL,
2,
(LPBYTE)&pPrinterNode->PrinterInfo2);
if ( !hPrinter ) {
dwLastError = GetLastError();
//
// If driver is unknown we already logged warned the user
// If printer already exists it is ok (for Fax printer this is true)
//
if ( dwLastError != ERROR_UNKNOWN_PRINTER_DRIVER &&
dwLastError != ERROR_INVALID_PRINTER_NAME &&
dwLastError != ERROR_PRINTER_ALREADY_EXISTS &&
(pszStr = ErrorMsg()) ) {
LogError(LogSevError,
IDS_ADDPRINTER_FAILED,
pszPrinterNameA,
pszStr);
FreeMem(pszStr);
}
continue;
}
pLocalData = FindLocalDataForDriver(pDriverNode,
pPrinterNode->PrinterInfo2.pDriverName);
pszPrinterNameW = AllocStrWFromStrA(pszPrinterNameA);
if ( pLocalData && pszPrinterNameW ) {
DrvField.Index = ICM_FILES;
DrvField.pszzICMFiles = NULL;
if ( LAZYLOAD_INFO.pfnGetLocalDataField(pLocalData,
PlatformX86,
&DrvField) ) {
if ( DrvField.pszzICMFiles )
LAZYLOAD_INFO.pfnAssociateICMProfiles(
(LPTSTR)pszPrinterNameW,
DrvField.pszzICMFiles);
LAZYLOAD_INFO.pfnFreeDrvField(&DrvField);
}
LAZYLOAD_INFO.pfnProcessPrinterAdded(hDevInfo,
pLocalData,
(LPTSTR)pszPrinterNameW,
INVALID_HANDLE_VALUE);
dwSize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)(pLocalData->InfInfo.pszVendorSetup),
-1, NULL, 0, NULL, NULL);
if (dwSize > 0)
{
pszVendorSetupA = (LPSTR)AllocMem( dwSize );
if (pszVendorSetupA)
{
if (WideCharToMultiByte (CP_ACP, 0, (LPCWSTR)(pLocalData->InfInfo.pszVendorSetup),
-1, pszVendorSetupA, dwSize, NULL, NULL))
{
WriteVendorSetupInfoInRegistry( pszVendorSetupA, pszPrinterNameA );
}
FreeMem( pszVendorSetupA );
}
}
}
//
// Default printer will be the one with PRINTER_ATTRIBUTE_DEFAULT attribute
// If the Win95 default printer could not be added to NT we will set the
// first printer as the default printer
//
if ( (pPrinterNode->PrinterInfo2.Attributes
& PRINTER_ATTRIBUTE_DEFAULT) ||
!pDefPrinter )
pDefPrinter = pPrinterNode;
FreeMem(pszPrinterNameW);
ClosePrinter(hPrinter);
}
if ( pDefPrinter )
pszDefaultPrinterString = GetDefPrnString(
pDefPrinter->PrinterInfo2.pPrinterName);
}
HDEVINFO
PrinterDevInfo(
IN OUT LPBOOL pbFail
)
/*++
--*/
{
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
if ( *pbFail || !InitLazyLoadInfo() ) {
*pbFail = TRUE;
goto Cleanup;
}
hDevInfo = LAZYLOAD_INFO.pfnCreatePrinterDeviceInfoList(INVALID_HANDLE_VALUE);
if ( hDevInfo == INVALID_HANDLE_VALUE ||
!LAZYLOAD_INFO.pfnBuildDriversFromPath(hDevInfo,
(LPSTR)L"ntprint.inf",
TRUE) ) {
*pbFail = TRUE;
goto Cleanup;
}
#ifdef VERBOSE
DebugMsg("Built the list of printer drivers from ntprint.inf");
#endif
if ( *pbFail && hDevInfo != INVALID_HANDLE_VALUE ) {
LAZYLOAD_INFO.pfnDestroyPrinterDeviceInfoList(hDevInfo);
hDevInfo = INVALID_HANDLE_VALUE;
}
Cleanup:
return hDevInfo;
}
LONG
CALLBACK
InitializeNT(
IN LPCWSTR pszWorkingDir,
IN LPCWSTR pszSourceDir,
LPVOID Reserved
)
/*++
Routine Description:
Setup calls this to intialize us on NT side
Arguments:
pszWorkingDir : Gives the working directory assigned for printing
pszSourceDir : Source location for NT distribution files
Reserved : Leave it alone
Return Value:
Win32 error code
--*/
{
BOOL bFail = FALSE;
DWORD dwReturn, ThreadId;
HANDLE hRunning = NULL, hThread;
HDSKSPC DiskSpace;
LPSTR pszStr;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
PDRIVER_NODE pDriverNode = NULL;
PPRINTER_NODE pPrinterNode = NULL;
PPORT_NODE pPortNode = NULL;
#ifdef VERBOSE
DebugMsg("InitializeNT : %ws, %ws", pszSourceDir, pszWorkingDir);
#endif
UpgradeData.pszDir = AllocStrAFromStrW(pszWorkingDir);
UpgradeData.pszSourceW = AllocStrW(pszSourceDir);
UpgradeData.pszSourceA = AllocStrAFromStrW(pszSourceDir);
if ( !UpgradeData.pszDir ||
!UpgradeData.pszSourceW ||
!UpgradeData.pszSourceA ) {
return GetLastError();
}
if ( (hAlive = OpenEventA(EVENT_MODIFY_STATE, FALSE, "MigDllAlive")) &&
(hRunning = CreateEventA(NULL, FALSE, FALSE, NULL)) &&
(hThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)KeepAliveThread,
hRunning,
0, &ThreadId)) )
CloseHandle(hThread);
SetupOpenLog(FALSE);
DeleteWin95Files();
if ( !ReadWin9xPrintConfig(&pDriverNode, &pPrinterNode, &pPortNode) ) {
bFail = TRUE;
DebugMsg("Unable to read Windows 9x printing configuration");
goto Cleanup;
}
#ifdef VERBOSE
DebugMsg("Succesfully read Windows 9x printing configuration");
#endif
//
// If no printers or drivers found nothing to do
//
if ( !pDriverNode && !pPrinterNode )
goto Cleanup;
if ( (hDevInfo = PrinterDevInfo(&bFail)) == INVALID_HANDLE_VALUE )
goto Cleanup;
UpgradePrinterDrivers(pDriverNode, hDevInfo, &bFail);
UpgradePrinters(pPrinterNode, pDriverNode, &pPortNode, hDevInfo);
MakeACopyOfMigrateDll( UpgradeData.pszDir );
Cleanup:
SetupCloseLog();
if ( bFail && (pszStr = ErrorMsg()) ) {
DebugMsg("Printing migration failed. %s", pszStr);
FreeMem(pszStr);
}
FreePrinterNodeList(pPrinterNode);
FreeDriverNodeList(pDriverNode);
FreePortNodeList(pPortNode);
if ( hDevInfo != INVALID_HANDLE_VALUE )
LAZYLOAD_INFO.pfnDestroyPrinterDeviceInfoList(hDevInfo);
if ( LAZYLOAD_INFO.hNtPrint )
FreeLibrary(LAZYLOAD_INFO.hNtPrint);
if ( bFail ) {
if ( (dwReturn = GetLastError()) == ERROR_SUCCESS ) {
ASSERT(dwReturn != ERROR_SUCCESS);
dwReturn = STG_E_UNKNOWN;
}
} else {
SetupNetworkPrinterUpgrade(UpgradeData.pszDir);
dwReturn = ERROR_SUCCESS;
#ifdef VERBOSE
DebugMsg("InitializeNT returning success");
#endif
}
if ( hRunning )
CloseHandle(hRunning);
while (hAlive)
Sleep(100); // Check after 0.1 second for the main thread to die
return dwReturn;
}
DWORD
MySetDefaultPrinter(
IN HKEY hUserRegKey,
IN LPSTR pszDefaultPrinterString
)
/*++
Routine Description:
Sets the default printer for the user by writing it to the registry
Arguments:
Return Value:
--*/
{
DWORD dwReturn;
HKEY hKey = NULL;
//
// Create the printers key in the user hive and write DeviceOld value
//
dwReturn = RegCreateKeyExA(hUserRegKey,
"Printers",
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if ( dwReturn == ERROR_SUCCESS ) {
dwReturn = RegSetValueExA(hKey,
"DeviceOld",
0,
REG_SZ,
(LPBYTE)pszDefaultPrinterString,
(strlen(pszDefaultPrinterString) + 1)
* sizeof(CHAR));
RegCloseKey(hKey);
}
return dwReturn;
}
LONG
CALLBACK
MigrateUserNT(
IN HINF hUnattendInf,
IN HKEY hUserRegKey,
IN LPCWSTR pszUserName,
LPVOID Reserved
)
/*++
Routine Description:
Migrate user settings
Arguments:
Return Value:
--*/
{
LPSTR pszStr;
DWORD dwReturn = ERROR_SUCCESS;
#ifdef VERBOSE
DebugMsg("Migrating settings for %ws", pszUserName);
#endif
if ( pszDefaultPrinterString ) {
dwReturn = MySetDefaultPrinter(hUserRegKey,
pszDefaultPrinterString);
if ( dwReturn )
DebugMsg("MySetDefaultPrinter failed with %d", dwReturn);
}
if ( bDoNetPrnUpgrade ) {
if ( ProcessNetPrnUpgradeForUser(hUserRegKey) )
++dwRunOnceCount;
else {
if ( dwReturn == ERROR_SUCCESS )
dwReturn = GetLastError();
DebugMsg("ProcessNetPrnUpgradeForUser failed with %d", dwReturn);
}
}
#ifdef VERBOSE
if ( dwReturn )
DebugMsg("MigrateUserNT failed with %d", dwReturn);
else
DebugMsg("MigrateUserNT succesful");
#endif
return dwReturn;
}
LONG
CALLBACK
MigrateSystemNT(
IN HINF hUnattendInf,
LPVOID Reserved
)
/*++
Routine Description:
Process system setttings for printing. All the printing setting are
migrated in InitializeNT since we need to know the default printer for
each user in the MigrateSystemNT call
Arguments:
hUnattendInf : Handle to the unattended INF
Return Value:
Win32 error code
--*/
{
WriteRunOnceCount();
return ERROR_SUCCESS;
}
//
// The following are to make sure if setup changes the header file they
// first tell me (otherwise they will break build of this)
//
P_INITIALIZE_NT pfnInitializeNT = InitializeNT;
P_MIGRATE_USER_NT pfnMigrateUserNt = MigrateUserNT;
P_MIGRATE_SYSTEM_NT pfnMigrateSystemNT = MigrateSystemNT;