windows-nt/Source/XPSP1/NT/base/ntsetup/setupapi/wrapper/setupapi.hpp

1223 lines
32 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
setupapi.hpp
Abstract:
Wrapper class library for setup api
Author:
Vijay Jayaseelan (vijayj) 04 Aug 2000
Revision History:
None
--*/
#pragma once
//
// Disable the compiler warning for long names
//
#pragma warning( disable : 4786 )
extern "C" {
#include <windows.h>
#include <setupapi.h>
#include <spapip.h>
}
#include <iostream>
#include <vector>
#include <map>
#include <string>
//
// Wide string output routine
//
std::string&
ToAnsiString(std::string &lhs, const std::wstring &rhs);
std::ostream&
operator<<(std::ostream &lhs, const std::basic_string<WCHAR> &rhs);
std::ostream&
operator<<(std::ostream &lhs, PCWSTR rhs);
//
// Exception classes
//
template<class T>
class BaseException {
public:
BaseException(){}
BaseException(const std::basic_string<T> &Info)
: ExceptionInfo(Info) {}
virtual ~BaseException(){}
virtual void Dump(std::ostream &os) = 0;
protected:
std::basic_string<T> ExceptionInfo;
};
template<class T>
class InvalidValueIndex : public BaseException<T>{
public:
InvalidValueIndex(unsigned int Idx) : Index(Idx){}
void Dump(std::ostream &os) {
os << "Invalid value index : (" << std::dec
<< Index << ")" << std::endl;
}
private:
unsigned int Index;
};
template<class T>
class InvalidValueKey : public BaseException<T>{
public:
InvalidValueKey(const std::basic_string<T> &SecName,
const std::basic_string<T> &Key) : SectionName(SecName), KeyName(Key){}
void Dump(std::ostream &os) {
os << "Invalid value key name (" << KeyName << ")"
<< " in " << SectionName << " section." << std::endl;
}
private:
std::basic_string<T> SectionName, KeyName;
};
//
// Abstracts a Win32 error
//
template <class T>
class W32Exception : public BaseException<T> {
public:
W32Exception(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
void Dump(std::ostream &os) {
T MsgBuffer[4096];
MsgBuffer[0] = NULL;
DWORD CharCount;
if (sizeof(T) == sizeof(WCHAR)) {
CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PWSTR)MsgBuffer,
sizeof(MsgBuffer)/sizeof(WCHAR),
NULL);
if (CharCount) {
std::wstring Msg((PWSTR)MsgBuffer);
os << Msg;
} else {
os << std::hex << ErrorCode;
}
} else {
CharCount = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PSTR)MsgBuffer,
sizeof(MsgBuffer)/sizeof(CHAR),
NULL);
if (CharCount) {
std::string Msg((PCSTR)MsgBuffer);
os << Msg;
} else {
os << std::hex << ErrorCode;
}
}
}
DWORD GetErrorCode() const { return ErrorCode; }
protected:
DWORD ErrorCode;
};
template<class T>
class Section;
template<class T>
class SectionValues {
public:
SectionValues(Section<T> &Sec, ULONG LineIdx, bool New = false);
SectionValues(Section<T> &Sec, const std::basic_string<T> &Key,
ULONG LineIdx, bool New = false);
void PutValue(ULONG Index, const std::basic_string<T> &Val) {
Values[Index] = Val;
GetContainer().GetContainer().SetDirty();
}
const std::basic_string<T>& GetValue(ULONG Index) const {
return Values[Index];
}
void AppendValue(const std::basic_string<T> &Val) {
Values.push_back(Val);
GetContainer().GetContainer().SetDirty();
}
void ClearValues() {
Values.clear();
GetContainer().GetContainer().SetDirty();
}
ULONG Count() const {
return Values.size();
}
Section<T>& GetContainer() { return Container; }
const std::basic_string<T>& GetName() const { return Name; }
ULONG GetIndex() const { return Index; }
friend std::ostream& operator<<(std::ostream &os, SectionValues<T> &rhs);
protected:
//
// data members
//
ULONG Index;
std::basic_string<T> Name;
std::vector< std::basic_string<T> > Values;
Section<T> &Container;
};
template<class T>
struct InvalidInfSection : public BaseException<T> {
public:
InvalidInfSection(const std::basic_string<T> &SecName,
const std::basic_string<T> &InfName)
: Name(SecName), FileName(InfName){}
std::basic_string<T> Name;
std::basic_string<T> FileName;
void Dump(std::ostream &os) {
os << "InvalidInfSection : " << Name << " in "
<< FileName << std::endl;
}
};
//
// forward declaration
//
template<class T>
class InfFile;
template<class T>
class Section {
public:
Section(InfFile<T> &file, const std::basic_string<T> &name);
Section(InfFile<T> &file, const std::basic_string<T> &name, bool NoKey) :
File(file), Name(name), Keyless(NoKey) {}
~Section(){}
const std::basic_string<T>& GetName() const{
return Name;
}
SectionValues<T>& GetValue(const std::basic_string<T> &Key) {
std::vector< SectionValues<T> *>::iterator Iter = Lines.begin();
SectionValues<T> *Values = NULL;
while (Iter != Lines.end()) {
Values = (*Iter);
if (sizeof(T) == sizeof(CHAR)) {
if (!_stricmp((PCSTR)Values->GetName().c_str(),
(PCSTR)Key.c_str())) {
break;
}
} else {
if (!_wcsicmp((PCWSTR)Values->GetName().c_str(),
(PCWSTR)Key.c_str())) {
break;
}
}
Iter++;
}
if (Iter == Lines.end()) {
throw new InvalidValueKey<T>(Name, Key);
}
return *Values;
}
//
// Note : For the following scenario
//
// [Section]
// a
// b,c
//
// a & b are treated as Keys i.e. for keyless sections
// the first value is treated as a key
//
bool IsKeyPresent(const std::basic_string<T> &Key) const {
bool Result = false;
if (!IsKeyless()) {
std::vector< SectionValues<T> *>::const_iterator Iter = Lines.begin();
SectionValues<T> *Values = NULL;
while (Iter != Lines.end()) {
Values = (*Iter);
if (sizeof(T) == sizeof(CHAR)) {
if (!_stricmp((PCSTR)Values->GetName().c_str(),
(PCSTR)Key.c_str())) {
break;
}
} else {
if (!_wcsicmp((PCWSTR)Values->GetName().c_str(),
(PCWSTR)Key.c_str())) {
break;
}
}
Iter++;
}
Result = (Iter != Lines.end());
} else {
std::vector< SectionValues<T> *>::const_iterator Iter = KeylessLines.begin();
SectionValues<T> *Values = NULL;
while (Iter != KeylessLines.end()) {
Values = (*Iter);
if (sizeof(T) == sizeof(CHAR)) {
if (!_stricmp((PCSTR)Values->GetValue(0).c_str(),
(PCSTR)Key.c_str())) {
break;
}
} else {
if (!_wcsicmp((PCWSTR)Values->GetValue(0).c_str(),
(PCWSTR)Key.c_str())) {
break;
}
}
Iter++;
}
Result = (Iter != KeylessLines.end());
}
return Result;
}
SectionValues<T>& GetValue(ULONG Index) {
return *(KeylessLines[Index]);
}
InfFile<T>& GetContainer() { return File; }
bool IsKeyless() const { return Keyless; }
Section<T>& operator+=(Section<T> &rhs) {
if (IsKeyless() == rhs.IsKeyless()) {
//
// add entries with key
//
std::vector< SectionValues<T> *>::iterator Iter = rhs.Lines.begin();
while (Iter != rhs.Lines.end()) {
Lines.push_back(*Iter);
Iter++;
}
//
// add entries without key
//
std::vector< SectionValues<T> *>::iterator KlIter = rhs.KeylessLines.begin();
while (KlIter != rhs.KeylessLines.end()) {
KeylessLines.push_back(*KlIter);
KlIter++;
}
} else {
throw new InvalidInfSection<T>(File.GetName(), rhs.GetName());
}
return *this;
}
SectionValues<T>* AddLine(const std::basic_string<T> &Key) {
SectionValues<T> *Value = NULL;
if (Key.length() && !IsKeyless()) {
Value = new SectionValues<T>(*this, Key, 0, true);
if (Value) {
Lines.push_back(Value);
}
} else {
Value = new SectionValues<T>(*this, KeylessLines.size(), true);
if (Value) {
KeylessLines.push_back(Value);
}
}
File.SetDirty();
return Value;
}
friend std::ostream& operator<<(std::ostream &os, Section<T> &rhs);
//
// Callback function pointer for
// working on each section element
//
typedef void (*ELEMENT_WORKER)(
SectionValues<T> &Values,
void *ContextData
);
void DoForEach(ELEMENT_WORKER Worker, void *ContextData);
//
// Iterator
//
class Iterator{
public:
Iterator(std::vector< SectionValues<T> *> *Collect = NULL) {
Collection = Collect;
if (Collection) {
Iter = (*Collection).begin();
}
}
Iterator& begin() {
if (Collection) {
Iter = Collection->begin();
}
return *this;
}
bool end() {
return Collection? (Iter == Collection->end()) : true;
}
Iterator& operator++(int) {
if (Collection) {
Iter++;
}
return *this;
}
friend SectionValues<T> * operator*(Iterator &lhs) {
return lhs.Collection ? *(lhs.Iter): NULL;
}
friend Section<T>;
protected:
void Init(std::vector< SectionValues<T> *> *Collect) {
Collection = Collect;
Iter = (*Collection).begin();
}
private:
//
// data members
//
std::vector< SectionValues<T> * >::iterator Iter;
std::vector< SectionValues<T> *> *Collection;
};
Iterator begin(void) {
Iterator Iter;
if (IsKeyless()) {
if (KeylessLines.size()) {
Iter.Init(&KeylessLines);
}
} else {
if (Lines.size()) {
Iter.Init(&Lines);
}
}
return Iter;
}
protected:
//
// data members
//
InfFile<T> &File;
std::basic_string<T> Name;
std::vector< SectionValues<T> *> Lines;
std::vector< SectionValues<T> *> KeylessLines;
bool Keyless;
};
template<class T>
class InvalidInfFile : public BaseException<T> {
public:
InvalidInfFile() : ErrorCode(0){}
InvalidInfFile(const std::basic_string<T> &Name) :
FileName(Name), ErrorCode(0) {}
InvalidInfFile(const std::basic_string<T> &Name, DWORD ErrCode) :
FileName(Name), ErrorCode(ErrCode) {}
void Dump(std::ostream &os) {
os << "Invalid INF file " << FileName;
if (ErrorCode) {
os << " (" << std::dec << ErrorCode << ") ";
}
os << std::endl;
}
protected:
std::basic_string<T> FileName;
DWORD ErrorCode;
};
template<class T>
class InvalidInfFormat : public InvalidInfFile<T> {
public:
InvalidInfFormat(const std::basic_string<T> &Name, UINT Line) :
InvalidInfFile<T>(Name), ErrorLine(Line) {}
void Dump(std::ostream &os) {
os << "Invalid INF format at " << std::dec
<< ErrorLine << " line of " << FileName << std::endl;
}
UINT ErrorLine;
};
//
// Inf file abstraction
//
template <class T>
class InfFile {
public:
InfFile(const std::basic_string<T> &name);
virtual ~InfFile() {
if (InfHandle && (InfHandle != INVALID_HANDLE_VALUE)) {
SetupCloseInfFile(InfHandle);
}
if (Dirty) {
//CommitChanges();
}
SetupApiUseCount--;
if (!SetupApiUseCount) {
FreeLibrary(SetupApiModuleHandle);
GetInfSections = NULL;
}
}
const std::basic_string<T>& GetName() const {
return Name;
}
friend bool operator==(const InfFile<T> &lhs, const InfFile<T> &rhs) {
return lhs.GetName() == rhs.GetName();
}
friend bool operator!=(const InfFile<T> &lhs, const InfFile<T> &rhs) {
return !(lhs == rhs);
}
void GetLines(Section<T> &Sec,
std::vector< SectionValues<T> *> &Lines,
std::vector< SectionValues<T> *> &KeylessLines);
void GetValues(Section<T> &Sec,
SectionValues<T> &SecValues,
std::vector< std::basic_string<T> > &Values);
friend std::ostream& operator<<(std::ostream &os, InfFile<T> &rhs) {
InfFile<T>::Iterator Iter = rhs.begin();
while (!Iter.end()) {
os << **Iter << std::endl;
Iter++;
}
return os;
}
Section<T>* AddSection(const std::basic_string<T> &SecName, bool Keyless) {
Section<T> *NewSection = NULL;
try {
NewSection = GetSection(SecName);
} catch(...) {
}
if (!NewSection) {
Sections[SecName] = NewSection =
new Section<T>(*this, SecName, Keyless);
SetDirty();
}
return NewSection;
}
Section<T>* GetSection(const std::basic_string<T> &SecName) {
std::map< std::basic_string<T>, Section<T> *>::iterator Iter = Sections.find(SecName);
Section<T>* Sec = NULL;
if (Iter != Sections.end()) {
Sec = (*Iter).second;
}
return Sec;
}
void GetSections(std::map< std::basic_string<T>, Section<T> *> &Secs) {
Secs = Sections;
}
void SetDirty() { Dirty = true; }
const HINF GetInfHandle() const { return InfHandle; }
//
// Callback function pointer for
// working on each section
//
typedef void (*ELEMENT_WORKER)(
Section<T> &Section,
void *ContextData
);
void DoForEach(ELEMENT_WORKER Worker, void *ContextData);
//
// Iterator
//
class Iterator{
public:
Iterator(std::map< std::basic_string<T>, Section<T> *> *Collect = NULL) {
Collection = Collect;
if (Collection) {
Iter = (*Collection).begin();
}
}
Iterator& begin() {
if (Collection) {
Iter = Collection->begin();
}
return *this;
}
bool end() {
return Collection? (Iter == Collection->end()) : true;
}
Iterator& operator++(int) {
if (Collection) {
Iter++;
}
return *this;
}
friend Section<T> * operator*(Iterator &lhs) {
return lhs.Collection ? (*(lhs.Iter)).second: NULL;
}
friend Section<T>;
protected:
void Init(std::map< std::basic_string<T>, Section<T> *> *Collect) {
Collection = Collect;
Iter = (*Collection).begin();
}
private:
//
// data members
//
std::map< std::basic_string<T>, Section<T> *>::iterator Iter;
std::map< std::basic_string<T>, Section<T> *> *Collection;
};
Iterator begin(void) {
return Iterator(&(this->Sections));
}
protected:
HINF OpenFile() {
HINF InfHandle = NULL;
UINT ErrorLine = 0;
if (sizeof(T) == sizeof(CHAR)) {
InfHandle = SetupOpenInfFileA((const CHAR*)(GetName().c_str()),
NULL,
INF_STYLE_WIN4,
&ErrorLine);
} else {
InfHandle = SetupOpenInfFileW((const WCHAR*)(GetName().c_str()),
NULL,
INF_STYLE_WIN4,
&ErrorLine);
}
if (InfHandle == INVALID_HANDLE_VALUE) {
DWORD ErrorCode = ::GetLastError();
if (ErrorLine) {
throw new InvalidInfFormat<T>(GetName(), ErrorLine);
} else {
throw new InvalidInfFile<T>(GetName(), ErrorCode);
}
}
return InfHandle;
}
typedef BOOL (* GetInfSectionsRoutine)(HINF, T*, UINT, UINT *);
//
// data members
//
std::basic_string<T> Name;
HINF InfHandle;
bool Dirty;
static GetInfSectionsRoutine GetInfSections;
static HMODULE SetupApiModuleHandle;
static ULONG SetupApiUseCount;
std::map< std::basic_string<T>, Section<T> *> Sections;
};
template <class T>
SectionValues<T>::SectionValues(Section<T> &Sec,
const std::basic_string<T> &Key, ULONG LineIdx, bool New)
: Container(Sec), Name(Key), Index(LineIdx) {
if (!New) {
GetContainer().GetContainer().GetValues(Sec, *this, Values);
}
}
template <class T>
SectionValues<T>::SectionValues(Section<T> &Sec, ULONG LineIdx, bool New)
: Container(Sec), Index(LineIdx) {
BYTE Buffer[64] = {0};
if (sizeof(T) == sizeof(CHAR)) {
Name = std::basic_string<T>((const T*)_ltoa(Index, (char *)Buffer, 10));
} else {
Name = std::basic_string<T>((const T*)_ltow(Index, (wchar_t*)Buffer, 10));
}
if (!New) {
GetContainer().GetContainer().GetValues(Sec, *this, Values);
}
}
template <class T>
std::ostream&
operator<<(std::ostream &os, SectionValues<T> &rhs) {
os << rhs.GetName() << " = ";
std::vector< std::basic_string<T> >::iterator Iter = rhs.Values.begin();
while (Iter != rhs.Values.end()) {
os << *Iter << ", ";
Iter++;
}
os << std::endl;
return os;
}
template <class T>
Section<T>::Section(InfFile<T> &file, const std::basic_string<T> &name)
: Name(name), File(file), Keyless(false) {
INFCONTEXT InfContext;
BOOL Result;
const HINF InfHandle = GetContainer().GetInfHandle();
if (sizeof(T) == sizeof(CHAR)) {
Result = SetupFindFirstLineA((HINF)InfHandle,
(PCSTR)GetName().c_str(),
NULL,
&InfContext);
} else {
Result = SetupFindFirstLineW((HINF)InfHandle,
(PCWSTR)GetName().c_str(),
NULL,
&InfContext);
}
//std::cout << Name << " is " << Keyless << std::endl;
if (Result) {
BYTE Buffer[4096], Buffer1[4096];
bool KeyPresent = false;
//
// NOTE : singular values in section are treated as keys
// by setupapi so take care of such cases correctly
// as keyless entries
//
// ISSUE : because of the way we are trying to determine
// keyless section a sections with first entry a = a will
// be treated as keyless section wrongly.
//
if (sizeof(T) == sizeof(CHAR)) {
*((PSTR)Buffer) = '\0';
*((PSTR)Buffer1) = '\0';
if (SetupGetStringFieldA(&InfContext,
0,
(PSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL) &&
SetupGetStringFieldA(&InfContext,
1,
(PSTR)Buffer1,
sizeof(Buffer1) / sizeof(T),
NULL)) {
KeyPresent = (_stricmp((PCSTR)Buffer, (PCSTR)Buffer1) != 0);
}
} else {
*((PWSTR)Buffer) = L'\0';
*((PWSTR)Buffer1) = L'\0';
if (SetupGetStringFieldW(&InfContext,
0,
(PWSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL) &&
SetupGetStringFieldW(&InfContext,
1,
(PWSTR)Buffer1,
sizeof(Buffer1) / sizeof(T),
NULL)) {
KeyPresent = (_wcsicmp((PCWSTR)Buffer, (PCWSTR)Buffer1) != 0);
}
}
// If we cannot read 0th value, then we
// assume that the whole section is
// doesnot have entries with key
//
Keyless = !KeyPresent;
}
GetContainer().GetLines(*this, Lines, KeylessLines);
//std::cout << Name << " is " << Keyless << std::endl;
}
template <class T>
std::ostream&
operator<<(std::ostream &os, Section<T> &rhs){
os << "[" << rhs.GetName() << "]" << std::endl;
Section<T>::Iterator Iter = rhs.begin();
SectionValues<T> *Values;
while (!Iter.end()) {
Values = *Iter;
if (Values) {
os << *Values;
}
Iter++;
}
return os;
}
template<class T>
void
Section<T>::DoForEach(Section<T>::ELEMENT_WORKER Worker,
void *ContextData) {
if (IsKeyless()) {
std::vector< SectionValues<T> * >::iterator Iter = KeylessLines.begin();
SectionValues<T> *Value;
while (Iter != KeylessLines.end()) {
Value = *Iter;
if (Value) {
Worker(*Value, ContextData);
}
Iter++;
}
} else {
std::vector< SectionValues<T> *>::iterator Iter = Lines.begin();
SectionValues<T> *Value;
while (Iter != Lines.end()) {
Value = *Iter;
if (Value) {
Worker(*Value, ContextData);
}
Iter++;
}
}
}
template <class T>
InfFile<T>::InfFile(const std::basic_string<T> &name) : Name(name) {
Dirty = false;
InfHandle = OpenFile();
if (!GetInfSections) {
SetupApiModuleHandle = LoadLibrary(TEXT("setupapi.dll"));
if (SetupApiModuleHandle) {
GetInfSections = (GetInfSectionsRoutine)(GetProcAddress(SetupApiModuleHandle,
"pSetupGetInfSections"));
if (!GetInfSections) {
GetInfSections = (GetInfSectionsRoutine)(GetProcAddress(SetupApiModuleHandle,
"SetupGetInfSections"));
}
}
if (!GetInfSections) {
throw new W32Exception<T>();
}
}
SetupApiUseCount++;
//
// get hold of all the sections
//
UINT CurrSize = 4096;
UINT SizeNeeded = 0;
DWORD LastError = 0;
WCHAR *Buffer = new WCHAR[CurrSize];
memset(Buffer, 0, CurrSize);
BOOL Result = GetInfSections(InfHandle, Buffer, CurrSize, &SizeNeeded);
if (!Result && (SizeNeeded > CurrSize)) {
delete []Buffer;
Buffer = new WCHAR[SizeNeeded];
memset(Buffer, 0, SizeNeeded);
CurrSize = SizeNeeded;
Result = GetInfSections(InfHandle, Buffer, CurrSize, &SizeNeeded);
}
std::vector<std::basic_string<T> > SectionNames;
if (Result) {
while (Buffer && *Buffer) {
std::basic_string<WCHAR> WNextSection((const WCHAR*)Buffer);
if (sizeof(T) == sizeof(CHAR)) {
std::basic_string<T> NextSection;
ToAnsiString((std::basic_string<char> &)NextSection, WNextSection);
SectionNames.push_back(NextSection);
} else {
std::basic_string<T> NextSection((const T *)WNextSection.c_str());
SectionNames.push_back(NextSection);
}
Buffer += (WNextSection.length() + 1);
}
} else {
LastError = ::GetLastError();
}
if (Result && SectionNames.size()) {
std::vector<std::basic_string<T> >::iterator NameIter = SectionNames.begin();
while (NameIter != SectionNames.end()) {
// std::cout << *NameIter << std::endl;
Sections[*NameIter] = new Section<T>(*this, *NameIter);
NameIter++;
}
}
if (!Result) {
throw new InvalidInfFile<T>(GetName(), LastError);
}
}
template<class T>
void
InfFile<T>::DoForEach(
InfFile<T>::ELEMENT_WORKER Worker,
void *ContextData
)
{
std::map< std::basic_string<T>, Section<T> *>::iterator
Iter = Sections.begin();
while (Iter != Sections.end()) {
Worker(*(*Iter).second, ContextData);
Iter++;
}
}
template <class T>
void
InfFile<T>::GetLines(
Section<T> &Sec,
std::vector< SectionValues<T> *> &Values,
std::vector< SectionValues<T> *> &KeylessValues
)
{
std::vector< SectionValues<T>* >::iterator MapIter = Values.begin();
//
// delete the old values (if any)
//
while (MapIter != Values.end()) {
if (*MapIter) {
delete (*MapIter);
}
MapIter++;
}
Values.clear();
std::vector< SectionValues<T>* >::iterator KeylessIter = KeylessValues.begin();
//
// delete the old values (if any)
//
while (KeylessIter != KeylessValues.end()) {
if (*KeylessIter) {
delete (*KeylessIter);
}
KeylessIter++;
}
KeylessValues.clear();
//
// locate the first line
//
INFCONTEXT InfContext;
BOOL Result;
DWORD LineCount;
if (sizeof(T) == sizeof(CHAR)) {
LineCount = SetupGetLineCountA(InfHandle,
(PCSTR)Sec.GetName().c_str());
} else {
LineCount = SetupGetLineCountW(InfHandle,
(PCWSTR)Sec.GetName().c_str());
}
if (LineCount) {
if (sizeof(T) == sizeof(CHAR)) {
Result = SetupFindFirstLineA(InfHandle,
(PCSTR)Sec.GetName().c_str(),
NULL,
&InfContext);
} else {
Result = SetupFindFirstLineW(InfHandle,
(PCWSTR)Sec.GetName().c_str(),
NULL,
&InfContext);
}
if (Result) {
BYTE Buffer[4096];
bool Read = false;
BOOL NextLine = TRUE;
DWORD Index = 0;
bool Keyless = Sec.IsKeyless();
for (Index=0; (NextLine && (Index < LineCount)); Index++) {
Buffer[0] = Buffer[1] = 0;
Read = false;
if (!Keyless) {
if (sizeof(T) == sizeof(CHAR)) {
if (SetupGetStringFieldA(&InfContext,
0,
(PSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL)) {
Read = true;
}
} else {
if (SetupGetStringFieldW(&InfContext,
0,
(PWSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL)) {
Read = true;
}
}
}
if (Read) {
std::basic_string<T> Key((const T *)Buffer);
//std::cout << Key << std::endl;
Values.push_back(new SectionValues<T>(Sec, Key, Index));
} else {
KeylessValues.push_back(new SectionValues<T>(Sec, Index));
}
NextLine = SetupFindNextLine(&InfContext, &InfContext);
}
if (!NextLine && (Index < LineCount)) {
throw new InvalidInfSection<T>(Sec.GetName(), GetName());
}
} else {
throw new InvalidInfSection<T>(Sec.GetName(), GetName());
}
}
}
template <class T>
void
InfFile<T>::GetValues(
Section<T> &Sec,
SectionValues<T> &SecValues,
std::vector<std::basic_string<T> > &Values
)
{
const std::basic_string<T> &SecName = Sec.GetName();
const std::basic_string<T> &Key = SecValues.GetName();
INFCONTEXT InfContext;
BOOL Result = TRUE;
ULONG Lines = 0;
Values.clear();
if (sizeof(T) == sizeof(CHAR)) {
Lines = SetupGetLineCountA(InfHandle,
(PCSTR)SecName.c_str());
} else {
Lines = SetupGetLineCountW(InfHandle,
(PCWSTR)SecName.c_str());
}
if (Lines) {
if (sizeof(T) == sizeof(CHAR)) {
Result = SetupGetLineByIndexA(InfHandle,
(PCSTR)SecName.c_str(),
SecValues.GetIndex(),
&InfContext);
} else {
Result = SetupGetLineByIndexW(InfHandle,
(PCWSTR)SecName.c_str(),
SecValues.GetIndex(),
&InfContext);
}
if (Result) {
DWORD FieldCount = SetupGetFieldCount(&InfContext);
BYTE Buffer[2048];
for (DWORD Index=0; Index < FieldCount; Index++) {
Buffer[0] = Buffer[1] = 0;
if (sizeof(T) == sizeof(CHAR)) {
if (SetupGetStringFieldA(&InfContext,
Index + 1,
(PSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL)) {
Values.push_back((const T *)Buffer);
}
} else {
if (SetupGetStringFieldW(&InfContext,
Index + 1,
(PWSTR)Buffer,
sizeof(Buffer) / sizeof(T),
NULL)) {
Values.push_back((const T *)Buffer);
}
}
}
} else {
throw new InvalidInfSection<T>(SecName, GetName());
}
}
}
typedef InfFile<CHAR> InfFileA;
typedef InfFile<WCHAR> InfFileW;