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.
1367 lines
34 KiB
1367 lines
34 KiB
/*++
|
|
|
|
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<LPTSTR>(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|