mirror of https://github.com/tongzx/nt5src
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.
1667 lines
46 KiB
1667 lines
46 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 } };
|
|
|
|
|
|
#if 0
|
|
TCHAR cszOEMInfGen[] = TEXT("%s\\inf\\OEM%d.INF");
|
|
TCHAR cszInfGen[] = TEXT("%s\\inf\\%s");
|
|
TCHAR cszClass[] = TEXT("Class");
|
|
TCHAR cszProvider[] = TEXT("Provider");
|
|
TCHAR cszPNF[] = TEXT ("PNF");
|
|
TCHAR cszINF[] = TEXT ("\\INF\\");
|
|
TCHAR cszInfWildCard[] = TEXT ("*.inf");
|
|
#endif
|
|
|
|
extern TCHAR cszPrinter[];
|
|
|
|
LPTSTR
|
|
GetInfQueryString(
|
|
IN PSP_INF_INFORMATION pSpInfInfo,
|
|
IN LPCTSTR pszKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets a specified string in a INF info list and put it into allocated memory
|
|
|
|
Arguments:
|
|
pSpInfInfo : Pointer to Handle to the information of an INF file
|
|
pszKey : Key of the string to be queried
|
|
|
|
Return Value:
|
|
The allocated string on success
|
|
NULL else
|
|
|
|
--*/
|
|
{
|
|
DWORD dwNeeded = 128;
|
|
LPTSTR pszStr;
|
|
|
|
if (! (pszStr = LocalAllocMem (dwNeeded * sizeof (*pszStr))))
|
|
return NULL;
|
|
|
|
if (SetupQueryInfVersionInformation(pSpInfInfo, 0, pszKey, pszStr,
|
|
dwNeeded, &dwNeeded)) {
|
|
return pszStr;
|
|
}
|
|
else {
|
|
LocalFreeMem (pszStr);
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER ) return NULL;
|
|
|
|
// Allocate Memory
|
|
if (! (pszStr = LocalAllocMem (dwNeeded * sizeof (*pszStr))))
|
|
return NULL;
|
|
|
|
if (!SetupQueryInfVersionInformation(pSpInfInfo, 0, pszKey, pszStr,
|
|
dwNeeded, &dwNeeded)){
|
|
LocalFreeMem (pszStr);
|
|
return NULL;
|
|
}
|
|
else
|
|
return pszStr;
|
|
}
|
|
}
|
|
|
|
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;
|
|
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 ..
|
|
//
|
|
LoadString(ghInst,
|
|
IDS_PRINTERWIZARD,
|
|
SelectDevParams.Title,
|
|
SIZECHARS(SelectDevParams.Title));
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
wsprintf(SelectDevParams.Instructions, pszWin95Instn, pszModel);
|
|
LocalFreeMem(pszWin95Instn);
|
|
} else {
|
|
|
|
LoadString(ghInst,
|
|
IDS_WINNTDEV_INSTRUCT,
|
|
SelectDevParams.Instructions,
|
|
SIZECHARS(SelectDevParams.Instructions));
|
|
}
|
|
|
|
LoadString(ghInst,
|
|
IDS_SELECTDEV_LABEL,
|
|
SelectDevParams.ListLabel,
|
|
SIZECHARS(SelectDevParams.ListLabel));
|
|
|
|
return SetupDiSetClassInstallParams(
|
|
hDevInfo,
|
|
pDevInfoData,
|
|
&SelectDevParams.ClassInstallHeader,
|
|
sizeof(SelectDevParams));
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
PSetupSetSelectDevTitleAndInstructions(
|
|
HDEVINFO hDevInfo,
|
|
LPCTSTR pszTitle,
|
|
LPCTSTR pszSubTitle,
|
|
LPCTSTR pszInstn
|
|
)
|
|
{
|
|
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 )
|
|
lstrcpy(SelectDevParams.Title, pszTitle);
|
|
|
|
if ( pszSubTitle )
|
|
lstrcpy(SelectDevParams.SubTitle, pszSubTitle);
|
|
|
|
if ( pszInstn )
|
|
lstrcpy(SelectDevParams.Instructions, pszInstn);
|
|
|
|
return SetupDiSetClassInstallParams(
|
|
hDevInfo,
|
|
NULL,
|
|
&SelectDevParams.ClassInstallHeader,
|
|
sizeof(SelectDevParams));
|
|
|
|
}
|
|
|
|
BOOL
|
|
PSetupSelectDeviceButtons(
|
|
HDEVINFO hDevInfo,
|
|
DWORD dwFlagsSet,
|
|
DWORD dwFlagsClear
|
|
)
|
|
{
|
|
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 )
|
|
lstrcpy(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;
|
|
|
|
lstrcpy(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));
|
|
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
|
|
)
|
|
{
|
|
return BuildInternalData(hDevInfo, NULL);
|
|
}
|
|
|
|
|
|
#if 0
|
|
DWORD GetDriverNumber (HDEVINFO hDevInfo)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the number of drivers in a particular INF file
|
|
|
|
Arguments:
|
|
|
|
hDevInfo : Handle got by calling PSetupCreateDrvSetupParams
|
|
|
|
Return Value:
|
|
Number of drivers (from 1 if no error happens)
|
|
|
|
++*/
|
|
{
|
|
SP_DRVINFO_DATA DrvInfoData;
|
|
DWORD dwLast = 0;
|
|
DWORD dwMiddle;
|
|
DWORD dwLastFailed = 10;
|
|
|
|
DrvInfoData.cbSize = sizeof (DrvInfoData);
|
|
|
|
// Expand the number
|
|
while (SetupDiEnumDriverInfo (hDevInfo, NULL,SPDIT_CLASSDRIVER,
|
|
dwLastFailed, &DrvInfoData)) {
|
|
dwLast = dwLastFailed;
|
|
dwLastFailed *= 2;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
|
|
// We've got an boundary, the number is between dwLast and dwLastFailed
|
|
|
|
while (dwLastFailed - dwLast > 1) {
|
|
dwMiddle = (dwLastFailed + dwLast) / 2;
|
|
if (!SetupDiEnumDriverInfo (hDevInfo, NULL,SPDIT_CLASSDRIVER,
|
|
dwMiddle, &DrvInfoData)) {
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
|
dwLastFailed = dwMiddle;
|
|
else
|
|
// Some other errors. Ignore them by assuming the driver number is 0
|
|
return 0;
|
|
}
|
|
else dwLast = dwMiddle;
|
|
}
|
|
return dwLast + 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
IsSubSet (
|
|
IN HDEVINFO hDevInfoA,
|
|
IN HDEVINFO hDevInfoB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if the driver list in hDevInfoA is a subset of
|
|
the driver list in hDevInfoB
|
|
|
|
Arguments:
|
|
|
|
hDevInfoA : The handle of the driver list A
|
|
hDevInfoB : The handle of the driver list B
|
|
|
|
Return Value:
|
|
TRUE if A is a subset of B, FALSE else
|
|
|
|
++*/
|
|
|
|
{
|
|
SP_DRVINFO_DATA DrvInfoDataA;
|
|
SP_DRVINFO_DATA DrvInfoDataB;
|
|
DWORD j,k;
|
|
DWORD lastUnmatched;
|
|
BOOL found;
|
|
BOOL bRet = FALSE;
|
|
BOOL bSameMfgName;
|
|
|
|
DrvInfoDataA.cbSize = sizeof (DrvInfoDataA);
|
|
DrvInfoDataB.cbSize = sizeof (DrvInfoDataB);
|
|
|
|
j = 0;
|
|
lastUnmatched = 0;
|
|
|
|
// Get a set of driver data
|
|
while (bRet = SetupDiEnumDriverInfo (hDevInfoA, NULL,
|
|
SPDIT_CLASSDRIVER, j, &DrvInfoDataA)) {
|
|
//Compare the old one with the new driver set to see if it is in the set
|
|
|
|
k = lastUnmatched;
|
|
found = FALSE;
|
|
bSameMfgName = FALSE;
|
|
|
|
while (SetupDiEnumDriverInfo (hDevInfoB, NULL, SPDIT_CLASSDRIVER, k,
|
|
&DrvInfoDataB) && !found) {
|
|
|
|
if (lstrcmpi (DrvInfoDataA.MfgName, DrvInfoDataB.MfgName)) {
|
|
if (bSameMfgName) {
|
|
// This means, we've scanned all the entries with the
|
|
// same manufacture name, but none of them matches
|
|
// So the list A contains an entry which the list B
|
|
// does not. Stop,
|
|
return FALSE;
|
|
}
|
|
// Different Manufacture name, never visit it again
|
|
k++;
|
|
lastUnmatched = k;
|
|
}
|
|
else {
|
|
bSameMfgName = TRUE; // Set the flag
|
|
|
|
// Manufacture matched
|
|
if (DrvInfoDataB.DriverType == DrvInfoDataA.DriverType &&
|
|
!lstrcmpi (DrvInfoDataB.Description, DrvInfoDataA.Description)) {
|
|
found = TRUE;
|
|
// A match
|
|
if (lastUnmatched == k) { // Continuous match
|
|
k++;
|
|
lastUnmatched = k;
|
|
}
|
|
else {
|
|
// It is a match, but some models in the new list is not on the
|
|
// old list
|
|
// Don't update lastUnmatched, because we've to revisit it again.
|
|
k++;
|
|
}
|
|
}
|
|
else { // does not match
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Can not delete the existing driver, quit the loop
|
|
if (!found) return FALSE;
|
|
|
|
// Otherwise, check the next existing driver in the list A
|
|
j++;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
|
// All the drivers in the list A have been found in list B
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CopyOEMInfFileAndGiveUniqueName(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pSpDevInfoData,
|
|
IN LPTSTR pszInfFile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if an OEM driver list is a subset of the driver
|
|
to be installed and if so
|
|
copies the OEM printer inf file to "<systemroot>\Inf\OEM<n>.INF".
|
|
Where n is the first unused file number.
|
|
|
|
|
|
Arguments:
|
|
|
|
hDevInfo : Handle got by calling PSetupCreateDrvSetupParams
|
|
pszInfFile : Fully qualified path of OEM inf file
|
|
|
|
Return Value:
|
|
TRUE if no error, FALSE else
|
|
|
|
++*/
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
TCHAR szNewFileName[MAX_PATH];
|
|
TCHAR szSystemDir[MAX_PATH];
|
|
DWORD i,j;
|
|
BOOL bRet = FALSE;
|
|
SP_DRVINFO_DATA DrvInfoData;
|
|
DWORD dwNeeded;
|
|
PSP_INF_INFORMATION pSpInfInfo = NULL;
|
|
LPTSTR pszProviderName = NULL;
|
|
LPTSTR pszNewProvider = NULL;
|
|
LPTSTR pszInfFullName = NULL;
|
|
LPTSTR pszInfName = NULL;
|
|
HDEVINFO hOldDevInfo = INVALID_HANDLE_VALUE;
|
|
SP_DEVINSTALL_PARAMS DevInstallParams;
|
|
DWORD dwNumNewDrivers;
|
|
DWORD dwNumOldDrivers;
|
|
DWORD dwLen;
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
HANDLE hInfFile = INVALID_HANDLE_VALUE;
|
|
UINT uErrorLine;
|
|
DWORD dwInfNeeded = 2048;
|
|
// Since to get file list takes long time,
|
|
// so we try to use the previous values to
|
|
// Allocate the memeory first.
|
|
|
|
DevInstallParams.cbSize = sizeof(DevInstallParams);
|
|
DevInstallParams.DriverPath[0] = 0;
|
|
DrvInfoData.cbSize = sizeof (DrvInfoData);
|
|
|
|
//
|
|
// Check DeviceInstallParams to see if OEM driver list is built
|
|
//
|
|
if ( !SetupDiGetDeviceInstallParams(hDevInfo,
|
|
pSpDevInfoData,
|
|
&DevInstallParams) )
|
|
return FALSE;
|
|
|
|
|
|
// If DriverPath is clear then not an OEM driver
|
|
if ( !DevInstallParams.DriverPath[0] ) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
if (!GetSystemDirectory(szSystemDir, SIZECHARS (szSystemDir)))
|
|
return FALSE;
|
|
|
|
dwLen = lstrlen (szSystemDir);
|
|
|
|
// 2 mean equal. If pszInfFile is in the system directory, don't copy it
|
|
if (2 == CompareString(LOCALE_SYSTEM_DEFAULT,
|
|
NORM_IGNORECASE,
|
|
szSystemDir,
|
|
dwLen,
|
|
pszInfFile,
|
|
dwLen))
|
|
return TRUE;
|
|
|
|
|
|
if ( !GetWindowsDirectory(szSystemDir,SIZECHARS(szSystemDir)))
|
|
goto Cleanup;
|
|
|
|
|
|
// Check to see if there is any existing .INF files which are subsets of the
|
|
// new driver to be installed
|
|
if (! PSetupBuildDriversFromPath(hDevInfo, pszInfFile, TRUE)) goto Cleanup;
|
|
|
|
dwNumNewDrivers = GetDriverNumber (hDevInfo);
|
|
|
|
// Get a set of driver data
|
|
if (!SetupDiEnumDriverInfo (hDevInfo, NULL, SPDIT_CLASSDRIVER, 0, &DrvInfoData))
|
|
goto Cleanup;
|
|
|
|
if (! (pszNewProvider = AllocStr (DrvInfoData.ProviderName))) goto Cleanup;
|
|
|
|
|
|
// Allocate enough memeory for the full path
|
|
if (! (pszInfFullName = LocalAllocMem ((lstrlen (szSystemDir) + lstrlen (cszINF)
|
|
+ MAX_PATH + 1) * sizeof (TCHAR))))
|
|
goto Cleanup;
|
|
|
|
lstrcpy (pszInfFullName, szSystemDir);
|
|
lstrcat (pszInfFullName, cszINF);
|
|
|
|
// pszInfName always points to the begining of the name
|
|
pszInfName = pszInfFullName + lstrlen (pszInfFullName);
|
|
lstrcpy (pszInfName, cszInfWildCard);
|
|
|
|
hFindFile = FindFirstFile (pszInfFullName, &FindData);
|
|
if (hFindFile != INVALID_HANDLE_VALUE) {
|
|
|
|
do {
|
|
//
|
|
// Skip directories
|
|
//
|
|
if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
continue;
|
|
}
|
|
|
|
// We've got a name
|
|
lstrcpy (pszInfName, FindData.cFileName);
|
|
|
|
hInfFile = SetupOpenInfFile(pszInfFullName,
|
|
cszPrinter,
|
|
INF_STYLE_WIN4 | INF_STYLE_OLDNT,
|
|
&uErrorLine);
|
|
if (hInfFile == INVALID_HANDLE_VALUE)
|
|
continue;
|
|
|
|
// We've opened a file which has a printer as the class name
|
|
|
|
if (! (pSpInfInfo = LocalAllocMem (dwInfNeeded * sizeof (TCHAR)))) goto NextFile;
|
|
|
|
// use dwNeeded so that dwInfNeeded is modified only when the buffer is insufficient
|
|
dwNeeded = dwInfNeeded;
|
|
if (!SetupGetInfInformation (hInfFile, INFINFO_INF_SPEC_IS_HINF, pSpInfInfo,
|
|
dwInfNeeded, &dwNeeded)) {
|
|
if (ERROR_INSUFFICIENT_BUFFER == GetLastError ()) {
|
|
LocalFree (pSpInfInfo);
|
|
if (! (pSpInfInfo = LocalAllocMem (dwNeeded * sizeof (TCHAR)))) goto NextFile;
|
|
dwInfNeeded = dwNeeded;
|
|
|
|
if (!SetupGetInfInformation (hInfFile, INFINFO_INF_SPEC_IS_HINF,
|
|
pSpInfInfo, dwInfNeeded, &dwNeeded))
|
|
goto NextFile;
|
|
}
|
|
else goto NextFile;
|
|
|
|
}
|
|
|
|
if (! (pszProviderName = GetInfQueryString(pSpInfInfo, cszProvider)))
|
|
goto NextFile;
|
|
|
|
if (!lstrcmpi (pszNewProvider, pszProviderName)) {
|
|
// If both INF files are from the same provider, try to check if it can be deleted
|
|
|
|
if ((hOldDevInfo = SetupDiCreateDeviceInfoList(
|
|
(LPGUID)&GUID_DEVCLASS_PRINTER, NULL)) == INVALID_HANDLE_VALUE)
|
|
goto NextFile;
|
|
|
|
if (! PSetupBuildDriversFromPath(hOldDevInfo, pszInfFullName, TRUE))
|
|
goto NextFile;
|
|
|
|
dwNumOldDrivers = GetDriverNumber (hOldDevInfo);
|
|
|
|
// It is not possible to be a subset of the new one
|
|
if (dwNumOldDrivers >= dwNumNewDrivers) {
|
|
if (IsSubSet (hDevInfo, hOldDevInfo)) {
|
|
// No need to copy the new one
|
|
bRet = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if (dwNumOldDrivers <= dwNumNewDrivers) {
|
|
if (IsSubSet (hOldDevInfo, hDevInfo)) {
|
|
// All the drivers in the current file have been found in the new
|
|
// driver file, delete the old file
|
|
DeleteFile (pszInfFullName);
|
|
// and its corresponding .PNF file
|
|
lstrcpyn (pszInfName + lstrlen (pszInfName) - 3, cszPNF, 4);
|
|
DeleteFile (pszInfFullName);
|
|
}
|
|
}
|
|
|
|
// Else Close the file and continue on the next one
|
|
} // End of provider name comparison
|
|
|
|
|
|
NextFile:
|
|
if (hInfFile != INVALID_HANDLE_VALUE) {
|
|
SetupCloseInfFile (hInfFile);
|
|
hInfFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
if (hOldDevInfo != INVALID_HANDLE_VALUE) {
|
|
SetupDiDestroyDeviceInfoList (hOldDevInfo);
|
|
hOldDevInfo = INVALID_HANDLE_VALUE;
|
|
}
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
// Clear the pointers so that the clean up won't free them again
|
|
LocalFreeMem (pSpInfInfo);
|
|
pSpInfInfo = NULL;
|
|
|
|
} // End of the loop
|
|
while (FindNextFile(hFindFile,&FindData));
|
|
}
|
|
|
|
// All the duplicate files are deleted. Let's create a new one
|
|
|
|
for ( i = 0 ; i < 10000 ; ++i ) {
|
|
|
|
wsprintf(szNewFileName, cszOEMInfGen, szSystemDir, i);
|
|
|
|
//
|
|
// By using the CREATE_NEW flag we reserve the file name and
|
|
// will not end up overwriting another file which gets created
|
|
// by another setup (some inf) thread
|
|
//
|
|
hFile = CreateFile(szNewFileName,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if ( hFile != INVALID_HANDLE_VALUE ) {
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
bRet = CopyFile(pszInfFile, szNewFileName, FALSE);
|
|
goto Cleanup;
|
|
}
|
|
else if ( GetLastError() != ERROR_FILE_EXISTS )
|
|
break;
|
|
}
|
|
|
|
Cleanup:
|
|
if (hFindFile != INVALID_HANDLE_VALUE)
|
|
FindClose (hFindFile);
|
|
if (hInfFile != INVALID_HANDLE_VALUE)
|
|
SetupCloseInfFile (hInfFile);
|
|
if (hOldDevInfo != INVALID_HANDLE_VALUE)
|
|
SetupDiDestroyDeviceInfoList (hOldDevInfo);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile);
|
|
LocalFreeMem (pszInfFullName);
|
|
LocalFreeMem (pszNewProvider);
|
|
LocalFreeMem (pszProviderName);
|
|
LocalFreeMem (pSpInfInfo);
|
|
return bRet;
|
|
}
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
PSetupSelectDriver(
|
|
IN HDEVINFO hDevInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Display manufacturer/model information and have the user select a
|
|
printer driver. 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 ))) {
|
|
|
|
lstrcpy(szDriverPath, pLocalData->DrvInfo.pszInfName);
|
|
if ( psz = FileNamePart(szDriverPath) ) {
|
|
|
|
*psz = TEXT('\0');
|
|
return;
|
|
}
|
|
}
|
|
|
|
pszTempPath = GetSystemInstallPath();
|
|
if ( pszTempPath != NULL )
|
|
{
|
|
lstrcpy(szDriverPath, pszTempPath);
|
|
LocalFreeMem(pszTempPath);
|
|
}
|
|
else
|
|
// Default put A:\ since we have to give something to setup
|
|
lstrcpy(szDriverPath, 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
|
|
PSetupRefreshDriverList(
|
|
IN HDEVINFO hDevInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Destroy current driver list and build new one if currently an OEM driver
|
|
list is associated. This way if you go back after choosing HaveDisk you
|
|
would still see drivers from inf directory instead of the OEM inf ...
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE on error
|
|
|
|
--*/
|
|
{
|
|
SP_DEVINSTALL_PARAMS DevInstallParams = { 0 };
|
|
|
|
DevInstallParams.cbSize = sizeof(DevInstallParams);
|
|
|
|
//
|
|
// Check DeviceInstallParams to see if OEM driver list is built
|
|
//
|
|
if ( SetupDiGetDeviceInstallParams(hDevInfo,
|
|
NULL,
|
|
&DevInstallParams) &&
|
|
!DevInstallParams.DriverPath[0] ) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Destroy current list and build another one
|
|
//
|
|
SetupDiDestroyDriverInfoList(hDevInfo,
|
|
NULL,
|
|
SPDIT_CLASSDRIVER);
|
|
|
|
DevInstallParams.DriverPath[0] = sZero;
|
|
|
|
return SetupDiSetDeviceInstallParams(hDevInfo,
|
|
NULL,
|
|
&DevInstallParams) &&
|
|
|
|
BuildClassDriverList(hDevInfo);
|
|
}
|
|
|
|
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('\\');
|
|
}
|
|
_tcscat(szSysInf, pRelInfPath);
|
|
if (!_tcsicmp(szSysInf, pszInfName))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
PSetupIsOemDriver(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN PBOOL pbIsOemDriver
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Returns indication if the currently selected driver list
|
|
is an OEM driver list.
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pLocalData : Gives the selected driver information
|
|
pbIsOemDriver : Pointer to bool where to return OEM driver indicator.
|
|
Set to TRUE if driver is an OEM driver.
|
|
Set to FALSE if driver is not an OEM driver.
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE on error.
|
|
|
|
--*/
|
|
{
|
|
TCHAR szSystemDir[MAX_PATH];
|
|
BOOL bRet = FALSE;
|
|
DWORD dwLen;
|
|
|
|
//
|
|
// Ideally Setup API should have an export for this. But rather than
|
|
// waiting for them to do this let me write the code and get it done with
|
|
//
|
|
if ( pLocalData &&
|
|
( pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ) )
|
|
{
|
|
*pbIsOemDriver = FALSE;
|
|
bRet = TRUE;
|
|
}
|
|
else if ( dwLen = GetSystemWindowsDirectory(szSystemDir, SIZECHARS(szSystemDir)) )
|
|
{
|
|
bRet = TRUE;
|
|
|
|
//
|
|
// If Inf is not under %windir% then it is OEM
|
|
//
|
|
*pbIsOemDriver = lstrncmpi(pLocalData->DrvInfo.pszInfName,
|
|
szSystemDir,
|
|
dwLen) != 0;
|
|
}
|
|
|
|
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.
|
|
|
|
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
|
|
)
|
|
{
|
|
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;
|
|
|
|
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) ) {
|
|
|
|
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
|
|
)
|
|
{
|
|
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
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwSize, dwIndex;
|
|
HANDLE hPrinter;
|
|
LPTSTR pszInf;
|
|
PPSETUP_LOCAL_DATA pLocalData = NULL;
|
|
LPDRIVER_INFO_6 pDriverInfo6 = NULL;
|
|
SP_DRVINFO_DATA DrvInfoData;
|
|
|
|
|
|
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) ) {
|
|
|
|
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;
|
|
}
|
|
|
|
lstrcpy(pszInfName, pszInf);
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
ClosePrinter(hPrinter);
|
|
LocalFreeMem(pDriverInfo6);
|
|
DestroyLocalData(pLocalData);
|
|
|
|
return bRet;
|
|
}
|