windows-nt/Source/XPSP1/NT/sdktools/infgen/infgen.cpp
2020-09-26 16:20:57 +08:00

1880 lines
51 KiB
C++

// infgen.cpp : Defines the initialization routines for the DLL.
//
#include <windows.h>
#include <stdio.h>
#include <mbctype.h>
#include <Shlwapi.h>
#include "infgen.h"
#include "message.h"
#define DELETE_EMPTY 1
#define MAX_LINE ( MAX_PATH * 2 )
struct _SectionEntry
{
TCHAR *szLine;
DWORD cRef;
};
// Track entries throughout the INF related to a section
typedef struct _AssociatedEntries
{
PSECTIONENTRY pse;
_AssociatedEntries *pNext;
} ASSOCIATEDENTRIES, *PASSOCIATEDENTRIES;
struct _SectionList
{
TCHAR szSectionName[ MAX_PATH ];
PSECTIONENTRY pseSectionEntries;
PASSOCIATEDENTRIES pAssociatedEntries;
DWORD dwSectionEntries;
DWORD cRef;
struct _SectionList *Next;
};
struct _SectionAssociationList
{
_SectionList *pSection;
_SectionAssociationList *pNext;
};
extern HINSTANCE g_hMyInstance;
CUpdateInf::CUpdateInf(
void
) : m_bGenInitCalled(FALSE), m_dwInfGenError(0),
m_sectionList(NULL), m_bActiveDB(FALSE), m_hInf(INVALID_HANDLE_VALUE),
m_pTypeInfo(NULL), m_cRef(1)
{
memset( m_rgNameHash, 0, sizeof( m_rgNameHash ) );
// Default DB connection
// WINSEQFE default DB with windows auth
_tcscpy( m_szDataServer, _T("WINSEQFE") );
m_szDatabase[0] = _T('\0');
m_szUserName[0] = _T('\0');
}
CUpdateInf::~CUpdateInf(
void
)
{
if ( m_pTypeInfo ) {
m_pTypeInfo->Release();
m_pTypeInfo = NULL;
}
Cleanup();
}
//
// IUnknown
//
ULONG
CUpdateInf::AddRef( void )
{
return ++m_cRef;
}
ULONG
CUpdateInf::Release( void )
{
if ( 0L == --m_cRef )
{
delete this;
return 0;
}
return m_cRef;
}
HRESULT
CUpdateInf::QueryInterface( REFIID riid, void **ppv )
{
if ( NULL == ppv )
return E_POINTER;
*ppv = NULL;
if ( IID_IUnknown == riid )
*ppv = (IUnknown *)this;
else if ( IID_IDispatch == riid )
*ppv = (IDispatch *)this;
else if ( IID_IUpdateInf == riid )
*ppv = (IUpdateInf *)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
//
// IDispatch
//
HRESULT
CUpdateInf::GetTypeInfoCount( UINT *pCountTypeInfo )
{
*pCountTypeInfo = 1;
return S_OK;
}
HRESULT
CUpdateInf::GetTypeInfo( UINT iTypeInfo,
LCID lcid,
ITypeInfo **ppTypeInfo )
{
*ppTypeInfo = NULL;
if ( 0 != iTypeInfo )
return DISP_E_BADINDEX;
m_pTypeInfo->AddRef();
*ppTypeInfo = m_pTypeInfo;
return S_OK;
}
HRESULT
CUpdateInf::GetIDsOfNames( REFIID riid,
LPOLESTR *aszNames,
UINT cNames,
LCID lcid,
DISPID *aDispIDs )
{
if ( IID_NULL != riid )
return DISP_E_UNKNOWNINTERFACE;
return DispGetIDsOfNames( m_pTypeInfo,
aszNames,
cNames,
aDispIDs );
}
HRESULT
CUpdateInf::Invoke( DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr )
{
if ( IID_NULL != riid )
return DISP_E_UNKNOWNINTERFACE;
return DispInvoke( this,
m_pTypeInfo,
dispIdMember,
wFlags,
pDispParams,
pVarResult,
pExcepInfo,
puArgErr );
}
//
// Initialization function so we can use type-library based
// functions to handle the IDispatch calls
//
BOOL
CUpdateInf::Init(
void
)
{
HRESULT hr;
ITypeLib *pTypeLib = NULL;
hr = LoadRegTypeLib( LIBID_InfGeneratorLib, (1), (0), LANG_NEUTRAL, &pTypeLib );
if ( FAILED(hr) )
{
return FALSE;
}
hr = pTypeLib->GetTypeInfoOfGuid( IID_IUpdateInf, &m_pTypeInfo );
if ( FAILED(hr) )
{
return FALSE;
}
// Cleanup
pTypeLib->Release();
return TRUE;
}
//
// IUpdateInf
//
HRESULT
CUpdateInf::InsertFile(
BSTR bstrFileName
)
{
HRESULT hr;
BOOL bRet = FALSE;
DWORD dwRecordCount;
LPTSTR lpszSQL;
CSimpleDBResults *prs;
if ( !m_bActiveDB )
{
m_dwInfGenError = FAIL_NO_DATABASE;
return E_FAIL;
}
if( NULL == bstrFileName ) {
m_dwInfGenError = FAIL_INVALIDPARAM;
return E_FAIL;
}
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
lpszSQL = new TCHAR [1000];
if( NULL == lpszSQL ) {
return E_OUTOFMEMORY;
}
#ifndef UNICODE
char *szFileName;
size_t lenFileName = SysStringLen(bstrFileName) + 1;
szFileName = new char[lenFileName];
if ( NULL == szFileName )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrFileName,
lenFileName,
szFileName,
lenFileName,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
wchar_t *szFileName = bstrFileName;
#endif
_stprintf( lpszSQL,
_T("Select DISTINCT Section,Entry from Ref_SrcFileLocations,Ref_DefaultInstallerInf where Ref_SrcFileLocations.FileName = '%s' AND Ref_SrcFileLocations.FileID = Ref_DefaultInstallerInf.FileID"), szFileName );
//sprintf( lpszSQL,
// "Select * from Ref_SrcFileLocations" );
if( SUCCEEDED(m_pdb->Execute( lpszSQL, &prs )) ) {
if ( S_OK == (hr = prs->NextRow()) )
{
bRet = TRUE;
do {
// an entry can consist of one or more null-terminated
// strings, so we clear the entry buffer here
memset( m_textBuffer2, 0, sizeof(m_textBuffer2) );
if ( FAILED(prs->GetFieldValue( _T("Section"), m_textBuffer, BUFFER_SIZE )) ||
FAILED(prs->GetFieldValue( _T("Entry"), m_textBuffer2, BUFFER_SIZE )) ) {
m_dwInfGenError = FAIL_RECORDSET;
bRet = FALSE;
break;
}
if ( !WritePrivateProfileSection( m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
break;
}
} while( S_OK == (hr = prs->NextRow()) );
if ( FAILED(hr) )
{
m_dwInfGenError = hr;
bRet = FALSE;
}
if ( bRet ) {
// Write an entry in the [SourceDiskFiles] section for this file
if ( !WritePrivateProfileString( _T("SourceDisksFiles"), szFileName, _T("1"), m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
}
} else if ( SUCCEEDED(hr) ) {
m_dwInfGenError = FAIL_NOSECTION;
}
else
{
m_dwInfGenError = hr;
}
delete prs;
} else {
m_dwInfGenError = FAIL_RECORDSET;
}
#ifndef UNICODE
delete [] szFileName;
#endif
delete [] lpszSQL;
if ( bRet ) {
return S_OK;
}
else {
return E_FAIL;
}
}
HRESULT
CUpdateInf::WriteSectionData(
BSTR bstrSection,
BSTR bstrValue
)
{
BOOL bRet = TRUE;
size_t lenSection = SysStringLen(bstrSection) + 1,
lenValue = SysStringLen(bstrValue) + 1;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( lenSection >= BUFFER_SIZE ||
lenValue + 1 >= BUFFER_SIZE )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrSection,
lenSection,
m_textBuffer,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrValue,
lenValue,
m_textBuffer2,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_textBuffer, bstrSection, sizeof(wchar_t) * lenSection );
memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
#endif
m_textBuffer2[lenValue] = '\0'; // end with a double NULL
if ( !WritePrivateProfileSection( m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
if (bRet) {
return S_OK;
}
else {
return E_FAIL;
}
}
HRESULT
CUpdateInf::SetConfigurationField(
BSTR bstrFieldName,
BSTR bstrValue
)
{
BOOL bRet = TRUE;
size_t lenFieldName = SysStringLen(bstrFieldName) + 1,
lenValue = SysStringLen(bstrValue) + 1;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( lenFieldName >= BUFFER_SIZE ||
lenValue >= BUFFER_SIZE )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrFieldName,
lenFieldName,
m_textBuffer,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrValue,
lenValue,
m_textBuffer2,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_textBuffer, bstrFieldName, sizeof(wchar_t) * lenFieldName );
memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
#endif
if ( !WritePrivateProfileString( _T("Configuration"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
if (bRet) {
return S_OK;
}
else {
return E_FAIL;
}
}
HRESULT
CUpdateInf::SetVersionField(
BSTR bstrFieldName,
BSTR bstrValue
)
{
BOOL bRet = TRUE;
size_t lenFieldName = SysStringLen(bstrFieldName) + 1,
lenValue = SysStringLen(bstrValue) + 1;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( lenFieldName >= BUFFER_SIZE ||
lenValue >= BUFFER_SIZE )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrFieldName,
lenFieldName,
m_textBuffer,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrValue,
lenValue,
m_textBuffer2,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_textBuffer, bstrFieldName, sizeof(wchar_t) * lenFieldName );
memcpy( m_textBuffer2, bstrValue, sizeof(wchar_t) * lenValue );
#endif
if ( !WritePrivateProfileString( _T("Version"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
if (bRet) {
return S_OK;
}
else {
return E_FAIL;
}
}
HRESULT
CUpdateInf::AddSourceDisksFilesEntry(
BSTR bstrFile,
BSTR bstrTag
)
{
BOOL bRet = TRUE;
size_t lenFile = SysStringLen(bstrFile) + 1,
lenTag = SysStringLen(bstrTag) + 1;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( lenFile >= BUFFER_SIZE ||
lenTag >= BUFFER_SIZE )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrFile,
lenFile,
m_textBuffer,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrTag,
lenTag,
m_textBuffer2,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_textBuffer, bstrFile, sizeof(wchar_t) * lenFile );
memcpy( m_textBuffer2, bstrTag, sizeof(wchar_t) * lenTag );
#endif
if ( !WritePrivateProfileString( _T("SourceDisksFiles"), m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
if (bRet) {
return S_OK;
}
else {
return E_FAIL;
}
}
HRESULT
CUpdateInf::AddEquality(
BSTR bstrSect,
BSTR bstrLVal,
BSTR bstrRVal
)
{
BOOL bRet = TRUE;
size_t lenSect = SysStringLen(bstrSect) + 1,
lenLVal = SysStringLen(bstrLVal) + 1,
lenRVal = SysStringLen(bstrRVal) + 1;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( lenLVal >= BUFFER_SIZE ||
lenRVal >= BUFFER_SIZE ||
lenSect >= BUFFER_SIZE )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrLVal,
lenLVal,
m_textBuffer,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrRVal,
lenRVal,
m_textBuffer2,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrSect,
lenSect,
m_textBuffer3,
BUFFER_SIZE,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_textBuffer, bstrLVal, sizeof(wchar_t) * lenLVal );
memcpy( m_textBuffer2, bstrRVal, sizeof(wchar_t) * lenRVal );
memcpy( m_textBuffer3, bstrSect, sizeof(wchar_t) * lenSect );
#endif
if ( !WritePrivateProfileString( m_textBuffer3, m_textBuffer, m_textBuffer2, m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
if (bRet) {
return S_OK;
}
else {
return E_FAIL;
}
}
void
CUpdateInf::Cleanup(
void
)
{
PSECTION psRef = m_sectionList;
OutputDebugString( _T("Freeing m_sectionList ...\n") );
while( psRef ) {
PSECTION psRef1 = psRef;
PSECTIONENTRY pse = psRef1->pseSectionEntries;
PASSOCIATEDENTRIES pAssoc = psRef1->pAssociatedEntries;
psRef = psRef->Next;
if ( NULL != pse ) {
for ( DWORD i = 0; i < psRef1->dwSectionEntries; i++ ) {
if ( pse[i].szLine ) delete [] pse[i].szLine;
}
delete [] pse;
}
while ( pAssoc ) {
PASSOCIATEDENTRIES pDel = pAssoc;
pAssoc = pAssoc->pNext;
delete pDel;
}
delete psRef1;
}
m_sectionList = NULL;
OutputDebugString( _T("Freeing m_rgNameHash ...\n") );
for ( short i = 0; i < HASH_BUCKETS; i++ ) {
if ( m_rgNameHash[i] ) {
PSECTIONASSOCIATIONLIST pAssocList = m_rgNameHash[i];
while ( pAssocList ) {
PSECTIONASSOCIATIONLIST pDel = pAssocList;
pAssocList = pAssocList->pNext;
delete pDel;
}
m_rgNameHash[i] = NULL;
}
}
OutputDebugString( _T("Cleanup finished\n") );
}
HRESULT
CUpdateInf::CloseGen(
BOOL bTrimInf
)
{
BOOL bRet = TRUE;
if( m_bGenInitCalled == FALSE ) {
m_dwInfGenError = FAIL_NOINITGENCALL;
return E_FAIL;
}
if ( bTrimInf ) {
if ( !TrimInf( m_szFilledInxFile, m_szOutFile ) ) {
bRet = FALSE;
}
}
else {
if ( !CopyFile( m_szFilledInxFile, m_szOutFile, FALSE ) ) {
m_dwInfGenError = GetLastError();
bRet = FALSE;
}
}
if ( !DeleteFile( m_szFilledInxFile ) ) {
m_dwInfGenError = GetLastError();
return S_FALSE;
}
Cleanup();
m_bGenInitCalled = FALSE;
if ( bRet ) return S_OK;
else return E_FAIL;
}
HRESULT
CUpdateInf::SetDB(
BSTR bstrServer,
BSTR bstrDB,
BSTR bstrUser,
BSTR bstrPassword
)
{
size_t lenServer = SysStringLen(bstrServer) + 1,
lenDB = SysStringLen(bstrDB) + 1,
lenUser = SysStringLen(bstrUser) + 1,
lenPassword = SysStringLen(bstrPassword) + 1;
if ( lenServer >= MAX_PATH ||
lenDB >= MAX_PATH ||
lenUser >= MAX_PATH ||
lenPassword >= MAX_PATH )
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
// Server
if ( lenServer > 1 )
{
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrServer,
lenServer,
m_szDataServer,
MAX_PATH,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_szDataServer, bstrServer, sizeof(wchar_t) * lenServer );
#endif
}
else
{
m_szDataServer[0] = _T('\0');
}
// Default DB
if ( lenDB > 1 )
{
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrDB,
lenDB,
m_szDatabase,
MAX_PATH,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_szDatabase, bstrDB, sizeof(wchar_t) * lenDB );
#endif
}
else
{
m_szDatabase[0] = _T('\0');
}
// Username
if ( lenUser > 1 )
{
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrUser,
lenUser,
m_szUserName,
MAX_PATH,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_szUserName, bstrUser, sizeof(wchar_t) * lenUser );
#endif
}
else
{
m_szUserName[0] = _T('\0');
}
// Password
if ( lenPassword > 1 )
{
#ifndef UNICODE
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrPassword,
lenPassword,
m_szPassword,
MAX_PATH,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
memcpy( m_szPassword, bstrPassword, sizeof(wchar_t) * lenPassword );
#endif
}
else
{
m_szPassword[0] = _T('\0');
}
return S_OK;
}
HRESULT
CUpdateInf::InitGen(
BSTR bstrInxFile,
BSTR bstrInfFile
)
{
size_t lenInxFile = SysStringLen(bstrInxFile) + 1,
lenInfFile = SysStringLen(bstrInfFile) + 1;
if( lenInxFile <= 1 ||
lenInfFile <= 1 )
{
m_dwInfGenError = FAIL_INVALIDPARAM;
return E_FAIL;
}
else if ( lenInxFile >= MAX_PATH ||
lenInfFile + 2 >= MAX_PATH ) // might need room to add '.\\'
{
m_dwInfGenError = FAIL_MAX_BUFFER;
return E_FAIL;
}
#ifndef UNICODE
char *szInxFile,
*szInfFile;
szInxFile = new char[lenInxFile];
szInfFile = new char[lenInfFile];
if ( NULL == szInxFile ||
NULL == szInfFile )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrInxFile,
lenInxFile,
szInxFile,
lenInxFile,
NULL,
NULL ) ) {
m_dwInfGenError = GetLastError();
return E_FAIL;
}
if ( 0 == WideCharToMultiByte( CP_ACP,
0L,
bstrInfFile,
lenInfFile,
szInfFile,
lenInfFile,
NULL,
NULL ) ) {
delete [] szInxFile;
m_dwInfGenError = GetLastError();
return E_FAIL;
}
#else
wchar_t *szInxFile = bstrInxFile,
*szInfFile = bstrInfFile;
#endif
_tcscpy( m_szInxFile, szInxFile );
_tcscpy( m_szOutFile,szInfFile );
// The Setup* function will infer a path given only a
// file, so we ensure that a path is always specified
_stprintf( m_szFilledInxFile, _T("%s%s"), (!_tcschr( szInfFile, _T('\\') )?_T(".\\"):_T("")), szInfFile );
_tcscpy( m_szFilledInxFile+_tcslen(m_szFilledInxFile)-3, _T("TMP") );
if( CopyFile( m_szInxFile, m_szFilledInxFile, FALSE ) ) {
SetFileAttributes( m_szFilledInxFile, FILE_ATTRIBUTE_NORMAL );
#ifndef UNICODE
delete [] szInfFile;
delete [] szInxFile;
#endif
// Open up a DB connection if a server was specified
if( m_szDataServer[0] ){
m_pdb = new CSimpleDatabase();
if ( SUCCEEDED(m_pdb->Connect( m_szDataServer,
m_szDatabase[0]?m_szDatabase:NULL,
m_szUserName[0]?m_szUserName:NULL,
m_szPassword[0]?m_szPassword:NULL )) ) {
m_bActiveDB = TRUE;
}
else {
m_dwInfGenError = FAIL_DSNOPEN;
return E_FAIL;
}
}
m_bGenInitCalled = TRUE;
return S_OK;
}
else {
#ifndef UNICODE
delete [] szInfFile;
delete [] szInxFile;
#endif
m_dwInfGenError = FAIL_COPYBASEINF;
return E_FAIL;
}
}
HRESULT
CUpdateInf::get_InfGenError(
BSTR *bstrError
)
{
LPVOID pErrorMsg;
DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS;
#ifndef UNICODE
wchar_t *wszErrorMsg;
size_t lenErrorMsg;
#endif
// assume system error codes will be win32-style or 0x8 stlye
if ( m_dwInfGenError | 0xc0000000 )
{
dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
}
else
{
dwFormatFlags |= FORMAT_MESSAGE_FROM_SYSTEM;
}
if ( NULL == bstrError ) {
return E_POINTER;
}
if ( !FormatMessage( dwFormatFlags,
g_hMyInstance,
m_dwInfGenError,
NULL,
(LPTSTR) &pErrorMsg,
0,
NULL ) )
{
return E_FAIL;
}
#ifndef UNICODE
lenErrorMsg = strlen((LPSTR)pErrorMsg) + 1;
wszErrorMsg = new wchar_t[lenErrorMsg];
if ( NULL == wszErrorMsg )
{
LocalFree( pErrorMsg );
return E_OUTOFMEMORY;
}
if ( 0 == MultiByteToWideChar( _getmbcp(),
0L,
(LPSTR)pErrorMsg,
lenErrorMsg,
wszErrorMsg,
lenErrorMsg ) )
{
delete [] wszErrorMsg;
LocalFree( pErrorMsg );
return E_FAIL;
}
*bstrError = SysAllocString( wszErrorMsg );
delete [] wszErrorMsg;
#else
*bstrError = SysAllocString( (LPWSTR)pErrorMsg );
#endif
LocalFree( pErrorMsg );
if ( NULL == *bstrError ) {
return E_OUTOFMEMORY;
}
return S_OK;
}
BOOL
CUpdateInf::TrimInf(
LPTSTR szINFIn,
LPTSTR szINFOut
)
{
BOOL bRet = TRUE;
// Open a handle to the INF
m_hInf = SetupOpenInfFile( szINFIn, NULL, INF_STYLE_WIN4 , NULL );
if ( INVALID_HANDLE_VALUE == m_hInf ) {
m_dwInfGenError = GetLastError();
return FALSE;
}
if ( !GetSectionListFromInF( szINFIn ) ||
!ReadSectionEntries( szINFIn ) ||
!IdentifyUninstallSections() ||
!DeleteUnusedEntries() ||
!WriteSmallINF( szINFIn, szINFOut ) ) {
bRet = FALSE;
}
SetupCloseInfFile( m_hInf );
m_hInf = INVALID_HANDLE_VALUE;
return bRet;
}
BOOL
CUpdateInf::ReverseSectionList(
void
)
{
PSECTION pSectionList2 = NULL;
PSECTION psRef,psRef2;
psRef = m_sectionList;
psRef2 = psRef->Next;
while( psRef ) {
psRef->Next = NULL;
m_sectionList = psRef2;
if( pSectionList2 == NULL ) {
pSectionList2 = psRef;
} else {
psRef->Next = pSectionList2 ;
pSectionList2 = psRef;
}
psRef = psRef2;
if( psRef != NULL ) {
psRef2 = psRef->Next;
}
}
m_sectionList = pSectionList2;
return TRUE;
}
BOOL
CUpdateInf::WriteSmallINF(
LPTSTR szINFIn,
LPTSTR szINFOut
)
{
BOOL bRet = FALSE;
FILE *fp2 = NULL;
PSECTION ps;
ReverseSectionList();
fp2 = _tfopen( szINFOut, _T("w+") );
if( fp2 ) {
// write all the entries from in file to out file excluding the empty sections from sectionlist
ps = m_sectionList;
while( ps ) {
if( ps->cRef ) {
if ( _ftprintf( fp2, _T("[%s]\n"),ps->szSectionName) < 0 ) {
m_dwInfGenError = GetLastError();
goto fail;
}
for( DWORD i=0; i < ps->dwSectionEntries ; i++ ) {
if( ps->pseSectionEntries[i].cRef ) {
if ( _ftprintf(fp2, _T(" %s\n"), ps->pseSectionEntries[i].szLine) < 0 ) {
m_dwInfGenError = GetLastError();
goto fail;
}
}
}
_ftprintf( fp2,_T("\n") );
}
ps = ps->Next;
}
bRet = TRUE;
}
fail:
if( fp2 ) {
fclose( fp2 );
}
return bRet ;
}
BOOL
CUpdateInf::DeleteUnusedEntries(
void
)
{
HINF hInf;
BOOL bRet = TRUE;
PSECTION ps, ps2;
if ( INVALID_HANDLE_VALUE == m_hInf ) {
return FALSE;
}
ps = m_sectionList;
while( ps ) {
if ( 0 == SetupGetLineCount( m_hInf, ps->szSectionName ) ) {
if ( 0 == --ps->cRef )
{
MarkAssociatedEntriesForDelete( ps );
}
}
ps = ps->Next;
}
ps2 = m_sectionList;
while( ps2 ) {
// If all the directives are marked delete, then mark this section
PSECTIONENTRY pse = ps2->pseSectionEntries;
// If this section has already been removed, ignore it
if ( ps2->cRef )
{
for( DWORD dwCount = 0; dwCount < ps2->dwSectionEntries ; dwCount++ ) {
if( pse[ dwCount ].cRef ) {
break;
}
}
if( dwCount == ps2->dwSectionEntries ) {
//All the directives are marked delete So mark this for delete.
if ( 0 == --ps2->cRef )
{
MarkAssociatedEntriesForDelete( ps2 );
}
}
}
ps2=ps2->Next;
}
// Determine if we can discard any AddDirId sections
DeleteUnusedDirIdSections();
return bRet;
}
/*
AddDirId sections are unused if their InstallFromSection entry has been marked
as deleted (as is the case if the corresponding section is empty). We identify
AddDirId sections by looking in the DirectoryId.Include section. This function
goes through all of the AddDirId section identified in the DirectoryId.Include
section and determines if the section is no longer used (based on whether
InstallFromSection has been marked deleted or not).
*/
BOOL
CUpdateInf::DeleteUnusedDirIdSections(
void
)
{
HINF hInf;
BOOL bRet = TRUE;
INFCONTEXT Context;
TCHAR szDirIDSection[ MAX_PATH ];
if ( INVALID_HANDLE_VALUE == m_hInf )
{
return FALSE;
}
if ( SetupFindFirstLine( m_hInf, _T("DirectoryId.Include"), _T("AddDirId"), &Context ) ) {
do{
if( SetupGetLineText( &Context, NULL, NULL, NULL , szDirIDSection, MAX_PATH , NULL ) ) {
PSECTIONASSOCIATIONLIST pSectionAssoc;
DWORD dwHash = CalcHashFromSectionName( szDirIDSection );
pSectionAssoc = m_rgNameHash[dwHash];
while ( pSectionAssoc && _tcsicmp( szDirIDSection, pSectionAssoc->pSection->szSectionName ) )
{
pSectionAssoc = pSectionAssoc->pNext;
}
// If we found a matching section, find the InstallFromSection entry
if ( pSectionAssoc ) {
PSECTIONENTRY pse = pSectionAssoc->pSection->pseSectionEntries;
DWORD dwCount;
for( dwCount = 0; dwCount < pSectionAssoc->pSection->dwSectionEntries ; dwCount++ ) {
if( 0 == _tcsncicmp( _T("InstallFromSection="), pse[ dwCount ].szLine, 19 ) ) {
break;
}
}
// If we found the InstallFromSection entry and it is marked for delete
// then this section is no longer needed; remove it and its associated
// entries
if( dwCount < pSectionAssoc->pSection->dwSectionEntries &&
!pse[dwCount].cRef ) {
if ( 0 == --pSectionAssoc->pSection->cRef )
{
MarkAssociatedEntriesForDelete( pSectionAssoc->pSection );
}
}
else if ( dwCount < pSectionAssoc->pSection->dwSectionEntries )
{
// Can InstallFromSection have more than one
// comma-delimited entry?
}
}
}
} while( SetupFindNextLine( &Context, &Context ) );
}
return bRet;
}
BOOL
CUpdateInf::IdentifyUninstallSections(
void
)
{
PSECTIONASSOCIATIONLIST pSectionFinder;
DWORD dwHash = CalcHashFromSectionName( _T("UninstallSections") );
pSectionFinder = m_rgNameHash[dwHash];
while ( pSectionFinder && _tcsicmp( _T("UninstallSections"), pSectionFinder->pSection->szSectionName ) )
{
pSectionFinder = pSectionFinder->pNext;
}
// If we found the [UninstallSections] section, identify the other sections
if ( pSectionFinder ) {
DWORD dwCount;
PSECTION pUninstallSection = pSectionFinder->pSection;
// the uninstall section is used by the installer
pUninstallSection->cRef++;
// for each entry of <uninstall_name>,<current_name> update the current_name section
for( dwCount = 0; dwCount < pUninstallSection->dwSectionEntries ; dwCount++ ) {
PSECTIONASSOCIATIONLIST pAssocSection;
TCHAR *pCurName;
pCurName = _tcschr( pUninstallSection->pseSectionEntries[dwCount].szLine, _T(',') );
if ( pCurName ) {
pCurName++; // move past the ,
dwHash = CalcHashFromSectionName( pCurName );
pAssocSection = m_rgNameHash[dwHash];
while ( pAssocSection && _tcsicmp( pCurName, pAssocSection->pSection->szSectionName ) )
{
pAssocSection = pAssocSection->pNext;
}
if ( pAssocSection )
{
DWORD dwEntry = 0;
// Update reference count on section
// NOTE: this is only necessary if we want to keep
// empty sections around, but since we don't
// know a lot about the uninstall logic we
// are playing it safe
pAssocSection->pSection->cRef++;
// Update reference count on all of the section's entries
while ( dwEntry < pAssocSection->pSection->dwSectionEntries ) {
pAssocSection->pSection->pseSectionEntries[dwEntry++].cRef++;
}
// Associate the current entry with this found section
AssociateEntryWithSection( &pUninstallSection->pseSectionEntries[dwCount], pCurName, FALSE );
}
}
}
}
return TRUE;
}
BOOL
CUpdateInf::RemoveSectionFromMultiEntry(
PSECTIONENTRY pse,
LPCTSTR szSectionName
)
{
TCHAR *pSectionName = StrStrI( pse->szLine, szSectionName );
TCHAR *pEndSection;
if ( NULL != pSectionName )
{
pEndSection = _tcschr( pSectionName, _T(',') );
if ( pEndSection )
{
memmove( pSectionName, pEndSection + 1, sizeof(TCHAR) * (_tcslen(pEndSection+1) + 1) );
}
else
{
// We might be the last entry in the list
pSectionName--;
while ( pSectionName > pse->szLine &&
_istspace( *pSectionName ) ) pSectionName--;
if ( _T(',') == *pSectionName )
{
*pSectionName = _T('\0');
}
// We must be the only remaining entry
else
{
*(pSectionName+1) = _T('\0');
}
}
return TRUE;
}
else
{
// We didn't find the section name to remove it
return FALSE;
}
}
BOOL
CUpdateInf::MarkAssociatedEntriesForDelete(
PSECTION ps
)
{
PASSOCIATEDENTRIES pAssociatedEntries = ps->pAssociatedEntries;
while ( pAssociatedEntries )
{
if ( --pAssociatedEntries->pse->cRef )
{
// This line apparently references more than one section
// so remove ourselves so the line is still useable
RemoveSectionFromMultiEntry(pAssociatedEntries->pse, ps->szSectionName);
}
pAssociatedEntries = pAssociatedEntries->pNext;
}
return TRUE;
}
BOOL
CUpdateInf::ReadSectionEntries(
LPCTSTR szINF
)
{
HINF hInf;
INFCONTEXT Context;
BOOL bRet = TRUE;
DWORD dwSectionEntries;
DWORD dwNumChars;
PSECTION ps;
if ( INVALID_HANDLE_VALUE == m_hInf ) {
return FALSE;
}
ps = m_sectionList;
while( ps ) {
if( ps->cRef ) {
dwSectionEntries = SetupGetLineCount( m_hInf, ps->szSectionName );
if( dwSectionEntries > 0 ) {
ps->pseSectionEntries = new SECTIONENTRY [dwSectionEntries];
if ( NULL == ps->pseSectionEntries ) {
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
memset( ps->pseSectionEntries, 0 , dwSectionEntries * sizeof( SECTIONENTRY ) );
memset( m_textBuffer, 0 , sizeof( m_textBuffer ) );
dwNumChars = GetPrivateProfileSection(
ps->szSectionName,
m_textBuffer,
BUFFER_SIZE,
szINF
);
if ( dwNumChars + 2 == BUFFER_SIZE ) {
m_dwInfGenError = FAIL_MAX_BUFFER;
return FALSE;
}
TCHAR * pch = m_textBuffer;
while( *pch ) {
TCHAR *pCurPos = m_textBuffer2;
do
{
if ( _T(';') != pch[0] )
{
_tcscpy( pCurPos, pch );
pCurPos += _tcslen(pch);
if ( _T('\\') == *(pCurPos - 1) ) pCurPos--;
}
pch = pch + _tcslen( pch) +1 ;
} while ( *pch && _T('\\') == *pCurPos );
pCurPos = _T('\0');
if ( _tcslen( m_textBuffer2 ) &&
!AddEntryToSection( ps, m_textBuffer2 ) ) {
bRet = FALSE;
break;
}
}
}
}
ps = ps->Next;
}
return bRet;
}
BOOL
CUpdateInf::AddEntryToSection(
PSECTION ps,
LPCTSTR szEntry
)
{
static TCHAR *rgKeys[] = { _T("CopyFiles"),
_T("DelFiles"),
_T("AddReg"),
_T("DelReg"),
_T("AddDirId"),
_T("InstallFromSection") };
TCHAR szNewEntry[MAX_PATH],
*pNewEntry;
BOOL bInQuote = FALSE;
TCHAR *szPostKey;
TCHAR *szComment;
// Add entry to section
ps->pseSectionEntries[ps->dwSectionEntries].szLine = new TCHAR [_tcslen(szEntry) + 1];
if ( NULL == ps->pseSectionEntries[ps->dwSectionEntries].szLine )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
_tcscpy( ps->pseSectionEntries[ps->dwSectionEntries].szLine, szEntry );
ps->pseSectionEntries[ps->dwSectionEntries].cRef = 1;
if ( _tcslen(szEntry) <= MAX_PATH )
{
pNewEntry = szNewEntry;
}
else
{
pNewEntry = new TCHAR [_tcslen(szEntry) + 1];
if ( NULL == pNewEntry )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
}
_tcscpy( pNewEntry, szEntry );
// Remove any comments
szComment = pNewEntry;
while ( *szComment )
{
if ( _T('\"') == *szComment ) bInQuote = !bInQuote;
if ( !bInQuote && _T(';') == *szComment ) break;
szComment++;
}
if ( *szComment )
{
while ( szComment >= pNewEntry &&
_istspace( *szComment ) ) { szComment--; }
*(szComment + 1) = _T('\0');
}
// Find the key (if one exists)
szPostKey = _tcschr( pNewEntry, _T('=') );
if ( szPostKey )
{
*szPostKey = _T('\0');
// If we recognize the entry type, add it to list affecting specified section
if( _tcsicmp( ps->szSectionName , _T("DestinationDirs") ) == 0 ) {
// This entry is necessary only as long as it has associations
ps->pseSectionEntries[ps->dwSectionEntries].cRef = 0;
AssociateEntryWithSection( &ps->pseSectionEntries[ps->dwSectionEntries], pNewEntry, FALSE );
} else {
DWORD iKey;
szPostKey++;
for ( iKey = 0; iKey < sizeof(rgKeys) / sizeof(rgKeys[0]); iKey++ )
{
if ( !_tcsicmp( rgKeys[iKey], pNewEntry ) )
{
// The associated sections may appear in a comma-delimited list,
// so make sure to associate all of the entries
BOOL fMultiEntry = (NULL != _tcschr( szPostKey, _T(',') ));
TCHAR *pSection = _tcstok( szPostKey, _T(" ,") );
// This entry is necessary only as long as it has associations
ps->pseSectionEntries[ps->dwSectionEntries].cRef = 0;
do
{
AssociateEntryWithSection( &ps->pseSectionEntries[ps->dwSectionEntries], pSection, fMultiEntry );
} while ( pSection = _tcstok(NULL, _T(" ,")) );
break;
}
}
}
}
// Free up buffer if we were forced to allocate one
if ( pNewEntry != szNewEntry ) delete [] pNewEntry;
ps->dwSectionEntries++;
return TRUE;
}
BOOL
CUpdateInf::AssociateEntryWithSection(
PSECTIONENTRY pse,
LPCTSTR szSectionName,
BOOL fMultiSection
)
{
DWORD dwHash;
PSECTION pSection;
PSECTIONASSOCIATIONLIST pSectionAssoc;
PASSOCIATEDENTRIES pAssociation;
// Find our section to associate in the hash list
dwHash = CalcHashFromSectionName( szSectionName );
pSectionAssoc = m_rgNameHash[dwHash];
while ( pSectionAssoc && _tcsicmp( szSectionName, pSectionAssoc->pSection->szSectionName ) )
{
pSectionAssoc = pSectionAssoc->pNext;
}
// If we couldn't find the section, assume it doesn't exit and mark the entry for delete
if ( !pSectionAssoc )
{
if ( fMultiSection )
{
// Remove the section name from a multi-section
// comma-delimited list
RemoveSectionFromMultiEntry(pse, szSectionName);
}
return TRUE;
}
// Add new entry to section association
pAssociation = new ASSOCIATEDENTRIES;
if ( NULL == pAssociation )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
// Update the ref count on the entry
pse->cRef++;
pAssociation->pse = pse;
pAssociation->pNext = NULL;
pSection = pSectionAssoc->pSection;
if ( pSection->pAssociatedEntries )
{
pAssociation->pNext = pSection->pAssociatedEntries;
pSection->pAssociatedEntries = pAssociation;
}
else
{
pSection->pAssociatedEntries = pAssociation;
}
return TRUE;
}
DWORD
CUpdateInf::CalcHashFromSectionName(
LPCTSTR szSectionName
)
{
TCHAR szSectionNameLC[ MAX_PATH ];
DWORD dwHash = 0L,
dwHashExtra = 0L;
BYTE *pData;
size_t bytesSectionName = sizeof( TCHAR ) * _tcslen( szSectionName );
size_t i;
// Dependent on sizeof(DWORD) = 4 * sizeof(BYTE) so put in a check
// which the compiler should optimize out
if ( sizeof(DWORD) != 4*sizeof(BYTE) ) DebugBreak();
// convert section name to lower-case
for ( i = 0; i < _tcslen( szSectionName ); i++ )
{
szSectionNameLC[i] = (_istupper(szSectionName[i])?_totlower(szSectionName[i]):szSectionName[i]);
}
pData = (PBYTE)szSectionNameLC;
for ( i = 0; i < bytesSectionName / sizeof(DWORD); i++ )
{
DWORD dwTempHash = 0L;
dwTempHash = pData[0] << 24 | pData[1] << 16 | pData[2] << 8 | pData[3];
#ifdef UNICODE
dwHash ^= i%2?dwTempHash >> 8:dwTempHash;
#else
dwHash ^= dwTempHash;
#endif
pData += sizeof(DWORD);
}
// Pick up any remaining bits that don't fit into a DWORD
for ( i = 0; i < bytesSectionName % sizeof(DWORD); i++ )
{
dwHashExtra <<= 8;
dwHashExtra += pData[i];
}
return (dwHash ^ dwHashExtra) % HASH_BUCKETS;
}
BOOL
CUpdateInf::GetSectionListFromInF(
LPTSTR szINF
)
{
BOOL bRet = TRUE;
PSECTION ps = NULL;
DWORD dwSize =0;
LPTSTR lpReturnedString;
DWORD dwResult;
TCHAR *pc;
DWORD dwHash;
BOOL fDuplicate;
PSECTIONASSOCIATIONLIST pAssociationList;
dwSize = GetFileSizeByName( szINF, NULL );
lpReturnedString = new TCHAR [dwSize];
dwResult = GetPrivateProfileString(
NULL, // section name
NULL, // key name
_T("1"), // default string
lpReturnedString, // destination buffer
dwSize, // size of destination buffer
szINF
);
pc = lpReturnedString;
if( dwResult > 0 ) {
// Form the list
while( ( bRet ) && ( _tcslen( pc ) != 0 ) ) {
ps = new SECTION;
if( ps ) {
fDuplicate = FALSE;
memset( ps, 0, sizeof( SECTION ) );
_tcscpy( ps->szSectionName, pc );
ps->cRef = 1;
// Add section to association hash
dwHash = CalcHashFromSectionName( ps->szSectionName );
if ( !m_rgNameHash[dwHash] )
{
m_rgNameHash[dwHash] = new SECTIONASSOCIATIONLIST;
if ( NULL == m_rgNameHash[dwHash] )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
bRet = FALSE;
break;
}
pAssociationList = m_rgNameHash[dwHash];
}
else
{
pAssociationList = m_rgNameHash[dwHash];
// Check for duplicate section name
do
{
if ( !_tcsicmp(pAssociationList->pSection->szSectionName, ps->szSectionName) )
{
fDuplicate = TRUE;
break;
}
}
while ( pAssociationList->pNext &&
NULL != (pAssociationList = pAssociationList->pNext) // should always be true
);
if ( !fDuplicate )
{
pAssociationList->pNext = new SECTIONASSOCIATIONLIST;
if ( NULL == pAssociationList->pNext )
{
m_dwInfGenError = ERROR_NOT_ENOUGH_MEMORY;
bRet = FALSE;
break;
}
pAssociationList = pAssociationList->pNext;
}
}
if ( !fDuplicate )
{
pAssociationList->pSection = ps;
pAssociationList->pNext = NULL;
//
// Add section to section list
//
if( m_sectionList == NULL ) {
m_sectionList = ps;
} else {
ps->Next = m_sectionList;
m_sectionList = ps;
}
}
else
{
// free duplicate section entry
delete ps;
}
} else{
bRet = FALSE;
}
pc += _tcslen( pc )+1 ;
}
} else {
bRet = FALSE;
}
if( lpReturnedString != NULL ) {
delete [] lpReturnedString;
}
TCHAR szDebug[50];
short cFilled = 0;
for ( short i = 0; i < HASH_BUCKETS; i++ ) { if ( m_rgNameHash[i] ) cFilled++; }
_stprintf( szDebug, _T("Buckets used: %u\n"), cFilled );
OutputDebugString( szDebug );
return bRet;
}
DWORD
CUpdateInf::GetFileSizeByName(
IN LPCTSTR pszFileName,
OUT PDWORD pdwFileSizeHigh
)
{
DWORD dwFileSizeLow = 0xFFFFFFFF;
HANDLE hFile;
hFile = CreateFile(
pszFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL
);
if ( hFile != INVALID_HANDLE_VALUE ) {
dwFileSizeLow = GetFileSize( hFile, pdwFileSizeHigh );
CloseHandle( hFile );
}
return dwFileSizeLow;
}