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

1019 lines
28 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
drvupgrd.c
Abstract:
When the system is upgraded from one release to another printer drivers
(e.g. RASDD ) wants to upgrade is PrinterDriverData to match the new mini driver.
Setup from NT 4.0 on do this by calling EnumPrinterDriver and then AddPrinterDriver
for each printer driver that we have installed.
We call DrvUpgrade each time a printer driver is upgraded.
For Example, pre NT 3.51 RASDD used to store its regstiry PrinterDriverData
based on internal indexes into the mini drivers, which was not valid beween
different updates of the mini driver, so before 3.51 it was by luck if there
were problems in retriving the settings. With 3.51 RASDD will convert these
indexes back to meaningful key names ( like Memory ) so hopefully in future
we don't have an upgrade problem.
Note also that other than upgrade time ( which happens once ) DrvUpgrade needs to
be called on Point and Print whenever a Driver file gets updated. See Driver.C
for details. Or anyone updates a printer driver by calling AddPrinterDriver.
Author:
Matthew A Felton ( MattFe ) March 11 1995
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
#include "clusspl.h"
#include <winddiui.h>
BOOL
UpdateUpgradeInfoStruct(
LPBYTE pDriverUpgradeInfo,
DWORD dwLevel,
LPWSTR pPrinterNameWithToken,
LPWSTR pOldDriverDir,
LPBYTE pDriverInfo
)
/*++
Function Description: This function fills in the Upgrade_Info struct with the
other parameters
Parameters: pDriverUpgradeInfo -- pointer Upgrade_Info_* struct
dwLevel -- Upgrade_Info level
pPrinterNameWithToken -- printer name
pOldDriverDir -- Directory containing the old driver files
pDriverInfo -- pointer to driver_info_4 struct
Return Values: TRUE for sucesss;
FALSE otherwise
--*/
{
BOOL bReturn = TRUE;
PDRIVER_UPGRADE_INFO_1 pDrvUpgInfo1;
PDRIVER_UPGRADE_INFO_2 pDrvUpgInfo2;
PDRIVER_INFO_4 pDriver4;
switch (dwLevel) {
case 1:
pDrvUpgInfo1 = (PDRIVER_UPGRADE_INFO_1) pDriverUpgradeInfo;
pDrvUpgInfo1->pPrinterName = pPrinterNameWithToken;
pDrvUpgInfo1->pOldDriverDirectory = pOldDriverDir;
break;
case 2:
if (pDriver4 = (PDRIVER_INFO_4) pDriverInfo) {
pDrvUpgInfo2 = (PDRIVER_UPGRADE_INFO_2) pDriverUpgradeInfo;
pDrvUpgInfo2->pPrinterName = pPrinterNameWithToken;
pDrvUpgInfo2->pOldDriverDirectory = pOldDriverDir;
pDrvUpgInfo2->cVersion = pDriver4->cVersion;
pDrvUpgInfo2->pName = pDriver4->pName;
pDrvUpgInfo2->pEnvironment = pDriver4->pEnvironment;
pDrvUpgInfo2->pDriverPath = pDriver4->pDriverPath;
pDrvUpgInfo2->pDataFile = pDriver4->pDataFile;
pDrvUpgInfo2->pConfigFile = pDriver4->pConfigFile;
pDrvUpgInfo2->pHelpFile = pDriver4->pHelpFile;
pDrvUpgInfo2->pDependentFiles = pDriver4->pDependentFiles;
pDrvUpgInfo2->pMonitorName = pDriver4->pMonitorName;
pDrvUpgInfo2->pDefaultDataType = pDriver4->pDefaultDataType;
pDrvUpgInfo2->pszzPreviousNames = pDriver4->pszzPreviousNames;
} else {
bReturn = FALSE;
}
break;
default:
bReturn = FALSE;
break;
}
return bReturn;
}
BOOL
bIsNewFile(
LPWSTR pDriverFile,
PINTERNAL_DRV_FILE pInternalDriverFiles,
DWORD dwFileCount
)
/*++
Function Description: This function checks to see if a driver file was updated
Parameters: pDriverFile -- driver file
pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
dwFileCount -- number of files in file set
Return Values: TRUE for sucesss;
FALSE otherwise
--*/
{
DWORD dwIndex;
LPCWSTR psz;
BOOL bRet = FALSE;
//
// Must have some files.
//
SPLASSERT( dwFileCount );
//
// Search for pDriverFile in ppFileNames array
//
for ( dwIndex = 0; dwIndex < dwFileCount ; ++dwIndex ) {
if( pInternalDriverFiles[dwIndex].pFileName ) {
//
// Find the filename portion of a path
//
psz = FindFileName(pInternalDriverFiles[dwIndex].pFileName );
if( psz ){
if( !lstrcmpi(pDriverFile, psz) ){
//
// Check if the file was updated
//
bRet = pInternalDriverFiles[dwIndex].bUpdated;
break;
}
}
}
}
return bRet;
}
BOOL
DriversShareFiles(
PINIDRIVER pIniDriver1,
PINIDRIVER pIniDriver2,
PINTERNAL_DRV_FILE pInternalDriverFiles,
DWORD dwFileCount
)
/*++
Function Description: Determines if the drivers have common files and
if the common files were updated
Parameters: pIniDriver1 -- driver #1
pIniDriver2 -- driver #2
pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
dwFileCount -- number of files in file set
pUpdateStatusBitMap -- map of bits that tells what files in the file set were actually updated
Return Values: TRUE if files are shared;
FALSE otherwise
--*/
{
LPWSTR pStr1, pStr2;
if (!pIniDriver1 || !pIniDriver2) {
return FALSE;
}
if (pIniDriver1->cVersion != pIniDriver2->cVersion) {
return FALSE;
}
//
// Compare the file names and if they were updated
//
if (pIniDriver1->pDriverFile && pIniDriver2->pDriverFile &&
!lstrcmpi(pIniDriver1->pDriverFile, pIniDriver2->pDriverFile) &&
bIsNewFile(pIniDriver1->pDriverFile, pInternalDriverFiles, dwFileCount)) {
return TRUE;
}
if (pIniDriver1->pConfigFile && pIniDriver2->pConfigFile &&
!lstrcmpi(pIniDriver1->pConfigFile, pIniDriver2->pConfigFile) &&
bIsNewFile(pIniDriver1->pConfigFile, pInternalDriverFiles, dwFileCount)) {
return TRUE;
}
if (pIniDriver1->pHelpFile && pIniDriver2->pHelpFile &&
!lstrcmpi(pIniDriver1->pHelpFile, pIniDriver2->pHelpFile) &&
bIsNewFile(pIniDriver1->pHelpFile, pInternalDriverFiles, dwFileCount)) {
return TRUE;
}
if (pIniDriver1->pDataFile && pIniDriver2->pDataFile &&
!lstrcmpi(pIniDriver1->pDataFile, pIniDriver2->pDataFile) &&
bIsNewFile(pIniDriver1->pDataFile, pInternalDriverFiles, dwFileCount)) {
return TRUE;
}
// Compare each pair of files from the Dependent file list
for (pStr1 = pIniDriver1->pDependentFiles;
pStr1 && *pStr1;
pStr1 += wcslen(pStr1) + 1) {
for (pStr2 = pIniDriver2->pDependentFiles;
pStr2 && *pStr2;
pStr2 += wcslen(pStr2) + 1) {
if (!lstrcmpi(pStr1, pStr2) &&
bIsNewFile(pStr1, pInternalDriverFiles, dwFileCount)) {
return TRUE;
}
}
}
return FALSE;
}
BOOL
ForEachPrinterCallDriverDrvUpgrade(
PINISPOOLER pIniSpooler,
PINIDRIVER pIniDriver,
LPCWSTR pOldDriverDir,
PINTERNAL_DRV_FILE pInternalDriverFiles,
DWORD dwFileCount,
LPBYTE pDriverInfo
)
/*++
Routine Description:
This routine is called at Spooler Initialization time if an upgrade is detected.
It will loop through all printers and then call the Printer Drivers DrvUpgrade
entry point giving it a chance to upgrade any configuration data ( PrinterDriverData )
passing them a pointer to the old Drivers Directory.
This routine also converts devmode to current version by calling the driver.
If driver does not support devmode conversion we will NULL the devmode so
that we do not have devmodes of different version in the system.
SECURITY NOTE - This routine Stops impersonation, because the printer drivers UI dll
needs to call SetPrinterData even if the user doesn't have permission to do it.
That is because the driver upgrading the settings.
Arguments:
pIniSpooler - Pointer to Spooler
pIniVersion - Pointer to the version of driver added
pOldDriverDir - Point to Directory where old driver files are stored.
pInternalDriverFiles - array of INTERNAL_DRV_FILE structures
dwFileCount - number of files in array
pUpdateStatusBitMap - map of bits that tells what files in the file set were actually updated
pDriverInfo - Driver Info buffer
Return Value:
TRUE - Success
FALSE - something major failed, like allocating memory.
--*/
{
PINIPRINTER pIniPrinter = NULL;
LPWSTR pPrinterNameWithToken = NULL;
DWORD dwNeeded;
DWORD dwServerMajorVersion;
DWORD dwServerMinorVersion;
BOOL bInSem = TRUE;
LPWSTR pConfigFile = NULL;
HMODULE hModuleDriverUI = NULL;
HANDLE hPrinter = NULL;
BOOL (*pfnDrvUpgrade)() = NULL;
BOOL bReturnValue = FALSE;
DRIVER_UPGRADE_INFO_1 DriverUpgradeInfo1;
DRIVER_UPGRADE_INFO_2 DriverUpgradeInfo2;
WCHAR ErrorBuffer[ 11 ];
HANDLE hToken = INVALID_HANDLE_VALUE;
LPDEVMODE pNewDevMode = NULL;
try {
SplInSem();
SPLASSERT( ( pIniSpooler != NULL ) &&
( pIniSpooler->signature == ISP_SIGNATURE ));
if (!pOldDriverDir && !pDriverInfo) {
leave;
}
//
// Stop Impersonating User
// So drivers can call SetPrinterData even if the user is not admin.
//
hToken = RevertToPrinterSelf();
//
// Loop Through All Printers. Skip the printers that use drivers that doesn't share files with
// the updated driver. Skip the printers that share files,but the files weren't updated.
//
for ( pIniPrinter = pIniSpooler->pIniPrinter ;
pIniPrinter ;
pIniPrinter = pIniPrinter->pNext ) {
SPLASSERT( pIniPrinter->signature == IP_SIGNATURE );
SPLASSERT( pIniPrinter->pName != NULL );
SplInSem();
// Verify if DrvUpgradePrinter needs to be called on this printer
if (!DriversShareFiles( pIniPrinter->pIniDriver,
pIniDriver,
pInternalDriverFiles,
dwFileCount)) {
continue;
}
//
// Cleanup from previous iteration
//
FreeSplStr( pPrinterNameWithToken );
FreeSplStr(pConfigFile);
FreeSplMem(pNewDevMode);
pPrinterNameWithToken = NULL;
pConfigFile = NULL;
pNewDevMode = NULL;
//
// If we download a driver of newer version we need to update
// pIniPrinter->pIniDriver
//
pIniPrinter->pIniDriver = FindLocalDriver(pIniPrinter->pIniSpooler, pIniPrinter->pIniDriver->pName);
if ( pIniPrinter->pIniDriver->pIniLangMonitor == NULL )
pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
// Prepare PrinterName to be passed to DrvUpgrade
// The name passed is "PrinterName, UpgradeToken"
// So that OpenPrinter can do an open without opening
// the port in the downlevel connection case.
// ( see openprn.c for details )
pPrinterNameWithToken = pszGetPrinterName( pIniPrinter,
TRUE,
pszLocalOnlyToken );
if ( pPrinterNameWithToken == NULL ) {
DBGMSG( DBG_WARNING, ("FEPCDDU Failed to allocated ScratchBuffer %d\n", GetLastError() ));
leave;
}
DBGMSG( DBG_TRACE, ("FEPCDDU PrinterNameWithToken %ws\n", pPrinterNameWithToken ));
pConfigFile = GetConfigFilePath(pIniPrinter);
if ( !pConfigFile ) {
DBGMSG( DBG_WARNING, ("FEPCDDU failed SplGetPrinterDriverEx %d\n", GetLastError() ));
leave;
}
INCPRINTERREF(pIniPrinter);
LeaveSplSem();
SplOutSem();
bInSem = FALSE;
//
// Load the UI DLL
//
hModuleDriverUI = LoadDriver(pConfigFile);
if ( hModuleDriverUI == NULL ) {
DBGMSG( DBG_WARNING, ("FEPCDDU failed LoadLibrary %ws error %d\n", pConfigFile, GetLastError() ));
wsprintf( ErrorBuffer, L"%d", GetLastError() );
SplLogEvent( pLocalIniSpooler,
LOG_ERROR,
MSG_DRIVER_FAILED_UPGRADE,
FALSE,
pPrinterNameWithToken,
pConfigFile,
ErrorBuffer,
NULL );
SplOutSem();
EnterSplSem();
bInSem = TRUE;
DECPRINTERREF( pIniPrinter );
continue;
}
DBGMSG( DBG_TRACE, ("FEPCDDU successfully loaded %ws\n", pConfigFile ));
//
// Call DrvUpgrade
//
pfnDrvUpgrade = (BOOL (*)())GetProcAddress( hModuleDriverUI, "DrvUpgradePrinter" );
if ( pfnDrvUpgrade != NULL ) {
try {
SPLASSERT( pPrinterNameWithToken != NULL );
SplOutSem();
//
// Call Driver UI DrvUpgrade
//
if (UpdateUpgradeInfoStruct((LPBYTE) &DriverUpgradeInfo2, 2,
pPrinterNameWithToken, (LPWSTR) pOldDriverDir,
pDriverInfo)) {
bReturnValue = (*pfnDrvUpgrade)(2 , &DriverUpgradeInfo2);
}
if ( bReturnValue == FALSE ) {
UpdateUpgradeInfoStruct((LPBYTE) &DriverUpgradeInfo1, 1,
pPrinterNameWithToken, (LPWSTR) pOldDriverDir,
NULL);
bReturnValue = (*pfnDrvUpgrade)(1 , &DriverUpgradeInfo1);
}
if ( bReturnValue == FALSE ) {
DBGMSG( DBG_WARNING, ("FEPCDDU Driver returned FALSE, doesn't support level %d error %d\n", 1, GetLastError() ));
wsprintf( ErrorBuffer, L"%d", GetLastError() );
SplLogEvent( pLocalIniSpooler,
LOG_ERROR,
MSG_DRIVER_FAILED_UPGRADE,
FALSE,
pPrinterNameWithToken,
pConfigFile,
ErrorBuffer,
NULL );
}
} except(1) {
SetLastError( GetExceptionCode() );
DBGMSG( DBG_ERROR, ("FEPCDDU ExceptionCode %x Driver %ws Error %d\n", GetLastError(), pConfigFile, GetLastError() ));
//
// Despite the exception in this driver we'll continue to do all printers
//
}
} else {
// Note this is non fatal, since a driver might not have a DrvUpgrade Entry Point.
DBGMSG( DBG_TRACE, ("FEPCDDU failed GetProcAddress DrvUpgrade error %d\n", GetLastError() ));
}
SplOutSem();
EnterSplSem();
bInSem = TRUE;
//
// Call ConvertDevMode -- On upgrading we will either convert devmode,
// or set to driver default, or NULL it. This way we can make sure
// we do not have any different version devmodes
//
pNewDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
pIniPrinter->pDevMode,
pConfigFile,
pPrinterNameWithToken,
CURRENT_VERSION);
SplInSem();
FreeSplMem(pIniPrinter->pDevMode);
pIniPrinter->pDevMode = (LPDEVMODE) pNewDevMode;
if ( pNewDevMode ) {
pIniPrinter->cbDevMode = ((LPDEVMODE)pNewDevMode)->dmSize
+ ((LPDEVMODE)pNewDevMode)->dmDriverExtra;
SPLASSERT(pIniPrinter->cbDevMode);
} else {
wsprintf( ErrorBuffer, L"%d", GetLastError() );
SplLogEvent(pLocalIniSpooler,
LOG_ERROR,
MSG_DRIVER_FAILED_UPGRADE,
TRUE,
pIniPrinter->pName,
pIniPrinter->pIniDriver->pName,
ErrorBuffer,
NULL);
pIniPrinter->cbDevMode = 0;
}
pNewDevMode = NULL;
SplInSem();
if ( !UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID)) {
DBGMSG(DBG_WARNING, ("FEPCDDU: UpdatePrinterIni failed with %d\n", GetLastError()));
}
//
// Clean Up - Free UI DLL
//
LeaveSplSem();
SplOutSem();
UnloadDriver( hModuleDriverUI );
EnterSplSem();
SplInSem();
hModuleDriverUI = NULL;
//
// End of Loop, Move to Next Printer
//
SPLASSERT( pIniPrinter->signature == IP_SIGNATURE );
DECPRINTERREF( pIniPrinter );
}
//
// Done
//
bReturnValue = TRUE;
DBGMSG( DBG_TRACE, ("FEPCDDU - Success\n" ));
} finally {
//
// Clean Up
//
FreeSplStr(pConfigFile);
FreeSplMem(pNewDevMode);
FreeSplStr(pPrinterNameWithToken);
if ( hModuleDriverUI != NULL )
UnloadDriver( hModuleDriverUI );
if ( !bInSem )
EnterSplSem();
if ( hToken != INVALID_HANDLE_VALUE )
ImpersonatePrinterClient(hToken);
}
SplInSem();
return bReturnValue;
}
BOOL
GetFileNamesFromDriverVersionInfo (
IN LPDRIVER_INFO_VERSION pDriverInfo,
OUT LPWSTR *ppszDriverPath,
OUT LPWSTR *ppszConfigFile,
OUT LPWSTR *ppszDataFile,
OUT LPWSTR *ppszHelpFile
)
/*++
Routine Name:
GetFileNamesFromDriverVersionInfo
Routine Description:
Get the name of Driver, Config, Data, Help file from an
array of DRIVER_FILE_INFO structures.
Arguments:
pDriverInfo - Pointer to LPDRIVER_INFO_VERSION buffer.
ppszDriverPath - out pointer to driver file string
ppszConfigFile - out pointer to config file string
ppszDataFile - out pointer to data file string
ppszHelpFile - out pointer to help file string
Return Value:
TRUE if file pointers successfully returned.
--*/
{
BOOL bRetValue = FALSE;
DWORD dwIndex;
if (pDriverInfo && pDriverInfo->pFileInfo)
{
bRetValue = TRUE;
for (dwIndex = 0; dwIndex < pDriverInfo->dwFileCount; dwIndex++)
{
switch (pDriverInfo->pFileInfo[dwIndex].FileType)
{
case DRIVER_FILE:
if (ppszDriverPath)
{
*ppszDriverPath = MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset);
}
break;
case CONFIG_FILE:
if (ppszConfigFile)
{
*ppszConfigFile = MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset);
}
break;
case DATA_FILE:
if (ppszDataFile)
{
*ppszDataFile = MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset);
}
break;
case HELP_FILE:
if (ppszHelpFile)
{
*ppszHelpFile = MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset);
}
break;
case DEPENDENT_FILE:
break;
default:
bRetValue = FALSE;
break;
}
}
}
return bRetValue;
}
BOOL
BuildDependentFilesFromDriverInfo (
IN LPDRIVER_INFO_VERSION pDriverInfo,
OUT LPWSTR *ppDependentFiles
)
/*++
Routine Name:
BuildDependentFilesFromDriverInfo
Routine Description:
Build a multisz string of driver dependent files from
a DRIVER_INFO_VERSION structure.
Arguments:
pDriverInfo - pointer to DRIVER_INFO_VERSION structure
ppDependentFiles - pointer to allocated multi-sz string
Return Value:
TRUE if SUCCESS
--*/
{
BOOL bRetValue = TRUE;
DWORD dwIndex;
DWORD dwLength = 0;
LPWSTR pszDllFile = NULL;
if (ppDependentFiles && pDriverInfo && pDriverInfo->pFileInfo)
{
*ppDependentFiles = NULL;
for (dwIndex = 0;
bRetValue && dwIndex < pDriverInfo->dwFileCount;
dwIndex++)
{
switch (pDriverInfo->pFileInfo[dwIndex].FileType)
{
case DRIVER_FILE:
case CONFIG_FILE:
case DATA_FILE:
case HELP_FILE:
break;
case DEPENDENT_FILE:
{
dwLength += wcslen(MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset)) + 1;
break;
}
default:
{
bRetValue = FALSE;
break;
}
}
}
if (bRetValue && dwLength > 0)
{
dwLength++;
dwLength *= sizeof(WCHAR);
pszDllFile = (LPWSTR)AllocSplMem(dwLength);
if (pszDllFile)
{
*ppDependentFiles = pszDllFile;
for (dwIndex = 0;
bRetValue && dwIndex < pDriverInfo->dwFileCount;
dwIndex++)
{
switch (pDriverInfo->pFileInfo[dwIndex].FileType)
{
case DRIVER_FILE:
case CONFIG_FILE:
case DATA_FILE:
case HELP_FILE:
break;
case DEPENDENT_FILE:
{
wcscpy(pszDllFile,
MakePTR(pDriverInfo,
pDriverInfo->pFileInfo[dwIndex].FileNameOffset));
pszDllFile += wcslen(pszDllFile) + 1;
break;
}
default:
{
bRetValue = FALSE;
break;
}
}
}
}
else
{
bRetValue = FALSE;
}
}
}
if (bRetValue == FALSE && ppDependentFiles)
{
FreeSplMem(*ppDependentFiles);
*ppDependentFiles = NULL;
}
return bRetValue;
}
BOOL
DriverAddedOrUpgraded (
IN PINTERNAL_DRV_FILE pInternalDriverFiles,
IN DWORD dwFileCount
)
/*++
Routine Name:
DriverAddedOrUpgraded
Routine Description:
Checks the Internal driver file array to see if at least
one driver file was updated. This is a performance optimization
for calling DrvUpgradePrinter for ecah printer using the upgraded
driver or a driver sharing files in common with upgraded driver
(see ForEachPrinterCallDriverDrvUpgrade).
Arguments:
pInternalDriverFiles - array of INTERNAL_DRV_FILE structures
dwFileCount - number of files in array
Return Value:
TRUE if driver files where added or upgraded.
--*/
{
BOOL bDriverAddedOrUpgraded = FALSE;
DWORD dwIndex;
for (dwIndex = 0; dwIndex < dwFileCount; dwIndex++)
{
if (pInternalDriverFiles[dwIndex].bUpdated)
{
bDriverAddedOrUpgraded = TRUE;
break;
}
}
return bDriverAddedOrUpgraded;
}
VOID
CleanupInternalDriverInfo(
PINTERNAL_DRV_FILE pInternalDriverFiles,
DWORD FileCount
)
/*++
Routine Name:
CleanupInternalDriverInfo
Routine Description:
Frees array of INTERNAL_DRV_FILE.
FileCount gives the element count in the array.
Arguments:
pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
FileCount -- number of files in file set
Return Value:
Nothing.
--*/
{
DWORD dwIndex;
if (pInternalDriverFiles)
{
for (dwIndex = 0; dwIndex < FileCount; dwIndex++)
{
FreeSplStr(pInternalDriverFiles[dwIndex].pFileName);
if (pInternalDriverFiles[dwIndex].hFileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(pInternalDriverFiles[dwIndex].hFileHandle);
}
}
FreeSplMem(pInternalDriverFiles);
}
}
BOOL
GetDriverFileVersionsFromNames(
IN PINTERNAL_DRV_FILE pInternalDriverFiles,
IN DWORD dwCount
)
/*++
Routine Name:
GetDriverFileVersionsFromNames
Routine Description:
Fills the array of INTERNAL_DRV_FILE with driver minor version,
by calling GetPrintDriverVersion for each file.
The array already has the file names filled in.
Arguments:
pInternalDriverFiles -- array of INTERNAL_DRV_FILE structures
FileCount -- number of files in file set
Return Value:
TRUE if SUCCESS
--*/
{
DWORD Count, Size;
BOOL bReturnValue = TRUE;
if (!pInternalDriverFiles || !dwCount)
{
bReturnValue = FALSE;
SetLastError(ERROR_INVALID_DATA);
}
else
{
for (Count = 0 ; Count < dwCount ; ++Count)
{
if (IsEXEFile(pInternalDriverFiles[Count].pFileName))
{
if (!GetPrintDriverVersion(pInternalDriverFiles[Count].pFileName,
NULL,
&pInternalDriverFiles[Count].dwVersion))
{
bReturnValue = FALSE;
break;
}
}
}
}
return bReturnValue;
}
BOOL
GetDriverFileVersions(
IN LPDRIVER_INFO_VERSION pDriverVersion,
IN PINTERNAL_DRV_FILE pInternalDriverFiles,
IN DWORD dwCount
)
/*++
Routine Name:
GetDriverFileVersions
Routine Description:
Fills the array of INTERNAL_DRV_FILE with driver minor version
stored in DRIVER_INFO_VERSION structure.
Arguments:
pDriverVersion - pointer to DRIVER_INFO_VERSION
pInternalDriverFiles - pointer to array of INTERNAL_DRV_FILE
dwCount - number of elemnts in array
Return Value:
TRUE if succeeded.
--*/
{
DWORD Count, Size;
BOOL bReturnValue = TRUE;
DWORD dwMajorVersion;
if (!pDriverVersion ||
!pDriverVersion->pFileInfo ||
pDriverVersion->dwFileCount != dwCount)
{
bReturnValue = FALSE;
SetLastError(ERROR_INVALID_DATA);
}
else
{
for (Count = 0; Count < pDriverVersion->dwFileCount; Count++)
{
pInternalDriverFiles[Count].dwVersion = pDriverVersion->pFileInfo[Count].FileVersion;
}
}
return bReturnValue;
}