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.
2015 lines
62 KiB
2015 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1995-97 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Ntprint.c
|
|
|
|
Abstract:
|
|
|
|
Ntprint.dll main functions
|
|
|
|
Author:
|
|
|
|
Muhunthan Sivapragasam (MuhuntS) 02-Jan-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#include "splcom.h"
|
|
#include "regstr.h"
|
|
|
|
HINSTANCE ghInst;
|
|
DWORD dwThisMajorVersion = 3;
|
|
|
|
PCODEDOWNLOADINFO gpCodeDownLoadInfo = NULL;
|
|
|
|
HANDLE hPrintui = NULL;
|
|
DWORD (*dwfnPnPInterface)(
|
|
IN EPnPFunctionCode Function,
|
|
IN TParameterBlock *pParameterBlock
|
|
) = NULL;
|
|
|
|
TCHAR cszPortName[] = TEXT("PortName");
|
|
TCHAR cszPnPKey[] = TEXT("PnPData");
|
|
TCHAR cszDeviceInstanceId[] = TEXT("DeviceInstanceId");
|
|
TCHAR cszHardwareID[] = TEXT("HardwareID");
|
|
TCHAR cszManufacturer[] = TEXT("Manufacturer");
|
|
TCHAR cszOEMUrl[] = TEXT("OEM URL");
|
|
TCHAR cszProcessAlways[] = TEXT(".ProcessPerPnpInstance");
|
|
TCHAR cszRunDll32[] = TEXT("rundll32.exe");
|
|
TCHAR cszBestDriverInbox[] = TEXT("InstallInboxDriver");
|
|
|
|
const DWORD dwFourMinutes = 240000;
|
|
|
|
OSVERSIONINFO OsVersionInfo;
|
|
LCID lcid;
|
|
|
|
#define MAX_PRINTER_NAME MAX_PATH
|
|
|
|
MODULE_DEBUG_INIT(DBG_WARN|DBG_ERROR, DBG_ERROR);
|
|
|
|
BOOL
|
|
DllMain(
|
|
IN HINSTANCE hInst,
|
|
IN DWORD dwReason,
|
|
IN LPVOID lpRes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Dll entry point.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(lpRes);
|
|
|
|
switch( dwReason ){
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
ghInst = hInst;
|
|
|
|
if( !bSplLibInit(NULL))
|
|
{
|
|
DBGMSG( DBG_WARN,
|
|
( "DllEntryPoint: Failed to init SplLib %d\n", GetLastError( )));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DisableThreadLibraryCalls(hInst);
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
|
|
|
|
if ( !GetVersionEx(&OsVersionInfo) )
|
|
return FALSE;
|
|
lcid = GetUserDefaultLCID();
|
|
|
|
InitializeCriticalSection(&CDMCritSect);
|
|
InitializeCriticalSection(&SkipCritSect);
|
|
|
|
if(IsInWow64())
|
|
{
|
|
//
|
|
// 32-bit code running on Win64 -> set platform appropriately
|
|
//
|
|
MyPlatform = PlatformIA64;
|
|
}
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
if ( hPrintui )
|
|
FreeLibrary(hPrintui);
|
|
|
|
DeleteCriticalSection(&CDMCritSect);
|
|
// Cleanup and CDM Context created by windows update.
|
|
DestroyCodedownload( gpCodeDownLoadInfo );
|
|
gpCodeDownLoadInfo = NULL;
|
|
//
|
|
// We call DeleteCriticalSection(&SkipCritSect) from here
|
|
//
|
|
CleanupSkipDir();
|
|
vSplLibFree();
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
LoadAndInitializePrintui(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Check the refcount on printui, load it on 0 and increment the refcount.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE on error
|
|
|
|
--*/
|
|
{
|
|
LPTSTR szDll = TEXT("printui.dll");
|
|
|
|
if ( hPrintui ) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if ( hPrintui = LoadLibraryUsingFullPath(szDll) ) {
|
|
|
|
if ( (FARPROC)dwfnPnPInterface = GetProcAddress(hPrintui,
|
|
"PnPInterface") ) {
|
|
|
|
return TRUE;
|
|
} else {
|
|
|
|
FreeLibrary(hPrintui);
|
|
hPrintui = NULL;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
PSetupAssociateICMProfiles(
|
|
IN LPCTSTR pszzICMFiles,
|
|
IN LPCTSTR pszPrinterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Install ICM color profiles for a printer driver and associate it with
|
|
the printer name given
|
|
|
|
Arguments:
|
|
pszzICMFiles : Multi-sz field giving ICM profile names
|
|
pszPrinterName : Printer name
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
TCHAR szDir[MAX_PATH], *p;
|
|
DWORD dwSize, dwNeeded;
|
|
|
|
dwSize = SIZECHARS(szDir);
|
|
dwNeeded = sizeof(szDir);
|
|
|
|
if( !pszzICMFiles || !pszPrinterName)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !GetColorDirectory(NULL, szDir, &dwNeeded) )
|
|
return FALSE;
|
|
|
|
dwNeeded /= sizeof(TCHAR);
|
|
szDir[dwNeeded-1] = TEXT('\\');
|
|
|
|
//
|
|
// Install and assoicate each profiles from the multi-sz field
|
|
//
|
|
for ( p = (LPTSTR)pszzICMFiles; *p ; p += lstrlen(p) + 1 ) {
|
|
|
|
if ( dwNeeded + lstrlen(p) + 1 > dwSize ) {
|
|
|
|
ASSERT(dwNeeded + lstrlen(p) + 1 <= dwSize);
|
|
continue;
|
|
}
|
|
|
|
StringCchCopy(szDir + dwNeeded, COUNTOF(szDir) - dwNeeded, p);
|
|
//
|
|
// We do not need the right server name here since ICM should send it
|
|
// to the right server
|
|
//
|
|
if ( !AssociateColorProfileWithDevice(NULL, szDir, pszPrinterName) )
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetPlugAndPlayInfo(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PPSETUP_LOCAL_DATA pLocalData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Get necessary PnP info LPT enumerator would have setup in the config
|
|
manager registry
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pLocalData : Gives installation data
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey = NULL;
|
|
TCHAR buf[MAX_PATH];
|
|
DWORD dwType, dwSize, dwReturn;
|
|
PNP_INFO PnPInfo;
|
|
|
|
if(!pDevInfoData || !pLocalData)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT( !(pLocalData->Flags & VALID_PNP_INFO) );
|
|
|
|
ZeroMemory(&PnPInfo, sizeof(PnPInfo));
|
|
|
|
//
|
|
// Look in the devnode for the printer created to get the port name and
|
|
// the device instance id
|
|
//
|
|
if ( dwReturn = CM_Open_DevNode_Key(pDevInfoData->DevInst, KEY_READ, 0,
|
|
RegDisposition_OpenExisting, &hKey,
|
|
CM_REGISTRY_HARDWARE) )
|
|
goto Cleanup;
|
|
|
|
dwSize = sizeof(buf);
|
|
|
|
if ( dwReturn = RegQueryValueEx(hKey, cszPortName, NULL, &dwType,
|
|
(LPBYTE)&buf, &dwSize) ) {
|
|
|
|
if ( dwReturn == ERROR_FILE_NOT_FOUND )
|
|
dwReturn = ERROR_UNKNOWN_PORT;
|
|
goto Cleanup;
|
|
}
|
|
|
|
buf[COUNTOF(buf)-1] = TEXT('\0');
|
|
|
|
if ( !(PnPInfo.pszPortName = AllocStr(buf)) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// This can't be bigger than MAX_DEVICE_ID_LEN so it is ok
|
|
//
|
|
if ( !SetupDiGetDeviceInstanceId(hDevInfo,
|
|
pDevInfoData,
|
|
buf,
|
|
SIZECHARS(buf),
|
|
NULL) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
buf[COUNTOF(buf)-1] = TEXT('\0');
|
|
|
|
if ( !(PnPInfo.pszDeviceInstanceId = AllocStr(buf)) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( dwReturn == ERROR_SUCCESS ) {
|
|
|
|
CopyMemory(&pLocalData->PnPInfo, &PnPInfo, sizeof(PnPInfo));
|
|
pLocalData->Flags |= VALID_PNP_INFO;
|
|
} else {
|
|
|
|
FreeStructurePointers((LPBYTE)&PnPInfo, PnPInfoOffsets, FALSE);
|
|
}
|
|
|
|
if ( hKey )
|
|
RegCloseKey(hKey);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrinterGoingToPort(
|
|
IN LPPRINTER_INFO_2 pPrinterInfo2,
|
|
IN LPCTSTR pszPortName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Find out if a printer is going to a port (it may go to other ports also)
|
|
|
|
Arguments:
|
|
pPrinterInfo2 : Gives the PRINTER_INFO_2 for the print queue
|
|
pszPortName : The port name
|
|
|
|
Return Value:
|
|
If the print queue is going to the port TRUE, else FALSE
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszStr1, pszStr2;
|
|
|
|
if (!pPrinterInfo2 || !pszPortName)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pszStr1 = pPrinterInfo2->pPortName;
|
|
|
|
//
|
|
// Port names are returned comma separated by spooler; and there are blanks
|
|
//
|
|
while ( pszStr2 = lstrchr(pszStr1, sComma) ) {
|
|
//
|
|
// ISSUE-2002/03/08-mikaelho
|
|
// Should we reset the '\0's to ',' in this function so we do not
|
|
// alter the PRINTER_INFO_2 structure passed in? Check how NewDriverForInstalledDevice
|
|
// uses this function.
|
|
//
|
|
*pszStr2 = sZero;
|
|
++pszStr2;
|
|
|
|
if ( !lstrcmpi(pszPortName, pszStr1) )
|
|
return TRUE;
|
|
pszStr1 = pszStr2;
|
|
|
|
//
|
|
// Skip spaces
|
|
//
|
|
while ( *pszStr1 == TEXT(' ') )
|
|
++pszStr1;
|
|
}
|
|
|
|
if ( !lstrcmpi(pszPortName, pszStr1) )
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetPnPInfoForPrinter(
|
|
IN HANDLE hPrinter,
|
|
IN LPCTSTR pszDeviceInstanceId,
|
|
IN LPCTSTR pszHardwareID,
|
|
IN LPCTSTR pszManufacturer,
|
|
IN LPCTSTR pszOEMUrl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Set registry values in the PnPInfo subkey
|
|
|
|
Arguments:
|
|
hPrinter : Printer handle
|
|
pszDeviceInstanceId : DeviceInstance Id
|
|
pszHardwareID : Device PnP or Compat Id
|
|
pszManufacturer : Manufacturer (from the inf)
|
|
pszOEMUrl : Manufacturer URL (from the inf)
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
|
|
if ( pszDeviceInstanceId && *pszDeviceInstanceId)
|
|
dwLastError = SetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszDeviceInstanceId,
|
|
REG_SZ,
|
|
(LPBYTE)pszDeviceInstanceId,
|
|
(lstrlen(pszDeviceInstanceId) + 1)
|
|
* sizeof(TCHAR));
|
|
|
|
if ( dwLastError == ERROR_SUCCESS && pszHardwareID && *pszHardwareID )
|
|
dwLastError = SetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszHardwareID,
|
|
REG_SZ,
|
|
(LPBYTE)pszHardwareID,
|
|
(lstrlen(pszHardwareID) + 1)
|
|
* sizeof(TCHAR));
|
|
|
|
if ( dwLastError == ERROR_SUCCESS && pszManufacturer && *pszManufacturer )
|
|
dwLastError = SetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszManufacturer,
|
|
REG_SZ,
|
|
(LPBYTE)pszManufacturer,
|
|
(lstrlen(pszManufacturer) + 1)
|
|
* sizeof(TCHAR));
|
|
|
|
if ( dwLastError == ERROR_SUCCESS && pszOEMUrl && *pszOEMUrl )
|
|
dwLastError = SetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszOEMUrl,
|
|
REG_SZ,
|
|
(LPBYTE)pszOEMUrl,
|
|
(lstrlen(pszOEMUrl) + 1)
|
|
* sizeof(TCHAR));
|
|
|
|
if ( dwLastError ) {
|
|
|
|
SetLastError(dwLastError);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrinterInfo2s(
|
|
OUT LPPRINTER_INFO_2 *ppPI2,
|
|
OUT LPDWORD pdwReturned
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Does an EnumPrinter and returns a list of PRINTER_INFO_2s of all local
|
|
printers. Caller should free the pointer.
|
|
|
|
Arguments:
|
|
ppPI2 : Points to PRINTER_INFO_2s on return
|
|
pdwReturned : Tells how many PRINTER_INFO_2s are returned
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwNeeded = 0x1000;
|
|
LPBYTE pBuf;
|
|
|
|
if ( !(pBuf = LocalAllocMem(dwNeeded)) )
|
|
goto Cleanup;
|
|
|
|
if ( !EnumPrinters(PRINTER_ENUM_LOCAL,
|
|
NULL,
|
|
2,
|
|
pBuf,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
pdwReturned) ) {
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|
goto Cleanup;
|
|
|
|
LocalFreeMem(pBuf);
|
|
if ( !(pBuf = LocalAllocMem(dwNeeded)) ||
|
|
!EnumPrinters(PRINTER_ENUM_LOCAL,
|
|
NULL,
|
|
2,
|
|
pBuf,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
pdwReturned) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if ( bRet ) {
|
|
|
|
*ppPI2 = (LPPRINTER_INFO_2)pBuf;
|
|
} else {
|
|
|
|
if ( pBuf )
|
|
LocalFreeMem(pBuf);
|
|
|
|
*ppPI2 = NULL;
|
|
*pdwReturned = 0;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DuplicateDevice(
|
|
IN PPSETUP_LOCAL_DATA pLocalData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Find out if a PnP reported printer is already installed
|
|
|
|
Arguments:
|
|
pLocalData : Gives installation data
|
|
|
|
Return Value:
|
|
If the printer is already install TRUE, else FALSE
|
|
|
|
--*/
|
|
{
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwReturned, dwNeeded;
|
|
HANDLE hPrinter;
|
|
LPTSTR pszDriverName = pLocalData->DrvInfo.pszModelName,
|
|
pszPortName = pLocalData->PnPInfo.pszPortName;
|
|
|
|
ASSERT( (pLocalData->Flags & VALID_PNP_INFO) &&
|
|
(pLocalData->Flags & VALID_INF_INFO) );
|
|
|
|
if ( !PrinterInfo2s(&p, &dwReturned) )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// If there is a local printer using the same driver and going to the
|
|
// same port then it is a duplicate
|
|
//
|
|
for ( dwNeeded = 0, pPrinterInfo2 = p ;
|
|
dwNeeded < dwReturned ;
|
|
++dwNeeded, pPrinterInfo2++ ) {
|
|
|
|
if ( !lstrcmpi(pszDriverName, pPrinterInfo2->pDriverName) &&
|
|
PrinterGoingToPort(pPrinterInfo2, pszPortName) )
|
|
break; // for loop
|
|
}
|
|
|
|
if ( dwNeeded == dwReturned )
|
|
goto Cleanup;
|
|
|
|
bReturn = TRUE;
|
|
|
|
if ( bReturn ) {
|
|
|
|
if ( OpenPrinter(pPrinterInfo2->pPrinterName,
|
|
&hPrinter,
|
|
&PrinterDefault) ) {
|
|
|
|
//
|
|
// If it fails can't help
|
|
//
|
|
(VOID)SetPnPInfoForPrinter(hPrinter,
|
|
pLocalData->PnPInfo.pszDeviceInstanceId,
|
|
pLocalData->DrvInfo.pszHardwareID,
|
|
pLocalData->DrvInfo.pszManufacturer,
|
|
pLocalData->DrvInfo.pszOEMUrl);
|
|
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
LocalFreeMem(p);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrinterPnPDataSame(
|
|
IN LPTSTR pszDeviceInstanceId,
|
|
IN LPTSTR pszPrinterName
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
Find out if a PnP printer has been installed with different driver name.
|
|
We need to associate the queue previously used with this new driver as
|
|
pnp says it's the new best driver for the device.
|
|
|
|
Arguments:
|
|
pszDeviceInstanceId : Gives the device ID instance string of the pnped device.
|
|
pszPrinterName : The name of the printer to compare the device instance ID to.
|
|
|
|
Return Value:
|
|
If printer's pnp data holds the same device instance ID as the passed ID returns TRUE, else FALSE.
|
|
|
|
*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
HANDLE hPrinter;
|
|
DWORD dwNeeded, dwType;
|
|
TCHAR szPrnId[MAX_DEVICE_ID_LEN];
|
|
|
|
if( pszPrinterName && pszDeviceInstanceId ) {
|
|
|
|
if ( OpenPrinter(pszPrinterName,
|
|
&hPrinter,
|
|
&PrinterDefault) ) {
|
|
|
|
if ( ERROR_SUCCESS == GetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszDeviceInstanceId,
|
|
&dwType,
|
|
(LPBYTE)szPrnId,
|
|
sizeof(szPrnId),
|
|
&dwNeeded) &&
|
|
(dwType == REG_SZ) &&
|
|
!lstrcmp(szPrnId, pszDeviceInstanceId) ) {
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NewDriverForInstalledDevice(
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
OUT LPTSTR pszPrinterName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Find out if a PnP printer has been installed with different driver name.
|
|
We need to associate the queue previously used with this new driver as
|
|
pnp says it's the new best driver for the device.
|
|
|
|
Arguments:
|
|
pLocalData : Gives installation data
|
|
pszPrinterName : Gives the printer name to return and use.
|
|
Must be at least MAX_PRINTER_NAME TCHARs in size
|
|
|
|
Return Value:
|
|
If a printer is already installed which uses another driver TRUE, else FALSE
|
|
|
|
--*/
|
|
{
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwReturned, dwNeeded;
|
|
HANDLE hPrinter;
|
|
LPTSTR pszPortName = pLocalData->PnPInfo.pszPortName;
|
|
LPTSTR pszDeviceInstanceId = pLocalData->PnPInfo.pszDeviceInstanceId;
|
|
|
|
ASSERT( (pLocalData->Flags & VALID_PNP_INFO) &&
|
|
(pLocalData->Flags & VALID_INF_INFO) );
|
|
|
|
if ( !PrinterInfo2s(&p, &dwReturned) )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// If there is a printer going to that same port and with the same pnp
|
|
// info, then it has been reinstalled with a newer driver.
|
|
//
|
|
for ( dwNeeded = 0, pPrinterInfo2 = p ;
|
|
dwNeeded < dwReturned ;
|
|
++dwNeeded, pPrinterInfo2++ ) {
|
|
|
|
if ( PrinterGoingToPort(pPrinterInfo2, pszPortName) &&
|
|
PrinterPnPDataSame(pszDeviceInstanceId, pPrinterInfo2->pPrinterName) ) {
|
|
|
|
break; // for loop
|
|
}
|
|
}
|
|
|
|
if ( dwNeeded == dwReturned ) {
|
|
//
|
|
// We didn't find anything...
|
|
//
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( OpenPrinter(pPrinterInfo2->pPrinterName,
|
|
&hPrinter,
|
|
&PrinterDefault) ) {
|
|
|
|
pPrinterInfo2->pDriverName = pLocalData->DrvInfo.pszModelName;
|
|
pPrinterInfo2->pPrintProcessor = pLocalData->InfInfo.pszPrintProc;
|
|
|
|
//
|
|
// ISSUE-2002/03/08-mikaelho
|
|
// Should we set the port name in the pPrinterInfo2 structure to pszPortName?
|
|
// Check comment in PrinterGoingToPort. Seems like we will now only
|
|
// use the first of the ports associated with the print queue.
|
|
//
|
|
if( SetPrinter( hPrinter, 2, (LPBYTE)pPrinterInfo2, 0 ) ) {
|
|
|
|
StringCchCopy( pszPrinterName, MAX_PRINTER_NAME, pPrinterInfo2->pPrinterName );
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
|
|
Cleanup:
|
|
if( p ) {
|
|
|
|
LocalFreeMem(p);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
VOID
|
|
CallVendorDll(
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN LPCTSTR pszPrinterName,
|
|
IN HWND hwnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
A VendorSetup was specified in the INF. Call the dll with the name of the
|
|
printer just created
|
|
|
|
Arguments:
|
|
pLocalData : Gives installation data
|
|
pszPrinterName : Name of the printer which got installed
|
|
hwnd : Window handle for any UI
|
|
|
|
Return Value:
|
|
If the printer is already install TRUE, else FALSE
|
|
|
|
--*/
|
|
{
|
|
TCHAR szCmd[MAX_PATH];
|
|
SHELLEXECUTEINFO ShellExecInfo;
|
|
TCHAR *pszExecutable = NULL;
|
|
TCHAR *pszParams = NULL;
|
|
LPTSTR pszVendorSetup = pLocalData->InfInfo.pszVendorSetup;
|
|
INT cParamsLength = 0;
|
|
INT cLength = 0;
|
|
|
|
|
|
if (IsSystemSetupInProgress())
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(pLocalData->Flags & VALID_INF_INFO);
|
|
|
|
cParamsLength = lstrlen(pszVendorSetup) + lstrlen(pszPrinterName) + 4;
|
|
pszParams = LocalAllocMem(cParamsLength * sizeof(TCHAR));
|
|
if (!pszParams)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringCchPrintf(pszParams, cParamsLength, TEXT("%s \"%s\""), pszVendorSetup, pszPrinterName);
|
|
|
|
GetSystemDirectory( szCmd, SIZECHARS(szCmd) );
|
|
cLength = lstrlen( szCmd ) + lstrlen( cszRunDll32 ) + 2;
|
|
pszExecutable = LocalAllocMem( cLength * sizeof(TCHAR) );
|
|
if (!pszExecutable)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
StringCchCopy(pszExecutable, cLength, szCmd);
|
|
|
|
if (*(pszExecutable + (lstrlen( pszExecutable ) - 1)) != TEXT('\\'))
|
|
{
|
|
StringCchCat( pszExecutable, cLength, TEXT("\\"));
|
|
}
|
|
StringCchCat(pszExecutable, cLength, cszRunDll32 );
|
|
|
|
ZeroMemory(&ShellExecInfo, sizeof(ShellExecInfo));
|
|
ShellExecInfo.cbSize = sizeof(ShellExecInfo);
|
|
ShellExecInfo.hwnd = hwnd;
|
|
ShellExecInfo.lpFile = pszExecutable;
|
|
ShellExecInfo.nShow = SW_SHOWNORMAL;
|
|
ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
ShellExecInfo.lpParameters = pszParams;
|
|
|
|
//
|
|
// Call run32dll and wait for the vendor dll to return before proceeding
|
|
//
|
|
if ( ShellExecuteEx(&ShellExecInfo) && ShellExecInfo.hProcess ) {
|
|
|
|
WaitForSingleObject(ShellExecInfo.hProcess, dwFourMinutes );
|
|
CloseHandle(ShellExecInfo.hProcess);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
LocalFreeMem(pszExecutable);
|
|
LocalFreeMem(pszParams);
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetPackageName (
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
{
|
|
SP_WINDOWSUPDATE_PARAMS WinUpParams;
|
|
|
|
//
|
|
// Get current SelectDevice parameters, and then set the fields
|
|
// we wanted changed from default
|
|
//
|
|
WinUpParams.ClassInstallHeader.cbSize = sizeof(WinUpParams.ClassInstallHeader);
|
|
WinUpParams.ClassInstallHeader.InstallFunction = DIF_GETWINDOWSUPDATEINFO;
|
|
if ( !SetupDiGetClassInstallParams( hDevInfo,
|
|
pDevInfoData,
|
|
&WinUpParams.ClassInstallHeader,
|
|
sizeof(WinUpParams),
|
|
NULL) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
StringCchCopy( WinUpParams.PackageId, COUNTOF(WinUpParams.PackageId), cszWebNTPrintPkg );
|
|
WinUpParams.CDMContext = gpCodeDownLoadInfo->hConnection;
|
|
|
|
if ( !SetupDiSetClassInstallParams( hDevInfo,
|
|
pDevInfoData,
|
|
(PSP_CLASSINSTALL_HEADER) &WinUpParams,
|
|
sizeof(WinUpParams) ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
ProcessPerInstanceAddRegSections(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PPSETUP_LOCAL_DATA pLocalData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Processes the AddReg section for this printer that is marked as to process per instance of this
|
|
device
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pLocalData : Pointer to the print setup local data
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn;
|
|
HINF hPrinterInf;
|
|
TCHAR *pszSection = NULL;
|
|
|
|
dwReturn = StrCatAlloc(&pszSection, pLocalData->InfInfo.pszInstallSection, cszProcessAlways, NULL);
|
|
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
hPrinterInf = SetupOpenInfFile(pLocalData->DrvInfo.pszInfName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
|
|
if (hPrinterInf != INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// Ignore return value - it doesn't make much sense to fail the install here
|
|
//
|
|
if (!SetupInstallFromInfSection(NULL,
|
|
hPrinterInf,
|
|
pszSection,
|
|
SPINST_REGISTRY,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
hDevInfo,
|
|
pDevInfoData))
|
|
{
|
|
DBGMSG( DBG_ERROR,("ProcessPerInstanceAddRegSections: SetupInstallFromInfSection failed: %d\n", GetLastError( )));
|
|
}
|
|
|
|
SetupCloseInfFile(hPrinterInf);
|
|
}
|
|
else
|
|
{
|
|
DBGMSG( DBG_ERROR,("ProcessPerInstanceAddRegSections: SetupOpenInfFile %s failed: %d\n", pLocalData->DrvInfo.pszInfName, GetLastError( )));
|
|
}
|
|
|
|
Done:
|
|
FreeSplMem(pszSection);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD
|
|
ClassInstall_SelectDevice(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_SELECTDEVICE
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
|
|
return SetSelectDevParams(hDevInfo, pDevInfoData, FALSE, NULL) &&
|
|
SetDevInstallParams(hDevInfo, pDevInfoData, NULL)
|
|
? ERROR_DI_DO_DEFAULT
|
|
: GetLastError();
|
|
}
|
|
|
|
|
|
DWORD
|
|
ClassInstall_InstallDevice(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_INSTALLDEVICE
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
PPSETUP_LOCAL_DATA pLocalData = NULL;
|
|
TPrinterInstall TPrnInstData;
|
|
TParameterBlock TParm;
|
|
TCHAR szPrinterName[MAX_PRINTER_NAME];
|
|
HANDLE hPrinter = NULL;
|
|
DWORD dwReturn;
|
|
SP_DRVINFO_DATA DrvInfoData = {0};
|
|
|
|
|
|
if ( !pDevInfoData ) {
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// check whether this is the NULL driver - we get that request if we fail DIF_ALLOW_INSTALL.
|
|
// If the DI_FLAGSEX_SETFAILEDINSTALL we must succeed. In this case call the default class installer
|
|
// to do it's thing, then set the REINSTALL flag on the devnode so on first boot
|
|
// they will try to reinstall the device
|
|
//
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
|
|
if (
|
|
!SetupDiGetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData) &&
|
|
(ERROR_NO_DRIVER_SELECTED == GetLastError()) &&
|
|
IsSystemSetupInProgress() &&
|
|
(pDevInstallParams->FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
|
|
)
|
|
{
|
|
DWORD dwConfigFlags = 0, cbRequiredSize =0, dwDataType = REG_DWORD;
|
|
|
|
//
|
|
// run the default class installer
|
|
//
|
|
if (SetupDiInstallDevice(hDevInfo, pDevInfoData))
|
|
{
|
|
//
|
|
// now set the appropriate config flags
|
|
//
|
|
dwReturn = SetupDiGetDeviceRegistryProperty(hDevInfo,
|
|
pDevInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
&dwDataType,
|
|
(PBYTE) &dwConfigFlags,
|
|
sizeof(dwConfigFlags),
|
|
&cbRequiredSize) ?
|
|
(REG_DWORD == dwDataType ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER)
|
|
: GetLastError();
|
|
|
|
if (ERROR_SUCCESS == dwReturn)
|
|
{
|
|
dwConfigFlags |= CONFIGFLAG_REINSTALL; // to make setupapi reinstall this on first boot
|
|
dwConfigFlags &= ~CONFIGFLAG_FAILEDINSTALL; // per LonnyM's request in order not to screw up anything setupapi-internal
|
|
|
|
dwReturn = SetupDiSetDeviceRegistryProperty(hDevInfo,
|
|
pDevInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
(PBYTE) &dwConfigFlags,
|
|
sizeof(dwConfigFlags)) ?
|
|
ERROR_SUCCESS : GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwReturn = GetLastError();
|
|
}
|
|
|
|
//
|
|
// don't go through the normal cleanup path that would munge the error code to
|
|
// DI_DO_DEFAULT - we have already called the default class installer and it would
|
|
// clean out the flags we've set.
|
|
//
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Parse the inf and also get PnP info from config manger registry
|
|
//
|
|
if ( !(pLocalData = BuildInternalData(hDevInfo, pDevInfoData)) ||
|
|
!ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0, FALSE) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Done;
|
|
}
|
|
|
|
if ( dwReturn = ProcessPerInstanceAddRegSections(hDevInfo, pDevInfoData, pLocalData)) {
|
|
goto Done;
|
|
}
|
|
|
|
if ( dwReturn = GetPlugAndPlayInfo(hDevInfo, pDevInfoData, pLocalData) ) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Install printer driver if FORCECOPY is set or if the driver is not
|
|
// available and it is ok to put up ui
|
|
//
|
|
if ( (pDevInstallParams->Flags & DI_FORCECOPY) ||
|
|
DRIVER_MODEL_INSTALLED_AND_IDENTICAL !=
|
|
PSetupIsTheDriverFoundInInfInstalled(NULL,
|
|
pLocalData,
|
|
MyPlatform,
|
|
KERNEL_MODE_DRIVER_VERSION) ) {
|
|
|
|
if ( pDevInstallParams->Flags & DI_NOFILECOPY ) {
|
|
|
|
dwReturn = ERROR_UNKNOWN_PRINTER_DRIVER;
|
|
goto Done;
|
|
}
|
|
|
|
dwReturn = InstallDriverFromCurrentInf(hDevInfo,
|
|
pLocalData,
|
|
pDevInstallParams->hwndParent,
|
|
MyPlatform,
|
|
dwThisMajorVersion,
|
|
NULL,
|
|
pDevInstallParams->FileQueue,
|
|
pDevInstallParams->InstallMsgHandlerContext,
|
|
pDevInstallParams->InstallMsgHandler,
|
|
pDevInstallParams->Flags,
|
|
NULL,
|
|
DRVINST_NO_WARNING_PROMPT,
|
|
APD_COPY_NEW_FILES,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if ( dwReturn != ERROR_SUCCESS )
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If the printer is already installed nothing to do
|
|
//
|
|
if ( DuplicateDevice(pLocalData) ) {
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto Done;
|
|
}
|
|
|
|
if( !NewDriverForInstalledDevice(pLocalData, (LPTSTR)&szPrinterName) ) {
|
|
|
|
if ( !LoadAndInitializePrintui() ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Done;
|
|
}
|
|
|
|
TPrnInstData.cbSize = sizeof(TPrinterInstall);
|
|
TPrnInstData.pszServerName = NULL;
|
|
TPrnInstData.pszDriverName = pLocalData->DrvInfo.pszModelName;
|
|
TPrnInstData.pszPortName = pLocalData->PnPInfo.pszPortName;
|
|
TPrnInstData.pszPrinterNameBuffer = szPrinterName;
|
|
TPrnInstData.pszPrintProcessor = pLocalData->InfInfo.pszPrintProc;
|
|
TPrnInstData.cchPrinterName = SIZECHARS(szPrinterName);
|
|
TParm.pPrinterInstall = &TPrnInstData;
|
|
|
|
if ( dwReturn = dwfnPnPInterface(kPrinterInstall, &TParm) )
|
|
goto Done;
|
|
} else {
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Set the device instance id with spooler
|
|
//
|
|
if ( OpenPrinter(szPrinterName, &hPrinter, &PrinterDefault) ) {
|
|
|
|
(VOID)SetPnPInfoForPrinter(hPrinter,
|
|
pLocalData->PnPInfo.pszDeviceInstanceId,
|
|
pLocalData->DrvInfo.pszHardwareID,
|
|
pLocalData->DrvInfo.pszManufacturer,
|
|
pLocalData->DrvInfo.pszOEMUrl);
|
|
}
|
|
|
|
//
|
|
// If a vendor dll is given we need to call into it
|
|
//
|
|
if ( pLocalData->InfInfo.pszVendorSetup )
|
|
CallVendorDll(pLocalData, szPrinterName, pDevInstallParams->hwndParent);
|
|
|
|
//
|
|
// If ICM files need to installed and associated do it
|
|
//
|
|
if ( pLocalData->InfInfo.pszzICMFiles )
|
|
(VOID)PSetupAssociateICMProfiles(pLocalData->InfInfo.pszzICMFiles,
|
|
szPrinterName);
|
|
|
|
Done:
|
|
if ( hPrinter )
|
|
ClosePrinter(hPrinter);
|
|
|
|
DestroyLocalData(pLocalData);
|
|
|
|
//
|
|
// On everything going smoothly we want setup to whatever it needs to do
|
|
// to make PnP system happy so that the devnode is marked as configured
|
|
// But we do not want them to copy files again
|
|
//
|
|
if ( dwReturn == ERROR_SUCCESS ) {
|
|
|
|
pDevInstallParams->Flags |= DI_NOFILECOPY;
|
|
|
|
SetupDiSetDeviceInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
pDevInstallParams);
|
|
|
|
dwReturn = ERROR_DI_DO_DEFAULT;
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ClassInstall_DestroyWizardData(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_DESTROYWIZARDDATA
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
SP_INSTALLWIZARD_DATA InstallWizData;
|
|
TDestroyWizard TDestroyWsd;
|
|
TParameterBlock TParams;
|
|
DWORD dwReturn;
|
|
|
|
ASSERT(hPrintui && dwfnPnPInterface);
|
|
if(!dwfnPnPInterface)
|
|
{
|
|
return ERROR_DI_DO_DEFAULT;
|
|
}
|
|
|
|
InstallWizData.ClassInstallHeader.cbSize
|
|
= sizeof(InstallWizData.ClassInstallHeader);
|
|
|
|
if ( !SetupDiGetClassInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&InstallWizData.ClassInstallHeader,
|
|
sizeof(InstallWizData),
|
|
NULL) ||
|
|
InstallWizData.ClassInstallHeader.InstallFunction != DIF_DESTROYWIZARDDATA ) {
|
|
|
|
return ERROR_DI_DO_DEFAULT;
|
|
}
|
|
|
|
TDestroyWsd.cbSize = sizeof(TDestroyWsd);
|
|
TDestroyWsd.pszServerName = NULL;
|
|
TDestroyWsd.pData = &InstallWizData;
|
|
TDestroyWsd.pReferenceData = (PVOID)pDevInstallParams->ClassInstallReserved;
|
|
|
|
TParams.pDestroyWizard = &TDestroyWsd;
|
|
|
|
dwReturn = dwfnPnPInterface(kDestroyWizardData, &TParams);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ClassInstall_InstallWizard(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_INSTALLWIZARD
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
|
|
{
|
|
SP_INSTALLWIZARD_DATA InstallWizData;
|
|
TInstallWizard TInstWzd;
|
|
TParameterBlock TParams;
|
|
DWORD dwReturn;
|
|
|
|
InstallWizData.ClassInstallHeader.cbSize
|
|
= sizeof(InstallWizData.ClassInstallHeader);
|
|
|
|
if ( !SetupDiGetClassInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&InstallWizData.ClassInstallHeader,
|
|
sizeof(InstallWizData),
|
|
NULL) ||
|
|
InstallWizData.ClassInstallHeader.InstallFunction != DIF_INSTALLWIZARD ) {
|
|
|
|
return ERROR_DI_DO_DEFAULT;
|
|
}
|
|
|
|
if ( !LoadAndInitializePrintui() )
|
|
return GetLastError();
|
|
|
|
TInstWzd.cbSize = sizeof(TInstWzd);
|
|
TInstWzd.pszServerName = NULL;
|
|
TInstWzd.pData = &InstallWizData;
|
|
TInstWzd.pReferenceData = (PVOID)pDevInstallParams->ClassInstallReserved;
|
|
|
|
TParams.pInstallWizard = &TInstWzd;
|
|
|
|
if ( dwReturn = dwfnPnPInterface(kInstallWizard, &TParams) )
|
|
goto Cleanup;
|
|
|
|
if ( !SetupDiSetClassInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&InstallWizData.ClassInstallHeader,
|
|
sizeof(InstallWizData)) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
}
|
|
|
|
pDevInstallParams->ClassInstallReserved = (LPARAM)TInstWzd.pReferenceData;
|
|
if ( !SetupDiSetDeviceInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
pDevInstallParams) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
}
|
|
|
|
Cleanup:
|
|
if ( dwReturn != ERROR_SUCCESS ) {
|
|
|
|
ClassInstall_DestroyWizardData(hDevInfo,
|
|
pDevInfoData,
|
|
pDevInstallParams);
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ClassInstall_InstallDeviceFiles(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_INSTALLDEVICEFILES
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
PPSETUP_LOCAL_DATA pLocalData;
|
|
DWORD dwReturn;
|
|
|
|
if ( pLocalData = BuildInternalData(hDevInfo, pDevInfoData) )
|
|
{
|
|
dwReturn = InstallDriverFromCurrentInf(hDevInfo,
|
|
pLocalData,
|
|
pDevInstallParams->hwndParent,
|
|
MyPlatform,
|
|
dwThisMajorVersion,
|
|
NULL,
|
|
pDevInstallParams->FileQueue,
|
|
pDevInstallParams->InstallMsgHandlerContext,
|
|
pDevInstallParams->InstallMsgHandler,
|
|
pDevInstallParams->Flags,
|
|
NULL,
|
|
DRVINST_NO_WARNING_PROMPT,
|
|
APD_COPY_NEW_FILES,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
DestroyLocalData(pLocalData);
|
|
}
|
|
else
|
|
{
|
|
dwReturn = GetLastError();
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ClassInstall_RemoveDevice(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for DIF_REMOVEDEVICE
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwRet = ERROR_SUCCESS, dwIndex, dwCount, dwNeeded, dwType;
|
|
HANDLE hPrinter;
|
|
LPPRINTER_INFO_2 pPrinterInfo2, pBuf = NULL;
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
TCHAR szDevId[MAX_DEVICE_ID_LEN], szPrnId[MAX_DEVICE_ID_LEN];
|
|
|
|
if ( !SetupDiGetDeviceInstanceId(hDevInfo,
|
|
pDevInfoData,
|
|
szDevId,
|
|
SIZECHARS(szDevId),
|
|
NULL) ||
|
|
!PrinterInfo2s(&pBuf, &dwCount) )
|
|
return GetLastError();
|
|
|
|
for ( dwIndex = 0, pPrinterInfo2 = pBuf ;
|
|
dwIndex < dwCount ;
|
|
++dwIndex, ++pPrinterInfo2 ) {
|
|
|
|
if ( !OpenPrinter(pPrinterInfo2->pPrinterName,
|
|
&hPrinter,
|
|
&PrinterDefault) )
|
|
continue;
|
|
|
|
if ( ERROR_SUCCESS == GetPrinterDataEx(hPrinter,
|
|
cszPnPKey,
|
|
cszDeviceInstanceId,
|
|
&dwType,
|
|
(LPBYTE)szPrnId,
|
|
sizeof(szPrnId),
|
|
&dwNeeded) &&
|
|
(dwType == REG_SZ) &&
|
|
!lstrcmp(szPrnId, szDevId) ) {
|
|
|
|
dwRet = DeletePrinter(hPrinter) ? ERROR_SUCCESS : GetLastError();
|
|
ClosePrinter(hPrinter);
|
|
goto Done;
|
|
}
|
|
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
|
|
//
|
|
// If we did not find the printer with spooler let setup do whatever they
|
|
// want to. Note even if a printer failed to install they can call us to
|
|
// remove it when Uninstall is selected from DevMan
|
|
//
|
|
dwRet = ERROR_DI_DO_DEFAULT;
|
|
|
|
Done:
|
|
LocalFreeMem(pBuf);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
DWORD
|
|
ClassInstall_SelectBestCompatDrv(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for
|
|
DIF_SELECTBESTCOMPATDRV.
|
|
|
|
We try to handle the broken OEM models which return same PnP id for
|
|
multiple devices. For that we do the following:
|
|
1. If only one compatible driver has been found by setup we got
|
|
nothing to do. We ask setup to do the default since this is a good
|
|
devive.
|
|
2. If multiple drivers are found we do the following:
|
|
2.1 What is the port this printer is attached to
|
|
2.2 Find list of printers installed currently
|
|
2.3 If we have a printer going to the port the PnP printer is
|
|
attached to AND the driver for that printer is one of the
|
|
compatible drivers then we got nothing to do. User has already
|
|
manually installed it.
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
BOOL bFound = FALSE, Rank0IHVMatchFound = FALSE;
|
|
HKEY hKey = NULL;
|
|
DWORD dwReturn = ERROR_DI_DO_DEFAULT, dwRank0Matches;
|
|
DWORD dwSize, dwType, dwIndex1, dwIndex2, dwReturned;
|
|
SP_DRVINFO_DATA DrvInfoData;
|
|
TCHAR szPortName[MAX_PATH];
|
|
LPPRINTER_INFO_2 p = NULL, pPrinterInfo2;
|
|
SP_DRVINSTALL_PARAMS DrvInstData;
|
|
LPTSTR pszModelName = NULL;
|
|
PSP_DRVINFO_DETAIL_DATA pDetailData;
|
|
DWORD dwDetailDataSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
|
|
//
|
|
// Allocate pDetailData on the heap, it's quite chunky
|
|
//
|
|
pDetailData = LocalAllocMem(dwDetailDataSize);
|
|
if ( !pDetailData )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If we do not have more than 1 compatible driver do default
|
|
// Note: API uses 0 based index.
|
|
//
|
|
for ( dwIndex1 = dwRank0Matches = 0 ; ; ++dwIndex1 ) {
|
|
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
if ( !SetupDiEnumDriverInfo(hDevInfo, pDevInfoData, SPDIT_COMPATDRIVER,
|
|
dwIndex1, &DrvInfoData) )
|
|
break;
|
|
|
|
DrvInstData.cbSize = sizeof(DrvInstData);
|
|
if ( SetupDiGetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData))
|
|
{
|
|
if (DrvInstData.Rank < 0x1000 )
|
|
{
|
|
if (!pszModelName)
|
|
{
|
|
pszModelName = AllocStr( DrvInfoData.Description );
|
|
if(!pszModelName)
|
|
{
|
|
goto Done;
|
|
}
|
|
++dwRank0Matches;
|
|
}
|
|
else if ( lstrcmpi( pszModelName, DrvInfoData.Description ) )
|
|
{
|
|
++dwRank0Matches;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for whether this match is in ntprint.inf. If so, set flag to prefer other drivers
|
|
//
|
|
ZeroMemory(pDetailData, dwDetailDataSize);
|
|
pDetailData->cbSize = dwDetailDataSize;
|
|
|
|
//
|
|
// check whether it's ntprint.inf
|
|
// function may return insufficient buffer if it couldn't stuff all the
|
|
// hardware IDs at the end of the structure.
|
|
//
|
|
if ((SetupDiGetDriverInfoDetail(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
pDetailData,
|
|
dwDetailDataSize,
|
|
NULL)) ||
|
|
(ERROR_INSUFFICIENT_BUFFER == GetLastError()))
|
|
{
|
|
SetLastError(ERROR_SUCCESS);
|
|
if (IsSystemNTPrintInf( pDetailData->InfFileName ) )
|
|
{
|
|
DrvInstData.Flags |= DNF_BASIC_DRIVER;
|
|
SetupDiSetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData);
|
|
|
|
}
|
|
else if (DrvInstData.Rank < 0x1000 )
|
|
{
|
|
Rank0IHVMatchFound = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the memory if allocated
|
|
//
|
|
LocalFreeMem( pszModelName );
|
|
pszModelName = NULL;
|
|
LocalFreeMem( pDetailData );
|
|
pDetailData = NULL;
|
|
|
|
if ( dwRank0Matches <= 1 )
|
|
goto Done;
|
|
|
|
//
|
|
// Look in the devnode of the printer for the port name
|
|
//
|
|
dwSize = sizeof(szPortName);
|
|
if ( ERROR_SUCCESS != CM_Open_DevNode_Key(pDevInfoData->DevInst, KEY_READ,
|
|
0, RegDisposition_OpenExisting,
|
|
&hKey, CM_REGISTRY_HARDWARE) ||
|
|
ERROR_SUCCESS != RegQueryValueEx(hKey, cszPortName, NULL, &dwType,
|
|
(LPBYTE)&szPortName, &dwSize) )
|
|
goto Done;
|
|
|
|
szPortName[COUNTOF(szPortName)-1] = TEXT('\0');
|
|
|
|
if ( !PrinterInfo2s(&p, &dwReturned) )
|
|
goto Done;
|
|
|
|
|
|
//
|
|
// If there is a local printer using a driver with rank-0 match and
|
|
// going to the same port then it is a duplicate
|
|
//
|
|
for ( dwIndex1 = 0, pPrinterInfo2 = p ;
|
|
dwIndex1 < dwReturned ;
|
|
++dwIndex1, pPrinterInfo2++ ) {
|
|
|
|
if ( !PrinterGoingToPort(pPrinterInfo2, szPortName) )
|
|
continue;
|
|
|
|
dwIndex2 = 0;
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
while ( SetupDiEnumDriverInfo(hDevInfo, pDevInfoData,
|
|
SPDIT_COMPATDRIVER, dwIndex2,
|
|
&DrvInfoData) ) {
|
|
|
|
DrvInstData.cbSize = sizeof(DrvInstData);
|
|
if ( SetupDiGetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData) &&
|
|
DrvInstData.Rank < 0x1000 &&
|
|
!lstrcmpi(DrvInfoData.Description,
|
|
pPrinterInfo2->pDriverName) ) {
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
++dwIndex2;
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
}
|
|
|
|
if ( bFound )
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we found a manually installed printer which matches one of the
|
|
// compatible drivers that is what we want to install
|
|
//
|
|
if ( bFound ) {
|
|
|
|
//
|
|
// This means newdev will choose this as the driver to install
|
|
//
|
|
if ( SetupDiSetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData) )
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
else if (!Rank0IHVMatchFound)
|
|
{
|
|
//
|
|
// We did not find a printer. So bump up the rank of all drivers
|
|
// to force newdev to ask the user to select a driver
|
|
//
|
|
dwIndex2 = 0;
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
while ( SetupDiEnumDriverInfo(hDevInfo, pDevInfoData,
|
|
SPDIT_COMPATDRIVER, dwIndex2,
|
|
&DrvInfoData) ) {
|
|
|
|
DrvInstData.cbSize = sizeof(DrvInstData);
|
|
if ( SetupDiGetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData) &&
|
|
DrvInstData.Rank < 0x1000 ) {
|
|
|
|
DrvInstData.Rank += 0x1000;
|
|
SetupDiSetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData);
|
|
}
|
|
|
|
++dwIndex2;
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
|
|
}
|
|
}
|
|
|
|
Done:
|
|
LocalFreeMem(p);
|
|
|
|
if ( hKey )
|
|
RegCloseKey(hKey);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD
|
|
StoreDriverTypeInDevnode(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDevInfoData)
|
|
{
|
|
SP_DRVINFO_DATA DrvInfoData = {0};
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
|
|
DrvInfoData.cbSize = sizeof(DrvInfoData);
|
|
|
|
if (SetupDiGetSelectedDriver(hDevInfo, pDevInfoData, &DrvInfoData))
|
|
{
|
|
SP_DRVINSTALL_PARAMS DrvInstData = {0};
|
|
|
|
DrvInstData.cbSize = sizeof(DrvInstData);
|
|
|
|
if ( SetupDiGetDriverInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DrvInfoData,
|
|
&DrvInstData))
|
|
{
|
|
HKEY hKey;
|
|
DWORD InstallInboxDriver;
|
|
|
|
InstallInboxDriver = (DrvInstData.Flags & DNF_BASIC_DRIVER) ? 1 : 0;
|
|
|
|
hKey = SetupDiOpenDevRegKey(hDevInfo, pDevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_WRITE);
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
dwRet = RegSetValueEx(hKey, cszBestDriverInbox, 0, REG_DWORD, (LPBYTE) &InstallInboxDriver, sizeof(InstallInboxDriver));
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
{
|
|
dwRet = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = GetLastError();
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ClassInstall_AllowInstall(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData,
|
|
IN PSP_DEVINSTALL_PARAMS pDevInstallParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function handles the class installer entry point for
|
|
DIF_ALLOW_INSTALL.
|
|
|
|
Do not allow PnP installs during GUI setup portion of system upgrade
|
|
Do not allow install of INFs using VendorSetup if QUIETINSTALL bit is set
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
pDevInstallParam : Pointer to the device install structure
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwReturn = ERROR_DI_DO_DEFAULT;
|
|
PPSETUP_LOCAL_DATA pLocalData;
|
|
|
|
if ( pDevInstallParams->Flags & DI_QUIETINSTALL ) {
|
|
|
|
//
|
|
// During system setup no PnP install of printers because there ain't no spooler
|
|
// check that the spooler is running - failing this will punt to client-side installation
|
|
// which should happen at a point in time where the spooler actually is running - we don't
|
|
// want to stall system startup until the spooler is up (think USB mouse...)
|
|
//
|
|
if (IsSystemSetupInProgress() ||
|
|
!IsSpoolerRunning()) {
|
|
//
|
|
// store the type (inbox or not) in the devnode. This fails if this is a clean install
|
|
// but it doesn't matter because we only need it for drivers that have been installed
|
|
// before upgrade.
|
|
// We use it to determine later on whether to clear the CONFIGFLAG_REINSTALL
|
|
// or not. We don't want to clear it if the best driver is inbox so we'll install it
|
|
// on first boot.
|
|
//
|
|
StoreDriverTypeInDevnode(hDevInfo, pDevInfoData);
|
|
|
|
dwReturn = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
|
|
goto Done;
|
|
}
|
|
|
|
if ( (pLocalData = BuildInternalData(hDevInfo, pDevInfoData)) &&
|
|
ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0, FALSE) ) {
|
|
|
|
if ( pLocalData->InfInfo.pszVendorSetup &&
|
|
*pLocalData->InfInfo.pszVendorSetup )
|
|
dwReturn = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
|
|
} else {
|
|
|
|
if ( (dwReturn = GetLastError()) == ERROR_SUCCESS )
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
|
|
Done:
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ClassInstall32(
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO hDevInfo,
|
|
IN PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the printer class installer entry point for SetupDiCallClassInstaller calls
|
|
|
|
Arguments:
|
|
InstallFunction : The function being called
|
|
hDevInfo : Handle to the printer class device information list
|
|
pDevInfoData : Pointer to the device info element for the printer
|
|
|
|
Return Value:
|
|
Win 32 error code
|
|
|
|
--*/
|
|
{
|
|
SP_DEVINSTALL_PARAMS DevInstallParams;
|
|
DWORD dwReturn = ERROR_DI_DO_DEFAULT;
|
|
|
|
DevInstallParams.cbSize = sizeof(DevInstallParams);
|
|
if ( !SetupDiGetDeviceInstallParams(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams) ) {
|
|
|
|
dwReturn = GetLastError();
|
|
goto Done;
|
|
}
|
|
|
|
switch (InstallFunction) {
|
|
|
|
case DIF_SELECTDEVICE:
|
|
dwReturn = ClassInstall_SelectDevice(hDevInfo, pDevInfoData);
|
|
break;
|
|
|
|
case DIF_INSTALLDEVICE:
|
|
dwReturn = ClassInstall_InstallDevice(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_INSTALLWIZARD:
|
|
dwReturn = ClassInstall_InstallWizard(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_DESTROYWIZARDDATA:
|
|
dwReturn = ClassInstall_DestroyWizardData(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_INSTALLDEVICEFILES:
|
|
dwReturn = ClassInstall_InstallDeviceFiles(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_REMOVE:
|
|
dwReturn = ClassInstall_RemoveDevice(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_GETWINDOWSUPDATEINFO:
|
|
|
|
|
|
if ( !InitCodedownload(HWND_DESKTOP) )
|
|
dwReturn = GetLastError();
|
|
else
|
|
{
|
|
if ( SetPackageName(hDevInfo, pDevInfoData) )
|
|
dwReturn = NO_ERROR;
|
|
else
|
|
dwReturn = GetLastError();
|
|
}
|
|
break;
|
|
case DIF_SELECTBESTCOMPATDRV:
|
|
dwReturn = ClassInstall_SelectBestCompatDrv(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_ALLOW_INSTALL:
|
|
dwReturn = ClassInstall_AllowInstall(hDevInfo,
|
|
pDevInfoData,
|
|
&DevInstallParams);
|
|
break;
|
|
|
|
case DIF_DESTROYPRIVATEDATA:
|
|
case DIF_MOVEDEVICE:
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Done:
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PSetupProcessPrinterAdded(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN LPCTSTR pszPrinterName,
|
|
IN HWND hwnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Called by Add Printer Wizard after driver has been installed.
|
|
Sets registry values in the PnPInfo subkey. If a vendor dll is given it
|
|
is called and it also installs ICM color profiles for a printer driver
|
|
and associates it with the printer name given.
|
|
|
|
Arguments:
|
|
hDevInfo : Handle to the printer class device information list
|
|
pLocalData : Has all the driver information and name of vendor DLL.
|
|
pszPrinterName : Name of printer.
|
|
hwnd : Window Handle
|
|
|
|
Return Value:
|
|
TRUE on success
|
|
FALSE else
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_DEFAULTS PrinterDefault = {NULL, NULL, PRINTER_ALL_ACCESS};
|
|
|
|
bRet = OpenPrinter((LPTSTR)pszPrinterName, &hPrinter, &PrinterDefault) &&
|
|
SetPnPInfoForPrinter(hPrinter,
|
|
pLocalData->PnPInfo.pszDeviceInstanceId,
|
|
pLocalData->DrvInfo.pszHardwareID,
|
|
pLocalData->DrvInfo.pszManufacturer,
|
|
pLocalData->DrvInfo.pszOEMUrl);
|
|
|
|
//
|
|
// If a vendor dll is given we need to call into it
|
|
//
|
|
if ( pLocalData->InfInfo.pszVendorSetup )
|
|
CallVendorDll(pLocalData, pszPrinterName, hwnd);
|
|
|
|
if ( pLocalData->InfInfo.pszzICMFiles )
|
|
(VOID)PSetupAssociateICMProfiles(pLocalData->InfInfo.pszzICMFiles,
|
|
pszPrinterName);
|
|
|
|
if ( hPrinter )
|
|
ClosePrinter(hPrinter);
|
|
|
|
return bRet;
|
|
}
|