|
|
//
// 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); TRACE("Error: Malloc failed on DRIVER_FILE_INFO.\r\n"); if (pFileInfo) { 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();
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;
cchAllFileNames += m_cbStringData + cFiles; cFiles += m_cFiles; INF_LAYOUT_FILE* pFile = (INF_LAYOUT_FILE*)realloc(m_prgFiles, cFiles * sizeof(INF_LAYOUT_FILE)); LPTSTR pchDest = (LPTSTR)realloc(m_pStringData, cchAllFileNames + INF_LAYOUT_FILE_PADDING);
if (pchDest) { m_pStringData = pchDest; } if (pFile) { m_prgFiles = pFile; }
if (pchDest && pFile) { m_cFiles = cFiles; m_cbStringData = cchAllFileNames; pchDest += dwOffset; pFile += 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++; } } else { return FALSE; }
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); } }
m_rgLayoutFileNames.Add(parser.m_strFileName, 0); 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; }
|