|
|
// 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; }
|