1771 lines
47 KiB
C
1771 lines
47 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Util.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Driver Setup UI Utility functions
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Muhunthan Sivapragasam (MuhuntS) 06-Sep-1995
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
//
|
||
|
// Keys to search for in ntprint.inf
|
||
|
//
|
||
|
TCHAR cszDataSection[] = TEXT("DataSection");
|
||
|
TCHAR cszDriverFile[] = TEXT("DriverFile");
|
||
|
TCHAR cszConfigFile[] = TEXT("ConfigFile");
|
||
|
TCHAR cszDataFile[] = TEXT("DataFile");
|
||
|
TCHAR cszHelpFile[] = TEXT("HelpFile");
|
||
|
TCHAR cszDefaultDataType[] = TEXT("DefaultDataType");
|
||
|
TCHAR cszLanguageMonitor[] = TEXT("LanguageMonitor");
|
||
|
TCHAR cszCopyFiles[] = TEXT("CopyFiles");
|
||
|
TCHAR cszComma[] = TEXT(",");
|
||
|
|
||
|
TCHAR cszPrinterInf[] = TEXT("printer.inf");
|
||
|
TCHAR cszNtprintInf[] = TEXT("ntprint.inf");
|
||
|
|
||
|
TCHAR sComma = TEXT(',');
|
||
|
TCHAR sHash = TEXT('@');
|
||
|
TCHAR sBackSlash = TEXT('\\');
|
||
|
TCHAR sZero = TEXT('\0');
|
||
|
|
||
|
//
|
||
|
// Native environment name used by spooler
|
||
|
//
|
||
|
PLATFORMINFO PlatformEnv[] = {
|
||
|
|
||
|
{ TEXT("Windows NT Alpha_AXP") },
|
||
|
{ TEXT("Windows NT x86") },
|
||
|
{ TEXT("Windows NT R4000") },
|
||
|
{ TEXT("Windows NT PowerPC") },
|
||
|
{ TEXT("Windows 4.0") }
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Platform override strings to be used to upgrade non-native architecture
|
||
|
// printer drivers
|
||
|
//
|
||
|
PLATFORMINFO PlatformOverride[] = {
|
||
|
|
||
|
{ TEXT("alpha") },
|
||
|
{ TEXT("i386") },
|
||
|
{ TEXT("mips") },
|
||
|
{ TEXT("ppc") },
|
||
|
{ TEXT("") } // will not be accessed
|
||
|
};
|
||
|
|
||
|
|
||
|
PLATFORM MyPlatform =
|
||
|
#if defined(_ALPHA_)
|
||
|
PlatformAlpha;
|
||
|
#elif defined(_MIPS_)
|
||
|
PlatformMIPS;
|
||
|
#elif defined(_PPC_)
|
||
|
PlatformPPC;
|
||
|
#elif defined(_X86_)
|
||
|
PlatformX86;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Forward declaration
|
||
|
//
|
||
|
VOID
|
||
|
InfGetDependentFiles(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR pszDriverSection,
|
||
|
IN LPCTSTR pszDataSection,
|
||
|
IN BOOL bDataSection,
|
||
|
OUT LPTSTR *ppszData,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
);
|
||
|
|
||
|
PVOID
|
||
|
AllocMem(
|
||
|
IN UINT cbSize
|
||
|
)
|
||
|
{
|
||
|
return LocalAlloc(LPTR, cbSize);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FreeMem(
|
||
|
IN PVOID p
|
||
|
)
|
||
|
{
|
||
|
LocalFree(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
LPTSTR
|
||
|
AllocStr(
|
||
|
LPCTSTR pszStr
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Allocate memory and make a copy of a string field
|
||
|
|
||
|
Arguments:
|
||
|
pszStr : String to copy
|
||
|
|
||
|
Return Value:
|
||
|
Pointer to the copied string. Memory is allocated.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
LPTSTR pszRet = NULL;
|
||
|
|
||
|
if ( pszStr && *pszStr ) {
|
||
|
|
||
|
pszRet = AllocMem((lstrlen(pszStr) + 1) * sizeof(*pszRet));
|
||
|
if ( pszRet )
|
||
|
lstrcpy(pszRet, pszStr);
|
||
|
}
|
||
|
|
||
|
return pszRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FreeStr(
|
||
|
LPTSTR pszStr
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Free memory allocated for a string
|
||
|
|
||
|
Arguments:
|
||
|
pszStr : String to free memory
|
||
|
|
||
|
Return Value:
|
||
|
Nothing
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if ( pszStr )
|
||
|
FreeMem((PVOID)pszStr);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
InfGetString(
|
||
|
IN PINFCONTEXT pInfContext,
|
||
|
IN DWORD dwFieldIndex,
|
||
|
OUT LPTSTR *ppszField,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Allocates memory and gets a string field from an Inf file
|
||
|
|
||
|
Arguments:
|
||
|
lpInfContext : Inf context for the line
|
||
|
dwFieldIndex : Index of the field within the specified line
|
||
|
ppszField : Pointer to the field to allocate memory and copy
|
||
|
pbFail : Set on error, could be TRUE when called
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; If *pbFail is not TRUE memory is allocated and the field is copied
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TCHAR Buffer[MAX_PATH];
|
||
|
DWORD dwNeeded;
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
if ( SetupGetStringField(pInfContext,
|
||
|
dwFieldIndex,
|
||
|
Buffer,
|
||
|
sizeof(Buffer)/sizeof(Buffer[0]),
|
||
|
&dwNeeded) ) {
|
||
|
|
||
|
*ppszField = AllocStr(Buffer);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
||
|
!(*ppszField = AllocMem(dwNeeded*sizeof(Buffer[0]))) ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !SetupGetStringField(pInfContext,
|
||
|
dwFieldIndex,
|
||
|
*ppszField,
|
||
|
dwNeeded,
|
||
|
&dwNeeded) ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
InfGetMultiSz(
|
||
|
IN PINFCONTEXT pInfContext,
|
||
|
IN DWORD dwFieldIndex,
|
||
|
OUT LPTSTR *ppszField,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Allocates memory and gets a multi-sz field from an Inf file
|
||
|
|
||
|
Arguments:
|
||
|
lpInfContext : Inf context for the line
|
||
|
dwFieldIndex : Index of the field within the specified line
|
||
|
ppszField : Pointer to the field to allocate memory and copy
|
||
|
pbFail : Set on error, could be TRUE when called
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; If *pbFail is not TRUE memory is allocated and the field is copied
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TCHAR Buffer[MAX_PATH];
|
||
|
DWORD dwNeeded;
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
if ( SetupGetMultiSzField(pInfContext,
|
||
|
dwFieldIndex,
|
||
|
Buffer,
|
||
|
sizeof(Buffer)/sizeof(Buffer[0]),
|
||
|
&dwNeeded) ) {
|
||
|
|
||
|
*ppszField = AllocMem(dwNeeded*sizeof(Buffer[0]));
|
||
|
if ( *ppszField )
|
||
|
CopyMemory(*ppszField, Buffer, dwNeeded * sizeof(Buffer[0]));
|
||
|
else
|
||
|
*pbFail = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
||
|
!(*ppszField = AllocMem(dwNeeded * sizeof(Buffer[0]))) ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !SetupGetMultiSzField(pInfContext,
|
||
|
dwFieldIndex,
|
||
|
*ppszField,
|
||
|
dwNeeded,
|
||
|
&dwNeeded) ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
InfGetDriverInfoString(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR pszDriverSection,
|
||
|
IN LPCTSTR pszDataSection, OPTIONAL
|
||
|
IN BOOL bDataSection,
|
||
|
IN LPCTSTR pszKey,
|
||
|
OUT LPTSTR *ppszData,
|
||
|
IN LPCTSTR pszDefaultData,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Allocates memory and gets a driver info field from an inf file
|
||
|
|
||
|
Arguments:
|
||
|
hInf : Handle to the Inf file
|
||
|
pszDriverSection : Section name for the driver
|
||
|
pszDataSection : Data section for the driver (optional)
|
||
|
bDataSection : Specifies if there is a data section
|
||
|
pszKey : Key value of the field to look for
|
||
|
*ppszData : Pointer to allocate memory and copy the data field
|
||
|
pszDefaultData : If key found this is the default value, coule be NULL
|
||
|
*pbFail : Set on error, could be TRUE when called
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; If *pbFail is not TRUE memory is allocated and the field is copied
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
INFCONTEXT InfContext;
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
if ( SetupFindFirstLine(hInf, pszDriverSection,
|
||
|
pszKey, &InfContext) ||
|
||
|
(bDataSection && SetupFindFirstLine(hInf,
|
||
|
pszDataSection,
|
||
|
pszKey,
|
||
|
&InfContext)) ) {
|
||
|
|
||
|
InfGetString(&InfContext, 1, ppszData, pbFail);
|
||
|
} else if ( pszDefaultData && *pszDefaultData ) {
|
||
|
|
||
|
if ( !(*ppszData = AllocStr(pszDefaultData)) )
|
||
|
*pbFail = TRUE;
|
||
|
} else
|
||
|
*ppszData = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PSetupDestroyDriverInfo3(
|
||
|
IN LPDRIVER_INFO_3 pDriverInfo3
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Frees memory allocated for a DRIVER_INFO_3 structure and all the string
|
||
|
fields in it
|
||
|
|
||
|
Arguments:
|
||
|
pDriverInfo3 : Pointer to the DRIVER_INFO_3 structure to free memory
|
||
|
|
||
|
Return Value:
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
if ( pDriverInfo3 ) {
|
||
|
|
||
|
FreeStr(pDriverInfo3->pName);
|
||
|
FreeStr(pDriverInfo3->pDriverPath);
|
||
|
FreeStr(pDriverInfo3->pDataFile);
|
||
|
FreeStr(pDriverInfo3->pConfigFile);
|
||
|
FreeStr(pDriverInfo3->pHelpFile);
|
||
|
FreeStr(pDriverInfo3->pMonitorName);
|
||
|
FreeStr(pDriverInfo3->pDefaultDataType);
|
||
|
|
||
|
if ( pDriverInfo3->pDependentFiles )
|
||
|
FreeMem(pDriverInfo3->pDependentFiles);
|
||
|
|
||
|
FreeMem(pDriverInfo3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
LPDRIVER_INFO_3
|
||
|
InfGetDriverInfo3(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR pszModelName,
|
||
|
IN LPCTSTR pszDriverSection
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Copies driver information from an Inf file to a DriverInfo3 structure.
|
||
|
|
||
|
The following fields are filled on successful return
|
||
|
pName
|
||
|
pDriverPath
|
||
|
pDataFile
|
||
|
pConfigFile
|
||
|
pHelpFile
|
||
|
pMonitorName
|
||
|
pDefaultDataType
|
||
|
|
||
|
Arguments:
|
||
|
hInf : Handle to the inf file to parse
|
||
|
pszModelName : Selected driver model name
|
||
|
pszDriverSection : Section name for the selected driver model
|
||
|
|
||
|
Return Value:
|
||
|
TRUE -- No error retrieving the driver information. Above mentioned
|
||
|
fields are filled, with memory allocation
|
||
|
FALSE -- Error
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDRIVER_INFO_3 pDriverInfo3;
|
||
|
LPTSTR pszDataSection;
|
||
|
BOOL bFail = FALSE, bDataSection = FALSE;
|
||
|
INFCONTEXT Context;
|
||
|
|
||
|
pszDataSection = NULL;
|
||
|
pDriverInfo3 = (PDRIVER_INFO_3) AllocMem(sizeof(DRIVER_INFO_3));
|
||
|
|
||
|
if ( !pDriverInfo3 ) {
|
||
|
|
||
|
bFail = TRUE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
ZeroMemory(pDriverInfo3, sizeof(DRIVER_INFO_3));
|
||
|
pDriverInfo3->pName = AllocStr(pszModelName);
|
||
|
|
||
|
if ( !pDriverInfo3->pName )
|
||
|
bFail = TRUE;
|
||
|
|
||
|
//
|
||
|
// Does the driver section have a data section name specified?
|
||
|
//
|
||
|
if ( SetupFindFirstLine(hInf, pszDriverSection,
|
||
|
cszDataSection, &Context) ) {
|
||
|
|
||
|
InfGetString(&Context, 1, &pszDataSection, &bFail);
|
||
|
bDataSection = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If DataFile key is not found data file is same as driver section name
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszDataFile,
|
||
|
&pDriverInfo3->pDataFile,
|
||
|
pszDriverSection,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// If DriverFile key is not found driver file is the driver section name
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszDriverFile,
|
||
|
&pDriverInfo3->pDriverPath,
|
||
|
pszDriverSection,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// If ConfigFile key is not found config file is same as driver file
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszConfigFile,
|
||
|
&pDriverInfo3->pConfigFile,
|
||
|
pDriverInfo3->pDriverPath,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// Help file is optional, and by default NULL
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszHelpFile,
|
||
|
&pDriverInfo3->pHelpFile,
|
||
|
NULL,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// Monitor name is optional, and by default none
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszLanguageMonitor,
|
||
|
&pDriverInfo3->pMonitorName,
|
||
|
NULL,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// Language monitor field is of the form "Monitor Name, Monitor.dll"
|
||
|
// we will replace , with \0 so that we can get dll name and install
|
||
|
// print monitor too
|
||
|
//
|
||
|
if ( pDriverInfo3->pMonitorName ) {
|
||
|
|
||
|
if ( !lstrtok(pDriverInfo3->pMonitorName, cszComma) ) {
|
||
|
|
||
|
bFail = TRUE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Default data type is optional, and by default none
|
||
|
//
|
||
|
InfGetDriverInfoString(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
cszDefaultDataType,
|
||
|
&pDriverInfo3->pDefaultDataType,
|
||
|
NULL,
|
||
|
&bFail);
|
||
|
|
||
|
InfGetDependentFiles(hInf,
|
||
|
pszDriverSection,
|
||
|
pszDataSection,
|
||
|
bDataSection,
|
||
|
&pDriverInfo3->pDependentFiles,
|
||
|
&bFail);
|
||
|
Cleanup:
|
||
|
|
||
|
FreeStr(pszDataSection);
|
||
|
|
||
|
//
|
||
|
// On failure free all the fields filled by this routine
|
||
|
//
|
||
|
if ( bFail || !pDriverInfo3->pDependentFiles ) {
|
||
|
|
||
|
PSetupDestroyDriverInfo3(pDriverInfo3);
|
||
|
pDriverInfo3 = NULL;
|
||
|
}
|
||
|
|
||
|
return pDriverInfo3;
|
||
|
}
|
||
|
|
||
|
|
||
|
LPDRIVER_INFO_3
|
||
|
PSetupGetDriverInfo3(
|
||
|
IN PSELECTED_DRV_INFO pSelectedDrvInfo
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Gets the selected drivers information in a DRIVER_INFO_3 structure
|
||
|
|
||
|
Arguments:
|
||
|
pSelectedDrvInfo : Points to a valid SELECTED_DRV_INFO
|
||
|
|
||
|
Return Value:
|
||
|
Pointer to the DRIVER_INFO_3 structure. Memory is allocated for it.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HINF hInf;
|
||
|
LPDRIVER_INFO_3 pDriverInfo3;
|
||
|
|
||
|
if ( !pSelectedDrvInfo ||
|
||
|
!pSelectedDrvInfo->pszInfFile ||
|
||
|
!*pSelectedDrvInfo->pszInfFile ||
|
||
|
!pSelectedDrvInfo->pszModelName ||
|
||
|
!*pSelectedDrvInfo->pszModelName ||
|
||
|
!pSelectedDrvInfo->pszDriverSection ||
|
||
|
!*pSelectedDrvInfo->pszDriverSection ) {
|
||
|
|
||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
hInf = SetupOpenInfFile(pSelectedDrvInfo->pszInfFile,
|
||
|
NULL,
|
||
|
INF_STYLE_WIN4,
|
||
|
NULL);
|
||
|
|
||
|
if ( hInf == INVALID_HANDLE_VALUE ) {
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
pDriverInfo3 = InfGetDriverInfo3(hInf,
|
||
|
pSelectedDrvInfo->pszModelName,
|
||
|
pSelectedDrvInfo->pszDriverSection);
|
||
|
|
||
|
SetupCloseInfFile(hInf);
|
||
|
|
||
|
return pDriverInfo3;
|
||
|
}
|
||
|
VOID
|
||
|
GetFilesInSection(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR szSection,
|
||
|
IN OUT LPTSTR pszFiles[],
|
||
|
IN OUT LPDWORD pdwFileCount,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Gets all the filenames in a section (the section consists of list of
|
||
|
filenames one per line) of an Inf file.
|
||
|
|
||
|
Arguments:
|
||
|
HINF : Inf handle
|
||
|
szSection : Section name
|
||
|
pszFiles : Array to build the filenames
|
||
|
pFileCount : Pointer to file count (for files in pszFiles list)
|
||
|
pbFail : Set on error
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; On error *pbFail is set. Else filenames are added in the list
|
||
|
allocating memory for them
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
INFCONTEXT InfContext;
|
||
|
LONG Index, Count;
|
||
|
|
||
|
Count = SetupGetLineCount(hInf, szSection);
|
||
|
if ( Count == -1 ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for ( Index = 0 ; Index < Count ; ++Index ) {
|
||
|
|
||
|
SetupGetLineByIndex(hInf, szSection, Index, &InfContext);
|
||
|
InfGetString(&InfContext, 1, pszFiles+*pdwFileCount, pbFail);
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
++(*pdwFileCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BuildFileList(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR szFileList,
|
||
|
IN LPTSTR pszFiles[],
|
||
|
IN OUT LPDWORD pdwFileCount,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Build the list of filenames to be copied from a CopyFiles field from
|
||
|
the Inf file
|
||
|
|
||
|
Arguments:
|
||
|
hInf : Inf file handle
|
||
|
szFileList : CopyFiles field read from the Inf file
|
||
|
pszFiles : Array to build the filenames (there may be some entries)
|
||
|
pdwFileCount: File count (for files in pszFiles list)
|
||
|
pbFail : Set on error
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; On error *pbFail is set. Else memory is allocated for filenames
|
||
|
and they are put in the pszFiles list
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
while ( !*pbFail && szFileList && *szFileList ) {
|
||
|
|
||
|
//
|
||
|
// Anything following @ is a filename, others are section name
|
||
|
// giving list of filenames
|
||
|
//
|
||
|
if ( szFileList[0] == sHash ) {
|
||
|
|
||
|
pszFiles[*pdwFileCount] = AllocStr(szFileList+1);
|
||
|
if ( !pszFiles[*pdwFileCount] )
|
||
|
*pbFail = TRUE;
|
||
|
else
|
||
|
++(*pdwFileCount);
|
||
|
} else {
|
||
|
|
||
|
GetFilesInSection(hInf, szFileList, pszFiles, pdwFileCount, pbFail);
|
||
|
}
|
||
|
|
||
|
szFileList += lstrlen(szFileList) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
BuildDependentFilesFromFileList(
|
||
|
IN LPTSTR pszFiles[],
|
||
|
IN DWORD dwFileCount,
|
||
|
OUT LPTSTR *pszData,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Build the dependent files field (a MultiSz field of filenames) from an
|
||
|
array of filenames
|
||
|
|
||
|
Arguments:
|
||
|
pszFiles : Array of filenames
|
||
|
dwFileCount : File count (for files in pszFiles list)
|
||
|
pszData : Pointer to the DependentFiles field
|
||
|
pbFail : Set on error
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; On error *pbFail is set. Else memory is allocated to *pszData
|
||
|
and DependentFiles field built
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwIndex, cbLen;
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
for ( dwIndex = cbLen = 0 ; dwIndex < dwFileCount ; ++dwIndex)
|
||
|
cbLen += lstrlen(pszFiles[dwIndex]) + 1;
|
||
|
|
||
|
// For the last \0
|
||
|
++cbLen;
|
||
|
|
||
|
if ( *pszData = AllocMem(cbLen*sizeof(TCHAR)) ) {
|
||
|
|
||
|
for ( dwIndex = cbLen = 0 ; dwIndex < dwFileCount ; ++dwIndex) {
|
||
|
|
||
|
lstrcpy(*pszData+cbLen, pszFiles[dwIndex]);
|
||
|
cbLen += lstrlen(pszFiles[dwIndex]) + 1;
|
||
|
}
|
||
|
|
||
|
(*pszData)[cbLen] = 0;
|
||
|
} else {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
InfGetDependentFiles(
|
||
|
IN HINF hInf,
|
||
|
IN LPCTSTR szDriverSection,
|
||
|
IN LPCTSTR szDataSection, OPTIONAL
|
||
|
IN BOOL bDataSection,
|
||
|
OUT LPTSTR *pszData,
|
||
|
IN OUT LPBOOL pbFail
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Build the dependent files field (MultiSz) for a driver. Dependent files
|
||
|
are all the files specified in the CopyFiles section of the driver,
|
||
|
data (optional) sections.
|
||
|
|
||
|
Anything following @ is a filename, others are section names
|
||
|
ex.
|
||
|
CopyFiles=@A_PNT518.PPD,PSCRIPT
|
||
|
|
||
|
[PSCRIPT]
|
||
|
PSCRIPT.DRV
|
||
|
PSCRIPT.HLP
|
||
|
PSCRIPT.INI
|
||
|
TESTPS.TXT
|
||
|
|
||
|
DependentFiles returned is
|
||
|
"A_PNT518.SPD\0PSCRIPT.DRV\0PSCRIPT.HLP\0PSCRIPT.INI\0TESTPS.TXT\0\0"
|
||
|
|
||
|
Arguments:
|
||
|
hInf : Inf file handle
|
||
|
szDriverSection : Driver section name
|
||
|
szDataSection : Data section name (optional)
|
||
|
bDataSection : Is ther a data section?
|
||
|
pszData : Pointer to the DependentFiles field
|
||
|
pbFail : Set on error
|
||
|
|
||
|
Return Value:
|
||
|
Nothing; On error *pbFail is set. Else memory is allocated to *pszData
|
||
|
and DependentFiles field built
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
INFCONTEXT InfContext;
|
||
|
LPTSTR szFileList1 = NULL, szFileList2 = NULL, p1, *pszFiles = NULL;
|
||
|
DWORD dwFileCount=0, dwCount;
|
||
|
|
||
|
if ( *pbFail )
|
||
|
return;
|
||
|
|
||
|
//
|
||
|
// Get the CopyFiles lines in the driver, data sections
|
||
|
//
|
||
|
if ( SetupFindFirstLine(hInf, szDriverSection,
|
||
|
cszCopyFiles, &InfContext) ) {
|
||
|
|
||
|
InfGetMultiSz(&InfContext, 1, &szFileList1, pbFail);
|
||
|
}
|
||
|
|
||
|
if ( bDataSection &&
|
||
|
SetupFindFirstLine(hInf, szDataSection,
|
||
|
cszCopyFiles, &InfContext) ) {
|
||
|
|
||
|
InfGetMultiSz(&InfContext, 1, &szFileList2, pbFail);
|
||
|
}
|
||
|
|
||
|
if ( *pbFail )
|
||
|
goto Cleanup;
|
||
|
|
||
|
//
|
||
|
// Find the total number of filenames we have
|
||
|
//
|
||
|
for ( p1 = szFileList1 ; p1 && *p1 ; p1 += lstrlen(p1) + 1 ) {
|
||
|
|
||
|
//
|
||
|
// Anything starting with @ is a filename, else a section name
|
||
|
//
|
||
|
if ( p1[0] == sHash )
|
||
|
++dwFileCount;
|
||
|
else {
|
||
|
|
||
|
dwCount = SetupGetLineCount(hInf, p1);
|
||
|
if ( dwCount == -1 ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
dwFileCount = 0;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
dwFileCount += dwCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( p1 = szFileList2 ; p1 && *p1 ; p1 += lstrlen(p1) + 1 ) {
|
||
|
|
||
|
//
|
||
|
// Anything starting with @ is a filename, else a section name
|
||
|
//
|
||
|
if ( p1[0] == sHash )
|
||
|
++dwFileCount;
|
||
|
else {
|
||
|
|
||
|
dwCount = SetupGetLineCount(hInf, p1);
|
||
|
if ( dwCount == -1 ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
dwFileCount = 0;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
dwFileCount += dwCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( dwFileCount ) {
|
||
|
|
||
|
//
|
||
|
// Build the list of filenames
|
||
|
//
|
||
|
if ( !(pszFiles = AllocMem(dwFileCount * sizeof(LPTSTR))) ) {
|
||
|
|
||
|
*pbFail = TRUE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwFileCount = 0;
|
||
|
BuildFileList(hInf, szFileList1, pszFiles, &dwFileCount, pbFail);
|
||
|
BuildFileList(hInf, szFileList2, pszFiles, &dwFileCount, pbFail);
|
||
|
|
||
|
//
|
||
|
// Convert list of filenames to a MultiSz field
|
||
|
//
|
||
|
BuildDependentFilesFromFileList(pszFiles, dwFileCount, pszData, pbFail);
|
||
|
}
|
||
|
|
||
|
|
||
|
Cleanup:
|
||
|
FreeStr(szFileList1);
|
||
|
FreeStr(szFileList2);
|
||
|
while ( dwFileCount )
|
||
|
FreeStr(pszFiles[--dwFileCount]);
|
||
|
if ( pszFiles )
|
||
|
FreeMem(pszFiles);
|
||
|
}
|
||
|
|
||
|
|
||
|
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 ( !lstrcmp(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_3 pDriverInfo3,
|
||
|
IN LPCTSTR pszSourcePath,
|
||
|
IN LPCTSTR pszDiskName,
|
||
|
IN LPCTSTR pszTargetPath,
|
||
|
IN HWND hwnd,
|
||
|
IN BOOL bForgetSource
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Copy printer driver files to a specified directory using SetupQueue APIs
|
||
|
|
||
|
Arguments:
|
||
|
pDriverInfo3 : 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;
|
||
|
PVOID QueueContext = NULL;
|
||
|
BOOL bFail = FALSE;
|
||
|
DWORD dwOldCount, dwNewCount, dwIndex;
|
||
|
LPTSTR psz, *List = NULL;
|
||
|
|
||
|
//
|
||
|
// Valid DriverInfo3
|
||
|
//
|
||
|
if ( !pDriverInfo3 ||
|
||
|
!pDriverInfo3->pDriverPath ||
|
||
|
!pDriverInfo3->pDataFile ||
|
||
|
!pDriverInfo3->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.
|
||
|
//
|
||
|
CopyQueue = SetupOpenFileQueue();
|
||
|
if( CopyQueue == INVALID_HANDLE_VALUE ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
CheckAndEnqueueOneFile(pDriverInfo3->pDriverPath,
|
||
|
pDriverInfo3->pDependentFiles,
|
||
|
CopyQueue,
|
||
|
pszSourcePath,
|
||
|
pszTargetPath,
|
||
|
pszDiskName,
|
||
|
&bFail);
|
||
|
|
||
|
CheckAndEnqueueOneFile(pDriverInfo3->pDataFile,
|
||
|
pDriverInfo3->pDependentFiles,
|
||
|
CopyQueue,
|
||
|
pszSourcePath,
|
||
|
pszTargetPath,
|
||
|
pszDiskName,
|
||
|
&bFail);
|
||
|
|
||
|
CheckAndEnqueueOneFile(pDriverInfo3->pConfigFile,
|
||
|
pDriverInfo3->pDependentFiles,
|
||
|
CopyQueue,
|
||
|
pszSourcePath,
|
||
|
pszTargetPath,
|
||
|
pszDiskName,
|
||
|
&bFail);
|
||
|
|
||
|
if ( pDriverInfo3->pHelpFile && *pDriverInfo3->pHelpFile )
|
||
|
CheckAndEnqueueOneFile(pDriverInfo3->pHelpFile,
|
||
|
pDriverInfo3->pDependentFiles,
|
||
|
CopyQueue,
|
||
|
pszSourcePath,
|
||
|
pszTargetPath,
|
||
|
pszDiskName,
|
||
|
&bFail);
|
||
|
|
||
|
//
|
||
|
// Add each file in the dependent files field to the setup queue
|
||
|
//
|
||
|
if ( pDriverInfo3->pDependentFiles ) {
|
||
|
|
||
|
for ( psz = pDriverInfo3->pDependentFiles ;
|
||
|
*psz ;
|
||
|
psz += lstrlen(psz) + 1 )
|
||
|
|
||
|
CheckAndEnqueueOneFile(psz,
|
||
|
NULL,
|
||
|
CopyQueue,
|
||
|
pszSourcePath,
|
||
|
pszTargetPath,
|
||
|
pszDiskName,
|
||
|
&bFail);
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( bFail )
|
||
|
goto Cleanup;
|
||
|
|
||
|
//
|
||
|
// Commit the file queue. This gets all files copied over.
|
||
|
//
|
||
|
QueueContext = SetupInitDefaultQueueCallback(hwnd);
|
||
|
if( !QueueContext ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
bFail = !SetupCommitFileQueue(hwnd,
|
||
|
CopyQueue,
|
||
|
SetupDefaultQueueCallback,
|
||
|
QueueContext);
|
||
|
|
||
|
//
|
||
|
// 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 ( QueueContext )
|
||
|
SetupTermDefaultQueueCallback(QueueContext);
|
||
|
|
||
|
return !bFail;
|
||
|
}
|
||
|
|
||
|
|
||
|
LPTSTR
|
||
|
GetStringFromRcFile(
|
||
|
UINT uId
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Load a string from the .rc file and make a copy of it by doing AllocStr
|
||
|
|
||
|
Arguments:
|
||
|
uId : Identifier for the string to be loaded
|
||
|
|
||
|
Return Value:
|
||
|
String value loaded, NULL on error. Caller should free the memory
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TCHAR buffer[MAX_SETUP_LEN];
|
||
|
|
||
|
LoadString(ghInst, uId, buffer, sizeof(buffer)/sizeof(buffer[0]));
|
||
|
|
||
|
return AllocStr(buffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
PSetupGetPathToSearch(
|
||
|
IN HWND hwnd,
|
||
|
IN LPCTSTR pszTitle,
|
||
|
IN LPCTSTR pszDiskName,
|
||
|
IN LPCTSTR pszFileName,
|
||
|
OUT TCHAR szPath[MAX_PATH]
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Get path to search for some files by prompting the user
|
||
|
|
||
|
Arguments:
|
||
|
hwnd : Window handle of current top-level window
|
||
|
pszTitle : Title for the UI
|
||
|
pszDiskName : Diskname ot prompt the user
|
||
|
pszFileName : Name of the file we are looking for (NULL ok)
|
||
|
pszPath : Buffer to get the path entered by the user
|
||
|
|
||
|
Return Value:
|
||
|
TRUE on succesfully getting a path from user
|
||
|
FALSE else, Do GetLastError() to get the error
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwReturn, dwNeeded;
|
||
|
|
||
|
dwReturn = SetupPromptForDisk(hwnd,
|
||
|
pszTitle,
|
||
|
pszDiskName,
|
||
|
NULL,
|
||
|
pszFileName,
|
||
|
NULL,
|
||
|
IDF_NOBEEP,
|
||
|
szPath,
|
||
|
MAX_PATH,
|
||
|
&dwNeeded);
|
||
|
|
||
|
if ( dwReturn == DPROMPT_SUCCESS ) {
|
||
|
|
||
|
//
|
||
|
// Remove this from source list so that next time we are looking for
|
||
|
// native drivers we do not end up picking from wrong source
|
||
|
//
|
||
|
SetupRemoveFromSourceList(SRCLIST_SYSIFADMIN, szPath);
|
||
|
|
||
|
//
|
||
|
// Terminate with a \ at the end
|
||
|
//
|
||
|
dwNeeded = lstrlen(szPath);
|
||
|
if ( *(szPath + dwNeeded - 1) != sBackSlash &&
|
||
|
dwNeeded < MAX_PATH - 2 ) {
|
||
|
|
||
|
*(szPath + dwNeeded) = sBackSlash;
|
||
|
*(szPath + dwNeeded + 1) = sZero;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if ( dwReturn == DPROMPT_OUTOFMEMORY ||
|
||
|
dwReturn == DPROMPT_BUFFERTOOSMALL ) {
|
||
|
|
||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
} else {
|
||
|
|
||
|
SetLastError(ERROR_CANCELLED);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
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 szCmd[] = TEXT("%s\\SETUP.EXE -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 pszSetupCmd = NULL;
|
||
|
TCHAR szSystemPath[MAX_PATH];
|
||
|
STARTUPINFO StartupInfo;
|
||
|
PROCESS_INFORMATION ProcessInformation;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup.exe is in the system path
|
||
|
//
|
||
|
GetSystemDirectory(szSystemPath,
|
||
|
sizeof(szSystemPath)/sizeof(szSystemPath[0]));
|
||
|
|
||
|
if ( !pszServerName )
|
||
|
pszServerName = TEXT("");
|
||
|
|
||
|
dwSize = lstrlen(pszOption) + 1 + lstrlen(pszSourcePath) + 1 +
|
||
|
lstrlen(pszServerName) + 1+
|
||
|
lstrlen(szSystemPath) + 1 +
|
||
|
lstrlen(pszInfFile) + 1;
|
||
|
|
||
|
dwSize *= sizeof(TCHAR);
|
||
|
//
|
||
|
// 20 for window handle in ASCII
|
||
|
//
|
||
|
dwSize += sizeof(szCmd) + 20;
|
||
|
|
||
|
pszSetupCmd = (LPTSTR) AllocMem(dwSize);
|
||
|
|
||
|
if ( !pszSetupCmd ) {
|
||
|
|
||
|
dwLastError = GetLastError();
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Noe print the command to invoke setup with all the arguments
|
||
|
//
|
||
|
wsprintf(pszSetupCmd, szCmd, szSystemPath, 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(NULL, 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);
|
||
|
|
||
|
if ( dwLastError ) {
|
||
|
|
||
|
SetLastError(dwLastError=(DWORD)STG_E_UNKNOWN);
|
||
|
}
|
||
|
|
||
|
CloseHandle (ProcessInformation.hProcess);
|
||
|
CloseHandle (ProcessInformation.hThread);
|
||
|
|
||
|
EnableWindow (hwnd, TRUE);
|
||
|
|
||
|
SetForegroundWindow(hwnd);
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
if ( pszSetupCmd )
|
||
|
FreeMem(pszSetupCmd);
|
||
|
|
||
|
return dwLastError;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
InstallNt3xDriver(
|
||
|
IN HWND hwnd,
|
||
|
IN LPCTSTR pszDriverName,
|
||
|
IN PLATFORM platform,
|
||
|
IN LPCTSTR pszServerName,
|
||
|
IN LPCTSTR pszDiskName
|
||
|
)
|
||
|
{
|
||
|
LPTSTR pszTitle = NULL, pszFormat;
|
||
|
TCHAR szSourcePath[MAX_PATH], szInfPath[MAX_PATH];
|
||
|
DWORD dwLastError;
|
||
|
|
||
|
//
|
||
|
// Build strings to use in the path dialog ..
|
||
|
//
|
||
|
pszFormat = GetStringFromRcFile(IDS_DRIVERS_FOR_PLATFORM);
|
||
|
if ( pszFormat ) {
|
||
|
|
||
|
pszTitle = AllocMem((lstrlen(pszFormat) + lstrlen(pszDiskName) + 2)
|
||
|
* sizeof(*pszTitle));
|
||
|
if ( pszTitle )
|
||
|
wsprintf(pszTitle, pszFormat, pszDiskName);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Ask the user where the printer.inf, printer driver files reside
|
||
|
//
|
||
|
if ( !PSetupGetPathToSearch(hwnd, pszTitle, pszDiskName,
|
||
|
cszPrinterInf, szSourcePath) ) {
|
||
|
|
||
|
dwLastError = GetLastError();
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( MAX_PATH > lstrlen(szSourcePath) + lstrlen(cszPrinterInf) + 1 ) {
|
||
|
|
||
|
lstrcpy(szInfPath, szSourcePath);
|
||
|
lstrcat(szInfPath, cszPrinterInf);
|
||
|
} else {
|
||
|
|
||
|
SetLastError(dwLastError=ERROR_INSUFFICIENT_BUFFER);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
dwLastError = InvokeSetup(hwnd,
|
||
|
pszDriverName,
|
||
|
szInfPath,
|
||
|
szSourcePath,
|
||
|
pszServerName);
|
||
|
|
||
|
Cleanup:
|
||
|
|
||
|
FreeStr(pszTitle);
|
||
|
FreeStr(pszFormat);
|
||
|
|
||
|
return dwLastError;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
PSetupInstallPrinterDriver(
|
||
|
IN HANDLE h,
|
||
|
IN PSELECTED_DRV_INFO pSelectedDrvInfo,
|
||
|
IN PLATFORM platform,
|
||
|
IN BOOL bNt3xDriver,
|
||
|
IN LPCTSTR pszServerName,
|
||
|
IN HWND hwnd,
|
||
|
IN LPCTSTR pszDiskName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Copies all the necessary driver files to the printer driver directory so
|
||
|
that an AddPrinterDriver call could be made.
|
||
|
|
||
|
Arguments:
|
||
|
h : Handle to the printer class device information list
|
||
|
pSelectedDrvInfo: Points to the selected driver info
|
||
|
platform : Platform for which driver needs to be installed
|
||
|
bNt3xDriver : TRUE if installation is from printer.inf
|
||
|
(NULL for local)
|
||
|
pszServerName : Server for which driver is to be installed (NULL : local)
|
||
|
hwnd : Window handle of current top-level window. If this
|
||
|
routine needes to put up any UI, this window will
|
||
|
become the dialog's owner.
|
||
|
pszDiskName : Disk name to prompt for (ONLY for non 4.0 driver)
|
||
|
|
||
|
Return Value:
|
||
|
On succesfully copying files ERROR_SUCCESS, else the error code
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
|
||
|
Retry:
|
||
|
//
|
||
|
// 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 ) {
|
||
|
|
||
|
dwRet = InstallWin95Driver(hwnd, pSelectedDrvInfo->pszModelName,
|
||
|
pszServerName, pszDiskName);
|
||
|
} else if ( bNt3xDriver ) {
|
||
|
|
||
|
dwRet = InstallNt3xDriver(hwnd,
|
||
|
pSelectedDrvInfo->pszModelName,
|
||
|
platform,
|
||
|
pszServerName,
|
||
|
pszDiskName);
|
||
|
} else {
|
||
|
|
||
|
dwRet = InstallDriverFromCurrentInf(h,
|
||
|
hwnd,
|
||
|
pSelectedDrvInfo,
|
||
|
platform,
|
||
|
pszServerName);
|
||
|
}
|
||
|
|
||
|
if ( dwRet == ERROR_EXE_MACHINE_TYPE_MISMATCH ) {
|
||
|
|
||
|
int i;
|
||
|
TCHAR szTitle[256], szMsg[256];
|
||
|
|
||
|
LoadString(ghInst,
|
||
|
IDS_INVALID_DRIVER,
|
||
|
szTitle,
|
||
|
sizeof(szTitle)/sizeof(szTitle[0]));
|
||
|
|
||
|
LoadString(ghInst,
|
||
|
IDS_WRONG_ARCHITECTURE,
|
||
|
szMsg,
|
||
|
sizeof(szMsg)/sizeof(szMsg[0]));
|
||
|
|
||
|
i = MessageBox(hwnd,
|
||
|
szMsg,
|
||
|
szTitle,
|
||
|
MB_RETRYCANCEL | MB_ICONSTOP | MB_DEFBUTTON1 | MB_APPLMODAL);
|
||
|
|
||
|
if ( i == IDRETRY )
|
||
|
goto Retry;
|
||
|
else {
|
||
|
|
||
|
SetLastError(dwRet =ERROR_CANCELLED);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
PSetupIsDriverInstalled(
|
||
|
IN LPCTSTR pszServerName,
|
||
|
IN LPCTSTR pszDriverName,
|
||
|
IN PLATFORM platform,
|
||
|
IN DWORD dwMajorVersion
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Findsout if a particular version of a printer driver is already installed
|
||
|
in the system by querying spooler
|
||
|
|
||
|
Arguments:
|
||
|
pszServerName : Server name (NULL for local)
|
||
|
szDriverName : Driver name
|
||
|
platform : platform for which we want to check the driver
|
||
|
dwMajorVersion : Version no
|
||
|
|
||
|
Return Value:
|
||
|
TRUE if driver is installed,
|
||
|
FALSE else (on error too)
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL bReturn = FALSE;
|
||
|
DWORD dwReturned, dwNeeded;
|
||
|
LPBYTE p = NULL;
|
||
|
LPDRIVER_INFO_2 pDriverInfo2;
|
||
|
|
||
|
if ( !EnumPrinterDrivers((LPTSTR)pszServerName,
|
||
|
PlatformEnv[platform].pszName,
|
||
|
2,
|
||
|
NULL,
|
||
|
0,
|
||
|
&dwNeeded,
|
||
|
&dwReturned) &&
|
||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
|
||
|
|
||
|
p = AllocMem(dwNeeded);
|
||
|
if ( !p ||
|
||
|
!EnumPrinterDrivers((LPTSTR)pszServerName,
|
||
|
PlatformEnv[platform].pszName,
|
||
|
2,
|
||
|
p,
|
||
|
dwNeeded,
|
||
|
&dwNeeded,
|
||
|
&dwReturned) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
for ( dwNeeded = 0, pDriverInfo2 = (LPDRIVER_INFO_2) p ;
|
||
|
dwNeeded < dwReturned ;
|
||
|
++dwNeeded, (LPBYTE) pDriverInfo2 += sizeof(DRIVER_INFO_2) ) {
|
||
|
|
||
|
if ( pDriverInfo2->cVersion == dwMajorVersion &&
|
||
|
!lstrcmp(pDriverInfo2->pName, pszDriverName) ) {
|
||
|
|
||
|
bReturn = TRUE;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
if ( p )
|
||
|
FreeMem(p);
|
||
|
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
PLATFORM
|
||
|
PSetupThisPlatform(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
return MyPlatform;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
AddPrinterDriverUsingDriverInfo2(
|
||
|
IN LPCTSTR pszServerName,
|
||
|
IN LPDRIVER_INFO_3 pDriverInfo3
|
||
|
)
|
||
|
{
|
||
|
DRIVER_INFO_2 DriverInfo2;
|
||
|
|
||
|
DriverInfo2.cVersion = 0; //Not used by spooler
|
||
|
DriverInfo2.pName = pDriverInfo3->pName;
|
||
|
DriverInfo2.pEnvironment = pDriverInfo3->pEnvironment;
|
||
|
DriverInfo2.pDriverPath = pDriverInfo3->pDriverPath;
|
||
|
DriverInfo2.pDataFile = pDriverInfo3->pDataFile;
|
||
|
DriverInfo2.pConfigFile = pDriverInfo3->pConfigFile;
|
||
|
|
||
|
return AddPrinterDriver((LPTSTR)pszServerName,
|
||
|
2,
|
||
|
(LPBYTE)&DriverInfo2);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
InstallDriverFromCurrentInf(
|
||
|
IN HANDLE h,
|
||
|
IN HWND hwnd,
|
||
|
IN PSELECTED_DRV_INFO pSelectedDrvInfo,
|
||
|
IN PLATFORM platform,
|
||
|
IN LPCTSTR pszServerName
|
||
|
)
|
||
|
{
|
||
|
TCHAR szTargetPath[MAX_PATH],
|
||
|
szSourcePath[MAX_PATH],
|
||
|
szPathOnSource[MAX_PATH];
|
||
|
HINF hPrinterInf = INVALID_HANDLE_VALUE;
|
||
|
HSPFILEQ CopyQueue = INVALID_HANDLE_VALUE;
|
||
|
PVOID QueueContext = NULL;
|
||
|
BOOL bRet = FALSE, bFail = FALSE, bAddMon = FALSE;
|
||
|
LPDRIVER_INFO_3 pDriverInfo3 = NULL;
|
||
|
DWORD dwNeeded;
|
||
|
LPTSTR pMonitorDll = NULL,
|
||
|
szSecnWithExt[MAX_SECT_NAME_LEN];
|
||
|
HANDLE hMonInfo = NULL;
|
||
|
|
||
|
//
|
||
|
// Open INF file and append layout.inf specified in Version section
|
||
|
//
|
||
|
hPrinterInf = SetupOpenInfFile(pSelectedDrvInfo->pszInfFile,
|
||
|
NULL,
|
||
|
INF_STYLE_WIN4,
|
||
|
NULL);
|
||
|
|
||
|
if ( hPrinterInf == INVALID_HANDLE_VALUE )
|
||
|
goto Cleanup;
|
||
|
|
||
|
SetupOpenAppendInfFile(NULL, hPrinterInf, NULL);
|
||
|
|
||
|
//
|
||
|
// 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.
|
||
|
// Also note setup does not reset PlatformPath override. So we need to
|
||
|
// call this always
|
||
|
//
|
||
|
if ( !SetupDiGetActualSectionToInstall(
|
||
|
hPrinterInf,
|
||
|
pSelectedDrvInfo->pszDriverSection,
|
||
|
(LPTSTR)szSecnWithExt,
|
||
|
sizeof(szSecnWithExt)/sizeof(szSecnWithExt[0]),
|
||
|
&dwNeeded,
|
||
|
NULL) ||
|
||
|
!SetupSetPlatformPathOverride(PlatformOverride[platform].pszName) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
|
||
|
}
|
||
|
|
||
|
pDriverInfo3 = InfGetDriverInfo3(hPrinterInf,
|
||
|
pSelectedDrvInfo->pszModelName,
|
||
|
(LPTSTR)szSecnWithExt);
|
||
|
|
||
|
if ( !pDriverInfo3 ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
pDriverInfo3->pEnvironment = PlatformEnv[platform].pszName;
|
||
|
|
||
|
CopyQueue = SetupOpenFileQueue();
|
||
|
if( CopyQueue == INVALID_HANDLE_VALUE ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( platform == MyPlatform ) {
|
||
|
|
||
|
GetDriverPath(h, szSourcePath);
|
||
|
|
||
|
if ( pDriverInfo3->pMonitorName ) {
|
||
|
|
||
|
//
|
||
|
// The code which parses INF puts monitor dll name after \0
|
||
|
//
|
||
|
pMonitorDll = pDriverInfo3->pMonitorName +
|
||
|
lstrlen(pDriverInfo3->pMonitorName) + 1;
|
||
|
|
||
|
if ( !GetSystemDirectory(szTargetPath,
|
||
|
sizeof(szTargetPath)/sizeof(szTargetPath[0])) ||
|
||
|
!FindPathOnSource(pMonitorDll,
|
||
|
hPrinterInf,
|
||
|
szPathOnSource,
|
||
|
sizeof(szPathOnSource)/sizeof(szPathOnSource[0])) ||
|
||
|
|
||
|
!SetupQueueCopy(CopyQueue,
|
||
|
szSourcePath,
|
||
|
szPathOnSource,
|
||
|
pMonitorDll,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
szTargetPath,
|
||
|
NULL,
|
||
|
0) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
bAddMon = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !GetPrinterDriverDirectory((LPTSTR)pszServerName,
|
||
|
pDriverInfo3->pEnvironment,
|
||
|
1,
|
||
|
(LPBYTE)szTargetPath,
|
||
|
sizeof(szTargetPath),
|
||
|
&dwNeeded) ||
|
||
|
!SetupSetDirectoryId(hPrinterInf,
|
||
|
PRINTER_DRIVER_DIRECTORY_ID,
|
||
|
szTargetPath) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( !SetupInstallFilesFromInfSection(hPrinterInf,
|
||
|
NULL,
|
||
|
CopyQueue,
|
||
|
(LPTSTR)szSecnWithExt,
|
||
|
platform == MyPlatform ? szSourcePath : NULL,
|
||
|
0) ||
|
||
|
!(QueueContext = SetupInitDefaultQueueCallback(hwnd)) ||
|
||
|
!SetupCommitFileQueue(hwnd,
|
||
|
CopyQueue,
|
||
|
SetupDefaultQueueCallback,
|
||
|
QueueContext) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
if ( bAddMon &&
|
||
|
!AddPrintMonitor(pDriverInfo3->pMonitorName, pMonitorDll) ) {
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
bRet = AddPrinterDriver((LPTSTR)pszServerName, 3, (LPBYTE)pDriverInfo3);
|
||
|
|
||
|
if ( !bRet && GetLastError() == ERROR_INVALID_LEVEL ) {
|
||
|
|
||
|
bRet = AddPrinterDriverUsingDriverInfo2(pszServerName, pDriverInfo3);
|
||
|
}
|
||
|
Cleanup:
|
||
|
|
||
|
PSetupDestroyMonitorInfo(hMonInfo);
|
||
|
PSetupDestroyDriverInfo3(pDriverInfo3);
|
||
|
|
||
|
if ( hPrinterInf != INVALID_HANDLE_VALUE )
|
||
|
SetupCloseInfFile(hPrinterInf);
|
||
|
|
||
|
if ( CopyQueue != INVALID_HANDLE_VALUE )
|
||
|
SetupCloseFileQueue(CopyQueue);
|
||
|
|
||
|
if ( QueueContext )
|
||
|
SetupTermDefaultQueueCallback(QueueContext);
|
||
|
|
||
|
return bRet ? ERROR_SUCCESS : GetLastError();
|
||
|
}
|