/*++ 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;