1636 lines
37 KiB
C
1636 lines
37 KiB
C
/*++
|
|
|
|
Copyright (c) 1993-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
infvalue.c
|
|
|
|
Abstract:
|
|
|
|
Externally exposed INF routines for INF value retreival and manipulation.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 20-Jan-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
BOOL
|
|
pAToI(
|
|
IN PCTSTR Field,
|
|
OUT PINT IntegerValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
|
|
space allowed between the prefix and the number.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT Value;
|
|
UINT c;
|
|
BOOL Neg;
|
|
UINT Base;
|
|
UINT NextDigitValue;
|
|
INT OverflowCheck;
|
|
BOOL b;
|
|
|
|
if(!Field) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
if(*Field == TEXT('-')) {
|
|
Neg = TRUE;
|
|
Field++;
|
|
} else {
|
|
Neg = FALSE;
|
|
if(*Field == TEXT('+')) {
|
|
Field++;
|
|
}
|
|
}
|
|
|
|
if((*Field == TEXT('0')) &&
|
|
((*(Field+1) == TEXT('x')) || (*(Field+1) == TEXT('X')))) {
|
|
//
|
|
// The number is in hexadecimal.
|
|
//
|
|
Base = 16;
|
|
Field += 2;
|
|
} else {
|
|
//
|
|
// The number is in decimal.
|
|
//
|
|
Base = 10;
|
|
}
|
|
|
|
for(OverflowCheck = Value = 0; *Field; Field++) {
|
|
|
|
c = (UINT)*Field;
|
|
|
|
if((c >= (UINT)'0') && (c <= (UINT)'9')) {
|
|
NextDigitValue = c - (UINT)'0';
|
|
} else if(Base == 16) {
|
|
if((c >= (UINT)'a') && (c <= (UINT)'f')) {
|
|
NextDigitValue = (c - (UINT)'a') + 10;
|
|
} else if ((c >= (UINT)'A') && (c <= (UINT)'F')) {
|
|
NextDigitValue = (c - (UINT)'A') + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
Value *= Base;
|
|
Value += NextDigitValue;
|
|
|
|
//
|
|
// Check for overflow. For decimal numbers, we check to see whether the
|
|
// new value has overflowed into the sign bit (i.e., is less than the
|
|
// previous value. For hexadecimal numbers, we check to make sure we
|
|
// haven't gotten more digits than will fit in a DWORD.
|
|
//
|
|
if(Base == 16) {
|
|
if(++OverflowCheck > (sizeof(INT) * 2)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if(Value < OverflowCheck) {
|
|
break;
|
|
} else {
|
|
OverflowCheck = Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(*Field) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
return(FALSE);
|
|
}
|
|
|
|
if(Neg) {
|
|
Value = 0-Value;
|
|
}
|
|
b = TRUE;
|
|
try {
|
|
*IntegerValue = Value;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
b = FALSE;
|
|
}
|
|
if(!b) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
return(b);
|
|
}
|
|
|
|
|
|
DWORD
|
|
SetupGetFieldCount(
|
|
IN PINFCONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PINF_LINE Line = NULL;
|
|
DWORD rc = NO_ERROR;
|
|
DWORD res = 0;
|
|
|
|
try {
|
|
if(!LockInf((PLOADED_INF)Context->Inf)) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(rc) {
|
|
SetLastError(rc);
|
|
return(0);
|
|
}
|
|
|
|
try {
|
|
Line = InfLineFromContext(Context);
|
|
if(!Line) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
leave;
|
|
}
|
|
|
|
if(HASKEY(Line)) {
|
|
res = Line->ValueCount - 2;
|
|
} else {
|
|
res = ISSEARCHABLE(Line) ? 1 : Line->ValueCount;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
res = 0;
|
|
}
|
|
|
|
try {
|
|
UnlockInf((PLOADED_INF)Context->Inf);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return res;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupGetStringFieldA(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR Field;
|
|
PCSTR field;
|
|
UINT Len;
|
|
DWORD rc, TmpRequiredSize;
|
|
|
|
//
|
|
// Context could be a bogus pointer -- guard access to it.
|
|
//
|
|
try {
|
|
Field = pSetupGetField(Context, FieldIndex);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(Field) {
|
|
field = pSetupUnicodeToAnsi(Field);
|
|
if(!field) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
//
|
|
// (last error already set by pSetupGetField)
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
Len = lstrlenA(field) + 1;
|
|
|
|
//
|
|
// RequiredSize and ReturnBuffer could be bogus pointers;
|
|
// guard access to them.
|
|
//
|
|
rc = NO_ERROR;
|
|
try {
|
|
if(RequiredSize) {
|
|
*RequiredSize = Len;
|
|
}
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= Len) {
|
|
lstrcpyA(ReturnBuffer, field);
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
MyFree(field);
|
|
SetLastError(rc);
|
|
return(rc == NO_ERROR);
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupGetStringFieldW(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Context);
|
|
UNREFERENCED_PARAMETER(FieldIndex);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupGetStringField(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR Field;
|
|
UINT Len;
|
|
DWORD rc;
|
|
|
|
//
|
|
// Context could be a bogus pointer -- guard access to it.
|
|
//
|
|
try {
|
|
Field = pSetupGetField(Context, FieldIndex);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!Field) {
|
|
//
|
|
// (last error already set by pSetupGetField)
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
Len = lstrlen(Field) + 1;
|
|
|
|
//
|
|
// RequiredSize and ReturnBuffer could be bogus pointers;
|
|
// guard access to them.
|
|
//
|
|
rc = NO_ERROR;
|
|
try {
|
|
if(RequiredSize) {
|
|
*RequiredSize = Len;
|
|
}
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize >= Len) {
|
|
lstrcpy(ReturnBuffer, Field);
|
|
} else {
|
|
rc = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
SetLastError(rc);
|
|
return(rc == NO_ERROR);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetupGetIntField(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PINT IntegerValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
Hexadecimal numbers are also supported. They must be prefixed by '0x' or '0X', with no
|
|
space allowed between the prefix and the number.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR Field;
|
|
|
|
try {
|
|
Field = pSetupGetField(Context,FieldIndex);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Field = NULL;
|
|
}
|
|
|
|
return (pAToI(Field, IntegerValue));
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupGetLineTextA(
|
|
IN PINFCONTEXT Context, OPTIONAL
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCSTR Section, OPTIONAL
|
|
IN PCSTR Key, OPTIONAL
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
INFCONTEXT context;
|
|
BOOL b;
|
|
UINT FieldCount;
|
|
UINT u;
|
|
BOOL InsufficientBuffer;
|
|
DWORD OldSize, TmpRequiredSize;
|
|
PCWSTR Field;
|
|
PCSTR field;
|
|
PCWSTR section,key;
|
|
|
|
//
|
|
// Set up inf context.
|
|
//
|
|
if(Context) {
|
|
u = NO_ERROR;
|
|
try {
|
|
context = *Context;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
u = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(u != NO_ERROR) {
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
if(!InfHandle || !Section || !Key) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if(Section) {
|
|
u = pSetupCaptureAndConvertAnsiArg(Section,§ion);
|
|
if(u != NO_ERROR) {
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
section = NULL;
|
|
}
|
|
|
|
if(Key) {
|
|
u = pSetupCaptureAndConvertAnsiArg(Key,&key);
|
|
if(u != NO_ERROR) {
|
|
if(section) {
|
|
MyFree(section);
|
|
}
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
key = NULL;
|
|
}
|
|
|
|
b = SetupFindFirstLine(InfHandle,section,key,&context);
|
|
u = GetLastError();
|
|
|
|
if(section) {
|
|
MyFree(section);
|
|
}
|
|
if(key) {
|
|
MyFree(key);
|
|
}
|
|
|
|
if(!b) {
|
|
SetLastError(u);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out how many fields are involved.
|
|
//
|
|
InsufficientBuffer = FALSE;
|
|
if(FieldCount = SetupGetFieldCount(&context)) {
|
|
TmpRequiredSize = 0;
|
|
|
|
for(u=0; u<FieldCount; u++) {
|
|
|
|
Field = pSetupGetField(&context, u+1);
|
|
MYASSERT(Field);
|
|
|
|
field = pSetupUnicodeToAnsi(Field);
|
|
if(!field) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
OldSize = TmpRequiredSize;
|
|
TmpRequiredSize += lstrlenA(field)+1;
|
|
|
|
if(ReturnBuffer) {
|
|
if(TmpRequiredSize > ReturnBufferSize) {
|
|
InsufficientBuffer = TRUE;
|
|
} else {
|
|
//
|
|
// lstrcpy is safe even with bad pointers
|
|
// (at least on NT)
|
|
//
|
|
lstrcpyA(ReturnBuffer+OldSize,field);
|
|
ReturnBuffer[TmpRequiredSize - 1] = ',';
|
|
}
|
|
}
|
|
|
|
MyFree(field);
|
|
}
|
|
|
|
//
|
|
// 0-terminate the buffer by overwriting the final comma.
|
|
//
|
|
if(ReturnBuffer && !InsufficientBuffer) {
|
|
ReturnBuffer[TmpRequiredSize - 1] = 0;
|
|
}
|
|
} else {
|
|
//
|
|
// Special case when no values -- need 1 byte for nul.
|
|
//
|
|
if (GetLastError() != NO_ERROR) {
|
|
//
|
|
// actually, something went wrong reading the data from our context...
|
|
// bail out
|
|
//
|
|
return(FALSE);
|
|
}
|
|
TmpRequiredSize = 1;
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize) {
|
|
*ReturnBuffer = 0;
|
|
} else {
|
|
InsufficientBuffer = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
u = NO_ERROR;
|
|
try {
|
|
*RequiredSize = TmpRequiredSize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
u = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(u != NO_ERROR) {
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if(InsufficientBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupGetLineTextW(
|
|
IN PINFCONTEXT Context, OPTIONAL
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCWSTR Section, OPTIONAL
|
|
IN PCWSTR Key, OPTIONAL
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Context);
|
|
UNREFERENCED_PARAMETER(InfHandle);
|
|
UNREFERENCED_PARAMETER(Section);
|
|
UNREFERENCED_PARAMETER(Key);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupGetLineText(
|
|
IN PINFCONTEXT Context, OPTIONAL
|
|
IN HINF InfHandle, OPTIONAL
|
|
IN PCTSTR Section, OPTIONAL
|
|
IN PCTSTR Key, OPTIONAL
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT PDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the contents of a line in a compact format.
|
|
All extraneous whitespace is removed, and multi-line values are converted
|
|
into a single contiguous string.
|
|
|
|
For example, consider the following extract from an INF:
|
|
|
|
HKLM, , Foo, 1, \
|
|
; This is a comment
|
|
01, 02, 03
|
|
|
|
would be returned as:
|
|
HKLM,,Foo,1,01,02,03
|
|
|
|
Arguments:
|
|
|
|
Context - Supplies context for an inf line whose text is to be retreived.
|
|
If not specified, then InfHandle, Section, and Key must be.
|
|
|
|
InfHandle - Supplies handle of the INF file to query.
|
|
Only used if Context is NULL.
|
|
|
|
Section - points to a null-terminated string that specifies the section
|
|
containing the key nameof the line whose text is to be retreived.
|
|
(Only used if InfLineHandle is NULL.)
|
|
|
|
Key - Points to the null-terminated string containing the key name
|
|
whose associated string is to be retrieved. (Only used if InfLineHandle is NULL.)
|
|
|
|
ReturnBuffer - Points to the buffer that receives the retrieved string.
|
|
|
|
ReturnBufferSize - Specifies the size, in characters, of the buffer pointed to
|
|
by the ReturnBuffer parameter.
|
|
|
|
RequiredSize - Receives the actual number of characters needed for the buffer
|
|
pointed to by the ReturnBuffer parameter. If this value is larger than the
|
|
value specified in the ReturnBufferSize parameter, the function fails and
|
|
the function stores no data in the buffer.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is TRUE.
|
|
If the function fails, the return value is FALSE. To get extended error information,
|
|
call GetLastError.
|
|
|
|
--*/
|
|
|
|
{
|
|
INFCONTEXT context;
|
|
BOOL b;
|
|
UINT FieldCount;
|
|
UINT u;
|
|
BOOL InsufficientBuffer;
|
|
DWORD OldSize, TmpRequiredSize;
|
|
PCTSTR Field;
|
|
|
|
//
|
|
// Set up inf context.
|
|
//
|
|
if(Context) {
|
|
u = NO_ERROR;
|
|
try {
|
|
context = *Context;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
u = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(u != NO_ERROR) {
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
if(!InfHandle || !Section || !Key) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
if(!SetupFindFirstLine(InfHandle, Section, Key, &context)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Figure out how many fields are involved.
|
|
//
|
|
InsufficientBuffer = FALSE;
|
|
if(FieldCount = SetupGetFieldCount(&context)) {
|
|
TmpRequiredSize = 0;
|
|
|
|
for(u=0; u<FieldCount; u++) {
|
|
|
|
Field = pSetupGetField(&context, u+1);
|
|
MYASSERT(Field);
|
|
|
|
OldSize = TmpRequiredSize;
|
|
TmpRequiredSize += lstrlen(Field)+1;
|
|
|
|
if(ReturnBuffer) {
|
|
if(TmpRequiredSize > ReturnBufferSize) {
|
|
InsufficientBuffer = TRUE;
|
|
} else {
|
|
//
|
|
// lstrcpy is safe even with bad pointers
|
|
// (at least on NT)
|
|
//
|
|
lstrcpy(ReturnBuffer+OldSize, Field);
|
|
ReturnBuffer[TmpRequiredSize - 1] = TEXT(',');
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 0-terminate the buffer by overwriting the final comma.
|
|
//
|
|
if(ReturnBuffer && !InsufficientBuffer) {
|
|
ReturnBuffer[TmpRequiredSize - 1] = TEXT('\0');
|
|
}
|
|
} else {
|
|
//
|
|
// Special case when no values -- need 1 byte for nul.
|
|
//
|
|
if (GetLastError() != NO_ERROR) {
|
|
//
|
|
// actually, something went wrong reading the data from our context...
|
|
// bail out
|
|
//
|
|
return(FALSE);
|
|
}
|
|
TmpRequiredSize = 1;
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize) {
|
|
*ReturnBuffer = TEXT('\0');
|
|
} else {
|
|
InsufficientBuffer = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
u = NO_ERROR;
|
|
try {
|
|
*RequiredSize = TmpRequiredSize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
u = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(u != NO_ERROR) {
|
|
SetLastError(u);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if(InsufficientBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
//
|
|
// ANSI version
|
|
//
|
|
BOOL
|
|
SetupGetMultiSzFieldA(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
PCTSTR Field;
|
|
UINT FieldCount;
|
|
UINT u;
|
|
UINT Len;
|
|
BOOL InsufficientBuffer;
|
|
DWORD OldSize, TmpRequiredSize;
|
|
DWORD rc;
|
|
PCSTR field;
|
|
|
|
rc = NO_ERROR;
|
|
|
|
//
|
|
// Disallow keys
|
|
//
|
|
if(FieldIndex == 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Figure out how many fields are involved.
|
|
//
|
|
FieldCount = SetupGetFieldCount(Context);
|
|
if (FieldCount == 0 && GetLastError() != NO_ERROR) {
|
|
return FALSE;
|
|
}
|
|
if(FieldCount > (FieldIndex-1)) {
|
|
FieldCount -= FieldIndex - 1;
|
|
} else {
|
|
FieldCount = 0;
|
|
}
|
|
|
|
//
|
|
// Need at least one byte for the terminating nul.
|
|
//
|
|
TmpRequiredSize = 1;
|
|
InsufficientBuffer = FALSE;
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize) {
|
|
try {
|
|
*ReturnBuffer = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
InsufficientBuffer = TRUE;
|
|
}
|
|
}
|
|
|
|
for(u=0; u<FieldCount; u++) {
|
|
|
|
try {
|
|
Field = pSetupGetField(Context, u+FieldIndex);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
MYASSERT(Field);
|
|
|
|
field = pSetupUnicodeToAnsi(Field);
|
|
if(!field) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
if((Len = lstrlenA(field)+1) == 1) {
|
|
//
|
|
// Then we've encountered an empty field. Since multi-sz lists can't contain
|
|
// an empty string, this terminates our list.
|
|
//
|
|
MyFree(field);
|
|
goto clean0;
|
|
}
|
|
|
|
OldSize = TmpRequiredSize;
|
|
TmpRequiredSize += Len;
|
|
|
|
if(ReturnBuffer) {
|
|
if(TmpRequiredSize > ReturnBufferSize) {
|
|
InsufficientBuffer = TRUE;
|
|
} else {
|
|
//
|
|
// lstrcpy is safe with bad pointers (at least on NT)
|
|
//
|
|
lstrcpyA(ReturnBuffer+OldSize-1,field);
|
|
ReturnBuffer[TmpRequiredSize - 1] = 0;
|
|
}
|
|
}
|
|
|
|
MyFree(field);
|
|
}
|
|
|
|
clean0:
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = TmpRequiredSize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if(InsufficientBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#else
|
|
//
|
|
// Unicode stub
|
|
//
|
|
BOOL
|
|
SetupGetMultiSzFieldW(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PWSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Context);
|
|
UNREFERENCED_PARAMETER(FieldIndex);
|
|
UNREFERENCED_PARAMETER(ReturnBuffer);
|
|
UNREFERENCED_PARAMETER(ReturnBufferSize);
|
|
UNREFERENCED_PARAMETER(RequiredSize);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
SetupGetMultiSzField(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PTSTR ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR Field;
|
|
UINT FieldCount;
|
|
UINT u;
|
|
UINT Len;
|
|
BOOL InsufficientBuffer;
|
|
DWORD OldSize, TmpRequiredSize;
|
|
DWORD rc;
|
|
|
|
rc = NO_ERROR;
|
|
|
|
//
|
|
// Disallow keys
|
|
//
|
|
if(FieldIndex == 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Figure out how many fields are involved.
|
|
//
|
|
FieldCount = SetupGetFieldCount(Context);
|
|
if (FieldCount == 0 && GetLastError() != NO_ERROR) {
|
|
return FALSE;
|
|
}
|
|
if(FieldCount > (FieldIndex-1)) {
|
|
FieldCount -= FieldIndex - 1;
|
|
} else {
|
|
FieldCount = 0;
|
|
}
|
|
|
|
//
|
|
// Need at least one byte for the terminating nul.
|
|
//
|
|
TmpRequiredSize = 1;
|
|
InsufficientBuffer = FALSE;
|
|
|
|
if(ReturnBuffer) {
|
|
if(ReturnBufferSize) {
|
|
try {
|
|
*ReturnBuffer = 0;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
} else {
|
|
InsufficientBuffer = TRUE;
|
|
}
|
|
}
|
|
|
|
for(u=0; u<FieldCount; u++) {
|
|
|
|
try {
|
|
Field = pSetupGetField(Context, u+FieldIndex);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
MYASSERT(Field);
|
|
|
|
if((Len = lstrlen(Field)+1) == 1) {
|
|
//
|
|
// Then we've encountered an empty field. Since multi-sz lists can't contain
|
|
// an empty string, this terminates our list.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
OldSize = TmpRequiredSize;
|
|
TmpRequiredSize += Len;
|
|
|
|
if(ReturnBuffer) {
|
|
if(TmpRequiredSize > ReturnBufferSize) {
|
|
InsufficientBuffer = TRUE;
|
|
} else {
|
|
//
|
|
// lstrcpy is safe with bad pointers (at least on NT)
|
|
//
|
|
lstrcpy(ReturnBuffer+OldSize-1, Field);
|
|
ReturnBuffer[TmpRequiredSize - 1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = TmpRequiredSize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if(InsufficientBuffer) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetupGetBinaryField(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex,
|
|
OUT PBYTE ReturnBuffer, OPTIONAL
|
|
IN DWORD ReturnBufferSize,
|
|
OUT LPDWORD RequiredSize OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR Field;
|
|
UINT FieldCount;
|
|
UINT u;
|
|
ULONG Value;
|
|
BOOL Store;
|
|
PTCHAR End;
|
|
DWORD TmpRequiredSize;
|
|
DWORD rc;
|
|
|
|
rc = NO_ERROR;
|
|
|
|
//
|
|
// Disallow keys
|
|
//
|
|
if(FieldIndex == 0) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Figure out how many fields are involved.
|
|
//
|
|
FieldCount = SetupGetFieldCount(Context);
|
|
if (FieldCount == 0 && GetLastError() != NO_ERROR) {
|
|
return FALSE;
|
|
}
|
|
if(FieldCount > (FieldIndex-1)) {
|
|
FieldCount -= FieldIndex - 1;
|
|
} else {
|
|
FieldCount = 0;
|
|
}
|
|
|
|
TmpRequiredSize = FieldCount;
|
|
|
|
Store = (ReturnBuffer && (TmpRequiredSize <= ReturnBufferSize));
|
|
|
|
//
|
|
// Even though we know the required size,
|
|
// go through the loop anyway to validate the data.
|
|
//
|
|
for(u=0; u<FieldCount; u++) {
|
|
|
|
try {
|
|
if(!(Field = pSetupGetField(Context,u+FieldIndex))) {
|
|
rc = ERROR_INVALID_HANDLE;
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
|
|
Value = _tcstoul(Field, &End, 16);
|
|
|
|
//
|
|
// Only the terminating nul should have caused the conversion
|
|
// to stop. In any other case there were non-hex digits in the string.
|
|
// Also disallow the empty string.
|
|
//
|
|
if((End == Field) || *End || (Value > 255)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
return FALSE;
|
|
}
|
|
|
|
if(Store) {
|
|
try {
|
|
*ReturnBuffer++ = (UCHAR)Value;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(RequiredSize) {
|
|
try {
|
|
*RequiredSize = TmpRequiredSize;
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
if(rc != NO_ERROR) {
|
|
SetLastError(rc);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if(ReturnBuffer && (TmpRequiredSize > ReturnBufferSize)) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PINF_LINE
|
|
InfLineFromContext(
|
|
IN PINFCONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an INF context, return a pointer to the inf line structure.
|
|
|
|
Arguments:
|
|
|
|
Context - supplies a pointer to the context structure that was filled
|
|
in by one of the line-related INF APIs.
|
|
No validation is performed on any value in the context structure.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the relevent inf line structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOADED_INF Inf;
|
|
PINF_SECTION Section;
|
|
PINF_LINE Line;
|
|
|
|
Inf = (PLOADED_INF)Context->CurrentInf;
|
|
|
|
if(!LockInf((PLOADED_INF)Context->Inf)) {
|
|
return(NULL);
|
|
}
|
|
|
|
Section = &Inf->SectionBlock[Context->Section];
|
|
Line = &Inf->LineBlock[Section->Lines + Context->Line];
|
|
|
|
UnlockInf((PLOADED_INF)Context->Inf);
|
|
return(Line);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
//
|
|
// Internal routines
|
|
//
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
pSetupGetSecurityInfo(
|
|
IN HINF Inf,
|
|
IN PCTSTR SectionName,
|
|
OUT PCTSTR *SecDesc )
|
|
{
|
|
|
|
BOOL b;
|
|
PTSTR SecuritySectionName;
|
|
INFCONTEXT LineContext;
|
|
DWORD rc;
|
|
|
|
|
|
SecuritySectionName = (PTSTR)MyMalloc( ((lstrlen(SectionName) + lstrlen((PCTSTR)L".Security"))*sizeof(TCHAR)) + 3l );
|
|
if( !SecuritySectionName ){
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return( FALSE );
|
|
}
|
|
|
|
lstrcpy( SecuritySectionName, SectionName );
|
|
lstrcat( SecuritySectionName, (PCTSTR)(L".Security") );
|
|
b = SetupFindFirstLine(Inf,(PCTSTR)SecuritySectionName,NULL,&LineContext);
|
|
MyFree( SecuritySectionName );
|
|
if(!b)
|
|
return( FALSE ); // Section did not exist or other error
|
|
|
|
|
|
if( !(*SecDesc = pSetupGetField( &LineContext, 1 )) )
|
|
return( FALSE ); // Error code is present by checking GetLastError() if needed
|
|
else
|
|
return( TRUE );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PCTSTR
|
|
pSetupGetField(
|
|
IN PINFCONTEXT Context,
|
|
IN DWORD FieldIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retreive a field from a line.
|
|
|
|
Arguments:
|
|
|
|
Context - supplies inf context. No validation is performed
|
|
on the values contained in this structure.
|
|
|
|
FieldIndex - supplies 1-based index of field to retreive.
|
|
An index of 0 retreives the key, if it exists.
|
|
|
|
Return Value:
|
|
|
|
Pointer to string. The caller must not write into this buffer.
|
|
|
|
If the field index is not valid, the return value is NULL,
|
|
and SetLastError() will have been called.
|
|
|
|
--*/
|
|
|
|
{
|
|
PINF_LINE Line;
|
|
PTSTR p = NULL;
|
|
DWORD Err = NO_ERROR;
|
|
|
|
//
|
|
// InfLineFromContext does it's own INF locking, but the later call
|
|
// to InfGetField doesn't, so go ahead and grab the lock up front.
|
|
//
|
|
if(LockInf((PLOADED_INF)Context->Inf)) {
|
|
|
|
if(Line = InfLineFromContext(Context)) {
|
|
|
|
if((p = InfGetField(Context->CurrentInf,Line,FieldIndex,NULL)) == NULL) {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockInf((PLOADED_INF)Context->Inf);
|
|
|
|
} else {
|
|
Err = ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return p;
|
|
}
|
|
|
|
BOOL
|
|
pSetupGetDriverDate(
|
|
IN HINF InfHandle,
|
|
IN PCTSTR Section,
|
|
IN OUT PFILETIME pFileTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retreive the date from a specified Section.
|
|
|
|
The Date specified in an INF section has the following format:
|
|
|
|
DriverVer=xx/yy/zzzz
|
|
|
|
or
|
|
|
|
DriverVer=xx-yy-zzzz
|
|
|
|
where xx is the month, yy is the day, and zzzz is the for digit year.
|
|
Note that the year MUST be 4 digits. A year of 98 will be considered
|
|
0098 and not 1998!
|
|
|
|
This date should be the date of the Drivers and not for the INF itself.
|
|
So a single INF can have multiple driver install Sections and each can
|
|
have different dates depending on when the driver was last updated.
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Supplies handle of the INF file to query.
|
|
|
|
Section - points to a null-terminated string that specifies the section
|
|
of the driver to get the FILETIME infomation.
|
|
|
|
pFileTime - points to a FILETIME structure that will receive the Date,
|
|
if it exists.
|
|
|
|
Return Value:
|
|
|
|
BOOL. TRUE if a valid date existed in the specified Section and FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
SYSTEMTIME SystemTime;
|
|
INFCONTEXT InfContext;
|
|
TCHAR DriverDate[20];
|
|
PTSTR Convert, Temp;
|
|
DWORD Value;
|
|
|
|
rc = NO_ERROR;
|
|
|
|
try {
|
|
|
|
*DriverDate = 0;
|
|
ZeroMemory(&SystemTime, sizeof(SYSTEMTIME));
|
|
pFileTime->dwLowDateTime = 0;
|
|
pFileTime->dwHighDateTime = 0;
|
|
|
|
if(SetupFindFirstLine(InfHandle, Section, pszDriverVer, &InfContext)) {
|
|
|
|
if ((SetupGetStringField(&InfContext,
|
|
1,
|
|
DriverDate,
|
|
SIZECHARS(DriverDate),
|
|
NULL)) &&
|
|
(*DriverDate)) {
|
|
|
|
Convert = DriverDate;
|
|
|
|
if (*Convert) {
|
|
|
|
Temp = DriverDate;
|
|
while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
|
|
Temp++;
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the month
|
|
//
|
|
pAToI(Convert, (PINT)&Value);
|
|
SystemTime.wMonth = LOWORD(Value);
|
|
|
|
Convert = Temp+1;
|
|
|
|
if (*Convert) {
|
|
|
|
Temp = Convert;
|
|
while (*Temp && (*Temp != TEXT('-')) && (*Temp != TEXT('/')))
|
|
Temp++;
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the day
|
|
//
|
|
pAToI(Convert, (PINT)&Value);
|
|
SystemTime.wDay = LOWORD(Value);
|
|
|
|
Convert = Temp+1;
|
|
|
|
if (*Convert) {
|
|
|
|
//
|
|
//Convert the year
|
|
//
|
|
pAToI(Convert, (PINT)&Value);
|
|
SystemTime.wYear = LOWORD(Value);
|
|
|
|
//
|
|
//Convert SYSTEMTIME into FILETIME
|
|
//
|
|
SystemTimeToFileTime(&SystemTime, pFileTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
SetLastError(rc);
|
|
return FALSE;
|
|
}
|
|
|
|
SetLastError(NO_ERROR);
|
|
return((pFileTime->dwLowDateTime != 0) || (pFileTime->dwHighDateTime != 0));
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pSetupGetDriverVersion(
|
|
IN HINF InfHandle,
|
|
IN PCTSTR Section,
|
|
OUT DWORDLONG *Version
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retreive the driver version from a specified Section.
|
|
|
|
The driver version specified in an INF section has the following format:
|
|
|
|
DriverVer=xx/yy/zzzz, a.b.c.d
|
|
|
|
or
|
|
|
|
DriverVer=xx-yy-zzzz, a.b.c.d
|
|
|
|
a.b.c.d is the version of the driver, where a, b, c, and d are all WORD
|
|
decimal values.
|
|
|
|
The version is in the second field in the DriverVer INF value, the driver date
|
|
is in the first field.
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Supplies handle of the INF file to query.
|
|
|
|
Section - points to a null-terminated string that specifies the section
|
|
of the driver to get the FILETIME infomation.
|
|
|
|
Version - points to a DWORDLONG value that will receive the version,
|
|
if it exists.
|
|
|
|
Return Value:
|
|
|
|
BOOL. TRUE if a valid driver version existed in the specified Section and FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD rc;
|
|
INFCONTEXT InfContext;
|
|
TCHAR DriverVersion[LINE_LEN];
|
|
BOOL bEnd = FALSE;
|
|
INT MajorHiWord, MajorLoWord, MinorHiWord, MinorLoWord;
|
|
PTSTR Convert, Temp;
|
|
|
|
rc = NO_ERROR;
|
|
|
|
try {
|
|
|
|
*DriverVersion = 0;
|
|
*Version = 0;
|
|
MajorHiWord = MajorLoWord = MinorHiWord = MinorLoWord = 0;
|
|
|
|
if(SetupFindFirstLine(InfHandle, Section, pszDriverVer, &InfContext)) {
|
|
|
|
if ((SetupGetStringField(&InfContext,
|
|
2,
|
|
DriverVersion,
|
|
SIZECHARS(DriverVersion),
|
|
NULL)) &&
|
|
(*DriverVersion)) {
|
|
|
|
Convert = DriverVersion;
|
|
|
|
if (*Convert) {
|
|
|
|
Temp = DriverVersion;
|
|
while (*Temp && (*Temp != TEXT('.'))) {
|
|
|
|
Temp++;
|
|
}
|
|
|
|
if (!*Temp) {
|
|
|
|
bEnd = TRUE;
|
|
}
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the HIWORD of the major version
|
|
//
|
|
if (pAToI(Convert, (PINT)&MajorHiWord)) {
|
|
|
|
Convert = Temp+1;
|
|
|
|
if (!bEnd && *Convert) {
|
|
|
|
Temp = Convert;
|
|
while (*Temp && (*Temp != TEXT('.'))) {
|
|
|
|
Temp++;
|
|
}
|
|
|
|
if (!*Temp) {
|
|
|
|
bEnd = TRUE;
|
|
}
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the LOWORD of the major version
|
|
//
|
|
if (pAToI(Convert, (PINT)&MajorLoWord)) {
|
|
|
|
Convert = Temp+1;
|
|
|
|
if (!bEnd && *Convert) {
|
|
|
|
Temp = Convert;
|
|
while (*Temp && (*Temp != TEXT('.'))) {
|
|
|
|
Temp++;
|
|
}
|
|
|
|
if (!*Temp) {
|
|
|
|
bEnd = TRUE;
|
|
}
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the HIWORD of the minor version
|
|
//
|
|
if (pAToI(Convert, (PINT)&MinorHiWord)) {
|
|
|
|
Convert = Temp+1;
|
|
|
|
if (!bEnd && *Convert) {
|
|
|
|
Temp = Convert;
|
|
while (*Temp && (*Temp != TEXT('.'))) {
|
|
|
|
Temp++;
|
|
}
|
|
|
|
*Temp = 0;
|
|
|
|
//
|
|
//Convert the LOWORD of the minor version
|
|
//
|
|
pAToI(Convert, (PINT)&MinorLoWord);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
*Version = (((DWORDLONG)MajorHiWord << 48) +
|
|
((DWORDLONG)MajorLoWord << 32) +
|
|
((DWORDLONG)MinorHiWord << 16) +
|
|
(DWORDLONG)MinorLoWord);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
*Version = 0;
|
|
SetLastError(rc);
|
|
return FALSE;
|
|
}
|
|
|
|
SetLastError(NO_ERROR);
|
|
return(*Version != 0);
|
|
}
|
|
|