You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4788 lines
135 KiB
4788 lines
135 KiB
/*++
|
|
|
|
Copyright (c) 1995-97 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"
|
|
#include "splcom.h"
|
|
|
|
#define MAX_DWORD_LENGTH 11
|
|
|
|
//
|
|
// 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 cszPrintProcessor[] = TEXT("PrintProcessor");
|
|
TCHAR cszCopyFiles[] = TEXT("CopyFiles");
|
|
TCHAR cszVendorSetup[] = TEXT("VendorSetup");
|
|
TCHAR cszVendorInstaller[] = TEXT("VendorInstaller");
|
|
|
|
TCHAR cszPreviousNamesSection[] = TEXT("Previous Names");
|
|
TCHAR cszOEMUrlSection[] = TEXT("OEM URLS");
|
|
|
|
TCHAR cszWebNTPrintPkg[] = TEXT("3FBF5B30-DEB4-11D1-AC97-00A0C903492B");
|
|
|
|
TCHAR cszAllInfs[] = TEXT("*.inf");
|
|
TCHAR cszInfExt[] = TEXT("\\*.inf");
|
|
|
|
TCHAR sComma = TEXT(',');
|
|
TCHAR sHash = TEXT('@');
|
|
TCHAR sZero = TEXT('\0');
|
|
|
|
TCHAR cszSystemSetupKey[] = TEXT("System\\Setup");
|
|
TCHAR cszSystemSetupInProgress[] = TEXT("SystemSetupInProgress");
|
|
|
|
TCHAR cszMonitorKey[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\");
|
|
|
|
//
|
|
// Native environment name used by spooler
|
|
//
|
|
SPLPLATFORMINFO PlatformEnv[] = {
|
|
|
|
{ TEXT("Windows NT Alpha_AXP") },
|
|
{ TEXT("Windows NT x86") },
|
|
{ TEXT("Windows NT R4000") },
|
|
{ TEXT("Windows NT PowerPC") },
|
|
{ TEXT("Windows 4.0") },
|
|
{ TEXT("Windows IA64") },
|
|
{ TEXT("Windows Alpha_AXP64") }
|
|
};
|
|
|
|
//
|
|
// Platform override strings to be used to upgrade non-native architecture
|
|
// printer drivers
|
|
//
|
|
SPLPLATFORMINFO PlatformOverride[] = {
|
|
|
|
{ TEXT("alpha") },
|
|
{ TEXT("i386") },
|
|
{ TEXT("mips") },
|
|
{ TEXT("ppc") },
|
|
{ NULL }, // Win95
|
|
{ TEXT("ia64") },
|
|
{ TEXT("axp64") }
|
|
};
|
|
|
|
DWORD PlatformArch[][2] =
|
|
{
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_ALPHA },
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_INTEL },
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_MIPS },
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_PPC },
|
|
{ VER_PLATFORM_WIN32_WINDOWS, PROCESSOR_ARCHITECTURE_INTEL },
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_IA64 },
|
|
{ VER_PLATFORM_WIN32_NT, PROCESSOR_ARCHITECTURE_ALPHA64 }
|
|
};
|
|
|
|
PLATFORM MyPlatform =
|
|
#if defined(_ALPHA_)
|
|
PlatformAlpha;
|
|
#elif defined(_MIPS_)
|
|
PlatformMIPS;
|
|
#elif defined(_PPC_)
|
|
PlatformPPC;
|
|
#elif defined(_X86_)
|
|
PlatformX86;
|
|
#elif defined(_IA64_)
|
|
PlatformIA64;
|
|
#elif defined(_AXP64_)
|
|
PlatformAlpha64;
|
|
#elif defined(_AMD64_)
|
|
0; // ****** fixfix ****** amd64
|
|
#else
|
|
#error "No Target Architecture"
|
|
#endif
|
|
|
|
// Declare the CritSec for CDM
|
|
CRITICAL_SECTION CDMCritSect;
|
|
|
|
#define SKIP_DIR TEXT("\\__SKIP_")
|
|
|
|
CRITICAL_SECTION SkipCritSect;
|
|
LPTSTR gpszSkipDir = NULL;
|
|
|
|
|
|
PVOID
|
|
LocalAllocMem(
|
|
IN UINT cbSize
|
|
)
|
|
{
|
|
return LocalAlloc( LPTR, cbSize );
|
|
}
|
|
|
|
VOID
|
|
LocalFreeMem(
|
|
IN PVOID p
|
|
)
|
|
{
|
|
LocalFree(p);
|
|
}
|
|
|
|
//
|
|
// For some reason these are needed by spllib when you use StrNCatBuf.
|
|
// This doesn't make any sense, but just implement them.
|
|
//
|
|
LPVOID
|
|
DllAllocSplMem(
|
|
DWORD cbSize
|
|
)
|
|
{
|
|
return LocalAllocMem(cbSize);
|
|
}
|
|
|
|
BOOL
|
|
DllFreeSplMem(
|
|
LPVOID pMem
|
|
)
|
|
{
|
|
LocalFreeMem(pMem);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
PSetupFreeMem(
|
|
IN PVOID p
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Just a call to LocalFree
|
|
|
|
Arguments:
|
|
p : memory to be freed
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
LocalFreeMem(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 = LocalAllocMem((lstrlen(pszStr) + 1) * sizeof(*pszRet));
|
|
if ( pszRet )
|
|
StringCchCopy(pszRet, (lstrlen(pszStr) + 1), pszStr);
|
|
}
|
|
|
|
return pszRet;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
AllocAndCatStr(
|
|
LPCTSTR pszStr1,
|
|
LPCTSTR pszStr2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allocate memory and make a copy of two string fields, cancatenate the second to
|
|
the first
|
|
|
|
Arguments:
|
|
pszStr1 : String to copy
|
|
pszStr2 : String to CAT
|
|
|
|
Return Value:
|
|
Pointer to the copied string. Memory is allocated.
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszRet = NULL;
|
|
|
|
if ( pszStr1 && *pszStr1 &&
|
|
pszStr2 && *pszStr2 ) {
|
|
DWORD dwBufSize = (lstrlen(pszStr1) + lstrlen(pszStr2) + 1) * sizeof(*pszRet);
|
|
|
|
pszRet = LocalAllocMem(dwBufSize);
|
|
if ( pszRet ) {
|
|
StringCbCopy( pszRet, dwBufSize, pszStr1 );
|
|
StringCbCat( pszRet, dwBufSize, pszStr2 );
|
|
}
|
|
}
|
|
return pszRet;
|
|
}
|
|
|
|
LPTSTR
|
|
AllocAndCatStr2(
|
|
LPCTSTR pszStr1,
|
|
LPCTSTR pszStr2,
|
|
LPCTSTR pszStr3
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allocate memory and make a copy of two string fields, cancatenate the second to
|
|
the first
|
|
|
|
Arguments:
|
|
pszStr1 : String to copy
|
|
pszStr2 : String to CAT
|
|
pszStr3 : Second string to CAT
|
|
|
|
Return Value:
|
|
Pointer to the copied string. Memory is allocated.
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszRet = NULL;
|
|
DWORD cSize = 0;
|
|
|
|
if ( pszStr1 &&
|
|
pszStr2 &&
|
|
pszStr3 ) {
|
|
|
|
if(*pszStr1)
|
|
{
|
|
cSize += lstrlen(pszStr1);
|
|
}
|
|
|
|
if(*pszStr2)
|
|
{
|
|
cSize += lstrlen(pszStr2);
|
|
}
|
|
|
|
if(*pszStr3)
|
|
{
|
|
cSize += lstrlen(pszStr3);
|
|
}
|
|
|
|
pszRet = LocalAllocMem((cSize+1)*sizeof(*pszRet));
|
|
|
|
if ( pszRet ) {
|
|
|
|
if(*pszStr1)
|
|
{
|
|
StringCchCopy( pszRet, (cSize+1), pszStr1 );
|
|
|
|
if(*pszStr2)
|
|
{
|
|
StringCchCat( pszRet, (cSize+1), pszStr2 );
|
|
}
|
|
|
|
if(*pszStr3)
|
|
{
|
|
StringCchCat( pszRet, (cSize+1), pszStr3 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(*pszStr2)
|
|
{
|
|
StringCchCopy( pszRet, (cSize+1), pszStr2 );
|
|
|
|
if(*pszStr3)
|
|
{
|
|
StringCchCat( pszRet, (cSize+1), pszStr3 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(*pszStr3)
|
|
{
|
|
StringCchCopy( pszRet, (cSize+1), pszStr3 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pszRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
FreeStructurePointers(
|
|
LPBYTE pStruct,
|
|
PULONG_PTR pOffsets,
|
|
BOOL bFreeStruct
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Frees memory allocated to fields given by the pointers in a structure.
|
|
Also optionally frees the memory allocated for the structure itself.
|
|
|
|
Arguments:
|
|
pStruct : Pointer to the structure
|
|
pOffsets : Array of DWORDS (terminated by -1) givings offsets
|
|
bFreeStruct : If TRUE structure is also freed
|
|
|
|
Return Value:
|
|
nothing
|
|
|
|
--*/
|
|
{
|
|
INT i;
|
|
|
|
if ( pStruct ) {
|
|
|
|
for( i = 0 ; pOffsets[i] != -1; ++i )
|
|
{
|
|
LocalFreeMem(*(LPBYTE *) (pStruct+pOffsets[i]));
|
|
(*(LPBYTE *) (pStruct+pOffsets[i])) = 0;
|
|
}
|
|
|
|
if ( bFreeStruct )
|
|
LocalFreeMem(pStruct);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyLocalData(
|
|
IN PPSETUP_LOCAL_DATA pLocalData
|
|
)
|
|
{
|
|
if ( pLocalData ) {
|
|
|
|
if ( pLocalData->Flags & VALID_INF_INFO )
|
|
FreeStructurePointers((LPBYTE)&pLocalData->InfInfo,
|
|
InfInfoOffsets,
|
|
FALSE);
|
|
|
|
if ( pLocalData->Flags & VALID_PNP_INFO )
|
|
FreeStructurePointers((LPBYTE)&pLocalData->PnPInfo,
|
|
PnPInfoOffsets,
|
|
FALSE);
|
|
|
|
FreeStructurePointers((LPBYTE)pLocalData, LocalDataOffsets, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGetString(
|
|
IN PINFCONTEXT pInfContext,
|
|
IN DWORD dwFieldIndex,
|
|
OUT LPTSTR *ppszField,
|
|
IN OUT LPDWORD pcchCopied,
|
|
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
|
|
pcchCopied : On success number of charaters copied is added
|
|
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,
|
|
SIZECHARS(Buffer),
|
|
&dwNeeded) ) {
|
|
|
|
*ppszField = AllocStr(Buffer);
|
|
*pcchCopied += dwNeeded;
|
|
return;
|
|
}
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(*ppszField = LocalAllocMem(dwNeeded*sizeof(Buffer[0]))) ) {
|
|
|
|
*pbFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
if ( !SetupGetStringField(pInfContext,
|
|
dwFieldIndex,
|
|
*ppszField,
|
|
dwNeeded,
|
|
&dwNeeded) ) {
|
|
|
|
*pbFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
*pcchCopied += dwNeeded;
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGetMultiSz(
|
|
IN PINFCONTEXT pInfContext,
|
|
IN DWORD dwFieldIndex,
|
|
OUT LPTSTR *ppszField,
|
|
IN OUT LPDWORD pcchCopied,
|
|
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
|
|
pcchCopied : On success number of charaters copied is added
|
|
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,
|
|
SIZECHARS(Buffer),
|
|
&dwNeeded) ) {
|
|
|
|
if ( *ppszField = LocalAllocMem(dwNeeded*sizeof(Buffer[0])) ) {
|
|
|
|
CopyMemory(*ppszField, Buffer, dwNeeded * sizeof(Buffer[0]));
|
|
*pcchCopied += dwNeeded;
|
|
} else {
|
|
|
|
*pbFail = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(*ppszField = LocalAllocMem(dwNeeded * sizeof(Buffer[0]))) ) {
|
|
|
|
*pbFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
if ( !SetupGetMultiSzField(pInfContext,
|
|
dwFieldIndex,
|
|
*ppszField,
|
|
dwNeeded,
|
|
&dwNeeded) ) {
|
|
|
|
*pbFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
*pcchCopied += dwNeeded;
|
|
}
|
|
|
|
|
|
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 LPDWORD pcchCopied,
|
|
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
|
|
pcchCopied : On success number of charaters copied is added
|
|
*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, pcchCopied, pbFail);
|
|
} else if ( pszDefaultData && *pszDefaultData ) {
|
|
|
|
if ( !(*ppszData = AllocStr(pszDefaultData)) )
|
|
*pbFail = TRUE;
|
|
else
|
|
*pcchCopied += lstrlen(pszDefaultData) + 1;
|
|
} else
|
|
*ppszData = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGet2PartString(
|
|
IN HINF hInf,
|
|
IN LPCTSTR pszDriverSection,
|
|
IN LPCTSTR pszDataSection, OPTIONAL
|
|
IN BOOL bDataSection,
|
|
IN LPCTSTR pszKey,
|
|
OUT LPTSTR *ppszData,
|
|
IN OUT LPBOOL pbFail
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allocates memory and gets a 2 part string 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
|
|
*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;
|
|
LPTSTR psz = NULL,
|
|
psz2 = NULL;
|
|
DWORD dwLen = 0;
|
|
|
|
if ( *pbFail )
|
|
return;
|
|
|
|
if ( SetupFindFirstLine(hInf, pszDriverSection,
|
|
pszKey, &InfContext) ||
|
|
(bDataSection && SetupFindFirstLine(hInf,
|
|
pszDriverSection = pszDataSection,
|
|
pszKey,
|
|
&InfContext)) ) {
|
|
|
|
InfGetString(&InfContext, 1, ppszData, &dwLen, pbFail);
|
|
|
|
if ( *pbFail || !*ppszData )
|
|
return; //Success, field is NULL
|
|
|
|
//
|
|
// Usual case : field is of the form "Description,DLL-Name"
|
|
//
|
|
if ( psz = lstrchr(*ppszData, sComma) ) {
|
|
|
|
*psz = sZero;
|
|
return; // Success, field is not NULL
|
|
} else {
|
|
|
|
//
|
|
// This is for the case "Description", DLL-Name
|
|
//
|
|
InfGetString(&InfContext, 2, &psz, &dwLen, pbFail);
|
|
if ( *pbFail || !psz )
|
|
goto Fail;
|
|
|
|
dwLen = lstrlen(*ppszData) + lstrlen(psz) + 2;
|
|
if ( psz2 = LocalAllocMem(dwLen * sizeof(*psz2)) ) {
|
|
DWORD dwPos;
|
|
|
|
StringCchCopy(psz2, dwLen, *ppszData);
|
|
LocalFreeMem(*ppszData);
|
|
*ppszData = psz2;
|
|
|
|
dwPos = lstrlen(psz2) + 1;
|
|
psz2 += dwPos;
|
|
StringCchCopy(psz2, dwLen - dwPos, psz);
|
|
LocalFreeMem(psz);
|
|
} else
|
|
goto Fail;
|
|
}
|
|
} else
|
|
*ppszData = NULL;
|
|
|
|
return;
|
|
|
|
Fail:
|
|
LocalFreeMem(*ppszData);
|
|
LocalFreeMem(psz);
|
|
LocalFreeMem(psz2);
|
|
|
|
*ppszData = NULL;
|
|
*pbFail = TRUE;
|
|
SetLastError(STG_E_UNKNOWN);
|
|
}
|
|
|
|
|
|
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, provided the DRIVER_INFO_3 structure was allocated using
|
|
PSetupGetDriverInfo3.
|
|
|
|
Arguments:
|
|
pDriverInfo3 : Pointer to the DRIVER_INFO_3 structure to free memory
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LocalFreeMem(pDriverInfo3);
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
PackString(
|
|
IN LPTSTR pszEnd,
|
|
IN LPTSTR pszSource,
|
|
IN LPTSTR *ppszTarget
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
After parsing the INF the DRIVER_INFO_6 is packed in a buffer where the
|
|
strings are at the end.
|
|
|
|
Arguments:
|
|
pszEnd : Pointer to the end of the buffer
|
|
pszSource : String to copy to the end of the buffer
|
|
ppszTarget : After copying the source to end of buffer this will receive
|
|
addess of the packed string
|
|
|
|
Return Value:
|
|
New end of buffer
|
|
|
|
--*/
|
|
{
|
|
if ( pszSource && *pszSource ) {
|
|
|
|
pszEnd -= lstrlen(pszSource) + 1;
|
|
StringCchCopy(pszEnd, lstrlen(pszSource) + 1, pszSource);
|
|
*ppszTarget = pszEnd;
|
|
}
|
|
|
|
return pszEnd;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
PackMultiSz(
|
|
IN LPTSTR pszEnd,
|
|
IN LPTSTR pszzSource,
|
|
IN LPTSTR *ppszzTarget
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
After parsing the INF the DRIVER_INFO_6 is packed in a buffer where the
|
|
strings are at the end.
|
|
|
|
Arguments:
|
|
pszEnd : Pointer to the end of the buffer
|
|
pszSource : Multi-sz field to copy to the end of the buffer
|
|
ppszTarget : After copying the source to end of buffer this will receive
|
|
addess of the packed multi-sz field
|
|
|
|
Return Value:
|
|
New end of buffer
|
|
|
|
--*/
|
|
{
|
|
size_t dwLen = 0;
|
|
LPTSTR psz1, psz2;
|
|
|
|
if ( (psz1 = pszzSource) != NULL && *psz1 ) {
|
|
|
|
while ( *psz1 )
|
|
psz1 += lstrlen(psz1) + 1;
|
|
|
|
dwLen = (size_t)((psz1 - pszzSource) + 1);
|
|
}
|
|
|
|
if ( dwLen == 0 ) {
|
|
|
|
*ppszzTarget = NULL;
|
|
return pszEnd;
|
|
}
|
|
|
|
pszEnd -= dwLen;
|
|
*ppszzTarget = pszEnd;
|
|
CopyMemory((LPBYTE)pszEnd, (LPBYTE)pszzSource, dwLen * sizeof(TCHAR));
|
|
|
|
return pszEnd;
|
|
}
|
|
|
|
|
|
VOID
|
|
PackDriverInfo6(
|
|
IN LPDRIVER_INFO_6 pSourceDriverInfo6,
|
|
IN LPDRIVER_INFO_6 pTargetDriverInfo6,
|
|
IN DWORD cbDriverInfo6
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Make a copy of a DRIVER_INFO_6 in a buffer where the strings are packed at
|
|
end of the buffer.
|
|
|
|
Arguments:
|
|
pSourceDriverInfo6 : The DRIVER_INFO_6 to make a copy
|
|
pTargetDriverInfo6 : Points to a buffer to copy the pSourceDriverInfo6
|
|
cbDriverInfo6 : Size of the buffer cbDriverInfo6, which is the size
|
|
needed for DRIVER_INFO_6 and the strings
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszStr, pszStr2, pszMonitorDll;
|
|
DWORD dwLen = 0;
|
|
|
|
// Copy over he couple non-string fields
|
|
pTargetDriverInfo6->cVersion = pSourceDriverInfo6->cVersion;
|
|
pTargetDriverInfo6->ftDriverDate = pSourceDriverInfo6->ftDriverDate;
|
|
pTargetDriverInfo6->dwlDriverVersion = pSourceDriverInfo6->dwlDriverVersion;
|
|
|
|
pszStr = (LPTSTR)(((LPBYTE)pTargetDriverInfo6) + cbDriverInfo6);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pName,
|
|
&pTargetDriverInfo6->pName);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pDriverPath,
|
|
&pTargetDriverInfo6->pDriverPath);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pDataFile,
|
|
&pTargetDriverInfo6->pDataFile);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pConfigFile,
|
|
&pTargetDriverInfo6->pConfigFile);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pHelpFile,
|
|
&pTargetDriverInfo6->pHelpFile);
|
|
|
|
//
|
|
// Monitor dll is put right after the name
|
|
// (ex. PJL Language monitor\0pjlmon.dd\0)
|
|
//
|
|
if ( pSourceDriverInfo6->pMonitorName ) {
|
|
|
|
pszMonitorDll = pSourceDriverInfo6->pMonitorName
|
|
+ lstrlen(pSourceDriverInfo6->pMonitorName) + 1;
|
|
|
|
pszStr = PackString(pszStr,
|
|
pszMonitorDll,
|
|
&pszStr2); // Don't care
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pMonitorName,
|
|
&pTargetDriverInfo6->pMonitorName);
|
|
|
|
}
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pDefaultDataType,
|
|
&pTargetDriverInfo6->pDefaultDataType);
|
|
|
|
pszStr = PackMultiSz(pszStr,
|
|
pSourceDriverInfo6->pDependentFiles,
|
|
&pTargetDriverInfo6->pDependentFiles);
|
|
|
|
pszStr = PackMultiSz(pszStr,
|
|
pSourceDriverInfo6->pszzPreviousNames,
|
|
&pTargetDriverInfo6->pszzPreviousNames);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pszMfgName,
|
|
&pTargetDriverInfo6->pszMfgName);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pszOEMUrl,
|
|
&pTargetDriverInfo6->pszOEMUrl);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pszHardwareID,
|
|
&pTargetDriverInfo6->pszHardwareID);
|
|
|
|
pszStr = PackString(pszStr,
|
|
pSourceDriverInfo6->pszProvider,
|
|
&pTargetDriverInfo6->pszProvider);
|
|
|
|
if ( pTargetDriverInfo6->pszProvider )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pszProvider
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
else if ( pTargetDriverInfo6->pszHardwareID )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pszHardwareID
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
else if ( pTargetDriverInfo6->pszOEMUrl )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pszOEMUrl
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
else if ( pTargetDriverInfo6->pszMfgName )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pszMfgName
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
else if ( pTargetDriverInfo6->pszzPreviousNames )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pszzPreviousNames
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
else if ( pTargetDriverInfo6->pDependentFiles )
|
|
{
|
|
ASSERT((LPBYTE)pTargetDriverInfo6->pDependentFiles
|
|
>= ((LPBYTE) pTargetDriverInfo6) + sizeof(DRIVER_INFO_6));
|
|
}
|
|
}
|
|
|
|
|
|
LPDRIVER_INFO_6
|
|
CloneDriverInfo6(
|
|
IN LPDRIVER_INFO_6 pSourceDriverInfo6,
|
|
IN DWORD cbDriverInfo6
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Make a copy of a DRIVER_INFO_6 in a buffer where the strings are packed at
|
|
end of the buffer.
|
|
|
|
Arguments:
|
|
pSourceDriverInfo6 : The DRIVER_INFO_6 to make a copy
|
|
cbDriverInfo6 : Size of the buffer cbDriverInfo6, which is the size
|
|
needed for DRIVER_INFO_6 and the strings
|
|
|
|
Return Value:
|
|
A pointer to a DRIVER_INFO_6 structure identical to the one we passed it.
|
|
|
|
--*/
|
|
{
|
|
LPDRIVER_INFO_6 pTargetDriverInfo6;
|
|
LPTSTR pszStr, pszStr2;
|
|
DWORD dwLen = 0;
|
|
|
|
pTargetDriverInfo6 = (LPDRIVER_INFO_6) LocalAllocMem(cbDriverInfo6);
|
|
|
|
if ( pTargetDriverInfo6 )
|
|
PackDriverInfo6(pSourceDriverInfo6,
|
|
pTargetDriverInfo6,
|
|
cbDriverInfo6);
|
|
|
|
return pTargetDriverInfo6;
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGetVendorSetup(
|
|
IN OUT PPARSEINF_INFO pInfInfo,
|
|
IN HINF hInf,
|
|
IN LPTSTR pszDriverSection,
|
|
IN LPTSTR pszDataSection,
|
|
IN BOOL bDataSection,
|
|
IN OUT LPBOOL pbFail
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Get the VendorSetup field, if specified, from the INF
|
|
|
|
Arguments:
|
|
pInfInfo : This is where the parsed info from the INF is stored
|
|
hInf : INF handle
|
|
pszDriverSection : Gives the driver installation section
|
|
pszDataSection : Data section specified (optional) in driver install section
|
|
bDataSection : Tells if a data section is specified
|
|
pbFail : Set on error
|
|
|
|
Return Value:
|
|
New end of buffer
|
|
|
|
--*/
|
|
{
|
|
LPTSTR p;
|
|
DWORD dwSize;
|
|
TCHAR szBuf[MAX_PATH];
|
|
INFCONTEXT InfContext;
|
|
|
|
if ( *pbFail )
|
|
return;
|
|
|
|
//
|
|
// If VendorSetup key is not found return; the key is optional
|
|
//
|
|
if ( !SetupFindFirstLine(hInf, pszDriverSection,
|
|
cszVendorSetup, &InfContext) &&
|
|
( !bDataSection ||
|
|
!SetupFindFirstLine(hInf, pszDataSection,
|
|
cszVendorSetup, &InfContext)) ) {
|
|
|
|
return;
|
|
}
|
|
|
|
if ( SetupGetLineText(&InfContext, hInf, NULL, NULL,
|
|
szBuf, SIZECHARS(szBuf), &dwSize) ) {
|
|
|
|
if ( dwSize == 0 || szBuf[0] == TEXT('\0') )
|
|
return;
|
|
|
|
if ( !(pInfInfo->pszVendorSetup = AllocStr(szBuf)) )
|
|
*pbFail = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
|
|
|
|
*pbFail = TRUE;
|
|
return;
|
|
}
|
|
|
|
pInfInfo->pszVendorSetup = (LPTSTR) LocalAllocMem(dwSize * sizeof(TCHAR));
|
|
if ( pInfInfo->pszVendorSetup &&
|
|
SetupGetLineText(&InfContext, hInf, NULL, NULL,
|
|
pInfInfo->pszVendorSetup, dwSize, &dwSize) ) {
|
|
|
|
return;
|
|
}
|
|
|
|
LocalFreeMem(pInfInfo->pszVendorSetup);
|
|
pInfInfo->pszVendorSetup = NULL;
|
|
|
|
*pbFail = TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGetPreviousNames(
|
|
IN HINF hInf,
|
|
IN PSELECTED_DRV_INFO pDrvInfo,
|
|
IN OUT LPDWORD pcchCopied,
|
|
IN OUT LPBOOL pbFail
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets the pszzPreviousNames field for the selected driver. This field is
|
|
optional, and if specified gives previous names under which the driver was
|
|
known
|
|
|
|
Arguments:
|
|
hInf : INF handle
|
|
pDrvInfo : Pointer to selected driver info
|
|
pcchCopied : Number of characters copied
|
|
pbFail : Set on failure
|
|
|
|
Return Value:
|
|
None. On failure *pbFail is set
|
|
|
|
--*/
|
|
{
|
|
INFCONTEXT Context;
|
|
|
|
if ( *pbFail )
|
|
return;
|
|
|
|
//
|
|
// Previous names is optional; if not found we are done
|
|
//
|
|
if ( SetupFindFirstLine(hInf,
|
|
cszPreviousNamesSection,
|
|
pDrvInfo->pszModelName,
|
|
&Context) ) {
|
|
|
|
pDrvInfo->Flags |= SDFLAG_PREVNAME_SECTION_FOUND;
|
|
InfGetMultiSz(&Context, 1, &pDrvInfo->pszzPreviousNames,
|
|
pcchCopied, pbFail);
|
|
} else if ( GetLastError() != ERROR_LINE_NOT_FOUND )
|
|
pDrvInfo->Flags |= SDFLAG_PREVNAME_SECTION_FOUND;
|
|
}
|
|
|
|
|
|
VOID
|
|
InfGetOEMUrl(
|
|
IN HINF hInf,
|
|
IN PSELECTED_DRV_INFO pDrvInfo,
|
|
IN OUT LPBOOL pbFail
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets the OEM URL Info for the selected driver. This field is optional
|
|
|
|
Arguments:
|
|
hInf : INF handle
|
|
pDrvInfo : Pointer to selected driver info
|
|
pbFail : Set on failure
|
|
|
|
Return Value:
|
|
None. On failure *pbFail is set
|
|
|
|
--*/
|
|
{
|
|
INFCONTEXT Context;
|
|
DWORD dwDontCare = 0;
|
|
|
|
if ( *pbFail )
|
|
return;
|
|
|
|
//
|
|
// OEM URL is optional; if not found we are done
|
|
//
|
|
if ( SetupFindFirstLine(hInf,
|
|
cszOEMUrlSection,
|
|
pDrvInfo->pszManufacturer,
|
|
&Context) ) {
|
|
|
|
InfGetString(&Context, 1, &pDrvInfo->pszOEMUrl, &dwDontCare, pbFail);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
AddAllIncludedInf(
|
|
IN HINF hInf,
|
|
IN LPTSTR pszInstallSection,
|
|
IN PLATFORM platform,
|
|
IN BOOL bCrossPlatformAllowed
|
|
)
|
|
|
|
{
|
|
INFCONTEXT INFContext;
|
|
PINFCONTEXT pINFContext = &INFContext;
|
|
DWORD dwBufferNeeded;
|
|
BOOL bRet = TRUE;
|
|
|
|
if ( SetupFindFirstLine( hInf, pszInstallSection, TEXT( "Include" ), pINFContext ) )
|
|
{
|
|
// Find each INF and load it & it's LAYOUT files
|
|
DWORD dwINFs = SetupGetFieldCount( pINFContext );
|
|
DWORD dwIndex;
|
|
|
|
//
|
|
// We cannot install a driver for a different platform than the current
|
|
// machine if the inf file of the driver uses include/needs. This would
|
|
// lead to problems with verifying the driver signature. The reason is that
|
|
// we do not keeps infs and cat-files of different architectures on the local
|
|
// machine.
|
|
// Since driver signing is somewhat broken when installing a Win95 driver
|
|
// we ignore this problem for these drivers.
|
|
//
|
|
if ((!bCrossPlatformAllowed) && (platform != MyPlatform) && (platform != PlatformWin95))
|
|
{
|
|
bRet = FALSE;
|
|
SetLastError(ERROR_INSTALL_PLATFORM_UNSUPPORTED);
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
for ( dwIndex = 1; dwIndex <= dwINFs; dwIndex++ )
|
|
{
|
|
if ( SetupGetStringField( pINFContext, dwIndex, NULL, 0, &dwBufferNeeded ) )
|
|
{
|
|
PTSTR pszINFName = (PTSTR) LocalAllocMem( dwBufferNeeded * sizeof(TCHAR) );
|
|
if ( pszINFName )
|
|
{
|
|
if ( SetupGetStringField( pINFContext, dwIndex, pszINFName, dwBufferNeeded, &dwBufferNeeded ) )
|
|
{
|
|
//
|
|
// Open INF file and append layout.inf specified in Version section
|
|
// Layout inf is optional
|
|
//
|
|
SetupOpenAppendInfFile( pszINFName, hInf, NULL);
|
|
SetupOpenAppendInfFile( NULL, hInf, NULL);
|
|
} // Got an INF Name
|
|
|
|
LocalFreeMem( pszINFName );
|
|
pszINFName = NULL;
|
|
} // Allocated pszINFName
|
|
} // Got the Field from the INF Line
|
|
} // Process all INFs in the Include Line
|
|
} // Found an Include= Line
|
|
|
|
Cleanup:
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
BOOL
|
|
InstallAllInfSections(
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN PLATFORM platform,
|
|
IN LPCTSTR pszServerName,
|
|
IN HSPFILEQ CopyQueue,
|
|
IN LPCTSTR pszSource,
|
|
IN DWORD dwInstallFlags,
|
|
IN HINF hInf,
|
|
IN LPCTSTR pszInstallSection
|
|
)
|
|
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HINF hIncludeInf;
|
|
INFCONTEXT INFContext;
|
|
PINFCONTEXT pINFContext = &INFContext;
|
|
INFCONTEXT NeedsContext;
|
|
PINFCONTEXT pNeedsContext = &NeedsContext;
|
|
DWORD dwBufferNeeded;
|
|
PTSTR pszINFName = NULL;
|
|
PTSTR pszSectionName = NULL;
|
|
|
|
if ( CopyQueue == INVALID_HANDLE_VALUE ||
|
|
!SetTargetDirectories( pLocalData,
|
|
platform,
|
|
pszServerName,
|
|
hInf,
|
|
dwInstallFlags ) ||
|
|
!SetupInstallFilesFromInfSection(
|
|
hInf,
|
|
NULL,
|
|
CopyQueue,
|
|
pszInstallSection,
|
|
pszSource,
|
|
SP_COPY_LANGUAGEAWARE) )
|
|
goto Cleanup;
|
|
|
|
// To get the source directories correct, we need to load all included INFs
|
|
// separately. THen use their associated layout files.
|
|
if ( SetupFindFirstLine( hInf, pszInstallSection, TEXT( "Include" ), pINFContext ) )
|
|
{
|
|
// Find each INF and load it & it's LAYOUT files
|
|
DWORD dwINFs = SetupGetFieldCount( pINFContext );
|
|
DWORD dwIIndex;
|
|
|
|
for ( dwIIndex = 1; dwIIndex <= dwINFs; dwIIndex++ )
|
|
{
|
|
if ( SetupGetStringField( pINFContext, dwIIndex, NULL, 0, &dwBufferNeeded ) )
|
|
{
|
|
pszINFName = (PTSTR) LocalAllocMem( dwBufferNeeded * sizeof(TCHAR) );
|
|
if ( pszINFName )
|
|
{
|
|
if ( SetupGetStringField( pINFContext, dwIIndex, pszINFName, dwBufferNeeded, &dwBufferNeeded ) )
|
|
{
|
|
//
|
|
// Open INF file and append layout.inf specified in Version section
|
|
// Layout inf is optional
|
|
//
|
|
// SetupOpenAppendInfFile( pszINFName, hPrinterInf, NULL);
|
|
hIncludeInf = SetupOpenInfFile(pszINFName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
|
|
if ( hIncludeInf == INVALID_HANDLE_VALUE )
|
|
goto Cleanup;
|
|
SetupOpenAppendInfFile( NULL, hIncludeInf, NULL);
|
|
|
|
// Now process all need sections for this INF
|
|
// Now find the Needs Line and install all called sections
|
|
if ( SetupFindFirstLine( hInf, pszInstallSection, TEXT( "needs" ), pNeedsContext ) )
|
|
{
|
|
// Find each INF and load it & it's LAYOUT files
|
|
DWORD dwSections = SetupGetFieldCount( pNeedsContext );
|
|
DWORD dwNIndex;
|
|
|
|
for ( dwNIndex = 1; dwNIndex <= dwSections; dwNIndex++ )
|
|
{
|
|
if ( SetupGetStringField( pNeedsContext, dwNIndex, NULL, 0, &dwBufferNeeded ) )
|
|
{
|
|
pszSectionName = (PTSTR) LocalAllocMem( dwBufferNeeded * sizeof(TCHAR) );
|
|
if ( pszSectionName )
|
|
{
|
|
if ( SetupGetStringField( pNeedsContext, dwNIndex, pszSectionName, dwBufferNeeded, &dwBufferNeeded ) )
|
|
{
|
|
if ( SetTargetDirectories(pLocalData,
|
|
platform,
|
|
pszServerName,
|
|
hIncludeInf,
|
|
dwInstallFlags) )
|
|
{
|
|
if ( !SetupInstallFilesFromInfSection(
|
|
hIncludeInf,
|
|
NULL,
|
|
CopyQueue,
|
|
pszSectionName,
|
|
NULL,
|
|
SP_COPY_LANGUAGEAWARE) )
|
|
goto Cleanup;
|
|
} // Able to setup Target Dirs
|
|
else
|
|
goto Cleanup;
|
|
} // Got a Section Name
|
|
|
|
LocalFreeMem( pszSectionName );
|
|
pszSectionName = NULL;
|
|
} // Allocated pszSectionName
|
|
} // Got the Field from the Section Line
|
|
} // Process all Sections in the Needs Line
|
|
} // Found a Needs= Line
|
|
|
|
// Close included INF
|
|
if ( hIncludeInf != INVALID_HANDLE_VALUE )
|
|
SetupCloseInfFile(hIncludeInf);
|
|
} // Got an INF Name
|
|
|
|
LocalFreeMem( pszINFName );
|
|
pszINFName = NULL;
|
|
} // Allocated pszINFName
|
|
} // Got the Field from the INF Line
|
|
} // Process all INFs in the Include Line
|
|
} // Found an Include= Line
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
if ( pszINFName )
|
|
LocalFreeMem( pszINFName );
|
|
|
|
if ( pszSectionName )
|
|
LocalFreeMem( pszSectionName );
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ParseInf(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN PLATFORM platform,
|
|
IN LPCTSTR pszServerName,
|
|
IN DWORD dwInstallFlags,
|
|
IN BOOL bCrossPlatformAllowed
|
|
)
|
|
/*++
|
|
|
|
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:
|
|
pLocalData :
|
|
platform : Platform for which inf should be parsed
|
|
|
|
Return Value:
|
|
TRUE -- Succesfully parsed the inf and built info for the selected driver
|
|
FALSE -- On Error
|
|
|
|
--*/
|
|
{
|
|
PPARSEINF_INFO pInfInfo = &pLocalData->InfInfo;
|
|
PDRIVER_INFO_6 pDriverInfo6 = &pLocalData->InfInfo.DriverInfo6;
|
|
LPTSTR pszDataSection, psz, pszInstallSection;
|
|
BOOL bWin95 = platform == PlatformWin95,
|
|
bFail = TRUE, bDataSection = FALSE;
|
|
INFCONTEXT Context;
|
|
DWORD cchDriverInfo6, dwNeeded, dwDontCare;
|
|
HINF hInf;
|
|
|
|
//
|
|
// Check if INF is already parsed, and if so for the right platform
|
|
//
|
|
if ( pLocalData->Flags & VALID_INF_INFO ) {
|
|
|
|
if ( platform == pInfInfo->platform )
|
|
return TRUE;
|
|
|
|
FreeStructurePointers((LPBYTE)pInfInfo, InfInfoOffsets, FALSE);
|
|
pLocalData->Flags &= ~VALID_INF_INFO;
|
|
ZeroMemory(pInfInfo, sizeof(*pInfInfo));
|
|
}
|
|
|
|
pszDataSection = NULL;
|
|
|
|
hInf = SetupOpenInfFile(pLocalData->DrvInfo.pszInfName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL);
|
|
|
|
if ( hInf == INVALID_HANDLE_VALUE )
|
|
goto Cleanup;
|
|
|
|
if ( bWin95 ) {
|
|
|
|
pszInstallSection = AllocStr(pLocalData->DrvInfo.pszDriverSection);
|
|
if ( !pszInstallSection )
|
|
goto Cleanup;
|
|
} else {
|
|
|
|
//
|
|
// Platform and ProcessorArchitecture only fields that are checked.
|
|
//
|
|
|
|
SP_ALTPLATFORM_INFO AltPlat_Info = {0};
|
|
|
|
AltPlat_Info.cbSize = sizeof(SP_ALTPLATFORM_INFO);
|
|
AltPlat_Info.Platform = PlatformArch[ platform ][OS_PLATFORM];
|
|
AltPlat_Info.ProcessorArchitecture = (WORD) PlatformArch[ platform ][PROCESSOR_ARCH];
|
|
|
|
if ( !SetupDiGetActualSectionToInstallEx(
|
|
hInf,
|
|
pLocalData->DrvInfo.pszDriverSection,
|
|
&AltPlat_Info,
|
|
NULL,
|
|
0,
|
|
&dwNeeded,
|
|
NULL,
|
|
NULL) ||
|
|
!(pInfInfo->pszInstallSection
|
|
= (LPTSTR) LocalAllocMem(dwNeeded * sizeof(TCHAR))) ||
|
|
!SetupDiGetActualSectionToInstallEx(
|
|
hInf,
|
|
pLocalData->DrvInfo.pszDriverSection,
|
|
&AltPlat_Info,
|
|
pInfInfo->pszInstallSection,
|
|
dwNeeded,
|
|
NULL,
|
|
NULL,
|
|
NULL) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
pszInstallSection = pInfInfo->pszInstallSection;
|
|
}
|
|
|
|
//
|
|
// Now load all other INFs referenced in the Install Section
|
|
//
|
|
if(!AddAllIncludedInf( hInf, pszInstallSection, platform, bCrossPlatformAllowed))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !(pDriverInfo6->pName = AllocStr(pLocalData->DrvInfo.pszModelName)) )
|
|
goto Cleanup;
|
|
|
|
bFail = FALSE;
|
|
|
|
if(bFail)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Does the driver section have a data section name specified?
|
|
//
|
|
if ( SetupFindFirstLine(hInf, pszInstallSection,
|
|
cszDataSection, &Context) ) {
|
|
|
|
InfGetString(&Context, 1, &pszDataSection, &dwDontCare, &bFail);
|
|
bDataSection = TRUE;
|
|
}
|
|
|
|
cchDriverInfo6 = lstrlen(pDriverInfo6->pName) + 1;
|
|
|
|
//
|
|
// If DataFile key is not found data file is same as driver section name
|
|
//
|
|
InfGetDriverInfoString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszDataFile,
|
|
&pDriverInfo6->pDataFile,
|
|
pszInstallSection,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
//
|
|
// If DriverFile key is not found driver file is the driver section name
|
|
//
|
|
InfGetDriverInfoString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszDriverFile,
|
|
&pDriverInfo6->pDriverPath,
|
|
pszInstallSection,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
//
|
|
// If ConfigFile key is not found config file is same as driver file
|
|
//
|
|
InfGetDriverInfoString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszConfigFile,
|
|
&pDriverInfo6->pConfigFile,
|
|
pDriverInfo6->pDriverPath,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
//
|
|
// Help file is optional, and by default NULL
|
|
//
|
|
InfGetDriverInfoString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszHelpFile,
|
|
&pDriverInfo6->pHelpFile,
|
|
NULL,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
//
|
|
// Monitor name is optional, and by default none
|
|
//
|
|
InfGet2PartString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszLanguageMonitor,
|
|
&pDriverInfo6->pMonitorName,
|
|
&bFail);
|
|
|
|
if ( psz = pDriverInfo6->pMonitorName ) {
|
|
|
|
psz += lstrlen(psz) + 1;
|
|
cchDriverInfo6 += lstrlen(pDriverInfo6->pMonitorName) + lstrlen(psz) + 2;
|
|
}
|
|
|
|
//
|
|
// Print processor is optional, and by default none
|
|
//
|
|
InfGet2PartString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszPrintProcessor,
|
|
&pLocalData->InfInfo.pszPrintProc,
|
|
&bFail);
|
|
|
|
//
|
|
// Default data type is optional, and by default none
|
|
//
|
|
InfGetDriverInfoString(hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
cszDefaultDataType,
|
|
&pDriverInfo6->pDefaultDataType,
|
|
NULL,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
//
|
|
// Vendor setup is optional, and by default none
|
|
//
|
|
InfGetVendorSetup(pInfInfo,
|
|
hInf,
|
|
pszInstallSection,
|
|
pszDataSection,
|
|
bDataSection,
|
|
&bFail);
|
|
|
|
bFail = bFail || !InfGetDependentFilesAndICMFiles(hDevInfo,
|
|
hInf,
|
|
bWin95,
|
|
pLocalData,
|
|
platform,
|
|
pszServerName,
|
|
dwInstallFlags,
|
|
pszInstallSection,
|
|
&cchDriverInfo6);
|
|
if ( !bWin95 ) {
|
|
|
|
InfGetPreviousNames(hInf,
|
|
&pLocalData->DrvInfo,
|
|
&cchDriverInfo6,
|
|
&bFail);
|
|
|
|
InfGetOEMUrl(hInf,
|
|
&pLocalData->DrvInfo,
|
|
&bFail);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Save the last error is we've failed. SetupCloseInfFile can change the last error and we
|
|
// don't care about it's last error in any way.
|
|
//
|
|
if( bFail ) {
|
|
|
|
dwDontCare = GetLastError();
|
|
}
|
|
|
|
LocalFreeMem(pszDataSection);
|
|
|
|
if ( hInf != INVALID_HANDLE_VALUE )
|
|
SetupCloseInfFile(hInf);
|
|
|
|
//
|
|
// On failure free all the fields filled by this routine
|
|
//
|
|
if ( bFail ) {
|
|
|
|
FreeStructurePointers((LPBYTE)pInfInfo, InfInfoOffsets, FALSE);
|
|
ZeroMemory(pInfInfo, sizeof(*pInfInfo));
|
|
SetLastError( dwDontCare );
|
|
|
|
} else {
|
|
|
|
// Point members of DriverInfo6 to strings in pDrvInfo
|
|
pInfInfo->DriverInfo6.pszzPreviousNames = pLocalData->DrvInfo.pszzPreviousNames;
|
|
|
|
pLocalData->InfInfo.DriverInfo6.pszMfgName = pLocalData->DrvInfo.pszManufacturer;
|
|
if ( pLocalData->InfInfo.DriverInfo6.pszMfgName )
|
|
cchDriverInfo6 += ( lstrlen( pLocalData->InfInfo.DriverInfo6.pszMfgName ) + 1 );
|
|
|
|
pLocalData->InfInfo.DriverInfo6.pszOEMUrl = pLocalData->DrvInfo.pszOEMUrl;
|
|
if ( pLocalData->InfInfo.DriverInfo6.pszOEMUrl )
|
|
cchDriverInfo6 += ( lstrlen( pLocalData->InfInfo.DriverInfo6.pszOEMUrl ) + 1 );
|
|
|
|
pLocalData->InfInfo.DriverInfo6.pszHardwareID = pLocalData->DrvInfo.pszHardwareID;
|
|
if ( pLocalData->InfInfo.DriverInfo6.pszHardwareID )
|
|
cchDriverInfo6 += ( lstrlen( pLocalData->InfInfo.DriverInfo6.pszHardwareID ) + 1 );
|
|
|
|
pLocalData->InfInfo.DriverInfo6.pszProvider = pLocalData->DrvInfo.pszProvider;
|
|
if ( pLocalData->InfInfo.DriverInfo6.pszProvider )
|
|
cchDriverInfo6 += ( lstrlen( pLocalData->InfInfo.DriverInfo6.pszProvider ) + 1 );
|
|
|
|
pLocalData->InfInfo.DriverInfo6.ftDriverDate = pLocalData->DrvInfo.ftDriverDate;
|
|
pLocalData->InfInfo.DriverInfo6.dwlDriverVersion = pLocalData->DrvInfo.dwlDriverVersion;
|
|
|
|
pInfInfo->cbDriverInfo6 = sizeof(DRIVER_INFO_6) +
|
|
cchDriverInfo6 * sizeof(TCHAR);
|
|
|
|
pLocalData->Flags |= VALID_INF_INFO;
|
|
pInfInfo->platform = platform;
|
|
}
|
|
|
|
return !bFail;
|
|
}
|
|
|
|
|
|
LPDRIVER_INFO_6
|
|
GetDriverInfo6(
|
|
IN PSELECTED_DRV_INFO pSelectedDrvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets the selected drivers information in a DRIVER_INFO_6 structure.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
Pointer to the DRIVER_INFO_6 structure. Memory is allocated for it.
|
|
|
|
--*/
|
|
{
|
|
HINF hInf;
|
|
PPSETUP_LOCAL_DATA LocalData = NULL;
|
|
LPDRIVER_INFO_6 pDriverInfo6 = NULL;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
SP_DEVINSTALL_PARAMS DiParams = {0};
|
|
|
|
if ( !pSelectedDrvInfo ||
|
|
!pSelectedDrvInfo->pszInfName ||
|
|
!*pSelectedDrvInfo->pszInfName ||
|
|
!pSelectedDrvInfo->pszModelName ||
|
|
!*pSelectedDrvInfo->pszModelName ||
|
|
!pSelectedDrvInfo->pszDriverSection ||
|
|
!*pSelectedDrvInfo->pszDriverSection ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(INVALID_HANDLE_VALUE == (hDevInfo = CreatePrinterDeviceInfoList(NULL)))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
DiParams.cbSize = sizeof(DiParams);
|
|
if (!SetupDiGetDeviceInstallParams(hDevInfo, NULL, &DiParams))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringCchCopy(DiParams.DriverPath, COUNTOF(DiParams.DriverPath), pSelectedDrvInfo->pszInfName);
|
|
|
|
DiParams.Flags |= DI_ENUMSINGLEINF;
|
|
|
|
if (!SetupDiSetDeviceInstallParams(hDevInfo, NULL, &DiParams))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
LocalData = PSetupDriverInfoFromName(hDevInfo, pSelectedDrvInfo->pszModelName);
|
|
if (!LocalData)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( ParseInf(hDevInfo, LocalData, MyPlatform, NULL, 0, FALSE) ) {
|
|
|
|
pDriverInfo6 = CloneDriverInfo6(&(LocalData->InfInfo.DriverInfo6),
|
|
LocalData->InfInfo.cbDriverInfo6);
|
|
}
|
|
|
|
Cleanup:
|
|
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
|
|
DestroyLocalData( LocalData );
|
|
|
|
return pDriverInfo6;
|
|
}
|
|
|
|
|
|
LPDRIVER_INFO_3
|
|
PSetupGetDriverInfo3(
|
|
IN PSELECTED_DRV_INFO pSelectedDrvInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets the selected drivers information in a DRIVER_INFO_3 structure.
|
|
The memory is allocated with one call to LocalAlloc.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
Pointer to the DRIVER_INFO_3 structure. Memory is allocated for it.
|
|
|
|
--*/
|
|
{
|
|
return (LPDRIVER_INFO_3) GetDriverInfo6(pSelectedDrvInfo);
|
|
}
|
|
|
|
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];
|
|
int RetVal = 0;
|
|
|
|
RetVal = LoadString(ghInst, uId, buffer, SIZECHARS(buffer));
|
|
|
|
if ( RetVal )
|
|
{
|
|
return AllocStr(buffer);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
LPTSTR
|
|
GetLongStringFromRcFile(
|
|
UINT uId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Load a long string from the .rc file, up to MAX_SETUP_ALLOC_STRING_LEN characters
|
|
|
|
Arguments:
|
|
uId : Identifier for the string to be loaded
|
|
|
|
Return Value:
|
|
String value loaded, NULL on error. Caller should free the memory
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pBuf = NULL;
|
|
int Retry = 0, RetVal;
|
|
|
|
//
|
|
// I couldn't find a way to determine the length of a string the resource file, hence
|
|
// I just try until the length returned by LoadString is smaller than the buffer I passed in
|
|
//
|
|
for (Retry = 1; Retry <= MAX_SETUP_ALLOC_STRING_LEN/MAX_SETUP_LEN; Retry++)
|
|
{
|
|
int CurrentSize = Retry * MAX_SETUP_LEN;
|
|
|
|
pBuf = LocalAllocMem(CurrentSize * sizeof(TCHAR));
|
|
if (!pBuf)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
RetVal = LoadString(ghInst, uId, pBuf, CurrentSize);
|
|
|
|
if (RetVal == 0)
|
|
{
|
|
LocalFreeMem(pBuf);
|
|
return NULL;
|
|
}
|
|
|
|
if (RetVal < CurrentSize -1) // -1 because the LoadString ret value doesn't include the termination
|
|
{
|
|
return pBuf;
|
|
}
|
|
|
|
//
|
|
// RetVal is CurrentSize - retry
|
|
//
|
|
LocalFreeMem(pBuf);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL
|
|
PSetupGetPathToSearch(
|
|
IN HWND hwnd,
|
|
IN LPCTSTR pszTitle,
|
|
IN LPCTSTR pszDiskName,
|
|
IN LPCTSTR pszFileName,
|
|
IN BOOL bPromptForInf,
|
|
IN 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,
|
|
szPath[0] ? szPath : NULL,
|
|
pszFileName,
|
|
NULL,
|
|
bPromptForInf ?
|
|
(IDF_NOSKIP | IDF_NOBEEP | IDF_NOREMOVABLEMEDIAPROMPT | IDF_USEDISKNAMEASPROMPT) :
|
|
(IDF_NOSKIP | 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) != TEXT('\\') &&
|
|
dwNeeded < MAX_PATH - 2 ) {
|
|
|
|
*(szPath + dwNeeded) = TEXT('\\');
|
|
*(szPath + dwNeeded + 1) = sZero;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if ( dwReturn == DPROMPT_OUTOFMEMORY ||
|
|
dwReturn == DPROMPT_BUFFERTOOSMALL ) {
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
} else {
|
|
|
|
SetLastError(ERROR_CANCELLED);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
IsDifferent(
|
|
LPTSTR p1,
|
|
LPTSTR p2,
|
|
DWORD (*pfn)(LPTSTR, LPTSTR)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Extended version of strcmp/memcmp kind of function. Treats NULL pointer and
|
|
the pointer to NULL as a match. For other cases call function passed in.
|
|
|
|
Arguments:
|
|
p1 : First address to compare
|
|
p2 : Second address to compare
|
|
pfn : Function to call if both p1 and p2 are non-NULL
|
|
|
|
Return Value:
|
|
+ means p1 > p2 (like how memcmp or strcmp defines), - means p1 < p2.
|
|
0 if the values match
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// We want to treat NULL ptr and ptr to NULL as the same thing
|
|
//
|
|
if ( p1 && !*p1 )
|
|
p1 = NULL;
|
|
|
|
if ( p2 && !*p2 )
|
|
p2 = NULL;
|
|
|
|
//
|
|
// If both are NULL then they match
|
|
//
|
|
if ( !p1 && !p2 )
|
|
return 0;
|
|
|
|
//
|
|
// Both are non NULL
|
|
//
|
|
if ( p1 && p2 )
|
|
return pfn(p1, p2);
|
|
|
|
//
|
|
// One of them is NULL
|
|
//
|
|
if ( p1 )
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
FileNamePart(
|
|
IN LPCTSTR pszFullName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Find the file name part of a fully qualified file name
|
|
|
|
Arguments:
|
|
pszFullName : Fully qualified path to the file
|
|
|
|
Return Value:
|
|
Pointer to the filename part in the fully qulaified string
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszSlash, pszTemp;
|
|
|
|
if ( !pszFullName )
|
|
return NULL;
|
|
|
|
//
|
|
// First find the : for the drive
|
|
//
|
|
if ( pszTemp = lstrchr(pszFullName, TEXT(':')) )
|
|
pszFullName = pszFullName + 1;
|
|
|
|
for ( pszTemp = (LPTSTR)pszFullName ;
|
|
pszSlash = lstrchr(pszTemp, TEXT('\\')) ;
|
|
pszTemp = pszSlash + 1 )
|
|
;
|
|
|
|
return *pszTemp ? pszTemp : NULL;
|
|
|
|
}
|
|
|
|
BOOL
|
|
IdenticalDriverInfo6(
|
|
IN LPDRIVER_INFO_6 p1,
|
|
IN LPDRIVER_INFO_6 p2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if DRIVER_INFO_6 are the same
|
|
|
|
Arguments:
|
|
p1 : DRIVER_INFO_6 from the INF
|
|
p2 : DRIVER_INFO_6 returned by the spooler
|
|
|
|
Return Value:
|
|
TRUE if the DRIVER_INFO_6s are identical, FALSE else
|
|
|
|
--*/
|
|
{
|
|
LPTSTR psz;
|
|
|
|
return (p1->dwlDriverVersion == (DWORDLONG)0 ||
|
|
p2->dwlDriverVersion == (DWORDLONG)0 ||
|
|
p1->dwlDriverVersion == p2->dwlDriverVersion) &&
|
|
!lstrcmpi(p1->pName, p2->pName) &&
|
|
(psz = FileNamePart(p2->pDriverPath)) &&
|
|
!lstrcmpi(p1->pDriverPath, psz) &&
|
|
(psz = FileNamePart(p2->pDataFile)) &&
|
|
!lstrcmpi(p1->pDataFile, psz) &&
|
|
(psz = FileNamePart(p2->pConfigFile)) &&
|
|
!lstrcmpi(p1->pConfigFile, psz) &&
|
|
!IsDifferent(p1->pHelpFile,
|
|
FileNamePart(p2->pHelpFile),
|
|
lstrcmpi) &&
|
|
!IsDifferent(p1->pMonitorName,
|
|
p2->pMonitorName,
|
|
lstrcmpi);
|
|
|
|
/*
|
|
|
|
We changed the way we find dependent files from NT4 to NT5.
|
|
So we do not want to look at them while deciding if a driver came from
|
|
an INF.
|
|
|
|
!IsDifferent(p1->pDefaultDataType,
|
|
p2->pDefaultDataType,
|
|
lstrcmpi);
|
|
SameMultiSz(p1->pDependentFiles, p2->pDependentFiles, TRUE) &&
|
|
SameMultiSz(p1->pszzPreviousNames, p2->pszzPreviousNames, FALSE);
|
|
*/
|
|
}
|
|
|
|
|
|
BOOL
|
|
AllICMFilesInstalled(
|
|
IN LPCTSTR pszServerName,
|
|
IN LPTSTR pszzICMFiles
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if all the icm files given are installed on the specified machine
|
|
|
|
Arguments:
|
|
pszServerName : Name of the server
|
|
pszzICMFiles : Multi-sz field giving all the ICM files
|
|
|
|
Return Value:
|
|
TRUE if all the ICM profiles are installed on the server, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPBYTE buf = NULL;
|
|
LPTSTR p1, p2;
|
|
DWORD dwNeeded, dwReturned;
|
|
ENUMTYPE EnumType;
|
|
|
|
if ( !pszzICMFiles || !*pszzICMFiles )
|
|
return TRUE;
|
|
|
|
//
|
|
// ICM apis are not remotablr for now
|
|
//
|
|
if ( pszServerName )
|
|
goto Cleanup;
|
|
|
|
ZeroMemory(&EnumType, sizeof(EnumType));
|
|
EnumType.dwSize = sizeof(EnumType);
|
|
EnumType.dwVersion = ENUM_TYPE_VERSION;
|
|
|
|
//
|
|
// Get all the color profiles installed on the machine
|
|
//
|
|
dwNeeded = 0;
|
|
if ( EnumColorProfiles((LPTSTR)pszServerName,
|
|
&EnumType,
|
|
NULL,
|
|
&dwNeeded,
|
|
&dwReturned) ||
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(buf = LocalAllocMem(dwNeeded)) ||
|
|
!EnumColorProfiles((LPTSTR)pszServerName,
|
|
&EnumType,
|
|
buf,
|
|
&dwNeeded,
|
|
&dwReturned) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
for ( p1 = pszzICMFiles ; *p1 ; p1 += lstrlen(p1) + 1 ) {
|
|
|
|
for ( p2 = (LPTSTR)buf, dwNeeded = 0 ;
|
|
dwNeeded < dwReturned && *p2 && lstrcmpi(p1, p2) ;
|
|
++dwNeeded, p2 += lstrlen(p2) + 1 )
|
|
;
|
|
|
|
//
|
|
// Did we find p1 in the enumerated color profiles?
|
|
//
|
|
if ( dwNeeded == dwReturned )
|
|
goto Cleanup;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
LocalFreeMem(buf);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CorrectVersionDriverFound(
|
|
IN LPDRIVER_INFO_2 pDriverInfo2,
|
|
IN DWORD dwCount,
|
|
IN LPCTSTR pszDriverName,
|
|
IN DWORD dwMajorVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Check if the correct version driver we are looking for is found in the list
|
|
we got from spooler
|
|
|
|
Arguments:
|
|
pDriverInfo2 : Points to the buffer of DRIVER_INFO_2 structs
|
|
dwCount : Number of DRIVER_INFO_2 elements in the buffer
|
|
szDriverName : Driver name
|
|
dwMajorVersion : Version no
|
|
|
|
Return Value:
|
|
TRUE if driver is found in the lise, FALSE else
|
|
|
|
--*/
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
for ( dwIndex = 0 ; dwIndex < dwCount ; ++dwIndex, ++pDriverInfo2 ) {
|
|
|
|
//
|
|
// Check if the driver is for the correct version
|
|
//
|
|
if ( dwMajorVersion != KERNEL_MODE_DRIVER_VERSION &&
|
|
dwMajorVersion != pDriverInfo2->cVersion )
|
|
continue;
|
|
|
|
if ( dwMajorVersion == KERNEL_MODE_DRIVER_VERSION &&
|
|
pDriverInfo2->cVersion < 2 )
|
|
continue;
|
|
|
|
if ( !lstrcmpi(pDriverInfo2->pName, pszDriverName) )
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PSetupIsDriverInstalled(
|
|
IN LPCTSTR pszServerName,
|
|
IN LPCTSTR pszDriverName,
|
|
IN PLATFORM platform,
|
|
IN DWORD dwMajorVersion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Finds out if a particular version of a printer driver is already installed
|
|
in the system by querying spooler
|
|
|
|
Arguments:
|
|
pszServerName : Server name (NULL for local)
|
|
pszDriverName : 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 = 1024, dwReturned2;
|
|
LPBYTE p = NULL, p2 = NULL;
|
|
LPTSTR psz;
|
|
LPDRIVER_INFO_6 pDriverInfo6;
|
|
LPTSTR pszServerArchitecture = NULL;
|
|
|
|
if ( !(p = LocalAllocMem(dwNeeded)) )
|
|
goto Cleanup;
|
|
|
|
if ( !EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
2,
|
|
p,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned) ) {
|
|
|
|
LocalFreeMem(p);
|
|
p = NULL;
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(p = LocalAllocMem(dwNeeded)) ||
|
|
!EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
2,
|
|
p,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
bReturn = CorrectVersionDriverFound((LPDRIVER_INFO_2)p,
|
|
dwReturned,
|
|
pszDriverName,
|
|
dwMajorVersion);
|
|
|
|
//
|
|
// Win95 drivers could have a different name than NT driver
|
|
//
|
|
if ( bReturn || platform != PlatformWin95 )
|
|
goto Cleanup;
|
|
|
|
dwNeeded = 1024;
|
|
if ( !(p2 = LocalAllocMem(dwNeeded)) )
|
|
goto Cleanup;
|
|
|
|
pszServerArchitecture = GetArchitectureName( (LPTSTR)pszServerName );
|
|
if (!pszServerArchitecture)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
pszServerArchitecture,
|
|
6,
|
|
p2,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned2) ) {
|
|
|
|
LocalFreeMem(p2);
|
|
p2 = NULL;
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(p2 = LocalAllocMem(dwNeeded)) ||
|
|
!EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
pszServerArchitecture,
|
|
6,
|
|
p2,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned2) )
|
|
goto Cleanup;
|
|
}
|
|
|
|
for ( dwNeeded = 0, pDriverInfo6 = (LPDRIVER_INFO_6)p2 ;
|
|
dwNeeded < dwReturned2 ;
|
|
++pDriverInfo6, ++dwNeeded ) {
|
|
|
|
if ( pDriverInfo6->cVersion < 2 )
|
|
continue;
|
|
|
|
if ( !lstrcmpi(pDriverInfo6->pName, pszDriverName) )
|
|
break;
|
|
}
|
|
|
|
if ( dwNeeded < dwReturned2 && (psz = pDriverInfo6->pszzPreviousNames) )
|
|
while ( *psz ) {
|
|
|
|
if ( bReturn = CorrectVersionDriverFound((LPDRIVER_INFO_2)p,
|
|
dwReturned,
|
|
psz,
|
|
dwMajorVersion) )
|
|
break;
|
|
|
|
psz += lstrlen(psz) + 1;
|
|
}
|
|
|
|
Cleanup:
|
|
LocalFreeMem(p);
|
|
LocalFreeMem(p2);
|
|
LocalFreeMem( pszServerArchitecture );
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
INT
|
|
PSetupIsTheDriverFoundInInfInstalled(
|
|
IN LPCTSTR pszServerName,
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN PLATFORM platform,
|
|
IN DWORD dwMajorVersion
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Finds out if a particular version of a printer driver is already installed
|
|
in the system by querying spooler; Additionally check if the installed
|
|
driver is the same found in the INF (file name matches only)
|
|
|
|
Arguments:
|
|
pszServerName : Server name (NULL for local)
|
|
szDriverName : Driver name
|
|
platform : platform for which we want to check the driver
|
|
dwMajorVersion : Version no;
|
|
If KERNEL_MODE_DRIVER_VERSION check for a KM driver
|
|
|
|
Return Value:
|
|
DRIVER_MODEL_INSTALLED_AND_IDENTICAL :
|
|
if driver is installed and all files are identical
|
|
DRIVER_MODEL_NOT_INSTALLED :
|
|
if a driver with the given model name is not available
|
|
DRIVER_MODEL_INSTALLED_BUT_DIFFERENT :
|
|
a driver with the given model name is installed but not all files
|
|
are identical
|
|
|
|
--*/
|
|
{
|
|
INT iRet = DRIVER_MODEL_NOT_INSTALLED;
|
|
DWORD dwReturned,
|
|
dwNeeded,
|
|
dwLastError;
|
|
LPBYTE p = NULL;
|
|
LPDRIVER_INFO_6 p1DriverInfo6,
|
|
p2DriverInfo6;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
|
|
ASSERT(pLocalData && pLocalData->signature == PSETUP_SIGNATURE);
|
|
|
|
if(INVALID_HANDLE_VALUE == (hDevInfo = CreatePrinterDeviceInfoList(NULL)))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !ParseInf(hDevInfo, pLocalData, platform, pszServerName, 0, TRUE) )
|
|
goto Cleanup;
|
|
|
|
p1DriverInfo6 = &pLocalData->InfInfo.DriverInfo6;
|
|
|
|
if ( EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
6,
|
|
NULL,
|
|
0,
|
|
&dwNeeded,
|
|
&dwReturned) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( (dwLastError = GetLastError()) == ERROR_INVALID_LEVEL ) {
|
|
|
|
iRet = PSetupIsDriverInstalled(pszServerName,
|
|
p1DriverInfo6->pName,
|
|
platform,
|
|
dwMajorVersion)
|
|
? DRIVER_MODEL_INSTALLED_BUT_DIFFERENT
|
|
: DRIVER_MODEL_NOT_INSTALLED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( dwLastError != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(p = LocalAllocMem(dwNeeded)) ||
|
|
!EnumPrinterDrivers((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
6,
|
|
p,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned) ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
for ( dwNeeded = 0, p2DriverInfo6 = (LPDRIVER_INFO_6) p ;
|
|
dwNeeded < dwReturned ;
|
|
++dwNeeded, (LPBYTE) p2DriverInfo6 += sizeof(DRIVER_INFO_6) ) {
|
|
|
|
//
|
|
// Check if the driver is for the correct version
|
|
//
|
|
if ( dwMajorVersion != KERNEL_MODE_DRIVER_VERSION &&
|
|
dwMajorVersion != p2DriverInfo6->cVersion )
|
|
continue;
|
|
|
|
if ( dwMajorVersion == KERNEL_MODE_DRIVER_VERSION &&
|
|
p2DriverInfo6->cVersion < 2 )
|
|
continue;
|
|
|
|
if ( !lstrcmpi(p2DriverInfo6->pName, p1DriverInfo6->pName) ) {
|
|
|
|
if ( IdenticalDriverInfo6(p1DriverInfo6,
|
|
p2DriverInfo6) &&
|
|
AllICMFilesInstalled(pszServerName,
|
|
pLocalData->InfInfo.pszzICMFiles) )
|
|
iRet = DRIVER_MODEL_INSTALLED_AND_IDENTICAL;
|
|
else
|
|
iRet = DRIVER_MODEL_INSTALLED_BUT_DIFFERENT;
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
LocalFreeMem(p);
|
|
|
|
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
PLATFORM
|
|
PSetupThisPlatform(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Returns the platform of the local machine.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
Platform of local machine
|
|
|
|
--*/
|
|
{
|
|
return MyPlatform;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DeleteAllFilesInDirectory(
|
|
LPCTSTR pszDir,
|
|
BOOL bDeleteDirectory
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Delete all the files in a directory, and optionally the directory as well.
|
|
|
|
Arguments:
|
|
pszDir : Directory name to cleanup
|
|
bDeleteDirectory : If TRUE the directory gets deleted as well
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = TRUE;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
DWORD dwLen;
|
|
TCHAR *pszFile = NULL;
|
|
TCHAR *pszBuf = NULL;
|
|
INT cchLength = 0;
|
|
INT cchBufLength = 0;
|
|
INT cchInitialLength = 4 * MAX_PATH;
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
|
|
if (!pszDir)
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
cchLength = max( cchInitialLength, lstrlen( pszDir ) + lstrlen( TEXT("\\*") ) + 1);
|
|
pszFile = LocalAllocMem( cchLength * sizeof( TCHAR ));
|
|
if (!pszFile)
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
StringCchCopy(pszFile, cchLength, pszDir);
|
|
dwLen = lstrlen(pszFile);
|
|
StringCchCopy(pszFile + dwLen, cchLength - dwLen, TEXT("\\*"));
|
|
|
|
hFile = FindFirstFile(pszFile, &FindData);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
*(pszFile + dwLen + 1) = TEXT('\0');
|
|
pszBuf = AllocStr( pszFile );
|
|
if (!pszBuf)
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
cchBufLength = lstrlen( pszBuf );
|
|
|
|
do {
|
|
|
|
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
|
continue;
|
|
|
|
cchLength = cchBufLength + lstrlen( FindData.cFileName ) + 1;
|
|
if (cchLength > cchInitialLength)
|
|
{
|
|
LocalFreeMem( pszFile );
|
|
pszFile = LocalAllocMem( cchLength * sizeof( TCHAR ));
|
|
if (!pszFile)
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
cchInitialLength = cchLength;
|
|
}
|
|
StringCchCopy(pszFile, cchLength, pszBuf);
|
|
StringCchCat( pszFile, cchLength, FindData.cFileName );
|
|
|
|
//
|
|
// Remove the FILE_ATTRIBUTE_READONLY file attribute if it has been set
|
|
//
|
|
if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_READONLY )
|
|
{
|
|
SetFileAttributes( pszFile,
|
|
FindData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY );
|
|
}
|
|
|
|
if ( !DeleteFile(pszFile) )
|
|
bRet = FALSE;
|
|
} while ( FindNextFile(hFile, &FindData) );
|
|
|
|
if ( bDeleteDirectory && !RemoveDirectory(pszDir) )
|
|
bRet = FALSE;
|
|
|
|
Cleanup:
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(hFile);
|
|
}
|
|
LocalFreeMem( pszFile );
|
|
LocalFreeMem( pszBuf );
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// enum to store the NT-CD type
|
|
//
|
|
typedef enum _eCDType {
|
|
CD_Unknown,
|
|
CD_NT4,
|
|
CD_W2K_SRV,
|
|
CD_W2K_PRO,
|
|
CD_WHISTLER_SRV,
|
|
CD_WHISTLER_WKS
|
|
} CD_TYPE;
|
|
|
|
//
|
|
// structure that stores the tag file names of the NT CDs
|
|
//
|
|
typedef struct _CD_TAGFILE_MAP_ENTRY {
|
|
CD_TYPE CdType;
|
|
LPTSTR pszTagFileName;
|
|
}CD_TAGFILE_MAP_ENTRY;
|
|
|
|
CD_TAGFILE_MAP_ENTRY TagEntries[] =
|
|
{
|
|
//
|
|
// the following entry for the Whistler CD is special in a couple of ways:
|
|
// - it uses a wildcard because the tag filename changes from Beta1 to Beta2 and again to RTM
|
|
// - it identifies the CD as W2k despite it being for Whistler. The reason is that the layout regarding
|
|
// printer drivers is identical to W2k, no need to distinguish (and duplicate entries)
|
|
//
|
|
{ CD_W2K_SRV, _T("WIN51.*") },
|
|
|
|
{ CD_W2K_SRV, _T("CDROM_NT.5") },
|
|
{ CD_NT4, _T("CDROM_S.40") },
|
|
{ CD_NT4, _T("CDROM_W.40") },
|
|
//
|
|
// no need to identify NT3.x CDs - different codepath !
|
|
//
|
|
{ CD_Unknown, NULL }
|
|
};
|
|
|
|
|
|
//
|
|
// structure to store the subpaths to printer INFs on the NT CDs
|
|
//
|
|
typedef struct _CD_SUBPATHS_FOR_PLATFORMS {
|
|
CD_TYPE CdType;
|
|
PLATFORM Platform;
|
|
DWORD Version;
|
|
LPCTSTR pszSubPath;
|
|
} CD_SUBPATHS_FOR_PLATFORMS;
|
|
|
|
//
|
|
// this list is used for lookup of pathes as well - must be sorted so that paths
|
|
// that contain other paths must come before them (e.g. xxx\zzz before \zzz)
|
|
//
|
|
CD_SUBPATHS_FOR_PLATFORMS SubPathInfo[] =
|
|
{
|
|
{ CD_W2K_SRV, PlatformX86, 2, _T("printers\\nt4\\i386\\") },
|
|
{ CD_W2K_SRV, PlatformWin95, 0, _T("printers\\win9x\\") },
|
|
{ CD_W2K_SRV, PlatformX86, 3, _T("i386\\") },
|
|
{ CD_W2K_SRV, PlatformIA64, 3, _T("ia64\\") },
|
|
|
|
{ CD_NT4, PlatformX86, 2, _T("i386\\") },
|
|
{ CD_NT4, PlatformAlpha, 2, _T("alpha\\") },
|
|
{ CD_NT4, PlatformMIPS, 2, _T("mips\\") },
|
|
{ CD_NT4, PlatformPPC, 2, _T("ppc\\") },
|
|
|
|
//
|
|
// path = NULL terminates the array
|
|
//
|
|
{ CD_Unknown, PlatformX86, 0 , NULL }
|
|
};
|
|
|
|
CD_TYPE
|
|
DetermineCDType(LPTSTR pszInfPath, LPTSTR pszRootPath)
|
|
/*++
|
|
|
|
Routine Description:
|
|
From a path to a printer INF, figure out what (if any) NT CD this is.
|
|
It does so by figuring out the root path if it's one of the NT CDs and
|
|
then checking the tag file that should be there.
|
|
|
|
Arguments:
|
|
pszInfPath : path to INF
|
|
pszRootPath : caller-supplied buffer (MAX_PATH long) that receives the
|
|
path to the CD "root". This is nontrivial in case the CD
|
|
is on a network share. Ends with a backslash
|
|
|
|
Return Value:
|
|
The type of CD detected, CD_Unknown if not one that we know of (i.e. an OEM CD)
|
|
|
|
--*/
|
|
{
|
|
LPTSTR pszTemp;
|
|
DWORD i;
|
|
|
|
//
|
|
// find the root path
|
|
//
|
|
DWORD_PTR MinPathLen = 0, SubPathLen, len;
|
|
|
|
StringCchCopy(pszRootPath, MAX_PATH, pszInfPath);
|
|
len = _tcslen(pszRootPath);
|
|
|
|
//
|
|
// make sure it ends with a backslash
|
|
//
|
|
if (pszRootPath[len-1] != _T('\\'))
|
|
{
|
|
pszRootPath[len++] = _T('\\');
|
|
pszRootPath[len] = 0;
|
|
}
|
|
|
|
//
|
|
// Is it a UNC path ?
|
|
//
|
|
|
|
if (!_tcsncmp(pszRootPath, _T("\\\\"), 2))
|
|
{
|
|
pszTemp = _tcschr(pszRootPath + 2, _T('\\'));
|
|
if (pszTemp)
|
|
{
|
|
pszTemp = _tcschr(pszTemp+1, _T('\\'));
|
|
if (pszTemp)
|
|
{
|
|
MinPathLen = pszTemp - pszRootPath;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for illegal path, shouldn't happen
|
|
//
|
|
if ((MinPathLen == 0) || (MinPathLen > len))
|
|
{
|
|
return CD_Unknown;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MinPathLen = 2;
|
|
}
|
|
|
|
//
|
|
// now check whether the final part of the path is one that I know of
|
|
//
|
|
for (i = 0; SubPathInfo[i].pszSubPath != NULL; ++i)
|
|
{
|
|
SubPathLen = _tcslen(SubPathInfo[i].pszSubPath);
|
|
if (SubPathLen + MinPathLen <= len)
|
|
{
|
|
if (!_tcsnicmp(&(pszRootPath[len - SubPathLen]),
|
|
SubPathInfo[i].pszSubPath, SubPathLen))
|
|
{
|
|
pszRootPath[len-SubPathLen] = 0;
|
|
len = _tcslen(pszRootPath);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if it's none of the paths I know of, it can still be the root itself.
|
|
// now I know where the tag files should be if they're there
|
|
//
|
|
for (i = 0;TagEntries[i].pszTagFileName != NULL; ++i)
|
|
{
|
|
StringCchCopy(&(pszRootPath[len]), MAX_PATH - len, TagEntries[i].pszTagFileName);
|
|
|
|
if (FileExists(pszRootPath))
|
|
{
|
|
pszRootPath[len] = 0; // cut off the tag file name
|
|
return TagEntries[i].CdType;
|
|
}
|
|
}
|
|
|
|
return CD_Unknown;
|
|
}
|
|
|
|
BOOL
|
|
CheckValidInfInPath(HWND hwnd, LPTSTR pszInfPath, DWORD dwVersion, PLATFORM Platform)
|
|
{
|
|
TCHAR szInfFiles[MAX_PATH];
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE hFind;
|
|
DWORD PathLen;
|
|
BOOL bRet = FALSE;
|
|
|
|
//
|
|
// first, find the INF in the path. There must be one else SetupPromptForPath would've complained
|
|
//
|
|
StringCchCopy(szInfFiles, COUNTOF(szInfFiles), pszInfPath);
|
|
PathLen = _tcslen(szInfFiles);
|
|
|
|
if (szInfFiles[PathLen-1] != _T('\\'))
|
|
{
|
|
szInfFiles[PathLen++] = _T('\\');
|
|
szInfFiles[PathLen] = 0;
|
|
}
|
|
|
|
StringCchCat(szInfFiles, COUNTOF(szInfFiles), _T("*.inf"));
|
|
|
|
hFind = FindFirstFile(szInfFiles, &FindData);
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD InfStyle;
|
|
HANDLE hInfFile;
|
|
|
|
if ((dwVersion == 0) && (Platform != PlatformWin95))
|
|
{
|
|
InfStyle = INF_STYLE_OLDNT;
|
|
}
|
|
else
|
|
{
|
|
InfStyle = INF_STYLE_WIN4;
|
|
}
|
|
|
|
do
|
|
{
|
|
StringCchCopy(&(szInfFiles[PathLen]), COUNTOF(szInfFiles) - PathLen, FindData.cFileName);
|
|
|
|
hInfFile = SetupOpenInfFile(szInfFiles, _T("Printer"), InfStyle, NULL);
|
|
|
|
if (hInfFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
SetupCloseInfFile(hInfFile);
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
} while ( FindNextFile(hFind, &FindData) );
|
|
|
|
FindClose(hFind);
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
LPTSTR pszFormat = NULL, pszPrompt = NULL, pszTitle = NULL;
|
|
|
|
pszFormat = GetStringFromRcFile(IDS_WARN_NO_ALT_PLATFORM_DRIVER);
|
|
pszTitle = GetStringFromRcFile(IDS_WARN_NO_DRIVER_FOUND);
|
|
|
|
if ( pszFormat && pszTitle)
|
|
{
|
|
DWORD dwBufSize;
|
|
|
|
dwBufSize = (lstrlen(pszFormat) + lstrlen(pszInfPath) + 2) * sizeof(TCHAR);
|
|
pszPrompt = LocalAllocMem(dwBufSize);
|
|
|
|
if ( pszPrompt )
|
|
{
|
|
StringCbPrintf(pszPrompt, dwBufSize, pszFormat, pszInfPath);
|
|
|
|
MessageBox(hwnd, pszPrompt, pszTitle, MB_OK);
|
|
|
|
LocalFreeMem(pszPrompt);
|
|
}
|
|
|
|
}
|
|
LocalFreeMem(pszFormat);
|
|
LocalFreeMem(pszTitle);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckInfPath(HWND hwnd, LPTSTR pszInfPath, DWORD dwVersion, PLATFORM platform,
|
|
LPTSTR *ppFileSrcPath)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Check whether the path that a user selected as a path to install a printer
|
|
from points to one of our CDs and correct the path if necessary, i.e. if
|
|
the luser selected the \i386 subdir for an NT4 driver.
|
|
|
|
Arguments:
|
|
hwnd : windows handle of the main window
|
|
pszInfPath : path to INF. This buffer must be at least
|
|
MAX_PATH in length.
|
|
dwVersion : driver version that the new driver is installed for
|
|
platform : the platform that the new driver is installed for
|
|
ppFileSrcPath: if not NULL, receives the path to the printer files. This
|
|
is used for installation from the NT4 CD that contains a
|
|
compressed INF that I have to uncompress and install from
|
|
without copying all the files possibly referenced in it.
|
|
Needs to be freed by the caller.
|
|
|
|
Return Value:
|
|
TRUE: path contains a valid print inf
|
|
FALSE: path doesn't contain a print inf, prompt user again
|
|
|
|
--*/
|
|
{
|
|
CD_TYPE CDType;
|
|
TCHAR szRootPath[MAX_PATH];
|
|
DWORD i;
|
|
|
|
//
|
|
// determine the type of CD
|
|
//
|
|
CDType = DetermineCDType(pszInfPath, szRootPath);
|
|
|
|
if (CDType == CD_Unknown)
|
|
{
|
|
return CheckValidInfInPath(hwnd, pszInfPath, dwVersion, platform);
|
|
}
|
|
|
|
//
|
|
// NT 4 drivers are compressed -> uncompress into temp dir
|
|
//
|
|
if ((dwVersion == 2) && (CDType == CD_NT4))
|
|
{
|
|
//
|
|
// Make sure the file is actually the compressed one
|
|
//
|
|
DWORD rc, CompressedFileSize, UncompressedFileSize;
|
|
UINT CompType;
|
|
LPTSTR pszUncompFilePath = NULL, pszInfFileName = _T("ntprint.in_");
|
|
TCHAR szInf[MAX_PATH];
|
|
|
|
StringCchCopy(szInf, COUNTOF(szInf), szRootPath);
|
|
|
|
//
|
|
// append the correct subpath
|
|
//
|
|
for (i = 0; SubPathInfo[i].pszSubPath != NULL; ++i)
|
|
{
|
|
if ((SubPathInfo[i].CdType == CD_NT4) &&
|
|
(platform == SubPathInfo[i].Platform) &&
|
|
(dwVersion == SubPathInfo[i].Version))
|
|
{
|
|
StringCchCat(szInf, COUNTOF(szInf), SubPathInfo[i].pszSubPath);
|
|
break;
|
|
}
|
|
}
|
|
StringCchCat(szInf, COUNTOF(szInf), pszInfFileName);
|
|
|
|
rc = SetupGetFileCompressionInfo(szInf,
|
|
&pszUncompFilePath,
|
|
&CompressedFileSize,
|
|
&UncompressedFileSize,
|
|
&CompType);
|
|
|
|
if (rc == NO_ERROR)
|
|
{
|
|
LocalFree(pszUncompFilePath); // don't need that
|
|
|
|
if (CompType != FILE_COMPRESSION_NONE)
|
|
{
|
|
TCHAR UncompFilePath[MAX_PATH], *pTmp;
|
|
|
|
//
|
|
// decompress into temp directory
|
|
//
|
|
if (GetTempPath(MAX_PATH, UncompFilePath) &&
|
|
(SUCCEEDED(StringCchCat(UncompFilePath, COUNTOF(UncompFilePath), _T("ntprint.inf")))) &&
|
|
(SetupDecompressOrCopyFile(szInf, UncompFilePath, NULL) == NO_ERROR))
|
|
{
|
|
if (ppFileSrcPath)
|
|
{
|
|
//
|
|
// delete the inf name from the path
|
|
//
|
|
pTmp = _tcsrchr(szInf, _T('\\'));
|
|
if (pTmp)
|
|
{
|
|
*(pTmp+1) = 0;
|
|
}
|
|
*ppFileSrcPath = AllocStr(szInf);
|
|
}
|
|
|
|
StringCchCopy(pszInfPath, MAX_PATH, UncompFilePath);
|
|
|
|
//
|
|
// delete the inf name from the path
|
|
//
|
|
pTmp = _tcsrchr(pszInfPath, _T('\\'));
|
|
if (pTmp)
|
|
{
|
|
*(pTmp+1) = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// correct the path if it's the one for a different platform
|
|
//
|
|
for (i = 0; SubPathInfo[i].pszSubPath != NULL; ++i)
|
|
{
|
|
if ((CDType == SubPathInfo[i].CdType) &&
|
|
(platform == SubPathInfo[i].Platform) &&
|
|
(dwVersion == SubPathInfo[i].Version))
|
|
{
|
|
StringCchCopy(pszInfPath, MAX_PATH, szRootPath);
|
|
StringCchCat( pszInfPath, MAX_PATH, SubPathInfo[i].pszSubPath);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return CheckValidInfInPath(hwnd, pszInfPath, dwVersion, platform);
|
|
}
|
|
|
|
|
|
HDEVINFO
|
|
GetInfAndBuildDrivers(
|
|
IN HWND hwnd,
|
|
IN DWORD dwTitleId,
|
|
IN DWORD dwDiskId,
|
|
IN TCHAR szInfPath[MAX_PATH],
|
|
IN DWORD dwInstallFlags,
|
|
IN PLATFORM platform,
|
|
IN DWORD dwVersion,
|
|
IN LPCTSTR pszDriverName, OPTIONAL
|
|
OUT PPSETUP_LOCAL_DATA *ppLocalData, OPTIONAL
|
|
OUT LPTSTR *ppFileSrcPath OPTIONAL
|
|
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Prompt for an INF and build the list of printer drivers from INFs found
|
|
in the directory. If pszDriverName is passed in then the INF should have
|
|
a model with matching name (i.e. alternate driver installation case)
|
|
|
|
Arguments:
|
|
hwnd : Parent window handle for UI
|
|
dwTitleId : Gives the identifier to be used to load the title string
|
|
from the rc file
|
|
dwDiskId : Gives the identifier to be used to load the disk identifier
|
|
from the rc file
|
|
szInfPath : Directory name where inf was found
|
|
pszDriverName : Name of the driver needed in the INF
|
|
ppLocalData : If a driver nam is given on return this will give
|
|
the local data for that
|
|
dwInstallFlags : Flags to control installation operation
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bDoRetry = TRUE;
|
|
DWORD dwLen, dwLastError;
|
|
LPTSTR pszTitle = NULL, pszDisk = NULL;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
|
|
dwLen = lstrlen(szInfPath);
|
|
szInfPath[dwLen] = TEXT('\\');
|
|
|
|
if ( dwLen + lstrlen(cszAllInfs) + 1 > MAX_PATH )
|
|
goto Cleanup;
|
|
|
|
StringCchCopy(szInfPath+dwLen + 1, MAX_PATH - (dwLen + 1), cszAllInfs);
|
|
|
|
Retry:
|
|
if ( bDoRetry && FileExists(szInfPath) ) {
|
|
|
|
szInfPath[dwLen] = TEXT('\0');
|
|
} else {
|
|
|
|
//
|
|
// if the file doesn't exist in the first place, prompt only once !
|
|
//
|
|
bDoRetry = FALSE;
|
|
|
|
//
|
|
// Always just prompt with the CD-ROM path
|
|
//
|
|
GetCDRomDrive(szInfPath);
|
|
|
|
if ( dwInstallFlags & DRVINST_PROMPTLESS ) {
|
|
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( dwTitleId && !(pszTitle = GetStringFromRcFile(dwTitleId)) )
|
|
goto Cleanup;
|
|
|
|
if ( dwDiskId && !(pszDisk = GetStringFromRcFile(dwDiskId)) )
|
|
goto Cleanup;
|
|
|
|
do
|
|
{
|
|
if ( !PSetupGetPathToSearch(hwnd, pszTitle, pszDisk,
|
|
cszAllInfs, TRUE, szInfPath) )
|
|
goto Cleanup;
|
|
|
|
} while (!CheckInfPath(hwnd, szInfPath, dwVersion, platform, ppFileSrcPath));
|
|
}
|
|
|
|
hDevInfo = CreatePrinterDeviceInfoList(hwnd);
|
|
|
|
if ( hDevInfo == INVALID_HANDLE_VALUE ||
|
|
!SetDevInstallParams(hDevInfo, NULL, szInfPath) ||
|
|
!BuildClassDriverList(hDevInfo) ||
|
|
(pszDriverName && ppLocalData &&
|
|
!(*ppLocalData = PSetupDriverInfoFromName(hDevInfo,
|
|
pszDriverName))) ) {
|
|
|
|
dwLastError = GetLastError();
|
|
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
|
|
hDevInfo = INVALID_HANDLE_VALUE;
|
|
SetLastError(dwLastError);
|
|
if ( bDoRetry ) {
|
|
|
|
bDoRetry = FALSE;
|
|
goto Retry;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
LocalFreeMem(pszTitle);
|
|
LocalFreeMem(pszDisk);
|
|
|
|
return hDevInfo;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MyName(
|
|
IN LPCTSTR pszServerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Tells if the string passed in identifies the local machine. Currently
|
|
it checks for NULL and computer name only
|
|
|
|
Arguments:
|
|
pszServerName : Name of the server passed in
|
|
|
|
Return Value:
|
|
TRUE if the name is recognized as that for local machine, FALSE else
|
|
|
|
--*/
|
|
{
|
|
TCHAR szBuf[MAX_COMPUTERNAME_LENGTH+1];
|
|
DWORD dwNeeded;
|
|
|
|
if ( !pszServerName || !*pszServerName )
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
/*
|
|
dwNeeded = SIZECHARS(szBuf);
|
|
|
|
if ( *pszServerName == TEXT('\\') &&
|
|
*(pszServerName+1) == TEXT('\\') &&
|
|
GetComputerName(szBuf, &dwNeeded) &&
|
|
!lstrcmpi(pszServerName+2, szBuf) ) {
|
|
|
|
return TRUE;
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
PSetupGetLocalDataField(
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN PLATFORM platform,
|
|
IN OUT PDRIVER_FIELD pDrvField
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Returns a driver installation field found from inf parsing.
|
|
Printui uses this routine for all the queries.
|
|
Since INF could have different sections for different platforms
|
|
(notably for Win95 and NT but architecture specific install sections
|
|
are possible too)
|
|
|
|
Arguments:
|
|
pLocalData : Pointer to local data
|
|
platform : Which platform the field is for
|
|
pDrvField : Points to DRIVER_FIELD where field is copied to
|
|
|
|
Return Value:
|
|
TRUE on success, FALSE else
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD cbSize;
|
|
LPTSTR psz;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
|
|
ASSERT(pLocalData &&
|
|
pDrvField &&
|
|
pLocalData->signature == PSETUP_SIGNATURE);
|
|
|
|
if(INVALID_HANDLE_VALUE == (hDevInfo = CreatePrinterDeviceInfoList(NULL)))
|
|
{
|
|
return bRet;
|
|
}
|
|
|
|
switch ( pDrvField->Index ) {
|
|
|
|
case DRIVER_NAME:
|
|
if ( pDrvField->pszDriverName = AllocStr(pLocalData->DrvInfo.pszModelName) )
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case INF_NAME:
|
|
if ( pDrvField->pszInfName = AllocStr(pLocalData->DrvInfo.pszInfName) )
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case DRV_INFO_4:
|
|
if ( ParseInf(hDevInfo, pLocalData, platform, NULL, 0, TRUE) &&
|
|
(pDrvField->pDriverInfo4
|
|
= (LPDRIVER_INFO_4) CloneDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
|
|
pLocalData->InfInfo.cbDriverInfo6)) )
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case DRV_INFO_6:
|
|
if ( ParseInf(hDevInfo, pLocalData, platform, NULL, 0, TRUE) &&
|
|
(pDrvField->pDriverInfo6
|
|
= CloneDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
|
|
pLocalData->InfInfo.cbDriverInfo6)) )
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case PRINT_PROCESSOR_NAME:
|
|
pDrvField->pszPrintProc = NULL;
|
|
|
|
if ( ParseInf(hDevInfo, pLocalData, platform, NULL, 0, TRUE) ) {
|
|
|
|
if ( !pLocalData->InfInfo.pszPrintProc ||
|
|
(pDrvField->pszPrintProc = AllocStr(pLocalData->InfInfo.pszPrintProc)) )
|
|
bRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ICM_FILES:
|
|
pDrvField->pszzICMFiles = NULL;
|
|
if ( ParseInf(hDevInfo, pLocalData, platform, NULL ,0, TRUE) ) {
|
|
|
|
for ( cbSize = 0, psz = pLocalData->InfInfo.pszzICMFiles ;
|
|
psz && *psz ;
|
|
cbSize += lstrlen(psz) + 1, psz += lstrlen(psz) + 1 )
|
|
;
|
|
|
|
if ( cbSize == 0 ) {
|
|
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// One more char for the last \0 in the multi-sz
|
|
//
|
|
cbSize = (cbSize + 1 ) * sizeof(TCHAR);
|
|
|
|
if ( pDrvField->pszzICMFiles = LocalAllocMem(cbSize) ) {
|
|
|
|
CopyMemory((LPBYTE)pDrvField->pszzICMFiles,
|
|
(LPBYTE)pLocalData->InfInfo.pszzICMFiles,
|
|
cbSize);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
|
|
}
|
|
|
|
DestroyOnlyPrinterDeviceInfoList(hDevInfo);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
VOID
|
|
PSetupFreeDrvField(
|
|
IN PDRIVER_FIELD pDrvField
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Frees the memory allocated for a driver installation field in a previous
|
|
call
|
|
|
|
Arguments:
|
|
pDrvField : Points to DRIVER_FIELD where field is copied to
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LocalFreeMem(pDrvField->pszPrintProc);
|
|
pDrvField->pszPrintProc = NULL;
|
|
}
|
|
|
|
BOOL
|
|
FileExists(
|
|
IN LPCTSTR pszFileName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks if the given file exists setting correct error modes not to bring
|
|
up any pop-ups.
|
|
call
|
|
|
|
Arguments:
|
|
pszFileName : File name (fully qualified)
|
|
|
|
Return Value:
|
|
TRUE if file exists, FALSE else.
|
|
|
|
--*/
|
|
{
|
|
UINT OldMode;
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
hFile = FindFirstFile(pszFileName, &FindData);
|
|
|
|
if ( hFile != INVALID_HANDLE_VALUE )
|
|
FindClose(hFile);
|
|
|
|
SetErrorMode(OldMode);
|
|
|
|
return hFile != INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
BOOL
|
|
IsLanguageMonitorInstalled(PCTSTR pszMonitorName)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Checks for whether a language monitor is installed. The function above only checks for
|
|
port monitors, because EnumMonitors doesn't enumerate language monitors. Since there is
|
|
no API to do that, we sneak a peek at the registry.
|
|
|
|
Arguments:
|
|
pszMonitorName : Monitor name to check
|
|
|
|
Return Value:
|
|
TRUE if installed
|
|
|
|
--*/
|
|
{
|
|
PTSTR pKeyName = NULL;
|
|
BOOL IsInstalled = FALSE;
|
|
|
|
StrCatAlloc(&pKeyName, cszMonitorKey, pszMonitorName, NULL);
|
|
if (pKeyName)
|
|
{
|
|
HKEY hKey;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, pKeyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
IsInstalled = TRUE;
|
|
RegCloseKey(hKey);
|
|
}
|
|
FreeSplMem(pKeyName);
|
|
}
|
|
|
|
return IsInstalled;
|
|
}
|
|
|
|
BOOL
|
|
CleanupUniqueScratchDirectory(
|
|
IN LPCTSTR pszServerName,
|
|
IN PLATFORM platform
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
TCHAR szDir[MAX_PATH];
|
|
DWORD dwNeeded;
|
|
|
|
bRet = GetPrinterDriverDirectory((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
1,
|
|
(LPBYTE)szDir,
|
|
sizeof(szDir),
|
|
&dwNeeded);
|
|
|
|
if (bRet)
|
|
{
|
|
bRet = AddDirectoryTag(szDir, MAX_PATH);
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
bRet = DeleteAllFilesInDirectory(szDir, TRUE);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CleanupScratchDirectory(
|
|
IN LPCTSTR pszServerName,
|
|
IN PLATFORM platform
|
|
)
|
|
{
|
|
TCHAR szDir[MAX_PATH];
|
|
DWORD dwNeeded;
|
|
|
|
return GetPrinterDriverDirectory((LPTSTR)pszServerName,
|
|
PlatformEnv[platform].pszName,
|
|
1,
|
|
(LPBYTE)szDir,
|
|
sizeof(szDir),
|
|
&dwNeeded) &&
|
|
DeleteAllFilesInDirectory(szDir, FALSE);
|
|
}
|
|
|
|
LPTSTR
|
|
GetSystemInstallPath(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwSize, dwType, dwLastPos;
|
|
HKEY hKey;
|
|
TCHAR szSetupKey[] = TEXT( "Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
|
|
TCHAR szSourceValue[] = TEXT("SourcePath");
|
|
LPTSTR pszSourcePath = NULL;
|
|
|
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
szSetupKey,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey) ) {
|
|
|
|
if ( ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
szSourceValue,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&dwSize) )
|
|
{
|
|
dwLastPos = (dwSize/sizeof(TCHAR)) - 1;
|
|
if (pszSourcePath = (LPTSTR) LocalAllocMem(dwSize))
|
|
{
|
|
if ( ERROR_SUCCESS != RegQueryValueEx(hKey,
|
|
szSourceValue,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pszSourcePath,
|
|
&dwSize) )
|
|
{
|
|
LocalFreeMem(pszSourcePath);
|
|
pszSourcePath = NULL;
|
|
}
|
|
else
|
|
{
|
|
pszSourcePath[dwLastPos] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return pszSourcePath;
|
|
}
|
|
|
|
PPSETUP_LOCAL_DATA
|
|
RebuildDeviceInfo(
|
|
IN HDEVINFO hDevInfo,
|
|
IN PPSETUP_LOCAL_DATA pLocalData,
|
|
IN LPCTSTR pszSource
|
|
)
|
|
{
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
SP_DRVINFO_DATA DriverInfoData, TempDriverInfoData;
|
|
PPSETUP_LOCAL_DATA pNewLocalData = NULL;
|
|
DWORD Err;
|
|
|
|
//
|
|
// Retrieve the current device install parameters, in preparation for modifying them to
|
|
// target driver search at a particular INF.
|
|
//
|
|
ZeroMemory(&DeviceInstallParams, sizeof(DeviceInstallParams));
|
|
|
|
DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
|
|
if(!SetupDiGetDeviceInstallParams(hDevInfo, pLocalData->DrvInfo.pDevInfoData, &DeviceInstallParams)) {
|
|
return NULL;
|
|
}
|
|
|
|
SetupDiDestroyDriverInfoList(hDevInfo,
|
|
NULL,
|
|
SPDIT_CLASSDRIVER);
|
|
|
|
// Set the path of the INF
|
|
StringCchCopy( DeviceInstallParams.DriverPath, COUNTOF(DeviceInstallParams.DriverPath), pszSource );
|
|
|
|
//
|
|
// set the flag that indicates DriverPath represents a single INF to be searched (and
|
|
// not a directory path). Then store the parameters back to the device information element.
|
|
//
|
|
// DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
|
|
DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
|
|
|
|
if(!SetupDiSetDeviceInstallParams(hDevInfo, pLocalData->DrvInfo.pDevInfoData, &DeviceInstallParams))
|
|
{
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Now build a class driver list from this INF.
|
|
//
|
|
if(!SetupDiBuildDriverInfoList(hDevInfo, pLocalData->DrvInfo.pDevInfoData, SPDIT_CLASSDRIVER))
|
|
{
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// OK, now select the driver node from that INF that was used to install this device.
|
|
// The three parameters that uniquely identify a driver node are INF Provider,
|
|
// Device Manufacturer, and Device Description. Retrieve these three pieces of information
|
|
// in preparation for selecting the proper driver node in the class list we just built.
|
|
//
|
|
ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
|
|
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
DriverInfoData.DriverType = SPDIT_CLASSDRIVER;
|
|
DriverInfoData.Reserved = 0; // Search for the driver matching the specified criteria and
|
|
// select it if found.
|
|
// Fill in the Model & Mfg from original INF
|
|
StringCchCopy( DriverInfoData.Description, COUNTOF(DriverInfoData.Description), pLocalData->DrvInfo.pszModelName );
|
|
StringCchCopy( DriverInfoData.MfgName, COUNTOF(DriverInfoData.MfgName), pLocalData->DrvInfo.pszManufacturer );
|
|
|
|
// Enum One driver entry to get the INF provider
|
|
ZeroMemory(&TempDriverInfoData, sizeof(TempDriverInfoData));
|
|
TempDriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
|
|
DriverInfoData.DriverType = SPDIT_CLASSDRIVER;
|
|
if (!SetupDiEnumDriverInfo (hDevInfo, NULL, SPDIT_CLASSDRIVER, 0, &TempDriverInfoData))
|
|
{
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
StringCchCopy( DriverInfoData.ProviderName, COUNTOF(DriverInfoData.ProviderName), TempDriverInfoData.ProviderName );
|
|
|
|
|
|
if(!SetupDiSetSelectedDriver(hDevInfo, pLocalData->DrvInfo.pDevInfoData, &DriverInfoData))
|
|
{
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// At this point, we've successfully selected the currently installed driver for the specified
|
|
// device information element.
|
|
//
|
|
// Now build the new LocalData
|
|
//
|
|
pNewLocalData = BuildInternalData(hDevInfo, NULL);
|
|
if ( pNewLocalData )
|
|
{
|
|
if ( !ParseInf(hDevInfo, pNewLocalData, MyPlatform, NULL, 0, FALSE) )
|
|
{
|
|
Err = GetLastError();
|
|
DestroyLocalData( pNewLocalData );
|
|
pNewLocalData = NULL;
|
|
}
|
|
else
|
|
{
|
|
SELECTED_DRV_INFO TempDrvInfo;
|
|
|
|
TempDrvInfo.pszInfName = AllocStr( pNewLocalData->DrvInfo.pszInfName );
|
|
TempDrvInfo.pszDriverSection = AllocStr( pNewLocalData->DrvInfo.pszDriverSection );
|
|
TempDrvInfo.pszModelName = AllocStr( pNewLocalData->DrvInfo.pszModelName );
|
|
TempDrvInfo.pszManufacturer = AllocStr( pNewLocalData->DrvInfo.pszManufacturer );
|
|
TempDrvInfo.pszHardwareID = AllocStr( pNewLocalData->DrvInfo.pszHardwareID );
|
|
TempDrvInfo.pszOEMUrl = AllocStr( pNewLocalData->DrvInfo.pszOEMUrl );
|
|
|
|
// Check that all strings were allocated
|
|
if ( !TempDrvInfo.pszInfName ||
|
|
!TempDrvInfo.pszDriverSection ||
|
|
!TempDrvInfo.pszModelName ||
|
|
!TempDrvInfo.pszManufacturer ||
|
|
!TempDrvInfo.pszHardwareID ||
|
|
!TempDrvInfo.pszOEMUrl )
|
|
{
|
|
// Free up all that worked
|
|
LocalFreeMem( TempDrvInfo.pszInfName );
|
|
LocalFreeMem( TempDrvInfo.pszDriverSection );
|
|
LocalFreeMem( TempDrvInfo.pszModelName );
|
|
LocalFreeMem( TempDrvInfo.pszManufacturer );
|
|
LocalFreeMem( TempDrvInfo.pszHardwareID );
|
|
LocalFreeMem( TempDrvInfo.pszOEMUrl );
|
|
|
|
}
|
|
else
|
|
{
|
|
// Free the DrvInfo pointers & refill from new local data
|
|
LocalFreeMem( pLocalData->DrvInfo.pszInfName );
|
|
LocalFreeMem( pLocalData->DrvInfo.pszDriverSection );
|
|
LocalFreeMem( pLocalData->DrvInfo.pszModelName );
|
|
LocalFreeMem( pLocalData->DrvInfo.pszManufacturer );
|
|
LocalFreeMem( pLocalData->DrvInfo.pszHardwareID );
|
|
LocalFreeMem( pLocalData->DrvInfo.pszOEMUrl );
|
|
|
|
|
|
pLocalData->DrvInfo.pszInfName = TempDrvInfo.pszInfName;
|
|
pLocalData->DrvInfo.pszDriverSection = TempDrvInfo.pszDriverSection;
|
|
pLocalData->DrvInfo.pszModelName = TempDrvInfo.pszModelName;
|
|
pLocalData->DrvInfo.pszManufacturer = TempDrvInfo.pszManufacturer;
|
|
pLocalData->DrvInfo.pszHardwareID = TempDrvInfo.pszHardwareID;
|
|
pLocalData->DrvInfo.pszOEMUrl = TempDrvInfo.pszOEMUrl;
|
|
}
|
|
|
|
Err = NO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
Err = GetLastError();
|
|
|
|
|
|
clean0:
|
|
|
|
SetLastError(Err);
|
|
return pNewLocalData;
|
|
|
|
}
|
|
|
|
BOOL
|
|
SetupSkipDir(
|
|
IN PLATFORM platform,
|
|
IN LPCTSTR pszServerName
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
//
|
|
// Temp directory length + SKIP_Dir length + ProcID length
|
|
//
|
|
TCHAR szDir[MAX_PATH + COUNTOF (SKIP_DIR) + 30 ];
|
|
TCHAR szProcId[30];
|
|
SYSTEMTIME SysTime;
|
|
DWORD dwNeeded = MAX_PATH;
|
|
|
|
EnterCriticalSection(&SkipCritSect);
|
|
|
|
// We already have a skip dir created
|
|
if ( !gpszSkipDir )
|
|
{
|
|
// Get a location for a Temp Path
|
|
// Since the files in skip dir will be deleted after
|
|
// setup is complete, so we just use a local directory
|
|
// to store the skip files
|
|
//
|
|
dwNeeded = GetTempPath (MAX_PATH, szDir);
|
|
|
|
if (dwNeeded == 0 || dwNeeded > MAX_PATH)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Add on the Skip Prefix
|
|
StringCchCat( szDir, COUNTOF(szDir), SKIP_DIR );
|
|
|
|
// Get Process Id:
|
|
StringCchPrintf( szProcId, COUNTOF(szProcId), TEXT("%lX"), GetCurrentProcessId() );
|
|
|
|
StringCchCat( szDir, COUNTOF(szDir), szProcId );
|
|
gpszSkipDir = AllocStr( szDir );
|
|
if (!gpszSkipDir )
|
|
goto Cleanup;
|
|
|
|
if (!CreateDirectory( gpszSkipDir, NULL ) )
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (!bRet)
|
|
{
|
|
if (gpszSkipDir)
|
|
{
|
|
LocalFreeMem( gpszSkipDir );
|
|
gpszSkipDir = NULL;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&SkipCritSect);
|
|
return bRet;
|
|
}
|
|
|
|
|
|
void
|
|
CleanupSkipDir(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
// We already have a skip dir created
|
|
if ( gpszSkipDir )
|
|
{
|
|
RemoveDirectory( gpszSkipDir );
|
|
LocalFreeMem( gpszSkipDir );
|
|
gpszSkipDir = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection(&SkipCritSect);
|
|
}
|
|
|
|
BOOL
|
|
IsLocalAdmin(BOOL *pbAdmin)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This Routine determines if the user is a local admin.
|
|
|
|
Parameters:
|
|
pbAdmin - Return Value, TRUE for local admin.
|
|
|
|
Return Value:
|
|
TRUE - Function succeded (return value is valid).
|
|
|
|
--*/ {
|
|
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
|
|
BOOL bRet = FALSE;
|
|
PSID pSIDAdmin = NULL;
|
|
|
|
ASSERT( pbAdmin != NULL ); // Called locally
|
|
|
|
*pbAdmin = FALSE;
|
|
|
|
if (!AllocateAndInitializeSid( &SIDAuth, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&pSIDAdmin) )
|
|
goto Cleanup;
|
|
|
|
if (!CheckTokenMembership( NULL,
|
|
pSIDAdmin,
|
|
pbAdmin ) )
|
|
goto Cleanup;
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (pSIDAdmin != NULL) {
|
|
FreeSid( pSIDAdmin );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PruneInvalidFilesIfNotAdmin(
|
|
IN HWND hWnd,
|
|
IN OUT HSPFILEQ CopyQueue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine checks whether you have administrator privileges, if you do, then
|
|
it does nothing and returns. If you do not, it scans the file queue for files
|
|
that are already present and signed and prunes them from the queue. The commit
|
|
will not allow mixing signed and unsigned files.
|
|
Note: We do this because if you are a power-user the call to MoveFileEx fails inside
|
|
SetupCommitFileQueue, this happens if the existing file cannot be overwritten. We
|
|
could improve this routine by checking if a file is actually in use before pruning
|
|
it.
|
|
|
|
Parameters:
|
|
CopyQueue - The copy queue to scan.
|
|
|
|
Return Value:
|
|
TRUE - Either you were an administrator and no action was taken, or
|
|
you were not and the FileQueue was successfully pruned.
|
|
FALSE - The operation failed.
|
|
|
|
--*/ {
|
|
BOOL bLocalAdmin;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwScanQueueResult;
|
|
|
|
if (!IsLocalAdmin( &bLocalAdmin) )
|
|
goto Cleanup;
|
|
|
|
if (bLocalAdmin) {
|
|
bRet = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!SetupScanFileQueue( CopyQueue,
|
|
SPQ_SCAN_FILE_PRESENCE | SPQ_SCAN_PRUNE_COPY_QUEUE,
|
|
hWnd ,
|
|
NULL ,
|
|
NULL ,
|
|
&dwScanQueueResult ) )
|
|
|
|
goto Cleanup;
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
AddDriverCatalogIfNotAdmin(
|
|
IN PCWSTR pszServer,
|
|
IN HANDLE hDriverSigningInfo,
|
|
IN PCWSTR pszInfPath,
|
|
IN PCWSTR pszSrcLoc,
|
|
IN DWORD dwMediaType,
|
|
IN DWORD dwCopyStyle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls AddDriverCatalog for non-admin, aka power user.
|
|
|
|
Parameters:
|
|
|
|
pszServer - Name of the server
|
|
hDriverSigningInfo - Handle to driver signing info
|
|
|
|
Return Value:
|
|
|
|
TRUE - Either you are an administrator and no action was taken,
|
|
or you are not and the catalog was successfully added
|
|
FALSE - The operation failed. Call GetLastError() to get
|
|
detailed error information
|
|
|
|
--*/ {
|
|
BOOL bRet = FALSE;
|
|
BOOL bLocalAdmin = TRUE;
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_DEFAULTS PrinterDefaults = {0};
|
|
DRIVER_INFCAT_INFO_1 DrvInfCatInfo1 = {0};
|
|
DRIVER_INFCAT_INFO_2 DrvInfCatInfo2 = {0};
|
|
PCWSTR pszCatPath = NULL;
|
|
|
|
if (!hDriverSigningInfo ||
|
|
!DrvSigningIsLocalAdmin(hDriverSigningInfo, &bLocalAdmin) ||
|
|
!GetCatalogFile(hDriverSigningInfo, &pszCatPath))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If there is no Cat file or we are local admin, there is nothing to do
|
|
// because for local admin, we use setup api to install the catalog file
|
|
//
|
|
if (!pszCatPath || bLocalAdmin)
|
|
{
|
|
bRet = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
PrinterDefaults.DesiredAccess = SERVER_ALL_ACCESS;
|
|
|
|
if (!OpenPrinterW((PWSTR) pszServer, &hPrinter, &PrinterDefaults))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If there is a catalogfile entry in the inf file, we should call private
|
|
// spooler API AddDriverCatalog with level 2 to install the catalog which
|
|
// will install the inf and cat file by calling SetupCopyOEMInf. For inf
|
|
// files that do not have catalogfile entry we shall call AddDriverCatalog
|
|
// with level 1 which will install the catalog by using CryptoAPI
|
|
//
|
|
if (!IsCatInInf(hDriverSigningInfo))
|
|
{
|
|
DrvInfCatInfo1.pszCatPath = pszCatPath;
|
|
|
|
if (!AddDriverCatalog(hPrinter, 1, &DrvInfCatInfo1, APDC_USE_ORIGINAL_CAT_NAME))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DrvInfCatInfo2.pszCatPath = pszCatPath;
|
|
DrvInfCatInfo2.pszInfPath = pszInfPath;
|
|
DrvInfCatInfo2.pszSrcLoc = pszSrcLoc;
|
|
DrvInfCatInfo2.dwMediaType = dwMediaType;
|
|
DrvInfCatInfo2.dwCopyStyle = dwCopyStyle;
|
|
|
|
if (!AddDriverCatalog(hPrinter, 2, &DrvInfCatInfo2, APDC_NONE))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (hPrinter)
|
|
{
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*
|
|
|
|
Function: AddDirectoryTag
|
|
|
|
pszDir - TCHAR string to add the two tags to.
|
|
dwSize - size in CHARACTERs of the allocated string buffer.
|
|
|
|
Purpose - Takes the string pszDir and tags on "\dwPIDdwTID" on the end of it.
|
|
This is used in the creation of a unique directory to copy the driver
|
|
files for a specific install to.
|
|
|
|
*/
|
|
BOOL
|
|
AddDirectoryTag(
|
|
IN LPTSTR pszDir,
|
|
IN DWORD dwSize )
|
|
{
|
|
DWORD dwDirSize,
|
|
dwPID,
|
|
dwTID;
|
|
PTCHAR pEnd;
|
|
|
|
if( !pszDir || !dwSize || !(dwDirSize = lstrlen( pszDir )) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
dwPID = GetCurrentProcessId();
|
|
dwTID = GetCurrentThreadId();
|
|
|
|
if( (pszDir[dwDirSize-1] != _TEXT('\\')) &&
|
|
(dwDirSize + 1 < dwSize) )
|
|
{
|
|
pszDir[dwDirSize++] = _TEXT('\\');
|
|
pszDir[dwDirSize] = 0;
|
|
}
|
|
|
|
pEnd = &pszDir[dwDirSize];
|
|
|
|
return SUCCEEDED(StringCchPrintf( pEnd,
|
|
(dwSize-dwDirSize),
|
|
_TEXT("%d%d"),
|
|
dwPID,
|
|
dwTID ));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Function: AddPnpDirTag
|
|
|
|
pszDir - TCHAR string to add the tag to.
|
|
dwSize - size in CHARACTERs of the allocated string buffer.
|
|
|
|
Purpose - Takes the string pszDir and tags on the pnp-ID on to it.
|
|
This is used in the creation of a unique directory to copy the driver
|
|
files for a specific install to.
|
|
|
|
*/
|
|
BOOL
|
|
AddPnpDirTag(
|
|
IN LPTSTR pszHardwareId,
|
|
IN OUT LPTSTR pszDir,
|
|
IN DWORD dwSize )
|
|
{
|
|
DWORD dwDirSize;
|
|
PTCHAR pEnd, pPnpId;
|
|
|
|
if( !pszHardwareId ||
|
|
!pszDir ||
|
|
!dwSize ||
|
|
!(dwDirSize = lstrlen( pszDir )) ||
|
|
dwSize < dwDirSize + 3 ) // need at least space for backslash, one char + 0 terminator
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
if( (pszDir[dwDirSize-1] != _TEXT('\\')))
|
|
{
|
|
pszDir[dwDirSize++] = _TEXT('\\');
|
|
pszDir[dwDirSize] = 0;
|
|
}
|
|
|
|
pEnd = &pszDir[dwDirSize];
|
|
|
|
//
|
|
// Try to strip off the port enumerator, if applicable. The printer driver
|
|
// should be independent of it.
|
|
//
|
|
if ((pPnpId = _tcsrchr(pszHardwareId, _TEXT('\\'))) == NULL)
|
|
{
|
|
//
|
|
// it doesn't have a port enumerator, so the whole thing is the pnp ID
|
|
//
|
|
pPnpId = pszHardwareId;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// found one: advance one beyond it if it's not the last character
|
|
// to illustrate LPTENUM\abcd would become \abcd instead of abcd
|
|
//
|
|
if (*(pPnpId+1))
|
|
{
|
|
pPnpId++;
|
|
}
|
|
}
|
|
StringCchCopy(pEnd, dwSize - dwDirSize, pPnpId);
|
|
|
|
//
|
|
// change all suspicious characters to underscores to avoid problems with / & \ etc.
|
|
// all the distinguishing information should be in the alphanumerical characters
|
|
//
|
|
while (*pEnd)
|
|
{
|
|
if (!_istalnum(*pEnd))
|
|
{
|
|
*pEnd = _TEXT('_');
|
|
}
|
|
pEnd++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
|
|
Function: AddDirToDriverInfo
|
|
|
|
pszDir - Directory to append to driver info structure.
|
|
pDriverInfo6 - Pointer to the driver info structure to update.
|
|
|
|
Purpose: This function will ensure that there is no directory structure specified in the
|
|
driver info structure yet (so as not to add it multiple times).
|
|
If there isn't then it will update the driver file entries with the full path
|
|
passed in in pszDir.
|
|
|
|
*/
|
|
BOOL
|
|
AddDirToDriverInfo(
|
|
IN LPTSTR pszDir,
|
|
IN LPDRIVER_INFO_6 pDriverInfo6
|
|
)
|
|
{
|
|
PTCHAR pOldString,
|
|
pCurrentString,
|
|
pNewString;
|
|
DWORD dwLength,
|
|
dwDirLength,
|
|
dwNeeded = 0;
|
|
|
|
if( !pszDir || !pDriverInfo6 )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If the path is zero length, nothing to do.
|
|
//
|
|
if( !(dwDirLength = lstrlen( pszDir )) )
|
|
return TRUE;
|
|
|
|
if( pDriverInfo6->pDriverPath &&
|
|
FileNamePart( pDriverInfo6->pDriverPath ) == pDriverInfo6->pDriverPath )
|
|
{
|
|
pOldString = pDriverInfo6->pDriverPath;
|
|
|
|
pDriverInfo6->pDriverPath = AllocAndCatStr2( pszDir, _TEXT("\\"), pOldString );
|
|
|
|
LocalFreeMem( pOldString );
|
|
pOldString = NULL;
|
|
}
|
|
|
|
if( pDriverInfo6->pDataFile &&
|
|
FileNamePart( pDriverInfo6->pDataFile ) == pDriverInfo6->pDataFile )
|
|
{
|
|
pOldString = pDriverInfo6->pDataFile;
|
|
|
|
pDriverInfo6->pDataFile = AllocAndCatStr2( pszDir, _TEXT("\\"), pOldString );
|
|
|
|
LocalFreeMem( pOldString );
|
|
pOldString = NULL;
|
|
}
|
|
|
|
if( pDriverInfo6->pConfigFile &&
|
|
FileNamePart( pDriverInfo6->pConfigFile ) == pDriverInfo6->pConfigFile )
|
|
{
|
|
pOldString = pDriverInfo6->pConfigFile;
|
|
|
|
pDriverInfo6->pConfigFile = AllocAndCatStr2( pszDir, _TEXT("\\"), pOldString );
|
|
|
|
LocalFreeMem( pOldString );
|
|
pOldString = NULL;
|
|
}
|
|
|
|
if( pDriverInfo6->pHelpFile &&
|
|
FileNamePart( pDriverInfo6->pHelpFile ) == pDriverInfo6->pHelpFile )
|
|
{
|
|
pOldString = pDriverInfo6->pHelpFile;
|
|
|
|
pDriverInfo6->pHelpFile = AllocAndCatStr2( pszDir, _TEXT("\\"), pOldString );
|
|
|
|
LocalFreeMem( pOldString );
|
|
pOldString = NULL;
|
|
}
|
|
|
|
if( pDriverInfo6->pDependentFiles )
|
|
{
|
|
pCurrentString = pDriverInfo6->pDependentFiles;
|
|
|
|
while( *pCurrentString )
|
|
{
|
|
dwLength = lstrlen( pCurrentString );
|
|
if( pCurrentString == FileNamePart( pCurrentString ) )
|
|
{
|
|
//
|
|
// Amount needed - the two lengths + \ + 0
|
|
//
|
|
dwNeeded += dwLength + dwDirLength + 1 + 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Amount needed - the existing + 0
|
|
//
|
|
dwNeeded += dwLength + 1;
|
|
}
|
|
|
|
pCurrentString += dwLength + 1;
|
|
}
|
|
|
|
//
|
|
// Increment for the final 0
|
|
//
|
|
dwNeeded++;
|
|
|
|
if(pNewString = LocalAllocMem( dwNeeded*sizeof(TCHAR) ))
|
|
{
|
|
pCurrentString = pNewString;
|
|
|
|
pOldString = pDriverInfo6->pDependentFiles;
|
|
|
|
while( *pOldString )
|
|
{
|
|
if( pOldString == FileNamePart( pOldString ) )
|
|
{
|
|
//
|
|
// Add the directory info.
|
|
//
|
|
StringCchCopy( pCurrentString, dwNeeded - (pCurrentString - pNewString), pszDir );
|
|
pCurrentString += dwDirLength;
|
|
*pCurrentString++ = _TEXT('\\');
|
|
}
|
|
|
|
//
|
|
// Add the existing file info.
|
|
//
|
|
StringCchCopy( pCurrentString, dwNeeded - (pCurrentString - pNewString), pOldString);
|
|
|
|
pCurrentString += lstrlen( pOldString );
|
|
*pCurrentString++ = 0;
|
|
pOldString += lstrlen( pOldString ) + 1;
|
|
}
|
|
*pCurrentString = 0;
|
|
|
|
LocalFreeMem( pDriverInfo6->pDependentFiles );
|
|
|
|
pDriverInfo6->pDependentFiles = pNewString;
|
|
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
IsSystemSetupInProgress(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Tells if we are in the middle of system setup (GUI mode)
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
TRUE if system setup in progress, FALSE else
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwValue = 0, dwSize;
|
|
|
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
cszSystemSetupKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) ) {
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if( ERROR_SUCCESS != RegQueryValueEx(hKey, cszSystemSetupInProgress, NULL, NULL,
|
|
(LPBYTE)&dwValue, &dwSize) ) {
|
|
dwValue = 0;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return dwValue == 1;
|
|
}
|
|
|
|
/*
|
|
|
|
Function: GetMyTempDir
|
|
|
|
Purpose: Creates a unique temporary directory off the TEMP directory.
|
|
This gets called by UnCompressCat to create a unique directory to store the cat
|
|
file that is to be expanded in.
|
|
|
|
Returns: NULL if failed. The full qualified path to the new directory otherwise.
|
|
|
|
Note: The returned string does contain the ending '\'.
|
|
|
|
*/
|
|
LPTSTR
|
|
GetMyTempDir()
|
|
{
|
|
LPTSTR pszPath = NULL;
|
|
PTCHAR pEnd;
|
|
DWORD dwSize = 0;
|
|
DWORD dwActualSize = 0;
|
|
DWORD dwThreadID = GetCurrentThreadId();
|
|
DWORD dwProcessID = GetCurrentProcessId();
|
|
DWORD dwIDCounter = dwThreadID;
|
|
BOOL bContinue = TRUE;
|
|
|
|
dwSize = GetTempPath( 0, pszPath );
|
|
//
|
|
// dwSize + size of the two DWORDs + \ + 0
|
|
//
|
|
dwActualSize = dwSize+MAX_DWORD_LENGTH*2+2;
|
|
|
|
if( dwSize &&
|
|
NULL != (pszPath = (LPTSTR)LocalAllocMem(dwActualSize*sizeof(TCHAR))))
|
|
{
|
|
//
|
|
// If this fails, then we assume that someone is playing with the temp path at the instant that
|
|
// we are requesting it - unlikely so just fail (worst effect = probably leads to driver signing warning)
|
|
//
|
|
if( dwSize >= GetTempPath( dwSize, pszPath ))
|
|
{
|
|
dwSize = lstrlen(pszPath);
|
|
|
|
pEnd = &pszPath[lstrlen(pszPath)];
|
|
|
|
do
|
|
{
|
|
StringCchPrintf( pEnd, dwActualSize-dwSize, _TEXT("%d%d%s"),
|
|
dwProcessID, dwIDCounter, _TEXT("\\") );
|
|
|
|
if(CreateDirectory( pszPath, NULL ) || GetLastError() == ERROR_FILE_EXISTS)
|
|
{
|
|
//
|
|
// We've got a directory, so drop out of loop.
|
|
//
|
|
bContinue = FALSE;
|
|
}
|
|
dwIDCounter++;
|
|
|
|
//
|
|
// Will stop loop when we have an unused directory or we loop round on the dwIDCounter
|
|
//
|
|
} while (bContinue && dwIDCounter != dwThreadID);
|
|
|
|
if(bContinue)
|
|
{
|
|
LocalFreeMem( pszPath );
|
|
pszPath = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LocalFreeMem( pszPath );
|
|
pszPath = NULL;
|
|
}
|
|
}
|
|
|
|
return pszPath;
|
|
}
|
|
|
|
BOOL
|
|
GetOSVersion(
|
|
IN LPCTSTR pszServerName,
|
|
OUT POSVERSIONINFO pOSVer
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if(pOSVer)
|
|
{
|
|
ZeroMemory(pOSVer,sizeof(OSVERSIONINFO));
|
|
pOSVer->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if(!pszServerName || !*pszServerName)
|
|
{
|
|
bRet = GetVersionEx(pOSVer);
|
|
}
|
|
else
|
|
{
|
|
HANDLE hServer = NULL;
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwType = REG_BINARY;
|
|
PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_READ };
|
|
|
|
//
|
|
// Open the server for read access.
|
|
//
|
|
if( OpenPrinter( (LPTSTR) pszServerName, &hServer, &Defaults ) )
|
|
{
|
|
//
|
|
// Get the os version from the remote spooler.
|
|
//
|
|
if( ERROR_SUCCESS == ( GetPrinterData( hServer,
|
|
SPLREG_OS_VERSION,
|
|
&dwType,
|
|
(PBYTE)pOSVer,
|
|
sizeof( OSVERSIONINFO ),
|
|
&dwNeeded ) ) )
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Assume that we're on NT4 as it doesn't support SPLREG_OS_VERSION
|
|
// at it's the only OS that doesn't that could land up in this remote code path.
|
|
//
|
|
ZeroMemory(pOSVer, sizeof(OSVERSIONINFO));
|
|
|
|
pOSVer->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
pOSVer->dwMajorVersion = 4;
|
|
pOSVer->dwMinorVersion = 0;
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
ClosePrinter( hServer );
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
GetArchitecture(
|
|
IN LPCTSTR pszServerName,
|
|
OUT LPTSTR pszArch,
|
|
IN OUT LPDWORD pcArchSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Obtains the local or remote server's architecture.
|
|
|
|
Arguments:
|
|
pszServerName - NULL = local machine.
|
|
pszArch - will hold the machine's architecture.
|
|
cArchSize - IN - size of pszArch in characters.
|
|
OUT - character count that was filled.
|
|
If failure is ERROR_MORE_DATA it will hold the needed character count.
|
|
|
|
Return Value:
|
|
TRUE on success.
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwByteCount = 0;
|
|
DWORD cLen = 0;
|
|
|
|
if( !pszArch )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
}
|
|
else
|
|
{
|
|
*pszArch = 0;
|
|
|
|
if( !pszServerName || !*pszServerName )
|
|
{
|
|
cLen = _tcslen(PlatformEnv[MyPlatform].pszName);
|
|
|
|
if( cLen <= *pcArchSize )
|
|
{
|
|
StringCchCopy( pszArch, *pcArchSize, PlatformEnv[MyPlatform].pszName );
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
*pcArchSize = cLen;
|
|
}
|
|
else
|
|
{
|
|
HANDLE hServer = NULL;
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwType = REG_SZ;
|
|
PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_READ };
|
|
|
|
//
|
|
// Open the server for read access.
|
|
//
|
|
if( OpenPrinter( (LPTSTR) pszServerName, &hServer, &Defaults ) )
|
|
{
|
|
dwByteCount = *pcArchSize * sizeof( TCHAR );
|
|
|
|
//
|
|
// Get the os version from the remote spooler.
|
|
//
|
|
if((ERROR_SUCCESS == GetPrinterData(hServer,
|
|
SPLREG_ARCHITECTURE,
|
|
&dwType,
|
|
(PBYTE)pszArch,
|
|
dwByteCount,
|
|
&dwNeeded)) && (dwType == REG_SZ))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pszArch = 0;
|
|
}
|
|
|
|
*pcArchSize = dwNeeded / sizeof(TCHAR);
|
|
|
|
ClosePrinter( hServer );
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL IsInWow64()
|
|
//
|
|
// find out whether we're running in WOW64
|
|
//
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG_PTR ul;
|
|
NTSTATUS st;
|
|
|
|
|
|
st = NtQueryInformationProcess(NtCurrentProcess(),
|
|
ProcessWow64Information,
|
|
&ul,
|
|
sizeof(ul),
|
|
NULL);
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
//
|
|
// If this call succeeds, we're on Win2000 or newer machines.
|
|
//
|
|
if (0 != ul)
|
|
{
|
|
//
|
|
// 32-bit code running on Win64
|
|
//
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsWhistlerOrAbove(
|
|
IN LPCTSTR pszServerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Determines whether the machine identified by ServerName is at least OS version 5.1
|
|
|
|
Arguments:
|
|
pszServerName - the name of the remote server. NULL means local machine.
|
|
|
|
Return Value:
|
|
TRUE if the remote server is whistler or more recent server or local
|
|
FALSE else
|
|
|
|
--*/
|
|
|
|
{
|
|
OSVERSIONINFO OsVer = {0};
|
|
BOOL bRet = FALSE;
|
|
|
|
if (!pszServerName)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else if (GetOSVersion(pszServerName,&OsVer))
|
|
{
|
|
if( (OsVer.dwMajorVersion > 5) ||
|
|
(OsVer.dwMajorVersion == 5 && OsVer.dwMinorVersion > 0) )
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IsProductType(
|
|
IN BYTE ProductType,
|
|
IN BYTE Comparison
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Determines whether the version of the OS is personal, professional or server
|
|
depending on the given ProductType and Comparison
|
|
|
|
Arguments:
|
|
ProductType - VER_NT_WORKSTATION or VER_NT_SERVER
|
|
Comaprison - VER_EQUAL, VER_GREATER, VER_GREATER_EQUAL, VER_LESS, VER_LESS_EQUAL
|
|
|
|
Return Value:
|
|
S_OK if the OS version if the OS satisfies the given conditions
|
|
S_FALSE else
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRetval = S_FALSE;
|
|
OSVERSIONINFOEX OsVerEx = {0};
|
|
ULONGLONG dwlConditionMask = 0;
|
|
|
|
OsVerEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
OsVerEx.wProductType = ProductType;
|
|
|
|
VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, Comparison );
|
|
|
|
if (VerifyVersionInfo(&OsVerEx, VER_PRODUCT_TYPE, dwlConditionMask))
|
|
{
|
|
hRetval = S_OK;
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
|
|
HMODULE LoadLibraryUsingFullPath(
|
|
LPCTSTR lpFileName
|
|
)
|
|
{
|
|
TCHAR szSystemPath[MAX_PATH];
|
|
INT cLength = 0;
|
|
INT cFileNameLength = 0;
|
|
|
|
|
|
if (!lpFileName || ((cFileNameLength = lstrlen(lpFileName)) == 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
if (GetSystemDirectory(szSystemPath, SIZECHARS(szSystemPath) ) == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
cLength = lstrlen(szSystemPath);
|
|
if (szSystemPath[cLength-1] != TEXT('\\'))
|
|
{
|
|
if ((cLength + 1) >= COUNTOF(szSystemPath))
|
|
{
|
|
return NULL;
|
|
}
|
|
szSystemPath[cLength] = TEXT('\\');
|
|
szSystemPath[cLength + 1] = TEXT('\0');
|
|
cLength++;
|
|
}
|
|
if ((cLength + cFileNameLength) >= MAX_PATH)
|
|
{
|
|
return NULL;
|
|
}
|
|
StringCchCat(szSystemPath, COUNTOF(szSystemPath), lpFileName);
|
|
|
|
return LoadLibrary( szSystemPath );
|
|
}
|
|
|
|
BOOL
|
|
IsSpoolerRunning(
|
|
VOID
|
|
)
|
|
{
|
|
HANDLE ph;
|
|
BOOL IsRunning = FALSE;
|
|
|
|
if (OpenPrinter(NULL, &ph, NULL))
|
|
{
|
|
IsRunning = TRUE;
|
|
ClosePrinter(ph);
|
|
}
|
|
|
|
return IsRunning;
|
|
}
|
|
|
|
BOOL
|
|
CheckAndKeepPreviousNames(
|
|
IN LPCTSTR pszServer,
|
|
IN PDRIVER_INFO_6 pDriverInfo6,
|
|
IN PLATFORM platform
|
|
)
|
|
{
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwReturned = 0;
|
|
DWORD dwIndex = 0;
|
|
LPDRIVER_INFO_4 pCurDriverInfo = NULL;
|
|
BOOL bRet = FALSE;
|
|
INT cPrevNamesLength = 0;
|
|
|
|
PLATFORM Platform2Enumerate = pszServer ? platform : MyPlatform;
|
|
|
|
if (pDriverInfo6 && pDriverInfo6->pName &&
|
|
(*(pDriverInfo6->pName) == TEXT('\0')) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
if ( !EnumPrinterDrivers((LPTSTR)pszServer,
|
|
PlatformEnv[Platform2Enumerate].pszName,
|
|
4,
|
|
(LPBYTE)pCurDriverInfo,
|
|
0,
|
|
&dwNeeded,
|
|
&dwReturned) )
|
|
{
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
|
|
!(pCurDriverInfo = LocalAllocMem(dwNeeded)) ||
|
|
!EnumPrinterDrivers((LPTSTR)pszServer,
|
|
PlatformEnv[Platform2Enumerate].pszName,
|
|
4,
|
|
(LPBYTE)pCurDriverInfo,
|
|
dwNeeded,
|
|
&dwNeeded,
|
|
&dwReturned) ||
|
|
(dwReturned <= 0))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
if (!pCurDriverInfo)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
for (dwIndex = 0; dwIndex < dwReturned; dwIndex++)
|
|
{
|
|
if ((pCurDriverInfo+dwIndex)->pName &&
|
|
(*(pCurDriverInfo+dwIndex)->pName != TEXT('\0')) &&
|
|
!lstrcmp(pDriverInfo6->pName,(pCurDriverInfo+dwIndex)->pName) )
|
|
{
|
|
if ((pCurDriverInfo+dwIndex)->pszzPreviousNames &&
|
|
(*(pCurDriverInfo+dwIndex)->pszzPreviousNames != TEXT('\0')))
|
|
{
|
|
cPrevNamesLength = lstrlen((pCurDriverInfo+dwIndex)->pszzPreviousNames);
|
|
pDriverInfo6->pszzPreviousNames = (LPTSTR)LocalAllocMem( (cPrevNamesLength + 2) * sizeof(TCHAR) );
|
|
if (pDriverInfo6->pszzPreviousNames)
|
|
{
|
|
bRet = TRUE;
|
|
CopyMemory( pDriverInfo6->pszzPreviousNames, (pCurDriverInfo+dwIndex)->pszzPreviousNames, cPrevNamesLength * sizeof(TCHAR) );
|
|
*(pDriverInfo6->pszzPreviousNames + cPrevNamesLength) = TEXT('\0');
|
|
*(pDriverInfo6->pszzPreviousNames + cPrevNamesLength + 1) = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (pCurDriverInfo)
|
|
{
|
|
LocalFreeMem(pCurDriverInfo);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
IsTheSamePlatform(
|
|
IN LPCTSTR pszServer,
|
|
IN PLATFORM platform
|
|
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwServerArchSize = 0;
|
|
DWORD dwServerArchSizeInChars = 0;
|
|
TCHAR *pszServerArchitecture = NULL;
|
|
|
|
if (!pszServer)
|
|
{
|
|
bRet = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
dwServerArchSizeInChars = lstrlen( PlatformEnv[platform].pszName ) + 1;
|
|
dwServerArchSize = dwServerArchSizeInChars * sizeof(TCHAR);
|
|
pszServerArchitecture = LocalAllocMem(dwServerArchSize);
|
|
if (!pszServerArchitecture ||
|
|
!GetArchitecture(pszServer, pszServerArchitecture, &dwServerArchSizeInChars ))
|
|
{
|
|
bRet = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
bRet = !lstrcmp( pszServerArchitecture, PlatformEnv[platform].pszName );
|
|
|
|
Cleanup:
|
|
|
|
if (pszServerArchitecture)
|
|
{
|
|
LocalFreeMem( pszServerArchitecture );
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
GetArchitectureName(
|
|
IN LPCTSTR pszServerName
|
|
)
|
|
{
|
|
LPTSTR pszArch = NULL;
|
|
DWORD dwArchSize = 80;
|
|
|
|
if (pszServerName && (*pszServerName == TEXT('\0')))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
if (!pszServerName)
|
|
{
|
|
return AllocStr( PlatformEnv[MyPlatform].pszName );
|
|
}
|
|
pszArch = LocalAllocMem( dwArchSize * sizeof(TCHAR));
|
|
if (!pszArch)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (!GetArchitecture( pszServerName, pszArch, &dwArchSize))
|
|
{
|
|
if (GetLastError() == ERROR_MORE_DATA)
|
|
{
|
|
LocalFreeMem( pszArch );
|
|
dwArchSize += 1;
|
|
pszArch = LocalAllocMem( dwArchSize * sizeof(TCHAR) );
|
|
if (!pszArch ||
|
|
!GetArchitecture( pszServerName, pszArch, &dwArchSize))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return pszArch;
|
|
}
|
|
|
|
/************************************************************************************
|
|
** End of File (util.c)
|
|
************************************************************************************/
|
|
|