1880 lines
51 KiB
C++
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;
|
|
}
|