mirror of https://github.com/lianthony/NT4.0
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.
1972 lines
52 KiB
1972 lines
52 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
infopenv.c
|
|
|
|
Abstract:
|
|
|
|
Externally exposed INF routines for INF opening, closing,
|
|
and versioning.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 20-Jan-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "setupntp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
BOOL
|
|
pSetupVersionNodeFromInfInformation(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
OUT PINF_VERSION_NODE VersionNode
|
|
);
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupGetInfInformationA(
|
|
IN LPCVOID InfSpec,
|
|
IN DWORD SearchControl,
|
|
OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR infspec;
|
|
BOOL b;
|
|
DWORD rc;
|
|
|
|
//
|
|
// For this API, the return buffer does not have to be translated
|
|
// from Unicode to ANSI. This makes things much easier since the
|
|
// required size is the same for the ANSI and Unicode versions.
|
|
//
|
|
if((SearchControl == INFINFO_INF_NAME_IS_ABSOLUTE)
|
|
|| (SearchControl == INFINFO_DEFAULT_SEARCH)
|
|
|| (SearchControl == INFINFO_REVERSE_DEFAULT_SEARCH)
|
|
|| (SearchControl == INFINFO_INF_PATH_LIST_SEARCH)) {
|
|
|
|
rc = CaptureAndConvertAnsiArg(InfSpec,&infspec);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Not a pointer to a string, just pass it on.
|
|
//
|
|
infspec = InfSpec;
|
|
}
|
|
|
|
//
|
|
// Note that the data returned from this API is in an
|
|
// internal format, and thus we don't need any less space
|
|
// for the ANSI API, and can just use the buffer and sizes
|
|
// passed in by the caller.
|
|
//
|
|
b = SetupGetInfInformationW(
|
|
infspec,
|
|
SearchControl,
|
|
ReturnBuffer,
|
|
ReturnBufferSize,
|
|
RequiredSize
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(infspec != InfSpec) {
|
|
MyFree(infspec);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupGetInfInformationW(
|
|
IN LPCVOID InfSpec,
|
|
IN DWORD SearchControl,
|
|
OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(InfSpec);
|
|
UNREFERENCED_PARAMETER(SearchControl);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupGetInfInformation(
|
|
IN LPCVOID InfSpec,
|
|
IN DWORD SearchControl,
|
|
OUT PSP_INF_INFORMATION ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL UnloadInf;
|
|
PLOADED_INF Inf, CurInf;
|
|
UINT InfCount;
|
|
PUCHAR Out;
|
|
DWORD TotalSpaceRequired;
|
|
DWORD d;
|
|
DWORD ErrorLineNumber;
|
|
TCHAR Path[MAX_PATH];
|
|
PINF_VERSION_NODE VersionNode;
|
|
INF_VERSION_BLOCK UNALIGNED *Prev;
|
|
BOOL TryPnf;
|
|
WIN32_FIND_DATA FindData;
|
|
PTSTR DontCare;
|
|
|
|
//
|
|
// Set up some state based on the SearchSpec parameter.
|
|
//
|
|
Inf = NULL;
|
|
switch(SearchControl) {
|
|
|
|
case INFINFO_INF_SPEC_IS_HINF:
|
|
|
|
Inf = (PLOADED_INF)InfSpec;
|
|
break;
|
|
|
|
case INFINFO_INF_NAME_IS_ABSOLUTE:
|
|
//
|
|
// Make sure we have a fully-qualified path.
|
|
//
|
|
if(GetFullPathName((PCTSTR)InfSpec, SIZECHARS(Path), Path, &DontCare) &&
|
|
FileExists(Path, &FindData)) {
|
|
|
|
InfSourcePathFromFileName(Path, NULL, &TryPnf);
|
|
break;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
case INFINFO_DEFAULT_SEARCH:
|
|
case INFINFO_REVERSE_DEFAULT_SEARCH:
|
|
case INFINFO_INF_PATH_LIST_SEARCH:
|
|
|
|
d = SearchForInfFile((PCTSTR)InfSpec,
|
|
&FindData,
|
|
SearchControl,
|
|
Path,
|
|
SIZECHARS(Path),
|
|
NULL
|
|
);
|
|
|
|
if(d == NO_ERROR) {
|
|
TryPnf = TRUE;
|
|
break;
|
|
} else {
|
|
SetLastError(d);
|
|
return FALSE;
|
|
}
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Load the inf if necessary.
|
|
//
|
|
if(Inf) {
|
|
UnloadInf = FALSE;
|
|
} else {
|
|
|
|
d = LoadInfFile(Path,
|
|
&FindData,
|
|
INF_STYLE_ALL,
|
|
TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Inf,
|
|
&ErrorLineNumber
|
|
);
|
|
|
|
if(d != NO_ERROR) {
|
|
SetLastError(d);
|
|
return(FALSE);
|
|
}
|
|
|
|
UnloadInf = TRUE;
|
|
}
|
|
|
|
//
|
|
// Determine the number of infs associated with this handle,
|
|
// and calculate the amount of space that will be needed to
|
|
// store version information about them.
|
|
//
|
|
// For each inf we will need space for the version block,
|
|
// as well as an offset in the SP_INF_INFORMATION structure
|
|
// to indicate where that inf's version block is located
|
|
// in the output buffer.
|
|
//
|
|
TotalSpaceRequired = offsetof(SP_INF_INFORMATION, VersionData);
|
|
for(InfCount = 0, CurInf = Inf;
|
|
CurInf;
|
|
InfCount++, CurInf = CurInf->Next)
|
|
{
|
|
TotalSpaceRequired += (offsetof(INF_VERSION_BLOCK, Filename) +
|
|
CurInf->VersionBlock.FilenameSize + CurInf->VersionBlock.DataSize);
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
*RequiredSize = TotalSpaceRequired;
|
|
}
|
|
|
|
//
|
|
// See if we have a large enough output buffer.
|
|
// If we have a large enough buffer then set up some
|
|
// initial values in it.
|
|
//
|
|
if(ReturnBufferSize < TotalSpaceRequired) {
|
|
if(UnloadInf) {
|
|
FreeInfFile(Inf);
|
|
}
|
|
if(ReturnBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
d = NO_ERROR;
|
|
|
|
try {
|
|
ReturnBuffer->InfStyle = Inf->Style;
|
|
ReturnBuffer->InfCount = InfCount;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
if(UnloadInf) {
|
|
FreeInfFile(Inf);
|
|
}
|
|
SetLastError(d = ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if(d != NO_ERROR) {
|
|
return FALSE;
|
|
}
|
|
|
|
Out = (PUCHAR)ReturnBuffer + offsetof(SP_INF_INFORMATION, VersionData);
|
|
|
|
//
|
|
// Traverse all infs associated with this inf handle and copy
|
|
// version data into the caller's buffer. Guard with SEH to ensure
|
|
// that the caller passed a valid buffer.
|
|
//
|
|
try {
|
|
Prev = NULL;
|
|
for(CurInf = Inf; CurInf; CurInf = CurInf->Next) {
|
|
//
|
|
// Store offset into
|
|
//
|
|
if(Prev) {
|
|
Prev->NextOffset = (UINT)Out - (UINT)ReturnBuffer;
|
|
}
|
|
Prev = (PVOID)Out;
|
|
|
|
Prev->LastWriteTime = CurInf->VersionBlock.LastWriteTime;
|
|
Prev->DatumCount = CurInf->VersionBlock.DatumCount;
|
|
Prev->OffsetToData = CurInf->VersionBlock.FilenameSize;
|
|
Prev->DataSize = CurInf->VersionBlock.DataSize;
|
|
Prev->TotalSize = offsetof(INF_VERSION_BLOCK, Filename) +
|
|
CurInf->VersionBlock.FilenameSize + CurInf->VersionBlock.DataSize;
|
|
|
|
Out += offsetof(INF_VERSION_BLOCK, Filename);
|
|
|
|
//
|
|
// Now copy the filename and version data into the output buffer.
|
|
//
|
|
CopyMemory(Out, CurInf->VersionBlock.Filename, CurInf->VersionBlock.FilenameSize);
|
|
Out += CurInf->VersionBlock.FilenameSize;
|
|
|
|
CopyMemory(Out, CurInf->VersionBlock.DataBlock, CurInf->VersionBlock.DataSize);
|
|
Out += CurInf->VersionBlock.DataSize;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
if(UnloadInf) {
|
|
FreeInfFile(Inf);
|
|
}
|
|
SetLastError(d = ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if(d != NO_ERROR) {
|
|
return FALSE;
|
|
}
|
|
|
|
Prev->NextOffset = 0;
|
|
|
|
//
|
|
// Unload the inf if necessary
|
|
//
|
|
if(UnloadInf) {
|
|
FreeInfFile(Inf);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupQueryInfFileInformationA(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
WCHAR returnbuffer[MAX_PATH];
|
|
DWORD requiredsize;
|
|
DWORD rc;
|
|
PSTR ansi;
|
|
BOOL b;
|
|
|
|
b = SetupQueryInfFileInformationW(
|
|
InfInformation,
|
|
InfIndex,
|
|
returnbuffer,
|
|
MAX_PATH,
|
|
&requiredsize
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(b) {
|
|
if(ansi = UnicodeToAnsi(returnbuffer)) {
|
|
|
|
rc = NO_ERROR;
|
|
requiredsize = lstrlenA(ansi);
|
|
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = requiredsize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
if(b) {
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= requiredsize) {
|
|
//
|
|
// lstrcpy returns NULL if it faults
|
|
//
|
|
if(!lstrcpyA(ReturnBuffer,ansi)) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
b = FALSE;
|
|
}
|
|
} else {
|
|
b = FALSE;
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
}
|
|
|
|
MyFree(ansi);
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupQueryInfFileInformationW(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(InfInformation);
|
|
UNREFERENCED_PARAMETER(InfIndex);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupQueryInfFileInformation(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT FilenameLength;
|
|
INF_VERSION_NODE VersionNode;
|
|
DWORD rc;
|
|
|
|
//
|
|
// See whether the index is in range and
|
|
// retrieve the version descriptor for this inf.
|
|
//
|
|
rc = NO_ERROR;
|
|
try {
|
|
if(!pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode)) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
FilenameLength = VersionNode.FilenameSize / sizeof(TCHAR);
|
|
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = FilenameLength;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check length of user's buffer.
|
|
//
|
|
if(FilenameLength > ReturnBufferSize) {
|
|
if(ReturnBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the data into user's buffer.
|
|
//
|
|
try {
|
|
CopyMemory(ReturnBuffer,VersionNode.Filename,VersionNode.FilenameSize);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupQueryInfVersionInformationA(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
IN PCSTR Key, OPTIONAL
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
INF_VERSION_NODE VersionNode;
|
|
PCWSTR Data;
|
|
DWORD rc;
|
|
PSTR ansidata;
|
|
UINT ansilength;
|
|
PCWSTR key;
|
|
|
|
//
|
|
// See whether the index is in range and
|
|
// get pointer to version descriptor for this inf.
|
|
//
|
|
try {
|
|
if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode)) {
|
|
//
|
|
// See whether we want a specific value.
|
|
//
|
|
if(Key) {
|
|
|
|
rc = CaptureAndConvertAnsiArg(Key,&key);
|
|
if(rc == NO_ERROR) {
|
|
|
|
if(Data = pSetupGetVersionDatum(&VersionNode,key)) {
|
|
|
|
if(ansidata = UnicodeToAnsi(Data)) {
|
|
|
|
ansilength = lstrlenA(ansidata) + 1;
|
|
if(RequiredSize) {
|
|
*RequiredSize = ansilength;
|
|
}
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= ansilength) {
|
|
CopyMemory(ReturnBuffer,ansidata,ansilength);
|
|
rc = NO_ERROR;
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
} else {
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
MyFree(ansidata);
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
rc = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
MyFree(key);
|
|
}
|
|
} else {
|
|
//
|
|
// Caller wants all values. Copy whole data block to caller's buffer,
|
|
// plus a terminating NUL character.
|
|
//
|
|
// Maximum size the data could be in ansi is the exact same
|
|
// size it is in unicode, if every char is a double-byte char.
|
|
//
|
|
if(ansidata = MyMalloc(VersionNode.DataSize)) {
|
|
|
|
ansilength = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
(PWSTR)VersionNode.DataBlock,
|
|
VersionNode.DataSize / sizeof(WCHAR),
|
|
ansidata,
|
|
VersionNode.DataSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(RequiredSize) {
|
|
//
|
|
// account for terminating nul
|
|
//
|
|
*RequiredSize = ansilength+1;
|
|
}
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= *RequiredSize) {
|
|
CopyMemory(ReturnBuffer,ansidata,ansilength);
|
|
ReturnBuffer[ansilength] = 0;
|
|
rc = NO_ERROR;
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
} else {
|
|
rc = NO_ERROR;
|
|
}
|
|
|
|
MyFree(ansidata);
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
} else {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(rc == NO_ERROR);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupQueryInfVersionInformationW(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
IN PCWSTR Key, OPTIONAL
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(InfInformation);
|
|
UNREFERENCED_PARAMETER(InfIndex);
|
|
UNREFERENCED_PARAMETER(Key);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupQueryInfVersionInformation(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
IN PCTSTR Key, OPTIONAL
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
INF_VERSION_NODE VersionNode;
|
|
PCTSTR Data;
|
|
UINT DataLength;
|
|
DWORD rc;
|
|
|
|
//
|
|
// See whether the index is in range and
|
|
// get pointer to version descriptor for this inf.
|
|
//
|
|
try {
|
|
if(pSetupVersionNodeFromInfInformation(InfInformation,InfIndex,&VersionNode)) {
|
|
//
|
|
// See whether we want a specific value.
|
|
//
|
|
if(Key) {
|
|
if(Data = pSetupGetVersionDatum(&VersionNode,Key)) {
|
|
|
|
DataLength = lstrlen(Data) + 1;
|
|
if(RequiredSize) {
|
|
*RequiredSize = DataLength;
|
|
}
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= DataLength) {
|
|
CopyMemory(ReturnBuffer,Data,DataLength * sizeof(TCHAR));
|
|
rc = NO_ERROR;
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
} else {
|
|
rc = NO_ERROR;
|
|
}
|
|
} else {
|
|
rc = ERROR_INVALID_DATA;
|
|
}
|
|
} else {
|
|
//
|
|
// Caller wants all values. Copy whole data block to caller's buffer,
|
|
// plus a terminating NUL character.
|
|
//
|
|
DataLength = (VersionNode.DataSize / sizeof(TCHAR)) + 1;
|
|
if(RequiredSize) {
|
|
*RequiredSize = DataLength;
|
|
}
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= DataLength) {
|
|
CopyMemory(ReturnBuffer,VersionNode.DataBlock,VersionNode.DataSize);
|
|
ReturnBuffer[VersionNode.DataSize/sizeof(TCHAR)] = 0;
|
|
rc = NO_ERROR;
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
} else {
|
|
rc = NO_ERROR;
|
|
}
|
|
}
|
|
} else {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(rc == NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
_SetupGetInfFileList(
|
|
IN PCTSTR DirectoryPath, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PVOID ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
#ifdef UNICODE
|
|
IN ,BOOL ConvertToAnsi
|
|
#endif
|
|
)
|
|
{
|
|
TCHAR SearchSpec[MAX_PATH];
|
|
PTCHAR FilenameStart;
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE FindHandle;
|
|
DWORD Style;
|
|
UINT FileNameLength;
|
|
DWORD RemainingSpaceInBuffer;
|
|
DWORD CurrentOffsetInBuffer;
|
|
DWORD TotalSpaceNeededInBuffer;
|
|
BOOL InsufficientBuffer;
|
|
DWORD d;
|
|
PTSTR DontCare;
|
|
#ifdef UNICODE
|
|
CHAR ansi[MAX_PATH];
|
|
#endif
|
|
|
|
//
|
|
// Set up the search directory
|
|
//
|
|
if(DirectoryPath) {
|
|
//
|
|
// Make sure this directory path is fully-qualified.
|
|
//
|
|
if(!GetFullPathName(DirectoryPath, SIZECHARS(SearchSpec), SearchSpec, &DontCare)) {
|
|
//
|
|
// Last error already set
|
|
//
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
lstrcpy(SearchSpec, InfDirectory);
|
|
}
|
|
|
|
ConcatenatePaths(SearchSpec, pszInfWildcard, SIZECHARS(SearchSpec), NULL);
|
|
FilenameStart = (PTSTR)MyGetFileTitle(SearchSpec);
|
|
|
|
FindHandle = FindFirstFile(SearchSpec,&FindData);
|
|
if(FindHandle == INVALID_HANDLE_VALUE) {
|
|
d = GetLastError();
|
|
if((d == ERROR_NO_MORE_FILES) || (d == ERROR_FILE_NOT_FOUND) || (d == ERROR_PATH_NOT_FOUND)) {
|
|
if(RequiredSize) {
|
|
d = NO_ERROR;
|
|
try {
|
|
*RequiredSize = 1;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(d != NO_ERROR) {
|
|
SetLastError(d);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize) {
|
|
d = NO_ERROR;
|
|
try {
|
|
#ifdef UNICODE
|
|
if(ConvertToAnsi) {
|
|
*(PCHAR)ReturnBuffer = 0;
|
|
} else
|
|
#endif
|
|
*(PTCHAR)ReturnBuffer = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
SetLastError(d);
|
|
return(d == NO_ERROR);
|
|
} else {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
SetLastError(d);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Leave space for the extra terminating nul char.
|
|
//
|
|
RemainingSpaceInBuffer = ReturnBufferSize;
|
|
if(RemainingSpaceInBuffer) {
|
|
RemainingSpaceInBuffer--;
|
|
}
|
|
|
|
TotalSpaceNeededInBuffer = 1;
|
|
CurrentOffsetInBuffer = 0;
|
|
|
|
InsufficientBuffer = FALSE;
|
|
d = NO_ERROR;
|
|
|
|
do {
|
|
//
|
|
// Skip directories
|
|
//
|
|
if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Form full pathname of file in SearchSpec.
|
|
//
|
|
lstrcpy(FilenameStart,FindData.cFileName);
|
|
|
|
//
|
|
// Determine the inf type and see whether the caller
|
|
// wants to know about infs of this type.
|
|
//
|
|
Style = DetermineInfStyle(SearchSpec, &FindData);
|
|
if((Style == INF_STYLE_NONE) || !(Style & InfStyle)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Got a legit inf file.
|
|
//
|
|
#ifdef UNICODE
|
|
if(ConvertToAnsi) {
|
|
//
|
|
// The nul is included because it's converted
|
|
// so no need to add 1
|
|
//
|
|
FileNameLength = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
FindData.cFileName,
|
|
-1,
|
|
ansi,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL
|
|
);
|
|
} else
|
|
#endif
|
|
FileNameLength = lstrlen(FindData.cFileName) + 1;
|
|
|
|
TotalSpaceNeededInBuffer += FileNameLength;
|
|
|
|
if(ReturnBuffer) {
|
|
|
|
if(RemainingSpaceInBuffer >= FileNameLength ) {
|
|
|
|
RemainingSpaceInBuffer -= FileNameLength;
|
|
|
|
//
|
|
// lstrcpy will return NULL if it faults
|
|
//
|
|
#ifdef UNICODE
|
|
if(ConvertToAnsi) {
|
|
DontCare = (PVOID)lstrcpyA((PCHAR)ReturnBuffer+CurrentOffsetInBuffer,ansi);
|
|
} else
|
|
#endif
|
|
DontCare = lstrcpy((PTCHAR)ReturnBuffer+CurrentOffsetInBuffer,FindData.cFileName);
|
|
|
|
if(!DontCare) {
|
|
|
|
d = ERROR_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
CurrentOffsetInBuffer += FileNameLength;
|
|
|
|
try {
|
|
#ifdef UNICODE
|
|
if(ConvertToAnsi) {
|
|
((PCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
|
|
} else
|
|
#endif
|
|
((PTCHAR)ReturnBuffer)[CurrentOffsetInBuffer] = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
} else {
|
|
InsufficientBuffer = TRUE;
|
|
}
|
|
}
|
|
|
|
} while((d == NO_ERROR) && FindNextFile(FindHandle,&FindData));
|
|
|
|
FindClose(FindHandle);
|
|
|
|
if(d != NO_ERROR) {
|
|
SetLastError(d);
|
|
}
|
|
|
|
if(GetLastError() == ERROR_NO_MORE_FILES) {
|
|
|
|
d = NO_ERROR;
|
|
|
|
try {
|
|
if(RequiredSize) {
|
|
*RequiredSize = TotalSpaceNeededInBuffer;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
if(InsufficientBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
return(TRUE);
|
|
} else {
|
|
SetLastError(d);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Last error already set
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupGetInfFileListA(
|
|
IN PCSTR DirectoryPath, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
PWSTR dirpath;
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
if(DirectoryPath) {
|
|
rc = CaptureAndConvertAnsiArg(DirectoryPath,&dirpath);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
dirpath = NULL;
|
|
}
|
|
|
|
|
|
b = _SetupGetInfFileList(dirpath,InfStyle,ReturnBuffer,ReturnBufferSize,RequiredSize,TRUE);
|
|
rc = GetLastError();
|
|
|
|
if(dirpath) {
|
|
MyFree(dirpath);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupGetInfFileListW(
|
|
IN PCWSTR DirectoryPath, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DirectoryPath);
|
|
UNREFERENCED_PARAMETER(InfStyle);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupGetInfFileList(
|
|
IN PCTSTR DirectoryPath, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR dirpath;
|
|
DWORD rc;
|
|
BOOL b;
|
|
|
|
if(DirectoryPath) {
|
|
rc = CaptureStringArg(DirectoryPath,&dirpath);
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
dirpath = NULL;
|
|
}
|
|
|
|
|
|
b = _SetupGetInfFileList(
|
|
dirpath,
|
|
InfStyle,
|
|
ReturnBuffer,
|
|
ReturnBufferSize,
|
|
RequiredSize
|
|
#ifdef UNICODE
|
|
,FALSE
|
|
#endif
|
|
);
|
|
|
|
rc = GetLastError();
|
|
|
|
if(dirpath) {
|
|
MyFree(dirpath);
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(b);
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
HINF
|
|
SetupOpenInfFileA(
|
|
IN PCSTR FileName,
|
|
IN PCSTR InfType, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
{
|
|
PCTSTR fileName,infType;
|
|
DWORD err;
|
|
HINF h;
|
|
|
|
err = NO_ERROR;
|
|
fileName = NULL;
|
|
infType = NULL;
|
|
|
|
//
|
|
// Set error line to 0 since ansi arg conversion could fail
|
|
// and we need to indicate that there's no error in the inf itself.
|
|
//
|
|
if(ErrorLine) {
|
|
try {
|
|
*ErrorLine = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if(err == NO_ERROR) {
|
|
err = CaptureAndConvertAnsiArg(FileName,&fileName);
|
|
if((err == NO_ERROR) && InfType) {
|
|
err = CaptureAndConvertAnsiArg(InfType,&infType);
|
|
}
|
|
}
|
|
|
|
if(err == NO_ERROR) {
|
|
h = SetupOpenInfFileW(fileName,infType,InfStyle,ErrorLine);
|
|
err = GetLastError();
|
|
} else {
|
|
h = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if(fileName) {
|
|
MyFree(fileName);
|
|
}
|
|
if(infType) {
|
|
MyFree(infType);
|
|
}
|
|
|
|
SetLastError(err);
|
|
return(h);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
HINF
|
|
SetupOpenInfFileW(
|
|
IN PCWSTR FileName,
|
|
IN PCWSTR InfType, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(FileName);
|
|
UNREFERENCED_PARAMETER(InfType);
|
|
UNREFERENCED_PARAMETER(InfStyle);
|
|
UNREFERENCED_PARAMETER(ErrorLine);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
#endif
|
|
|
|
|
|
HINF
|
|
SetupOpenInfFile(
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR InfClass, OPTIONAL
|
|
IN DWORD InfStyle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens an INF file and returns a handle to it.
|
|
|
|
Arguments:
|
|
|
|
FileName - Supplies the address of a NULL-terminated string containing
|
|
the name (and optionally, the path) of the INF file to be opened. If
|
|
the filename contains no path separator characters, it is searched for
|
|
first in the %windir%\inf directory, and then in the %windir%\system32
|
|
directory. Otherwise, the name is assumed to be a full path specification,
|
|
and no is opened as-is.
|
|
|
|
InfClass - Optionally, supplies the address of a NULL-terminated string containing
|
|
the class of the INF file desired. For old-style (i.e., Windows NT 3.x script-
|
|
base) INF files, this string must match the type specified in the OptionType
|
|
value of the [Identification] section of the INF (e.g., OptionType=NetAdapter).
|
|
For Windows 95-compatibile INF files, this string must match the class of the
|
|
specified INF. If the INF has a Class value in its [version] section, then this
|
|
value is used for the comparison. If no Class value is present, but a ClassGUID
|
|
value is present in the [version] section, then the corresponding class name for
|
|
that GUID is retrieved, and comparison is done based on that name.
|
|
|
|
InfStyle - Specifies the style of the INF to open. May be a combination of the
|
|
following flags:
|
|
|
|
INF_STYLE_OLDNT - Windows NT 3.x script-based INF files.
|
|
|
|
INF_STYLE_WIN4 - Windows 95-compatible INF files.
|
|
|
|
ErrorLine - If an error occurs loading the file, this parameter receives the
|
|
(1-based) line number where the error occurred. This value is generally
|
|
reliable only if GetLastError does not return ERROR_NOT_ENOUGH_MEMORY. If
|
|
out-of-memory does occur, the ErrorLine may be 0.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a handle to the opened INF file.
|
|
|
|
If the function fails, the return value is INVALID_HANDLE_VALUE. To get
|
|
extended error information, call GetLastError.
|
|
|
|
Remarks:
|
|
|
|
If the load fails because the INF class does not match InfClass, the function returns
|
|
FALSE, and GetLastError returns ERROR_CLASS_MISMATCH.
|
|
|
|
The SetupCloseInfFile function is used to close a handle returned by
|
|
SetupOpenInfFile.
|
|
|
|
If multiple INF styles are specified, the style of the INF file opened may be
|
|
ascertained by calling SetupGetInfInformation.
|
|
|
|
Since there may be multiple class GUIDs all having the same class name, callers
|
|
interested in only INFs of a particular class (i.e., a particular class GUID)
|
|
should retrieve the ClassGuid value from the INF to verify that the class matches
|
|
exactly.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT errorLine;
|
|
DWORD d;
|
|
PLOADED_INF Inf;
|
|
PCTSTR Class;
|
|
TCHAR TempString[MAX_PATH];
|
|
GUID ClassGuid;
|
|
HRESULT hr;
|
|
BOOL TryPnf;
|
|
WIN32_FIND_DATA FindData;
|
|
PTSTR DontCare;
|
|
PTSTR TempCharPtr = NULL;
|
|
|
|
//
|
|
// Determine whether just the filename (no path) was specified. If so,
|
|
// look for it in the DevicePath directory search path. Otherwise,
|
|
// use the path as-is.
|
|
//
|
|
try {
|
|
if(FileName == MyGetFileTitle(FileName)) {
|
|
//
|
|
// The specified INF name is a simple filename. Search for it in
|
|
// the INF directories using the default search order.
|
|
//
|
|
d = SearchForInfFile(
|
|
FileName,
|
|
&FindData,
|
|
INFINFO_DEFAULT_SEARCH,
|
|
TempString,
|
|
SIZECHARS(TempString),
|
|
NULL
|
|
);
|
|
|
|
if(d == NO_ERROR) {
|
|
TryPnf = TRUE;
|
|
}
|
|
} else {
|
|
//
|
|
// The specified INF filename contains more than just a filename.
|
|
// Assume it's an absolute path. (We need to make sure it's
|
|
// fully-qualified, because that's what LoadInfFile expects.)
|
|
//
|
|
if(GetFullPathName(FileName, SIZECHARS(TempString), TempString, &DontCare) &&
|
|
FileExists(TempString, &FindData)) {
|
|
//
|
|
// We have everything we need to load this INF.
|
|
//
|
|
InfSourcePathFromFileName(TempString, &TempCharPtr, &TryPnf);
|
|
d = NO_ERROR;
|
|
} else {
|
|
d = GetLastError();
|
|
}
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// Assume FileName was invalid and thus MyGetFileTitle fell over.
|
|
//
|
|
d = ERROR_INVALID_PARAMETER;
|
|
TempCharPtr = TempCharPtr;
|
|
}
|
|
|
|
if(d != NO_ERROR) {
|
|
goto PrepareForReturn;
|
|
}
|
|
|
|
try {
|
|
d = LoadInfFile(
|
|
TempString,
|
|
&FindData,
|
|
InfStyle,
|
|
TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
|
|
NULL,
|
|
TempCharPtr,
|
|
NULL,
|
|
&Inf,
|
|
&errorLine
|
|
);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
|
|
if(InfClass) {
|
|
|
|
d = ERROR_CLASS_MISMATCH; // assume mismatch
|
|
|
|
//
|
|
// Match based on class of inf. The following check works for
|
|
// both new and old style infs, because old-style infs use
|
|
// [Identification].OptionType as the class (see oldinf.c
|
|
// function ProcessOldInfVersionBlock()).
|
|
//
|
|
if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass)) {
|
|
try {
|
|
if(!lstrcmpi(Class,InfClass)) {
|
|
d = NO_ERROR;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
//
|
|
// No Class entry--check for ClassGUID entry.
|
|
//
|
|
if(Class = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClassGuid)) {
|
|
//
|
|
// Get the class name associated with this GUID, and see if it
|
|
// matches the caller-supplied class name.
|
|
//
|
|
// (We have to cast away the CONST-ness of the Class string, because
|
|
// the prototype for CLSIDFromString doesn't specify this parameter
|
|
// as constant.)
|
|
//
|
|
if((hr = pSetupGuidFromString((PTSTR)Class, &ClassGuid)) == S_OK) {
|
|
|
|
if(SetupDiClassNameFromGuid(&ClassGuid,
|
|
TempString,
|
|
SIZECHARS(TempString),
|
|
NULL)) {
|
|
|
|
try {
|
|
if(!lstrcmpi(TempString,InfClass)) {
|
|
d = NO_ERROR;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
} else {
|
|
if(hr == E_OUTOFMEMORY) {
|
|
d = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(d != NO_ERROR) {
|
|
FreeInfFile(Inf);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if(ErrorLine) {
|
|
try {
|
|
*ErrorLine = errorLine;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
PrepareForReturn:
|
|
|
|
if(TempCharPtr) {
|
|
MyFree(TempCharPtr);
|
|
}
|
|
|
|
SetLastError(d);
|
|
|
|
return((d == NO_ERROR) ? (HINF)Inf : (HINF)INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
|
|
HINF
|
|
SetupOpenMasterInf(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR FileName[MAX_PATH];
|
|
|
|
lstrcpy(FileName,InfDirectory);
|
|
lstrcat(FileName,TEXT("\\LAYOUT.INF"));
|
|
|
|
return(SetupOpenInfFile(FileName,NULL,INF_STYLE_WIN4,NULL));
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupOpenAppendInfFileA(
|
|
IN PCSTR FileName, OPTIONAL
|
|
IN HINF InfHandle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR fileName;
|
|
DWORD d;
|
|
BOOL b;
|
|
|
|
//
|
|
// Set error line to 0 since ansi arg conversion could fail
|
|
// and we need to indicate that there's no error in the inf itself.
|
|
//
|
|
d = NO_ERROR;
|
|
if(ErrorLine) {
|
|
try {
|
|
*ErrorLine = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
if(FileName) {
|
|
d = CaptureAndConvertAnsiArg(FileName,&fileName);
|
|
} else {
|
|
fileName = NULL;
|
|
}
|
|
}
|
|
|
|
if(d == NO_ERROR) {
|
|
b = SetupOpenAppendInfFileW(fileName,InfHandle,ErrorLine);
|
|
d = GetLastError();
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
|
|
if(fileName) {
|
|
MyFree(fileName);
|
|
}
|
|
|
|
SetLastError(d);
|
|
return(b);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupOpenAppendInfFileW(
|
|
IN PCWSTR FileName, OPTIONAL
|
|
IN HINF InfHandle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(FileName);
|
|
UNREFERENCED_PARAMETER(InfHandle);
|
|
UNREFERENCED_PARAMETER(ErrorLine);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupOpenAppendInfFile(
|
|
IN PCTSTR FileName, OPTIONAL
|
|
IN HINF InfHandle,
|
|
OUT PUINT ErrorLine OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOADED_INF ExistingInf = NULL, CurInf = NULL;
|
|
DWORD d = NO_ERROR;
|
|
TCHAR Filename[2][MAX_PATH];
|
|
UINT FilenameCount, i, Field;
|
|
UINT errorLine = 0;
|
|
BOOL LookInInfDirAlso;
|
|
BOOL TryPnf;
|
|
WIN32_FIND_DATA FindData;
|
|
PTSTR TempCharPtr = NULL;
|
|
PTSTR DontCare;
|
|
PINF_SECTION InfSection;
|
|
UINT LineNumber;
|
|
PINF_LINE InfLine = NULL;
|
|
|
|
try {
|
|
|
|
if(LockInf((PLOADED_INF)InfHandle)) {
|
|
ExistingInf = (PLOADED_INF)InfHandle;
|
|
} else {
|
|
d = ERROR_INVALID_HANDLE;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Check INF Signature field as a further validation on the InfHandle.
|
|
//
|
|
if(ExistingInf->Signature != LOADED_INF_SIG) {
|
|
d = ERROR_INVALID_HANDLE;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// Only allow this for win95-style infs.
|
|
//
|
|
if(ExistingInf->Style != INF_STYLE_WIN4) {
|
|
d = ERROR_INVALID_PARAMETER;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// If there is no filename, search through the list of existing INFs, looking
|
|
// for a layout entry in their version blocks. We begin at the end of the list,
|
|
// and search backward, using the first layout file we encounter. This allows
|
|
// for the possibility of append-loading several INFs together (e.g., as done by the
|
|
// optional components dialog), and calling SetupOpenAppendInfFile with no filename
|
|
// for each. Each INF could specify its own layout file, and everything works great.
|
|
// (NOTE: In the above example, if all the INFs specified the same layout file, it
|
|
// would only get loaded once, as expected.)
|
|
//
|
|
// We also can now handle 'LayoutFile' entries that specify multiple layout files. E.g.,
|
|
//
|
|
// LayoutFile = pluslay.inf, layout.inf
|
|
//
|
|
// In the above example, we would append-load 'pluslay.inf', followed by 'layout.inf'.
|
|
// Because of the way we store INFs, any duplicate entries in both INFs would resolve in
|
|
// favor of pluslay.inf, since it was loaded first (unless, of course, layout.inf was
|
|
// already in our list of loaded INFs).
|
|
//
|
|
if(!FileName) {
|
|
//
|
|
// First, find the end of the list.
|
|
//
|
|
for(CurInf = ExistingInf; CurInf->Next; CurInf = CurInf->Next);
|
|
|
|
//
|
|
// Now, search the list, back-to-front, looking for a layout file in each INF's
|
|
// [version] section.
|
|
//
|
|
for(; CurInf; CurInf = CurInf->Prev) {
|
|
//
|
|
// Locate the [Version] section.
|
|
//
|
|
if(InfSection = InfLocateSection(CurInf, pszVersion, NULL)) {
|
|
//
|
|
// Now look for a LayoutFile line.
|
|
//
|
|
LineNumber = 0;
|
|
if(InfLocateLine(CurInf, InfSection, pszLayoutFile, &LineNumber, &InfLine)) {
|
|
//
|
|
// We've found the line containing the INFs to be append-loaded. Get the
|
|
// first field on the line to start off our loop below.
|
|
//
|
|
FileName = InfGetField(CurInf, InfLine, 1, NULL);
|
|
break;
|
|
} else {
|
|
//
|
|
// Make sure InfLine is still NULL, so we won't try to use it.
|
|
//
|
|
InfLine = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!FileName) {
|
|
//
|
|
// Then we didn't find any INFs that specify a layout file.
|
|
//
|
|
d = ERROR_INVALID_DATA;
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now append load the INF (or the possibly multiple INFs, if we're using a LayoutFile line).
|
|
//
|
|
for(Field = 1;
|
|
FileName;
|
|
FileName = InfLine ? InfGetField(CurInf, InfLine, ++Field, NULL) : NULL) {
|
|
|
|
FilenameCount = 0;
|
|
LookInInfDirAlso = TRUE;
|
|
TryPnf = FALSE;
|
|
|
|
//
|
|
// Determine whether just the filename (no path) was specified.
|
|
//
|
|
if(FileName == MyGetFileTitle(FileName)) {
|
|
//
|
|
// If we retrieved this filename from an INF's [version] section, then we
|
|
// first attempt to open up the layout file from the directory where we
|
|
// found the INF. If we don't find it in that directory, and that directory
|
|
// wasn't the Inf directory, then we try to open it up in %windir%\Inf as well.
|
|
//
|
|
if(CurInf) {
|
|
//
|
|
// Copy the path without the ending backslash character, because that's how the
|
|
// 'InfDirectory' string is formatted.
|
|
//
|
|
lstrcpyn(Filename[0],
|
|
CurInf->VersionBlock.Filename,
|
|
MyGetFileTitle(CurInf->VersionBlock.Filename) - CurInf->VersionBlock.Filename
|
|
);
|
|
|
|
//
|
|
// Compare this path against the InfDirectory path, to see if they're the same.
|
|
//
|
|
if(!lstrcmpi(Filename[0], InfDirectory)) {
|
|
TryPnf = TRUE;
|
|
LookInInfDirAlso = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now concatenate the layout filename onto the path.
|
|
//
|
|
ConcatenatePaths(Filename[0], FileName, MAX_PATH, NULL);
|
|
FilenameCount = 1;
|
|
|
|
//
|
|
// If 'TryPnf' is still FALSE, then that means that the INF wasn't in the
|
|
// INF directory. Now find out if it's in a location that requires a non-NULL
|
|
// SourcePath (i.e., something other than the default).
|
|
//
|
|
if(!TryPnf) {
|
|
InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
|
|
}
|
|
}
|
|
|
|
if(LookInInfDirAlso) {
|
|
lstrcpy(Filename[FilenameCount], InfDirectory);
|
|
ConcatenatePaths(Filename[FilenameCount], FileName, MAX_PATH, NULL);
|
|
|
|
if(!FilenameCount) {
|
|
TryPnf = TRUE;
|
|
}
|
|
|
|
FilenameCount++;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// The INF filename contains more than just a filename. Assume it's an absolute
|
|
// path. (We need to make sure it's fully-qualified, because that's what LoadInfFile
|
|
// expects.)
|
|
//
|
|
if(GetFullPathName(FileName, SIZECHARS(Filename[0]), Filename[0], &DontCare)) {
|
|
InfSourcePathFromFileName(Filename[0], &TempCharPtr, &TryPnf);
|
|
FilenameCount = 1;
|
|
} else {
|
|
d = GetLastError();
|
|
goto clean0;
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < FilenameCount; i++) {
|
|
//
|
|
// Load the inf
|
|
//
|
|
if(FileExists(Filename[i], &FindData)) {
|
|
|
|
if((d = LoadInfFile(Filename[i],
|
|
&FindData,
|
|
INF_STYLE_WIN4,
|
|
(i | TryPnf) ? LDINF_FLAG_ALWAYS_TRY_PNF : 0,
|
|
NULL,
|
|
(i | TryPnf) ? NULL : TempCharPtr,
|
|
ExistingInf,
|
|
&ExistingInf,
|
|
&errorLine)) == NO_ERROR) {
|
|
break;
|
|
}
|
|
} else {
|
|
d = GetLastError();
|
|
}
|
|
}
|
|
|
|
//
|
|
// We no longer need the INF source path--free it if necessary.
|
|
//
|
|
if(TempCharPtr) {
|
|
MyFree(TempCharPtr);
|
|
TempCharPtr = NULL;
|
|
}
|
|
|
|
if(d != NO_ERROR) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
//
|
|
// If the caller requested it, give them the line number at which any error occurred.
|
|
// (This may be zero on non-parse errors.)
|
|
//
|
|
if(ErrorLine) {
|
|
*ErrorLine = errorLine;
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// If we hit an AV, then use invalid parameter error, otherwise, assume an inpage error when dealing
|
|
// with a mapped-in file.
|
|
//
|
|
d = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
|
|
|
|
if(TempCharPtr) {
|
|
MyFree(TempCharPtr);
|
|
}
|
|
|
|
//
|
|
// Access the 'ExistingInf' variable, so that the compiler will respect our statement
|
|
// ordering w.r.t. this variable. Otherwise, we may not always know whether or not
|
|
// we should be unlocking this INF.
|
|
//
|
|
ExistingInf = ExistingInf;
|
|
}
|
|
|
|
if(ExistingInf) {
|
|
UnlockInf(ExistingInf);
|
|
}
|
|
|
|
SetLastError(d);
|
|
|
|
return(d == NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetupCloseInfFile(
|
|
IN HINF InfHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOADED_INF CurInf, NextInf;
|
|
|
|
try {
|
|
//
|
|
// Make sure we can lock the head of the INF list before
|
|
// we start deleting!
|
|
//
|
|
if(LockInf((PLOADED_INF)InfHandle)) {
|
|
//
|
|
// Also check INF Signature field as a further validation.
|
|
//
|
|
if(((PLOADED_INF)InfHandle)->Signature == LOADED_INF_SIG) {
|
|
|
|
CurInf = ((PLOADED_INF)InfHandle)->Next;
|
|
|
|
DestroySynchronizedAccess(&(((PLOADED_INF)InfHandle)->Lock));
|
|
FreeLoadedInfDescriptor((PLOADED_INF)InfHandle);
|
|
|
|
for(; CurInf; CurInf = NextInf) {
|
|
NextInf = CurInf->Next;
|
|
FreeInfFile(CurInf);
|
|
}
|
|
|
|
} else {
|
|
UnlockInf((PLOADED_INF)InfHandle);
|
|
}
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal routines
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
pSetupVersionNodeFromInfInformation(
|
|
IN PSP_INF_INFORMATION InfInformation,
|
|
IN UINT InfIndex,
|
|
OUT PINF_VERSION_NODE VersionNode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills in a caller-supplied INF_VERSION_NODE buffer for an INF file
|
|
from the SP_INF_INFORMATION structure.
|
|
|
|
Arguments:
|
|
|
|
InfInformation - supplies the inf information descriptor
|
|
|
|
InfIndex - supplies the 0-based index of the inf whose version block
|
|
is requested. If this value is not inrange an error is returned.
|
|
|
|
Return Value:
|
|
|
|
If successful, the return value is TRUE, otherwise, it is FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
PINF_VERSION_BLOCK First;
|
|
INF_VERSION_BLOCK UNALIGNED *Ver;
|
|
PUCHAR Base;
|
|
UINT ord;
|
|
INF_VERSION_BLOCK TempVersionBlock;
|
|
|
|
//
|
|
// Get pointer to first version block.
|
|
//
|
|
Base = (PUCHAR)InfInformation;
|
|
First = (PINF_VERSION_BLOCK)(Base+offsetof(SP_INF_INFORMATION,VersionData));
|
|
|
|
//
|
|
// Find relevent version block
|
|
//
|
|
ord = 0;
|
|
for(Ver=First; Ver; Ver=(INF_VERSION_BLOCK UNALIGNED *)(Base+Ver->NextOffset)) {
|
|
|
|
if(ord++ == InfIndex) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!Ver) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Now fill in the version node based on the information contained in the version block.
|
|
//
|
|
VersionNode->LastWriteTime = Ver->LastWriteTime;
|
|
VersionNode->FilenameSize = Ver->OffsetToData;
|
|
VersionNode->DataBlock = (CONST TCHAR *)((PBYTE)(Ver->Filename) + Ver->OffsetToData);
|
|
VersionNode->DataSize = Ver->DataSize;
|
|
VersionNode->DatumCount = Ver->DatumCount;
|
|
|
|
CopyMemory(VersionNode->Filename, Ver->Filename, VersionNode->FilenameSize);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pSetupGetVersionDatum(
|
|
IN PINF_VERSION_NODE VersionNode,
|
|
IN PCTSTR DatumName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look up a piece of version data in an version data node.
|
|
|
|
Arguments:
|
|
|
|
VersionNode - supplies a pointer to the version node to
|
|
be searched for the datum.
|
|
|
|
DatumName - supplies the name of the datum to be retreived.
|
|
|
|
Return Value:
|
|
|
|
NULL if the datum does not exist in the data block.
|
|
Otherwise a pointer to the datum value is returned. The caller
|
|
must not free or write into this memory.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD Datum;
|
|
UINT StringLength;
|
|
PCTSTR Data = VersionNode->DataBlock;
|
|
|
|
for(Datum=0; Datum < VersionNode->DatumCount; Datum++) {
|
|
|
|
StringLength = lstrlen(Data) + 1;
|
|
|
|
//
|
|
// Go through the version block looking for a matching datum name.
|
|
//
|
|
if(lstrcmpi(Data, DatumName)) {
|
|
|
|
//
|
|
// Point to the next one.
|
|
//
|
|
Data += StringLength;
|
|
Data += lstrlen(Data) + 1;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Found it. Return datum value to caller.
|
|
//
|
|
return (Data + StringLength);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|