/*++ Copyright (C) 1998 - 2002 Microsoft Corporation All rights reserved. Module Name: PrntWrn Abstract: Code checks if any of the installed printers will fail during upgrade to Londhorn Author: Mikael Horal 15-March-2002 --*/ #include "precomp.h" #pragma hdrstop #include "string.hxx" enum EPrintUpgConstants { kReplacementDriver = 1, kWarnLevelWks = 2, kWarnLevelSrv = 3, kFileTime = 4, kUnidrv54 = 5, }; enum EPrintUpgLevels { kBlocked = 1, kWarned = 2, }; TCHAR cszPrintDriverMapping[] = TEXT("Printer Driver Mapping"); TCHAR cszVersion[] = TEXT("Version"); TCHAR cszExcludeSection[] = TEXT("Excluded Driver Files"); EXTERN_C BOOL WINAPI DllMain( IN HINSTANCE hInst, IN DWORD dwReason, IN LPVOID lpRes ) { UNREFERENCED_PARAMETER(lpRes); switch( dwReason ){ case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInst); break; case DLL_PROCESS_DETACH: break; } return TRUE; } HRESULT GetLastErrorAsHResult( VOID ) { return HRESULT_FROM_WIN32(GetLastError()); } LPTSTR FileNamePart( IN LPCTSTR pszFullName ) /*++ Routine Description: Find the file name part of a fully qualified file name Arguments: pszFullName : Fully qualified path to the file Return Value: Pointer to the filename part in the fully qulaified string --*/ { LPTSTR pszSlash, pszTemp; if ( !pszFullName ) return NULL; // // First find the : for the drive // if ( pszTemp = wcschr(pszFullName, TEXT(':')) ) pszFullName = pszFullName + 1; for ( pszTemp = (LPTSTR)pszFullName ; pszSlash = wcschr(pszTemp, TEXT('\\')) ; pszTemp = pszSlash + 1 ) ; return *pszTemp ? pszTemp : NULL; } /*++ Routine Name GetFileTimeByName Routine Description: Get the file time of the file given a full path. Arguments: pszPath - Full path of the driver pFileTime - Points to the file time Return Value: An HRESULT --*/ HRESULT GetFileTimeByName( IN LPCTSTR pszPath, OUT FILETIME *pFileTime ) { HRESULT hRetval = E_FAIL; HANDLE hFile = INVALID_HANDLE_VALUE; hRetval = pszPath && *pszPath && pFileTime ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { hFile = CreateFile(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); hRetval = (INVALID_HANDLE_VALUE != hFile) ? S_OK : GetLastErrorAsHResult(); } if (SUCCEEDED(hRetval)) { hRetval = GetFileTime(hFile, NULL, NULL, pFileTime) ? S_OK : GetLastErrorAsHResult(); } if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } return hRetval; } /*++ Routine Name GetSectionName Routine Description: Get the Section name in terms of environment and driver version. Arguments: pszEnvironment - The environment of the server, such as uVersion - The major version of the driver pstrSection - Points the name of section of driver mapping Return Value: An HRESULT --*/ HRESULT GetSectionName( IN LPCTSTR pszEnvironment, IN UINT uVersion, OUT TString *pstrSection ) { HRESULT hRetval = E_FAIL; hRetval = pszEnvironment && pstrSection ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { hRetval = pstrSection->Format(_T("%s_%s_%s %d"), cszPrintDriverMapping, pszEnvironment, cszVersion, uVersion); } return hRetval; } /*++ Routine Name InfGetString Routine Description: This routine is a wrapper to SetupGetStringField using TString. Arguments: pInfContext - The context of the inf uFieldIndex - The field index of the string to retrieve pstrField - Points to the string field as TString Return Value: An HRESULT --*/ HRESULT InfGetString( IN INFCONTEXT *pInfContext, IN UINT uFieldIndex, OUT TString *pstrField ) { HRESULT hRetval = E_FAIL; TCHAR szField[MAX_PATH] = {0}; DWORD dwNeeded = 0; TCHAR *pszField = NULL; hRetval = pInfContext && pstrField ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { hRetval = SetupGetStringField(pInfContext, uFieldIndex, szField, COUNTOF(szField), &dwNeeded) ? S_OK : GetLastErrorAsHResult(); if (SUCCEEDED(hRetval)) { hRetval = pstrField->Update(szField); } else if (FAILED(hRetval) && (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hRetval))) { pszField = new TCHAR[dwNeeded]; hRetval = pszField ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hRetval)) { hRetval = SetupGetStringField(pInfContext, uFieldIndex, pszField, dwNeeded, &dwNeeded) ? S_OK : GetLastErrorAsHResult(); } if (SUCCEEDED(hRetval)) { hRetval = pstrField->Update(pszField); } } } delete [] pszField; return hRetval; } LPTSTR ReadDigit( LPTSTR ptr, LPWORD pW ) { TCHAR c; // // Skip spaces // while ( !iswdigit(c = *ptr) && c != TEXT('\0') ) ++ptr; if ( c == TEXT('\0') ) return NULL; // // Read field // for ( *pW = 0 ; iswdigit(c = *ptr) ; ++ptr ) *pW = *pW * 10 + c - TEXT('0'); return ptr; } HRESULT StringToDate( LPTSTR pszDate, SYSTEMTIME *pInfTime ) { BOOL bRet = FALSE; ZeroMemory(pInfTime, sizeof(*pInfTime)); bRet = (pszDate = ReadDigit(pszDate, &(pInfTime->wMonth))) && (pszDate = ReadDigit(pszDate, &(pInfTime->wDay))) && (pszDate = ReadDigit(pszDate, &(pInfTime->wYear))); // // Y2K compatible check // if ( bRet && pInfTime->wYear < 100 ) { ASSERT(pInfTime->wYear >= 100); if ( pInfTime->wYear < 10 ) pInfTime->wYear += 2000; else pInfTime->wYear += 1900; } if(!bRet) { SetLastError(ERROR_INVALID_DATA); } return bRet? S_OK : GetLastErrorAsHResult(); } /*++ Routine Name StringTimeToFileTime Routine Description: Converts a string of time in the form of "11/27/1999" to FILETIME. Arguments: pszFileTime - The file time as string such as "11/27/1999" pFileTime - Points to the converted FILETIME Return Value: An HRESULT --*/ HRESULT StringTimeToFileTime( IN LPCTSTR pszFileTime, OUT FILETIME *pFileTime ) { HRESULT hRetval = E_FAIL; SYSTEMTIME SystemTime; hRetval = pszFileTime && pFileTime ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { // // StringToDate should take pszFileTime as const. // hRetval = StringToDate(const_cast(pszFileTime), &SystemTime) ? S_OK : GetLastErrorAsHResult(); } if (SUCCEEDED(hRetval)) { hRetval = SystemTimeToFileTime(&SystemTime, pFileTime) ? S_OK : GetLastErrorAsHResult(); } return hRetval; } /*++ Routine Name InfGetStringAsFileTime Routine Description: This routine get the time of driver in printupg and converts it to FILETIME. Arguments: pInfContext - The context of the inf uFieldIndex - The field index of the string to retrieve pFielTime - Points to the FILETIME structure Return Value: An HRESULT --*/ HRESULT InfGetStringAsFileTime( IN INFCONTEXT *pInfContext, IN UINT uFieldIndex, OUT FILETIME *pFileTime ) { HRESULT hRetval = E_FAIL; TString strDate; hRetval = pInfContext && pFileTime ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { hRetval = InfGetString(pInfContext, uFieldIndex, &strDate); } if (SUCCEEDED(hRetval)) { hRetval = StringTimeToFileTime(strDate, pFileTime); } return hRetval; } /*++ Routine Name IsDateInLineNoOlderThanDriverDate Routine Description: This routines process the current line of inf and determinate whether the date in the line is not older than that of driver. Arguments: pInfContext - Points to the current context of an INF pDriverFileTime - File time of the actual driver pdwWarnLevelSrv - Points to the warning level for server SKU pdwWarnLevelWks - Points to the warning level for wks SKU pstrReplacementDriver - The replacement driver. pbHasUnidrv54 - Points to BOOL variable indicating if the driver has a Unidrv5.4 if function returns S_OK. Return Value: An HRESULT - S_OK means the date in the current line is no older than that of the driver --*/ HRESULT IsDateInLineNoOlderThanDriverDate( IN INFCONTEXT *pInfContext, IN FILETIME *pDriverFileTime, OUT UINT *puWarnLevelSrv, OUT UINT *puWarnLevelWks, OUT TString *pstrReplacementDriver, OUT BOOL *pbHasUnidrv54 ) { HRESULT hRetval = E_FAIL; INT iWarnLevel = 0; FILETIME FileTimeInInf = {0}; DWORD dwFieldCount; hRetval = pInfContext && pDriverFileTime && puWarnLevelSrv && puWarnLevelWks && pstrReplacementDriver && pbHasUnidrv54 ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { dwFieldCount = SetupGetFieldCount(pInfContext); hRetval = SetupGetIntField(pInfContext, kWarnLevelSrv, &iWarnLevel) ? S_OK: GetLastErrorAsHResult(); if (SUCCEEDED(hRetval)) { *puWarnLevelSrv = iWarnLevel; hRetval = SetupGetIntField(pInfContext, kWarnLevelWks, &iWarnLevel) ? S_OK: GetLastErrorAsHResult(); } if (SUCCEEDED(hRetval)) { *puWarnLevelWks = iWarnLevel; hRetval = InfGetString(pInfContext, kReplacementDriver, pstrReplacementDriver); } if (SUCCEEDED(hRetval) && (dwFieldCount >= kUnidrv54)) { INT iUniDrv54 = 0; // // Unidrv5.4 field is optional // if(FAILED(SetupGetIntField(pInfContext, kUnidrv54, &iUniDrv54) ? S_OK: GetLastErrorAsHResult())) { *pbHasUnidrv54 = FALSE; } else { *pbHasUnidrv54 = iUniDrv54 ? TRUE : FALSE; } } if (SUCCEEDED(hRetval)) { hRetval = InfGetStringAsFileTime(pInfContext, kFileTime, &FileTimeInInf); // // Date field is optional. // if (FAILED(hRetval) && (ERROR_INVALID_PARAMETER == HRESULT_CODE(hRetval))) { hRetval = S_OK; } else if (SUCCEEDED(hRetval)) { hRetval = CompareFileTime(pDriverFileTime, &FileTimeInInf) <= 0 ? S_OK : S_FALSE ; } } } return hRetval; } /*++ Routine Name GetBlockingStatusByWksType Routine Description: Fill out the status of blocking according to the type of SKU that runs the service. Arguments: uWarnLevelSrv - The warn level for server SKU uWarnLevelSrv - The warn level for wks SKU bIsServer - Whether the SKU running printing service is server puBlockingStatus - Points to the result as status of blocking Return Value: An HRESULT --*/ HRESULT GetBlockingStatusByWksType( IN UINT uWarnLevelSrv, IN UINT uWarnLevelWks, IN BOOL bIsServer, OUT UINT *puBlockingStatus ) { HRESULT hRetval = E_FAIL; UINT uWarnLevel = 0; hRetval = puBlockingStatus ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { *puBlockingStatus &= ~BSP_BLOCKING_LEVEL_MASK; *puBlockingStatus |= BSP_PRINTER_DRIVER_OK; uWarnLevel = bIsServer ? uWarnLevelSrv : uWarnLevelWks; switch (uWarnLevel) { case kBlocked: *puBlockingStatus |= BSP_PRINTER_DRIVER_BLOCKED; break; case kWarned: *puBlockingStatus |= BSP_PRINTER_DRIVER_WARNED; break; default: hRetval = E_FAIL; break; } } return hRetval; } /*++ Routine Name IsDriverDllInExcludedSection Routine Description: Determine Whether the driver dll name is in the excluded section of printupg. Arguments: pszDriverPath - The path of the driver and this can be a full path or the file name hPrintUpgInf - The handle to printupg INF file Return Value: An HRESULT - S_OK means the driver dll is in the excluded section, S_FALSE means it is not. --*/ HRESULT IsDriverDllInExcludedSection( IN LPCTSTR pszDriverPath, IN HINF hPrintUpgInf ) { HRESULT hRetval = E_FAIL; TString strDriverFileName; INFCONTEXT InfContext; hRetval = pszDriverPath && (INVALID_HANDLE_VALUE != hPrintUpgInf) ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { hRetval = strDriverFileName.Update(FileNamePart(pszDriverPath)); } if (SUCCEEDED(hRetval) && !strDriverFileName.bEmpty()) { hRetval = SetupFindFirstLine(hPrintUpgInf, cszExcludeSection, strDriverFileName, &InfContext) ? S_OK : GetLastErrorAsHResult(); // // ERROR_LINE_NOT_FOUND is an HRESULT! // if (FAILED(hRetval) && (HRESULT_CODE(ERROR_LINE_NOT_FOUND) == HRESULT_CODE(hRetval))) { hRetval = S_FALSE; } } return hRetval; } /*++ Routine Name IsDriverInMappingSection Routine Description: Check whether the driver is mapped, aka a bad driver. Arguments: pszDriverModel - The name of the driver to check pszEnvironment - The environment of the server, such as uVersion - The major version of the driver hPrintUpgInf - The handle to the PrintUpg Inf file pFileTimeDriver - Points to the file time of the driver pdwWarnLevelSrv - Points to the warning level for server SKU pdwWarnLevelWks - Points to the warning level for wks SKU pstrReplacementDriver - The replacement driver pbHasUnidrv54 - Points to BOOL variable indicating if the driver has a Unidrv5.4 if function returns S_OK. Return Value: An HRESULT - S_OK means the driver is a bad driver and is mapped to some inbox driver, S_FALSE means the driver is not. --*/ HRESULT IsDriverInMappingSection( IN LPCTSTR pszModelName, IN LPCTSTR pszEnvironment, IN UINT uVersion, IN HINF hPrintUpgInf, IN FILETIME *pFileTimeDriver, OUT UINT *puWarnLevelSrv, OUT UINT *puWarnLevelWks, OUT TString *pstrReplacementDriver, OUT BOOL *pbHasUnidrv54 ) { HRESULT hRetval = E_FAIL; UINT uWarnLevelSrv = 0; UINT uWarnLevelWks = 0; INFCONTEXT InfContext; TString strMappingSection; TString strReplacementDriver; hRetval = pszModelName && pszEnvironment && (INVALID_HANDLE_VALUE != hPrintUpgInf) && pFileTimeDriver && puWarnLevelSrv && puWarnLevelWks && pstrReplacementDriver && pbHasUnidrv54 ? S_OK : E_INVALIDARG; if (SUCCEEDED(hRetval)) { *puWarnLevelSrv = 0; *puWarnLevelWks = 0; hRetval = GetSectionName(pszEnvironment, uVersion, &strMappingSection); } if (SUCCEEDED(hRetval)) { hRetval = SetupFindFirstLine(hPrintUpgInf, strMappingSection, pszModelName, &InfContext) ? S_FALSE : GetLastErrorAsHResult(); } // // This code assumes that: // // There can be multiple lines for the same printer driver, but they // are sorted in non-descreasing order by date, the last field of the // line. The fist line that has the date no older than the driver's // date is used. // // An interesting case would be like (since date is optional) // // "HP LaserJet 4" = "HP LaserJet 4", 1, 2, "11/28/1999" // "HP LaserJet 4" = "HP LaserJet 4", 2, 1 // // If a date is empty then the driver of all dates are blocked, hence // an empty date means close to a very late date in the future. // for (;S_FALSE == hRetval;) { hRetval = IsDateInLineNoOlderThanDriverDate(&InfContext, pFileTimeDriver, &uWarnLevelSrv, &uWarnLevelWks, &strReplacementDriver, pbHasUnidrv54); if (S_FALSE == hRetval) { hRetval = SetupFindNextMatchLine(&InfContext, pszModelName, &InfContext) ? S_FALSE : GetLastErrorAsHResult(); } } // // ERROR_LINE_NOT_FOUND is an HRESULT! // if (FAILED(hRetval) && (HRESULT_CODE(ERROR_LINE_NOT_FOUND) == HRESULT_CODE(hRetval))) { hRetval = S_FALSE; } if (S_OK == hRetval) { *puWarnLevelSrv = uWarnLevelSrv; *puWarnLevelWks = uWarnLevelWks; hRetval = pstrReplacementDriver->Update(strReplacementDriver); } return hRetval; } /*++ Routine Name bFoundSwitch Routine Description: Checks if the switch pszFlag is given at the command prompt. If it is it tries to find (the compressed) printupg at this location and decompress it into pszTempFileName. Arguments: pszFlag - Flag pszTempFileName - The name of the temporary file to which the compressed printupg.inf is decompressed. Return Value: A BOOL - TRUE if path was found and file successfully decompressed FALSE otherwise --*/ BOOL bFoundSwitch(IN TCHAR *pszFlag, IN TCHAR *pszTempFileName) { BOOL bRet = FALSE; TCHAR szInstallPath[MAX_PATH]; HRESULT hRet; int nr_args; LPTSTR *ppszCommandLine = CommandLineToArgvW(GetCommandLine(), &nr_args); if (ppszCommandLine == NULL) { // // Note GlobalFree does NOT take NULL argument! // (generates an access violation!) // return FALSE; } for (int i = 0; i < nr_args; i++) { if (!_tcsncicmp(ppszCommandLine[i], pszFlag, _tcslen(pszFlag))) { TCHAR *pszPath = ppszCommandLine[i] + _tcslen(pszFlag); // // Only check if a non-zero length path was specified // if (_tcslen(pszPath)) { // // Add "\" if it is not already the last charachter in the path. // Append printupg.inf to path // hRet = StringCchCopy(szInstallPath, COUNTOF(szInstallPath), pszPath); if (SUCCEEDED(hRet) && (szInstallPath[_tcslen(szInstallPath)-1] != _T('\\'))) { hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("\\")); } if(SUCCEEDED(hRet)) { hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("printupg.inf")); } if (SUCCEEDED(hRet)) { hRet = HRESULT_FROM_WIN32(SetupDecompressOrCopyFile(szInstallPath, pszTempFileName, NULL)); } if(SUCCEEDED(hRet)) { bRet = TRUE; } else { SetLastError(HRESULT_CODE(hRet)); } } break; } } GlobalFree(ppszCommandLine); return bRet; } /*++ Routine Name CreateInfHandle Routine Description: Creates a handle to printupg.inf. The function first tries to find the directory where printupg.inf resides. First it checks is the flag /m: was found at the command prompt. If it is it looks in the specified directory. If it does not find it there - or if no /s: flag was given - it checks the directory specified after /m: and if it is not found there it checks the directory in which winnt32.exe was started up from. Arguments: pszTempFileName - The name of the temporary file to which the compressed printupg.inf is decompressed. hInfFile - Pointer to a the printupg.inf file's handle Return Value: A BOOL - TRUE if success; FALSE otherwise --*/ BOOL CreateInfHandle(IN TCHAR *pszTempFileName, OUT HINF *hInfFile){ BOOL bRet = FALSE; BOOL bFoundInf = bFoundSwitch(_T("/m:"), pszTempFileName); if (!bFoundInf) { bFoundInf = bFoundSwitch(_T("/s:"), pszTempFileName); } if (!bFoundInf) { TCHAR szInstallPath[MAX_PATH]; // // szInstallPath will contain the full path for winnt32.exe // if (!GetModuleFileName(NULL, szInstallPath, COUNTOF(szInstallPath))) { goto Cleanup; } szInstallPath[COUNTOF(szInstallPath) - 1] = TEXT('\0'); // // Keep the directory, but exchange winnt32.exe for printupg.inf // TCHAR *pszTemp = (TCHAR *) _tcsrchr(szInstallPath, _T('\\')); HRESULT hRet; if(!pszTemp) { goto Cleanup; } pszTemp++; *pszTemp = _T('\0'); if(FAILED(hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("printupg.inf")))) { SetLastError(HRESULT_CODE(hRet)); goto Cleanup; } // // Did we find printupg.inf in the local directory? // if (SetupDecompressOrCopyFile(szInstallPath, pszTempFileName, NULL) != ERROR_SUCCESS) { goto Cleanup; } } *hInfFile = SetupOpenInfFile(pszTempFileName, _T("PrinterUpgrade"), INF_STYLE_WIN4, NULL); if ((*hInfFile) != INVALID_HANDLE_VALUE) { bRet = TRUE; } Cleanup: return bRet; } /*++ Routine Name GetTempInfFile Routine Description: Creates a temporary file and returns its name (and full path) in pszTempFileName Arguments: pszTempFileName - The full path and name of the temporary file Must have length MAX_PATH Return Value: A BOOL - TRUE if success; FALSE otherwise --*/ BOOL GetTempInfFile(OUT TCHAR *pszTempFileName){ TCHAR szTempPath[MAX_PATH]; BOOL bRet = FALSE; if (!GetTempPath(COUNTOF(szTempPath), szTempPath)) { goto Cleanup; } if (!GetTempFileName(szTempPath, _T("upg"), 0, pszTempFileName)) { pszTempFileName[0] = _T('\0'); goto Cleanup; } bRet = TRUE; Cleanup: return bRet;} /*++ Routine Name GetProductType Routine Description: Check whether the product type of the running version is Workstation. Arguments: bIsWrk - Boolean indicating if the product type of the running version is Workstation (i.e. not Server) Return Value: A BOOL - TRUE if success; FALSE otherwise --*/ BOOL GetProductType(OUT BOOL *bIsWrk) { OSVERSIONINFOEX osvi; // // Try calling GetVersionEx using the OSVERSIONINFOEX structure. // If that fails, check registry instead // ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if ( GetVersionEx ((OSVERSIONINFO *) &osvi) ) { if ( osvi.wProductType == VER_NT_WORKSTATION ) { *bIsWrk = TRUE; } else { *bIsWrk = FALSE; } } else { HKEY hKey; TCHAR szProductType[MAX_PATH]; DWORD dwBufLen; if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) { return FALSE; } dwBufLen = sizeof(szProductType); if (RegQueryValueEx(hKey, _T("ProductType"), NULL, NULL, (LPBYTE) szProductType, &dwBufLen) != ERROR_SUCCESS) { RegCloseKey(hKey); return FALSE; } RegCloseKey( hKey ); szProductType[COUNTOF(szProductType)-1] = _T('\0'); if ( lstrcmpi( _T("WINNT"), szProductType) == 0 ) { *bIsWrk = TRUE; } else { *bIsWrk = FALSE; } } return TRUE; } /*++ Routine Name SetupCallback Routine Description: Calls the callback function after setting up the parameters. Arguments: BlockingStatus - The blocking status of the driver bHasInBox - Boolean indicating if there exists a replacement driver for the driver bHasUnidrv54 - Boolean indicating if there exists a Unidrv5.4 for the driver pszDriverName - The name of the driver CompatibilityCallback - The Callback funtcion Context - Argument for the callback function Return Value: A BOOL - TRUE if callback called successfull or if the driver is not blocked FALSE otherwise --*/ BOOL SetupCallback(IN INT BlockingStatus, IN BOOL bHasInBox, IN BOOL bHasUnidrv54, IN PCTSTR pszDriverName, IN PCOMPAIBILITYCALLBACK CompatibilityCallback, IN LPVOID Context){ COMPATIBILITY_ENTRY CompEntry = {0}; CompEntry.Description = (TCHAR *) pszDriverName; CompEntry.RegKeyName = NULL; CompEntry.RegValName = NULL; CompEntry.RegValDataSize= 0; CompEntry.RegValData = NULL; CompEntry.SaveValue = NULL; CompEntry.Flags = 0; /*++ case 0: Driver not blocked - will not happen here! case 1: Driver Blocked case 2: Driver Warned case n: Illegal blocking status - ignore --*/ switch (BlockingStatus) { case kBlocked: if (bHasInBox && bHasUnidrv54) { CompEntry.HtmlName = _T("CompData\\upgbyy.htm"); CompEntry.TextName = _T("CompData\\upgbyy.txt"); } else if (bHasInBox) { CompEntry.HtmlName = _T("CompData\\upgbyn.htm"); CompEntry.TextName = _T("CompData\\upgbyn.txt"); } else { CompEntry.HtmlName = _T("CompData\\upgbnn.htm"); CompEntry.TextName = _T("CompData\\upgbnn.txt"); } break; case kWarned: if (bHasInBox) { CompEntry.HtmlName = _T("CompData\\upgwy.htm"); CompEntry.TextName = _T("CompData\\upgwy.txt"); } else { CompEntry.HtmlName = _T("CompData\\upgwn.htm"); CompEntry.TextName = _T("CompData\\upgwn.txt"); } break; default: return TRUE; } return CompatibilityCallback(&CompEntry,Context); } /*++ Entry point for prntwrn.dll Return Value: A BOOL - FALSE if something failed TRUE in all other cases --*/ BOOL PrntWrn( PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context ) { BOOL bRet = FALSE; HRESULT hRetval = S_OK; PDRIVER_INFO_3 pInstalledDrivers = NULL; DWORD dwMemoryNeeded = 0, cInstalledDrivers = 0; HINF hInfFile = INVALID_HANDLE_VALUE; TCHAR szTempFileName[MAX_PATH+1] = _T("\0"); BOOL bIsWrk; if (!GetProductType(&bIsWrk)) { goto Cleanup; } if (!GetTempInfFile(szTempFileName)) { goto Cleanup; } if (!CreateInfHandle(szTempFileName, &hInfFile)) { goto Cleanup; } // // ISSUE-2002/03/14-mikaelho // We will only warn for printer drivers of the same platform. // // // Note - EnumPrinterDrivers succeedes if there are no drivers!! // if (!EnumPrinterDrivers(NULL, LOCAL_ENVIRONMENT, 3, NULL, 0, &dwMemoryNeeded, &cInstalledDrivers)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { pInstalledDrivers = (PDRIVER_INFO_3) LocalAlloc(LPTR, dwMemoryNeeded); if (pInstalledDrivers == NULL) { goto Cleanup; } } else { goto Cleanup; } } // // No drivers installed! // if (!pInstalledDrivers) { bRet = TRUE; goto Cleanup; } // // Copy all the installed drivers into pInstalledDrivers array // if (!EnumPrinterDrivers(NULL, LOCAL_ENVIRONMENT, 3, (LPBYTE) pInstalledDrivers, dwMemoryNeeded, &dwMemoryNeeded, &cInstalledDrivers)) { goto Cleanup; } // // Check all installed drivers // for (DWORD cDrivers = 0; SUCCEEDED(hRetval) && (cDrivers < cInstalledDrivers); cDrivers++) { FILETIME DriverFileTime; BOOL bHasUnidrv54 = FALSE; TString strReplacementDriver; UINT uBlockingStatus = 0; UINT uWarnLevelSrv = 0; UINT uWarnLevelWks = 0; if (SUCCEEDED(GetFileTimeByName(pInstalledDrivers[cDrivers].pDriverPath, &DriverFileTime))) { hRetval = IsDriverDllInExcludedSection(pInstalledDrivers[cDrivers].pDriverPath, hInfFile); // // S_FALSE means that the driver is not in excluded driverfiles secion. // if (S_FALSE == hRetval) { hRetval = IsDriverInMappingSection(pInstalledDrivers[cDrivers].pName, LOCAL_ENVIRONMENT, pInstalledDrivers[cDrivers].cVersion, hInfFile, &DriverFileTime, &uWarnLevelSrv, &uWarnLevelWks, &strReplacementDriver, &bHasUnidrv54); // // S_OK means that driver is blocked or warned // if (S_OK == hRetval) { if (SUCCEEDED(GetBlockingStatusByWksType(uWarnLevelSrv, uWarnLevelWks, !bIsWrk, &uBlockingStatus))) { if (!SetupCallback(uBlockingStatus, !strReplacementDriver.bEmpty(), bHasUnidrv54, pInstalledDrivers[cDrivers].pName, CompatibilityCallback, Context)) { goto Cleanup; } } } } } } if(SUCCEEDED(hRetval)) { bRet = TRUE; } Cleanup: LocalFree(pInstalledDrivers); if (hInfFile != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInfFile); } if (_tcslen(szTempFileName)) { DeleteFile(szTempFileName); } return bRet; }