2020-09-30 17:12:29 +02:00

643 lines
15 KiB
C++

/*++
Copyright (c) 1996 Microsoft Corporation
All rights reserved.
Module Name:
drvrver.hxx
Abstract:
Driver version detection header.
Author:
Steve Kiraly (SteveKi) 21-Jan-1996
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "splsetup.h"
#include "drvver.hxx"
#include "splapip.h"
#include "compinfo.hxx"
#if defined(_MIPS_)
const DWORD kDriverCurrent = ARCH_MIPS + VERSION_2;
#elif defined(_ALPHA_)
const DWORD kDriverCurrent = ARCH_ALPHA + VERSION_2;
#elif defined(_PPC_)
const DWORD kDriverCurrent = ARCH_PPC + VERSION_2;
#else
const DWORD kDriverCurrent = ARCH_X86 + VERSION_2;
#endif
BOOL
bGetCurrentDriver(
IN LPCTSTR pszServerName,
OUT LPDWORD pdwCurrentDriver
)
{
BOOL bRetval = FALSE;
//
// Null this is the local machine return the
// current Architcture / Driver version.
//
if( !pszServerName ){
*pdwCurrentDriver = kDriverCurrent;
bRetval = TRUE;
} else {
TCHAR szArch[kStrMax];
DWORD dwVer = 0;
//
// Attempt to get the architecture / version from the remote machine.
// First attempt to get the information from the remote spooler.
//
bRetval = bGetArchUseSpooler( pszServerName, szArch, COUNTOF( szArch ), &dwVer );
//
// If remote spooler did not respond, this may be a downlevel
// print spooler. "Downlevel" meaning older version.
//
if( !bRetval ){
//
// Attempt to get the information using the remote registry calls
//
bRetval = bGetArchUseReg( pszServerName, szArch, COUNTOF( szArch ), &dwVer );
}
//
// Check if any return information was returned.
//
if( bRetval ){
DBGMSG( DBG_TRACE, ( "Server " TSTR " Arch " TSTR " Ver %d\n", pszServerName, szArch, dwVer ) );
//
// Encode the architecture / version into a dword.
//
if( bEncodeArchVersion( szArch, dwVer, pdwCurrentDriver ) ){
DBGMSG( DBG_TRACE, ( "Encoded arch/Version %d\n", *pdwCurrentDriver ) );
bRetval = TRUE;
} else {
DBGMSG( DBG_WARN, ( "Encode remote architecture and version failed.\n" ) );
bRetval = FALSE;
}
} else {
DBGMSG( DBG_WARN, ( "Getting remote architecture and version failed.\n" ) );
bRetval = FALSE;
}
}
return bRetval;
}
BOOL
bGetArchUseSpooler(
IN LPCTSTR pName,
OUT LPTSTR pszArch,
IN DWORD dwSize,
IN OUT LPDWORD pdwVer
)
/*++
Routine Description:
Gets the specified print server the architectue and
driver version using the spooler.
Arguments:
pName - pointer to print server name.
pszArch - pointer to a buffer where to return the machine architecture string
dwSize - Size in characters of the provided architecture string
pdwVersion - pointer where to return the remote machine driver version.
Return Value:
TRUE - remote information returned, FALSE - remote information not available.
--*/
{
#ifndef SPLREG_ARCHITECTURE
#define SPLREG_ARCHITECTURE TEXT("Architecture")
#define SPLREG_MAJOR_VERSION TEXT("MajorVersion")
#define SPLREG_MINOR_VERSION TEXT("MinorVersion")
#endif
//
// Attempt to open print server with full access.
//
BOOL bReturn = FALSE;
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwAccess = SERVER_READ;
HANDLE hServer;
TStatus Status;
Status DBGCHK = TPrinter::sOpenPrinter( pName,
&dwAccess,
&hServer );
//
// Save administrator capability flag.
//
if( Status == ERROR_SUCCESS ){
//
// Get the remote spooler's architecture type and version.
//
TCHAR szArch[kStrMax];
DWORD dwNeeded = 0;
DWORD dwVer = 0;
DWORD dwVerType = REG_DWORD;
DWORD dwArchType = REG_SZ;
if( dwStatus == ERROR_SUCCESS ){
dwStatus = GetPrinterData( hServer,
SPLREG_ARCHITECTURE,
&dwArchType,
(PBYTE)szArch,
sizeof( szArch ),
&dwNeeded );
}
if( dwStatus == ERROR_SUCCESS ){
dwStatus = GetPrinterData( hServer,
SPLREG_MAJOR_VERSION,
&dwVerType,
(PBYTE)&dwVer,
sizeof( dwVer ),
&dwNeeded );
}
if( dwStatus == ERROR_SUCCESS ){
DBGMSG( DBG_TRACE, ( "GetPrinterData: Architecture " TSTR "\n" , szArch ) );
DBGMSG( DBG_TRACE, ( "GetPrinterData: MajorVersion %d\n" , dwVer ) );
//
// Only success if provided buffer is big enough.
//
if( (DWORD)lstrlen( szArch ) < dwSize ){
lstrcpy( pszArch, szArch );
*pdwVer = dwVer;
bReturn = TRUE;
} else {
dwStatus = ERROR_INSUFFICIENT_BUFFER;
}
} else {
DBGMSG( DBG_WARN, ( "GetPrinterData failed with %d\n", dwStatus ) );
}
}
if( hServer ){
ClosePrinter( hServer );
}
return bReturn;
}
BOOL
bGetArchUseReg(
IN LPCTSTR pName,
OUT LPTSTR pszArch,
IN DWORD dwSize,
OUT LPDWORD pdwVer
)
/*++
Routine Description:
Gets the specified print server the architectue and
driver version using the remote registry.
Arguments:
pName - pointer to print server name.
pszArch - pointer to a buffer where to return the machine architecture string
dwSize - Size in characters of the provided architecture string
pdwVersion - pointer where to return the remote machine driver version.
Return Value:
TRUE - remote information returned, FALSE - remote information not available.
--*/
{
BOOL bStatus = TRUE;
DWORD dwDriverEnvId = 0;
DWORD dwArch = 0;
TString strDriverEnv;
//
// Create the computer information.
//
CComputerInfo CompInfo ( pName );
//
// Get the information from the remote machine.
//
if( !CompInfo.GetInfo() ){
DBGMSG( DBG_WARN, ( "CComputerInfo.GetInfo failed with %d\n", GetLastError() ) );
return FALSE;
}
//
// If this is a windows 95 machine set resource string
// id and set the version to zero.
//
if( CompInfo.IsRunningWindows95() ){
dwDriverEnvId = IDS_ENVIRONMENT_WIN95;
*pdwVer = 0;
} else {
//
// Convert processor type to spooler defined environment string.
//
dwArch = CompInfo.GetProcessorArchitecture();
*pdwVer = CompInfo.GetSpoolerVersion();
struct ArchMap {
DWORD dwArch;
DWORD dwVersion;
UINT uId;
};
static ArchMap aArchMap [] = {
{ PROCESSOR_ARCHITECTURE_MIPS, 0, IDS_ENVIRONMENT_MIPS },
{ PROCESSOR_ARCHITECTURE_ALPHA, 0, IDS_ENVIRONMENT_APLHA },
{ PROCESSOR_ARCHITECTURE_INTEL, 0, IDS_ENVIRONMENT_X86 },
{ PROCESSOR_ARCHITECTURE_MIPS, 1, IDS_ENVIRONMENT_MIPS },
{ PROCESSOR_ARCHITECTURE_ALPHA, 1, IDS_ENVIRONMENT_APLHA },
{ PROCESSOR_ARCHITECTURE_PPC, 1, IDS_ENVIRONMENT_PPC },
{ PROCESSOR_ARCHITECTURE_INTEL, 1, IDS_ENVIRONMENT_X86 },
{ PROCESSOR_ARCHITECTURE_MIPS, 2, IDS_ENVIRONMENT_MIPS },
{ PROCESSOR_ARCHITECTURE_ALPHA, 2, IDS_ENVIRONMENT_APLHA },
{ PROCESSOR_ARCHITECTURE_PPC, 2, IDS_ENVIRONMENT_PPC },
{ PROCESSOR_ARCHITECTURE_INTEL, 2, IDS_ENVIRONMENT_X86 }};
bStatus = FALSE;
for( UINT i = 0; i < COUNTOF( aArchMap ); i++ ){
//
// If a version and architecture match.
//
if( aArchMap[i].dwVersion == *pdwVer &&
aArchMap[i].dwArch == dwArch ){
dwDriverEnvId = aArchMap[i].uId;
bStatus = TRUE;
break;
}
}
}
//
// If Environment ID and version found.
//
if( !bStatus ){
DBGMSG( DBG_WARN, ( "Failed to find architecture in map.\n" ) );
return FALSE;
}
//
// Load the environment string from our resource file.
//
if( !strDriverEnv.bLoadString( ghInst, dwDriverEnvId ) ){
DBGMSG( DBG_WARN, ( "Failed to load driver name string resource with %d\n", GetLastError() ) );
return FALSE;
}
//
// Check the provided buffer is large enough.
//
if( (DWORD)lstrlen( strDriverEnv ) >= ( dwSize - 1 ) ){
DBGMSG( DBG_WARN, ( "Insuffcient buffer provided to bGetArchUseReg.\n" ) );
return FALSE;
}
//
// Copy back environment string to provided buffer.
//
lstrcpy( pszArch, strDriverEnv );
DBGMSG( DBG_TRACE, ( "CComputerInfo.GetInfo: Architecture " TSTR "\n" , pszArch ) );
DBGMSG( DBG_TRACE, ( "CComputerInfo.GetInfo: MajorVersion %d\n" , *pdwVer ) );
return TRUE;
}
BOOL
bEncodeArchVersion(
IN LPCTSTR pszArch,
IN DWORD dwVer,
OUT LPDWORD pdwVal
)
/*++
Routine Description:
Encode the Architecture and version into a DWORD.
Arguments:
pszArch - pointer to machine spooler defined environment string
dwVer - machines driver version
pdwVal - pointer where to store the encoded value
Return Value:
TRUE - remote information returned, FALSE - remote information not available.
--*/
{
struct ArchMap {
UINT uArchId;
DWORD dwVersion;
DWORD dwPUIVer;
DWORD dwPUIArch;
};
static ArchMap aArchMap [] = {
{ IDS_ENVIRONMENT_APLHA, 0, VERSION_0, ARCH_ALPHA },
{ IDS_ENVIRONMENT_X86, 0, VERSION_0, ARCH_X86 },
{ IDS_ENVIRONMENT_MIPS, 0, VERSION_0, ARCH_MIPS },
{ IDS_ENVIRONMENT_WIN95, 0, VERSION_0, ARCH_WIN95 },
{ IDS_ENVIRONMENT_APLHA, 1, VERSION_1, ARCH_ALPHA },
{ IDS_ENVIRONMENT_X86, 1, VERSION_1, ARCH_X86 },
{ IDS_ENVIRONMENT_MIPS, 1, VERSION_1, ARCH_MIPS },
{ IDS_ENVIRONMENT_PPC, 1, VERSION_1, ARCH_PPC },
{ IDS_ENVIRONMENT_APLHA, 2, VERSION_2, ARCH_ALPHA },
{ IDS_ENVIRONMENT_X86, 2, VERSION_2, ARCH_X86 },
{ IDS_ENVIRONMENT_MIPS, 2, VERSION_2, ARCH_MIPS },
{ IDS_ENVIRONMENT_PPC, 2, VERSION_2, ARCH_PPC }};
BOOL bRetval = FALSE;
TString strDriverEnv;
for( UINT i = 0; i < COUNTOF( aArchMap ); i++ ){
//
// Attempt to load the driver environment string from our resource file.
//
if( !strDriverEnv.bLoadString( ghInst, aArchMap[i].uArchId ) ){
DBGMSG( DBG_WARN, ( "Error loading environment string from resource.\n" ) );
break;
}
//
// If the environment and version match, then encode the environment
// and version into a single dword.
//
if( !lstrcmpi( pszArch, (LPCTSTR)strDriverEnv ) &&
aArchMap[i].dwVersion == dwVer ){
*pdwVal = aArchMap[i].dwPUIVer + aArchMap[i].dwPUIArch;
bRetval = TRUE;
break;
}
}
return bRetval;
}
BOOL
bGetDriverEnv(
IN DWORD dwDriverVersion,
OUT LPTSTR pszDriverEnv,
IN DWORD dwSize
)
/*++
Routine Description:
Convert the Encoded the Architecture and version to a
spooler defined environment string.
Arguments:
pszArch - pointer to machine spooler defined environment string
dwVer - machines driver version
pdwVal - pointer where to store the encoded value
Return Value:
TRUE - environment string found, FALSE - error occured.
--*/
{
struct ArchMap {
DWORD dwDrvVer;
UINT uArchId;
};
static ArchMap aArchMap [] = {
{ DRIVER_X86_2, IDS_ENVIRONMENT_X86 },
{ DRIVER_MIPS_2, IDS_ENVIRONMENT_MIPS },
{ DRIVER_ALPHA_2, IDS_ENVIRONMENT_APLHA },
{ DRIVER_PPC_2, IDS_ENVIRONMENT_PPC },
{ DRIVER_X86_1, IDS_ENVIRONMENT_X86 },
{ DRIVER_MIPS_1, IDS_ENVIRONMENT_MIPS },
{ DRIVER_ALPHA_1, IDS_ENVIRONMENT_APLHA },
{ DRIVER_PPC_1, IDS_ENVIRONMENT_PPC },
{ DRIVER_X86_0, IDS_ENVIRONMENT_X86 },
{ DRIVER_MIPS_0, IDS_ENVIRONMENT_MIPS },
{ DRIVER_ALPHA_0, IDS_ENVIRONMENT_APLHA },
{ DRIVER_WIN95, IDS_ENVIRONMENT_WIN95 }};
UINT uId = 0;
BOOL bRetval = FALSE;
TString strDriverEnv;
for( UINT i = 0; i < COUNTOF( aArchMap ); i++ ){
if( aArchMap[i].dwDrvVer == dwDriverVersion ){
uId = aArchMap[i].uArchId;
bRetval = TRUE;
break;
}
}
#if DBG
if( !bRetval ){
DBGMSG( DBG_WARN, ( "Driver / Version not found, bGetDriverEnv.\n" ) );
}
#endif
if( bRetval ){
//
// Attempt to load the driver environment string from our resource file.
//
if( !strDriverEnv.bLoadString( ghInst, uId ) ){
DBGMSG( DBG_WARN, ( "Error loading environment string from resource.\n" ) );
bRetval = FALSE;
}
}
if( bRetval ){
//
// Check if the provided buffer is large enough.
//
if( (DWORD)lstrlen( strDriverEnv ) >= (dwSize - 1) ){
DBGMSG( DBG_WARN, ( "Insuffcient buffer provided to bGetDriverEnv.\n" ) );
bRetval = FALSE;
}
}
if( bRetval ){
//
// Copy the environment string back.
//
lstrcpy( pszDriverEnv, strDriverEnv );
}
return bRetval;
}
PLATFORM
GetDriverPlatform(
IN DWORD dwDriver
)
/*++
Routine Description:
Return the driver platform value (used by splsetup apis).
Arguments:
dwDriver - DWORD indicating driver platform/version.
Return Value:
PLATFORM.
--*/
{
return (PLATFORM)( dwDriver % ARCH_MAX );
}
DWORD
GetDriverVersion(
IN DWORD dwDriver
)
/*++
Routine Description:
Return the driver version value (used by DRIVER_INFO_x).
Arguments:
dwDriver - DWORD indicating driver platform/version.
Return Value:
DWORD version.
--*/
{
return dwDriver / ARCH_MAX;
}
BOOL
bIsNativeDriver(
IN LPCTSTR pszServerName,
IN DWORD dwDriver
)
/*++
Routine Description:
Determines whether the platform/version is compatible with the
current OS.
Arguments:
dwDriver - DWORD indicating driver platform/version.
Return Value:
TRUE - compatible, FALSE - not compatible.
--*/
{
//
// Get the current driver / version.
//
DWORD dwDrv;
if( bGetCurrentDriver( pszServerName, &dwDrv ) ){
return dwDrv == dwDriver;
}
return FALSE;
}
BOOL
bIs3xDriver(
IN DWORD dwDriver
)
/*++
Routine Description:
Returns TRUE iff driver works with 3.5x.
Arguments:
dwDriver - DWORD indicating driver platform/version.
Return Value:
--*/
{
return dwDriver < VERSION_2;
}