windows-nt/Source/XPSP1/NT/shell/ext/hnw/shared/parseinf.cpp

1698 lines
39 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// ParseInf.cpp
//
// Code that parses network INF files
//
// History:
//
// ?/??/1999 KenSh Created for JetNet
// 9/29/1999 KenSh Repurposed for Home Networking Wizard
//
#include "stdafx.h"
#include "ParseInf.h"
#include "SortStr.h"
#include "Registry.h"
#define SECTION_BUFFER_SIZE (32 * 1024)
// Non-localized strings
#define SZ_INF_BACKUP_SUFFIX ".inf (HNW backup)"
#define SZ_MODIFIED_INF_HEADER "; Modified by Home Networking Wizard\r\n" \
"; Original version backed up to \""
#define SZ_MODIFIED_INF_HEADER2 "\"\r\n"
#define SZ_CHECK_MODIFIED_HEADER "; Modified by Home Networking Wizard"
//////////////////////////////////////////////////////////////////////////////
// Utility functions
int GetInfDirectory(LPTSTR pszBuf, int cchBuf, BOOL bAppendBackslash)
{
CRegistry regWindows;
int cch = 0;
if (regWindows.OpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", KEY_QUERY_VALUE))
{
cch = regWindows.QueryStringValue("DevicePath", pszBuf, cchBuf);
}
// Fill in a default if the reg key is missing
// REVIEW: Is this likely enough that we should even bother?
if (cch == 0)
{
ASSERT(cchBuf > 8);
cch = GetWindowsDirectory(pszBuf, cchBuf - 4);
if (0!=cch)
{
if (pszBuf[cch-1] != '\\')
pszBuf[cch++] = '\\';
}
lstrcpy(pszBuf + cch, "INF");
cch += 3;
}
if (bAppendBackslash)
{
if (pszBuf[cch-1] != '\\')
{
pszBuf[cch++] = '\\';
pszBuf[cch] = '\0';
}
}
return cch;
}
int GetFullInfPath(LPCTSTR pszPartialPath, LPTSTR pszBuf, int cchBuf)
{
if (IsFullPath(pszPartialPath))
{
lstrcpyn(pszBuf, pszPartialPath, cchBuf);
}
else
{
int cch = GetInfDirectory(pszBuf, cchBuf, TRUE);
lstrcpyn(pszBuf + cch, pszPartialPath, cchBuf - cch);
}
return lstrlen(pszBuf);
}
int AddCommaSeparatedValues(const CStringArray& rgTokens, CStringArray& rgValues, BOOL bIgnoreInfSections)
{
int cAdded = 0;
for (int iToken = 2; iToken < rgTokens.GetSize(); iToken++)
{
CString& strTok = ((CStringArray&)rgTokens).ElementAt(iToken);
if (strTok.Compare(",") == 0)
continue;
if (strTok.Compare(";") == 0)
break;
// Hack: ignore sections whose name ends in ".inf"
if (bIgnoreInfSections)
{
if (0 == lstrcmpi(FindExtension(strTok), "inf"))
continue;
}
rgValues.Add(strTok);
cAdded++;
}
return cAdded;
}
// Builds a list of all files that need to be copied for the device
BOOL GetDeviceCopyFiles(CInfParser& parser, LPCTSTR pszDeviceID, CDriverFileArray& rgDriverFiles)
{
if (!parser.GotoSection("Manufacturer"))
return FALSE;
CStringArray rgMfr;
CStringArray rgLineTokens;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 3 && rgLineTokens.ElementAt(1).Compare("=") == 0)
rgMfr.Add(rgLineTokens.ElementAt(2));
}
CString strNdiSection;
// Look in each manufacturer section (e.g. "[3COM]") for the given DeviceID
for (int iMfr = 0; iMfr < rgMfr.GetSize(); iMfr++)
{
if (!parser.GotoSection(rgMfr[iMfr]))
continue;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 5 &&
rgLineTokens.ElementAt(1).Compare("=") == 0 &&
rgLineTokens.ElementAt(3).Compare(",") == 0)
{
if (rgLineTokens.ElementAt(4).CompareNoCase(pszDeviceID) == 0)
{
strNdiSection = rgLineTokens.ElementAt(2);
break;
}
}
}
if (!strNdiSection.IsEmpty())
break;
}
if (strNdiSection.IsEmpty())
return FALSE;
CStringArray rgCopySections;
CStringArray rgAddRegSections;
// Look in [DeviceID.ndi] section for AddReg= and CopyFiles=
if (!parser.GotoSection(strNdiSection))
return FALSE;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 3 &&
rgLineTokens.ElementAt(1).Compare("=") == 0)
{
CString& strKey = rgLineTokens.ElementAt(0);
CString& strValue = rgLineTokens.ElementAt(2);
if (strKey.CompareNoCase("AddReg") == 0)
{
AddCommaSeparatedValues(rgLineTokens, rgAddRegSections, FALSE);
}
else if (strKey.CompareNoCase("CopyFiles") == 0)
{
AddCommaSeparatedValues(rgLineTokens, rgCopySections, FALSE);
}
}
}
// Look through AddReg sections for HKR,Ndi\Install,,,"DeviceID.Install"
for (int iAddReg = 0; iAddReg < rgAddRegSections.GetSize(); iAddReg++)
{
if (!parser.GotoSection(rgAddRegSections[iAddReg]))
continue;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 7 &&
rgLineTokens.ElementAt(0).CompareNoCase("HKR") == 0 &&
rgLineTokens.ElementAt(1).Compare(",") == 0 &&
rgLineTokens.ElementAt(2).CompareNoCase("Ndi\\Install") == 0 &&
rgLineTokens.ElementAt(3).Compare(",") == 0)
{
// Pull out the 5th comma-separated string, and pull the quotes off
int iSection = 2;
for (int iToken = 4; iToken < rgLineTokens.GetSize(); iToken++)
{
CString& strTok = rgLineTokens.ElementAt(iToken);
if (strTok.Compare(";") == 0)
break;
if (strTok.Compare(",") == 0)
{
iSection++;
continue;
}
if (iSection == 4)
{
CString strSection = strTok;
if (strSection[0] == '\"')
strSection = strSection.Mid(1, strSection.GetLength() - 2);
rgCopySections.Add(strSection);
break;
}
}
}
}
}
// Look in [DeviceID.Install], etc., sections for CopyFiles= lines
for (int iCopyFiles = 0; iCopyFiles < rgCopySections.GetSize(); iCopyFiles++)
{
parser.GetFilesFromInstallSection(rgCopySections[iCopyFiles], rgDriverFiles);
}
parser.GetFilesFromCopyFilesSections(rgCopySections, rgDriverFiles);
return TRUE;
}
BOOL GetDeviceCopyFiles(LPCTSTR pszInfFileName, LPCTSTR pszDeviceID, CDriverFileArray& rgDriverFiles)
{
CInfParser parser;
if (!parser.LoadInfFile(pszInfFileName))
return FALSE;
return GetDeviceCopyFiles(parser, pszDeviceID, rgDriverFiles);
}
CDriverFileArray::~CDriverFileArray()
{
for (int i = 0; i < GetSize(); i++)
{
free((DRIVER_FILE_INFO*)GetAt(i));
}
}
//////////////////////////////////////////////////////////////////////////////
// CInfParser
CInfParser::CInfParser()
{
m_pszFileData = NULL;
}
CInfParser::~CInfParser()
{
free(m_pszFileData);
}
BOOL CInfParser::LoadInfFile(LPCTSTR pszInfFile, LPCTSTR pszSeparators)
{
TCHAR szInfFile[MAX_PATH];
GetFullInfPath(pszInfFile, szInfFile, _countof(szInfFile));
free(m_pszFileData);
m_pszFileData = (LPSTR)LoadFile(szInfFile, &m_cbFile);
m_iPos = 0;
m_strSeparators = pszSeparators;
m_strExtSeparators = pszSeparators;
m_strExtSeparators += " \t\r\n";
m_strFileName = pszInfFile;
return (BOOL)m_pszFileData;
}
BOOL CInfParser::Rewind()
{
ASSERT(m_pszFileData != NULL);
m_iPos = 0;
return (BOOL)m_pszFileData;
}
BOOL CInfParser::GotoNextLine()
{
ASSERT(m_pszFileData != NULL);
for (LPTSTR pch = m_pszFileData + m_iPos; *pch != '\0' && *pch != '\r' && *pch != '\n'; pch++)
NULL;
if (*pch == '\r')
pch++;
if (*pch == '\n')
pch++;
DWORD iPos = (DWORD)(pch - m_pszFileData);
if (iPos == m_iPos)
return FALSE; // we were already at EOF
m_iPos = iPos;
return TRUE;
}
BOOL CInfParser::GetToken(CString& strTok)
{
strTok.Empty();
if (m_pszFileData == NULL)
{
ASSERT(FALSE);
return FALSE;
}
LPTSTR pch = m_pszFileData + m_iPos;
TCHAR ch;
BOOL bQuoted = FALSE;
// Skip whitespace
while ((ch = *pch) == ' ' || ch == '\t')
pch++;
if (ch == '\0')
goto done;
// Check for linebreak
if (ch == '\r' || ch == '\n')
{
strTok = ch;
pch++;
if (ch == '\r' && *pch == '\n')
{
strTok += '\n';
pch++;
}
goto done;
}
// Check for separator
if (NULL != strchr(m_strSeparators, ch))
{
strTok = ch;
pch++;
goto done;
}
LPTSTR pszStart;
for (pszStart = pch; (ch = *pch) != '\0'; pch++)
{
if (!bQuoted && NULL != strchr(m_strExtSeparators, ch))
{
break;
}
else if (ch == '\"')
{
bQuoted = !bQuoted;
}
}
if (pch != pszStart)
{
DWORD cch = (DWORD)(pch - pszStart);
LPTSTR pszToken = strTok.GetBufferSetLength(cch);
lstrcpyn(pszToken, pszStart, cch+1);
}
done:
m_iPos = (DWORD)(pch - m_pszFileData);
return (BOOL)strTok.GetLength();
}
BOOL CInfParser::GetLineTokens(CStringArray& sa)
{
CString strToken;
BOOL bResult = FALSE;
sa.RemoveAll();
while (GetToken(strToken))
{
bResult = TRUE; // not at EOF
if (strToken[0] == '\r' || strToken[0] == '\n')
break;
sa.Add(strToken);
}
return bResult;
}
BOOL CInfParser::GetSectionLineTokens(CStringArray& sa)
{
begin:
if (!GetLineTokens(sa))
return FALSE;
if (sa.GetSize() == 0)
goto begin;
CString& strFirst = sa.ElementAt(0);
if (strFirst[0] == '[') // end of section
return FALSE;
if (strFirst.Compare(";") == 0) // comment
{
sa.RemoveAll();
goto begin;
}
return TRUE;
}
BOOL CInfParser::GotoSection(LPCTSTR pszSection)
{
CString strSection;
CString strToken;
if (!Rewind())
return FALSE;
TCHAR ch;
BOOL bStartOfLine = TRUE;
int cchSection = lstrlen(pszSection) + 1;
for (LPTSTR pch = m_pszFileData; (ch = *pch) != '\0'; pch++)
{
if (ch == '\r' || ch == '\n')
{
bStartOfLine = TRUE;
}
else if (bStartOfLine)
{
if (ch == '[')
{
LPTSTR pchCloseBracket = strchr(pch+1, ']');
if ((int)(pchCloseBracket - pch) == cchSection)
{
CString str(pch+1, cchSection-1);
if (str.CompareNoCase(pszSection) == 0)
{
pch = pchCloseBracket+1;
if (*pch == '\r')
pch++;
if (*pch == '\n')
pch++;
m_iPos = (DWORD)(pch - m_pszFileData);
return TRUE;
}
}
}
bStartOfLine = FALSE;
}
}
return FALSE;
}
int CInfParser::GetProfileInt(LPCTSTR pszSection, LPCTSTR pszKey, int nDefault)
{
DWORD iPos = m_iPos;
if (GotoSection(pszSection))
{
CStringArray rgTokens;
while (GetSectionLineTokens(rgTokens))
{
if (rgTokens.GetSize() >= 3 &&
rgTokens.ElementAt(0).CompareNoCase(pszKey) == 0&&
rgTokens.ElementAt(1).Compare("=") == 0)
{
nDefault = MyAtoi(rgTokens.ElementAt(2));
break;
}
}
}
m_iPos = iPos;
return nDefault;
}
BOOL CInfParser::GetFilesFromInstallSection(LPCTSTR pszSection, CDriverFileArray& rgAllFiles)
{
CStringArray rgLineTokens;
CStringArray rgCopyFilesSections;
if (!GotoSection(pszSection))
return FALSE;
while (GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 3 &&
rgLineTokens.ElementAt(0).CompareNoCase("CopyFiles") == 0 &&
rgLineTokens.ElementAt(1).Compare("=") == 0)
{
AddCommaSeparatedValues(rgLineTokens, rgCopyFilesSections, FALSE);
// REVIEW: There can be AddReg= lines here. Do we need to
// check the referenced sections for more CopyFiles= lines?
}
}
GetFilesFromCopyFilesSections(rgCopyFilesSections, rgAllFiles);
return TRUE;
}
// Looks in [DestinationDirs] for pszSectionName, fills pbDirNumber and pszSubDir with
// the matching target directory and (optional) subdirectory.
BOOL CInfParser::GetDestinationDir(LPCTSTR pszSectionName, BYTE* pbDirNumber, LPTSTR pszSubDir, UINT cchSubDir)
{
DWORD iSavedPos = m_iPos;
BOOL bSuccess = FALSE;
*pbDirNumber = 0;
pszSubDir[0] = '\0';
if (GotoSection("DestinationDirs"))
{
CStringArray rgTokens;
while (GetSectionLineTokens(rgTokens))
{
if (rgTokens.GetSize() >= 3 &&
rgTokens.ElementAt(0).CompareNoCase(pszSectionName) == 0 &&
rgTokens.ElementAt(1).Compare("=") == 0)
{
*pbDirNumber = (BYTE)MyAtoi(rgTokens.ElementAt(2));
if (rgTokens.GetSize() >= 5 && rgTokens.ElementAt(3).Compare(",") == 0)
{
lstrcpyn(pszSubDir, rgTokens.ElementAt(4), cchSubDir);
}
bSuccess = TRUE;
break;
}
}
}
m_iPos = iSavedPos;
return bSuccess;
}
void CInfParser::GetFilesFromCopyFilesSections(const CStringArray& rgCopyFiles, CDriverFileArray& rgAllFiles)
{
CStringArray rgLineTokens;
for (int iSection = 0; iSection < rgCopyFiles.GetSize(); iSection++)
{
TCHAR szTargetSubDir[MAX_PATH];
BYTE nTargetDir;
GetDestinationDir(rgCopyFiles[iSection], &nTargetDir, szTargetSubDir, _countof(szTargetSubDir));
// BYTE nTargetDir = (BYTE)GetProfileInt("DestinationDirs", rgCopyFiles[iSection], 0);
#ifdef _DEBUG
if (nTargetDir == 0)
TRACE("Warning: CopyFiles section [%s] has no destination directory.\r\n", rgCopyFiles[iSection]);
#endif
if (!GotoSection(rgCopyFiles[iSection]))
continue;
// Get the first item from each line
while (GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() == 1 ||
(rgLineTokens.GetSize() >= 2 &&
(rgLineTokens.ElementAt(1).Compare(",") == 0 ||
rgLineTokens.ElementAt(1).Compare(";") == 0)))
{
CString& strFileName = rgLineTokens.ElementAt(0);
// Don't install this INF file
// REVIEW: might want to allow this based on a flag or something
if (0 != lstrcmpi(FindFileTitle(strFileName), FindFileTitle(m_strFileName)))
{
UINT cbFileInfo = sizeof(DRIVER_FILE_INFO) + strFileName.GetLength() + lstrlen(szTargetSubDir) + 1;
DRIVER_FILE_INFO* pFileInfo = (DRIVER_FILE_INFO*)malloc(cbFileInfo);
pFileInfo->nTargetDir = nTargetDir;
lstrcpy(pFileInfo->szFileTitle, strFileName);
lstrcpy(pFileInfo->szFileTitle + strFileName.GetLength() + 1, szTargetSubDir);
rgAllFiles.Add(pFileInfo);
}
}
}
}
// TODO: Remove duplicate files (maybe here, maybe not)
}
int CInfParser::GetNextSourceFile(LPTSTR pszBuf, BYTE* pDiskNumber)
{
LPTSTR pch = m_pszFileData + m_iPos;
int cch = 0;
BYTE bDiskNumber = 0;
for (;;)
{
TCHAR ch;
while ((ch = *pch) == '\r' || ch == '\n')
pch++;
if (ch == '\0' || ch == '[' || cch != 0)
break;
if (ch != ';')
{
LPTSTR pchStart = pch;
while ((UCHAR)(ch = *pch) > 32 && ch != '=')
pch++;
cch = (int)(pch - pchStart);
lstrcpyn(pszBuf, pchStart, cch+1);
// skip whitespace while avoiding '\0'
while ((UCHAR)(*pch-1) < 32)
pch++;
if (*pch == '=')
{
pch++;
// skip whitespace while avoiding '\0'
while ((UCHAR)(*pch-1) < 32)
pch++;
bDiskNumber = (BYTE)MyAtoi(pch);
#if 1 // ignore files with disk number of 0
if (bDiskNumber == 0)
cch = 0;
#endif
}
}
// skip text up to newline
while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
pch++;
}
*pDiskNumber = bDiskNumber;
m_iPos = (DWORD)(pch - m_pszFileData);
return cch;
}
/*
int CInfParser::ReadSourceFilesSection(INF_LAYOUT_FILE* prgFiles, int cFiles)
{
WORD wOffset = (WORD)(cFiles * sizeof(INF_LAYOUT_FILE));
LPTSTR pchDest = (LPTSTR)((LPBYTE)m_prgFiles + wOffset);
INF_LAYOUT_FILE* pFile = prgFiles;
INF_LAYOUT_FILE* pFileEnd = pFile + cFiles;
while (pFile < pFileEnd)
{
pFile->wNameOffset = (WORD)((LPBYTE)pchDest - (LPBYTE)prgFiles);
int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
wOffset += cch+1;
pchDest += cch+1;
pFile++;
}
LPTSTR pch = m_pszFileData + m_iPos;
int cch = 0;
*pDiskNumber = 0;
for (;;)
{
TCHAR ch;
while ((ch = *pch) == '\r' || ch == '\n')
pch++;
if (ch == '\0' || ch == '[' || cch != 0)
break;
if (ch != ';')
{
LPTSTR pchStart = pch;
while ((UCHAR)(ch = *pch) > 32 && ch != '=')
pch++;
cch = (int)(pch - pchStart);
lstrcpyn(pszBuf, pchStart, cch+1);
// skip whitespace while avoiding '\0'
while ((UCHAR)(*pch-1) < 32)
pch++;
if (*pch == '=')
{
pch++;
// skip whitespace while avoiding '\0'
while ((UCHAR)(*pch-1) < 32)
pch++;
*pDiskNumber = (BYTE)atoi(pch);
}
}
// skip text up to newline
while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
pch++;
}
m_iPos = (DWORD)(pch - m_pszFileData);
return cch;
}
*/
void CInfParser::ScanSourceFileList(int* pcFiles, int* pcchAllFileNames)
{
int cFiles = 0;
int cchAllFileNames = 0;
LPTSTR pch = m_pszFileData + m_iPos;
for (;;)
{
TCHAR ch;
while ((ch = *pch) == '\r' || ch == '\n')
pch++;
if (ch == '\0' || ch == '[')
break;
if (ch != ';')
{
cFiles += 1;
LPTSTR pchStart = pch;
while ((UCHAR)(ch = *pch) >= 32 && ch != '=')
pch++;
cchAllFileNames += (int)(pch - pchStart);
}
// skip text up to newline
while ((ch = *pch) != '\0' && ch != '\r' && ch != '\n')
pch++;
}
*pcFiles = cFiles;
*pcchAllFileNames = cchAllFileNames;
}
//////////////////////////////////////////////////////////////////////////////
// CInfLayoutFiles
#define INF_LAYOUT_FILE_PADDING 40 // extra bytes at end of string data
CInfLayoutFiles::CInfLayoutFiles()
{
m_prgFiles = NULL;
m_pStringData = NULL;
m_cFiles = 0;
m_cbStringData = 0;
#ifdef _DEBUG
m_bSorted = FALSE;
#endif
}
CInfLayoutFiles::~CInfLayoutFiles()
{
free(m_prgFiles);
free(m_pStringData);
for (int i = m_rgSourceDisks.GetSize()-1; i >= 0; i--)
{
delete m_rgSourceDisks[i];
}
}
LPTSTR CInfLayoutFiles::s_pStringData;
int __cdecl CInfLayoutFiles::CompareInfLayoutFiles(const void* pEl1, const void* pEl2)
{
LPCTSTR psz1 = s_pStringData + ((INF_LAYOUT_FILE*)pEl1)->dwNameOffset;
LPCTSTR psz2 = s_pStringData + ((INF_LAYOUT_FILE*)pEl2)->dwNameOffset;
return lstrcmpi(psz1, psz2);
}
BOOL CInfLayoutFiles::Add(CInfParser& parser, BOOL bLayoutFile)
{
// Check if we've already added this layout file
if (-1 != m_rgLayoutFileNames.Find(parser.m_strFileName))
return TRUE;
BYTE iLayoutFile = (BYTE)m_rgLayoutFileNames.GetSize();
m_rgLayoutFileNames.Add(parser.m_strFileName, 0);
if (parser.GotoSection("SourceDisksFiles"))
{
DWORD dwTicks1 = GetTickCount();
int cFiles;
int cchAllFileNames;
parser.ScanSourceFileList(&cFiles, &cchAllFileNames);
DWORD dwTicks2 = GetTickCount();
DWORD dwOffset = (DWORD)m_cbStringData;
int iFile = m_cFiles;
m_cFiles += cFiles;
m_cbStringData += cchAllFileNames + cFiles;
m_prgFiles = (INF_LAYOUT_FILE*)realloc(m_prgFiles, m_cFiles * sizeof(INF_LAYOUT_FILE));
m_pStringData = (LPTSTR)realloc(m_pStringData, m_cbStringData + INF_LAYOUT_FILE_PADDING);
LPTSTR pchDest = m_pStringData + dwOffset;
INF_LAYOUT_FILE* pFile = m_prgFiles + iFile;
for ( ; iFile < m_cFiles; iFile++)
{
pFile->dwNameOffset = dwOffset;
pFile->iLayout = iLayoutFile;
int cch = parser.GetNextSourceFile(pchDest, &pFile->iDisk);
dwOffset += cch+1;
pchDest += cch+1;
pFile++;
}
DWORD dwTicks3 = GetTickCount();
CString str;
str.Format("LoadLayout(%s) timings: %d ms, %d ms. Total time: %d ms",
parser.m_strFileName, dwTicks2-dwTicks1, dwTicks3-dwTicks2, dwTicks3-dwTicks1);
TRACE("%s\r\n", str);
// AfxMessageBox(str);
// for (int i = 0; i < cFiles; i++)
// {
// INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
// TRACE("File %d: %s=%d\r\n", i, m_pStringData + pFile->dwNameOffset), pFile->iDisk);
// }
#ifdef _DEBUG
m_bSorted = FALSE;
#endif
}
if (parser.GotoSection("SourceDisksNames"))
{
CStringArray rgTokens;
while (parser.GetSectionLineTokens(rgTokens))
{
if (rgTokens.GetSize() >= 3)
{
BYTE iDiskNumber = (BYTE)MyAtoi(rgTokens.ElementAt(0));
if (iDiskNumber != 0)
{
SOURCE_DISK_INFO* pDiskInfo = new SOURCE_DISK_INFO;
pDiskInfo->wDiskID = MAKE_DISK_ID(iDiskNumber, iLayoutFile);
// Get disk description, pull off quotes
CString& strDesc = rgTokens.ElementAt(2);
if (strDesc[0] == '\"')
pDiskInfo->strDescription = strDesc.Mid(1, strDesc.GetLength()-2);
else
pDiskInfo->strDescription = strDesc;
// If this is Layout*.inf, Get CAB filename, pull off quotes
if (bLayoutFile && rgTokens.GetSize() >= 5)
{
CString& strCab = rgTokens.ElementAt(4);
if (strCab[0] == '\"')
pDiskInfo->strCabFile = strCab.Mid(1, strCab.GetLength()-2);
else
pDiskInfo->strCabFile = strCab;
}
m_rgSourceDisks.Add(pDiskInfo);
}
}
}
}
//
// Now add any referenced layout files
//
if (parser.GotoSection("version"))
{
CStringArray rgLayoutFiles;
CStringArray rgLineTokens;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 3 &&
rgLineTokens.ElementAt(0).CompareNoCase("LayoutFile") == 0 &&
rgLineTokens.ElementAt(1).Compare("=") == 0)
{
AddCommaSeparatedValues(rgLineTokens, rgLayoutFiles, FALSE);
break;
}
}
for (int i = 0; i < rgLayoutFiles.GetSize(); i++)
{
Add(rgLayoutFiles.ElementAt(i), TRUE);
}
}
return TRUE;
}
BOOL CInfLayoutFiles::Add(LPCTSTR pszInfFile, BOOL bLayoutFile)
{
CInfParser parser;
if (!parser.LoadInfFile(pszInfFile))
return FALSE;
return Add(parser, bLayoutFile);
}
void CInfLayoutFiles::Sort()
{
s_pStringData = m_pStringData;
qsort(m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
#ifdef _DEBUG
m_bSorted = TRUE;
#endif
}
SOURCE_DISK_INFO* CInfLayoutFiles::FindDriverFileSourceDisk(LPCTSTR pszDriverFileTitle)
{
ASSERT(m_bSorted);
// Build a dummy layout-file key to allow the standard binary search to work
// (Note that we've left INF_LAYOUT_FILE_PADDING chars at the end of the string data)
ASSERT(lstrlen(pszDriverFileTitle) + 1 < INF_LAYOUT_FILE_PADDING);
INF_LAYOUT_FILE key;
key.dwNameOffset = m_cbStringData;
lstrcpy(m_pStringData + m_cbStringData, pszDriverFileTitle);
s_pStringData = m_pStringData;
INF_LAYOUT_FILE* pResult = (INF_LAYOUT_FILE*)bsearch(
&key, m_prgFiles, m_cFiles, sizeof(INF_LAYOUT_FILE), CompareInfLayoutFiles);
if (pResult == NULL)
{
ASSERT(FALSE);
return NULL;
}
// REVIEW: Is it worth making this a binary search?
WORD wDiskID = MAKE_DISK_ID(pResult->iDisk, pResult->iLayout);
for (int iDisk = 0; iDisk < m_rgSourceDisks.GetSize(); iDisk++)
{
SOURCE_DISK_INFO* pDiskInfo = m_rgSourceDisks[iDisk];
if (pDiskInfo->wDiskID == wDiskID)
return pDiskInfo;
}
ASSERT(FALSE);
return NULL;
}
#ifdef _DEBUG
void CInfLayoutFiles::Dump()
{
TRACE("CInfLayoutFiles (0x%08x)\r\n", (int)this);
for (int i = 0; i < m_cFiles; i++)
{
INF_LAYOUT_FILE* pFile = &m_prgFiles[i];
TRACE(" File %d: %s, layout %d, disk %d\r\n", i, m_pStringData + pFile->dwNameOffset, (int)pFile->iLayout, (int)pFile->iDisk);
}
}
#endif // _DEBUG
//////////////////////////////////////////////////////////////////////////////
// CInfFileList
CInfFileList::CInfFileList()
{
}
CInfFileList::~CInfFileList()
{
for (int i = m_rgDriverFiles.GetSize()-1; i >= 0; i--)
{
free(m_rgDriverFiles[i]);
}
for (i = m_rgCabFiles.GetSize() - 1; i >= 0; i--)
{
free((LPTSTR)m_rgCabFiles.GetItemData(i));
}
}
void CInfFileList::SetDriverSourceDir(LPCTSTR pszSourceDir)
{
m_strDriverSourceDir = pszSourceDir;
}
BOOL CInfFileList::AddBaseFiles(LPCTSTR pszInfFile)
{
CInfParser parser;
if (!parser.LoadInfFile(pszInfFile))
return FALSE;
if (!parser.GotoSection("BaseWinOptions"))
return FALSE;
CStringArray rgSections;
CStringArray rgLineTokens;
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 1)
rgSections.Add(rgLineTokens.ElementAt(0));
}
int cSections = rgSections.GetSize();
if (cSections == 0)
return FALSE;
// Walk through each major section, grabbing section names from CopyFiles= lines
CStringArray rgCopyFiles;
for (int iSection = 0; iSection < cSections; iSection++)
{
if (!parser.GotoSection(rgSections[iSection]))
continue;
// Look for "CopyFiles="
while (parser.GetSectionLineTokens(rgLineTokens))
{
if (rgLineTokens.GetSize() >= 3 &&
rgLineTokens.ElementAt(0).CompareNoCase("CopyFiles") == 0 &&
rgLineTokens.ElementAt(1).Compare("=") == 0)
{
AddCommaSeparatedValues(rgLineTokens, rgCopyFiles, TRUE);
}
}
}
// Walk through each CopyFiles section, grabbing the names of files to copy
parser.GetFilesFromCopyFilesSections(rgCopyFiles, m_rgDriverFiles);
m_rgLayoutFiles.Add(parser);
// for (int i = 0; i < rgAllFiles.GetSize(); i++)
// {
// TRACE("File %d: %s\r\n", i, rgAllFiles[i]);
// }
return TRUE;
}
BOOL CInfFileList::AddDeviceFiles(LPCTSTR pszInfFile, LPCTSTR pszDeviceID)
{
CInfParser parser;
if (!parser.LoadInfFile(pszInfFile))
return FALSE;
if (!GetDeviceCopyFiles(parser, pszDeviceID, m_rgDriverFiles))
return FALSE;
// Build a list of all layout files, including current file
m_rgLayoutFiles.Add(parser);
return TRUE;
}
// Retrieves one of the standard setupx destination directories.
// Always appends a backslash to the name.
// Returns number of characters copied.
//
// See setupx.h for a list of valid LDID_ values.
//
int GetStandardTargetPath(int iDirNumber, LPCTSTR pszTargetSubDir, LPTSTR pszBuf)
{
int cch = GetWindowsDirectory(pszBuf, MAX_PATH);
if (pszBuf[cch-1] != '\\')
pszBuf[cch++] = '\\';
switch (iDirNumber)
{
case 10: // LDID_WIN
break;
case 11: // LDID_SYS
cch = GetSystemDirectory(pszBuf, MAX_PATH);
if (pszBuf[cch-1] != '\\')
pszBuf[cch++] = '\\';
break;
case 17: // LDID_INF
lstrcpy(pszBuf + cch, "INF\\");
cch += 4;
break;
case 18: // LDID_HELP
lstrcpy(pszBuf + cch, "HELP\\");
cch += 5;
break;
case 25: // LDID_SHARED (windows dir)
break;
case 26: // LDID_WINBOOT (windows dir)
break;
default:
ASSERT(FALSE);
cch = 0;
break;
}
if (pszTargetSubDir != NULL && *pszTargetSubDir != '\0')
{
lstrcpy(pszBuf + cch, pszTargetSubDir);
cch += lstrlen(pszTargetSubDir);
if (pszBuf[cch-1] != '\\')
pszBuf[cch++] = '\\';
}
pszBuf[cch] = '\0';
return cch;
}
int GetDriverTargetPath(const DRIVER_FILE_INFO* pFileInfo, LPTSTR pszBuf)
{
LPCTSTR pszTargetSubDir = pFileInfo->szFileTitle + lstrlen(pFileInfo->szFileTitle) + 1;
return GetStandardTargetPath(pFileInfo->nTargetDir, pszTargetSubDir, pszBuf);
}
// Returns number of CAB files (from Windows CD) that need to be copied.
// Note that other files may still need to be copied from the driver source directory.
int CInfFileList::BuildSourceFileList()
{
TCHAR szPath[MAX_PATH];
CSortedStringArray& rgCabFiles = m_rgCabFiles;
CSortedStringArray& rgSourceFiles = m_rgSourceFiles;
m_rgLayoutFiles.Sort();
#ifdef _DEBUG
// m_rgLayoutFiles.Dump();
#endif
for (int iDriverFile = 0; iDriverFile < m_rgDriverFiles.GetSize(); iDriverFile++)
{
DRIVER_FILE_INFO* pDriverFileInfo = m_rgDriverFiles[iDriverFile];
// Check if file is already installed
// GetStandardTargetPath(pDriverFileInfo->nTargetDir, szPath);
// MakePath(szPath, szPath, pDriverFileInfo->szFileTitle);
// if (DoesFileExist(szPath))
// continue; // skip this file
if (!m_strDriverSourceDir.IsEmpty())
{
// Check if file exists in source directory
MakePath(szPath, m_strDriverSourceDir, pDriverFileInfo->szFileTitle);
if (DoesFileExist(szPath))
{
if (-1 == rgSourceFiles.Find(pDriverFileInfo->szFileTitle))
{
rgSourceFiles.Add(pDriverFileInfo->szFileTitle, 0);
}
continue;
}
}
SOURCE_DISK_INFO* pSourceDiskInfo = m_rgLayoutFiles.FindDriverFileSourceDisk(pDriverFileInfo->szFileTitle);
if (pSourceDiskInfo != NULL && !pSourceDiskInfo->strCabFile.IsEmpty())
{
if (-1 == rgCabFiles.Find(pSourceDiskInfo->strCabFile))
{
LPTSTR pszDiskName = lstrdup(pSourceDiskInfo->strDescription);
rgCabFiles.Add(pSourceDiskInfo->strCabFile, (DWORD)pszDiskName);
}
continue;
}
}
for (int i = 0; i < rgCabFiles.GetSize(); i++)
{
TRACE("%s\r\n", rgCabFiles[i]);
}
return rgCabFiles.GetSize();
}
#if NOT_FINISHED
BOOL CInfFileList::CheckWindowsCD(LPCTSTR pszDirectory)
{
if (m_rgCabFiles.GetSize() == 0)
return TRUE; // no files to copy
UINT uPrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
// Check for existence of one of the cabs on the CD
// REVIEW: if it's a fixed disk, should check for all files
// REVIEW: if it's a network share, this could take a long time
TCHAR szPath[MAX_PATH];
BOOL bResult = FALSE;
MakePath(szPath, pszDirectory, ".");
if (DoesFileExist(szPath))
{
MakePath(szPath, pszDirectory, m_rgCabFiles[0]);
bResult = DoesFileExist(szPath);
if (!bResult)
{
// Search one level of subdirectories starting with "W"
WIN32_FIND_DATA Find;
HANDLE hFind;
MakePath(szPath, pszDirectory, "W*.*");
if (INVALID_HANDLE_VALUE != (hFind = FindFirstFile(szPath, &Find)))
{
do
{
MakePath(szPath, pszDirectory, Find.cFileName);
MakePath(szPath, szPath, m_rgCabFiles[0]);
if (DoesFileExist(szPath))
{
bResult = TRUE;
break;
}
}
while (FindNextFile(hFind, &Find));
FindClose(hFind);
}
}
}
SetErrorMode(uPrevErrorMode);
return bResult;
}
BOOL CInfFileList::FindWindowsCD(HWND hwndParent)
{
TCHAR szPath[MAX_PATH];
// check the version of the Windows source path that we've saved
if (theApp.GetProfileString(c_szRegVal_PrevSourcePath, szPath, _countof(szPath)))
{
if (CheckWindowsCD(szPath))
{
// goto success;
}
}
else
{
// Check the current Windows source path
CRegistry reg;
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szSetupKey) &&
reg.QueryStringValue(c_szRegVal_SourcePath, szPath, _countof(szPath)))
{
if (CheckWindowsCD(szPath))
{
goto success;
}
}
}
if (!PromptWindowsCD(hwndParent, szPath, szPath))
return FALSE;
success:
m_strWindowsCD = szPath;
return TRUE;
}
BOOL CInfFileList::PromptWindowsCD(HWND hwndParent, LPCTSTR pszInitialDir, LPTSTR pszResultDir)
{
LPCTSTR pszDiskName = (LPCTSTR)m_rgCabFiles.GetItemData(0);
CWinPathDlg dlg(pszInitialDir, pszDiskName, CWnd::FromHandle(hwndParent));
// Loop until user types a path to a valid CD, or clicks Cancel
for (;;)
{
if (IDOK != dlg.DoModal())
return FALSE;
if (CheckWindowsCD(dlg.m_strPath))
{
lstrcpy(pszResultDir, dlg.m_strPath);
return TRUE;
}
}
}
BOOL CInfFileList::CopySourceFiles(HWND hwndParent, LPCTSTR pszDestDir, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
{
int cFiles = m_rgCabFiles.GetSize() + m_rgSourceFiles.GetSize();
if (m_rgCabFiles.GetSize() > 0)
{
}
return TRUE;
}
#endif
//////////////////////////////////////////////////////////////////////////////
// Modify system INF
class CInfUpdater : public CInfParser
{
public:
CInfUpdater(LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL);
~CInfUpdater();
enum eUpdateType {
update_NoVersionConflict = 0x01,
update_NoCopyFiles = 0x02,
update_RequireExclude = 0x04,
};
BOOL IsModified();
BOOL UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType);
LPCTSTR m_pszRequire;
LPCTSTR m_pszExclude;
protected:
void WriteToCurPos();
void Write(LPCTSTR pszString);
void Write(const void* pvData, UINT cbData);
BOOL OpenTempFile();
BOOL CloseTempFile();
BOOL RenameTempFile();
protected:
CString m_strTempFile;
HANDLE m_hTempFile;
BOOL m_bWriteSuccess;
DWORD m_iWritePos;
};
CInfUpdater::CInfUpdater(LPCTSTR pszRequire /*=NULL*/, LPCTSTR pszExclude /*=NULL*/)
{
m_hTempFile = INVALID_HANDLE_VALUE;
m_pszRequire = pszRequire;
m_pszExclude = pszExclude;
}
CInfUpdater::~CInfUpdater()
{
CloseTempFile();
if (!m_strTempFile.IsEmpty())
{
DeleteFile(m_strTempFile);
}
}
BOOL CInfUpdater::IsModified()
{
ASSERT(m_pszFileData != NULL);
return !memcmp(SZ_CHECK_MODIFIED_HEADER, m_pszFileData, _lengthof(SZ_CHECK_MODIFIED_HEADER));
}
BOOL CInfUpdater::UpdateInfFile(LPCTSTR pszBackupLocation, UINT updateType)
{
ASSERT(m_pszFileData != NULL);
if (m_pszFileData == NULL)
return FALSE;
Rewind();
if (!OpenTempFile())
return FALSE;
Write(SZ_MODIFIED_INF_HEADER);
Write(pszBackupLocation);
Write(SZ_MODIFIED_INF_HEADER2);
BOOL bInSection = FALSE;
for (;;)
{
// Skip whitespace
while (m_pszFileData[m_iPos] == ' ' || m_pszFileData[m_iPos] == '\t')
m_iPos++;
// Note: we're always at the beginning of a line here.
TCHAR ch = m_pszFileData[m_iPos];
if (ch == '\0')
break;
if (updateType & update_NoVersionConflict)
{
if (ch != '[' && ch != ';' && (UINT)ch > ' ')
{
// Look for lines w/ just a filename, and append ",,,32" to them
LPTSTR pszLine = m_pszFileData + m_iPos;
LPTSTR pchEnd = pszLine;
while (*pchEnd != '\0' && *pchEnd != '\r' && *pchEnd != '\n' &&
*pchEnd != ';' && *pchEnd != '=' && *pchEnd != ',')
{
pchEnd++;
}
// don't change lines that already have ,,,16 or something
// also don't change lines like CatalogFile=nettrans.cat
if (*pchEnd != ',' && *pchEnd != '=')
{
// Backup over whitespace
while (*(pchEnd-1) == ' ' || *(pchEnd-1) == '\t')
pchEnd--;
// Is it a filename? Note that some filenames will be missed here, but
// we really only care about .dll, .386, .vxd, and a few others
CString str(pszLine, (int)(pchEnd - pszLine));
if (lstrlen(FindExtension(str)) == 3)
{
m_iPos = (DWORD)(pchEnd - m_pszFileData);
WriteToCurPos();
Write(",,,32");
}
}
}
}
if (updateType & update_NoCopyFiles)
{
if (0 == memcmp(m_pszFileData + m_iPos, "CopyFiles", _lengthof("CopyFiles")))
{
// Comment out the reference to the CopyFiles section
WriteToCurPos();
Write(";hc ");
}
}
if (updateType & update_RequireExclude)
{
ASSERT(m_pszRequire != NULL);
ASSERT(m_pszExclude != NULL);
const TCHAR c_szRequireAll[] = _T("HKR,Ndi\\Compatibility,RequireAll,,\"");
const TCHAR c_szExcludeAll[] = _T("HKR,Ndi\\Compatibility,ExcludeAll,,\"");
LPCTSTR pszInsert = NULL;
if (0 == memcmp(m_pszFileData + m_iPos, c_szRequireAll, _lengthof(c_szRequireAll)))
pszInsert = m_pszRequire;
else if (0 == memcmp(m_pszFileData + m_iPos, c_szExcludeAll, _lengthof(c_szExcludeAll)))
pszInsert = m_pszExclude;
if (pszInsert != NULL)
{
// Insert the appropriate string between the double-quotes
ASSERT(_lengthof(c_szRequireAll) == _lengthof(c_szExcludeAll));
m_iPos += _lengthof(c_szRequireAll);
WriteToCurPos();
Write(pszInsert);
// Skip to closing quote
while (m_pszFileData[m_iPos] != '\"' && m_pszFileData[m_iPos] != '\0')
m_iPos += 1;
m_iWritePos = m_iPos;
}
}
GotoNextLine();
}
WriteToCurPos();
if (!CloseTempFile())
return FALSE;
if (!RenameTempFile())
return FALSE;
return TRUE;
}
void CInfUpdater::WriteToCurPos()
{
ASSERT(m_iPos >= m_iWritePos);
Write(m_pszFileData + m_iWritePos, m_iPos - m_iWritePos);
m_iWritePos = m_iPos;
}
void CInfUpdater::Write(LPCTSTR pszString)
{
Write(pszString, lstrlen(pszString));
}
void CInfUpdater::Write(const void* pvData, UINT cbData)
{
DWORD cbWritten;
if (!WriteFile(m_hTempFile, pvData, cbData, &cbWritten, NULL) || cbData != cbWritten)
m_bWriteSuccess = FALSE;
}
BOOL CInfUpdater::OpenTempFile()
{
TCHAR szDirectory[MAX_PATH];
GetFullInfPath(m_strFileName, szDirectory, _countof(szDirectory));
*(FindFileTitle(szDirectory)) = '\0';
LPTSTR pszBuf = m_strTempFile.GetBuffer(MAX_PATH);
GetTempFileName(szDirectory, "inf", 0, pszBuf);
m_strTempFile.ReleaseBuffer();
ASSERT(m_hTempFile == INVALID_HANDLE_VALUE);
m_hTempFile = CreateFile(m_strTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_hTempFile == INVALID_HANDLE_VALUE)
return FALSE;
m_iWritePos = 0;
m_bWriteSuccess = TRUE;
return TRUE;
}
BOOL CInfUpdater::CloseTempFile()
{
if (m_hTempFile == INVALID_HANDLE_VALUE)
return FALSE;
BOOL bResult = CloseHandle(m_hTempFile);
m_hTempFile = INVALID_HANDLE_VALUE;
if (m_bWriteSuccess)
m_bWriteSuccess = bResult;
return m_bWriteSuccess;
}
BOOL CInfUpdater::RenameTempFile()
{
TCHAR szInfPath[MAX_PATH];
GetFullInfPath(m_strFileName, szInfPath, _countof(szInfPath));
if (!DeleteFile(szInfPath))
return FALSE;
if (!MoveFile(m_strTempFile, szInfPath))
return FALSE;
return TRUE;
}
// Modifies the given INF file to avoid the Version Conflict dialog.
// Backs up original version in same directory, e.g. "Net (HomeClick backup).inf"
BOOL ModifyInf_Helper(LPCTSTR pszInfFile, UINT updateType, LPCTSTR pszRequire = NULL, LPCTSTR pszExclude = NULL)
{
CInfUpdater infUpdate(pszRequire, pszExclude);
if (!infUpdate.LoadInfFile(pszInfFile))
return FALSE;
// Already updated?
if (infUpdate.IsModified())
return FALSE; // already modified, don't modify again
TCHAR szInfPath[MAX_PATH];
GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
TCHAR szBackup[MAX_PATH];
lstrcpy(szBackup, szInfPath);
lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
FILETIME ftSrcCreated;
FILETIME ftSrcModified;
HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
CloseHandle(hFile);
if (!CopyFile(szInfPath, szBackup, FALSE))
return FALSE;
BOOL bResult = infUpdate.UpdateInfFile(szBackup, updateType);
hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
DWORD dwFileSize = GetFileSize(hFile, NULL);
SetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
CloseHandle(hFile);
return bResult;
}
BOOL ModifyInf_NoVersionConflict(LPCTSTR pszInfFile)
{
return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoVersionConflict);
}
BOOL ModifyInf_NoCopyFiles(LPCTSTR pszInfFile)
{
return ModifyInf_Helper(pszInfFile, CInfUpdater::update_NoCopyFiles);
}
BOOL ModifyInf_RequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
{
return ModifyInf_Helper(pszInfFile, CInfUpdater::update_RequireExclude, pszRequire, pszExclude);
}
BOOL ModifyInf_NoCopyAndRequireExclude(LPCTSTR pszInfFile, LPCTSTR pszRequire, LPCTSTR pszExclude)
{
return ModifyInf_Helper(pszInfFile,
CInfUpdater::update_NoCopyFiles | CInfUpdater::update_RequireExclude,
pszRequire, pszExclude);
}
BOOL RestoreInfBackup(LPCTSTR pszInfFile)
{
TCHAR szInfPath[MAX_PATH];
GetFullInfPath(pszInfFile, szInfPath, _countof(szInfPath));
TCHAR szBackup[MAX_PATH];
lstrcpy(szBackup, szInfPath);
lstrcpy(FindExtension(szBackup)-1, SZ_INF_BACKUP_SUFFIX);
/*
FILETIME ftSrcCreated;
FILETIME ftSrcModified;
HANDLE hFile = CreateFile(szInfPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
CloseHandle(hFile);
*/
if (!DoesFileExist(szBackup))
return FALSE;
if (!DeleteFile(szInfPath))
return FALSE;
if (!MoveFile(szBackup, szInfPath))
return FALSE;
/*
hFile = CreateFile(szInfPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
GetFileTime(hFile, &ftSrcCreated, NULL, &ftSrcModified);
CloseHandle(hFile);
*/
return TRUE;
}
BOOL CheckInfSectionInstallation(LPCTSTR pszInfFile, LPCTSTR pszInfSection)
{
CInfParser parser;
if (!parser.LoadInfFile(pszInfFile))
{
ASSERT(FALSE);
return TRUE; // all known files are present even though it's an error
}
CDriverFileArray rgFiles;
if (!parser.GetFilesFromInstallSection(pszInfSection, rgFiles))
{
ASSERT(FALSE);
return TRUE; // all known files are present even though it's an error
}
TCHAR szPath[MAX_PATH];
int cFiles = rgFiles.GetSize();
for (int iFile = 0; iFile < cFiles; iFile++)
{
int cch = GetDriverTargetPath(rgFiles[iFile], szPath);
if (cch != 0)
{
lstrcpy(szPath + cch, rgFiles[iFile]->szFileTitle);
if (!DoesFileExist(szPath))
return FALSE;
}
}
return TRUE;
}
BOOL InstallInfSection(LPCTSTR pszInfFile, LPCTSTR pszInfSection, BOOL bWait)
{
// Make a modified copy of the INF
BOOL bModifiedInf = ModifyInf_NoVersionConflict(pszInfFile);
TCHAR szPath[MAX_PATH + 200];
int cch = GetWindowsDirectory(szPath, _countof(szPath));
#ifdef UNICODE
wnsprintf(szPath + cch, ARRAYSIZE(szPath) - cch, L"\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
#else
wsprintf(szPath + cch, "\\RunDll.exe setupx.dll,InstallHinfSection %s 0 %s", pszInfSection, pszInfFile);
#endif
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
BOOL bResult = CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (bResult)
{
if (bWait)
{
WaitForSingleObject(pi.hProcess, INFINITE);
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
if (bModifiedInf)
{
RestoreInfBackup(pszInfFile);
}
return bResult;
}