Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2238 lines
73 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
All rights reserved.
Module Name:
printupg.cxx
Abstract:
Code to implement printupg. Please refer to printupg.hxx for an overview
of printupg feature set.
Author:
Larry Zhu (LZhu) 20-Feb-2001
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "printupg.hxx"
/*++
Routine Name
PSetupIsCompatibleDriver
Routine Description:
Check whether the driver is blocked or warned and if the driver is blocked
or warned, return the blocking status and the replacement driver, if any.
Arguments:
pszServer - The server that needs to check for bad driver. If
pszServer is NULL, that means the local machine
pszDriverModel - The name of the driver to check
pszDriverPath - The path of the driver, this can be a full path
or the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
dwVersion - The major version of the driver
pFileTimeDriver - The FileTime of the driver
puBlockingStatus - Points to status of blocking
ppszReplacementDriver - Points to the NULL terminating name of the replacement
driver. A *NULL* string (instead of an empty string)
means there is no replacement driver
Return Value:
A BOOL - TRUE if success; FALSE otherwise, Call GetLastError()
to get the Error code. Pass a NULL to ppszReplacementDriver
will not receive the name of replacement driver otherwise
Call PSetupFreeMem to free the received string pointed by
ppszReplacementDriver
--*/
BOOL
PSetupIsCompatibleDriver(
IN LPCTSTR pszServer, OPTIONAL
IN LPCTSTR pszDriverModel,
IN LPCTSTR pszDriverPath, // main rendering driver dll
IN LPCTSTR pszEnvironment,
IN DWORD dwVersion,
IN FILETIME *pFileTimeDriver,
OUT DWORD *pdwBlockingStatus,
OUT LPTSTR *ppszReplacementDriver OPTIONAL // caller must free it.
)
{
HRESULT hRetval = E_FAIL;
UINT uBlockingStatus = 0;
TString strReplacementDriver;
hRetval = pszDriverModel && pszDriverPath && pszEnvironment && pFileTimeDriver && pdwBlockingStatus ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = 0;
if (ppszReplacementDriver)
{
*ppszReplacementDriver = NULL;
}
hRetval = IsLocalMachineServer();
}
if (SUCCEEDED(hRetval))
{
hRetval = InternalCompatibleDriverCheck(pszDriverModel,
pszDriverPath,
pszEnvironment,
pFileTimeDriver,
cszUpgradeInf,
dwVersion,
S_OK == hRetval ? TRUE : FALSE, // bIsServer
&uBlockingStatus,
&strReplacementDriver);
}
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = uBlockingStatus;
if ((BSP_PRINTER_DRIVER_OK != (*pdwBlockingStatus & BSP_BLOCKING_LEVEL_MASK)) && ppszReplacementDriver && !strReplacementDriver.bEmpty())
{
*ppszReplacementDriver = AllocStr(strReplacementDriver);
hRetval = ppszReplacementDriver ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus |= BSP_INBOX_DRIVER_AVAILABLE;
}
}
}
SetLastError(SUCCEEDED(hRetval) ? ERROR_SUCCESS : HRESULT_CODE(hRetval));
return SUCCEEDED(hRetval);
}
/*++
Routine Name:
AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry
Routine Description:
This routine tries to add the printer driver and it is blocked or
warned, it popups a message box either indicates the driver is blocked
and installation will abort or at the case of warned driver, whether
to preceed the driver installation.
Arguments:
pszServer - The server that needs to check for bad driver. If
pszServer is NULL, that means the local machine
pDriverInfo6 - Points to DRINVER_INFO_6 structor
dwAddDrvFlags - Flags used in AddPrinterDriver
bIsDriverPathFullPath - Whether the driverpath is a full path
bOfferReplacement - Whether to offer replacement
bPopupUI - Whether to popup UI
ppszReplacementDriver - Points to the replacement driver
pdwBlockingStatus - Points to blocking status of the driver
Return Value:
An BOOL - GetLastError() on failure
--*/
BOOL
AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry(
IN LPCTSTR pszServer, OPTIONAL
IN DRIVER_INFO_6 *pDriverInfo6,
IN DWORD dwAddDrvFlags,
IN BOOL bIsDriverPathFullPath,
IN BOOL bOfferReplacement,
IN BOOL bPopupUI,
OUT LPTSTR *ppszReplacementDriver,
OUT DWORD *pdwBlockingStatus
)
{
HRESULT hRetval = E_FAIL;
DWORD dwLevel = 6;
FILETIME DriverFileTime;
hRetval = pDriverInfo6 && ppszReplacementDriver && pdwBlockingStatus ? S_OK : E_INVALIDARG;
//
// Set APD_NO_UI flag and call AddPrinterDriver.
//
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = BSP_PRINTER_DRIVER_OK;
*ppszReplacementDriver = NULL;
dwAddDrvFlags |= APD_NO_UI;
hRetval = AddPrinterDriverEx(const_cast<LPTSTR>(pszServer),
dwLevel,
reinterpret_cast<BYTE*>(pDriverInfo6),
dwAddDrvFlags) ? ERROR_SUCCESS : GetLastErrorAsHResult();
}
for ( dwLevel = 4; (FAILED(hRetval) && (ERROR_INVALID_LEVEL == HRESULT_CODE(hRetval))) && (dwLevel > 1) ; --dwLevel ) {
//
// Since DRIVER_INFO_2, 3, 4 are subsets of DRIVER_INFO_6 and all fields
// are at the beginning these calls can be made with same buffer
//
hRetval = AddPrinterDriverEx(const_cast<LPTSTR>(pszServer),
dwLevel,
reinterpret_cast<BYTE*>(pDriverInfo6),
dwAddDrvFlags) ? S_OK : GetLastErrorAsHResult();
}
//
// Set the blocking status information (either blocked or warned) from the
// server.
//
// Show printupg ui and get the replacement driver from printupg.inf on
// client and get user's response and retry AddPrinterDriver with level
// dwLevel.
//
if (FAILED(hRetval) && bPopupUI && ((ERROR_PRINTER_DRIVER_BLOCKED == HRESULT_CODE(hRetval)) || (ERROR_PRINTER_DRIVER_WARNED == HRESULT_CODE(hRetval))))
{
*pdwBlockingStatus = (ERROR_PRINTER_DRIVER_BLOCKED == HRESULT_CODE(hRetval)) ? BSP_PRINTER_DRIVER_BLOCKED : BSP_PRINTER_DRIVER_WARNED;
hRetval = PrintUpgRetry(pszServer,
dwLevel,
pDriverInfo6,
dwAddDrvFlags,
bIsDriverPathFullPath,
bOfferReplacement,
pdwBlockingStatus,
ppszReplacementDriver);
}
SetLastError(SUCCEEDED(hRetval) ? ERROR_SUCCESS : HRESULT_CODE(hRetval));
return SUCCEEDED(hRetval);
}
/*++
Routine Name:
BlockedDriverPrintUpgUI
Routine Description:
This routine checks the printupg.inf and see if the driver is there. If the
driver is there, consider it blocked even if it is warned. Then it popups a
message box either indicates the driver is blocked and ask whether the user
wants to proceed to install a replacement driver it has one.
Arguments:
pszServer - The server that needs to check for bad driver. If
pszServer is NULL, that means the local machine
pDriverInfo6 - Points to DRINVER_INFO_6 structor
bIsDriverPathFullPath - Whether the driverpath is a full path
bOfferReplacement - Whether to offer replacement
bPopupUI - Whether to popup UI
ppszReplacementDriver - Points to the replacement driver
pdwBlockingStatus - Points to blocking status of the driver
Return Value:
An BOOL - GetLastError() on failure
--*/
BOOL
BlockedDriverPrintUpgUI(
IN LPCTSTR pszServer, OPTIONAL
IN DRIVER_INFO_6 *pDriverInfo6,
IN BOOL bIsDriverPathFullPath,
IN BOOL bOfferReplacement,
IN BOOL bPopupUI,
OUT LPTSTR *ppszReplacementDriver,
OUT DWORD *pdwBlockingStatus
)
{
HRESULT hRetval = E_FAIL;
DWORD dwBlockingStatusOnClient = BSP_PRINTER_DRIVER_OK;
hRetval = pDriverInfo6 && ppszReplacementDriver && pdwBlockingStatus ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = BSP_PRINTER_DRIVER_OK;
*ppszReplacementDriver = NULL;
hRetval = IsDriverBadLocally(pszServer,
pDriverInfo6,
bIsDriverPathFullPath,
&dwBlockingStatusOnClient,
ppszReplacementDriver);
//
// Get the replacement driver information
//
if (SUCCEEDED(hRetval) && (BSP_PRINTER_DRIVER_OK != (dwBlockingStatusOnClient & BSP_BLOCKING_LEVEL_MASK)))
{
*pdwBlockingStatus |= (dwBlockingStatusOnClient & ~BSP_BLOCKING_LEVEL_MASK) | BSP_PRINTER_DRIVER_BLOCKED;
}
}
if (SUCCEEDED(hRetval) && bPopupUI && (BSP_PRINTER_DRIVER_BLOCKED & *pdwBlockingStatus))
{
hRetval = PrintUpgRetry(pszServer,
6, // dwLevel, do not care in the case of blocked driver
pDriverInfo6,
0, // dwAddDrvFlags, do not care in the case of blocked driver
bIsDriverPathFullPath,
bOfferReplacement,
pdwBlockingStatus,
ppszReplacementDriver);
}
SetLastError(SUCCEEDED(hRetval) ? ERROR_SUCCESS : HRESULT_CODE(hRetval));
return SUCCEEDED(hRetval);
}
/*++
Routine Name:
PrintUpgRetry
Routine Description:
This routine popups up a message box either indicates the driver is blocked
or warned and asks the user how to preceed. In the case of warned driver,
whether to preceed the driver installation and retry AddPrinterDriver if
the user wants to proceed with a warned driver.
Arguments:
pszServer - Remote machine that has the driver files
dwLevel - Driver info level, since DRIVER_INFO_6
is a super set of level 4, 3, and 2,
the driver info structure is shared
pDriverInfo6 - Points to DRIVER_INFO_6 structure
dwAddDrvFlags - Flags used to AddPrinterDriver
bIsDriverPathFullPath - Whether the driverpath is a full path
bOffereReplacement - Whether to offer a replacement driver
pdwBlockingStatus - Points to blocking status on server
ppszReplacementDriver - Points to the replacement driver
Return Value:
An HRESULT
--*/
HRESULT
PrintUpgRetry(
IN LPCTSTR pszServer, OPTIONAL
IN DWORD dwLevel,
IN DRIVER_INFO_6 *pDriverInfo6,
IN DWORD dwAddDrvFlags,
IN BOOL bIsDriverPathFullPath,
IN BOOL bOfferReplacement,
IN OUT DWORD *pdwBlockingStatus,
OUT LPTSTR *ppszReplacementDriver
)
{
HRESULT hRetval = E_FAIL;
hRetval = pDriverInfo6 && pdwBlockingStatus && ppszReplacementDriver && ((6 == dwLevel) || (dwLevel >= 2) && (dwLevel <= 4)) ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
*ppszReplacementDriver = NULL;
hRetval = PrintUpgUI(pszServer,
pDriverInfo6,
bIsDriverPathFullPath,
bOfferReplacement,
pdwBlockingStatus,
ppszReplacementDriver);
//
// There are 4 cases here:
// 1. For warned driver and the user instructs to install it, try
// AddPrinterDriverEx again with APD_INSTALL_WARNED_DRIVER.
// 2. If the user wants to cancel, set the last error correctly and
// abort.
// 3. If the user wants to install the replacement driver, we will
// set the error code correctly and do not install the replacement
// driver at this moment since we shall clean ourself up first.
// 4. If other errors occur, we will just return the correct error
// code.
//
// For case 1, 2, 4, we do not return the replacement driver because
// I can not see any reason to do so.
//
if (FAILED(hRetval) || !(*pdwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED)) // except case 3
{
LocalFreeMem(*ppszReplacementDriver);
*ppszReplacementDriver = NULL;
}
if (SUCCEEDED(hRetval) && (*pdwBlockingStatus & BSP_PRINTER_DRIVER_PROCEEDED)) // case 1
{
dwAddDrvFlags |= APD_INSTALL_WARNED_DRIVER;
hRetval = AddPrinterDriverEx(const_cast<LPTSTR>(pszServer),
dwLevel,
reinterpret_cast<BYTE*>(pDriverInfo6),
dwAddDrvFlags) ? ERROR_SUCCESS : GetLastErrorAsHResult();
}
else if (SUCCEEDED(hRetval) && (*pdwBlockingStatus & BSP_PRINTER_DRIVER_CANCELLED)) // case 2
{
hRetval = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
else if (SUCCEEDED(hRetval) && (*pdwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED)) // case 3
{
hRetval = HResultFromWin32((*pdwBlockingStatus & BSP_PRINTER_DRIVER_BLOCKED) ? ERROR_PRINTER_DRIVER_BLOCKED : ERROR_PRINTER_DRIVER_WARNED);
}
}
return hRetval;
}
/*++
Routine Name:
PrintUpgUI
Routine Description:
This routine asks ntprint.dll to popup a message box either indicates
the driver is blocked and installation will abort or at the case of
warned driver, whether to preceed the driver installation.
Arguments:
pszServer - Remote machine that has the driver files
pDriverInfo6 - Points to DRINVER_INFO_6 structor
bIsDriverPathFullPath - Whether the driverpath is a full path
bOffereReplacement - Whether to offer a replacement driver
pdwBlockingStatus - Points to blocking status on server
ppszReplacementDriver - Points to the replacement driver
Return Value:
An HRESULT
--*/
HRESULT
PrintUpgUI(
IN LPCTSTR pszServer, OPTIONAL
IN DRIVER_INFO_6 *pDriverInfo6,
IN BOOL bIsDriverPathFullPath,
IN BOOL bOfferReplacement,
IN OUT DWORD *pdwBlockingStatus,
OUT LPTSTR *ppszReplacementDriver
)
{
HRESULT hRetval = E_FAIL;
DWORD dwBlockingStatusOnClient = BSP_PRINTER_DRIVER_OK;
hRetval = pDriverInfo6 && pdwBlockingStatus && ppszReplacementDriver ? S_OK : E_INVALIDARG;
//
// Take the replacement driver information from local client.
//
if (SUCCEEDED(hRetval) && bOfferReplacement)
{
*ppszReplacementDriver = NULL;
hRetval = IsDriverBadLocally(pszServer,
pDriverInfo6,
bIsDriverPathFullPath,
&dwBlockingStatusOnClient,
ppszReplacementDriver);
//
// Get the replacement driver information
//
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus |= (dwBlockingStatusOnClient & ~BSP_BLOCKING_LEVEL_MASK);
}
}
//
// Get the user's response
//
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus &= ~BSP_USER_RESPONSE_MASK;
hRetval = InternalPrintUpgUI(pDriverInfo6->pName,
pDriverInfo6->pDriverPath, // main rendering driver dll
pDriverInfo6->pEnvironment,
pDriverInfo6->cVersion,
pdwBlockingStatus);
}
return hRetval;
}
/*++
Routine Name
InfIsCompatibleDriver
Routine Description:
Check whether the driver is blocked or warned and if the driver is blocked
or warned, return the blocking status and the replacement driver, if any.
Arguments:
pszDriverModel - The name of the driver to check
pszDriverPath - The path of the driver, this can be a full path
or the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
hInf - Handle to printupg inf
puBlockingStatus - Points to status of blocking
ppszReplacementDriver - Points to the NULL terminating name of the replacement
driver. A *NULL* string (instead of an empty string)
means there is no replacement driver
Return Value:
A BOOL - TRUE if success; FALSE otherwise, Call GetLastError()
to get the Error code. Pass a NULL to ppszReplacementDriver
will not receive the name of replacement driver otherwise
Call PSetupFreeMem to free the received string pointed by
ppszReplacementDriver
--*/
BOOL
InfIsCompatibleDriver(
IN LPCTSTR pszDriverModel,
IN LPCTSTR pszDriverPath, // main rendering driver dll
IN LPCTSTR pszEnvironment,
IN HINF hInf,
OUT DWORD *pdwBlockingStatus,
OUT LPTSTR *ppszReplacementDriver OPTIONAL // caller must free it.
)
{
HRESULT hRetval = E_FAIL;
UINT uBlockingStatus = 0;
DWORD dwMajorVersion = 0;
BOOL bIsServer = FALSE;
TString strReplacementDriver;
FILETIME DriverFileTime;
hRetval = pszDriverModel && pszDriverPath && pszEnvironment && (hInf != INVALID_HANDLE_VALUE) && pdwBlockingStatus ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = 0;
if (ppszReplacementDriver)
{
*ppszReplacementDriver = NULL;
}
hRetval = GetPrinterDriverVersion(pszDriverPath, &dwMajorVersion, NULL);
}
if (SUCCEEDED(hRetval))
{
hRetval = IsLocalMachineServer();
}
if (SUCCEEDED(hRetval))
{
bIsServer = S_OK == hRetval ? TRUE : FALSE;
hRetval = GetFileTimeByName(pszDriverPath, &DriverFileTime);
}
if (S_OK == hRetval)
{
hRetval = InternalCompatibleInfDriverCheck(pszDriverModel,
pszDriverPath,
pszEnvironment,
&DriverFileTime,
hInf,
dwMajorVersion,
bIsServer,
&uBlockingStatus,
&strReplacementDriver);
}
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus = uBlockingStatus;
if ((BSP_PRINTER_DRIVER_OK != (*pdwBlockingStatus & BSP_BLOCKING_LEVEL_MASK)) && ppszReplacementDriver && !strReplacementDriver.bEmpty())
{
*ppszReplacementDriver = AllocStr(strReplacementDriver);
hRetval = ppszReplacementDriver ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hRetval))
{
*pdwBlockingStatus |= BSP_INBOX_DRIVER_AVAILABLE;
}
}
}
SetLastError(SUCCEEDED(hRetval) ? ERROR_SUCCESS : HRESULT_CODE(hRetval));
return SUCCEEDED(hRetval);
}
/*++
Routine Name:
GetPrinterDriverVersion
Routine Description:
Gets version information about an executable file. If the file is not an
executable, it will return 0 for both major and minor version.
Arguments:
pszFileName - file name, this is either a full path for
the file is under the path in the search
sequence specified used the LoadLibrary
function.
pdwFileMajorVersion - pointer to major version
pdwFileMinorVersion - pointer to minor version
Return Value:
An HRESULT
--*/
HRESULT
GetPrinterDriverVersion(
IN LPCTSTR pszFileName,
OUT DWORD *pdwFileMajorVersion, OPTIONAL
OUT DWORD *pdwFileMinorVersion OPTIONAL
)
{
HRESULT hRetval = E_FAIL;
DWORD dwSize = 0;
UINT uLen = 0;
BYTE *pbBlock = NULL;
VS_FIXEDFILEINFO *pFileVersion = NULL;
hRetval = pszFileName && *pszFileName ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
dwSize = GetFileVersionInfoSize(const_cast<LPTSTR>(pszFileName), 0);
if (dwSize == 0)
{
hRetval = GetLastErrorAsHResult();
}
}
if (SUCCEEDED(hRetval))
{
pbBlock = new BYTE[dwSize];
hRetval = pbBlock ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hRetval))
{
hRetval = GetFileVersionInfo(const_cast<LPTSTR>(pszFileName), 0, dwSize, pbBlock) ? S_OK : GetLastErrorAsHResult();
}
//
// VerQueryValue does not set last error.
//
if (SUCCEEDED(hRetval))
{
hRetval = VerQueryValue(pbBlock, _T("\\"), reinterpret_cast<VOID **> (&pFileVersion), &uLen) && pFileVersion && uLen ? S_OK : E_INVALIDARG;
}
if (SUCCEEDED(hRetval))
{
hRetval = GetDriverVersionFromFileVersion(pFileVersion, pdwFileMajorVersion, pdwFileMinorVersion);
}
delete [] pbBlock;
return hRetval;
}
/*++
Routine Name:
GetDriverVersionFromFileVersion
Routine Description:
Gets driver info from a FileVersion structure.
Arguments:
pFileVersion - Points to a file info structure
pdwFileMajorVersion - pointer to major version
pdwFileMinorVersion - pointer to minor version
Return Value:
An HRESULT
--*/
HRESULT
GetDriverVersionFromFileVersion(
IN VS_FIXEDFILEINFO *pFileVersion,
OUT DWORD *pdwFileMajorVersion, OPTIONAL
OUT DWORD *pdwFileMinorVersion OPTIONAL
)
{
HRESULT hRetval = E_FAIL;
hRetval = pFileVersion ? S_OK : E_INVALIDARG;
//
// Return versions for drivers designed for Windows NT/Windows 2000,
// and marked as printer drivers.
// Hold for all dlls Pre-Daytona.
// After Daytona, printer driver writers must support
// version control or we'll dump them as Version 0 drivers.
//
if (SUCCEEDED(hRetval))
{
if (pdwFileMajorVersion)
{
*pdwFileMajorVersion = 0;
}
if (pdwFileMinorVersion)
{
*pdwFileMinorVersion = 0;
}
if (VOS_NT_WINDOWS32 == pFileVersion->dwFileOS)
{
if ((VFT_DRV == pFileVersion->dwFileType) && (VFT2_DRV_VERSIONED_PRINTER == pFileVersion->dwFileSubtype))
{
if (pdwFileMajorVersion)
{
*pdwFileMajorVersion = pFileVersion->dwFileVersionMS;
}
if (pdwFileMinorVersion)
{
*pdwFileMinorVersion = pFileVersion->dwFileVersionLS;
}
}
else if (pdwFileMajorVersion)
{
if (pFileVersion->dwProductVersionMS == pFileVersion->dwFileVersionMS)
{
*pdwFileMajorVersion = 0;
}
else
{
*pdwFileMajorVersion = pFileVersion->dwFileVersionMS;
}
}
}
}
return hRetval;
}
/*++
Routine Name:
IsDriverBadLocally
Routine Description:
This routine loads the file and gets the FILETIME of the driver and check
whether the driver is blokced or warned according the printupg.inf on the
local machine.
Arguments:
pszServer - The server that has the driver files
pDriverInfo6 - Points to DRINVER_INFO_6 structor
dwAddDrvFlags - Flags used in AddPrinterDriver
bIsDriverPathFullPath - Whether the driverpath is a full path
pdwBlockingStatus - Points to blocking status of the driver
ppszReplacementDriver - Points to the replacement driver
Return Value:
An HRESULT
--*/
HRESULT
IsDriverBadLocally(
IN LPCTSTR pszServer, OPTIONAL
IN DRIVER_INFO_6 *pDriverInfo6,
IN BOOL bIsDriverPathFullPath,
OUT DWORD *pdwBlockingStatus,
OUT LPTSTR *ppszReplacementDriver
)
{
HRESULT hRetval = E_FAIL;
DWORD dwMajorVersion = 0;
FILETIME DriverFileTime;
TString strDriverFullPath;
hRetval = pDriverInfo6 && pdwBlockingStatus && ppszReplacementDriver ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
hRetval = GetPrinterDriverPath(pszServer,
pDriverInfo6->pDriverPath,
pDriverInfo6->pEnvironment,
bIsDriverPathFullPath,
&strDriverFullPath);
}
if (SUCCEEDED(hRetval))
{
hRetval = GetFileTimeByName(strDriverFullPath, &DriverFileTime);
}
if (SUCCEEDED(hRetval))
{
hRetval = GetPrinterDriverVersion(strDriverFullPath, &dwMajorVersion, NULL);
}
if (SUCCEEDED(hRetval))
{
hRetval = PSetupIsCompatibleDriver(NULL,
pDriverInfo6->pName,
pDriverInfo6->pDriverPath,
pDriverInfo6->pEnvironment,
dwMajorVersion,
&DriverFileTime,
pdwBlockingStatus,
ppszReplacementDriver) ? S_OK : GetLastErrorAsHResult();
}
if (FAILED(hRetval) && ppszReplacementDriver && *ppszReplacementDriver)
{
LocalFreeMem(*ppszReplacementDriver);
*ppszReplacementDriver = NULL;
}
return hRetval;
}
/*++
Routine Name:
InternalPrintUpgUI
Routine Description:
This routine asks ntprint.dll to popup a message box either indicates
the driver is blocked and installation will abort or at the case of
warned driver, whether to preceed the driver installation.
Arguments:
pszDriverModel - The name of the driver to check
pszDriverPath - The path of the driver, this can be a full path
or the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
dwVersion - The major version of the driver
pdwBlockingStatus - Points to blocking status on the client
ppszReplacementDriver - Points to the name of replacement driver
Return Value:
An HRESULT - When this function is successful, user choose
either proceed to install warned driver or install
replacement driver.
--*/
HRESULT
InternalPrintUpgUI(
IN LPCTSTR pszDriverModel,
IN LPCTSTR pszDriverPath, // main rendering driver dll
IN LPCTSTR pszEnvironment,
IN DWORD dwVersion,
IN OUT DWORD *pdwBlockingStatus
)
{
DWORD hRetval = E_FAIL;
HWND hWndParent = NULL;
DWORD dwStatusResponsed = BSP_PRINTER_DRIVER_OK;
hRetval = pszDriverModel && pszDriverPath && pszEnvironment && pdwBlockingStatus ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval) && (BSP_PRINTER_DRIVER_OK != (*pdwBlockingStatus & BSP_BLOCKING_LEVEL_MASK)))
{
*pdwBlockingStatus &= ~BSP_USER_RESPONSE_MASK;
hWndParent = SUCCEEDED(GetCurrentThreadLastPopup(&hWndParent)) ? hWndParent : NULL;
//
// Ask the user what they want to do. If they don't want to proceed,
// then the error is what the would get from the localspl call.
//
// PSetupShowBlockedDriverUI can not fail!
//
*pdwBlockingStatus |= (PSetupShowBlockedDriverUI(hWndParent, *pdwBlockingStatus) & BSP_USER_RESPONSE_MASK);
}
return hRetval;
}
//
// This function is trying to get the last active popup of the top
// level owner of the current thread active window.
//
HRESULT
GetCurrentThreadLastPopup(
OUT HWND *phwnd
)
{
HWND hwndOwner, hwndParent;
HRESULT hr = E_INVALIDARG;
GUITHREADINFO ti = {0};
if( phwnd )
{
hr = E_FAIL;
*phwnd = NULL;
ti.cbSize = sizeof(ti);
if( GetGUIThreadInfo(0, &ti) && ti.hwndActive )
{
*phwnd = ti.hwndActive;
// climb up to the top parent in case it's a child window...
while( hwndParent = GetParent(*phwnd) )
{
*phwnd = hwndParent;
}
// get the owner in case the top parent is owned
hwndOwner = GetWindow(*phwnd, GW_OWNER);
if( hwndOwner )
{
*phwnd = hwndOwner;
}
// get the last popup of the owner window
*phwnd = GetLastActivePopup(*phwnd);
hr = (*phwnd) ? S_OK : E_FAIL;
}
}
return hr;
}
/*++
Routine Name
GetPrinterDriverPath
Routine Description:
Get the file full path of the driver.
Arguments:
pszServer - The server that needs to check for bad driver. If
pszServer is NULL, that means the local machine
pszDriverPath - The path of the driver, this can be a full path or
the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
bIsDriverpathFullPath - Whether pszDriverPath is the full path or just the
the file name of the driver
pstrFull - The full path of the driver
Return Value:
An HRESULT
--*/
HRESULT
GetPrinterDriverPath(
IN LPCTSTR pszServer, OPTIONAL
IN LPCTSTR pszDriverPath,
IN LPCTSTR pszEnvironment,
IN BOOL bIsDriverPathFullPath,
OUT TString *pstrFullPath
)
{
HRESULT hRetval = E_FAIL;
TCHAR szDir[MAX_PATH] = {0};
DWORD dwNeeded = 0;
hRetval = pszEnvironment && *pszEnvironment && pszDriverPath && *pszDriverPath && pstrFullPath ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval) && !bIsDriverPathFullPath)
{
hRetval = GetPrinterDriverDirectory(const_cast<LPTSTR>(pszServer), // This API is designed wrongly.
const_cast<LPTSTR>(pszEnvironment),
1, // This value must be 1
(LPBYTE)szDir,
sizeof(szDir),
&dwNeeded) ? S_OK : GetLastErrorAsHResult();
}
if (FAILED(hRetval) && (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hRetval)))
{
hRetval = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
}
//
// Add 1 '\\' between driverpath and filename. Note if the path is too
// long StrNCatBuff will truncate it and StrNCatBuff always NULL terminates
// the buffer.
//
if (SUCCEEDED(hRetval))
{
hRetval = HResultFromWin32(StrNCatBuff(szDir, COUNTOF(szDir), szDir, *szDir ? _T("\\") : _T(""), pszDriverPath, NULL));
}
if (SUCCEEDED(hRetval))
{
hRetval = pstrFullPath->bUpdate(szDir) ? S_OK : E_OUTOFMEMORY;
}
return hRetval;
}
/*++
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
InternalCompatibleDriverCheck
Routine Description:
Check whether the driver is blocked or warned and if the driver
is blocked or warned, return the replacement driver.
Arguments:
pszDriverModel - The name of the driver to check
pszDriverPath - The path of the driver, this can be a full path or
the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
pFileTimeDriver - The FileTime of the driver
pszPrintUpgInf - The PrintUpg Inf filename
uVersion - The major version of the driver
bIsServer - Where the printing services runs on an NT Server SKU
puBlockingStatus - Points to status of blocking
pstrReplacementDriver - The replacement driver.
Return Value:
An HRESULT
--*/
HRESULT
InternalCompatibleDriverCheck(
IN LPCTSTR pszDriverModel,
IN LPCTSTR pszDriverPath,
IN LPCTSTR pszEnvironment,
IN FILETIME *pFileTimeDriver,
IN LPCTSTR pszPrintUpgInf,
IN UINT uVersion,
IN BOOL bIsServer,
OUT UINT *puBlockingStatus,
OUT TString *pstrReplacementDriver
)
{
DBG_MSG(DBG_TRACE, (_T("In the InternalCompatibleDriverCheck routine\n")));
HRESULT hRetval = E_FAIL;
HINF hInf = INVALID_HANDLE_VALUE;
hRetval = pszDriverModel && pszDriverPath && pszEnvironment && pFileTimeDriver && pszPrintUpgInf && puBlockingStatus && pstrReplacementDriver ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
*puBlockingStatus = 0;
hInf = SetupOpenInfFile(pszPrintUpgInf, NULL, INF_STYLE_WIN4, NULL);
hRetval = (INVALID_HANDLE_VALUE == hInf) ? S_OK : GetLastErrorAsHResult();
}
if (SUCCEEDED(hRetval))
{
hRetval = InternalCompatibleInfDriverCheck(pszDriverModel,
pszDriverPath,
pszEnvironment,
pFileTimeDriver,
hInf,
uVersion,
bIsServer,
puBlockingStatus,
pstrReplacementDriver);
}
if (INVALID_HANDLE_VALUE != hInf)
{
SetupCloseInfFile(hInf);
}
return hRetval;
}
/*++
Routine Name
InternalCompatibleInfDriverCheck
Routine Description:
Check whether the driver is blocked or warned and if the driver
is blocked or warned, return the replacement driver.
Arguments:
pszDriverModel - The name of the driver to check
pszDriverPath - The path of the driver, this can be a full path or
the filename
pszEnvironment - The environment of the server, such as
"Windows NT x86"
pFileTimeDriver - The FileTime of the driver
hPrintUpgInf - The handle to the PrintUpg Inf file
uVersion - The major version of the driver
bIsServer - Where the printing services runs on an NT Server SKU
puBlockingStatus - Points to status of blocking
pstrReplacementDriver - The replacement driver.
Return Value:
An HRESULT
--*/
HRESULT
InternalCompatibleInfDriverCheck(
IN LPCTSTR pszModelName,
IN LPCTSTR pszDriverPath,
IN LPCTSTR pszEnvironment,
IN FILETIME *pFileTimeDriver,
IN HINF hPrintUpgInf,
IN UINT uVersion,
IN BOOL bIsServer,
OUT UINT *puBlockingStatus,
OUT TString *pstrReplacementDriver OPTIONAL
)
{
HRESULT hRetval = E_FAIL;
HINF hInf = INVALID_HANDLE_VALUE;
UINT uWarnLevelSrv = 0;
UINT uWarnLevelWks = 0;
UINT uWarnLevel = 0;
FILETIME FileTimeOfDriverInInf;
hRetval = pszModelName && pszDriverPath && pszEnvironment && pFileTimeDriver && (INVALID_HANDLE_VALUE != hPrintUpgInf) && puBlockingStatus && pstrReplacementDriver? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
hRetval = IsDriverDllInExcludedSection(pszDriverPath, hPrintUpgInf);
}
if (S_FALSE == hRetval)
{
hRetval = IsDriverInMappingSection(pszModelName,
pszEnvironment,
uVersion,
hPrintUpgInf,
pFileTimeDriver,
&uWarnLevelSrv,
&uWarnLevelWks,
pstrReplacementDriver);
if (S_OK == hRetval)
{
hRetval = GetBlockingStatusByWksType(uWarnLevelSrv, uWarnLevelWks, bIsServer, puBlockingStatus);
}
}
if (SUCCEEDED(hRetval))
{
DBG_MSG(DBG_TRACE, (_T("Driver \"%s\" Driverpath \"%s\" Environment \"%s\" Version %d WarnLevel Server %d WarnLevel Wks %d bIsServer %d *Blocking Status* 0X%X *Replacement Driver* \"%s\"\n"), pszModelName, pszDriverPath, pszEnvironment,uVersion, uWarnLevelSrv, uWarnLevelSrv, bIsServer, *puBlockingStatus, static_cast<LPCTSTR>(*pstrReplacementDriver)));
hRetval = (BSP_PRINTER_DRIVER_OK == (*puBlockingStatus & BSP_BLOCKING_LEVEL_MASK)) ? S_OK : 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
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
)
{
DBG_MSG(DBG_TRACE, (_T("In the IsDriverInMappingSection routine\n")));
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 ? 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);
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)))
{
DBG_MSG(DBG_TRACE, (_T("Driver \"%s\" is not mapped\n"), pszModelName));
hRetval = S_FALSE;
}
if (S_OK == hRetval)
{
DBG_MSG(DBG_TRACE, (_T("Driver \"%s\" is mapped\n"), pszModelName));
*puWarnLevelSrv = uWarnLevelSrv;
*puWarnLevelWks = uWarnLevelWks;
hRetval = pstrReplacementDriver->bUpdate(strReplacementDriver) ? S_OK : E_OUTOFMEMORY;
}
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.
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
)
{
HRESULT hRetval = E_FAIL;
INT iWarnLevel = 0;
FILETIME FileTimeInInf;
hRetval = pInfContext && pDriverFileTime && puWarnLevelSrv && puWarnLevelWks && pstrReplacementDriver ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
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))
{
hRetval = InfGetStringAsFileTime(pInfContext, kFileTime, &FileTimeInInf);
//
// Date field is optional.
//
if (FAILED(hRetval) && (ERROR_INVALID_PARAMETER == HRESULT_CODE(hRetval)))
{
DBG_MSG(DBG_TRACE, (_T("Date in inf is empty, drivers of all dates are blocked.\n")));
hRetval = S_OK;
}
else if (SUCCEEDED(hRetval))
{
hRetval = CompareFileTime(pDriverFileTime, &FileTimeInInf) <= 0 ? S_OK : S_FALSE ;
}
}
}
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->bFormat(_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->bUpdate(szField) ? S_OK : E_OUTOFMEMORY;
}
else if (FAILED(hRetval) && (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hRetval)))
{
pszField = new TCHAR[dwNeeded];
hRetval = pszField ? S_OK : E_OUTOFMEMORY;
DBG_MSG(DBG_TRACE, (_T("Long string encountered\n")));
if (SUCCEEDED(hRetval))
{
hRetval = SetupGetStringField(pInfContext,
uFieldIndex,
pszField,
dwNeeded,
&dwNeeded) ? S_OK : GetLastErrorAsHResult();
}
if (SUCCEEDED(hRetval))
{
hRetval = pstrField->bUpdate(pszField) ? S_OK : E_OUTOFMEMORY;
}
}
}
delete [] pszField;
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))
{
DBG_MSG(DBG_TRACE, (_T("FileTime in INF as string \"%s\"\n"), static_cast<LPCTSTR>(strDate)));
hRetval = StringTimeToFileTime(strDate, pFileTime);
}
return hRetval;
}
/*++
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
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
)
{
DBG_MSG(DBG_TRACE, (_T("In the IsDriverDllInExcludedSection routine\n")));
HRESULT hRetval = E_FAIL;
TString strDriverFileName;
INFCONTEXT InfContext;
hRetval = pszDriverPath && (INVALID_HANDLE_VALUE != hPrintUpgInf) ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
hRetval = strDriverFileName.bUpdate(FileNamePart(pszDriverPath)) ? S_OK : E_OUTOFMEMORY;
}
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;
}
DBG_MSG(DBG_TRACE, (_T("Driver Path %s driver dll %s excluded section \"%s\" Is not excluded? %d\n"), pszDriverPath, static_cast<LPCTSTR>(strDriverFileName), cszExcludeSection, hRetval));
}
return hRetval;
}
/*++
Routine Name
IsEnvironmentAndVersionNeededToCheck
Routine Description:
This routine looks up a table of environment and version to see whether it
is necessary to check for blocked/warned driver.
Arguments:
pszEnvironment - The environment where the driver runs
uVersion - The major version of the driver.
Return Value:
An HRESULT
--*/
HRESULT
IsEnvironmentAndVersionNeededToCheck(
IN LPCTSTR pszEnvironment,
IN UINT uVersion
)
{
HRESULT hRetval = E_FAIL;
static struct TPrintUPGCheckListItem
{
LPCTSTR pszEnvironment;
UINT uVersion;
} aPrintUpgCheckList[] = {
{X86_ENVIRONMENT, 2},
{X86_ENVIRONMENT, 3},
{IA64_ENVIRONMENT, 3},
};
hRetval = pszEnvironment ? S_FALSE : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
for (UINT i = 0; i < COUNTOF(aPrintUpgCheckList); i++)
{
if (!lstrcmpi(aPrintUpgCheckList[i].pszEnvironment, pszEnvironment) && (aPrintUpgCheckList[i].uVersion == uVersion))
{
hRetval = S_OK;
break;
}
}
}
return hRetval;
}
/*++
Routine Name
IsLocalMachineServer
Routine Description:
This routine determines whether the local machine is a server SKU.
Arguments:
None
Return Value:
An HRESULT - S_OK if it is a server, S_FALSE otherwise.
--*/
HRESULT
IsLocalMachineServer(
VOID
)
{
HRESULT hRetval = E_FAIL;
DWORDLONG dwlConditionMask = 0;
OSVERSIONINFOEX OsVerEx;
(VOID)ZeroMemory(&OsVerEx, sizeof(OSVERSIONINFOEX));
OsVerEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
OsVerEx.wProductType = VER_NT_SERVER;
VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );
hRetval = VerifyVersionInfo(&OsVerEx, VER_PRODUCT_TYPE, dwlConditionMask) ? S_OK : GetLastErrorAsHResult();
if (FAILED(hRetval) && (ERROR_OLD_WIN_VERSION == HRESULT_CODE(hRetval)))
{
hRetval = S_FALSE;
}
return hRetval;
}
#if DBG_PRINTUPG
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;
}
BOOL
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 ) {
if ( pInfTime->wYear < 10 )
pInfTime->wYear += 2000;
else
pInfTime->wYear += 1900;
}
return bRet;
}
LPTSTR
FileNamePart(
IN LPCTSTR pszFullName
)
{
LPTSTR pszSlash, pszTemp;
if ( !pszFullName )
return NULL;
//
// First find the : for the drive
//
if ( pszTemp = lstrchr(pszFullName, TEXT(':')) )
pszFullName = pszFullName + 1;
for ( pszTemp = (LPTSTR)pszFullName ;
pszSlash = lstrchr(pszTemp, TEXT('\\')) ;
pszTemp = pszSlash + 1 )
;
return *pszTemp ? pszTemp : NULL;
}
PVOID
LocalAllocMem(
IN UINT cbSize
)
{
return LocalAlloc( LPTR, cbSize );
}
VOID
LocalFreeMem(
IN PVOID p
)
{
LocalFree(p);
}
/*++
Routine Description:
Allocate memory and make a copy of a string field
Arguments:
pszStr : String to copy
Return Value:
Pointer to the copied string. Memory is allocated.
--*/
LPTSTR
AllocStr(
IN LPCTSTR pszStr
)
{
LPTSTR pszRet = NULL;
if ( pszStr && *pszStr ) {
pszRet = reinterpret_cast<LPTSTR>(LocalAllocMem((lstrlen(pszStr) + 1) * sizeof(*pszRet)));
if ( pszRet )
lstrcpy(pszRet, pszStr);
}
return pszRet;
}
//
// For some reason these are needed by spllib when you use StrNCatBuf.
// This doesn't make any sense, but just implement them.
//
extern "C"
LPVOID
DllAllocSplMem(
DWORD cbSize
)
{
return LocalAllocMem(cbSize);
}
HRESULT
TestPrintUpgOne(
IN LPCTSTR pszDriverModel,
IN LPCTSTR pszDriverPath,
IN LPCTSTR pszEnvironment,
IN LPCTSTR pszDriverTime,
IN LPCTSTR pszPrintUpgInf,
IN UINT uVersion,
IN BOOL bIsServer,
IN UINT uBlockingStatusInput,
IN LPCTSTR pszReplacementDriver,
IN BOOL bSuccess
)
{
HRESULT hRetval = E_FAIL;
UINT uBlockingStatus = 0;
TString strReplacementDriver;
FILETIME FileTimeDriver;
hRetval = pszDriverModel && pszDriverPath && pszEnvironment && pszDriverTime && pszPrintUpgInf && pszReplacementDriver ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hRetval))
{
hRetval = StringTimeToFileTime(pszDriverTime, &FileTimeDriver);
}
//if (SUCCEEDED(hRetval))
//{
// hRetval = IsEnvironmentAndVersionNeededToCheck(pszEnvironment, uVersion);
//}
//if (S_OK == hRetval)
if (SUCCEEDED(hRetval))
{
DBG_MSG(DBG_TRACE, (_T("TEST case: Driver of time %s Expected status %d Expected Replacement \"%s\"\n"), pszDriverTime, uBlockingStatusInput, pszReplacementDriver));
hRetval = InternalCompatibleDriverCheck(pszDriverModel,
pszDriverPath,
pszEnvironment,
&FileTimeDriver,
pszPrintUpgInf,
uVersion,
bIsServer,
&uBlockingStatus,
&strReplacementDriver);
}
if (SUCCEEDED(hRetval))
{
hRetval = ((uBlockingStatusInput & BSP_BLOCKING_LEVEL_MASK) == (uBlockingStatus & BSP_BLOCKING_LEVEL_MASK)) ? S_OK : S_FALSE;
}
if ((S_OK == hRetval) && (BSP_PRINTER_DRIVER_OK != (uBlockingStatus & BSP_BLOCKING_LEVEL_MASK)))
{
hRetval = !lstrcmp(pszReplacementDriver, strReplacementDriver) ? S_OK : S_FALSE;
//
// we can not test whether BSP_INBOX_DRIVER_AVAILABLE is set
//
//if((S_OK == hRetval) && pszReplacemtDriver && *ppszReplacementDriver)
//{
// hRetval = (BSP_INBOX_DRIVER_AVAILABLE & uBlockingStatus) ? S_OK : S_FALSE;
//}
}
if (SUCCEEDED(hRetval))
{
hRetval = (((S_FALSE == hRetval) && !bSuccess) || (S_OK == hRetval) && bSuccess) ? S_OK : E_FAIL;
}
return hRetval;
}
TCHAR szModel1[] = _T("HP LaserJet 4");
TCHAR szModel2[] = _T("HP LaserJet 4P");
TCHAR szModel3[] = _T("");
TCHAR szModel4[] = _T("HP LaserJet 4M Plus");
TCHAR szModel5[] = _T("HP LaserJet 4Si");
TCHAR szModel6[] = _T("HP LaserJet 4PPP");
TCHAR szModel7[] = _T("Lexmark Optra T612");
TCHAR szModel8[] = _T("HP LaserJet 4V");
TCHAR szModel9[] = _T("Apple LaserJet 400PS");
TCHAR szModel0[] = _T("HP Laserjet 4Si mx");
TCHAR szDriverPath1[] = _T("H:\\WINDOWS\\system32\\spool\\drivers\\w32x86\\3\\ps5ui.dll");
TCHAR szDriverPath2[] = _T("pscript5.dll");
TCHAR szDriverPath3[] = _T("H:\\WINDOWS\\system32\\spool\\drivers\\w32x86\\3\\ps5ui.dll");
TCHAR szDriverPath4[] = _T("psCrIpt5.dll");
TCHAR szDriverPath5[] = _T("ps5ui.dll");
TCHAR szEnvironment1[] = _T("Windows NT x86");
TCHAR szEnvironment2[] = _T("Windows 4.0");
TCHAR szEnvironment3[] = _T("Windows IA64");
TCHAR szEnvironment4[] = _T("Windows XP");
TCHAR szDriverTime1[] = _T("11/27/1999");
TCHAR szDriverTime2[] = _T("11/27/2999");
TCHAR szDriverTime3[] = _T("11/27/2001");
TCHAR szDriverTime4[] = _T("10/27/1999");
TCHAR szDriverTime5[] = _T("11/28/1998");
TCHAR szDriverTime6[] = _T("11/28/1999");
TCHAR szDriverTime7[] = _T("10/28/1999");
DWORD dwStatus1 = BSP_PRINTER_DRIVER_OK;
DWORD dwStatus2 = BSP_PRINTER_DRIVER_WARNED;
DWORD dwStatus3 = BSP_PRINTER_DRIVER_BLOCKED;
TCHAR cszUpgradeInf[] = _T("printupg.inf");
TCHAR cszPrintDriverMapping[] = _T("Printer Driver Mapping");
TCHAR cszVersion[] = _T("Version");
TCHAR cszExcludeSection[] = _T("Excluded Driver Files");
TCHAR cszPrintUpgInf[] = _T("\\\\lzhu0\\zdrive\\sdroot\\printscan\\print\\spooler\\test\\printupg\\printupg.inf");
HRESULT
TestPrintUpgAll(
VOID
)
{
HRESULT hRetval = S_OK;
const struct PrintUpgTest aPrintUpgTests [] =
{
//
// model driverPath environment drivertime ver isServer status replacement isSuccess
//
{szModel1, szDriverPath1, szEnvironment1, szDriverTime4, 2, TRUE, dwStatus2, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus3, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime2, 2, TRUE, dwStatus1, szModel1, TRUE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel6, TRUE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus2, szModel6, TRUE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel6, TRUE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus2, szModel1, FALSE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel1, FALSE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus2, szModel1, FALSE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime2, 2, TRUE, dwStatus3, szModel1, FALSE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel1, FALSE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus2, szModel6, FALSE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus1, szModel6, FALSE},
{szModel2, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus2, szModel1, FALSE},
//
// case 16 is next
//
{szModel7, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel3, TRUE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus2, szModel3, TRUE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel3, TRUE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime2, 2, TRUE, dwStatus1, szModel3, TRUE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus2, szModel3, TRUE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus3, szModel3, TRUE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel3, TRUE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus1, szModel3, TRUE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus3, szModel7, FALSE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus2, szModel7, FALSE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus2, szModel7, FALSE},
{szModel7, szDriverPath1, szEnvironment1, szDriverTime2, 2, TRUE, dwStatus3, szModel7, FALSE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus2, szModel7, FALSE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime2, 2, FALSE, dwStatus3, szModel8, FALSE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus1, szModel8, FALSE},
{szModel8, szDriverPath1, szEnvironment1, szDriverTime1, 2, FALSE, dwStatus2, szModel7, FALSE},
//
// case 32 is next
//
{szModel4, szDriverPath2, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel4, FALSE},
{szModel4, szDriverPath5, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus3, szModel4, FALSE},
{szModel4, szDriverPath5, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus2, szModel4, FALSE},
{szModel4, szDriverPath4, szEnvironment1, szDriverTime1, 2, TRUE, dwStatus1, szModel7, TRUE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime1, 3, TRUE, dwStatus3, szModel4, TRUE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime1, 3, FALSE, dwStatus2, szModel4, TRUE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime2, 3, FALSE, dwStatus1, szModel4, TRUE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime2, 3, TRUE, dwStatus1, szModel4, TRUE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime1, 3, FALSE, dwStatus3, szModel4, FALSE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime1, 3, TRUE, dwStatus2, szModel4, FALSE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime2, 3, FALSE, dwStatus2, szModel4, FALSE},
{szModel4, szDriverPath1, szEnvironment1, szDriverTime2, 3, TRUE, dwStatus3, szModel4, FALSE},
{szModel0, szDriverPath1, szEnvironment1, szDriverTime1, 3, TRUE, dwStatus3, szModel3, TRUE},
{szModel0, szDriverPath1, szEnvironment1, szDriverTime1, 3, FALSE, dwStatus2, szModel3, TRUE},
{szModel0, szDriverPath1, szEnvironment1, szDriverTime2, 3, FALSE, dwStatus1, szModel3, TRUE},
{szModel0, szDriverPath1, szEnvironment1, szDriverTime2, 3, TRUE, dwStatus1, szModel3, TRUE},
//
// case 48 is next
//
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 3, TRUE, dwStatus2, szModel8, FALSE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 3, FALSE, dwStatus2, szModel2, TRUE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime2, 3, FALSE, dwStatus1, szModel8, TRUE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime2, 3, TRUE, dwStatus1, szModel8, TRUE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 3, FALSE, dwStatus2, szModel8, FALSE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 3, TRUE, dwStatus3, szModel8, FALSE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime2, 3, FALSE, dwStatus2, szModel8, FALSE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime2, 3, TRUE, dwStatus3, szModel8, FALSE},
{szModel5, szDriverPath1, szEnvironment3, szDriverTime1, 3, TRUE, dwStatus3, szModel3, TRUE},
{szModel5, szDriverPath1, szEnvironment3, szDriverTime1, 3, FALSE, dwStatus2, szModel3, TRUE},
{szModel5, szDriverPath1, szEnvironment3, szDriverTime2, 3, FALSE, dwStatus1, szModel3, TRUE},
{szModel5, szDriverPath1, szEnvironment3, szDriverTime2, 3, TRUE, dwStatus1, szModel3, TRUE},
{szModel5, szDriverPath1, szEnvironment2, szDriverTime1, 3, TRUE, dwStatus1, szModel3, TRUE},
{szModel5, szDriverPath1, szEnvironment3, szDriverTime1, 1, FALSE, dwStatus2, szModel3, FALSE},
{szModel9, szDriverPath1, szEnvironment1, szDriverTime2, 3, FALSE, dwStatus1, szModel3, TRUE},
{szModel9, szDriverPath1, szEnvironment1, szDriverTime2, 3, TRUE, dwStatus2, szModel3, FALSE},
//
// case 64 is next
//
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 2, TRUE, dwStatus3, szModel8, TRUE},
{szModel4, szDriverPath1, szEnvironment3, szDriverTime1, 3, FALSE, dwStatus2, szModel2, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime5, 2, TRUE, dwStatus3, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime6, 2, TRUE, dwStatus2, szModel1, TRUE},
{szModel1, szDriverPath1, szEnvironment1, szDriverTime7, 2, TRUE, dwStatus2, szModel1, TRUE},
{szModel2, szDriverPath1, szEnvironment3, szDriverTime2, 3, TRUE, dwStatus2, szModel3, TRUE},
{szModel2, szDriverPath1, szEnvironment3, szDriverTime2, 3, FALSE, dwStatus3, szModel3, TRUE},
{szModel2, szDriverPath1, szEnvironment4, szDriverTime2, 3, FALSE, dwStatus1, szModel3, TRUE},
{szModel2, szDriverPath1, szEnvironment3, szDriverTime2, 4, FALSE, dwStatus1, szModel3, TRUE},
};
DBG_MSG(DBG_TRACE, (L"tests started\n"));
for (int i = 0; SUCCEEDED(hRetval) && i < COUNTOF(aPrintUpgTests); i++)
{
DBG_MSG(DBG_TRACE, (_T("************************ %d **********************\n"), i));
hRetval = TestPrintUpgOne(aPrintUpgTests[i].pszDriverModel,
aPrintUpgTests[i].pszDriverPath,
aPrintUpgTests[i].pszEnvironment,
aPrintUpgTests[i].pszDriverTime,
cszPrintUpgInf,
aPrintUpgTests[i].uVersion,
aPrintUpgTests[i].bIsServer,
aPrintUpgTests[i].uBlockingStatus,
aPrintUpgTests[i].pszReplacementDriver,
aPrintUpgTests[i].bSuccess);
}
DBG_MSG(DBG_TRACE, (L"tests ended\n"));
return hRetval;
}
#endif // DBG_PRINTUPG