/*++ 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 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 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 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 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 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++; if (*Temp == TEXT('\0')) { // // There is no day or year in this date, so just exit. // leave; } *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++; if (*Temp == TEXT('\0')) { // // There is no day or year in this date, so just exit. // leave; } *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); }