diff options
Diffstat (limited to 'setup_native/source/win32/customactions/patch/swappatchfiles.cxx')
-rwxr-xr-x | setup_native/source/win32/customactions/patch/swappatchfiles.cxx | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/setup_native/source/win32/customactions/patch/swappatchfiles.cxx b/setup_native/source/win32/customactions/patch/swappatchfiles.cxx new file mode 100755 index 000000000000..d6f0933077fc --- /dev/null +++ b/setup_native/source/win32/customactions/patch/swappatchfiles.cxx @@ -0,0 +1,908 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _WIN32_WINDOWS 0x0410 + +#ifdef _MSC_VER +#pragma warning(push, 1) /* disable warnings within system headers */ +#endif +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <msiquery.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include <malloc.h> +#include <assert.h> + +#ifdef UNICODE +#define _UNICODE +#define _tstring wstring +#else +#define _tstring string +#endif +#include <tchar.h> +#include <string> +#include <queue> +#include <stdio.h> + +#include <systools/win32/uwinapi.h> +#include <../tools/seterror.hxx> + +#define WININIT_FILENAME "wininit.ini" +#define RENAME_SECTION "rename" + +#ifdef DEBUG +inline void OutputDebugStringFormat( LPCTSTR pFormat, ... ) +{ + _TCHAR buffer[1024]; + va_list args; + + va_start( args, pFormat ); + _vsntprintf( buffer, elementsof(buffer), pFormat, args ); + OutputDebugString( buffer ); +} +#else +static inline void OutputDebugStringFormat( LPCTSTR, ... ) +{ +} +#endif + +static std::_tstring GetMsiProperty( MSIHANDLE handle, const std::_tstring& sProperty ) +{ + std::_tstring result; + TCHAR szDummy[1] = TEXT(""); + DWORD nChars = 0; + + if ( MsiGetProperty( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA ) + { + DWORD nBytes = ++nChars * sizeof(TCHAR); + LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes)); + ZeroMemory( buffer, nBytes ); + MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars); + result = buffer; + } + + return result; +} + +// The provided GUID must be without surounding '{}' +static std::_tstring GetGuidPart(const std::_tstring& guid, int index) +{ + assert((guid.length() == 36) && "No GUID or wrong format!"); + assert(((index > -1) && (index < 5)) && "Out of range!"); + + if (index == 0) return std::_tstring(guid.c_str(), 8); + if (index == 1) return std::_tstring(guid.c_str() + 9, 4); + if (index == 2) return std::_tstring(guid.c_str() + 14, 4); + if (index == 3) return std::_tstring(guid.c_str() + 19, 4); + if (index == 4) return std::_tstring(guid.c_str() + 24, 12); + + return std::_tstring(); +} + +static void Swap(char* p1, char* p2) +{ + char tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +static std::_tstring Invert(const std::_tstring& str) +{ + char* buff = reinterpret_cast<char*>(_alloca(str.length())); + strncpy(buff, str.c_str(), str.length()); + + char* front = buff; + char* back = buff + str.length() - 1; + + while (front < back) + Swap(front++, back--); + + return std::_tstring(buff, str.length()); +} + +// Convert the upgrade code (which is a GUID) according +// to the way the windows installer does when writing it +// to the registry +// The first 8 bytes will be inverted, from the the last +// 8 bytes always the nibbles will be inverted for further +// details look in the MSDN under compressed registry keys +static std::_tstring ConvertGuid(const std::_tstring& guid) +{ + std::_tstring convertedGuid; + + std::_tstring part = GetGuidPart(guid, 0); + convertedGuid = Invert(part); + + part = GetGuidPart(guid, 1); + convertedGuid += Invert(part); + + part = GetGuidPart(guid, 2); + convertedGuid += Invert(part); + + part = GetGuidPart(guid, 3); + convertedGuid += Invert(std::_tstring(part.c_str(), 2)); + convertedGuid += Invert(std::_tstring(part.c_str() + 2, 2)); + + part = GetGuidPart(guid, 4); + int pos = 0; + for (int i = 0; i < 6; i++) + { + convertedGuid += Invert(std::_tstring(part.c_str() + pos, 2)); + pos += 2; + } + return convertedGuid; +} + +static inline bool IsSetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) +{ + std::_tstring value = GetMsiProperty(handle, sProperty); + return (value.length() > 0); +} + +static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) +{ + MsiSetProperty(handle, sProperty.c_str(), NULL); +} + +static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) +{ + MsiSetProperty(handle, sProperty.c_str(), TEXT("1")); +} + +static BOOL MoveFileEx9x( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags ) +{ + BOOL fSuccess = FALSE; // assume failure + + // Windows 9x has a special mechanism to move files after reboot + + if ( dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT ) + { + CHAR szExistingFileNameA[MAX_PATH]; + CHAR szNewFileNameA[MAX_PATH] = "NUL"; + + // Path names in WININIT.INI must be in short path name form + + if ( + GetShortPathNameA( lpExistingFileNameA, szExistingFileNameA, MAX_PATH ) && + (!lpNewFileNameA || GetShortPathNameA( lpNewFileNameA, szNewFileNameA, MAX_PATH )) + ) + { + CHAR szBuffer[32767]; // The buffer size must not exceed 32K + DWORD dwBufLen = GetPrivateProfileSectionA( RENAME_SECTION, szBuffer, elementsof(szBuffer), WININIT_FILENAME ); + + CHAR szRename[MAX_PATH]; // This is enough for at most to times 67 chracters + strcpy( szRename, szNewFileNameA ); + strcat( szRename, "=" ); + strcat( szRename, szExistingFileNameA ); + size_t lnRename = strlen(szRename); + + if ( dwBufLen + lnRename + 2 <= elementsof(szBuffer) ) + { + CopyMemory( &szBuffer[dwBufLen], szRename, lnRename ); + szBuffer[dwBufLen + lnRename ] = 0; + szBuffer[dwBufLen + lnRename + 1 ] = 0; + + fSuccess = WritePrivateProfileSectionA( RENAME_SECTION, szBuffer, WININIT_FILENAME ); + } + else + SetLastError( ERROR_BUFFER_OVERFLOW ); + } + } + else + { + + fSuccess = MoveFileA( lpExistingFileNameA, lpNewFileNameA ); + + if ( !fSuccess && GetLastError() != ERROR_ACCESS_DENIED && + 0 != (dwFlags & (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) ) + { + BOOL bFailIfExist = 0 == (dwFlags & MOVEFILE_REPLACE_EXISTING); + + fSuccess = CopyFileA( lpExistingFileNameA, lpNewFileNameA, bFailIfExist ); + + if ( fSuccess ) + fSuccess = DeleteFileA( lpExistingFileNameA ); + } + + } + + return fSuccess; +} + +static BOOL MoveFileExImpl( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags ) +{ + if ( 0 > ((LONG)GetVersion())) // High order bit indicates Win 9x + return MoveFileEx9x( lpExistingFileNameA, lpNewFileNameA, dwFlags ); + else + return MoveFileExA( lpExistingFileNameA, lpNewFileNameA, dwFlags ); +} + +static bool SwapFiles( const std::_tstring& sFileName1, const std::_tstring& sFileName2 ) +{ + std::_tstring sTempFileName = sFileName1 + TEXT(".tmp"); + + bool fSuccess = true; + + //Try to move the original file to a temp file + fSuccess = MoveFileExImpl( sFileName1.c_str(), sTempFileName.c_str(), MOVEFILE_REPLACE_EXISTING); + + std::_tstring mystr; + + if ( fSuccess ) + { + fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING ); + + if ( fSuccess ) + { + fSuccess = MoveFileExImpl( sTempFileName.c_str(), sFileName2.c_str(), + MOVEFILE_REPLACE_EXISTING ); + if ( !fSuccess ) + { + MoveFileExImpl( sFileName1.c_str(), sFileName2.c_str(), MOVEFILE_REPLACE_EXISTING ); + } + } + else + { + MoveFileExImpl( sTempFileName.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING ); + } + } + else + { + //It could be that there is no original file and therefore copying the original to a temp + // file failed. Examine if there is no original and if so then move file2 to file1 + + WIN32_FIND_DATA data; + HANDLE hdl = FindFirstFile(sFileName1.c_str(), &data); + if (hdl == INVALID_HANDLE_VALUE) + { + fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING ); + + // if ( fSuccess ) + // { + // mystr = "Success"; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + // } + // else + // { + // char buff[256]; + // wsprintf(buff, "Failure %d", GetLastError()); + // MessageBox( NULL, buff, "Titel", MB_OK ); + // } + } + else + { + FindClose(hdl); + } + } + + OutputDebugStringFormat( TEXT("%s <-> %s: %s"), sFileName1.c_str(), sFileName2.c_str(), fSuccess ? TEXT("OK") : TEXT("FAILED") ); + + if (!fSuccess ) + { + DWORD dwError = GetLastError(); + LPVOID lpMsgBuf; + if ( FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) + { + OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError, lpMsgBuf ); + LocalFree( lpMsgBuf ); + } + else + OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError ); + SetMsiErrorCode( dwError ); + } + + return fSuccess; +} + +static std::_tstring strip( const std::_tstring& s, _TCHAR c ) +{ + std::_tstring result = s; + + std::_tstring::size_type f; + + do + { + f = result.find( c ); + if ( f != std::_tstring::npos ) + result.erase( f, 1 ); + } while ( f != std::_tstring::npos ); + + return result; +} + +static std::_tstring trim( const std::_tstring& rString ) +{ + std::_tstring temp = rString; + + while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' ) + temp.erase( 0, 1 ); + + std::_tstring::size_type len = temp.length(); + + while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' ) + { + temp.erase( len - 1, 1 ); + len = temp.length(); + } + + return temp; +} + +static bool readLine( FILE *fp, std::_tstring& rLine ) +{ + _TCHAR szBuffer[1024]; + bool bSuccess = false; + bool bEOL = false; + std::_tstring line; + + + while ( !bEOL && _fgetts( szBuffer, sizeof(szBuffer), fp ) ) + { + int len = _tcslen(szBuffer); + + bSuccess = true; + + while ( len && szBuffer[len - 1] == '\n' ) + { + szBuffer[--len] = 0; + bEOL = true; + } + + line.append( szBuffer ); + } + + rLine = line; + return bSuccess; +} + + +static std::_tstring getProfileString( + const std::_tstring& aFileName, + const std::_tstring& aSectionName, + const std::_tstring& aKeyName, + const std::_tstring& aDefault = _T("") ) +{ + FILE *fp = _tfopen( aFileName.c_str(), _T("r") ); + std::_tstring retValue = aDefault.length() ? aDefault : _T(""); + + if ( fp ) + { + std::_tstring line; + std::_tstring section; + + while ( readLine( fp, line ) ) + { + line = trim( line ); + + if ( line.length() && line[0] == '[' ) + { + line.erase( 0, 1 ); + std::_tstring::size_type end = line.find( ']', 0 ); + + if ( std::_tstring::npos != end ) + section = trim( line.substr( 0, end ) ); + } + else + { + + std::_tstring::size_type iEqualSign = line.find( '=', 0 ); + + if ( iEqualSign != std::_tstring::npos ) + { + std::_tstring keyname = line.substr( 0, iEqualSign ); + keyname = trim( keyname ); + + std::_tstring value = line.substr( iEqualSign + 1 /*, std::_tstring::npos */ ); + value = trim( value ); + + if ( + 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) && + 0 == _tcsicmp( keyname.c_str(), aKeyName.c_str() ) + ) + { + retValue = value; + break; + } + } + } + } + + fclose( fp ); + } + + return retValue; +} + +static std::queue< std::_tstring > getProfileSections( const std::_tstring& aFileName ) +{ + FILE *fp = _tfopen( aFileName.c_str(), _T("r") ); + std::queue< std::_tstring > aResult; + + OutputDebugStringFormat( TEXT("*** Retrieving Section Names ****") ); + + if ( fp ) + { + std::_tstring line; + std::_tstring section; + + while ( readLine( fp, line ) ) + { + line = trim( line ); + + if ( line.length() && line[0] == '[' ) + { + line.erase( 0, 1 ); + std::_tstring::size_type end = line.find( ']', 0 ); + + if ( std::_tstring::npos != end ) + section = trim( line.substr( 0, end ) ); + + aResult.push( section ); + + OutputDebugStringFormat( TEXT("Section: %s"), section.c_str() ); + + } + } + + fclose( fp ); + } + + OutputDebugStringFormat( TEXT("*** Done Section Names ***") ); + + return aResult; +} + +static std::queue< std::_tstring > getProfileKeys( const std::_tstring& aFileName, const std::_tstring& aSectionName ) +{ + FILE *fp = _tfopen( aFileName.c_str(), _T("r") ); + std::queue< std::_tstring > aResult; + + OutputDebugStringFormat( TEXT("*** Retrieving Key Names for [%s] ***"), aSectionName.c_str() ); + + if ( fp ) + { + std::_tstring line; + std::_tstring section; + + while ( readLine( fp, line ) ) + { + line = trim( line ); + + if ( line.length() && line[0] == '[' ) + { + line.erase( 0, 1 ); + std::_tstring::size_type end = line.find( ']', 0 ); + + if ( std::_tstring::npos != end ) + section = trim( line.substr( 0, end ) ); + } + else + { + + std::_tstring::size_type iEqualSign = line.find( '=', 0 ); + + if ( iEqualSign != std::_tstring::npos ) + { + std::_tstring keyname = line.substr( 0, iEqualSign ); + keyname = trim( keyname ); + + if ( 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) ) + { + aResult.push( keyname ); + + OutputDebugStringFormat( keyname.c_str() ); + + } + } + } + } + + fclose( fp ); + } + + OutputDebugStringFormat( TEXT("*** Done Key Names for [%s] ***"), aSectionName.c_str() ); + + return aResult; +} + +extern "C" UINT __stdcall InstallPatchedFiles( MSIHANDLE handle ) +{ + std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") ); + std::_tstring sBasisInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") ); + std::_tstring sProgramDir = sBasisInstDir + TEXT("program\\"); + std::_tstring sPatchFile = sProgramDir + TEXT("patchlist.txt"); + + std::queue< std::_tstring > aSectionNames; + std::queue< std::_tstring > aKeyNames; + + OutputDebugStringA( "Starting Custom Action" ); + + // std::_tstring mystr; + // mystr = "Patchfile: " + sPatchFile; + // MessageBox( NULL, mystr.c_str(), "Patchfile", MB_OK ); + + aSectionNames = getProfileSections( sPatchFile ); + while ( !aSectionNames.empty() ) + { + std::_tstring sSectionName = aSectionNames.front(); + if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); } + // mystr = "Section: " + sSectionName; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + + aKeyNames = getProfileKeys( sPatchFile, sSectionName ); + while ( !aKeyNames.empty() ) + { + std::_tstring sKeyName = aKeyNames.front(); + std::_tstring sValue = getProfileString( sPatchFile, sSectionName, sKeyName ); + + if ( sValue.length() ) + { + std::_tstring sFileName1 = sKeyName; + std::_tstring sExtension = sValue; + std::_tstring sFileName2; + + sFileName1 = strip( sFileName1, '\"' ); + sExtension = strip( sExtension, '\"' ); + + sFileName1 = sInstDir + sSectionName + sFileName1; + sFileName2 = sFileName1 + sExtension; + + // mystr = "Convert: " + sFileName1 + " to " + sFileName2; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + + SwapFiles( sFileName1, sFileName2 ); + } + + aKeyNames.pop(); + } + + aSectionNames.pop(); + } + + return ERROR_SUCCESS; +} + +extern "C" UINT __stdcall UninstallPatchedFiles( MSIHANDLE handle ) +{ + TCHAR szValue[8192]; + DWORD nValueSize = sizeof(szValue); + HKEY hKey; + + std::_tstring sInstDir; + std::_tstring sBasisInstDir; + + std::_tstring sProductKey = GetMsiProperty( handle, TEXT("FINDPRODUCT") ); + + if ( ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER, sProductKey.c_str(), &hKey ) ) + { + if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("BASISINSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) ) + { + sBasisInstDir = szValue; + } + if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) ) + { + sInstDir = szValue; + } + RegCloseKey( hKey ); + } + else if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, sProductKey.c_str(), &hKey ) ) + { + if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("BASISINSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) ) + { + sBasisInstDir = szValue; + } + if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) ) + { + sInstDir = szValue; + } + RegCloseKey( hKey ); + } + else + return ERROR_SUCCESS; + + std::_tstring sProgramDir = sBasisInstDir + TEXT("program\\"); + std::_tstring sPatchFile = sProgramDir + TEXT("patchlist.txt"); + + std::queue< std::_tstring > aSectionNames; + std::queue< std::_tstring > aKeyNames; + + // std::_tstring mystr; + // mystr = "Patchfile: " + sPatchFile; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + + aSectionNames = getProfileSections( sPatchFile ); + while ( !aSectionNames.empty() ) + { + std::_tstring sSectionName = aSectionNames.front(); + if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); } + // mystr = "Section: " + sSectionName; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + + aKeyNames = getProfileKeys( sPatchFile, sSectionName ); + while( !aKeyNames.empty() ) + { + std::_tstring sKeyName = aKeyNames.front(); + std::_tstring sValue = getProfileString( sPatchFile, sSectionName, sKeyName ); + + if ( sValue.length() ) + { + std::_tstring sFileName1 = sKeyName; + std::_tstring sExtension = sValue; + std::_tstring sFileName2; + + sFileName1 = strip( sFileName1, '\"' ); + sExtension = strip( sExtension, '\"' ); + + sFileName1 = sInstDir + sSectionName + sFileName1; + sFileName2 = sFileName1 + sExtension; + + // mystr = "Convert: " + sFileName1 + " to " + sFileName2; + // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); + + SwapFiles( sFileName2, sFileName1 ); + } + + aKeyNames.pop(); + } + + aSectionNames.pop(); + } + + return ERROR_SUCCESS; +} + +extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle ) +{ + std::_tstring sInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") ); + std::_tstring sResourceDir = sInstDir + TEXT("program\\resource\\"); + std::_tstring sPattern = sResourceDir + TEXT("vcl*.res"); + + WIN32_FIND_DATA aFindFileData; + HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData ); + + if ( IsValidHandle(hFind) ) + { + BOOL fSuccess = false; + bool fRenameSucceeded; + + do + { + std::_tstring sResourceFile = sResourceDir + aFindFileData.cFileName; + std::_tstring sIntermediate = sResourceFile + TEXT(".tmp"); + + fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING ); + if ( fRenameSucceeded ) + { + MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 ); + fSuccess = FindNextFile( hFind, &aFindFileData ); + } + } while ( fSuccess && fRenameSucceeded ); + + if ( !fRenameSucceeded ) + { + MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1")); + SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING ); + } + + FindClose( hFind ); + } + + + return ERROR_SUCCESS; +} + +extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle ) +{ + std::_tstring mystr; + + // 1. Reading Product Code from setup.ini of installed Office + + std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("OFFICEINSTALLLOCATION")); + // MessageBox(NULL, sInstallPath.c_str(), "BASISINSTALLLOCATION", MB_OK); + std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini"); + + TCHAR szProductCode[32767]; + + GetPrivateProfileString( + TEXT("Bootstrap"), + TEXT("ProductCode"), + TEXT("NOTFOUND"), + szProductCode, + elementsof(szProductCode), + sSetupiniPath.c_str() + ); + + if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) ) + { + // No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory. + // MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK); + return ERROR_SUCCESS; + } + + // 2. Converting Product code + + std::_tstring productCode = TEXT(szProductCode); + productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2)); + mystr = TEXT("Changed product code: ") + productCode; + // MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK); + + // 3. Setting path in the Windows registry to find installed features + + std::_tstring registryKey; + HKEY registryRoot; + + if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) ) + { + registryRoot = HKEY_LOCAL_MACHINE; + registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode; + mystr = registryKey; + // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK ); + } + else + { + registryRoot = HKEY_CURRENT_USER; + registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode; + mystr = registryKey; + // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK ); + } + + // 4. Collecting all installed features from Windows registry + + HKEY hKey; + if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS) + { + int counter = 0; + // DWORD counter = 0; + LONG lEnumResult; + + do + { + TCHAR szValueName[8192]; + DWORD nValueNameSize = sizeof(szValueName); + LPDWORD pValueNameSize = &nValueNameSize; + TCHAR szValueData[8192]; + DWORD nValueDataSize = sizeof(szValueData); + + lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize); + + if ( ERROR_SUCCESS == lEnumResult ) + { + std::_tstring sValueName = szValueName; + std::_tstring sValueData = szValueData; + + // mystr = sValueName; + // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); + // mystr = sValueData; + // MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK ); + + // Does this feature exist in this patch? + if ( IsSetMsiProperty(handle, sValueName) ) + { + // Feature is not installed, if szValueData starts with a "square" (ascii 6) + if ( 6 == szValueData[0] ) + { + MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature + // mystr = TEXT("Do NOT install: ") + sValueName; + // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); + } + else + { + MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature + // mystr = TEXT("Do install: ") + sValueName; + // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); + } + } + } + + counter = counter + 1; + + } while ( ERROR_SUCCESS == lEnumResult ); + + RegCloseKey( hKey ); + } + + return ERROR_SUCCESS; +} + +extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle ) +{ + std::_tstring mystr; + std::_tstring sValueName; + + sValueName = TEXT("gm_o_Onlineupdate"); + + if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"))) + { + MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature + // mystr = TEXT("OnlineUpdate wird installiert!"); + // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK); + } + else + { + MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature + // mystr = TEXT("OnlineUpdate wird NICHT installiert!"); + // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK); + } + + return ERROR_SUCCESS; +} + +extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle ) +{ + // Checking existence of file "updchk.uno.dll", which shows, that + // Online Update functionality is always available. Then the dialog + // that offers the Online Update is superfluous. + + std::_tstring sInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") ); + std::_tstring sProgramDir = sInstDir + TEXT("program\\"); + std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll"); + + WIN32_FIND_DATA data; + HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data); + if (hdl != INVALID_HANDLE_VALUE) // the file exists + { + // std::_tstring mystr; + // mystr = "Found file: " + sSearchFile; + // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK ); + + // And finally setting property SHOW_ONLINEUPDATE_DIALOG + // to hide this dialog + UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG")); + + // Setting SELECT_OU_FEATURE to 1, which is probably superfluous + // because this is already the default value. But only this + // guarantees, that CustomAction SetNewFeatureState always sets + // the correct FeatureState for "gm_o_Onlineupdate", if it is + // already installed. + SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")); + } + else + { + // std::_tstring mystr; + // mystr = "Did not find file: " + sSearchFile; + // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK ); + + // If the file does not exist, the Online Update dialog + // has to be shown. + SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG")); + FindClose(hdl); + } + + return ERROR_SUCCESS; +} |