You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
589 lines
15 KiB
589 lines
15 KiB
/*** reginst.c - RegInstall API
|
|
*
|
|
* This file contains the RegInstall API and its implementation.
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation
|
|
* Author: Matt Squires (MattSq)
|
|
* Created 08/12/96
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <ole2.h>
|
|
#include <advpub.h>
|
|
#include <setupapi.h>
|
|
#include "globals.h"
|
|
#include "advpack.h"
|
|
#include "regstr.h"
|
|
|
|
// FIXFIX - Sundown - let's use public de
|
|
// #define IS_RESOURCE(x) ((((LPTSTR)(x)) <= MAKEINTRESOURCE(-1)) && (((LPTSTR)(x)) != NULL))
|
|
#define IS_RESOURCE(x) ( (((LPTSTR)(x)) != NULL) && IS_INTRESOURCE(x) )
|
|
|
|
#define FILESIZE_63K 64449
|
|
|
|
BOOL GetProgramFilesDir( LPSTR pszPrgfDir, int iSize )
|
|
{
|
|
*pszPrgfDir = 0;
|
|
|
|
if ( ctx.wOSVer >= _OSVER_WINNT50 )
|
|
{
|
|
if ( GetEnvironmentVariable( TEXT("ProgramFiles"), pszPrgfDir, iSize ) )
|
|
return TRUE;
|
|
}
|
|
|
|
if ( GetValueFromRegistry( pszPrgfDir, iSize, "HKLM", REGSTR_PATH_SETUP, REGVAL_PROGRAMFILES ) )
|
|
{
|
|
if ( ctx.wOSVer >= _OSVER_WINNT40 )
|
|
{
|
|
char szSysDrv[5] = { 0 };
|
|
|
|
// combine reg value and systemDrive to get the acurate ProgramFiles dir
|
|
if ( GetEnvironmentVariable( TEXT("SystemDrive"), szSysDrv, ARRAYSIZE(szSysDrv) ) &&
|
|
szSysDrv[0] )
|
|
*pszPrgfDir = szSysDrv[0];
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***LP CreateInfFile - Create an INF file from an hmodule
|
|
*
|
|
* ENTRY
|
|
* hm - hmodule that contains the REGINST resource
|
|
* pszInfFileName -> the location to get the INF filename
|
|
*
|
|
* EXIT
|
|
* Standard API return
|
|
*/
|
|
HRESULT CreateInfFile(HMODULE hm, LPTSTR pszInfFileName, DWORD *pdwFileSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szInfFilePath[MAX_PATH] = { 0 };
|
|
LPVOID pvInfData;
|
|
HRSRC hrsrcInfData;
|
|
DWORD cbInfData, cbWritten;
|
|
HANDLE hfileInf = INVALID_HANDLE_VALUE;
|
|
|
|
if ( pdwFileSize )
|
|
*pdwFileSize = 0;
|
|
|
|
if (GetTempPath(ARRAYSIZE(szInfFilePath), szInfFilePath) > ARRAYSIZE(szInfFilePath))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !IsGoodDir( szInfFilePath ) )
|
|
{
|
|
GetWindowsDirectory( szInfFilePath, sizeof(szInfFilePath) );
|
|
}
|
|
|
|
if (GetTempFileName(szInfFilePath, TEXT("RGI"), 0, pszInfFileName) == 0)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
hrsrcInfData = FindResource(hm, TEXT("REGINST"), TEXT("REGINST"));
|
|
if (hrsrcInfData == NULL)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
cbInfData = SizeofResource(hm, hrsrcInfData);
|
|
|
|
pvInfData = LockResource(LoadResource(hm, hrsrcInfData));
|
|
if (pvInfData == NULL)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
WritePrivateProfileString( NULL, NULL, NULL, pszInfFileName );
|
|
|
|
hfileInf = CreateFile(pszInfFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hfileInf == INVALID_HANDLE_VALUE)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ((WriteFile(hfileInf, pvInfData, cbInfData, &cbWritten, NULL) == FALSE) ||
|
|
(cbWritten != cbInfData))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( pdwFileSize )
|
|
*pdwFileSize = cbWritten;
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
if (hfileInf != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hfileInf);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#if 0
|
|
|
|
LPTSTR CheckPrefix(LPTSTR lpszStr, LPCTSTR lpszSub )
|
|
{
|
|
int ilen;
|
|
TCHAR chTmp;
|
|
LPTSTR lpTmp = NULL;
|
|
|
|
ilen = lstrlen( lpszSub );
|
|
lpTmp = lpszStr;
|
|
while ( ilen && *lpTmp )
|
|
{
|
|
lpTmp = CharNext( lpTmp );
|
|
ilen--;
|
|
}
|
|
|
|
chTmp = *lpTmp;
|
|
*lpTmp = '\0';
|
|
if ( lstrcmpi( lpszSub, lpszStr ) )
|
|
{
|
|
*lpTmp = chTmp;
|
|
lpTmp = NULL;
|
|
}
|
|
else
|
|
*lpTmp = chTmp;
|
|
return lpTmp;
|
|
}
|
|
#endif
|
|
|
|
BOOL ReplaceSubString( LPSTR pszOutLine, LPSTR pszOldLine, LPCSTR pszSubStr, LPCSTR pszSubReplacement )
|
|
{
|
|
LPSTR lpszStart = NULL;
|
|
LPSTR lpszNewLine;
|
|
LPSTR lpszCur;
|
|
BOOL bFound = FALSE;
|
|
int ilen;
|
|
|
|
lpszCur = pszOldLine;
|
|
lpszNewLine = pszOutLine;
|
|
while ( lpszStart = ANSIStrStrI( lpszCur, pszSubStr ) )
|
|
{
|
|
// this module path has the systemroot
|
|
ilen = (int)(lpszStart - lpszCur);
|
|
if ( ilen )
|
|
{
|
|
lstrcpyn( lpszNewLine, lpszCur, ilen + 1 );
|
|
lpszNewLine += ilen;
|
|
}
|
|
lstrcpy( lpszNewLine, pszSubReplacement );
|
|
|
|
lpszCur = lpszStart + lstrlen(pszSubStr);
|
|
lpszNewLine += lstrlen(pszSubReplacement);
|
|
bFound = TRUE;
|
|
}
|
|
|
|
lstrcpy( lpszNewLine, lpszCur );
|
|
|
|
return bFound;
|
|
}
|
|
|
|
//==========================================================================================
|
|
//
|
|
//==========================================================================================
|
|
|
|
BOOL AddEnvInPath( PSTR pszOldPath, PSTR pszNew )
|
|
{
|
|
CHAR szBuf[MAX_PATH];
|
|
CHAR szBuf2[MAX_PATH];
|
|
CHAR szEnvVar[100];
|
|
CHAR szReplaceStr[100];
|
|
CHAR szSysDrv[5];
|
|
BOOL bFound = FALSE;
|
|
BOOL bRet;
|
|
LPSTR pszFinalStr;
|
|
|
|
pszFinalStr = pszOldPath;
|
|
|
|
// replace c:\winnt Windows folder
|
|
if ( GetEnvironmentVariable( "SystemRoot", szEnvVar, ARRAYSIZE(szEnvVar) ) )
|
|
{
|
|
if ( ReplaceSubString( szBuf, pszFinalStr, szEnvVar, "%SystemRoot%" ) )
|
|
{
|
|
bFound = TRUE;
|
|
pszFinalStr = szBuf;
|
|
}
|
|
}
|
|
|
|
if ( GetProgramFilesDir( szEnvVar, sizeof(szEnvVar) ) &&
|
|
GetEnvironmentVariable( "SystemDrive", szSysDrv, ARRAYSIZE(szSysDrv) ) )
|
|
{
|
|
// Get the replacement string first, so c:\program files replacement is
|
|
// %SystemDrive%\program files or %ProgramFiles% if >= WINNT50
|
|
// Replace the c:\Program Files folder
|
|
//
|
|
if ( ctx.wOSVer >= _OSVER_WINNT50 )
|
|
{
|
|
if ( ReplaceSubString( szBuf2, pszFinalStr, szEnvVar, "%ProgramFiles%" ) )
|
|
{
|
|
bFound = TRUE;
|
|
lstrcpy( szBuf, szBuf2 );
|
|
pszFinalStr = szBuf;
|
|
}
|
|
}
|
|
|
|
// Replace the c: System Drive letter
|
|
if ( ReplaceSubString( szBuf2, pszFinalStr, szSysDrv, "%SystemDrive%" ) )
|
|
{
|
|
lstrcpy( szBuf, szBuf2 );
|
|
pszFinalStr = szBuf;
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
// this way, if caller pass the same location for both params, still OK.
|
|
if ( bFound || ( pszNew != pszOldPath ) )
|
|
lstrcpy( pszNew, pszFinalStr );
|
|
return bFound;
|
|
}
|
|
|
|
//==========================================================================================
|
|
//
|
|
//==========================================================================================
|
|
|
|
BOOL MySmartWrite( LPCSTR pcszSection, LPCSTR pcszKey, LPCSTR pcszValue, LPCSTR pcszFilename, DWORD dwFileSize )
|
|
{
|
|
DWORD cbData, cbWritten = 0;
|
|
BOOL bRet = FALSE;
|
|
|
|
if ( dwFileSize <= FILESIZE_63K )
|
|
{
|
|
bRet = WritePrivateProfileString( pcszSection, pcszKey, pcszValue, pcszFilename );
|
|
}
|
|
else
|
|
{
|
|
HANDLE hfileInf = INVALID_HANDLE_VALUE;
|
|
LPSTR pszBuf = NULL;
|
|
const char c_szLineTmplate[] = "%s=\"%s\"\r\n";
|
|
const char c_szLineTmplate2[] = "%s=%s\r\n";
|
|
|
|
pszBuf = LocalAlloc( LPTR, 1024 );
|
|
if ( !pszBuf )
|
|
return bRet;
|
|
|
|
hfileInf = CreateFile( pcszFilename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hfileInf == INVALID_HANDLE_VALUE)
|
|
{
|
|
if ( pszBuf )
|
|
LocalFree( pszBuf );
|
|
return bRet;
|
|
}
|
|
|
|
if ( SetFilePointer( hfileInf, 0 , NULL, FILE_END ) != 0xFFFFFFFF )
|
|
{
|
|
if ( *pcszValue != '"' )
|
|
wsprintf( pszBuf, c_szLineTmplate, pcszKey, pcszValue );
|
|
else
|
|
wsprintf( pszBuf, c_szLineTmplate2, pcszKey, pcszValue );
|
|
cbData = lstrlen(pszBuf); // key="value"\r\n
|
|
WriteFile(hfileInf, pszBuf, cbData, &cbWritten, NULL);
|
|
bRet = (cbData == cbWritten);
|
|
}
|
|
CloseHandle(hfileInf);
|
|
|
|
if ( pszBuf )
|
|
LocalFree( pszBuf );
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/***LP WritePredefinedStrings - Write all predefined strings to an INF
|
|
*
|
|
* ENTRY
|
|
* pszInfFileName -> name of INF file
|
|
* hm - hmodule of caller
|
|
*
|
|
* EXIT
|
|
* Standard API return
|
|
*/
|
|
HRESULT WritePredefinedStrings( LPCTSTR pszInfFileName, HMODULE hm, DWORD dwFileSize )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szModulePath[MAX_PATH + 2];
|
|
BOOL bSysModPath = FALSE;
|
|
|
|
szModulePath[0] = '"';
|
|
if (GetModuleFileName(hm, &szModulePath[1], ARRAYSIZE(szModulePath) - 2) == 0)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
lstrcat( szModulePath, "\"" );
|
|
|
|
MySmartWrite(TEXT("Strings"), TEXT("_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
|
|
|
|
if ( CheckOSVersion() )
|
|
{
|
|
|
|
// BOOL bFound = FALSE;
|
|
|
|
if ( ctx.wOSVer >= _OSVER_WINNT40 )
|
|
{
|
|
if ( AddEnvInPath( szModulePath, szModulePath) )
|
|
{
|
|
MySmartWrite(TEXT("Strings"), TEXT("_SYS_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
|
|
bSysModPath = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bSysModPath )
|
|
MySmartWrite(TEXT("Strings"), TEXT("_SYS_MOD_PATH"), szModulePath, pszInfFileName, dwFileSize);
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***LP WriteCallerStrings - Write caller supplied strings to an INF
|
|
*
|
|
* ENTRY
|
|
* pszInfFileName -> name of INF file
|
|
* hm - hmodule of caller
|
|
* pstTable - caller supplied string table
|
|
*
|
|
* EXIT
|
|
* Standard API return
|
|
*/
|
|
HRESULT WriteCallerStrings(LPCTSTR pszInfFileName, HMODULE hm, LPCSTRTABLE pstTable, DWORD dwFileSize)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szValue[MAX_PATH];
|
|
DWORD i;
|
|
LPSTRENTRY pse;
|
|
TCHAR szQuoteValue[MAX_PATH];
|
|
LPTSTR lpValue;
|
|
|
|
for (i=0, pse=pstTable->pse; i<pstTable->cEntries; i++, pse++)
|
|
{
|
|
if (IsBadReadPtr(pse, SIZEOF(*pse)))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (IS_RESOURCE(pse->pszValue))
|
|
{
|
|
if (LoadString(hm, (UINT)(ULONG_PTR)(pse->pszValue), szValue, ARRAYSIZE(szValue)) == 0)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
lpValue = szValue;
|
|
}
|
|
else
|
|
lpValue = pse->pszValue;
|
|
|
|
if ( *lpValue != '"' )
|
|
{
|
|
// if no quote, insert it
|
|
szQuoteValue[0] = '"';
|
|
lstrcpy( &szQuoteValue[1], lpValue );
|
|
lstrcat( szQuoteValue, "\"" );
|
|
lpValue = szQuoteValue;
|
|
}
|
|
|
|
MySmartWrite(TEXT("Strings"), pse->pszName, lpValue, pszInfFileName, dwFileSize);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL GetRollbackSection( LPCSTR pcszModule, LPSTR pszSec, DWORD dwSize )
|
|
{
|
|
HKEY hKey;
|
|
TCHAR szBuf[MAX_PATH];
|
|
DWORD dwTmp;
|
|
BOOL fRet = FALSE;
|
|
|
|
lstrcpy( szBuf, REGKEY_SAVERESTORE );
|
|
AddPath( szBuf, pcszModule );
|
|
if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, szBuf, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ,
|
|
NULL, &hKey, &dwTmp ) == ERROR_SUCCESS )
|
|
{
|
|
dwTmp = dwSize;
|
|
if ( (RegQueryValueEx( hKey, REGVAL_BKINSTSEC, NULL, NULL, pszSec, &dwTmp ) == ERROR_SUCCESS) && *pszSec )
|
|
fRet = TRUE;
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***LP ExecuteInfSection - Ask RunSetupCommand to execute an INF section
|
|
*
|
|
* ENTRY
|
|
* pszInfFileName -> name of INF file
|
|
* pszInfSection -> section to execute
|
|
*
|
|
* EXIT
|
|
* Standard API return
|
|
*/
|
|
HRESULT ExecuteInfSection(LPCTSTR pszInfFileName, LPCTSTR pszInfSection)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szTempPath[MAX_PATH];
|
|
TCHAR szBuf[MAX_PATH];
|
|
BOOL fSavedContext = FALSE;
|
|
DWORD dwFlags = 0;
|
|
|
|
|
|
if (!SaveGlobalContext())
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
fSavedContext = TRUE;
|
|
|
|
// get the source dir
|
|
if (GetTempPath(ARRAYSIZE(szTempPath), szTempPath) > ARRAYSIZE(szTempPath))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// we check if this caller needs to do save/rollback, or just simple GenInstall
|
|
if (SUCCEEDED(GetTranslatedString(pszInfFileName, pszInfSection, ADVINF_MODNAME, szBuf, ARRAYSIZE(szBuf), NULL)))
|
|
{
|
|
dwFlags = GetTranslatedInt(pszInfFileName, pszInfSection, ADVINF_FLAGS, 0);
|
|
}
|
|
|
|
if ( (dwFlags & ALINF_BKINSTALL) || (dwFlags & ALINF_ROLLBKDOALL) || (dwFlags & ALINF_ROLLBACK) )
|
|
{
|
|
CABINFO cabInfo;
|
|
|
|
ZeroMemory( &cabInfo, sizeof(CABINFO) );
|
|
cabInfo.pszInf = (LPSTR)pszInfFileName;
|
|
lstrcpy( cabInfo.szSrcPath, szTempPath );
|
|
cabInfo.dwFlags = dwFlags;
|
|
|
|
if ( dwFlags & ALINF_BKINSTALL )
|
|
{
|
|
cabInfo.pszSection = (LPSTR)pszInfSection;
|
|
}
|
|
else
|
|
{
|
|
if ( !GetRollbackSection( szBuf, szTempPath, ARRAYSIZE(szTempPath) ) )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
cabInfo.pszSection = szTempPath;
|
|
}
|
|
|
|
hr = ExecuteCab( NULL, &cabInfo, NULL );
|
|
}
|
|
else
|
|
{
|
|
hr = RunSetupCommand(INVALID_HANDLE_VALUE, pszInfFileName, pszInfSection,
|
|
szTempPath, NULL, NULL, RSC_FLAG_INF | RSC_FLAG_QUIET,
|
|
NULL);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (fSavedContext)
|
|
{
|
|
RestoreGlobalContext();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***EP RegInstall - Install a registry INF
|
|
*
|
|
* @doc API REGINSTALL
|
|
*
|
|
* @api STDAPI | RegInstall | Install a registry INF
|
|
*
|
|
* @parm HMODULE | hm | The hmodule of the caller. The INF is extracted
|
|
* from the module's resources (type="REGINST", name="REGINST").
|
|
*
|
|
* @parm LPCTSTR | pszSection | The section of the INF to execute.
|
|
*
|
|
* @parm LPCSTRTABLE | pstTable | A table of string mappings.
|
|
*
|
|
* @rdesc S_OK - registry INF successfully installed.
|
|
*
|
|
* @rdesc E_FAIL - error installing INF.
|
|
*/
|
|
STDAPI RegInstall(HMODULE hm, LPCTSTR pszSection, LPCSTRTABLE pstTable)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
TCHAR szInfFileName[MAX_PATH];
|
|
DWORD dwFileSize = 0;
|
|
|
|
AdvWriteToLog("RegInstall: Section=%1\r\n", pszSection);
|
|
//
|
|
// Create the INF file.
|
|
//
|
|
szInfFileName[0] = TEXT('\0');
|
|
hr = CreateInfFile(hm, szInfFileName, &dwFileSize);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Write out our predefined strings.
|
|
//
|
|
hr = WritePredefinedStrings(szInfFileName, hm, dwFileSize);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Write out the user supplied strings.
|
|
//
|
|
if (pstTable)
|
|
{
|
|
hr = WriteCallerStrings(szInfFileName, hm, pstTable, dwFileSize);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
WritePrivateProfileString( NULL, NULL, NULL, szInfFileName );
|
|
|
|
//
|
|
// Execute the INF engine on the INF.
|
|
//
|
|
hr = ExecuteInfSection(szInfFileName, pszSection);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Delete the INF file.
|
|
//
|
|
if (szInfFileName[0])
|
|
{
|
|
DeleteFile(szInfFileName);
|
|
}
|
|
AdvWriteToLog("RegInstall: Section=%1 End hr=%2!x!\r\n", pszSection, hr);
|
|
return hr;
|
|
}
|