windows-nt/Source/XPSP1/NT/printscan/print/spooler/localspl/version.c
2020-09-26 16:20:57 +08:00

661 lines
19 KiB
C

/*++
Copyright (c) 1994 - 1995 Microsoft Corporation
Module Name:
version.c
Abstract:
This module contains code that determines what the driver major
version is.
Author:
Krishna Ganugapati (KrishnaG) 15-Mar-1994
Revision History:
--*/
#include <precomp.h>
#define X86_ENVIRONMENT L"Windows NT x86"
#define IA64_ENVIRONMENT L"Windows IA64"
#define MIPS_ENVIRONMENT L"Windows NT R4000"
#define ALPHA_ENVIRONMENT L"Windows NT Alpha_AXP"
#define PPC_ENVIRONMENT L"Windows NT PowerPC"
#define WIN95_ENVIRONMENT L"Windows 4.0"
DWORD
GetDriverMajorVersion(
LPWSTR pFileName
)
{
DWORD dwSize = 0;
LPVOID pFileVersion;
UINT uLen = 0;
LPVOID pMem;
DWORD dwFileOS;
DWORD dwFileVersionMS;
DWORD dwFileVersionLS;
DWORD dwProductVersionMS;
DWORD dwProductVersionLS;
if (!(dwSize = GetFileVersionInfoSize(pFileName, 0))) {
DBGMSG(DBG_TRACE, ("Error: GetFileVersionInfoSize failed with %d\n", GetLastError()));
DBGMSG(DBG_TRACE, ("Returning back a version # 0\n"));
return(0);
}
if (!(pMem = AllocSplMem(dwSize))) {
DBGMSG(DBG_TRACE, ("AllocMem failed \n"));
DBGMSG(DBG_TRACE, ("Returning back a version # 0\n"));
return(0);
}
if (!GetFileVersionInfo(pFileName, 0, dwSize, pMem)) {
FreeSplMem(pMem);
DBGMSG(DBG_TRACE, ("GetFileVersionInfo failed\n"));
DBGMSG(DBG_TRACE, ("Returning back a version # 0\n"));
return(0);
}
if (!VerQueryValue(pMem, L"\\",
&pFileVersion, &uLen)) {
FreeSplMem(pMem);
DBGMSG(DBG_TRACE, ("VerQueryValue failed \n"));
DBGMSG(DBG_TRACE, ("Returning back a version # 0\n"));
return(0);
}
//
// We could determine the Version Information
//
DBGMSG(DBG_TRACE, ("dwFileVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS));
DBGMSG(DBG_TRACE, ("dwFileVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS));
DBGMSG(DBG_TRACE, ("dwProductVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS));
DBGMSG(DBG_TRACE, ("dwProductVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS));
dwFileOS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileOS;
dwFileVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS;
dwFileVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS;
dwProductVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS;
dwProductVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS;
FreeSplMem(pMem);
if (dwFileOS != VOS_NT_WINDOWS32) {
DBGMSG(DBG_TRACE,("Returning back a version # 0\n"));
return(0);
}
if (dwProductVersionMS == dwFileVersionMS) {
//
// This means this hold for all dlls Pre-Daytona
// after Daytona, printer driver writers must support
// version control or we'll dump them as Version 0
// drivers
DBGMSG(DBG_TRACE,("Returning back a version # 0\n"));
return(0);
}
//
// Bug-Bug: suppose a third-party vendor uses a different system
// methinks we should use the lower dword to have specific value
// which implies he/she supports spooler version -- check with MattFe
DBGMSG(DBG_TRACE,("Returning back a version # %d\n", dwFileVersionMS));
return(dwFileVersionMS);
}
BOOL
GetPrintDriverVersion(
IN LPCWSTR pszFileName,
OUT LPDWORD pdwFileMajorVersion,
OUT LPDWORD pdwFileMinorVersion
)
/*++
Routine Name:
GetPrintDriverVersion
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
pdwFileMajorVersion - pointer to major version
pdwFileMinorVersion - pointer to minor version
Return Value:
TRUE if success.
--*/
{
DWORD dwSize = 0;
LPVOID pFileVersion = NULL;
UINT uLen = 0;
LPVOID pMem = NULL;
DWORD dwFileVersionLS;
DWORD dwFileVersionMS;
DWORD dwProductVersionMS;
DWORD dwProductVersionLS;
DWORD dwFileOS, dwFileType, dwFileSubType;
BOOL bRetValue = FALSE;
if (pdwFileMajorVersion)
{
*pdwFileMajorVersion = 0;
}
if (pdwFileMinorVersion)
{
*pdwFileMinorVersion = 0;
}
try
{
if (pszFileName && *pszFileName)
{
dwSize = GetFileVersionInfoSize((LPWSTR)pszFileName, 0);
if (dwSize == 0)
{
//
// Return version 0 for files without a version resource
//
bRetValue = TRUE;
}
else if ((pMem = AllocSplMem(dwSize)) &&
GetFileVersionInfo((LPWSTR)pszFileName, 0, dwSize, pMem) &&
VerQueryValue(pMem, L"\\", &pFileVersion, &uLen))
{
dwFileOS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileOS;
dwFileType = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileType;
dwFileSubType = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileSubtype;
dwFileVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS;
dwFileVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS;
dwProductVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS;
dwProductVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS;
//
// Return versions for drivers designed for Windows NT/Windows 2000,
// 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 (dwFileOS == VOS_NT_WINDOWS32)
{
if (dwFileType == VFT_DRV &&
dwFileSubType == VFT2_DRV_VERSIONED_PRINTER)
{
if (pdwFileMinorVersion)
{
*pdwFileMinorVersion = dwFileVersionLS;
}
if (pdwFileMajorVersion)
{
*pdwFileMajorVersion = dwFileVersionMS;
}
}
else
{
if (pdwFileMajorVersion)
{
if (dwProductVersionMS == dwFileVersionMS)
{
//
// Hold for all dlls Pre-Daytona.
// After Daytona, printer driver writers must support
// version control or we'll dump them as Version 0
// drivers.
//
*pdwFileMajorVersion = 0;
}
else
{
*pdwFileMajorVersion = dwFileVersionMS;
}
}
}
}
bRetValue = TRUE;
}
}
}
finally
{
FreeSplMem(pMem);
}
return bRetValue;
}
BOOL
CheckFilePlatform(
IN LPWSTR pszFileName,
IN LPWSTR pszEnvironment
)
{
HANDLE hFile, hMapping;
LPVOID BaseAddress = NULL;
PIMAGE_NT_HEADERS pImgHdr;
BOOL bRet = FALSE;
try {
hFile = CreateFile(pszFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if ( hFile == INVALID_HANDLE_VALUE )
leave;
hMapping = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL);
if ( !hMapping )
leave;
BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
CloseHandle(hMapping);
if ( !BaseAddress )
leave;
pImgHdr = RtlImageNtHeader(BaseAddress);
if ( !pImgHdr ) {
//
// This happens for Win95 drivers. The second part of || is for
// any environments we may add in the future
//
bRet = !_wcsicmp(pszEnvironment, WIN95_ENVIRONMENT) ||
!( _wcsicmp(pszEnvironment, X86_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, IA64_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, ALPHA_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, PPC_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, MIPS_ENVIRONMENT) );
leave;
}
switch (pImgHdr->FileHeader.Machine) {
case IMAGE_FILE_MACHINE_I386:
bRet = !_wcsicmp(pszEnvironment, X86_ENVIRONMENT);
break;
case IMAGE_FILE_MACHINE_ALPHA:
bRet = !_wcsicmp(pszEnvironment, ALPHA_ENVIRONMENT);
break;
case IMAGE_FILE_MACHINE_IA64:
bRet = !_wcsicmp(pszEnvironment, IA64_ENVIRONMENT);
break;
case IMAGE_FILE_MACHINE_POWERPC:
bRet = !_wcsicmp(pszEnvironment, PPC_ENVIRONMENT);
break;
case IMAGE_FILE_MACHINE_R3000:
case IMAGE_FILE_MACHINE_R4000:
case IMAGE_FILE_MACHINE_R10000:
bRet = !_wcsicmp(pszEnvironment, MIPS_ENVIRONMENT);
break;
default:
//
// For any environments we may add in the future.
//
bRet = !(_wcsicmp(pszEnvironment, X86_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, IA64_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, ALPHA_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, PPC_ENVIRONMENT) &&
_wcsicmp(pszEnvironment, MIPS_ENVIRONMENT) );
}
} finally {
if ( hFile != INVALID_HANDLE_VALUE ) {
if ( BaseAddress )
UnmapViewOfFile(BaseAddress);
CloseHandle(hFile);
}
}
return bRet;
}
/*++
Routine Name:
GetBinaryVersion
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. This function does
not are if the file is a printer driver or anything
else as long as it has a resource.
Arguments:
pszFileName - file name
pdwFileMajorVersion - pointer to major version
pdwFileMinorVersion - pointer to minor version
Return Value:
TRUE if success.
--*/
BOOL
GetBinaryVersion(
IN PCWSTR pszFileName,
OUT PDWORD pdwFileMajorVersion,
OUT PDWORD pdwFileMinorVersion
)
{
DWORD dwSize = 0;
LPVOID pFileVersion = NULL;
UINT uLen = 0;
LPVOID pMem = NULL;
DWORD dwFileVersionLS;
DWORD dwFileVersionMS;
BOOL bRetValue = FALSE;
if (pdwFileMajorVersion && pdwFileMinorVersion && pszFileName && *pszFileName)
{
*pdwFileMajorVersion = 0;
*pdwFileMinorVersion = 0;
try
{
dwSize = GetFileVersionInfoSize((LPWSTR)pszFileName, 0);
if (dwSize == 0)
{
//
// Return version 0 for files without a version resource
//
bRetValue = TRUE;
}
else if ((pMem = AllocSplMem(dwSize)) &&
GetFileVersionInfo((LPWSTR)pszFileName, 0, dwSize, pMem) &&
VerQueryValue(pMem, L"\\", &pFileVersion, &uLen))
{
dwFileVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS;
dwFileVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS;
*pdwFileMinorVersion = dwFileVersionLS;
*pdwFileMajorVersion = dwFileVersionMS;
bRetValue = TRUE;
}
}
finally
{
FreeSplMem(pMem);
}
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
}
return bRetValue;
}
typedef struct
{
PCWSTR pszDriver;
DWORD DrvMajor;
DWORD DrvMinor;
PCWSTR pszProc;
DWORD ProcMajor;
DWORD ProcMinor;
} SPECIALDRIVER;
typedef struct
{
PCWSTR pszPrintProcFile;
DWORD PrintProcMajVer;
DWORD PrintProcMinVer;
} NOIMPERSONATEPRINTPROCS;
NOIMPERSONATEPRINTPROCS NoImpPrintProcs[] =
{
{L"lxaspp.dll", 0x00010000, 0x00000001},
{L"lxarpp.dll", 0x00010000, 0x00000001},
{L"lxampp.dll", 0x00010000, 0x00000001},
{L"lxaupp.dll", 0x00010000, 0x00000001},
{L"lxatpp.dll", 0x00010000, 0x00000001},
{L"lxacpp.dll", 0x00010000, 0x00000001},
{L"lxaapp.dll", 0x00010000, 0x00000001},
{L"lxaepp.dll", 0x00010000, 0x00000001},
{L"lxadpp.dll", 0x00010000, 0x00000001},
{L"lxcapp.dll", 0x00010000, 0x00000001},
{L"lexepp.dll", 0x00010000, 0x00000001},
{L"lexfpp.dll", 0x00010000, 0x00000001},
{L"jw61pp.dll", 0x00010000, 0x00000001},
{L"fxj4pp.dll", 0x00010000, 0x00000001},
{L"lxalpp5c.dll", 0x00020000, 0x00020000},
{L"lxalpp5c.dll", 0x00010000, 0x00060000},
{L"lxalpp5c.dll", 0x00020000, 0x00010000},
{L"lxalpp5c.dll", 0x00010000, 0x00050000},
{L"lxakpp5c.dll", 0x00020000, 0x00010000},
{L"lxakpp5c.dll", 0x00010000, 0x00050001},
{L"lxazpp5c.dll", 0x00010000, 0x00040002},
{L"lxazpp5c.dll", 0x00010000, 0x00050001},
{L"lxaxpp5c.dll", 0x00010000, 0x00060008},
{L"lxaipp5c.dll", 0x00020000, 0x00020002},
{L"lxaipp5c.dll", 0x00030000, 0x00020001},
{L"lxajpp5c.dll", 0x00030000, 0x00010000},
{L"lxajpp5c.dll", 0x00010000, 0x00020001},
{L"lxavpp5c.dll", 0x00010000, 0x000A0000},
{L"lxavpp5c.dll", 0x00010000, 0x00060000},
{L"lg24pp5c.dll", 0x00010000, 0x00010008},
{L"lg24pp5c.dll", 0x00010000, 0x00070002},
{L"lgl2pp5c.dll", 0x00010000, 0x00010006},
{L"lgaxpp5c.dll", 0x00010000, 0x00020001},
{L"smaxpp5c.dll", 0x00010000, 0x00030000},
{L"smazpp5c.dll", 0x00010000, 0x00020000},
{L"lxbhpp5c.dll", 0x00010000, 0x00050000},
};
PCWSTR ArraySpecialDriversInbox[] =
{
L"Lexmark 3200 Color Jetprinter",
L"Lexmark 5700 Color Jetprinter",
L"Lexmark Z11 Color Jetprinter",
L"Lexmark Z12 Color Jetprinter",
L"Lexmark Z22-Z32 Color Jetprinter",
L"Lexmark Z31 Color Jetprinter",
L"Lexmark Z42 Color Jetprinter",
L"Lexmark Z51 Color Jetprinter",
L"Lexmark Z52 Color Jetprinter",
L"Compaq IJ300 Inkjet Printer",
L"Compaq IJ600 Inkjet Printer",
L"Compaq IJ700 Inkjet Printer",
L"Compaq IJ750 Inkjet Printer",
L"Compaq IJ900 Inkjet Printer",
L"Compaq IJ1200 Inkjet Printer"
};
/*++
Name:
FillInVersionInfo
Description:
We have the following 2 DWORD fields in INIDRIVER: DriverFileMajorVersion and DriverFileMinorVersion
They are not filled in when a driver is added or when the spooler starts. The reason for the
existence of these 2 fields is that we cannot always rely on the informatin in dwlDriverVersion
(part of driver-info_6). Not all driver packages supply this information.
So when we print for the first time using a certain INIDRIVER, we call this function to look at
the resource of the driver DLL and populate DriverFileMajorVersion and DriverFileMinorVersion.
The numbers come from VS_FIXEDFILEINFO.FileVer
Arguments:
pIniDriver - pinidriver to fill in the major and minor versions
pIniSpooler - pinispooler to which the driver belongs
Return Value:
Win32 error code
--*/
DWORD
FillInVersionInfo(
IN PINIDRIVER pIniDriver,
IN PINISPOOLER pIniSpooler
)
{
DWORD Error = ERROR_INVALID_ENVIRONMENT;
WCHAR szPath[MAX_PATH];
DWORD cbNeeded;
PINIENVIRONMENT pIniEnvironment;
EnterSplSem();
pIniEnvironment = FindEnvironment(LOCAL_ENVIRONMENT, pIniSpooler);
if (pIniEnvironment)
{
Error = StrNCatBuff(szPath,
MAX_PATH,
pIniSpooler->pDir,
L"\\",
szDriverDir,
L"\\",
pIniEnvironment->pDirectory,
L"\\3\\",
pIniDriver->pDriverFile,
NULL);
}
LeaveSplSem();
if (Error == ERROR_SUCCESS)
{
Error = GetBinaryVersion(szPath,
&pIniDriver->DriverFileMajorVersion,
&pIniDriver->DriverFileMinorVersion) ? ERROR_SUCCESS : GetLastError();
}
SPLASSERT(Error == ERROR_SUCCESS);
return Error;
}
/*++
Name:
IsSpecialDriver
Description:
Checks whether a printer driver (and print processor) needs to be special
cased. Some print processors want to be loaded in local system context.
The are listed in the tables above. some are inbox, some are IHV.
Arguments:
pIniDriver - pinidriver for the current job
pIniProc - piniprintproc for the current job
pIniSpooler - pinispooler for current job
Return Value:
TRUE - this print processor needs to be loaded in local system context
FALSE - load print processor in impersonation context
--*/
BOOL
IsSpecialDriver(
IN PINIDRIVER pIniDriver,
IN PINIPRINTPROC pIniProc,
IN PINISPOOLER pIniSpooler
)
{
BOOL bSpecial = FALSE;
DWORD i;
//
// Check if it is an inbox driver that needs to be special cased
//
for (i = 0; i < COUNTOF(ArraySpecialDriversInbox); i++)
{
if (!_wcsicmp(pIniDriver->pName, ArraySpecialDriversInbox[i]))
{
bSpecial = TRUE;
break;
}
}
//
// Check if it is an IHV driver that needs to be special cased
//
if (!bSpecial)
{
if (pIniDriver->DriverFileMajorVersion == 0 && pIniDriver->DriverFileMinorVersion == 0)
{
//
// We fill in on demand the major and minor file version
//
FillInVersionInfo(pIniDriver, pIniSpooler);
}
for (i = 0; i < COUNTOF(NoImpPrintProcs); i++)
{
if (!_wcsicmp(pIniProc->pDLLName, NoImpPrintProcs[i].pszPrintProcFile) &&
pIniProc->FileMajorVersion == NoImpPrintProcs[i].PrintProcMajVer &&
pIniProc->FileMinorVersion == NoImpPrintProcs[i].PrintProcMinVer)
{
bSpecial = TRUE;
break;
}
}
}
return bSpecial;
}