Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1207 lines
33 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
All rights reserved.
Module Name:
Utildi.c
Abstract:
Driver Setup DeviceInstaller Utility functions
Author:
Muhunthan Sivapragasam (MuhuntS) 06-Sep-1995
Revision History:
--*/
#include "precomp.h"
static const GUID GUID_DEVCLASS_PRINTER =
{ 0x4d36e979L, 0xe325, 0x11ce,
{ 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
BOOL
SetSelectDevParams(
IN HDEVINFO hDevInfo,
IN PSP_DEVINFO_DATA pDevInfoData,
IN BOOL bWin95,
IN LPCTSTR pszModel OPTIONAL
)
/*++
Routine Description:
Sets the select device parameters by calling setup apis
Arguments:
hDevInfo : Handle to the printer class device information list
bWin95 : TRUE if selecting Win95 driver, else WinNT driver
pszModel : Printer model we are looking for -- only for Win95 case
Return Value:
TRUE on success
FALSE else
--*/
{
SP_SELECTDEVICE_PARAMS SelectDevParams = {0};
LPTSTR pszWin95Instn;
SelectDevParams.ClassInstallHeader.cbSize
= sizeof(SelectDevParams.ClassInstallHeader);
SelectDevParams.ClassInstallHeader.InstallFunction
= DIF_SELECTDEVICE;
//
// Get current SelectDevice parameters, and then set the fields
// we want to be different from default
//
if ( !SetupDiGetClassInstallParams(
hDevInfo,
pDevInfoData,
&SelectDevParams.ClassInstallHeader,
sizeof(SelectDevParams),
NULL) ) {
if ( GetLastError() != ERROR_NO_CLASSINSTALL_PARAMS )
return FALSE;
ZeroMemory(&SelectDevParams, sizeof(SelectDevParams)); // NEEDED 10/11 ?
SelectDevParams.ClassInstallHeader.cbSize
= sizeof(SelectDevParams.ClassInstallHeader);
SelectDevParams.ClassInstallHeader.InstallFunction
= DIF_SELECTDEVICE;
}
//
// Set the strings to use on the select driver page ..
//
if(!LoadString(ghInst,
IDS_PRINTERWIZARD,
SelectDevParams.Title,
SIZECHARS(SelectDevParams.Title)))
{
return FALSE;
}
//
// For Win95 drivers instructions are different than NT drivers
//
if ( bWin95 ) {
pszWin95Instn = GetStringFromRcFile(IDS_WIN95DEV_INSTRUCT);
if ( !pszWin95Instn )
return FALSE;
if ( lstrlen(pszWin95Instn) + lstrlen(pszModel) + 1
> sizeof(SelectDevParams.Instructions) ) {
LocalFreeMem(pszWin95Instn);
return FALSE;
}
StringCchPrintf(SelectDevParams.Instructions, COUNTOF(SelectDevParams.Instructions), pszWin95Instn, pszModel);
LocalFreeMem(pszWin95Instn);
pszWin95Instn = NULL;
} else {
if(!LoadString(ghInst,
IDS_WINNTDEV_INSTRUCT,
SelectDevParams.Instructions,
SIZECHARS(SelectDevParams.Instructions)))
{
return FALSE;
}
}
if(!LoadString(ghInst,
IDS_SELECTDEV_LABEL,
SelectDevParams.ListLabel,
SIZECHARS(SelectDevParams.ListLabel)))
{
return FALSE;
}
return SetupDiSetClassInstallParams(
hDevInfo,
pDevInfoData,
&SelectDevParams.ClassInstallHeader,
sizeof(SelectDevParams));
}
BOOL
PSetupSetSelectDevTitleAndInstructions(
HDEVINFO hDevInfo,
LPCTSTR pszTitle,
LPCTSTR pszSubTitle,
LPCTSTR pszInstn
)
/*++
Routine Description:
Sets title, subtitle and instructions for the Add Printer/Add Printer Driver dialogs.
Arguments:
hDevInfo : Handle to the printer class device information list
pszTitle : Title
pszSubTitle : Subtitle
pszInstn : Instructions
Return Value:
TRUE on success, FALSE on error
--*/
{
SP_SELECTDEVICE_PARAMS SelectDevParams;
if ( pszTitle && lstrlen(pszTitle) + 1 > MAX_TITLE_LEN ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( pszSubTitle && lstrlen(pszSubTitle) + 1 > MAX_SUBTITLE_LEN ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( pszInstn && lstrlen(pszInstn) + 1 > MAX_INSTRUCTION_LEN ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SelectDevParams.ClassInstallHeader.cbSize
= sizeof(SelectDevParams.ClassInstallHeader);
SelectDevParams.ClassInstallHeader.InstallFunction
= DIF_SELECTDEVICE;
if ( !SetupDiGetClassInstallParams(hDevInfo,
NULL,
&SelectDevParams.ClassInstallHeader,
sizeof(SelectDevParams),
NULL) )
return FALSE;
if ( pszTitle )
StringCchCopy(SelectDevParams.Title, COUNTOF(SelectDevParams.Title), pszTitle);
if ( pszSubTitle )
StringCchCopy(SelectDevParams.SubTitle, COUNTOF(SelectDevParams.SubTitle), pszSubTitle);
if ( pszInstn )
StringCchCopy(SelectDevParams.Instructions, COUNTOF(SelectDevParams.Instructions), pszInstn);
return SetupDiSetClassInstallParams(
hDevInfo,
NULL,
&SelectDevParams.ClassInstallHeader,
sizeof(SelectDevParams));
}
BOOL
PSetupSelectDeviceButtons(
HDEVINFO hDevInfo,
DWORD dwFlagsSet,
DWORD dwFlagsClear
)
/*++
Routine Description:
Determines if the "Have Disk" and "Windows Update" buttons are to be displayed
on the Select Device page.
Arguments:
hDevInfo : Handle to the printer class device information list
dwFlagsSet : Flags to set
dwFlagsClear : Flags to clean
Return Value:
TRUE on success, FALSE otherwise
--*/
{
PSP_DEVINFO_DATA pDevInfoData = NULL;
SP_DEVINSTALL_PARAMS DevInstallParams;
// Check that no flags are both set & cleared
if (dwFlagsSet & dwFlagsClear)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Get current SelectDevice parameters, and then set the fields
// we wanted changed from default
//
DevInstallParams.cbSize = sizeof(DevInstallParams);
if ( !SetupDiGetDeviceInstallParams(hDevInfo,
pDevInfoData,
&DevInstallParams) ) {
return FALSE;
}
//
// Set Flag based on Argument for Web Button
if ( dwFlagsSet & SELECT_DEVICE_FROMWEB )
DevInstallParams.FlagsEx |= DI_FLAGSEX_SHOWWINDOWSUPDATE;
if ( dwFlagsClear & SELECT_DEVICE_FROMWEB )
DevInstallParams.FlagsEx &= ~DI_FLAGSEX_SHOWWINDOWSUPDATE;
if ( dwFlagsSet & SELECT_DEVICE_HAVEDISK )
DevInstallParams.Flags |= DI_SHOWOEM;
if ( dwFlagsClear & SELECT_DEVICE_HAVEDISK )
DevInstallParams.Flags &= ~DI_SHOWOEM;
return SetupDiSetDeviceInstallParams(hDevInfo,
pDevInfoData,
&DevInstallParams);
}
BOOL
SetDevInstallParams(
IN HDEVINFO hDevInfo,
IN PSP_DEVINFO_DATA pDevInfoData,
IN LPCTSTR pszDriverPath OPTIONAL
)
/*++
Routine Description:
Sets the device installation parameters by calling setup apis
Arguments:
hDevInfo : Handle to the printer class device information list
pszDriverPath : Path where INF file should be searched
Return Value:
TRUE on success
FALSE else
--*/
{
SP_DEVINSTALL_PARAMS DevInstallParams;
//
// Get current SelectDevice parameters, and then set the fields
// we wanted changed from default
//
DevInstallParams.cbSize = sizeof(DevInstallParams);
if ( !SetupDiGetDeviceInstallParams(hDevInfo,
pDevInfoData,
&DevInstallParams) ) {
return FALSE;
}
//
// Drivers are class drivers,
// ntprint.inf is sorted do not waste time sorting,
// show Have Disk button,
// use our strings on the select driver page
//
DevInstallParams.Flags |= DI_SHOWCLASS | DI_INF_IS_SORTED
| DI_SHOWOEM
| DI_USECI_SELECTSTRINGS;
if ( pszDriverPath && *pszDriverPath )
StringCchCopy(DevInstallParams.DriverPath, COUNTOF(DevInstallParams.DriverPath), pszDriverPath);
return SetupDiSetDeviceInstallParams(hDevInfo,
pDevInfoData,
&DevInstallParams);
}
BOOL
PSetupBuildDriversFromPath(
IN HDEVINFO hDevInfo,
IN LPCTSTR pszDriverPath,
IN BOOL bEnumSingleInf
)
/*++
Routine Description:
Builds the list of printer drivers from infs from a specified path.
Path could specify a directory or a single inf.
Arguments:
hDevInfo : Handle to the printer class device information list
pszDriverPath : Path where INF file should be searched
bEnumSingleInf : If TRUE pszDriverPath is a filename instead of path
Return Value:
TRUE on success
FALSE else
--*/
{
SP_DEVINSTALL_PARAMS DevInstallParams;
//
// Get current SelectDevice parameters, and then set the fields
// we wanted changed from default
//
DevInstallParams.cbSize = sizeof(DevInstallParams);
if ( !SetupDiGetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams) ) {
return FALSE;
}
DevInstallParams.Flags |= DI_INF_IS_SORTED;
if ( bEnumSingleInf )
DevInstallParams.Flags |= DI_ENUMSINGLEINF;
StringCchCopy(DevInstallParams.DriverPath, COUNTOF(DevInstallParams.DriverPath), pszDriverPath);
SetupDiDestroyDriverInfoList(hDevInfo,
NULL,
SPDIT_CLASSDRIVER);
return SetupDiSetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams) &&
SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
}
BOOL
DestroyOnlyPrinterDeviceInfoList(
IN HDEVINFO hDevInfo
)
/*++
Routine Description:
This routine should be called at the end to destroy the printer device
info list
Arguments:
hDevInfo : Handle to the printer class device information list
Return Value:
TRUE on success, FALSE on error
--*/
{
return hDevInfo == INVALID_HANDLE_VALUE
? TRUE : SetupDiDestroyDeviceInfoList(hDevInfo);
}
BOOL
PSetupDestroyPrinterDeviceInfoList(
IN HDEVINFO hDevInfo
)
/*++
Routine Description:
This routine should be called at the end to destroy the printer device
info list
Arguments:
hDevInfo : Handle to the printer class device information list
Return Value:
TRUE on success, FALSE on error
--*/
{
// Cleanup and CDM Context created by windows update.
DestroyCodedownload( gpCodeDownLoadInfo );
gpCodeDownLoadInfo = NULL;
return DestroyOnlyPrinterDeviceInfoList(hDevInfo);
}
HDEVINFO
CreatePrinterDeviceInfoList(
IN HWND hwnd
)
{
return SetupDiCreateDeviceInfoList((LPGUID)&GUID_DEVCLASS_PRINTER, hwnd);
}
HDEVINFO
PSetupCreatePrinterDeviceInfoList(
IN HWND hwnd
)
/*++
Routine Description:
This routine should be called at the beginning to do the initialization
It returns a handle which will be used on any subsequent calls to the
driver setup routines.
Arguments:
None
Return Value:
On success a handle to an empty printer device information set.
If the function fails INVALID_HANDLE_VALUE is returned
--*/
{
HDEVINFO hDevInfo;
hDevInfo = SetupDiCreateDeviceInfoList((LPGUID)&GUID_DEVCLASS_PRINTER, hwnd);
if ( hDevInfo != INVALID_HANDLE_VALUE ) {
if ( !SetSelectDevParams(hDevInfo, NULL, FALSE, NULL) ||
!SetDevInstallParams(hDevInfo, NULL, NULL) ) {
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
hDevInfo = INVALID_HANDLE_VALUE;
}
}
return hDevInfo;
}
HPROPSHEETPAGE
PSetupCreateDrvSetupPage(
IN HDEVINFO hDevInfo,
IN HWND hwnd
)
/*++
Routine Description:
Returns the print driver selection property page
Arguments:
hDevInfo : Handle to the printer class device information list
hwnd : Window handle that owns the UI
Return Value:
Handle to the property page, NULL on failure -- use GetLastError()
--*/
{
SP_INSTALLWIZARD_DATA InstallWizardData;
ZeroMemory(&InstallWizardData, sizeof(InstallWizardData));
InstallWizardData.ClassInstallHeader.cbSize
= sizeof(InstallWizardData.ClassInstallHeader);
InstallWizardData.ClassInstallHeader.InstallFunction
= DIF_INSTALLWIZARD;
InstallWizardData.DynamicPageFlags = DYNAWIZ_FLAG_PAGESADDED;
InstallWizardData.hwndWizardDlg = hwnd;
return SetupDiGetWizardPage(hDevInfo,
NULL,
&InstallWizardData,
SPWPT_SELECTDEVICE,
0);
}
PPSETUP_LOCAL_DATA
BuildInternalData(
IN HDEVINFO hDevInfo,
IN PSP_DEVINFO_DATA pSpDevInfoData
)
/*++
Routine Description:
Fills out the selected driver info in the SELECTED_DRV_INFO structure
Arguments:
hDevInfo : Handle to the printer class device information list
pSpDevInfoData : Gives the selected device info element.
Return Value:
On success a non-NULL pointer to PSETUP_LOCAL_DATA struct
NULL on error
--*/
{
PSP_DRVINFO_DETAIL_DATA pDrvInfoDetailData;
PSP_DRVINSTALL_PARAMS pDrvInstallParams;
PPSETUP_LOCAL_DATA pLocalData;
PSELECTED_DRV_INFO pDrvInfo;
SP_DRVINFO_DATA DrvInfoData;
DWORD dwNeeded;
BOOL bRet = FALSE;
pLocalData = (PPSETUP_LOCAL_DATA) LocalAllocMem(sizeof(*pLocalData));
//
// If we don't do this the call to DestroyLocalData in the cleanup code
// might cause an AV.
//
if(pLocalData)
{
ZeroMemory(pLocalData, sizeof(*pLocalData));
}
pDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA)
LocalAllocMem(sizeof(*pDrvInfoDetailData));
pDrvInstallParams = (PSP_DRVINSTALL_PARAMS) LocalAllocMem(sizeof(*pDrvInstallParams));
if ( !pLocalData || !pDrvInstallParams || !pDrvInfoDetailData )
goto Cleanup;
pDrvInfo = &pLocalData->DrvInfo;
pLocalData->DrvInfo.pDevInfoData = pSpDevInfoData;
pLocalData->signature = PSETUP_SIGNATURE;
DrvInfoData.cbSize = sizeof(DrvInfoData);
if ( !SetupDiGetSelectedDriver(hDevInfo, pSpDevInfoData, &DrvInfoData) )
goto Cleanup;
// Need to Check the flag in the DrvInstallParms
pDrvInstallParams->cbSize = sizeof(*pDrvInstallParams);
if ( !SetupDiGetDriverInstallParams(hDevInfo,
pSpDevInfoData,
&DrvInfoData,
pDrvInstallParams) ) {
goto Cleanup;
}
//
// Did the user press the "Web" button
//
if ( pDrvInstallParams->Flags & DNF_INET_DRIVER )
pDrvInfo->Flags |= SDFLAG_CDM_DRIVER;
LocalFreeMem(pDrvInstallParams);
pDrvInstallParams = NULL;
dwNeeded = sizeof(*pDrvInfoDetailData);
pDrvInfoDetailData->cbSize = dwNeeded;
if ( !SetupDiGetDriverInfoDetail(hDevInfo,
pSpDevInfoData,
&DrvInfoData,
pDrvInfoDetailData,
dwNeeded,
&dwNeeded) ) {
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
goto Cleanup;
}
LocalFreeMem(pDrvInfoDetailData);
pDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA) LocalAllocMem(dwNeeded);
if ( !pDrvInfoDetailData )
goto Cleanup;
pDrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
if ( !SetupDiGetDriverInfoDetail(hDevInfo,
pSpDevInfoData,
&DrvInfoData,
pDrvInfoDetailData,
dwNeeded,
NULL) ) {
goto Cleanup;
}
}
pDrvInfo->pszInfName = AllocStr(pDrvInfoDetailData->InfFileName);
pDrvInfo->pszDriverSection = AllocStr(pDrvInfoDetailData->SectionName);
pDrvInfo->pszModelName = AllocStr(DrvInfoData.Description);
pDrvInfo->pszManufacturer = AllocStr(DrvInfoData.MfgName);
pDrvInfo->pszProvider = AllocStr(DrvInfoData.ProviderName);
pDrvInfo->ftDriverDate = DrvInfoData.DriverDate;
pDrvInfo->dwlDriverVersion = DrvInfoData.DriverVersion;
if ( pDrvInfoDetailData->HardwareID && *pDrvInfoDetailData->HardwareID ) {
pDrvInfo->pszHardwareID = AllocStr(pDrvInfoDetailData->HardwareID);
if(!pDrvInfo->pszHardwareID)
goto Cleanup;
}
bRet = pDrvInfo->pszInfName &&
pDrvInfo->pszDriverSection &&
pDrvInfo->pszModelName &&
pDrvInfo->pszProvider &&
pDrvInfo->pszManufacturer;
Cleanup:
LocalFreeMem(pDrvInfoDetailData);
LocalFreeMem(pDrvInstallParams);
if ( bRet ) {
return pLocalData;
} else {
//
// On failure we will leave the old private local data around
//
DestroyLocalData(pLocalData);
return NULL;
}
}
PPSETUP_LOCAL_DATA
PSetupGetSelectedDriverInfo(
IN HDEVINFO hDevInfo
)
/**++
Routine Description:
Fills out the selected driver info in the SELECTED_DRV_INFO structure
(inside the PPSETUP_LOCAL_DATA structure)
Arguments:
hDevInfo - Handle to the printer class device information list
Return Value:
Pointer to PSETUP_LOCAL_DATA containing information about the selected
driver.
--*/
{
return BuildInternalData(hDevInfo, NULL);
}
BOOL
PSetupSelectDriver(
IN HDEVINFO hDevInfo
)
/*++
Routine Description:
Builds the class driver list and selects a driver for the class printer driver list.
Selected driver is remembered and PSetupGetSelectedDriver
call will give the selected driver.
Arguments:
hDevInfo - Handle to the printer class device information list
Return Value:
TRUE on success, FALSE on error
--*/
{
return BuildClassDriverList(hDevInfo) &&
SetupDiSelectDevice(hDevInfo, NULL);
}
VOID
GetDriverPath(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA pLocalData,
OUT TCHAR szDriverPath[MAX_PATH]
)
/*++
Routine Description:
Gets the path where driver files should be searched first to copy from
Arguments:
pszDriverPath : Pointer to a buffer of MAX_PATH size. Gives path where
system was installed from
Return Value:
Nothing
--*/
{
BOOL bOemDriver = FALSE;
LPTSTR *List, psz;
DWORD dwCount;
LPTSTR pszTempPath = NULL;
//
// For OEM drivers look at the place where the inf came from, else
// look at the place we installed NT from
//
if ( pLocalData &&
!(IsSystemNTPrintInf(pLocalData->DrvInfo.pszInfName) || (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ))) {
StringCchCopy(szDriverPath, MAX_PATH, pLocalData->DrvInfo.pszInfName);
if ( psz = FileNamePart(szDriverPath) ) {
*psz = TEXT('\0');
return;
}
}
pszTempPath = GetSystemInstallPath();
if ( pszTempPath != NULL )
{
StringCchCopy(szDriverPath, MAX_PATH, pszTempPath);
LocalFreeMem(pszTempPath);
}
else
// Default put A:\ since we have to give something to setup
StringCchCopy(szDriverPath, MAX_PATH, TEXT("A:\\"));
}
BOOL
BuildClassDriverList(
IN HDEVINFO hDevInfo
)
/*++
Routine Description:
Build the class driver list.
Note: If driver list is already built this comes back immediately
Arguments:
hDevInfo : Handle to the printer class device information list
Return Value:
TRUE on success, FALSE on error
--*/
{
DWORD dwLastError;
SP_DRVINFO_DATA DrvInfoData;
//
// Build the class driver list and also make sure there is atleast one driver
//
if ( !SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER) )
return FALSE;
DrvInfoData.cbSize = sizeof(DrvInfoData);
if ( !SetupDiEnumDriverInfo(hDevInfo,
NULL,
SPDIT_CLASSDRIVER,
0,
&DrvInfoData) &&
GetLastError() == ERROR_NO_MORE_ITEMS ) {
SetLastError(SPAPI_E_DI_BAD_PATH);
return FALSE;
}
return TRUE;
}
BOOL
IsNTPrintInf(
IN LPCTSTR pszInfName
)
/*
Function: IsNTPrintInf
Purpose: Verifies is the inf file being copied is a system inf - ntprint.inf.
Parameters:
pszInfName - the fully qualified inf name that is being installed.
Notes: This is needed to make the decision of whether to zero or even copy the inf
with SetupCopyOEMInf.
Should we be doing a deeper comparison than this to decide?
*/
{
BOOL bRet = FALSE;
PTCHAR pFileName = FileNamePart( pszInfName );
if( pFileName )
{
bRet = ( 0 == lstrcmpi( pFileName, cszNtprintInf ) );
}
return bRet;
}
BOOL
IsSystemNTPrintInf(
IN PCTSTR pszInfName
)
/*
Function: IsSystemNTPrintInf
Purpose: Verifies if the inf file the one system printer inf : %windir\inf\ntprint.inf.
Parameters:
pszInfName - the fully qualified inf name that is being verified.
Notes: Needed to decide whether to downrank our inbox drivers
*/
{
BOOL bRet = FALSE;
TCHAR szSysInf[MAX_PATH] = {0};
UINT Len;
PCTSTR pRelInfPath = _T("inf\\ntprint.inf");
Len = GetSystemWindowsDirectory(szSysInf, MAX_PATH);
if (
(Len != 0) &&
(Len + _tcslen(pRelInfPath) + 2 < MAX_PATH)
)
{
if (szSysInf[Len-1] != _T('\\'))
{
szSysInf[Len++] = _T('\\');
szSysInf[Len] = _T('\0');
}
StringCchCat(szSysInf, COUNTOF(szSysInf), pRelInfPath);
if (!_tcsicmp(szSysInf, pszInfName))
{
bRet = TRUE;
}
}
return bRet;
}
BOOL
PSetupPreSelectDriver(
IN HDEVINFO hDevInfo,
IN LPCTSTR pszManufacturer,
IN LPCTSTR pszModel
)
/*++
Routine Description:
Preselect a manufacturer and model for the driver dialog
If same model is found select it, else if a manufacturer is given and
a match in manufacturer is found select first driver for the manufacturer.
If no manufacturer or model is given select the first driver.
Arguments:
hDevInfo : Handle to the printer class device information list
pszManufacturer : Manufacterer name to preselect
pszModel : Model name to preselect
Return Value:
TRUE on a model or manufacturer match
FALSE else
--*/
{
SP_DRVINFO_DATA DrvInfoData;
DWORD dwIndex, dwManf, dwMod;
if ( !BuildClassDriverList(hDevInfo) ) {
return FALSE;
}
dwIndex = 0;
//
// To do only one check later
//
if ( pszManufacturer && !*pszManufacturer )
pszManufacturer = NULL;
if ( pszModel && !*pszModel )
pszModel = NULL;
//
// If no model/manf given select first driver
//
if ( pszManufacturer || pszModel ) {
dwManf = dwMod = MAX_DWORD;
DrvInfoData.cbSize = sizeof(DrvInfoData);
while ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
dwIndex, &DrvInfoData) ) {
if ( pszManufacturer &&
dwManf == MAX_DWORD &&
!lstrcmpi(pszManufacturer, DrvInfoData.MfgName) ) {
dwManf = dwIndex;
}
if ( pszModel &&
!lstrcmpi(pszModel, DrvInfoData.Description) ) {
dwMod = dwIndex;
break; // the for loop
}
DrvInfoData.cbSize = sizeof(DrvInfoData);
++dwIndex;
}
if ( dwMod != MAX_DWORD ) {
dwIndex = dwMod;
} else if ( dwManf != MAX_DWORD ) {
dwIndex = dwManf;
} else {
SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
return FALSE;
}
}
DrvInfoData.cbSize = sizeof(DrvInfoData);
if ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
dwIndex, &DrvInfoData) &&
SetupDiSetSelectedDriver(hDevInfo, NULL, &DrvInfoData) ) {
return TRUE;
}
return FALSE;
}
PPSETUP_LOCAL_DATA
PSetupDriverInfoFromName(
IN HDEVINFO hDevInfo,
IN LPCTSTR pszModel
)
/*++
Routine Description:
Fills out the selected driver info in the SELECTED_DRV_INFO structure
(inside the PPSETUP_LOCAL_DATA structure) for the model passed into
the function.
Arguments:
hDevInfo - Handle to the printer class device information list
pszModel - Printer Driver name
Return Value:
Pointer to PSETUP_LOCAL_DATA containing information about pszModel
--*/
{
return PSetupPreSelectDriver(hDevInfo, NULL, pszModel) ?
BuildInternalData(hDevInfo, NULL) :
NULL;
}
LPDRIVER_INFO_6
Win95DriverInfo6FromName(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA* ppLocalData,
IN LPCTSTR pszModel,
IN LPCTSTR pszzPreviousNames
)
{
LPDRIVER_INFO_6 pDriverInfo6=NULL;
PPSETUP_LOCAL_DATA pLocalData;
BOOL bFound;
LPCTSTR pszName;
if(!ppLocalData)
{
return FALSE;
}
bFound = PSetupPreSelectDriver(hDevInfo, NULL, pszModel);
for ( pszName = pszzPreviousNames ;
!bFound && pszName && *pszName ;
pszName += lstrlen(pszName) + 1 ) {
bFound = PSetupPreSelectDriver(hDevInfo, NULL, pszName);
}
if ( !bFound )
return NULL;
if ( (pLocalData = BuildInternalData(hDevInfo, NULL)) &&
ParseInf(hDevInfo, pLocalData, PlatformWin95, NULL, 0, FALSE) ) {
pDriverInfo6 = CloneDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
pLocalData->InfInfo.cbDriverInfo6);
*ppLocalData = pLocalData;
}
if (!pDriverInfo6 && pLocalData)
{
DestroyLocalData(pLocalData);
*ppLocalData = NULL;
}
return pDriverInfo6;
}
BOOL
PSetupDestroySelectedDriverInfo(
IN PPSETUP_LOCAL_DATA pLocalData
)
/**++
Routine Description:
Frees memory allocated to fields given by the pointers in the
PPSETUP_LOCAL_DATA structure. Also frees the memory allocated
for the structure itself.
Arguments:
pLocalData - Handle to the printer class device information list
Return Value:
Always returns TRUE
--*/
{
ASSERT(pLocalData && pLocalData->signature == PSETUP_SIGNATURE);
DestroyLocalData(pLocalData);
return TRUE;
}
BOOL
PSetupGetDriverInfForPrinter(
IN HDEVINFO hDevInfo,
IN LPCTSTR pszPrinterName,
IN OUT LPTSTR pszInfName,
IN OUT LPDWORD pcbInfNameSize
)
/*++
Routine Description:
Checks if there is an INF in %WINDIR%\inf that is identical (same driver name,
same driver filename, same data file, same configuration file, same help file
and same monitor name) to the driver of the printer that is passed in
by comparing their DRIVER_INFO_6 structures. If such an INF is found the name
of it is returned.
Arguments:
hDevInfo : Handle to the printer class device information list
pszPrinterName : Name of printer.
pszInfName : Buffer to hold name of inf file - if found
pcbInfNameSize : Size of buffer pointed to by pszInfName in BYTES! Returns required size.
Return Value:
TRUE if INF is found
FALSE else
--*/
{
BOOL bRet = FALSE;
DWORD dwSize, dwIndex;
HANDLE hPrinter = NULL;
LPTSTR pszInf;
PPSETUP_LOCAL_DATA pLocalData = NULL;
LPDRIVER_INFO_6 pDriverInfo6 = NULL;
SP_DRVINFO_DATA DrvInfoData;
if(!pszInfName || !pcbInfNameSize)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( !OpenPrinter((LPTSTR)pszPrinterName, &hPrinter, NULL) )
return FALSE;
if ( !BuildClassDriverList(hDevInfo) )
goto Cleanup;
GetPrinterDriver(hPrinter,
NULL,
6,
NULL,
0,
&dwSize);
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
goto Cleanup;
if ( !((LPBYTE)pDriverInfo6 = LocalAllocMem(dwSize)) ||
!GetPrinterDriver(hPrinter,
NULL,
6,
(LPBYTE)pDriverInfo6,
dwSize,
&dwSize) ) {
goto Cleanup;
}
dwIndex = 0;
DrvInfoData.cbSize = sizeof(DrvInfoData);
while ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
dwIndex, &DrvInfoData) ) {
//
// Is the driver name same?
//
if ( !lstrcmpi(pDriverInfo6->pName, DrvInfoData.Description) ) {
if ( !SetupDiSetSelectedDriver(hDevInfo, NULL, &DrvInfoData) ||
!(pLocalData = BuildInternalData(hDevInfo, NULL)) ||
!ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0, FALSE) ) {
if ( pLocalData ) {
DestroyLocalData(pLocalData);
pLocalData = NULL;
}
break;
}
//
// Are the DRIVER_INFO_6's identical?
//
if ( IdenticalDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
pDriverInfo6) )
break;
DestroyLocalData(pLocalData);
pLocalData = NULL;
}
DrvInfoData.cbSize = sizeof(DrvInfoData);
++dwIndex;
}
if ( pLocalData == NULL ) {
SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
goto Cleanup;
}
pszInf= pLocalData->DrvInfo.pszInfName;
dwSize = *pcbInfNameSize;
*pcbInfNameSize = (lstrlen(pszInf) + 1) * sizeof(TCHAR);
if ( dwSize < *pcbInfNameSize ) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto Cleanup;
}
StringCbCopy(pszInfName, dwSize, pszInf);
bRet = TRUE;
Cleanup:
ClosePrinter(hPrinter);
LocalFreeMem(pDriverInfo6);
DestroyLocalData(pLocalData);
return bRet;
}