/*++ Copyright (C) Microsoft Corporation, 1996 - 1997 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 "psetup.hxx" #include "drvver.hxx" #include "splapip.h" #include "compinfo.hxx" BOOL bGetCurrentDriver( IN LPCTSTR pszServerName, OUT LPDWORD pdwCurrentDriver ) { TCHAR szArch[kStrMax]; BOOL bRetval = FALSE; DWORD dwVer = 0; // // Attempt to get the architecture / version from the machine. // First attempt to get the information from the spooler. // bRetval = bGetArchUseSpooler( pszServerName, szArch, COUNTOF( szArch ), &dwVer ); // // If 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 // We only connect to the remote registry if a server name was passed. // if( pszServerName ) { bRetval = bGetArchUseReg( pszServerName, szArch, COUNTOF( szArch ), &dwVer ); } } // // Check for any retuned information. // if( bRetval ) { DBGMSG( DBG_TRACE, ( "Server " TSTR " Arch " TSTR " Ver %d\n", DBGSTR(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 architecture and version failed.\n" ) ); bRetval = FALSE; } } else { DBGMSG( DBG_WARN, ( "Fetching 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. --*/ { // // Attempt to open print server with full access. // BOOL bReturn = FALSE; DWORD dwStatus = ERROR_SUCCESS; DWORD dwAccess = SERVER_READ; HANDLE hServer = NULL; TStatus Status; // // Open the server for read access. // 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]; memset( szArch, 0, sizeof( szArch ) ); 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; SetLastError( ERROR_INSUFFICIENT_BUFFER ); bReturn = FALSE; } } 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; }; // // disable MIPS & PPC drivers, since they are not supported from setup // static ArchMap aArchMap [] = { { PROCESSOR_ARCHITECTURE_INTEL, 0, IDS_ENVIRONMENT_WIN95 }, //{ PROCESSOR_ARCHITECTURE_MIPS, 0, IDS_ENVIRONMENT_MIPS }, { PROCESSOR_ARCHITECTURE_ALPHA, 0, IDS_ENVIRONMENT_ALPHA }, { PROCESSOR_ARCHITECTURE_INTEL, 0, IDS_ENVIRONMENT_X86 }, //{ PROCESSOR_ARCHITECTURE_MIPS, 1, IDS_ENVIRONMENT_MIPS }, { PROCESSOR_ARCHITECTURE_ALPHA, 1, IDS_ENVIRONMENT_ALPHA }, //{ 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_ALPHA }, //{ PROCESSOR_ARCHITECTURE_PPC, 2, IDS_ENVIRONMENT_PPC }, { PROCESSOR_ARCHITECTURE_INTEL, 2, IDS_ENVIRONMENT_X86 }, { PROCESSOR_ARCHITECTURE_ALPHA, 3, IDS_ENVIRONMENT_ALPHA }, { PROCESSOR_ARCHITECTURE_INTEL, 3, 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; }; // // disable MIPS & PPC drivers, since they are not supported from setup // static ArchMap aArchMap [] = { { IDS_ENVIRONMENT_ALPHA, 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_ALPHA, 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_ALPHA, 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 }, { IDS_ENVIRONMENT_ALPHA, 3, VERSION_3, ARCH_ALPHA }, { IDS_ENVIRONMENT_X86, 3, VERSION_3, ARCH_X86 }, { IDS_ENVIRONMENT_IA64, 3, VERSION_3, ARCH_IA64 }}; 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 TString &strDriverEnv ) /*++ Routine Description: Convert the Encoded the Architecture and version to a spooler defined environment string. Arguments: dwDriverVersion - encoded driver version strDriverEnv - string where to return the environment string. Return Value: TRUE - environment string found, FALSE - error occured. --*/ { struct ArchMap { DWORD dwDrvVer; UINT uArchId; }; // // disable MIPS & PPC drivers, since they are not supported from setup // static ArchMap aArchMap [] = { { DRIVER_IA64_3, IDS_ENVIRONMENT_IA64 }, { DRIVER_X86_3, IDS_ENVIRONMENT_X86 }, { DRIVER_ALPHA_3, IDS_ENVIRONMENT_ALPHA }, { DRIVER_X86_2, IDS_ENVIRONMENT_X86 }, //{ DRIVER_MIPS_2, IDS_ENVIRONMENT_MIPS }, { DRIVER_ALPHA_2, IDS_ENVIRONMENT_ALPHA }, //{ DRIVER_PPC_2, IDS_ENVIRONMENT_PPC }, { DRIVER_X86_1, IDS_ENVIRONMENT_X86 }, //{ DRIVER_MIPS_1, IDS_ENVIRONMENT_MIPS }, { DRIVER_ALPHA_1, IDS_ENVIRONMENT_ALPHA }, //{ DRIVER_PPC_1, IDS_ENVIRONMENT_PPC }, { DRIVER_X86_0, IDS_ENVIRONMENT_X86 }, //{ DRIVER_MIPS_0, IDS_ENVIRONMENT_MIPS }, { DRIVER_ALPHA_0, IDS_ENVIRONMENT_ALPHA }, { DRIVER_WIN95, IDS_ENVIRONMENT_WIN95 }}; UINT uId = 0; BOOL bRetval = FALSE; for( UINT i = 0; i < COUNTOF( aArchMap ); i++ ){ if( aArchMap[i].dwDrvVer == dwDriverVersion ){ uId = aArchMap[i].uArchId; bRetval = TRUE; break; } } 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; } } else { DBGMSG( DBG_WARN, ( "Driver / Version not found, bGetDriverEnv.\n" ) ); } 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; } BOOL bGetArchName( IN DWORD dwDriver, OUT TString &strDrvArchName ) /*++ Routine Description: Retrieves the platform/version name from a driver platform/version. Arguments: dwDriver - DWORD indicating driver platform/version. strDrvArchName - String where to retun platform/version string. Return Value: TRUE strDrvArchName contains architecture name. FALSE error occurred reading string. --*/ { TStatusB bStatus; // // Load the architecute / driver name. // bStatus DBGCHK = strDrvArchName.bLoadString( ghInst, IDS_DRIVER_BASE + dwDriver ); return bStatus; } BOOL bIsCompatibleDriverVersion( IN DWORD dwDriver, IN DWORD dwVersion ) /*++ Routine Description: Checks if the specified drivers version is a compatible version. NOTE: This function MUST be re-rewritten if the drvier model changes. Arguments: dwDriver - DWORD indicating driver platform/version. dwVersion - DWORD version number to check. Return Value: TRUE version is compatible. FALSE verion is not compatible. --*/ { DWORD dwDriverVersion = GetDriverVersion( dwDriver ); // // If the version are equal then they are compatible. // if( dwVersion == dwDriverVersion ) return TRUE; // // If current driver version is a version 3 (Win2K or above) // then version 2 (NT4 Kernel mode) are compatible drivers. // if( dwDriverVersion == 3 && dwVersion == 2 ) return TRUE; return FALSE; } BOOL SpoolerGetVersionEx( IN LPCTSTR pszServerName, IN OUT OSVERSIONINFO *pOsVersionInfo ) /*++ Routine Description: Gets the osversion using spooler apis, thus it's remotable. Arguments: pszServerName - pointer to a string which contains the server name a NULL indicates the local machine. pOsVersionInf - pointer to osversion structure to fill in. Return Value: TRUE version structure was filled successfully. FALSE error occurred. --*/ { SPLASSERT ( pOsVersionInfo ); TStatusB bStatus; bStatus DBGNOCHK = FALSE; if( !pszServerName ) { // // Get the osversion info structure size // bStatus DBGCHK = GetVersionEx( pOsVersionInfo ); } else { // // Attempt to open print server with just read. // DWORD dwStatus = ERROR_SUCCESS; DWORD dwAccess = SERVER_READ; HANDLE hServer = NULL; DWORD dwNeeded = 0; DWORD dwType = REG_BINARY; // // Open the server for read access. // dwStatus = TPrinter::sOpenPrinter( pszServerName, &dwAccess, &hServer ); // // Get the os version from the remote spooler. // if( dwStatus == ERROR_SUCCESS ) { dwStatus = GetPrinterData( hServer, SPLREG_OS_VERSION, &dwType, (PBYTE)pOsVersionInfo, sizeof( OSVERSIONINFO ), &dwNeeded ); if( dwStatus == ERROR_SUCCESS ) { bStatus DBGCHK = TRUE; } } } return bStatus; }