/*++ Copyright (c) 1995-97 Microsoft Corporation All rights reserved. Module Name: Win95.c Abstract: Routines for installing win95 driver files Author: Muhunthan Sivapragasam (MuhuntS) 30-Nov-1995 Revision History: --*/ #include "precomp.h" const TCHAR cszPrtupg9x[] = TEXT("prtupg9x.inf"); const TCHAR cszPrinterDriverMapping[] = TEXT("Printer Driver Mapping"); const TCHAR cszPrinterDriverMappingNT[] = TEXT("Printer Driver Mapping WINNT"); void CutLastDirFromPath(LPTSTR pszPath) /*++ Routine Description: Cuts of the last directory from a path, e.g. c:\a\b\c\f.x -> c:\a\b\f.x Arguments: pszPath : the path to operate on Return Value: none --*/ { LPTSTR pLastWhack, pSecondButLastWhack; pLastWhack = _tcsrchr(pszPath, _T('\\')); if (!pLastWhack) { return; } *pLastWhack = 0; pSecondButLastWhack = _tcsrchr(pszPath, _T('\\')); if (!pSecondButLastWhack) { return; } _tcscpy(pSecondButLastWhack+1, pLastWhack+1); } BOOL CopyDriverFileAndModPath(LPTSTR pszPath) /*++ Routine Description: Copies a driver file from the original location one dir up and modifies the path name accordingly Arguments: pszPath : the path of the file to copy and to operate on Return Value: TRUE if OK, FALSE on error --*/ { BOOL bRes = TRUE; TCHAR *pszTmp = NULL; if (!pszPath) { goto Cleanup; // nothing to copy } pszTmp = AllocStr( pszPath ); if (!pszTmp) { bRes = FALSE; goto Cleanup; } CutLastDirFromPath(pszPath); bRes = CopyFile(pszTmp, pszPath, FALSE); Cleanup: LocalFreeMem( pszTmp ); return bRes; } BOOL CopyDependentFiles(LPTSTR pszzDepFiles) /*++ Routine Description: Copies the dependent files one directory up and modifies the name buffers. Arguments: pszzDepFiles : the multi-sz string containing the pathes of the files to copy and to operate on Return Value: TRUE if OK, FALSE on error --*/ { LPTSTR pCur = pszzDepFiles, pBuf = NULL, pCurCopy; DWORD ccBufLen; BOOL bRet = FALSE; if (pszzDepFiles == NULL) { bRet = TRUE; goto Cleanup; } // // count the total length of the buffer // for (ccBufLen = 0; *(pszzDepFiles + ccBufLen) != 0; ccBufLen += _tcslen(pszzDepFiles + ccBufLen) + 1) ; ccBufLen +=2; // for the two terminating zeros pBuf = LocalAllocMem(ccBufLen * sizeof(TCHAR)); if (!pBuf) { goto Cleanup; } // // go through the source buffer file by file, modify names and copy files // for (pCur = pszzDepFiles, pCurCopy = pBuf; *pCur != 0; pCur += _tcslen(pCur) +1, pCurCopy += _tcslen(pCurCopy) +1) { _tcscpy(pCurCopy, pCur); CutLastDirFromPath(pCurCopy); if (!CopyFile(pCur, pCurCopy, FALSE)) { goto Cleanup; } } // // 00-terminate the new buffer // *pCurCopy = 0; *(++pCurCopy) = 0; // // copy it back - the new version is always shorter than the original // CopyMemory(pszzDepFiles, pBuf, (pCurCopy - pBuf + 1) * sizeof(TCHAR)); bRet = TRUE; Cleanup: if (pBuf) { LocalFreeMem(pBuf); } return bRet; } BOOL SetPreviousNamesSection(LPCTSTR pszServer, LPCTSTR pszModelName, LPCTSTR pszAddPrevName) /*++ Routine Description: Adds a printer name to the list of previous names of a W2k/NT4 driver. This makes the driver usable under that name for point-and-print. To change the previous name section, do another call to AddPrinterDriver with all the files in place Arguments: pszServer : the machine we're operating on. pszModelName : the model name of the native driver pszAddPrevName : the name of the Win9x driver to be added to the previous names entry. Return Value: TRUE if OK, FALSE on error. --*/ { PBYTE pBuf = NULL; DRIVER_INFO_6 *pDrvInfo6 = NULL; DWORD cbNeeded, cReceived, i; BOOL bRet = FALSE; LPTSTR pTmp; TCHAR pArch[MAX_PATH]; // // previous names section only supported from Whistler upwards // if (!IsWhistlerOrAbove(pszServer)) { bRet = TRUE; goto Cleanup; } cbNeeded = COUNTOF(pArch); if(!GetArchitecture( pszServer, pArch, &cbNeeded )) { _tcsncpy( pArch, PlatformEnv[MyPlatform].pszName, COUNTOF(pArch) ); } // // Check whether the name is different in the first place // if (!_tcscmp(pszModelName, pszAddPrevName)) { bRet = TRUE; goto Cleanup; } // // Get the DRIVER_INFO_6 of the W2k driver // EnumPrinterDrivers((LPTSTR) pszServer, pArch, 6, pBuf, 0, &cbNeeded, &cReceived); pBuf = LocalAllocMem(cbNeeded); if (!pBuf) { goto Cleanup; } if (!EnumPrinterDrivers((LPTSTR) pszServer, pArch, 6, pBuf, cbNeeded, &cbNeeded, &cReceived)) { goto Cleanup; } for (i = 0; i < cReceived ; i++) { pDrvInfo6 = (DRIVER_INFO_6 *) (pBuf + i*sizeof(DRIVER_INFO_6)); if (!_tcscmp(pszModelName, pDrvInfo6->pName)) { break; } } // // was the corresponding W2k driver found ? // if (i == cReceived) { // // Couldn't find the W2k driver to set the previous names section on. // This must be the AddPrinterDriver wizard, else there would be one. // Just let the user install this driver. // bRet = TRUE; goto Cleanup; } // // check whether the name to add is already in the list // if (pDrvInfo6->pszzPreviousNames) { for (pTmp = pDrvInfo6->pszzPreviousNames; *pTmp; pTmp += _tcslen(pTmp) +1) { if (!_tcscmp(pTmp, pszAddPrevName)) { bRet = TRUE; goto Cleanup; } } } // // Copy all the files into the driver dir // if (!CopyDriverFileAndModPath(pDrvInfo6->pDriverPath) || !CopyDriverFileAndModPath(pDrvInfo6->pConfigFile) || !CopyDriverFileAndModPath(pDrvInfo6->pDataFile) || !CopyDriverFileAndModPath(pDrvInfo6->pHelpFile) || !CopyDependentFiles(pDrvInfo6->pDependentFiles)) { goto Cleanup; } // // Modify the PreviousNames section. // No reallocation since string lives in the same buffer as the DrvInfo6 ! // +2 for the psz terminating zero and the second zero for the whole // pDrvInfo6->pszzPreviousNames = LocalAllocMem((_tcslen(pszAddPrevName) + 2) * sizeof(TCHAR)); if (!pDrvInfo6->pszzPreviousNames) { goto Cleanup; } _tcscpy(pDrvInfo6->pszzPreviousNames, pszAddPrevName); // // write the driver info 6 back // bRet = AddPrinterDriver((LPTSTR) pszServer, 6, (LPBYTE) pDrvInfo6); LocalFreeMem (pDrvInfo6->pszzPreviousNames); Cleanup: if (pBuf) { LocalFreeMem (pBuf); } return bRet; } DWORD InstallWin95Driver( IN HWND hwnd, IN LPCTSTR pszModel, IN LPCTSTR pszzPreviousNames, IN BOOL bPreviousNamesSection, IN LPCTSTR pszServerName, IN OUT LPTSTR pszInfPath, IN LPCTSTR pszDiskName, IN DWORD dwInstallFlags, IN DWORD dwAddDrvFlags ) /*++ Routine Description: List all the printer drivers from Win95 INF files and install the printer driver selected by the user Arguments: hwnd : Window handle that owns the UI pszModel : Printer driver model pszzPreviousNames : Multi-sz string giving other names for the driver bPreviousNamesSection : If TRUE the NT inf had a Previous Names section pszServerName : Server for which driver is to be installed (NULL : local) pszInfPath : Default path for inf. Prompt will have this name for user pszDiskName : Name of the disk to prompt for and use in title dwInstallFlags : Installation flags given by caller dwAddDrvFlags : Flags for AddPrinterDriverEx Return Value: On succesfully installing files ERROR_SUCCESS, else the error code --*/ { BOOL bFreeDriverName=FALSE, bFirstTime=TRUE; DWORD dwNeeded, dwRet = ERROR_CANCELLED; TCHAR szTargetPath[MAX_PATH]; LPDRIVER_INFO_6 pDriverInfo6 = NULL; PPSETUP_LOCAL_DATA pLocalData = NULL; HDEVINFO hDevInfo = INVALID_HANDLE_VALUE; Retry: // // If we get here second time that means default path has INFs but not the // model we are looking for. Ex. an OEM driver in the previous names section // that is not on Win2K CD. So make sure we prompt // if ( !bFirstTime ) { dwInstallFlags |= DRVINST_ALT_PLATFORM_INSTALL; if (pszInfPath) { *pszInfPath = 0; } } hDevInfo = GetInfAndBuildDrivers(hwnd, IDS_DRIVERS_FOR_WIN95, IDS_PROMPT_ALT_PLATFORM_DRIVER, pszInfPath, dwInstallFlags, PlatformWin95, 0, NULL, NULL, NULL); if ( hDevInfo == INVALID_HANDLE_VALUE || !SetSelectDevParams(hDevInfo, NULL, TRUE, pszModel) ) { goto Cleanup; } // // First look for an exact model match. // // If previous name is found then we will allow one retry since now we // have some previous names with no driver on CD (since it is an OEM driver) // If previous name is not found ask user to select a model // if ( !(pDriverInfo6 = Win95DriverInfo6FromName(hDevInfo, &pLocalData, pszModel, pszzPreviousNames)) ) { if ( bPreviousNamesSection ) { if ( bFirstTime == TRUE ) { ASSERT(pLocalData == NULL); DestroyOnlyPrinterDeviceInfoList(hDevInfo); hDevInfo = INVALID_HANDLE_VALUE; bFirstTime = FALSE; goto Retry; } } if ( (dwInstallFlags & DRVINST_PROMPTLESS) == 0) { PVOID pDSInfo = NULL; // Holds pointer to the driver signing class that C can't understand. HSPFILEQ CopyQueue; SP_DEVINSTALL_PARAMS DevInstallParams = {0}; DevInstallParams.cbSize = sizeof(DevInstallParams); DestroyOnlyPrinterDeviceInfoList(hDevInfo); hDevInfo = CreatePrinterDeviceInfoList(hwnd); if ( hDevInfo == INVALID_HANDLE_VALUE || !SetDevInstallParams(hDevInfo, NULL, pszInfPath)) { DWORD dwLastError; dwLastError = GetLastError(); DestroyOnlyPrinterDeviceInfoList(hDevInfo); hDevInfo = INVALID_HANDLE_VALUE; SetLastError(dwLastError); goto Cleanup; } CopyQueue = SetupOpenFileQueue(); if ( CopyQueue == INVALID_HANDLE_VALUE ) { goto Cleanup; } // // associate the queue with the HDEVINFO // if ( SetupDiGetDeviceInstallParams(hDevInfo, NULL, &DevInstallParams) ) { DevInstallParams.Flags |= DI_NOVCP; DevInstallParams.FileQueue = CopyQueue; SetupDiSetDeviceInstallParams(hDevInfo, NULL, &DevInstallParams); } if (NULL == (pDSInfo = SetupDriverSigning(hDevInfo, pszServerName, NULL, pszInfPath, PlatformWin95, 0, CopyQueue, FALSE))) { SetupCloseFileQueue(CopyQueue); goto Cleanup; } if ( BuildClassDriverList(hDevInfo) && PSetupSelectDriver(hDevInfo) && (pLocalData = BuildInternalData(hDevInfo, NULL)) && ParseInf(hDevInfo, pLocalData, PlatformWin95, pszServerName, dwInstallFlags) ) { LPCTSTR pDriverName; pDriverInfo6 = CloneDriverInfo6(&pLocalData->InfInfo.DriverInfo6, pLocalData->InfInfo.cbDriverInfo6); // // if setup selected a "compatible" driver: // pre-Whistler: rename the compatible driver to the requested model name // on Whistler: set the driver name to the compatible one and set the previous names section accordingly // if (IsWhistlerOrAbove(pszServerName)) { pDriverName = pLocalData->DrvInfo.pszModelName; } else { pDriverName = pszModel; } if ( pDriverInfo6 && (pDriverInfo6->pName = AllocStr(pDriverName)) ) { bFreeDriverName = TRUE; } } // // disassociate the queue before deleting it // DevInstallParams.Flags &= ~DI_NOVCP; DevInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH; DevInstallParams.FileQueue = INVALID_HANDLE_VALUE; SetupDiSetDeviceInstallParams(hDevInfo, NULL, &DevInstallParams); SetupCloseFileQueue(CopyQueue); CleanupDriverSigning(pDSInfo); } } else if (lstrcmp(pDriverInfo6->pName, pszModel)) { // // if the driver was selected because of an entry in the previous names section // then on anything before Whistler we need to rename the driver to the queue driver's name // if (!IsWhistlerOrAbove(pszServerName)) { if (pDriverInfo6->pName = AllocStr(pszModel) ) { bFreeDriverName = TRUE; } } } if ( !pDriverInfo6 || !pDriverInfo6->pName ) goto Cleanup; pDriverInfo6->pEnvironment = PlatformEnv[PlatformWin95].pszName; // // For Win95 driver pszzPreviousNames does not make sense // ASSERT(pDriverInfo6->pszzPreviousNames == NULL); if ( GetPrinterDriverDirectory((LPTSTR)pszServerName, pDriverInfo6->pEnvironment, 1, (LPBYTE)szTargetPath, sizeof(szTargetPath), &dwNeeded) && CopyPrinterDriverFiles(pDriverInfo6, pLocalData->DrvInfo.pszInfName, pszInfPath, pszDiskName, szTargetPath, hwnd, dwInstallFlags, TRUE) && SetPreviousNamesSection(pszServerName, pszModel, (LPCTSTR) pLocalData->DrvInfo.pszModelName) && AddPrinterDriverUsingCorrectLevel(pszServerName, pDriverInfo6, dwAddDrvFlags) ) { dwRet = ERROR_SUCCESS; } Cleanup: if (pLocalData) { DestroyLocalData(pLocalData); pLocalData = NULL; } if ( dwRet != ERROR_SUCCESS ) dwRet = GetLastError(); if ( hDevInfo != INVALID_HANDLE_VALUE ) DestroyOnlyPrinterDeviceInfoList(hDevInfo); if ( pDriverInfo6 ) { if ( bFreeDriverName ) LocalFreeMem(pDriverInfo6->pName); PSetupDestroyDriverInfo3((LPDRIVER_INFO_3)pDriverInfo6); } CleanupScratchDirectory(pszServerName, PlatformWin95); CleanupScratchDirectory(pszServerName, PlatformX86); return dwRet; } /*++ Routine Name: PSetupFindMappedDriver Routine Description: Find the remapped NT printer driver name for the given driver name. If the function does not find a remapped driver, it simply returns the name that was passed in. This looks in the [Printer Driver Mapping] and [Printer Driver Mapping WINNT] sections of prtupg9x.inf. Arguments: bWinNT - If TRUE, find this from the WINNT section. pszDriverName - The driver name to be remapped. ppszRemappedDriverName - The remapped driver name, allocated and returned to the caller. (Free with PSetupFreeMem). pbDriverFound - If TRUE, the driver was remapped. Otherwise, the output is simpy a copy of the input. Return Value: If there is an unexpected error, FALSE, otherwise TRUE. Last Error has the error code. --*/ BOOL PSetupFindMappedDriver( IN BOOL bWinNT, IN LPCTSTR pszDriverName, OUT LPTSTR *ppszRemappedDriverName, OUT BOOL *pbDriverFound ) { HINF hInf = INVALID_HANDLE_VALUE; BOOL bRet = FALSE; BOOL bFound = FALSE; LPTSTR pszRemappedDriverName = NULL; INFCONTEXT InfContext; TCHAR szNtName[LINE_LEN]; bRet = pszDriverName && ppszRemappedDriverName && pbDriverFound; if (ppszRemappedDriverName) { *ppszRemappedDriverName = NULL; } if (pbDriverFound) { *pbDriverFound = FALSE; } if (!bRet) { SetLastError(ERROR_INVALID_PARAMETER); } // // Open ntprint.inf, it should be in the %windir%\inf directory. // if (bRet) { hInf = SetupOpenInfFile(cszPrtupg9x, NULL, INF_STYLE_WIN4, NULL); bRet = hInf != INVALID_HANDLE_VALUE; } // // Find the driver in the appropriate Printer Driver Mapping section of the // inf. // if (bRet) { bFound = SetupFindFirstLine(hInf, bWinNT ? cszPrinterDriverMappingNT : cszPrinterDriverMapping, pszDriverName, &InfContext); // // Get the name of the in-box driver. // if (bFound) { bRet = SetupGetStringField(&InfContext, 1, szNtName, COUNTOF(szNtName), NULL); } else if (ERROR_LINE_NOT_FOUND != GetLastError()) { bRet = FALSE; } } // // If we found the driver, return it. Otherwise, just allocate and return the // string that was passed in. // if (bRet) { if (bFound) { pszRemappedDriverName = AllocStr(szNtName); *pbDriverFound = pszRemappedDriverName != NULL; } else { // // The remapped driver is not in the inf. Return the one we were passed in. // pszRemappedDriverName = AllocStr(pszDriverName); } bRet = pszRemappedDriverName != NULL; } if (bRet) { *ppszRemappedDriverName = pszRemappedDriverName; pszRemappedDriverName = NULL; } if (hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } if (pszRemappedDriverName) { LocalFreeMem(pszRemappedDriverName); } return bRet; }