windows-nt/Source/XPSP1/NT/windows/appcompat/shimdbc/registry.cpp
2020-09-26 16:20:57 +08:00

628 lines
18 KiB
C++

////////////////////////////////////////////////////////////////////////////////////
//
// File: registry.cpp
//
// History: 21-Mar-00 markder Created.
// 13-Dec-00 markder Renamed from appshelp.cpp
//
// Desc: This file contains all code needed to produce matching info registry
// files and setup files (INX) for the Windows 2000 (RTM) shim mechanism.
//
////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "registry.h"
////////////////////////////////////////////////////////////////////////////////////
//
// Func: DumpString, DumpDword, DumpBinVersion, InsertString
//
// Desc: Helper functions for CreateMessageBlob.
//
void DumpString( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, CString& csString )
{
DWORD dwLen;
**(DWORD**)ppBlob = dwId;
*ppBlob += sizeof(DWORD);
dwLen = csString.GetLength();
**(DWORD**)ppBlob = ( dwLen + 1) * sizeof(WCHAR);
*ppBlob += sizeof(DWORD);
CopyMemory(*ppBlob, T2W((LPTSTR) (LPCTSTR) csString), (dwLen + 1) * sizeof(WCHAR));
*ppBlob += (dwLen + 1) * sizeof(WCHAR);
*pnTotalBytes += ((dwLen + 1) * sizeof(WCHAR) + 2 * sizeof(DWORD));
}
void DumpDword( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, DWORD dwVal )
{
**(DWORD**)ppBlob = dwId;
*ppBlob += sizeof(DWORD);
**(DWORD**)ppBlob = sizeof(DWORD);
*ppBlob += sizeof(DWORD);
**(DWORD**)ppBlob = dwVal;
*ppBlob += sizeof(DWORD);
*pnTotalBytes += 3 * sizeof(DWORD);
}
void DumpBinVersion(DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, ULONGLONG ullVersion)
{
ULONGLONG ullMask = 0;
ULONGLONG ullVer = 0;
WORD wVerPart = 0;
LONG j;
PBYTE pBlob = *ppBlob;
for( j = 0; j < 4; j++ ) {
wVerPart = (WORD) (ullVersion >> (j*16));
if (wVerPart != 0xFFFF) {
ullVer += ((ULONGLONG)wVerPart) << (j*16);
ullMask += ((ULONGLONG) 0xFFFF) << (j*16);
}
}
//
// id
//
*(DWORD*)pBlob = dwId;
pBlob += sizeof(DWORD);
// size
*(DWORD*)pBlob = 2 * sizeof(ULONGLONG);
pBlob += sizeof(DWORD);
// version
CopyMemory(pBlob, &ullVer, sizeof(ULONGLONG));
pBlob += sizeof(ULONGLONG);
// mask
CopyMemory(pBlob, &ullMask, sizeof(ULONGLONG));
pBlob += sizeof(ULONGLONG);
*pnTotalBytes += (2 * sizeof(ULONGLONG) + 2 * sizeof(DWORD));
*ppBlob = pBlob;
}
void InsertString( CString* pcs, DWORD dwIndex, CString csInsertedString )
{
*pcs = pcs->Left( dwIndex ) + csInsertedString + pcs->Right( pcs->GetLength() - dwIndex );
}
BOOL WriteStringToFile(
HANDLE hFile,
CString& csString)
{
CHAR szBuffer[1024];
DWORD dwConvBufReqSize;
DWORD dwConvBufSize = sizeof(szBuffer);
BOOL b; // this will be set if default char is used, we make no use of this
LPSTR szConvBuf = szBuffer;
BOOL bAllocated = FALSE;
BOOL bSuccess;
DWORD dwBytesWritten;
dwConvBufReqSize = WideCharToMultiByte(CP_ACP, 0, csString, -1, NULL, NULL, 0, &b);
if (dwConvBufReqSize > sizeof(szBuffer)) {
szConvBuf = (LPSTR) new CHAR[dwConvBufReqSize];
dwConvBufSize = dwConvBufReqSize;
bAllocated = TRUE;
}
WideCharToMultiByte(CP_ACP, 0, csString, -1, szConvBuf, dwConvBufSize, 0, &b);
bSuccess = WriteFile( hFile, szConvBuf, dwConvBufReqSize - 1, &dwBytesWritten, NULL);
if (bAllocated) {
delete [] szConvBuf;
}
return bSuccess;
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: FreeRegistryBlob, CreateRegistryBlob
//
// Desc: Creates a binary blob in the format of Windows 2000's
// Message registry keys.
//
void FreeRegistryBlob( PBYTE pBlob )
{
delete pBlob;
}
BOOL CreateRegistryBlob(
SdbExe* pExe,
PBYTE* ppBlob,
DWORD* pdwSize,
DWORD dwMessageID = 0, // these two are optional
DWORD dwBlobType = 6)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
PBYTE pBlob = (PBYTE) new BYTE[4096];
PBYTE pStartOfBlob = pBlob;
DWORD dwBufSize = 4096;
DWORD dwReqBufSize = 0;
LONG nTotalBytes = 0;
LONG i, j;
LONG nBytes;
SdbMatchingFile* pMFile;
FILETIME FileTime;
CString* pcsFilename;
ULONGLONG ullMask = 0;
WORD wVerPart = 0;
ULONGLONG ullVer = 0;
*pdwSize = 0;
// Prolog
*((DWORD*)pBlob + 0) = 3 * sizeof(DWORD);
// message id
*((DWORD*)pBlob + 1) = dwMessageID;
// type is not shim anymore
*((DWORD*)pBlob + 2) = dwBlobType; // shim type
pBlob += 3 * sizeof(DWORD);
nTotalBytes += 3 * sizeof(DWORD);
for( i = 0; i < pExe->m_rgMatchingFiles.GetSize(); i++ )
{
pMFile = (SdbMatchingFile *) pExe->m_rgMatchingFiles[i];
if( pMFile->m_csName == _T("*") ) {
pcsFilename = &(pExe->m_csName);
} else {
pcsFilename = &(pMFile->m_csName);
}
DumpString( VTID_REQFILE, &pBlob, &nTotalBytes, *pcsFilename );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_SIZE )
DumpDword( VTID_FILESIZE, &pBlob, &nTotalBytes, pMFile->m_dwSize );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_CHECKSUM )
DumpDword( VTID_CHECKSUM, &pBlob, &nTotalBytes, pMFile->m_dwChecksum );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_COMPANY_NAME )
DumpString( VTID_COMPANYNAME, &pBlob, &nTotalBytes, pMFile->m_csCompanyName );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_NAME )
DumpString( VTID_PRODUCTNAME, &pBlob, &nTotalBytes, pMFile->m_csProductName );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_VERSION )
DumpString( VTID_PRODUCTVERSION, &pBlob, &nTotalBytes, pMFile->m_csProductVersion );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_DESCRIPTION )
DumpString( VTID_FILEDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_csFileDescription );
if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_FILE_VERSION )
DumpBinVersion(VTID_BINFILEVER, &pBlob, &nTotalBytes, pMFile->m_ullBinFileVersion);
if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_PRODUCT_VERSION )
DumpBinVersion(VTID_BINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullBinProductVersion);
if (pMFile->m_dwMask & SDB_MATCHINGINFO_MODULE_TYPE)
DumpDword( VTID_EXETYPE, &pBlob, &nTotalBytes, pMFile->m_dwModuleType );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATEHI)
DumpDword( VTID_FILEDATEHI, &pBlob, &nTotalBytes, pMFile->m_dwFileDateMS );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATELO)
DumpDword( VTID_FILEDATELO, &pBlob, &nTotalBytes, pMFile->m_dwFileDateLS );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEOS)
DumpDword( VTID_FILEVEROS, &pBlob, &nTotalBytes, pMFile->m_dwFileOS );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILETYPE)
DumpDword( VTID_FILEVERTYPE, &pBlob, &nTotalBytes, pMFile->m_dwFileType );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_PE_CHECKSUM)
DumpDword( VTID_PECHECKSUM, &pBlob, &nTotalBytes, (DWORD)pMFile->m_ulPECheckSum );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_VERSION)
DumpString( VTID_FILEVERSION, &pBlob, &nTotalBytes, pMFile->m_csFileVersion );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_ORIGINAL_FILENAME)
DumpString( VTID_ORIGINALFILENAME, &pBlob, &nTotalBytes, pMFile->m_csOriginalFileName );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_INTERNAL_NAME)
DumpString( VTID_INTERNALNAME, &pBlob, &nTotalBytes, pMFile->m_csInternalName );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_LEGAL_COPYRIGHT)
DumpString( VTID_LEGALCOPYRIGHT, &pBlob, &nTotalBytes, pMFile->m_csLegalCopyright );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_16BIT_DESCRIPTION)
DumpString( VTID_16BITDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_cs16BitDescription );
if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_BIN_PRODUCT_VERSION)
DumpBinVersion(VTID_UPTOBINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullUpToBinProductVersion);
if (pMFile->m_dwMask & SDB_MATCHINGINFO_LINK_DATE) {
SDBERROR(_T("LINK_DATE not allowed for Win2k registry matching."));
goto eh;
}
if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_LINK_DATE) {
SDBERROR(_T("UPTO_LINK_DATE not allowed for Win2k registry matching."));
goto eh;
}
}
// Terminator
*((DWORD*)pBlob) = 0;
pBlob += sizeof(DWORD);
nTotalBytes += sizeof(DWORD);
bSuccess = TRUE;
eh:
if( bSuccess ) {
*pdwSize = nTotalBytes;
*ppBlob = pStartOfBlob;
} else if( pStartOfBlob ) {
FreeRegistryBlob( pStartOfBlob );
*pdwSize = 0;
*ppBlob = NULL;
}
return bSuccess;
}
BOOL RegistryBlobToString(PBYTE pBlob, DWORD dwBlobSize, CString& csBlob)
{
DWORD i;
CString csTemp;
csBlob = "";
for (i = 0; i < dwBlobSize; i++, ++pBlob) {
csTemp.Format( _T("%02X"), (DWORD)*pBlob );
if (i == dwBlobSize - 1) { // this is the last char
csTemp += _T("\r\n");
}
else {
if ((i+1) % 27 == 0) { // time to do end of the line ?
csTemp += _T(",\\\r\n");
}
else {
csTemp += _T(","); // just add comma
}
}
csBlob += csTemp;
}
return(TRUE);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: CreateMessageRegEntry, WriteMessageRegistryFiles
//
// Desc: These functions create Win2k-style registry entries for the old
// Message mechanism, which exists in SHELL32!ShellExecute.
//
BOOL CreateMessageRegEntry(
SdbExe* pExe,
DWORD dwExeCount,
CString& csReg,
CString& csInx)
{
PBYTE pBlob = NULL;
BOOL bSuccess = FALSE;
DWORD dwBlobSize = 0;
CString csRegEntry, csInxEntry;
CString csApp;
CString csBlob;
CString csTemp;
if (!CreateRegistryBlob(pExe,
&pBlob,
&dwBlobSize,
(DWORD)_ttol(pExe->m_AppHelpRef.m_pAppHelp->m_csName),
pExe->m_AppHelpRef.m_pAppHelp->m_Type)) {
SDBERROR(_T("Error in CreateRegistryBlob()"));
goto eh;
}
csApp = pExe->m_pApp->m_csName;
csApp.Remove(_T(' '));
csTemp.Format(_T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%05X %s\"=hex:"),
pExe->m_csName, dwExeCount, csApp.Left(25));
csRegEntry = csTemp;
csTemp.Format(_T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%05X %s\",0x00030003,\\\r\n"),
pExe->m_csName, dwExeCount, csApp.Left(25) );
csInxEntry = csTemp;
//
// now grab the blob
//
if (!RegistryBlobToString(pBlob, dwBlobSize, csBlob)) {
SDBERROR(_T("Error in RegistryBlobToString()"));
goto eh;
}
csRegEntry += csBlob;
csInxEntry += csBlob;
csReg = csRegEntry;
csInx = csInxEntry;
bSuccess = TRUE;
eh:
if (NULL != pBlob) {
FreeRegistryBlob( pBlob );
}
return(bSuccess);
}
////////////////////////////////////////////////////////////////////////////////////
//
// Func: CreateRegistryBlob, WriteRegistryFiles
//
// Desc: These functions create a Win2k-style registry entries for both
// Message as well as a stub entry for shimming that provides no
// additional matching info past EXE name. This allows the 'new'
// Win2k version of the shim engine to 'bootstrap' itself into memory
// via the original mechanism and then perform more detailed matching
// in its own way.
//
BOOL CreateWin2kExeStubRegistryBlob(
SdbExe* pExe,
PBYTE* ppBlob,
DWORD* pdwSize,
DWORD dwMessageID = 0, // these two are optional
DWORD dwBlobType = 6)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
DWORD dwBufSize = sizeof(DWORD) * 4;
LONG nTotalBytes = 0;
PBYTE pStartOfBlob;
PBYTE pBlob = (PBYTE) new BYTE[dwBufSize];
pStartOfBlob = pBlob;
*pdwSize = 0;
if (NULL != pBlob) {
// Prolog
*((DWORD*)pBlob + 0) = 3 * sizeof(DWORD); // 0x0C 00 00 00
// message id
*((DWORD*)pBlob + 1) = dwMessageID; // 0x00 00 00 00
// type is shim
*((DWORD*)pBlob + 2) = dwBlobType; // 0x06 00 00 00
pBlob += 3 * sizeof(DWORD);
nTotalBytes += 3 * sizeof(DWORD);
// Terminator
*((DWORD*)pBlob) = 0;
pBlob += sizeof(DWORD);
nTotalBytes += sizeof(DWORD);
*pdwSize = (DWORD)nTotalBytes;
*ppBlob = pStartOfBlob;
bSuccess = TRUE;
}
return bSuccess;
}
BOOL WriteRegistryFiles(
SdbDatabase* pDatabase,
CString csRegFile,
CString csInxFile,
BOOL bAddExeStubs)
{
CString csRegEntry, csInxEntry, csTemp, csCmdLineREG, csCmdLineINX,
csTemp1, csApp, csExeName;
SdbExe* pExe;
SdbApp* pApp;
long i, j, l, m;
DWORD k, dwBlobSize, dwBytesWritten, dwExeCount = 0;
PBYTE pBlob;
BOOL b, bSuccess = FALSE;
CMapStringToPtr mapNames;
SdbApp* pAppValue;
HANDLE hRegFile = NULL;
HANDLE hInxFile = NULL;
hRegFile = CreateFile( csRegFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
hInxFile = CreateFile( csInxFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( hRegFile == INVALID_HANDLE_VALUE ||
hInxFile == INVALID_HANDLE_VALUE ) {
SDBERROR_FORMAT((_T("Error creating registry files:\n%s\n%s\n"), csRegFile, csInxFile));
goto eh;
}
if( ! WriteFile( hRegFile, "REGEDIT4\r\n\r\n", strlen("REGEDIT4\r\n\r\n"), &dwBytesWritten, NULL ) ) {
SDBERROR(_T("Error writing header to .reg file.\n"));
goto eh;
}
//
// loop through all the apps, make apphelp entries
//
for (i = 0; i < pDatabase->m_rgExes.GetSize(); i++) {
pExe = (SdbExe *) pDatabase->m_rgExes[i];
if (pExe->m_AppHelpRef.m_pAppHelp == NULL) { // not an apphelp entry
continue;
}
if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) {
continue;
}
b = CreateMessageRegEntry(pExe, dwExeCount, csRegEntry, csInxEntry);
if (!b) {
SDBERROR(_T("Error creating reg entry.\n"));
goto eh;
}
if (!WriteStringToFile(hRegFile, csRegEntry)) {
SDBERROR(_T("Error writing reg entry.\n"));
goto eh;
}
if (!WriteStringToFile(hInxFile, csInxEntry)) {
SDBERROR(_T("Error writing inx entry.\n"));
goto eh;
}
++dwExeCount;
}
//
// Add the Win2k EXE stubs to bootstrap the new shim mechanism
//
if (bAddExeStubs) {
for( i = 0; i < pDatabase->m_rgApps.GetSize(); i++ )
{
pApp = (SdbApp *) pDatabase->m_rgApps[i];
csApp = pApp->m_csName;
csApp.Remove(_T(' '));
for( j = 0; j < pApp->m_rgExes.GetSize(); j++ )
{
pExe = (SdbExe *) pApp->m_rgExes[j];
//
// check whether this entry is apphelp-only
// if so, skip to the next exe
//
if (pExe->m_AppHelpRef.m_pAppHelp) {
if (pExe->m_AppHelpRef.m_bApphelpOnly) {
continue;
}
}
if (pExe->m_bWildcardInName) {
continue;
}
if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) {
continue;
}
csExeName = pExe->m_csName;
csExeName.MakeUpper();
// now we have to create an application entry -- if we have not hit this
// exe name before
if (mapNames.Lookup(csExeName, (VOID*&)pAppValue)) {
continue;
}
csRegEntry.Empty();
csInxEntry.Empty();
if (!CreateWin2kExeStubRegistryBlob(pExe, &pBlob, &dwBlobSize)) {
SDBERROR(_T("Error creating EXE stub.\n"));
goto eh;
}
//
// To reduce the amount of space that we take, we substitute
// app name for something short
//
csApp = _T("x");
csTemp.Format( _T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%s\"=hex:"),
pExe->m_csName, csApp.Left(25) );
csRegEntry += csTemp;
csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%s\",0x00030003,\\\r\n"),
pExe->m_csName, csApp.Left(25) );
csInxEntry += csTemp;
RegistryBlobToString(pBlob, dwBlobSize, csTemp);
csRegEntry += csTemp;
csInxEntry += csTemp;
csCmdLineREG.Empty();
csCmdLineINX.Empty();
csTemp.Format( _T("\"DllPatch-%s\"=\"%s\"\r\n"),
csApp.Left(25), csCmdLineREG );
csRegEntry += csTemp;
csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"DllPatch-%s\",0x00000002,\"%s\"\r\n"),
pExe->m_csName, csApp.Left(25), csCmdLineINX );
csInxEntry += csTemp;
csRegEntry += _T("\r\n");
csInxEntry += _T("\r\n");
if (!WriteStringToFile(hRegFile, csRegEntry)) {
SDBERROR(_T("Error writing reg line.\n"));
goto eh;
}
if (!WriteStringToFile(hInxFile, csInxEntry)) {
SDBERROR(_T("Error writing inx line.\n"));
goto eh;
}
++dwExeCount;
// now update the map
mapNames.SetAt(csExeName, (PVOID)pExe);
FreeRegistryBlob( pBlob );
}
}
}
bSuccess = TRUE;
eh:
if( hRegFile )
CloseHandle( hRegFile );
if( hInxFile )
CloseHandle( hInxFile );
return bSuccess;
}