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

3849 lines
118 KiB
C

/*++
Copyright (c) 1995-97 Microsoft Corporation
All rights reserved.
Module Name:
Install.c
Abstract:
File queue functions
Author:
Muhunthan Sivapragasam (MuhuntS) 18-Nov-96
Revision History:
--*/
#include "precomp.h"
#include <winsprlp.h>
const TCHAR szWebDirPrefix[] = TEXT("\\web\\printers\\");
const TCHAR szNtPrintInf[] = TEXT("inf\\ntprint.inf");
//
// File queue flags, and structure
//
#define CALLBACK_MEDIA_CHECKED 0x01
#define CALLBACK_SOURCE_SET 0x02
#define CALLBACK_PATH_MODIFIED 0x04
typedef struct _FILE_QUEUE_CONTEXT {
HWND hwnd;
PVOID QueueContext;
LPCTSTR pszSource;
BOOL dwCallbackFlags;
DWORD dwInstallFlags;
LPCTSTR pszFileSrcPath;
TCHAR szInfPath[MAX_PATH];
PLATFORM platform;
DWORD dwVersion;
} FILE_QUEUE_CONTEXT, *PFILE_QUEUE_CONTEXT;
/*
BOOL
SystemCab(
LPCTSTR pszPath
)
{
BOOL bRet = FALSE;
HKEY hKey;
DWORD dwSize, dwType;
TCHAR szCabLocation[MAX_PATH],
szReg[] = TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szReg,
0,
KEY_READ,
&hKey ) ) {
dwSize = sizeof(szCabLocation);
if ( ERROR_SUCCESS == RegQueryValueEx(hKey,
TEXT("DriverCachePath"),
NULL,
&dwType,
(LPBYTE)szCabLocation,
&dwSize) &&
dwType == REG_EXPAND_SZ ) {
bRet = lstrncmpi(szCabLocation, pszPath, lstrlen(pszPath)) == 0;
}
RegCloseKey(hKey);
}
return bRet;
}
*/
BOOL
FileExistsOnMedia(
PSOURCE_MEDIA pSourceMedia
)
{
BOOL bRes = FALSE;
TCHAR *pszFile = NULL;
INT cbLength = 0;
INT cbAdditionalSymbolsLen = 0;
DWORD dwLen1 = 0;
DWORD dwLen2 = 0;
LPTSTR p = NULL;
LPTSTR q = NULL;
if ( !pSourceMedia->SourcePath || !*pSourceMedia->SourcePath ||
!pSourceMedia->SourceFile || !*pSourceMedia->SourceFile )
{
goto Cleanup;
}
cbAdditionalSymbolsLen = lstrlen(TEXT("\\")) + lstrlen(TEXT("_")) + 1;
cbLength = lstrlen(pSourceMedia->SourcePath) + lstrlen(pSourceMedia->SourceFile) +
cbAdditionalSymbolsLen;
if (cbLength == cbAdditionalSymbolsLen)
{
goto Cleanup;
}
//
// First check if file is there on source path
//
pszFile = LocalAllocMem(cbLength * sizeof(TCHAR));
if (!pszFile)
{
goto Cleanup;
}
lstrcpy(pszFile, pSourceMedia->SourcePath);
dwLen1 = lstrlen(pszFile);
if ( *(pszFile + (dwLen1-1)) != TEXT('\\') )
{
*(pszFile + dwLen1) = TEXT('\\');
++dwLen1;
}
lstrcpy(pszFile + dwLen1, pSourceMedia->SourceFile);
dwLen2 = dwLen1 + lstrlen(pSourceMedia->SourceFile);
bRes = FileExists(pszFile);
if (bRes)
{
goto Cleanup;
}
p = lstrchr(pszFile, TEXT('.'));
q = lstrchr(pszFile, TEXT('\\'));
//
// A dot present in filename?
//
if ( q < p )
{
//
// For files with 0, 1, 2 characters after the dot append underscore
//
if ( lstrlen(p) < 4 )
{
*(pszFile + dwLen2) = TEXT('_');
++dwLen2;
*(pszFile + dwLen2) = TEXT('\0');
}
else
{
//
// If 3+ characters after dot then replace last character with _
// to get the compressed file name
//
*(pszFile + (dwLen2-1)) = TEXT('_');
}
}
else
{
//
// If no dot then replace last character with _ for compressed name
//
*(pszFile + (dwLen2-1)) = TEXT('_');
}
//
// Does the compressed file exist on source path?
//
bRes = FileExists(pszFile);
if (bRes)
{
goto Cleanup;
}
//
// Check for the file in compressed form with $ as the character
//
*(pszFile + (dwLen2-1)) = TEXT('$');
bRes = FileExists(pszFile);
if (bRes)
{
goto Cleanup;
}
if ( !pSourceMedia->Tagfile || !*pSourceMedia->Tagfile )
{
goto Cleanup;
}
//
// Look for tag file
//
lstrcpy(pszFile + dwLen1, pSourceMedia->Tagfile);
bRes = FileExists(pszFile);
Cleanup:
LocalFreeMem(pszFile);
return bRes;
}
UINT
MyQueueCallback(
IN PVOID QueueContext,
IN UINT Notification,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
{
PFILE_QUEUE_CONTEXT pFileQContext=(PFILE_QUEUE_CONTEXT)QueueContext;
PSOURCE_MEDIA pSourceMedia;
LPTSTR pszPathOut;
PFILEPATHS pFilePaths;
switch (Notification) {
case SPFILENOTIFY_NEEDMEDIA:
pSourceMedia = (PSOURCE_MEDIA)Param1;
pszPathOut = (LPTSTR)Param2;
//
// If pszSource is specified then we have a flat share where
// all the files are available. Setup is looking for the file
// in the sub-directory (ex. ..\i386) based on the layout info.
// We need to tell setup to look in the root directory
//
if ( !(pFileQContext->dwCallbackFlags & CALLBACK_SOURCE_SET) &&
pFileQContext->pszSource &&
lstrcmpi(pFileQContext->pszSource,
pSourceMedia->SourcePath) ) {
lstrcpy(pszPathOut, pFileQContext->pszSource);
pFileQContext->dwCallbackFlags |= CALLBACK_SOURCE_SET;
return FILEOP_NEWPATH;
}
/*
} else if ( (pFileQContext->dwInstallFlags & DRVINST_CABONLY) &&
!SystemCab(pSourceMedia->SourcePath) ) {
return FILEOP_ABORT;
}
if ( pFileQContext->dwInstallFlags & DRVINST_WEBPNP ) {
if ( !pFileQContext->bMediaChecked ) {
pFileQContext->bMediaChecked = TRUE;
return FILEOP_DOIT;
} else
return FILEOP_ABORT;
}
*/
//
// If DRVINST_PROMPTLESS is set then we can't allow prompt
//
if ( pFileQContext->dwInstallFlags & DRVINST_PROMPTLESS ) {
if ( !(pFileQContext->dwCallbackFlags & CALLBACK_MEDIA_CHECKED) ) {
pFileQContext->dwCallbackFlags |= CALLBACK_MEDIA_CHECKED;
if ( FileExistsOnMedia(pSourceMedia) )
return FILEOP_DOIT;
}
return FILEOP_ABORT;
}
//
// If we do a non-native platform install and the user points
// to a server CD, the inf will specify a subdir \i386 which is
// correct on an installed machine but not on a CD. Remove that dir
// and try again.
//
if ( (pFileQContext->dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) &&
!(pFileQContext->dwCallbackFlags & CALLBACK_PATH_MODIFIED))
{
LPSTR pCur;
size_t Pos, Len, OverrideLen;
//
// for NT4 installations we have possibly expanded the INF
// from a server CD. Point there if that's the case
//
if ((pFileQContext->dwVersion == 2) &&
(pFileQContext->pszFileSrcPath))
{
Len = _tcslen(pFileQContext->szInfPath);
if (_tcsnicmp(pSourceMedia->SourcePath,
pFileQContext->szInfPath, Len) == 0)
{
_tcscpy(pszPathOut, pFileQContext->pszFileSrcPath);
pFileQContext->dwCallbackFlags |= CALLBACK_PATH_MODIFIED;
return FILEOP_NEWPATH;
}
}
//
// Find the spot where the platform ID begins
//
Pos = Len = _tcslen(pFileQContext->szInfPath);
//
// sanity check
//
if (_tcslen(pSourceMedia->SourcePath) <= Len)
goto Default;
if (pSourceMedia->SourcePath[Len] == _T('\\'))
{
Pos++;
}
OverrideLen = _tcslen(PlatformOverride[pFileQContext->platform].pszName);
if (_tcsnicmp(pSourceMedia->SourcePath,
pFileQContext->szInfPath, Len) == 0 &&
_tcsnicmp(&(pSourceMedia->SourcePath[Pos]),
PlatformOverride[pFileQContext->platform].pszName,
OverrideLen) == 0)
{
_tcscpy(pszPathOut, pFileQContext->szInfPath);
pFileQContext->dwCallbackFlags |= CALLBACK_PATH_MODIFIED;
return FILEOP_NEWPATH;
}
}
goto Default;
case SPFILENOTIFY_STARTCOPY:
pFilePaths = (PFILEPATHS)Param1;
if ( gpszSkipDir &&
!lstrncmpi(gpszSkipDir, pFilePaths->Target, lstrlen(gpszSkipDir)) )
return FILEOP_SKIP;
goto Default;
case SPFILENOTIFY_ENDCOPY:
// Here we set the bMediaChecked flag to FALSE, this is because some OEM drivers
// have more than one media, so we assume NEEDMEDIA,STARTCOPY,ENDCOPY,NEEDMEDIA
// So if we reset the NEEDMEDIA flag after the ENDCOPY, we are OK
//
// Clear the per file flags
//
pFileQContext->dwCallbackFlags &= ~(CALLBACK_MEDIA_CHECKED |
CALLBACK_SOURCE_SET |
CALLBACK_PATH_MODIFIED);
goto Default;
case SPFILENOTIFY_COPYERROR:
pFilePaths = (PFILEPATHS)Param1;
// If there is a copy error happens in webpnp, we force it retry
// the orginal flat directory
if ( pFileQContext->dwInstallFlags & DRVINST_WEBPNP) {
pszPathOut = (LPTSTR)Param2;
// We need to make sure the path used in the copy operation is not as same as we're going
// to replace, otherwise, it will go to indefinite loop.
//
if (lstrncmpi(pFileQContext->pszSource, pFilePaths->Source, lstrlen(pFileQContext->pszSource)) ||
lstrchr (pFilePaths->Source + lstrlen(pFileQContext->pszSource) + 1, TEXT ('\\'))) {
lstrcpy(pszPathOut, pFileQContext->pszSource);
return FILEOP_NEWPATH;
}
}
goto Default;
}
Default:
return SetupDefaultQueueCallback(pFileQContext->QueueContext,
Notification,
Param1,
Param2);
}
VOID
CheckAndEnqueueOneFile(
IN LPCTSTR pszFileName,
IN LPCTSTR pszzDependentFiles, OPTIONAL
IN HSPFILEQ CopyQueue,
IN LPCTSTR pszSourcePath,
IN LPCTSTR pszTargetPath,
IN LPCTSTR pszDiskName, OPTIONAL
IN OUT LPBOOL lpFail
)
/*++
Routine Description:
Ensure that a file is enqueue only once for copying. To do so we check
if the given file name also appears in the list of dependent files and
enqueue it only if it does not.
Arguments:
pszFileName : File name to be checked and enqueued
pszzDependentFiles : Dependent files (multi-sz) list
pszSourcePath : Source directory to look for the files
pszTargetPath : Target directory to copy the files to
pszDiskName : Title of the disk where files are
lpBool : Will be set to TRUE on error
Return Value:
Nothing
--*/
{
LPCTSTR psz;
if ( *lpFail )
return;
//
// If the file also appears as a dependent file do not enqueue it
//
if ( pszzDependentFiles ) {
for ( psz = pszzDependentFiles ; *psz ; psz += lstrlen(psz) + 1 )
if ( !lstrcmpi(pszFileName, psz) )
return;
}
*lpFail = !SetupQueueCopy(
CopyQueue,
pszSourcePath,
NULL, // Path relative to source
pszFileName,
pszDiskName,
NULL, // Source Tag file
pszTargetPath,
NULL, // Target file name
0); // Copy style flags
}
BOOL
CopyPrinterDriverFiles(
IN LPDRIVER_INFO_6 pDriverInfo6,
IN LPCTSTR pszInfName,
IN LPCTSTR pszSourcePath,
IN LPCTSTR pszDiskName,
IN LPCTSTR pszTargetPath,
IN HWND hwnd,
IN DWORD dwInstallFlags,
IN BOOL bForgetSource
)
/*++
Routine Description:
Copy printer driver files to a specified directory using SetupQueue APIs
Arguments:
pDriverInfo6 : Points to a valid SELECTED_DRV_INFO
szTargetPath : Target directory to copy to
szSourcePath : Source directory to look for the files, if none is
specified will use the one from prev. operation
pszDiskName : Title of the disk where files are
hwnd : Windows handle of current top-level window
bForgetSource : TRUE if the path where driver files were copied from
should not be remembered for future use
Return Value:
TRUE on succes
FALSE else, use GetLastError() to get the error code
--*/
{
HSPFILEQ CopyQueue;
BOOL bFail = FALSE;
DWORD dwOldCount, dwNewCount, dwIndex;
LPTSTR psz, *List = NULL;
FILE_QUEUE_CONTEXT FileQContext;
//
// Valid DriverInfo6
//
if ( !pDriverInfo6 ||
!pDriverInfo6->pDriverPath ||
!pDriverInfo6->pDataFile ||
!pDriverInfo6->pConfigFile )
return FALSE;
//
// If no additions should be made to the source list findout the count
//
if ( bForgetSource ) {
dwOldCount = 0;
if ( !SetupQuerySourceList(SRCLIST_USER | SRCLIST_SYSTEM,
&List, &dwOldCount) ) {
return FALSE;
}
SetupFreeSourceList(&List, dwOldCount);
}
//
// Create a setup file copy queue and initialize setup queue callback
//
ZeroMemory(&FileQContext, sizeof(FileQContext));
FileQContext.hwnd = hwnd;
FileQContext.pszSource = NULL;
FileQContext.dwInstallFlags = dwInstallFlags;
if ( dwInstallFlags & DRVINST_PROGRESSLESS ) {
FileQContext.QueueContext = SetupInitDefaultQueueCallbackEx(
hwnd,
INVALID_HANDLE_VALUE,
0,
0,
NULL);
} else {
FileQContext.QueueContext = SetupInitDefaultQueueCallback(hwnd);
}
CopyQueue = SetupOpenFileQueue();
if ( CopyQueue == INVALID_HANDLE_VALUE || !FileQContext.QueueContext )
goto Cleanup;
CheckAndEnqueueOneFile(pDriverInfo6->pDriverPath,
pDriverInfo6->pDependentFiles,
CopyQueue,
pszSourcePath,
pszTargetPath,
pszDiskName,
&bFail);
CheckAndEnqueueOneFile(pDriverInfo6->pDataFile,
pDriverInfo6->pDependentFiles,
CopyQueue,
pszSourcePath,
pszTargetPath,
pszDiskName,
&bFail);
CheckAndEnqueueOneFile(pDriverInfo6->pConfigFile,
pDriverInfo6->pDependentFiles,
CopyQueue,
pszSourcePath,
pszTargetPath,
pszDiskName,
&bFail);
if ( pDriverInfo6->pHelpFile && *pDriverInfo6->pHelpFile )
CheckAndEnqueueOneFile(pDriverInfo6->pHelpFile,
pDriverInfo6->pDependentFiles,
CopyQueue,
pszSourcePath,
pszTargetPath,
pszDiskName,
&bFail);
//
// Add each file in the dependent files field to the setup queue
//
if ( pDriverInfo6->pDependentFiles ) {
for ( psz = pDriverInfo6->pDependentFiles ;
*psz ;
psz += lstrlen(psz) + 1 )
CheckAndEnqueueOneFile(psz,
NULL,
CopyQueue,
pszSourcePath,
pszTargetPath,
pszDiskName,
&bFail);
}
if ( bFail )
goto Cleanup;
{
// Before adding files to the File Queue set the correct Platform/Version
// info for Driver Signing
// Setup the structure for SETUPAPI
SP_ALTPLATFORM_INFO AltPlat_Info;
HINF hInf;
TCHAR CatalogName[ MAX_PATH ];
LPTSTR pszCatalogFile = NULL;
AltPlat_Info.cbSize = sizeof(SP_ALTPLATFORM_INFO);
AltPlat_Info.Platform = VER_PLATFORM_WIN32_WINDOWS;
AltPlat_Info.MajorVersion = 4;
AltPlat_Info.MinorVersion = 0;
AltPlat_Info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
AltPlat_Info.Reserved = 0;
AltPlat_Info.FirstValidatedMajorVersion = AltPlat_Info.MajorVersion;
AltPlat_Info.FirstValidatedMinorVersion = AltPlat_Info.MinorVersion;
if ( CheckForCatalogFileInInf(pszInfName, &pszCatalogFile) && pszCatalogFile )
{
if ( (lstrlen(pszSourcePath)+lstrlen(pszCatalogFile)+2) < MAX_PATH )
{
lstrcpy( CatalogName, pszSourcePath );
lstrcat( CatalogName, TEXT("\\") );
lstrcat( CatalogName, pszCatalogFile );
}
else
{
bFail = TRUE;
}
LocalFreeMem( pszCatalogFile );
pszCatalogFile = CatalogName;
}
if (bFail)
goto Cleanup;
// Now call the Setup API to change the parms on the FileQueue
bFail = !SetupSetFileQueueAlternatePlatform( CopyQueue, &AltPlat_Info, pszCatalogFile );
}
if ( bFail )
goto Cleanup;
bFail = !SetupCommitFileQueue(hwnd,
CopyQueue,
MyQueueCallback,
&FileQContext);
//
// If bForegetSource is set fix source list
//
if ( bForgetSource &&
SetupQuerySourceList(SRCLIST_USER | SRCLIST_SYSTEM,
&List, &dwNewCount) ) {
dwOldCount = dwNewCount - dwOldCount;
if ( dwOldCount < dwNewCount )
for ( dwIndex = 0 ; dwIndex < dwOldCount ; ++dwIndex ) {
SetupRemoveFromSourceList(SRCLIST_SYSIFADMIN,
List[dwIndex]);
}
SetupFreeSourceList(&List, dwNewCount);
}
Cleanup:
if ( CopyQueue != INVALID_HANDLE_VALUE )
SetupCloseFileQueue(CopyQueue);
if ( FileQContext.QueueContext )
SetupTermDefaultQueueCallback(FileQContext.QueueContext);
return !bFail;
}
BOOL
AddPrinterDriverUsingCorrectLevel(
IN LPCTSTR pszServerName,
IN LPDRIVER_INFO_6 pDriverInfo6,
IN DWORD dwAddDrvFlags
)
{
BOOL bReturn;
DWORD dwLevel;
bReturn = AddPrinterDriverEx((LPTSTR)pszServerName,
6,
(LPBYTE)pDriverInfo6,
dwAddDrvFlags );
for ( dwLevel = 4 ;
!bReturn && GetLastError() == ERROR_INVALID_LEVEL && dwLevel > 1 ;
--dwLevel ) {
//
// Since DRIVER_INFO_2, 3, 4 are subsets of DRIVER_INFO_6 and all fields
// are at the beginning these calls can be made with same buffer
//
bReturn = AddPrinterDriverEx((LPTSTR)pszServerName,
dwLevel,
(LPBYTE)pDriverInfo6,
dwAddDrvFlags);
}
return bReturn;
}
typedef struct _MONITOR_SCAN_INFO {
LPTSTR pszMonitorDll;
LPTSTR pszTargetDir;
BOOL bFound;
} MONITOR_SCAN_INFO, *PMONITOR_SCAN_INFO;
UINT
MonitorCheckCallback(
IN PVOID pContext,
IN UINT Notification,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
/*++
Routine Description:
This callback routine is to check language monitor dll is getting copied
to system32 directory.
Arguments:
pContext : Gives the MONITOR_SCAN_INFO structure
Notification : Ignored
Param1 : Gives the target file name
Param2 : Ignored
Return Value:
Win32 error code
--*/
{
size_t dwLen;
LPTSTR pszTarget = (LPTSTR)Param1, pszFileName;
PMONITOR_SCAN_INFO pScanInfo = (PMONITOR_SCAN_INFO)pContext;
if ( !pScanInfo->bFound ) {
if ( !(pszFileName = FileNamePart(pszTarget)) )
return ERROR_INVALID_PARAMETER;
if ( !lstrcmpi(pScanInfo->pszMonitorDll, pszFileName) ) {
//
// Length excludes \ (i.e. D:\winnt\system32)
//
dwLen = (size_t)(pszFileName - pszTarget - 1);
if ( !lstrncmpi(pScanInfo->pszTargetDir, pszTarget, dwLen) &&
dwLen == (DWORD) lstrlen(pScanInfo->pszTargetDir) )
pScanInfo->bFound = TRUE;
}
}
return NO_ERROR;
}
BOOL
CheckAndEnqueueMonitorDll(
IN LPCTSTR pszMonitorDll,
IN LPCTSTR pszSource,
IN HSPFILEQ CopyQueue,
IN HINF hInf
)
/*++
Routine Description:
This routine is to check language monitor dll is getting copied to system32
directory. On NT 4.0 we did not list LM as a file to be copied. ntprint.dll
automatically did it. Now we use a DRID for it. But for backward
compatibility this routine is there to get NT 4.0 INFs to work.
Arguments:
pszMonitorDll : Monitor dll to enqueue
pszSource : Source directory to look for files
CopyQueue : File queue
hInf : Printer driver INF file handle
Return Value:
TRUE on success, FALSE else
--*/
{
BOOL bRet = FALSE;
DWORD dwNeeded;
LPTSTR pszPathOnSource = NULL, pszDescription = NULL,
pszTagFile = NULL;
TCHAR szDir[MAX_PATH];
MONITOR_SCAN_INFO ScanInfo;
SP_FILE_COPY_PARAMS FileCopyParams = {0};
if ( !GetSystemDirectory(szDir, SIZECHARS(szDir)) )
goto Cleanup;
ScanInfo.pszMonitorDll = (LPTSTR)pszMonitorDll;
ScanInfo.pszTargetDir = szDir;
ScanInfo.bFound = FALSE;
if ( !SetupScanFileQueue(CopyQueue,
SPQ_SCAN_USE_CALLBACK,
0,
MonitorCheckCallback,
&ScanInfo,
&dwNeeded) )
goto Cleanup;
if ( !ScanInfo.bFound ) {
pszPathOnSource = (LPTSTR) LocalAllocMem(MAX_PATH * sizeof(TCHAR));
if ( !pszPathOnSource )
goto Cleanup;
//
// This gives which subdirectory to look for. By default in same dir
//
if ( !FindPathOnSource(pszMonitorDll, hInf,
pszPathOnSource, MAX_PATH,
&pszDescription, &pszTagFile) ) {
LocalFreeMem(pszPathOnSource);
pszPathOnSource = NULL;
}
FileCopyParams.cbSize = sizeof( SP_FILE_COPY_PARAMS );
FileCopyParams.QueueHandle = CopyQueue;
FileCopyParams.SourceRootPath = pszSource;
FileCopyParams.SourcePath = pszPathOnSource;
FileCopyParams.SourceFilename = pszMonitorDll;
FileCopyParams.SourceDescription = pszDescription;
FileCopyParams.SourceTagfile = pszTagFile;
FileCopyParams.TargetDirectory = szDir;
FileCopyParams.TargetFilename = NULL;
FileCopyParams.CopyStyle = SP_COPY_NEWER;
FileCopyParams.LayoutInf = hInf;
FileCopyParams.SecurityDescriptor = NULL;
if ( !SetupQueueCopyIndirect(&FileCopyParams) )
{
goto Cleanup;
}
}
bRet = TRUE;
Cleanup:
LocalFreeMem(pszPathOnSource);
LocalFreeMem(pszDescription);
LocalFreeMem(pszTagFile);
return bRet;
}
BOOL
GetWebPageDir(
IN PPSETUP_LOCAL_DATA pLocalData,
OUT TCHAR szDir[MAX_PATH]
)
{
BOOL bRet = FALSE;
DWORD dwLen;
if ( !GetSystemWindowsDirectory(szDir, MAX_PATH) )
goto Done;
dwLen = lstrlen(szDir) + lstrlen(szWebDirPrefix)
+ lstrlen(pLocalData->DrvInfo.pszManufacturer)
+ lstrlen(pLocalData->DrvInfo.pszModelName)
+ 2;
if ( dwLen >= MAX_PATH ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Done;
}
lstrcat(szDir, szWebDirPrefix);
lstrcat(szDir, pLocalData->DrvInfo.pszManufacturer);
lstrcat(szDir, TEXT("\\"));
lstrcat(szDir, pLocalData->DrvInfo.pszModelName);
bRet = TRUE;
Done:
return bRet;
}
BOOL
SetTargetDirectories(
IN PPSETUP_LOCAL_DATA pLocalData,
IN PLATFORM platform,
IN LPCTSTR pszServerName,
IN HINF hInf,
IN DWORD dwInstallFlags
)
/*++
Routine Description:
Set all the target directories listed in the INF file for file copy
operations. Also gets the source directory where we should look for
driver files
Arguments:
hDevInfo : Handle to printer device info list
pLocalData : INF parsing information
platform : Gives the platform
pszSource : Source directory to look for files
CopyQueue : File queue
hInf : Printer driver INF file handle
dwInstallFlags : Driver installation flags
Return Value:
TRUE on success, FALSE else
--*/
{
BOOL bRet=FALSE;
DWORD dwNeeded, dwIndex, dwIndex2, dwCount, dwCount2;
INT DRID;
TCHAR szDir[MAX_PATH];
INFCONTEXT InfContext;
if ( (dwCount = SetupGetLineCount(hInf, TEXT("DestinationDirs"))) == -1 )
goto Cleanup;
// Setup the Skip Dir
if ( !SetupSkipDir( platform, pszServerName ) )
goto Cleanup;
//
// Process every line in the DestinationDirs section
//
for ( dwIndex = 0 ; dwIndex < dwCount ; ++dwIndex ) {
if ( !SetupGetLineByIndex(hInf, TEXT("DestinationDirs"),
dwIndex, &InfContext) )
goto Cleanup;
//
// A file could be copied to multiple destination directories
//
if ( (dwCount2 = SetupGetFieldCount(&InfContext)) == -1 )
continue;
for ( dwIndex2 = 1 ; dwIndex2 <= dwCount2 ; ++dwIndex2 ) {
//
// Not all directories are specified with a DRID
// for ex. %ProgramFiles%\%OLD_ICWDIR% could be used
// If DRID is smaller than DIRID_USER setup has predefined
// meaning to it
//
if ( !SetupGetIntField(&InfContext, dwIndex2, &DRID) ||
DRID < DIRID_USER )
continue;
if ( DRID < DIRID_USER )
continue;
dwNeeded = SIZECHARS(szDir);
switch (DRID) {
case PRINTER_DRIVER_DIRECTORY_ID:
if ( !GetPrinterDriverDirectory(
(LPTSTR)pszServerName,
PlatformEnv[platform].pszName,
1,
(LPBYTE)szDir,
sizeof(szDir),
&dwNeeded) )
{
goto Cleanup;
}
if ( dwInstallFlags & DRVINST_PRIVATE_DIRECTORY )
{
//
// if we have a pnp-ID, and it's an installation of a native driver
// and it's not an inbox driver, make the files stick around for
// pnp-reinstallations, else the user gets prompted over and over again
//
if ((lstrlen(pLocalData->DrvInfo.pszHardwareID) != 0) &&
!(dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) &&
!IsSystemNTPrintInf(pLocalData->DrvInfo.pszInfName))
{
//
// add the pnp-ID to szDir and set flag to not clean up this directory
// this is to get around users getting prompted for pnp-reinstallation
//
AddPnpDirTag( pLocalData->DrvInfo.pszHardwareID, szDir, sizeof(szDir)/sizeof(TCHAR));
pLocalData->Flags |= LOCALDATAFLAG_PNP_DIR_INSTALL;
}
else
{
//
// Add PID\TID to szDir.
// If this fails, add the dir info held in szDir to the DRIVER_INFO struct
// anyway as we'll attempt the install with this.
//
AddDirectoryTag( szDir, sizeof(szDir)/sizeof(TCHAR) );
}
ASSERT(pLocalData);
//
// Change DI6 to have the full szDir path included.
// Can't do anything if this fails, so try finish install anyway.
//
AddDirToDriverInfo( szDir, &(pLocalData->InfInfo.DriverInfo6) );
}
break;
case PRINT_PROC_DIRECTORY_ID:
if ( dwInstallFlags & DRVINST_DRIVERFILES_ONLY ) {
lstrcpy(szDir, gpszSkipDir);
} else if ( !GetPrintProcessorDirectory(
(LPTSTR)pszServerName,
PlatformEnv[platform].pszName,
1,
(LPBYTE)szDir,
sizeof(szDir),
&dwNeeded) )
goto Cleanup;
break;
case SYSTEM_DIRECTORY_ID_ONLY_FOR_NATIVE_ARCHITECTURE:
if ( !(dwInstallFlags & DRVINST_DRIVERFILES_ONLY) &&
platform == MyPlatform &&
MyName(pszServerName) ) {
if ( !GetSystemDirectory(szDir, dwNeeded) )
goto Cleanup;
} else {
lstrcpy(szDir, gpszSkipDir);
}
break;
case ICM_PROFILE_DIRECTORY_ID:
if ( !GetColorDirectory(pszServerName, szDir, &dwNeeded) )
goto Cleanup;
break;
case WEBPAGE_DIRECTORY_ID:
if ( !GetWebPageDir(pLocalData, szDir) )
goto Cleanup;
break;
default:
//
// This is for any new DRIDs we may add in the future
//
lstrcpy(szDir, gpszSkipDir);
}
if ( !SetupSetDirectoryId(hInf, DRID, szDir) )
goto Cleanup;
}
}
bRet = TRUE;
Cleanup:
return bRet;
}
BOOL
PSetupInstallICMProfiles(
IN LPCTSTR pszServerName,
IN LPCTSTR pszzICMFiles
)
/*++
Routine Description:
Install ICM color profiles associated with a printer driver.
Arguments:
pszServerName : Server name to which we are installing
pszzICMFiles : ICM profiles to install (multi-sz)
Return Value:
TRUE on success, FALSE else
--*/
{
TCHAR szDir[MAX_PATH], *p;
DWORD dwSize, dwNeeded;
BOOL bRet = TRUE;
if ( !pszzICMFiles || !*pszzICMFiles )
return bRet;
dwSize = SIZECHARS(szDir);
dwNeeded = sizeof(szDir);
if ( !GetColorDirectory(pszServerName, 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; bRet && *p ; p += lstrlen(p) + 1 ) {
if ( dwNeeded + lstrlen(p) + 1 > dwSize ) {
ASSERT(dwNeeded + lstrlen(p) + 1 <= dwSize);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
lstrcpy(szDir + dwNeeded, p);
// This function only supports NULL as the servername
// bRet = InstallColorProfile(pszServerName, szDir);
bRet = InstallColorProfile( NULL, szDir);
}
return bRet;
}
BOOL
MonitorRedirectDisable(
IN LPCTSTR pszMonitorDll,
OUT PTCHAR *ppszDir
)
{
BOOL bRet = FALSE;
PTCHAR pszBuffer = NULL;
DWORD dwDirLen = 0;
if( IsInWow64() )
{
pszBuffer = (PTCHAR)LocalAllocMem( MAX_PATH * sizeof( TCHAR ) );
if((pszBuffer != NULL) && GetSystemDirectory(pszBuffer, MAX_PATH))
{
dwDirLen = lstrlen(pszBuffer);
//
// Size of the returned string + size of file name + '\' + terminating null.
//
if( (dwDirLen + lstrlen(pszMonitorDll) + 2) < MAX_PATH )
{
if( *(pszBuffer + dwDirLen-1) != _T('\\') )
{
*(pszBuffer + dwDirLen++) = _T('\\');
*(pszBuffer + dwDirLen) = 0;
}
lstrcat(pszBuffer,pszMonitorDll);
#if !_WIN64
Wow64DisableFilesystemRedirector(pszBuffer);
#endif
bRet = TRUE;
}
}
if (ppszDir != NULL)
{
*ppszDir = pszBuffer;
}
}
return bRet;
}
BOOL
MonitorRedirectEnable(
IN OUT PTCHAR *ppszDir
)
{
BOOL bRet = FALSE;
if( IsInWow64() )
{
//
// This MACRO works on the current thread. Only one file can be disabled for redirection at a time.
//
#if !_WIN64
Wow64EnableFilesystemRedirector();
#endif
}
if ((ppszDir != NULL) && (*ppszDir != NULL))
{
LocalFreeMem( *ppszDir );
*ppszDir = NULL;
bRet = TRUE;
}
return bRet;
}
BOOL
UseUniqueDirectory(
IN LPCTSTR pszServerName
)
/*++
Routine Description:
Determines whether the unique install directory flags should be used or not.
Arguments:
pszServerName - the name of the remote server. NULL means local machine.
Return Value:
TRUE if we are going remote to a whistler or more recent server
or we are installing locally but not in setup.
FALSE else
--*/
{
BOOL bRet = FALSE;
if( pszServerName && *pszServerName )
{
bRet = IsWhistlerOrAbove(pszServerName);
}
else
{
if( !IsSystemSetupInProgress() )
{
bRet = TRUE;
}
}
return bRet;
}
DWORD
PSetupShowBlockedDriverUI(HWND hwnd,
DWORD BlockingStatus)
/*++
Routine Description:
Throws UI to ask user what to do with a blocked/warned driver
Arguments:
hwnd: parent window
BlockingStatus: the DWORD containing the BSP_* flags that indicate whether driver is blocked
Return Value:
New blocking status, the user selection is OR'd. Treats errors as if the user cancelled.
--*/
{
DWORD NewBlockingStatus = BlockingStatus;
LPTSTR pszTitle = NULL, pszPrompt = NULL;
switch (BlockingStatus & BSP_BLOCKING_LEVEL_MASK)
{
case BSP_PRINTER_DRIVER_WARNED:
if (BlockingStatus & BSP_INBOX_DRIVER_AVAILABLE)
{
pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
pszPrompt = GetLongStringFromRcFile(IDS_BSP_WARN_WITH_INBOX);
if (!pszTitle || !pszPrompt)
{
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
goto Cleanup;
}
switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_YESNOCANCEL | MB_ICONWARNING))
{
case IDYES:
NewBlockingStatus |= BSP_PRINTER_DRIVER_PROCEEDED;
break;
case IDNO:
NewBlockingStatus |= BSP_PRINTER_DRIVER_REPLACED;
break;
default:
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
break;
}
}
else // warned but not inbox available
{
pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
pszPrompt = GetLongStringFromRcFile(IDS_BSP_WARN_NO_INBOX);
if (!pszTitle || !pszPrompt)
{
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
goto Cleanup;
}
switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_OKCANCEL | MB_ICONWARNING))
{
case IDOK:
NewBlockingStatus |= BSP_PRINTER_DRIVER_PROCEEDED;
break;
default:
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
break;
}
}
break;
case BSP_PRINTER_DRIVER_BLOCKED:
if (BlockingStatus & BSP_INBOX_DRIVER_AVAILABLE)
{
pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_WARN);
pszPrompt = GetLongStringFromRcFile(IDS_BSP_BLOCK_WITH_INBOX);
if (!pszTitle || !pszPrompt)
{
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
goto Cleanup;
}
switch (MessageBox(hwnd, pszPrompt, pszTitle, MB_OKCANCEL | MB_ICONWARNING))
{
case IDOK:
NewBlockingStatus |= BSP_PRINTER_DRIVER_REPLACED;
break;
default:
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
break;
}
}
else // blocked and no inbox available - don't allow installation
{
pszTitle = GetStringFromRcFile(IDS_TITLE_BSP_ERROR);
pszPrompt = GetLongStringFromRcFile(IDS_BSP_BLOCK_NO_INBOX);
if (!pszTitle || !pszPrompt)
{
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
goto Cleanup;
}
MessageBox(hwnd, pszPrompt, pszTitle, MB_OK | MB_ICONSTOP);
NewBlockingStatus |= BSP_PRINTER_DRIVER_CANCELLED;
}
break;
}
Cleanup:
if (pszTitle)
{
LocalFreeMem(pszTitle);
}
if (pszPrompt)
{
LocalFreeMem(pszPrompt);
}
return NewBlockingStatus;
}
DWORD
InstallDriverFromCurrentInf(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA pLocalData,
IN HWND hwnd,
IN PLATFORM platform,
IN DWORD dwVersion,
IN LPCTSTR pszServerName,
IN HSPFILEQ CopyQueue,
IN PVOID QueueContext,
IN PSP_FILE_CALLBACK InstallMsgHandler,
IN DWORD Flags,
IN LPCTSTR pszSource,
IN DWORD dwInstallFlags,
IN DWORD dwAddDrvFlags,
IN LPCTSTR pszFileSrcPath,
OUT LPTSTR *ppszNewDriverName,
OUT PDWORD pBlockingStatus
)
{
HINF hPrinterInf = INVALID_HANDLE_VALUE;
BOOL bRet = FALSE;
BOOL bAddMon = FALSE;
BOOL bKeepMonName = FALSE;
BOOL bCatInInf = FALSE;
DWORD dwStatus = EXIT_FAILURE;
LPTSTR pszMonitorDll,
psz;
PSELECTED_DRV_INFO pDrvInfo = &pLocalData->DrvInfo;
PPARSEINF_INFO pInfInfo = &pLocalData->InfInfo;
PVOID pDSInfo = NULL; // Holds pointer to the driver signing class that C can't understand.
FILE_QUEUE_CONTEXT FileQContext;
//
// The following are only used during Cleanup
//
BOOL bZeroInf = FALSE,
bCopyInf = FALSE;
DWORD dwMediaType = SPOST_NONE;
DWORD dwInstallLE = ERROR_SUCCESS; // We record the LastError in case Cleanup
// alters it
LPTSTR pszINFName = NULL; // This will record whether the inf was
// copied in
LPTSTR pszNewINFName = NULL; // Hold the name of the inf to be zeroed if necessary
TCHAR szFullINFName[ MAX_PATH ]; // The Original Inf Name
TCHAR szFullNewINFName[ MAX_PATH ]; // The fully qualified inf name as copied onto the system.
HANDLE hDriverFile = INVALID_HANDLE_VALUE;
LPTSTR pszNewDriverName = NULL;
DWORD fBlockingStatus = BSP_PRINTER_DRIVER_OK;
PTCHAR pszDirPtr = NULL;
DWORD ScanResult = 0;
//
// Those below are used to manage the situation when the driver is not signed
//
BOOL bIsPersonalOrProfessional = FALSE;
HANDLE hRestorePointHandle = NULL;
BOOL bDriverNotInstalled = TRUE;
BOOL bIsWindows64 = FALSE;
BOOL bPreviousNames = FALSE;
DWORD dwOEMInfFileAttrs = 0;
const DWORD dwGetFileAttrsError = 0xFFFFFFFF;
szFullINFName[0] = TEXT('\0');
szFullNewINFName[0] = TEXT('\0');
//
// Set the unique directory flags if we are in a situation that uses them.
//
if( UseUniqueDirectory(pszServerName) ) {
dwInstallFlags |= DRVINST_PRIVATE_DIRECTORY;
dwAddDrvFlags |= APD_COPY_FROM_DIRECTORY;
}
//
// If this is a Windows update install, we need to ensure that all
// cluster spooler resources get their drivers updated.
//
if (dwInstallFlags & DRVINST_WINDOWS_UPDATE)
{
dwAddDrvFlags |= APD_COPY_TO_ALL_SPOOLERS;
pInfInfo->DriverInfo6.cVersion = dwVersion;
}
//
// Open INF file and append layout.inf specified in Version section
// Layout inf is optional
//
hPrinterInf = SetupOpenInfFile(pDrvInfo->pszInfName,
NULL,
INF_STYLE_WIN4,
NULL);
if ( hPrinterInf == INVALID_HANDLE_VALUE )
goto Cleanup;
SetupOpenAppendInfFile(NULL, hPrinterInf, NULL);
pInfInfo->DriverInfo6.pEnvironment = PlatformEnv[platform].pszName;
//
// DI_VCP tells us not to create new file-queue and use user provided one
//
if ( !(Flags & DI_NOVCP) ) {
CopyQueue = SetupOpenFileQueue();
if ( CopyQueue == INVALID_HANDLE_VALUE )
goto Cleanup;
if ( dwInstallFlags & DRVINST_PROGRESSLESS ) {
QueueContext = SetupInitDefaultQueueCallbackEx(
hwnd,
INVALID_HANDLE_VALUE,
0,
0,
NULL);
} else {
QueueContext = SetupInitDefaultQueueCallback(hwnd);
}
InstallMsgHandler = MyQueueCallback;
ZeroMemory(&FileQContext, sizeof(FileQContext));
FileQContext.hwnd = hwnd;
FileQContext.QueueContext = QueueContext;
FileQContext.dwInstallFlags = dwInstallFlags;
FileQContext.pszSource = (dwInstallFlags & DRVINST_FLATSHARE)
? pszSource : NULL;
FileQContext.platform = platform;
FileQContext.dwVersion = dwVersion;
FileQContext.pszFileSrcPath = pszFileSrcPath;
if (pDrvInfo->pszInfName)
{
_tcscpy(FileQContext.szInfPath, pDrvInfo->pszInfName);
//
// Cut off the inf file name
//
psz = _tcsrchr(FileQContext.szInfPath, _T('\\'));
if (psz)
{
*psz = 0;
}
}
}
//
// Setup the driver signing info.
//
if(NULL == (pDSInfo = SetupDriverSigning(hDevInfo, pszServerName,pDrvInfo->pszInfName,
pszSource, platform, dwVersion, CopyQueue, dwInstallFlags & DRVINST_WEBPNP)))
{
goto Cleanup;
}
//
// Find out if the cat was listed in a CatalogFile= entry.
// This is used in the cleanup.
//
bCatInInf = IsCatInInf(pDSInfo);
//
// Check if this Driver is from CDM.
// IF it is pass in the correct MediaType to Setup.
//
if ( (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER) || (dwInstallFlags & DRVINST_WINDOWS_UPDATE) )
dwMediaType = SPOST_URL;
//
// For non admins, we install the catalog by calling AddDriverCatalog
//
// Do not fail the call when AddDriverCatalog fails
//
(void)AddDriverCatalogIfNotAdmin(pszServerName, pDSInfo, pDrvInfo->pszInfName, NULL, dwMediaType, 0);
//
// To support same INFs to install both NT and Win95 drivers actual
// section to install could be different than the one corresponding
// to the selected driver.
//
// SetupSetPlatformOverride tells setup which platform drivers we need
// from the media
// Also note setup does not reset PlatformPath override. So we need to
// call this always
//
if ( !ParseInf(hDevInfo, pLocalData, platform, pszServerName, dwInstallFlags) ||
!SetupSetPlatformPathOverride(PlatformOverride[platform].pszName) ) {
goto Cleanup;
}
// Now do the actual file copies...
if ( !InstallAllInfSections( pLocalData,
platform,
pszServerName,
CopyQueue,
pszSource,
dwInstallFlags,
hPrinterInf,
pInfInfo->pszInstallSection ) )
goto Cleanup;
//
// If there is a language monitor make sure it is getting copied to
// system32. On NT 4 we used to manually queue it to system32
//
if ( pInfInfo->DriverInfo6.pMonitorName &&
platform == MyPlatform &&
!(dwInstallFlags & DRVINST_DRIVERFILES_ONLY) &&
!pszServerName)
{
//
// if it's an alternate platform but the platform really is the same (checked above)
// it's an NT4 driver on an x86 server. In this case install the LM too if not
// already installed, see XP-bug 416129, else point-and-print from an NT4 client
// that has the same driver installed locally will delete the LM info from the NT4 driver.
// The logic is a little twisted: install the monitor if it's not an alternate platform
// or if it is (within the limits checked above) but no monitor with this name is installed yet.
//
if (!(dwInstallFlags & DRVINST_ALT_PLATFORM_INSTALL) ||
!IsLanguageMonitorInstalled(pInfInfo->DriverInfo6.pMonitorName))
{
pszMonitorDll = pInfInfo->DriverInfo6.pMonitorName +
lstrlen(pInfInfo->DriverInfo6.pMonitorName) + 1;
//
// When we parse the INF we put the monitor dll name after \0
//
if ( !CheckAndEnqueueMonitorDll(pszMonitorDll,
pszSource,
CopyQueue,
hPrinterInf) )
goto Cleanup;
MonitorRedirectDisable( pszMonitorDll, &pszDirPtr );
bAddMon = TRUE;
}
else
{
//
// we get here if it's an alternate platform driver and the monitor is already installed
// in this case, don't clean out the monitor name from the driver info 6 below.
//
bKeepMonName = TRUE;
}
}
//
// DI_NOVCP is used for pre-install when the class installer is just
// supposed to queue the files and return. Printing needs special
// handling since APIs need to be called. But we will obey the flags
// as much as possible for those who use it
//
if ( Flags & DI_NOVCP ) {
bRet = TRUE;
goto Cleanup;
}
// We need a Queue Context to actually install files
if ( !QueueContext )
goto Cleanup;
// Check if this is a WebPnP install
if ( dwInstallFlags & DRVINST_WEBPNP || !(bAddMon || bKeepMonName) )
{
//
// Check to see if there is a Monitor. If so clear out if it is not installed already
//
if ( pInfInfo->DriverInfo6.pMonitorName &&
!IsMonitorInstalled( pInfInfo->DriverInfo6.pMonitorName ) )
{
LocalFreeMem( pInfInfo->DriverInfo6.pMonitorName );
pInfInfo->DriverInfo6.pMonitorName = NULL;
}
}
if (!PruneInvalidFilesIfNotAdmin( hwnd,
CopyQueue ))
goto Cleanup;
//
// prune files that are already present (correct version etc. checked by signature), ignore return value
//
SetupScanFileQueue( CopyQueue,
(SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE),
hwnd,
NULL,
NULL,
&ScanResult);
if (!pszServerName || !lstrlen(pszServerName))
{
bIsPersonalOrProfessional = IsProductType( VER_NT_WORKSTATION, VER_EQUAL) == S_OK;
}
else
{
bIsPersonalOrProfessional = FALSE;
}
if (bIsPersonalOrProfessional)
{
SetupSetFileQueueFlags( CopyQueue,
SPQ_FLAG_ABORT_IF_UNSIGNED,
SPQ_FLAG_ABORT_IF_UNSIGNED );
}
if ( !SetupCommitFileQueue(hwnd,
CopyQueue,
(PSP_FILE_CALLBACK)InstallMsgHandler,
(PVOID)&FileQContext) )
{
bIsWindows64 = IsInWow64();
if ((bIsWindows64 == FALSE) && bIsPersonalOrProfessional &&
(GetLastError() == ERROR_SET_SYSTEM_RESTORE_POINT))
{
//
// Here we have to start a Restore Point because there is
// something unsigned and this is either a personal or
// professional.
//
hRestorePointHandle = StartSystemRestorePoint( NULL,
(PCWSTR)(pLocalData->DrvInfo.pszModelName),
ghInst,
IDS_BSP_WARN_UNSIGNED_DRIVER );
//
// Terminate the default setupapi callback
//
SetupTermDefaultQueueCallback( QueueContext );
QueueContext = NULL;
//
// Initialize the QueueContext structure
//
if ( dwInstallFlags & DRVINST_PROGRESSLESS )
{
QueueContext = SetupInitDefaultQueueCallbackEx(hwnd,
INVALID_HANDLE_VALUE,
0,
0,
NULL);
}
else
{
QueueContext = SetupInitDefaultQueueCallback(hwnd);
}
if (!QueueContext)
{
goto Cleanup;
}
else
{
FileQContext.QueueContext = QueueContext;
}
//
// Reset the flag and call the function again
//
SetupSetFileQueueFlags( CopyQueue,
SPQ_FLAG_ABORT_IF_UNSIGNED,
0 );
if ( !SetupCommitFileQueue(hwnd,
CopyQueue,
(PSP_FILE_CALLBACK)InstallMsgHandler,
(PVOID)&FileQContext) )
{
goto Cleanup;
}
}
else
{
goto Cleanup;
}
}
//
// Now that we did the file copy part of install we will do anything
// else specified in the INF
//
if ( !pszServerName && platform == MyPlatform )
{
SetupInstallFromInfSection(hwnd,
hPrinterInf,
pInfInfo->pszInstallSection,
SPINST_ALL & (~SPINST_FILES),
NULL,
pszSource,
0,
NULL,
QueueContext,
hDevInfo,
pDrvInfo->pDevInfoData);
}
if ( bAddMon )
{
if( !AddPrintMonitor(pInfInfo->DriverInfo6.pMonitorName, pszMonitorDll) )
{
DWORD dwSavedLastError = EXIT_FAILURE;
//
// Fix bug 346937: when we can not add monitor, check whether this
// driver is in printupg. If it is, consider it blocked then and
// popups a UI asking whether to install the replacement driver.
//
// After this point bRet is allways false, we only try to change
// the error code in last error.
//
//
// Save the last error first
//
dwSavedLastError = GetLastError();
if (BlockedDriverPrintUpgUI(pszServerName,
&pInfInfo->DriverInfo6,
dwInstallFlags & DRVINST_PRIVATE_DIRECTORY, // whether use full path
!(dwInstallFlags & DRVINST_DONT_OFFER_REPLACEMENT), // whether to offer replacement
!(dwInstallFlags & (DRVINST_NO_WARNING_PROMPT | DRVINST_PROMPTLESS)), // whether to popup UI
&pszNewDriverName,
&fBlockingStatus) &&
(fBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
{
SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
}
else
{
SetLastError(dwSavedLastError); // restore the error code
}
goto Cleanup;
}
MonitorRedirectEnable( &pszDirPtr );
}
//
// If a print processor is specified in the INF need to install it.
// For non-native architectur spooler fails this call (for remote case)
//
if ( pInfInfo->pszPrintProc &&
!AddPrintProcessor((LPTSTR)pszServerName,
PlatformEnv[platform].pszName,
pInfInfo->pszPrintProc
+ lstrlen(pInfInfo->pszPrintProc) + 1,
pInfInfo->pszPrintProc) &&
GetLastError() != ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED &&
GetLastError() != ERROR_INVALID_ENVIRONMENT )
{
goto Cleanup;
}
if (IsTheSamePlatform(pszServerName, platform) && IsWhistlerOrAbove(pszServerName))
{
bPreviousNames = CheckAndKeepPreviousNames( pszServerName, &pInfInfo->DriverInfo6, platform );
}
bRet = AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry(pszServerName,
&pInfInfo->DriverInfo6,
dwAddDrvFlags | APD_DONT_SET_CHECKPOINT,
dwInstallFlags & DRVINST_PRIVATE_DIRECTORY, // whether use full path
!(dwInstallFlags & DRVINST_DONT_OFFER_REPLACEMENT), // whether to offer replacement
!(dwInstallFlags & (DRVINST_NO_WARNING_PROMPT | DRVINST_PROMPTLESS)), // whether to popup UI
&pszNewDriverName,
&fBlockingStatus) &&
PSetupInstallICMProfiles(pszServerName, pInfInfo->pszzICMFiles);
if (bPreviousNames)
{
LocalFreeMem( pInfInfo->DriverInfo6.pszzPreviousNames );
}
bDriverNotInstalled = FALSE;
Cleanup:
dwInstallLE = GetLastError(); // Get the real error message
if (bAddMon && pszDirPtr)
{
MonitorRedirectEnable( &pszDirPtr );
}
if ((bIsWindows64 == FALSE) && hRestorePointHandle)
{
//
// Here we have to end the Restore Point because one was
// started
//
EndSystemRestorePoint(hRestorePointHandle, bDriverNotInstalled);
}
if (hDriverFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hDriverFile);
}
//
// Zero the inf if DI_NOVCP and - either we've fail, it is a Web PNP
// install. or - this is installing from a non-system ntprint.inf AND
// there is a cat to be protected. - not yet!!
//
bZeroInf = (!bRet || ( dwInstallFlags & DRVINST_WEBPNP )
|| (IsNTPrintInf( pDrvInfo->pszInfName ) && bCatInInf)) &&
!(Flags & DI_NOVCP);
//
// We have to copy the INF if the following conditions are satisfied
//
bCopyInf = // bRet is TRUE (the call to AddPrinterDriverUsingCorrectLevelWithPrintUpgRetry succeeded)
bRet &&
// and the Installation flags say the INF to be copied
!(dwInstallFlags & DRVINST_DONOTCOPY_INF) &&
// and the platform is the same as ours
platform == MyPlatform &&
// and the INF it's not the system ntprint.inf (obviously) or
// it's from WU
(!IsSystemNTPrintInf(pDrvInfo->pszInfName) || (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER)) &&
// and DI_NOVCP flag is not set
!(Flags & DI_NOVCP) &&
// and this is not Web PnP or there is a cat to protect
!((dwInstallFlags & DRVINST_WEBPNP) && !bCatInInf) &&
// and this is not ntprint.inf or there is a cat to protect
!(IsNTPrintInf( pDrvInfo->pszInfName ) && !bCatInInf);
//
// How we have to call SetupCopyOEMInf to take the name of the INF which
// has been copied on our system when we called SetupCommitFileQueue
//
if (!SetupCopyOEMInf(pDrvInfo->pszInfName,
NULL,
dwMediaType,
SP_COPY_REPLACEONLY,
szFullINFName,
MAX_PATH,
NULL,
&pszINFName) )
{
// If we can't find the original name might as well not copy or
// zero
if (bZeroInf && !bCopyInf)
{
bZeroInf = FALSE;
}
}
else
{
if (bZeroInf)
{
bCopyInf = FALSE;
}
}
//
// If we succesfully installed a native architecture driver
// then is when we copy the OEM INF file and give it a unique name
//
if ( bCopyInf )
{
//
// Earlier we used to call CopyOEMInfFileAndGiveUniqueName here
// Now that Setup API has this and we are going to support CDM
// we call this setup API
//
(VOID)SetupCopyOEMInf(pDrvInfo->pszInfName,
NULL,
dwMediaType,
SP_COPY_NOOVERWRITE,
szFullNewINFName,
MAX_PATH,
NULL,
&pszNewINFName);
//
// If this fails we don't give the proverbial, since the file won't
// be there
//
}
else
{
if (!bZeroInf && !(Flags & DI_NOVCP))
{
//
// We have to remove the INF in the case of unsuccessful installation and ONLY if the DI_NOVCP
// flag is not set. If the flag is set then we don't have to change the state because the file
// queue hasn't been commited and the INF just has been already there before the call to our
// function.
//
//
// Remove the READONLY file attribute if set
//
dwOEMInfFileAttrs = GetFileAttributes( szFullINFName );
if ((dwOEMInfFileAttrs != dwGetFileAttrsError) &&
(dwOEMInfFileAttrs & FILE_ATTRIBUTE_READONLY))
{
dwOEMInfFileAttrs &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributes( szFullINFName, dwOEMInfFileAttrs);
}
DeleteFile( szFullINFName );
}
}
// Ignore the error message from SetupCopyOEMInf and DeleteFile
dwStatus = bRet ? ERROR_SUCCESS : dwInstallLE;
// If the install failed or this was Web Point&Print
// we may need to get rid of the INF
if ( bZeroInf )
{
// If INFName is different then possibly set to 0 length
// Or this is ntprint.inf being renamed to OEMx.inf - we want it zeroed.
if (( pszINFName &&
(psz=FileNamePart( pDrvInfo->pszInfName )) &&
lstrcmp( psz, pszINFName ) ) ||
( IsNTPrintInf( pDrvInfo->pszInfName ) &&
bCatInInf &&
pszNewINFName &&
(psz=FileNamePart( pDrvInfo->pszInfName )) &&
lstrcmp( psz, pszINFName ) ) )
{
HANDLE hFile;
//
// Remove the READONLY file attribute if set
//
dwOEMInfFileAttrs = GetFileAttributes(szFullINFName ? szFullINFName : szFullNewINFName);
if ((dwOEMInfFileAttrs != dwGetFileAttrsError) &&
(dwOEMInfFileAttrs & FILE_ATTRIBUTE_READONLY))
{
dwOEMInfFileAttrs &= ~FILE_ATTRIBUTE_READONLY;
SetFileAttributes(szFullINFName ? szFullINFName : szFullNewINFName, dwOEMInfFileAttrs);
}
// Open the File
hFile = CreateFile( szFullINFName ? szFullINFName : szFullNewINFName,
(GENERIC_READ | GENERIC_WRITE),
( FILE_SHARE_READ | FILE_SHARE_WRITE ),
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
// If we opened a file
if ( hFile != INVALID_HANDLE_VALUE )
{
SetFilePointer( hFile, 0, 0, FILE_BEGIN );
SetEndOfFile( hFile );
CloseHandle( hFile );
}
}
}
if ( hPrinterInf != INVALID_HANDLE_VALUE )
SetupCloseInfFile(hPrinterInf);
//
// Free the Driver Signing class.
//
if(pDSInfo)
{
CleanupDriverSigning(pDSInfo);
}
if ( !(Flags & DI_NOVCP) ) {
//
// The driver signing code may have associated the queue to the SP_DEVINSTALL_PARAMS.
// We've finished with this and need to remove the queue from the SP_DEVINSTALL_PARAMS before we delete it.
//
SP_DEVINSTALL_PARAMS DevInstallParams = {0};
DevInstallParams.cbSize = sizeof(DevInstallParams);
if(SetupDiGetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams))
{
if(DevInstallParams.FileQueue == CopyQueue)
{
DevInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
DevInstallParams.Flags &= ~DI_NOVCP;
DevInstallParams.FileQueue = INVALID_HANDLE_VALUE;
SetupDiSetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams);
}
}
//
// Now free up the queue.
//
if ( CopyQueue != INVALID_HANDLE_VALUE )
{
SetupCloseFileQueue(CopyQueue);
}
if ( QueueContext )
{
SetupTermDefaultQueueCallback(QueueContext);
}
if( dwAddDrvFlags & APD_COPY_FROM_DIRECTORY )
{
//
// if this was an installation with a path derived from the Pnp-ID,
// do not cleanup, else users will get prompted for media when they re-pnp the driver
//
if ( ! (pLocalData->Flags & LOCALDATAFLAG_PNP_DIR_INSTALL) )
{
CleanupUniqueScratchDirectory( pszServerName, platform );
}
}
else
{
CleanupScratchDirectory( pszServerName, platform );
}
}
//
// Return the new driver name and the blocking flags if they were asked for.
//
if (ppszNewDriverName)
{
*ppszNewDriverName = pszNewDriverName;
}
else if (pszNewDriverName)
{
LocalFreeMem(pszNewDriverName);
}
if (pBlockingStatus)
{
*pBlockingStatus = fBlockingStatus;
}
return dwStatus;
}
DWORD
InstallDriverAfterPromptingForInf(
IN PLATFORM platform,
IN LPCTSTR pszServerName,
IN HWND hwnd,
IN LPCTSTR pszModelName,
IN DWORD dwVersion,
IN OUT TCHAR szInfPath[MAX_PATH],
IN DWORD dwInstallFlags,
IN DWORD dwAddDrvFlags,
OUT LPTSTR *ppszNewDriverName
)
{
DWORD dwRet, dwTitleId, dwMediaId;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
PPSETUP_LOCAL_DATA pLocalData = NULL;
LPTSTR pszFileSrcPath = NULL;
DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
switch (platform) {
case PlatformAlpha:
dwTitleId = IDS_DRIVERS_FOR_NT4_ALPHA;
break;
case PlatformX86:
if( dwVersion == 2 )
{
dwTitleId = IDS_DRIVERS_FOR_NT4_X86;
}
else
{
dwTitleId = IDS_DRIVERS_FOR_X86;
}
break;
case PlatformMIPS:
dwTitleId = IDS_DRIVERS_FOR_NT4_MIPS;
break;
case PlatformPPC:
dwTitleId = IDS_DRIVERS_FOR_NT4_PPC;
break;
case PlatformIA64:
dwTitleId = IDS_DRIVERS_FOR_IA64;
break;
default:
ASSERT(0);
return ERROR_INVALID_PARAMETER;
}
dwMediaId = IDS_PROMPT_ALT_PLATFORM_DRIVER;
dwInstallFlags |= DRVINST_ALT_PLATFORM_INSTALL | DRVINST_NO_WARNING_PROMPT;
hDevInfo = GetInfAndBuildDrivers(hwnd,
dwTitleId,
dwMediaId,
szInfPath,
dwInstallFlags,
platform, dwVersion,
pszModelName,
&pLocalData,
&pszFileSrcPath);
if ( hDevInfo == INVALID_HANDLE_VALUE ) {
dwRet = GetLastError();
goto Cleanup;
}
//
// we want the printupg prompt
//
dwInstallFlags &= ~DRVINST_NO_WARNING_PROMPT;
dwRet = InstallDriverFromCurrentInf(hDevInfo,
pLocalData,
hwnd,
platform,
dwVersion,
pszServerName,
INVALID_HANDLE_VALUE,
NULL,
NULL,
0,
szInfPath,
dwInstallFlags,
dwAddDrvFlags,
pszFileSrcPath,
ppszNewDriverName,
&dwBlockingStatus);
if (((ERROR_PRINTER_DRIVER_BLOCKED == dwRet) || (ERROR_PRINTER_DRIVER_WARNED == dwRet)) &&
(ppszNewDriverName && *ppszNewDriverName) &&
(dwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
{
dwRet = InstallReplacementDriver(hwnd,
pszServerName,
*ppszNewDriverName,
platform,
dwVersion,
dwInstallFlags,
dwAddDrvFlags);
}
else if (ppszNewDriverName && *ppszNewDriverName)
{
LocalFreeMem(*ppszNewDriverName);
*ppszNewDriverName = NULL;
}
Cleanup:
if (pszFileSrcPath)
{
//
// we did the NT4 copy/expand thing -> delete the expanded inf!
//
_tcscat(szInfPath, _T("ntprint.inf"));
DeleteFile(szInfPath);
LocalFreeMem(pszFileSrcPath);
}
if ( hDevInfo != INVALID_HANDLE_VALUE )
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
DestroyLocalData(pLocalData);
return dwRet;
}
const TCHAR gcszNTPrint[] = _TEXT("inf\\ntprint.inf");
DWORD GetNtprintDotInfPath(LPTSTR pszNTPrintInf, DWORD len)
{
DWORD dwLastError = ERROR_INVALID_DATA, dwSize;
LPTSTR pData;
//
// Get %windir%
// If the return is 0 - the call failed.
// If the return is greater than MAX_PATH we want to fail as something has managed to change
// the system dir to longer than MAX_PATH which is invalid.
//
dwSize = GetSystemWindowsDirectory( pszNTPrintInf, len );
if( !dwSize || dwSize > len )
goto Cleanup;
//
// If we don't end in a \ then add one.
//
dwSize = _tcslen(pszNTPrintInf);
pData = &(pszNTPrintInf[ dwSize ]);
if (*pData != _TEXT('\\') )
{
if (dwSize + 1 < len)
{
*(pData++) = _TEXT('\\');
dwSize++;
}
}
*(pData) = 0;
dwSize += _tcslen( gcszNTPrint ) + 1;
//
// If what we've got sums up to a longer string than the allowable length MAX_PATH - fail
//
if ( dwSize > len )
goto Cleanup;
//
// Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
//
_tcscpy( pData, gcszNTPrint );
dwLastError = ERROR_SUCCESS;
Cleanup:
if (dwLastError != ERROR_SUCCESS)
{
//
// Got here due to some error. Get what the called function set the last error to.
// If the function set a success, set some error code.
//
if ( (dwLastError = GetLastError()) == ERROR_SUCCESS)
{
dwLastError = ERROR_INVALID_DATA;
}
if (len)
{
pszNTPrintInf[0] = 0;
}
}
return dwLastError;
}
DWORD
InstallReplacementDriver(HWND hwnd,
LPCTSTR pszServerName,
LPCTSTR pszModelName,
PLATFORM platform,
DWORD version,
DWORD dwInstallFlags,
DWORD dwAddDrvFlags)
/*++
Routine Description:
Install an inbox replacement driver for blocked/warned drivers.
Arguments:
hwnd : parent windows handle.
pszServerName : Server name to which we are installing
pszModelName : driver model name to install
Return Value:
ERROR_SUCCESS on success, error code otherwise
--*/
{
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
PPSETUP_LOCAL_DATA pLocalData = NULL;
TCHAR szNtprintDotInf[MAX_PATH];
DWORD dwLastError;
if ((dwLastError = GetNtprintDotInfPath(szNtprintDotInf, COUNTOF(szNtprintDotInf))) != ERROR_SUCCESS)
{
goto Cleanup;
}
if ((hDevInfo = PSetupCreatePrinterDeviceInfoList(NULL)) != INVALID_HANDLE_VALUE &&
PSetupBuildDriversFromPath(hDevInfo, szNtprintDotInf, TRUE) &&
PSetupPreSelectDriver(hDevInfo, NULL, pszModelName) &&
(pLocalData = BuildInternalData(hDevInfo, NULL)) != NULL &&
ParseInf(hDevInfo, pLocalData, platform, NULL, dwInstallFlags))
{
//
// Don't prompt for blocked or warned drivers.
//
dwInstallFlags |= DRVINST_NO_WARNING_PROMPT;
dwLastError = InstallDriverFromCurrentInf( hDevInfo,
pLocalData,
hwnd,
platform,
version,
pszServerName,
INVALID_HANDLE_VALUE,
NULL,
NULL,
0,
szNtprintDotInf,
dwInstallFlags,
dwAddDrvFlags,
NULL,
NULL,
NULL);
}
else
{
dwLastError = GetLastError();
}
Cleanup:
if(pLocalData != NULL)
{
PSetupDestroySelectedDriverInfo(pLocalData);
}
//
// Release the driver setup parameter handle.
//
if(hDevInfo != INVALID_HANDLE_VALUE)
{
PSetupDestroyPrinterDeviceInfoList( hDevInfo );
}
return dwLastError;
}
DWORD
InvokeSetup(
IN HWND hwnd,
IN LPCTSTR pszOption,
IN LPCTSTR pszInfFile,
IN LPCTSTR pszSourcePath,
IN LPCTSTR pszServerName OPTIONAL
)
/*++
Routine Description:
Invoke setup to do an install operation associated with an INF.
Will be used to install drivers from printer.inf, monitors from monitor.inf
Arguments:
hwnd : Window handle of current top-level window
pszOption : Option from the INF file to install
pszInfFile : Name of the INF file to be used for the setup
pszSourcePath : Location where the required files are available
pszServerName : Server to install printer driver on (NULL if local)
Return Value:
ERROR_SUCCESS on succesfully installing the driver
Erro code on failure
--*/
{
TCHAR szAppName[] = TEXT("%s\\SETUP.exe");
TCHAR szCmd[] = TEXT(" -f -s %s -i %s -c ExternalInstallOption \
/t STF_LANGUAGE = ENG /t OPTION = \"%s\" \
/t STF_PRINTSERVER = \"%s\" /t ADDCOPY = YES /t DOCOPY = YES \
/t DOCONFIG = YES /w %d");
MSG Msg;
DWORD dwSize, dwLastError = ERROR_SUCCESS;
LPTSTR pszSetupExe = NULL;
LPTSTR pszSetupCmd = NULL;
TCHAR szSystemPath[MAX_PATH];
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
#if defined(_WIN64)
//
// Setup.exe must be loaded from the wow64 directory.
//
if( (dwSize = GetSystemWindowsDirectory(szSystemPath,SIZECHARS(szSystemPath))))
{
if( szSystemPath[dwSize-1] != _TEXT('\\') && dwSize + 1 < SIZECHARS(szSystemPath) )
{
szSystemPath[dwSize++] = _TEXT('\\');
szSystemPath[dwSize] = 0;
}
}
#ifdef UNICODE
if(dwSize + lstrlen(WOW64_SYSTEM_DIRECTORY_U) + 1 < SIZECHARS(szSystemPath))
{
lstrcat( szSystemPath, WOW64_SYSTEM_DIRECTORY_U );
}
#else
if(dwSize + lstrlen(WOW64_SYSTEM_DIRECTORY) + 1 < SIZECHARS(szSystemPath))
{
lstrcat( szSystemPath, WOW64_SYSTEM_DIRECTORY );
}
#endif // #ifdef UNICODE
#else
//
// Setup.exe is in the system path
//
if( (dwSize = GetSystemDirectory(szSystemPath,SIZECHARS(szSystemPath))))
{
if( szSystemPath[dwSize-1] != _TEXT('\\') && dwSize + 1 < SIZECHARS(szSystemPath) )
{
szSystemPath[dwSize++] = _TEXT('\\');
szSystemPath[dwSize] = 0;
}
}
#endif // #if defined(_WIN64)
if ( !pszServerName )
pszServerName = TEXT("");
dwSize = lstrlen(pszOption) + 1 + lstrlen(pszSourcePath) + 1 +
lstrlen(pszServerName) + 1 + lstrlen(pszInfFile) + 1;
dwSize *= sizeof(TCHAR);
//
// 20 for window handle in ASCII
//
dwSize += sizeof(szCmd) + 20;
pszSetupCmd = (LPTSTR) LocalAllocMem(dwSize);
if ( !pszSetupCmd ) {
dwLastError = GetLastError();
goto Cleanup;
}
dwSize = (lstrlen(szAppName) + lstrlen(szSystemPath) + 1) * sizeof(TCHAR);
pszSetupExe = LocalAllocMem( dwSize );
if ( !pszSetupExe ) {
dwLastError = GetLastError();
goto Cleanup;
}
//
// Now print the full path including SETUP.EXE
//
wsprintf(pszSetupExe, szAppName, szSystemPath);
//
// Now print the command to invoke setup with all the arguments
//
wsprintf(pszSetupCmd, szCmd, pszSourcePath, pszInfFile, pszOption,
pszServerName, hwnd);
//
// Invoke setup as a separate process
//
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.wShowWindow = SW_SHOW;
if ( !CreateProcess(pszSetupExe, pszSetupCmd, NULL, NULL, FALSE, 0, NULL,
NULL, &StartupInfo, &ProcessInformation) ) {
dwLastError = GetLastError();
goto Cleanup;
}
EnableWindow (hwnd, FALSE);
while ( MsgWaitForMultipleObjects(1, (LPHANDLE)&ProcessInformation,
FALSE, (DWORD)-1, QS_ALLINPUT) ) {
//
// This message loop is a duplicate of main
// message loop with the exception of using
// PeekMessage instead of waiting inside of
// GetMessage. Process wait will actually
// be done in MsgWaitForMultipleObjects api.
//
while ( PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage (&Msg);
DispatchMessage (&Msg);
}
}
//
// Did setup complete succesfully?
//
GetExitCodeProcess(ProcessInformation.hProcess, &dwLastError);
//
// Setup.exe magic return codes I found out by trial and error
//
if ( dwLastError == 1 )
SetLastError(dwLastError = ERROR_CANCELLED);
else if ( dwLastError == 2 )
SetLastError(dwLastError = ERROR_UNKNOWN_PRINTER_DRIVER);
else if ( dwLastError )
SetLastError(dwLastError=(DWORD)STG_E_UNKNOWN);
CloseHandle (ProcessInformation.hProcess);
CloseHandle (ProcessInformation.hThread);
EnableWindow (hwnd, TRUE);
SetForegroundWindow(hwnd);
Cleanup:
LocalFreeMem(pszSetupCmd);
LocalFreeMem(pszSetupExe);
return dwLastError;
}
DWORD
InstallNt3xDriver(
IN HWND hwnd,
IN LPCTSTR pszDriverName,
IN PLATFORM platform,
IN LPCTSTR pszServerName,
IN OUT LPTSTR pszSourcePath,
IN LPCTSTR pszDiskName,
IN DWORD dwInstallFlags
)
{
LPTSTR pszTitle = NULL, pszFormat, pszPrompt = NULL;
TCHAR szInfPath[MAX_PATH];
DWORD dwLastError;
//
// Build strings to use in the path dialog ..
//
pszFormat = GetStringFromRcFile(IDS_DRIVERS_FOR_PLATFORM);
if ( pszFormat ) {
pszTitle = LocalAllocMem((lstrlen(pszFormat) + lstrlen(pszDiskName) + 2)
* sizeof(*pszTitle));
if ( pszTitle )
wsprintf(pszTitle, pszFormat, pszDiskName);
}
//
// First see if the inf could be found on our default location
//
if ( MAX_PATH >
lstrlen(pszSourcePath) + lstrlen(TEXT("printer.inf")) + 1 ) {
lstrcpy(szInfPath, pszSourcePath);
lstrcat(szInfPath, TEXT("printer.inf"));
} else {
SetLastError(dwLastError=ERROR_INSUFFICIENT_BUFFER);
goto Cleanup;
}
if ( !FileExists(szInfPath) ) {
if ( dwInstallFlags & DRVINST_PROMPTLESS ) {
dwLastError = ERROR_FILE_NOT_FOUND;
goto Cleanup;
}
//
// Always just prompt with the CD-ROM path
//
GetCDRomDrive(pszSourcePath);
dwInstallFlags |= DRVINST_ALT_PLATFORM_INSTALL;
pszPrompt = GetStringFromRcFile(IDS_PROMPT_ALT_PLATFORM_DRIVER);
if (!pszPrompt)
{
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Ask the user where the printer.inf, printer driver files reside
//
if ( !PSetupGetPathToSearch(hwnd, pszTitle, pszPrompt,
TEXT("printer.inf"), TRUE, pszSourcePath) ) {
dwLastError = GetLastError();
goto Cleanup;
}
if ( MAX_PATH >
lstrlen(pszSourcePath) + lstrlen(TEXT("printer.inf")) + 1 ) {
lstrcpy(szInfPath, pszSourcePath);
lstrcat(szInfPath, TEXT("printer.inf"));
} else {
SetLastError(dwLastError=ERROR_INSUFFICIENT_BUFFER);
goto Cleanup;
}
}
dwLastError = InvokeSetup(hwnd,
pszDriverName,
szInfPath,
pszSourcePath,
pszServerName);
Cleanup:
LocalFreeMem(pszPrompt);
LocalFreeMem(pszTitle);
LocalFreeMem(pszFormat);
CleanupScratchDirectory(pszServerName, platform);
return dwLastError;
}
//
// Paths where we search for the driver files
//
SPLPLATFORMINFO szPlatformExtn[] = {
{ TEXT("\\alpha") },
{ TEXT("\\i386") },
{ TEXT("\\mips") },
{ TEXT("\\ppc") },
{ TEXT("") },
{ TEXT("\\ia64") }
};
VOID
GetCDRomDrive(
TCHAR szDrive[5]
)
{
DWORD dwDrives;
INT iIndex;
szDrive[1] = TEXT(':');
szDrive[2] = TEXT('\\');
szDrive[3] = TEXT('\0');
dwDrives = GetLogicalDrives();
for ( iIndex = 0 ; iIndex < 26 ; ++iIndex )
if ( dwDrives & (1 << iIndex) ) {
szDrive[0] = TEXT('A') + iIndex;
if ( GetDriveType(szDrive) == DRIVE_CDROM )
goto Done;
}
szDrive[0] = TEXT('A');
Done:
return;
}
BOOL
BuildPathToPrompt(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA pLocalData,
IN PLATFORM platform,
IN DWORD dwVersion,
IN TCHAR szPathOut[MAX_PATH]
)
/*++
--*/
{
LPTSTR pszExtn = TEXT("");
DWORD dwLen;
//
// The CD we installed from OS can have only the following drivers:
// -- NT5 same platform drivers
// -- NT4 same platform drivers (only on server CD)
// -- Win9x drivers (only on server CD)
//
if ( (platform == MyPlatform && dwVersion >= 2) ||
platform == PlatformWin95 ) {
GetDriverPath(hDevInfo, pLocalData, szPathOut);
} else {
GetCDRomDrive(szPathOut);
}
if ( dwVersion >= dwThisMajorVersion && platform == MyPlatform )
return TRUE;
//
// append a backslash if needed
//
dwLen = lstrlen(szPathOut);
if (dwLen && (dwLen + 1 < MAX_PATH) && (szPathOut[dwLen-1] != TEXT('\\')))
{
szPathOut[dwLen] = TEXT('\\');
szPathOut[++dwLen] = 0;
}
switch (dwVersion) {
case 0:
if ( platform == PlatformWin95 )
pszExtn = TEXT("printers\\Win9X\\");
//
// For NT 3.51 and 3.1 we do not include drivers on CD, so
// nothing to add to the base path
//
case 1:
break;
case 2:
if ( platform == PlatformX86 ) // Alpha is now on the NT4.0 CD
pszExtn = TEXT("printers\\NT4\\");
break;
case 3:
break;
default:
ASSERT(dwVersion <= 3);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ( dwLen + lstrlen(pszExtn) + lstrlen(szPlatformExtn[platform].pszName) + 1
> MAX_PATH ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
lstrcat(szPathOut, pszExtn);
//
// Skip the leading \ of the platform extension as we have one already.
//
lstrcat(szPathOut, &(szPlatformExtn[platform].pszName[1]));
return TRUE;
}
DWORD
PSetupInstallPrinterDriver(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA pLocalData,
IN LPCTSTR pszDriverName,
IN PLATFORM platform,
IN DWORD dwVersion,
IN LPCTSTR pszServerName,
IN HWND hwnd,
IN LPCTSTR pszDiskName,
IN LPCTSTR pszSource OPTIONAL,
IN DWORD dwInstallFlags,
IN DWORD dwAddDrvFlags,
OUT LPTSTR *ppszNewDriverName
)
/*++
Routine Description:
Copies all the necessary driver files to the printer driver directory so
that an AddPrinterDriver call could be made.
Arguments:
hDevInfo : Handle to the printer class device information list
pLocalData : Gives information got by parsing the inf
pszDriverName : Printer driver name, used only if pLocalData is NULL
platform : Platform for which drivers need to be installed
dwVersion : Version of the driver to install
pszServerName : Server on which driver should be installed
hwnd : Parent windows handle for UI
pszDiskName : Disk name for prompting
pszSource : If provided this is a flat directory having all the files
dwAddDrvFlags : Flags for AddPrinterDriverEx
Return Value:
On succesfully copying files ERROR_SUCCESS, else the error code
--*/
{
BOOL bDeleteLocalData = pLocalData == NULL;
DWORD dwRet;
TCHAR szPath[MAX_PATH];
szPath[0] = 0;
if ( pszSource && !*pszSource )
pszSource = NULL;
if ( pLocalData )
{
ASSERT(pLocalData->signature == PSETUP_SIGNATURE && !pszDriverName);
}
else
{
ASSERT(pszDriverName && *pszDriverName);
}
//
// If FLATSHARE bit is set then a path should be given
//
ASSERT( (dwInstallFlags & DRVINST_FLATSHARE) == 0 || pszSource != NULL );
Retry:
//
// If a path is given use it. Otherwise if this is a driver for different
// version or platform then we determine the path, otherwise let SetupAPI determine the
// path.
//
if ( dwVersion != dwThisMajorVersion || platform != MyPlatform ) {
// If this is not an NT5 driver and we are asked to get it
// from the web, then just return.....
if ( pLocalData &&
( pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ) )
return ERROR_SUCCESS;
if ( pszSource )
lstrcpy(szPath, pszSource);
else if ( !BuildPathToPrompt(hDevInfo,
pLocalData,
platform,
dwVersion,
szPath) ) {
if ( (dwRet = GetLastError()) == ERROR_SUCCESS )
dwRet = STG_E_UNKNOWN;
return dwRet;
}
}
//
// For Win95 drivers we need to parse their INFs,
// For Nt 3x driver we need to call setup
// For non native environemnt dirvers ask user for path
//
if ( platform == PlatformWin95 ) {
if ( pLocalData ) {
//
// Parse the inf as a X86 inf so that we can pick up any
// previous names entries and use them.
//
if ( !ParseInf(hDevInfo, pLocalData, PlatformX86,
pszServerName, dwInstallFlags) )
return GetLastError();
dwRet = InstallWin95Driver(hwnd,
pLocalData->DrvInfo.pszModelName,
pLocalData->DrvInfo.pszzPreviousNames,
(pLocalData->DrvInfo.Flags &
SDFLAG_PREVNAME_SECTION_FOUND),
pszServerName,
szPath,
pszDiskName,
dwInstallFlags,
dwAddDrvFlags);
} else {
dwRet = InstallWin95Driver(hwnd,
pszDriverName,
NULL,
TRUE, // Exact model name match only
pszServerName,
szPath,
pszDiskName,
dwInstallFlags,
dwAddDrvFlags);
}
} else if ( dwVersion < 2 ) {
dwRet = InstallNt3xDriver(hwnd,
pLocalData ?
pLocalData->DrvInfo.pszModelName :
pszDriverName,
platform,
pszServerName,
szPath,
pszDiskName,
dwInstallFlags);
} else if ( dwVersion != dwThisMajorVersion || platform != MyPlatform ) {
dwRet = InstallDriverAfterPromptingForInf(
platform,
pszServerName,
hwnd,
pLocalData ?
pLocalData->DrvInfo.pszModelName :
pszDriverName,
dwVersion,
szPath,
dwInstallFlags,
dwAddDrvFlags,
ppszNewDriverName);
} else if ( pLocalData &&
(pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER) ) {
dwRet = PSetupInstallPrinterDriverFromTheWeb(hDevInfo,
pLocalData,
platform,
pszServerName,
&OsVersionInfo,
hwnd,
pszSource);
} else {
if ( !pLocalData )
{
pLocalData = PSetupDriverInfoFromName(hDevInfo, pszDriverName);
}
if ( pLocalData )
{
DWORD dwBlockingStatus = BSP_PRINTER_DRIVER_OK;
dwRet = InstallDriverFromCurrentInf(hDevInfo,
pLocalData,
hwnd,
platform,
dwVersion,
pszServerName,
INVALID_HANDLE_VALUE,
NULL,
NULL,
0,
pszSource,
dwInstallFlags,
dwAddDrvFlags,
NULL,
ppszNewDriverName,
&dwBlockingStatus);
if ((ppszNewDriverName && *ppszNewDriverName) &&
(dwBlockingStatus & BSP_PRINTER_DRIVER_REPLACED))
{
dwRet = InstallReplacementDriver(hwnd,
pszServerName,
*ppszNewDriverName,
platform,
dwVersion,
dwInstallFlags,
dwAddDrvFlags);
}
else if (ppszNewDriverName && *ppszNewDriverName)
{
LocalFreeMem(*ppszNewDriverName);
*ppszNewDriverName = NULL;
}
}
else
{
dwRet = GetLastError();
}
}
if (
(dwRet == ERROR_EXE_MACHINE_TYPE_MISMATCH) &&
!(dwInstallFlags & DRVINST_PROMPTLESS)
)
{
int i;
TCHAR szTitle[256], szMsg[256];
LoadString(ghInst,
IDS_INVALID_DRIVER,
szTitle,
SIZECHARS(szTitle));
LoadString(ghInst,
IDS_WRONG_ARCHITECTURE,
szMsg,
SIZECHARS(szMsg));
i = MessageBox(hwnd,
szMsg,
szTitle,
MB_RETRYCANCEL | MB_ICONSTOP | MB_DEFBUTTON1 | MB_APPLMODAL);
if ( i == IDRETRY )
{
if ( bDeleteLocalData )
{
DestroyLocalData(pLocalData);
pLocalData = NULL;
}
goto Retry;
}
else
{
SetLastError(dwRet =ERROR_CANCELLED);
}
}
if ( bDeleteLocalData )
DestroyLocalData(pLocalData);
return dwRet;
}
//
// SCAN_INFO structure is used with SetupScanFileQueue to find dependent files
// and ICM files
//
typedef struct _SCAN_INFO {
BOOL bWin95;
PPSETUP_LOCAL_DATA pLocalData;
DWORD cchDependentFiles, cchICMFiles;
DWORD cchDriverDir, cchColorDir;
LPTSTR p1, p2;
TCHAR szDriverDir[MAX_PATH], szColorDir[MAX_PATH];
} SCAN_INFO, *PSCAN_INFO;
UINT
DriverInfoCallback(
IN PVOID pContext,
IN UINT Notification,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
/*++
Routine Description:
This callback routine is used with SetupScanFileQueue to findout the
dependent files and ICM files associated in an INF. All files going to the
printer driver directory are dependent files in DRIVER_INFO_6, and all
files goint to the Color directory are ICM files.
We use SetupScanFileQueue twice. We find the size of the buffers required
for the multi-sz fields in the first pass. After allocating buffers of size
found in first pass second pass is used to copy the strings and build the
multi-sz fields.
Arguments:
pContext : Gives the SCAN_INFO structure
Notification : Ignored
Param1 : Gives the target file name
Param2 : Ignored
Return Value:
Win32 error code
--*/
{
DWORD dwLen;
LPTSTR pszTarget = (LPTSTR)Param1, pszFileName;
PSCAN_INFO pScanInfo = (PSCAN_INFO)pContext;
LPDRIVER_INFO_6 pDriverInfo6;
pszFileName = FileNamePart(pszTarget);
if ( pszFileName )
{
dwLen = lstrlen(pszFileName) + 1;
if ( !lstrncmpi(pszTarget,
gpszSkipDir,
lstrlen( gpszSkipDir ) ) )
goto Done;
if ( !lstrncmpi(pszTarget,
pScanInfo->szDriverDir,
pScanInfo->cchDriverDir) ) {
pDriverInfo6 = &pScanInfo->pLocalData->InfInfo.DriverInfo6;
//
// On NT dependent file list will not include files appearing as
// other DRIVER_INFO_6 fields
//
if ( !pScanInfo->bWin95 &&
( !lstrcmpi(pszFileName, pDriverInfo6->pDriverPath) ||
!lstrcmpi(pszFileName, pDriverInfo6->pConfigFile) ||
!lstrcmpi(pszFileName, pDriverInfo6->pDataFile) ||
( pDriverInfo6->pHelpFile &&
!lstrcmpi(pszFileName, pDriverInfo6->pHelpFile))) )
goto Done;
//
// If pointer is not NULL this is pass 2
//
if ( pScanInfo->p1 ) {
lstrcpy(pScanInfo->p1, pszFileName);
pScanInfo->p1 += dwLen;
} else {
pScanInfo->cchDependentFiles += dwLen;
}
} else if ( !lstrncmpi(pszTarget,
pScanInfo->szColorDir,
pScanInfo->cchColorDir) ) {
//
// If pointer is not NULL this is pass 2
//
if ( pScanInfo->p2 ) {
lstrcpy(pScanInfo->p2, pszFileName);
pScanInfo->p2 += dwLen;
} else {
pScanInfo->cchICMFiles += dwLen;
}
}
}
else
{
return ERROR_INVALID_PARAMETER;
}
Done:
return NO_ERROR;
}
BOOL
InfGetDependentFilesAndICMFiles(
IN HDEVINFO hDevInfo,
IN HINF hInf,
IN BOOL bWin95,
IN OUT PPSETUP_LOCAL_DATA pLocalData,
IN PLATFORM platform,
IN LPCTSTR pszServerName,
IN DWORD dwInstallFlags,
IN LPCTSTR pszSectionNameWithExt,
IN OUT LPDWORD pcchSize
)
/*++
Routine Description:
Findout the dependent files for the DRIVER_INFO_6 and the ICM files
for the selected driver
This is done by simulating the install operation by create a setup
queue to do the install operations and scanning the queue to find out
where files are getting copied to
Dependent files are those getting copied to driver scratch directory
without including other DRIVER_INFO_6 fields like pDriverPath. For Win95
case all files getting copied to the driver directory are dependent files.
ICM files are those getting copied to the color directory
Arguments:
hInf : INF handle
bWin95 : TRUE if it is a Win95 INF
pLocalData : INF parsing information
pszSectionNameWithExt : Section name with extension for install
pcchSize : Size needed for DRIVER_INFO_6 and strings in it
Return Value:
TRUE on success, FALSE on error
--*/
{
BOOL bRet = FALSE;
DWORD dwResult;
SCAN_INFO ScanInfo;
HSPFILEQ ScanQueue = INVALID_HANDLE_VALUE;
LPTSTR ppszDepFiles = NULL,
pszzICMFiles = NULL;
SP_DEVINSTALL_PARAMS StoreDevInstallParams = {0};
SP_DEVINSTALL_PARAMS DevInstallParams = {0};
SP_ALTPLATFORM_INFO AltPlat_Info = {0};
OSVERSIONINFO OSVer = {0};
ScanInfo.p1 = ScanInfo.p2 = NULL;
ScanInfo.cchDependentFiles = ScanInfo.cchICMFiles = 0;
ScanInfo.cchColorDir = sizeof(ScanInfo.szColorDir);
ScanInfo.cchDriverDir = sizeof(ScanInfo.szDriverDir);
if ( !GetColorDirectory( pszServerName, ScanInfo.szColorDir, &ScanInfo.cchColorDir) ||
!GetSystemDirectory(ScanInfo.szDriverDir, ScanInfo.cchDriverDir) ) {
goto Cleanup;
}
//
// Set ScanInfo.cchColorDir to char count of ScanInfo.szColorDir without \0
//
ScanInfo.cchColorDir /= sizeof(TCHAR);
--ScanInfo.cchColorDir;
//
// Win95 INFs tell setup to copy the driver files to system32 directory
// NT INFs expect install programs to set the target using
// SetupSetDirectoryId
//
if ( bWin95 ) {
ScanInfo.cchDriverDir = lstrlen(ScanInfo.szDriverDir);
} else {
if ( !GetPrinterDriverDirectory((LPTSTR)pszServerName,
PlatformEnv[platform].pszName,
1,
(LPBYTE)ScanInfo.szDriverDir,
ScanInfo.cchDriverDir,
&ScanInfo.cchDriverDir) )
goto Cleanup;
//
// Set ScanInfo.cchDriverDir to char count of ScanInfo.szDriverDir
// without \0
//
ScanInfo.cchDriverDir /= sizeof(TCHAR);
--ScanInfo.cchDriverDir;
}
//
// Inf MAY refer to another one (like layout.inf)
//
SetupOpenAppendInfFile(NULL, hInf, NULL);
ScanInfo.bWin95 = bWin95;
ScanInfo.pLocalData = pLocalData;
ScanQueue = SetupOpenFileQueue();
if (ScanQueue == INVALID_HANDLE_VALUE)
{
goto Cleanup;
}
DevInstallParams.cbSize = sizeof(DevInstallParams);
if(!SetupDiGetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams))
{
goto Cleanup;
}
if(!GetOSVersion(pszServerName, &OSVer))
{
goto Cleanup;
}
//
// Save the current config...
//
memcpy(&StoreDevInstallParams, &DevInstallParams, sizeof(DevInstallParams));
DevInstallParams.FlagsEx |= DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
DevInstallParams.Flags |= DI_NOVCP;
DevInstallParams.FileQueue = ScanQueue;
AltPlat_Info.cbSize = sizeof(SP_ALTPLATFORM_INFO);
AltPlat_Info.MajorVersion = OSVer.dwMajorVersion;
AltPlat_Info.MinorVersion = OSVer.dwMinorVersion;
AltPlat_Info.Platform = PlatformArch[ platform ][OS_PLATFORM];
AltPlat_Info.ProcessorArchitecture = (WORD) PlatformArch[ platform ][PROCESSOR_ARCH];
AltPlat_Info.Reserved = 0;
AltPlat_Info.FirstValidatedMajorVersion = AltPlat_Info.MajorVersion;
AltPlat_Info.FirstValidatedMinorVersion = AltPlat_Info.MinorVersion;
if(!SetupDiSetDeviceInstallParams(hDevInfo,
NULL,
&DevInstallParams) ||
!SetupSetFileQueueAlternatePlatform(ScanQueue,
&AltPlat_Info,
NULL))
{
goto Cleanup;
}
//
// First pass using SetupScanFileQueue will find the sizes required
//
if ( !InstallAllInfSections( pLocalData,
platform,
pszServerName,
ScanQueue,
NULL,
dwInstallFlags,
hInf,
pszSectionNameWithExt ) ||
!SetupScanFileQueue(ScanQueue,
SPQ_SCAN_USE_CALLBACK,
0,
DriverInfoCallback,
&ScanInfo,
&dwResult) ) {
goto Cleanup;
}
if ( ScanInfo.cchDependentFiles ) {
++ScanInfo.cchDependentFiles;
ppszDepFiles = (LPTSTR) LocalAllocMem(ScanInfo.cchDependentFiles * sizeof(TCHAR));
if ( !ppszDepFiles )
goto Cleanup;
ScanInfo.p1 = ppszDepFiles;
}
if ( ScanInfo.cchICMFiles ) {
++ScanInfo.cchICMFiles;
pszzICMFiles = (LPTSTR) LocalAllocMem(ScanInfo.cchICMFiles * sizeof(TCHAR));
if ( !pszzICMFiles )
goto Cleanup;
ScanInfo.p2 = pszzICMFiles;
}
//
// Second call to SetupScanFileQueue build the actual multi-sz fields
//
bRet = SetupScanFileQueue(ScanQueue,
SPQ_SCAN_USE_CALLBACK,
0,
DriverInfoCallback,
&ScanInfo,
&dwResult);
Cleanup:
//
// Save the last error as it may get toasted by the following calls.
//
dwResult = GetLastError();
if ( ScanQueue != INVALID_HANDLE_VALUE )
{
DevInstallParams.FlagsEx &= ~DI_FLAGSEX_ALTPLATFORM_DRVSEARCH;
DevInstallParams.Flags &= ~DI_NOVCP;
DevInstallParams.FileQueue = INVALID_HANDLE_VALUE;
if (!SetupDiSetDeviceInstallParams(hDevInfo, NULL, &DevInstallParams))
{
dwResult = (ERROR_SUCCESS == dwResult) ? GetLastError() : dwResult;
}
SetupCloseFileQueue(ScanQueue);
}
if(StoreDevInstallParams.cbSize == sizeof(DevInstallParams))
{
//
// Reset the HDEVINFO params.
//
SetupDiSetDeviceInstallParams(hDevInfo,
NULL,
&StoreDevInstallParams);
}
if ( bRet ) {
*pcchSize += ScanInfo.cchDependentFiles;
pLocalData->InfInfo.DriverInfo6.pDependentFiles = ppszDepFiles;
pLocalData->InfInfo.pszzICMFiles = pszzICMFiles;
} else {
LocalFreeMem(ppszDepFiles);
LocalFreeMem(pszzICMFiles);
}
SetLastError(dwResult);
return bRet;
}
VOID
DestroyCodedownload(
PCODEDOWNLOADINFO pCodeDownLoadInfo
)
{
if ( pCodeDownLoadInfo ) {
pCodeDownLoadInfo->pfnClose(pCodeDownLoadInfo->hConnection);
if ( pCodeDownLoadInfo->hModule )
FreeLibrary(pCodeDownLoadInfo->hModule);
LocalFreeMem(pCodeDownLoadInfo);
}
}
BOOL
InitCodedownload(
HWND hwnd
)
{
BOOL bRet = FALSE;
PCODEDOWNLOADINFO pCDMInfo = NULL;
EnterCriticalSection(&CDMCritSect);
// We already have a context & function pointers
// So reuse them...
if (gpCodeDownLoadInfo)
{
LeaveCriticalSection(&CDMCritSect);
return TRUE;
}
pCDMInfo = (PCODEDOWNLOADINFO) LocalAllocMem(sizeof(CODEDOWNLOADINFO));
if ( !pCDMInfo )
goto Cleanup;
pCDMInfo->hModule = LoadLibraryUsingFullPath(TEXT("cdm.dll"));
if ( !pCDMInfo->hModule )
goto Cleanup;
(FARPROC)pCDMInfo->pfnOpen = GetProcAddress(pCDMInfo->hModule,
"OpenCDMContext");
(FARPROC)pCDMInfo->pfnDownload = GetProcAddress(pCDMInfo->hModule,
"DownloadUpdatedFiles");
(FARPROC)pCDMInfo->pfnClose = GetProcAddress(pCDMInfo->hModule,
"CloseCDMContext");
bRet = pCDMInfo->pfnOpen &&
pCDMInfo->pfnDownload &&
pCDMInfo->pfnClose;
if ( bRet )
pCDMInfo->hConnection = pCDMInfo->pfnOpen(hwnd);
Cleanup:
if ( !bRet ||
( pCDMInfo && !pCDMInfo->hConnection ) ) {
DestroyCodedownload(pCDMInfo);
pCDMInfo = NULL;
bRet = FALSE;
}
if (bRet)
gpCodeDownLoadInfo = pCDMInfo;
LeaveCriticalSection(&CDMCritSect);
return bRet;
}
DWORD
PSetupInstallPrinterDriverFromTheWeb(
IN HDEVINFO hDevInfo,
IN PPSETUP_LOCAL_DATA pLocalData,
IN PLATFORM platform,
IN LPCTSTR pszServerName,
IN LPOSVERSIONINFO pOsVersionInfo,
IN HWND hwnd,
IN LPCTSTR pszSource
)
{
BOOL bRet = FALSE;
DWORD dwLen, dwReturn = ERROR_SUCCESS;
UINT uNeeded;
TCHAR szSourceDir[MAX_PATH];
DOWNLOADINFO DownLoadInfo;
PPSETUP_LOCAL_DATA pNewLocalData = NULL;
INT clpFileBufferLength = 0;
INT cProviderNameLength = 0;
INT cManufacturerNameLength = 0;
INT cDriverNameLength = 0;
ZeroMemory(&DownLoadInfo, sizeof(DownLoadInfo));
if ( !gpCodeDownLoadInfo )
goto Cleanup;
DownLoadInfo.dwDownloadInfoSize = sizeof(DownLoadInfo);
DownLoadInfo.localid = lcid;
// dwLen = lstrlen( cszWebNTPrintPkg );
dwLen = lstrlen(pLocalData->DrvInfo.pszHardwareID);
//
// lpHardwareIDs is multi-sz
//
if ( !(DownLoadInfo.lpHardwareIDs = LocalAllocMem((dwLen + 2 ) * sizeof(TCHAR))) )
goto Cleanup;
// lstrcpy(DownLoadInfo.lpHardwareIDs, cszWebNTPrintPkg );
lstrcpy( (LPTSTR) DownLoadInfo.lpHardwareIDs, pLocalData->DrvInfo.pszHardwareID);
CopyMemory(&DownLoadInfo.OSVersionInfo,
pOsVersionInfo,
sizeof(OSVERSIONINFO));
// Assign the correct Processor Architecture to the download
DownLoadInfo.dwArchitecture = (WORD) PlatformArch[ platform ][PROCESSOR_ARCH];
DownLoadInfo.lpFile = NULL;
//
// Below we have to check if we have valid Provider, Manufacturer, and
// driver names and if this is the case then we have to prepare a
// MULTISZ including Provider, Manufacturer, and Driver Names,
// and to set a pointer to that MULTISZ into DownLoadInfo.lpFile
//
if (pLocalData->DrvInfo.pszProvider &&
pLocalData->DrvInfo.pszManufacturer &&
pLocalData->DrvInfo.pszModelName)
{
cProviderNameLength = lstrlen(pLocalData->DrvInfo.pszProvider);
if (cProviderNameLength)
{
cManufacturerNameLength = lstrlen(pLocalData->DrvInfo.pszManufacturer);
if (cManufacturerNameLength)
{
cDriverNameLength = lstrlen(pLocalData->DrvInfo.pszModelName);
if (cDriverNameLength)
{
clpFileBufferLength = cProviderNameLength + 1 +
cManufacturerNameLength + 1 +
cDriverNameLength + 1 +
1;
DownLoadInfo.lpFile = (LPTSTR)LocalAllocMem(clpFileBufferLength * sizeof(TCHAR));
if (DownLoadInfo.lpFile)
{
lstrcpy( (LPTSTR)(DownLoadInfo.lpFile), (LPTSTR)(pLocalData->DrvInfo.pszProvider));
lstrcpy( (LPTSTR)(DownLoadInfo.lpFile + cProviderNameLength + 1), (LPTSTR)(pLocalData->DrvInfo.pszManufacturer));
lstrcpy( (LPTSTR)(DownLoadInfo.lpFile + cProviderNameLength + 1 + cManufacturerNameLength + 1), (LPTSTR)(pLocalData->DrvInfo.pszModelName));
}
}
}
}
}
if ( !gpCodeDownLoadInfo->pfnDownload(gpCodeDownLoadInfo->hConnection,
hwnd,
&DownLoadInfo,
szSourceDir,
SIZECHARS(szSourceDir),
&uNeeded) )
goto Cleanup;
// Now rework install data based on the actual INF
pNewLocalData = RebuildDeviceInfo( hDevInfo, pLocalData, szSourceDir );
if ( pNewLocalData == NULL )
goto Cleanup;
pNewLocalData->DrvInfo.Flags |= SDFLAG_CDM_DRIVER;
dwReturn = InstallDriverFromCurrentInf(hDevInfo,
pNewLocalData,
hwnd,
platform,
dwThisMajorVersion,
pszServerName,
INVALID_HANDLE_VALUE,
NULL,
NULL,
0,
szSourceDir,
DRVINST_FLATSHARE | DRVINST_NO_WARNING_PROMPT,
APD_COPY_NEW_FILES,
NULL,
NULL,
NULL);
(VOID) DeleteAllFilesInDirectory(szSourceDir, TRUE);
if ( dwReturn == ERROR_SUCCESS )
bRet = TRUE;
Cleanup:
if ( pNewLocalData )
DestroyLocalData( pNewLocalData );
LocalFreeMem((PVOID)DownLoadInfo.lpHardwareIDs);
LocalFreeMem((PVOID)DownLoadInfo.lpFile);
CleanupScratchDirectory(pszServerName, platform);
if ( !bRet && ( dwReturn == ERROR_SUCCESS ) )
dwReturn = STG_E_UNKNOWN;
return dwReturn;
}
/*++
Routine Name:
PSetupInstallInboxDriverSilently
Routine Description:
This is used to install inbox drivers silently. The driver must exist in
ntprint.inf. The inf isn't passed in to make the only code that needs to know
about ntprint.inf reside in setup.
Arguments:
pszDriverName - The driver name that we want to install.
Return Value:
BOOL, Last error
--*/
DWORD
PSetupInstallInboxDriverSilently(
IN LPCTSTR pszDriverName
)
{
DWORD Status = ERROR_SUCCESS;
TCHAR szInfFile[MAX_PATH];
Status = pszDriverName ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
//
// Get the system directory.
//
if (Status == ERROR_SUCCESS)
{
Status = GetSystemWindowsDirectory(szInfFile, COUNTOF(szInfFile)) ? ERROR_SUCCESS : GetLastError();
}
if (Status == ERROR_SUCCESS)
{
Status = StrNCatBuff(szInfFile, COUNTOF(szInfFile), szInfFile, TEXT("\\"), szNtPrintInf, NULL);
}
if (Status == ERROR_SUCCESS)
{
Status = InstallDriverSilently(szInfFile, pszDriverName, NULL);
}
return Status;
}
/*++
Routine Name:
InstallDriverSilently
Routine Description:
Install the given printer driver from the given inf from the optional
source directory, do not pop up UI and fail if UI would be required.
Arguments:
pszInfFile - The inf file to install the driver from.
pszDriverName - The driver name.
pszSource - The source installation location.
Return Value:
BOOL, Last error
--*/
DWORD
InstallDriverSilently(
IN LPCTSTR pszInfFile,
IN LPCTSTR pszDriverName,
IN LPCTSTR pszSource
)
{
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
DWORD dwInstallFlags = DRVINST_PROGRESSLESS | DRVINST_PROMPTLESS;
PPSETUP_LOCAL_DATA pData = NULL;
DWORD Status = ERROR_SUCCESS;
Status = pszInfFile && pszDriverName ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
//
// Ensure that setupapi does not throw any UI
//
SetupSetNonInteractiveMode(TRUE);
if (Status == ERROR_SUCCESS)
{
if ((hDevInfo = PSetupCreatePrinterDeviceInfoList(NULL)) != INVALID_HANDLE_VALUE &&
PSetupBuildDriversFromPath(hDevInfo, pszInfFile, TRUE) &&
PSetupPreSelectDriver(hDevInfo, NULL, pszDriverName) &&
(pData = BuildInternalData(hDevInfo, NULL)) != NULL &&
ParseInf(hDevInfo, pData, MyPlatform, NULL, dwInstallFlags))
{
Status = ERROR_SUCCESS;
}
else
{
//
// Ensure that if we have a failure the return is shown as such.
//
Status = GetLastError();
Status = Status == ERROR_SUCCESS ? ERROR_INVALID_DATA : Status;
}
}
if (Status == ERROR_SUCCESS)
{
//
// We don't want to launch a vendor setup entry, but vendor setup
// only gets launch after an AddPrinter call, which we're not doing - just adding drivers here.
// NOTE: For future if this included Queue creation we WILL have to handle this.
//
Status = PSetupInstallPrinterDriver(hDevInfo,
pData,
NULL,
MyPlatform,
dwThisMajorVersion,
NULL,
NULL,
NULL,
pszSource,
dwInstallFlags,
APD_COPY_NEW_FILES,
NULL);
}
//
// Switch on setupapi UI again
//
SetupSetNonInteractiveMode(FALSE);
if(pData != NULL)
{
PSetupDestroySelectedDriverInfo(pData);
}
//
// Release the driver setup parameter handle.
//
if(hDevInfo != INVALID_HANDLE_VALUE)
{
PSetupDestroyPrinterDeviceInfoList( hDevInfo );
}
return Status;
}