Update ooo320-m1
[ooovba.git] / setup_native / source / win32 / customactions / patch / swappatchfiles.cxx
blobff8605c0c09238ea66c4ac4802ef777dda7f324d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swappatchfiles.cxx,v $
10 * $Revision: 1.22 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #define _WIN32_WINDOWS 0x0410
33 #ifdef _MSC_VER
34 #pragma warning(push, 1) /* disable warnings within system headers */
35 #endif
36 #define WIN32_LEAN_AND_MEAN
37 #include <windows.h>
38 #include <msiquery.h>
39 #ifdef _MSC_VER
40 #pragma warning(pop)
41 #endif
43 #include <malloc.h>
44 #include <assert.h>
46 #ifdef UNICODE
47 #define _UNICODE
48 #define _tstring wstring
49 #else
50 #define _tstring string
51 #endif
52 #include <tchar.h>
53 #include <string>
54 #include <queue>
55 #include <stdio.h>
57 #include <systools/win32/uwinapi.h>
58 #include <../tools/seterror.hxx>
60 #define WININIT_FILENAME "wininit.ini"
61 #define RENAME_SECTION "rename"
63 #ifdef DEBUG
64 inline void OutputDebugStringFormat( LPCTSTR pFormat, ... )
66 _TCHAR buffer[1024];
67 va_list args;
69 va_start( args, pFormat );
70 _vsntprintf( buffer, elementsof(buffer), pFormat, args );
71 OutputDebugString( buffer );
73 #else
74 static inline void OutputDebugStringFormat( LPCTSTR, ... )
77 #endif
79 static std::_tstring GetMsiProperty( MSIHANDLE handle, const std::_tstring& sProperty )
81 std::_tstring result;
82 TCHAR szDummy[1] = TEXT("");
83 DWORD nChars = 0;
85 if ( MsiGetProperty( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA )
87 DWORD nBytes = ++nChars * sizeof(TCHAR);
88 LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
89 ZeroMemory( buffer, nBytes );
90 MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
91 result = buffer;
94 return result;
97 // The provided GUID must be without surounding '{}'
98 static std::_tstring GetGuidPart(const std::_tstring& guid, int index)
100 assert((guid.length() == 36) && "No GUID or wrong format!");
101 assert(((index > -1) && (index < 5)) && "Out of range!");
103 if (index == 0) return std::_tstring(guid.c_str(), 8);
104 if (index == 1) return std::_tstring(guid.c_str() + 9, 4);
105 if (index == 2) return std::_tstring(guid.c_str() + 14, 4);
106 if (index == 3) return std::_tstring(guid.c_str() + 19, 4);
107 if (index == 4) return std::_tstring(guid.c_str() + 24, 12);
109 return std::_tstring();
112 static void Swap(char* p1, char* p2)
114 char tmp = *p1;
115 *p1 = *p2;
116 *p2 = tmp;
119 static std::_tstring Invert(const std::_tstring& str)
121 char* buff = reinterpret_cast<char*>(_alloca(str.length()));
122 strncpy(buff, str.c_str(), str.length());
124 char* front = buff;
125 char* back = buff + str.length() - 1;
127 while (front < back)
128 Swap(front++, back--);
130 return std::_tstring(buff, str.length());
133 // Convert the upgrade code (which is a GUID) according
134 // to the way the windows installer does when writing it
135 // to the registry
136 // The first 8 bytes will be inverted, from the the last
137 // 8 bytes always the nibbles will be inverted for further
138 // details look in the MSDN under compressed registry keys
139 static std::_tstring ConvertGuid(const std::_tstring& guid)
141 std::_tstring convertedGuid;
143 std::_tstring part = GetGuidPart(guid, 0);
144 convertedGuid = Invert(part);
146 part = GetGuidPart(guid, 1);
147 convertedGuid += Invert(part);
149 part = GetGuidPart(guid, 2);
150 convertedGuid += Invert(part);
152 part = GetGuidPart(guid, 3);
153 convertedGuid += Invert(std::_tstring(part.c_str(), 2));
154 convertedGuid += Invert(std::_tstring(part.c_str() + 2, 2));
156 part = GetGuidPart(guid, 4);
157 int pos = 0;
158 for (int i = 0; i < 6; i++)
160 convertedGuid += Invert(std::_tstring(part.c_str() + pos, 2));
161 pos += 2;
163 return convertedGuid;
166 static inline bool IsSetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
168 std::_tstring value = GetMsiProperty(handle, sProperty);
169 return (value.length() > 0);
172 static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
174 MsiSetProperty(handle, sProperty.c_str(), NULL);
177 static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
179 MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
182 static BOOL MoveFileEx9x( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
184 BOOL fSuccess = FALSE; // assume failure
186 // Windows 9x has a special mechanism to move files after reboot
188 if ( dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT )
190 CHAR szExistingFileNameA[MAX_PATH];
191 CHAR szNewFileNameA[MAX_PATH] = "NUL";
193 // Path names in WININIT.INI must be in short path name form
195 if (
196 GetShortPathNameA( lpExistingFileNameA, szExistingFileNameA, MAX_PATH ) &&
197 (!lpNewFileNameA || GetShortPathNameA( lpNewFileNameA, szNewFileNameA, MAX_PATH ))
200 CHAR szBuffer[32767]; // The buffer size must not exceed 32K
201 DWORD dwBufLen = GetPrivateProfileSectionA( RENAME_SECTION, szBuffer, elementsof(szBuffer), WININIT_FILENAME );
203 CHAR szRename[MAX_PATH]; // This is enough for at most to times 67 chracters
204 strcpy( szRename, szNewFileNameA );
205 strcat( szRename, "=" );
206 strcat( szRename, szExistingFileNameA );
207 size_t lnRename = strlen(szRename);
209 if ( dwBufLen + lnRename + 2 <= elementsof(szBuffer) )
211 CopyMemory( &szBuffer[dwBufLen], szRename, lnRename );
212 szBuffer[dwBufLen + lnRename ] = 0;
213 szBuffer[dwBufLen + lnRename + 1 ] = 0;
215 fSuccess = WritePrivateProfileSectionA( RENAME_SECTION, szBuffer, WININIT_FILENAME );
217 else
218 SetLastError( ERROR_BUFFER_OVERFLOW );
221 else
224 fSuccess = MoveFileA( lpExistingFileNameA, lpNewFileNameA );
226 if ( !fSuccess && GetLastError() != ERROR_ACCESS_DENIED &&
227 0 != (dwFlags & (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) )
229 BOOL bFailIfExist = 0 == (dwFlags & MOVEFILE_REPLACE_EXISTING);
231 fSuccess = CopyFileA( lpExistingFileNameA, lpNewFileNameA, bFailIfExist );
233 if ( fSuccess )
234 fSuccess = DeleteFileA( lpExistingFileNameA );
239 return fSuccess;
242 static BOOL MoveFileExImpl( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
244 if ( 0 > ((LONG)GetVersion())) // High order bit indicates Win 9x
245 return MoveFileEx9x( lpExistingFileNameA, lpNewFileNameA, dwFlags );
246 else
247 return MoveFileExA( lpExistingFileNameA, lpNewFileNameA, dwFlags );
250 static bool SwapFiles( const std::_tstring& sFileName1, const std::_tstring& sFileName2 )
252 std::_tstring sTempFileName = sFileName1 + TEXT(".tmp");
254 bool fSuccess = true;
256 //Try to move the original file to a temp file
257 fSuccess = MoveFileExImpl( sFileName1.c_str(), sTempFileName.c_str(), MOVEFILE_REPLACE_EXISTING);
259 std::_tstring mystr;
261 if ( fSuccess )
263 fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
265 if ( fSuccess )
267 fSuccess = MoveFileExImpl( sTempFileName.c_str(), sFileName2.c_str(),
268 MOVEFILE_REPLACE_EXISTING );
269 if ( !fSuccess )
271 MoveFileExImpl( sFileName1.c_str(), sFileName2.c_str(), MOVEFILE_REPLACE_EXISTING );
274 else
276 MoveFileExImpl( sTempFileName.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
279 else
281 //It could be that there is no original file and therefore copying the original to a temp
282 // file failed. Examine if there is no original and if so then move file2 to file1
284 WIN32_FIND_DATA data;
285 HANDLE hdl = FindFirstFile(sFileName1.c_str(), &data);
286 if (hdl == INVALID_HANDLE_VALUE)
288 fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
290 // if ( fSuccess )
291 // {
292 // mystr = "Success";
293 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
294 // }
295 // else
296 // {
297 // char buff[256];
298 // wsprintf(buff, "Failure %d", GetLastError());
299 // MessageBox( NULL, buff, "Titel", MB_OK );
300 // }
302 else
304 FindClose(hdl);
308 OutputDebugStringFormat( TEXT("%s <-> %s: %s"), sFileName1.c_str(), sFileName2.c_str(), fSuccess ? TEXT("OK") : TEXT("FAILED") );
310 if (!fSuccess )
312 DWORD dwError = GetLastError();
313 LPVOID lpMsgBuf;
314 if ( FormatMessage(
315 FORMAT_MESSAGE_ALLOCATE_BUFFER |
316 FORMAT_MESSAGE_FROM_SYSTEM |
317 FORMAT_MESSAGE_IGNORE_INSERTS,
318 NULL,
319 GetLastError(),
320 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
321 (LPTSTR) &lpMsgBuf,
323 NULL ))
325 OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError, lpMsgBuf );
326 LocalFree( lpMsgBuf );
328 else
329 OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError );
330 SetMsiErrorCode( dwError );
333 return fSuccess;
336 static std::_tstring strip( const std::_tstring& s, _TCHAR c )
338 std::_tstring result = s;
340 std::_tstring::size_type f;
344 f = result.find( c );
345 if ( f != std::_tstring::npos )
346 result.erase( f, 1 );
347 } while ( f != std::_tstring::npos );
349 return result;
352 static std::_tstring trim( const std::_tstring& rString )
354 std::_tstring temp = rString;
356 while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' )
357 temp.erase( 0, 1 );
359 std::_tstring::size_type len = temp.length();
361 while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' )
363 temp.erase( len - 1, 1 );
364 len = temp.length();
367 return temp;
370 static bool readLine( FILE *fp, std::_tstring& rLine )
372 _TCHAR szBuffer[1024];
373 bool bSuccess = false;
374 bool bEOL = false;
375 std::_tstring line;
378 while ( !bEOL && _fgetts( szBuffer, sizeof(szBuffer), fp ) )
380 int len = _tcslen(szBuffer);
382 bSuccess = true;
384 while ( len && szBuffer[len - 1] == '\n' )
386 szBuffer[--len] = 0;
387 bEOL = true;
390 line.append( szBuffer );
393 rLine = line;
394 return bSuccess;
398 static std::_tstring getProfileString(
399 const std::_tstring& aFileName,
400 const std::_tstring& aSectionName,
401 const std::_tstring& aKeyName,
402 const std::_tstring& aDefault = _T("") )
404 FILE *fp = _tfopen( aFileName.c_str(), _T("r") );
405 std::_tstring retValue = aDefault.length() ? aDefault : _T("");
407 if ( fp )
409 std::_tstring line;
410 std::_tstring section;
412 while ( readLine( fp, line ) )
414 line = trim( line );
416 if ( line.length() && line[0] == '[' )
418 line.erase( 0, 1 );
419 std::_tstring::size_type end = line.find( ']', 0 );
421 if ( std::_tstring::npos != end )
422 section = trim( line.substr( 0, end ) );
424 else
427 std::_tstring::size_type iEqualSign = line.find( '=', 0 );
429 if ( iEqualSign != std::_tstring::npos )
431 std::_tstring keyname = line.substr( 0, iEqualSign );
432 keyname = trim( keyname );
434 std::_tstring value = line.substr( iEqualSign + 1 /*, std::_tstring::npos */ );
435 value = trim( value );
437 if (
438 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) &&
439 0 == _tcsicmp( keyname.c_str(), aKeyName.c_str() )
442 retValue = value;
443 break;
449 fclose( fp );
452 return retValue;
455 static std::queue< std::_tstring > getProfileSections( const std::_tstring& aFileName )
457 FILE *fp = _tfopen( aFileName.c_str(), _T("r") );
458 std::queue< std::_tstring > aResult;
460 OutputDebugStringFormat( TEXT("*** Retrieving Section Names ****") );
462 if ( fp )
464 std::_tstring line;
465 std::_tstring section;
467 while ( readLine( fp, line ) )
469 line = trim( line );
471 if ( line.length() && line[0] == '[' )
473 line.erase( 0, 1 );
474 std::_tstring::size_type end = line.find( ']', 0 );
476 if ( std::_tstring::npos != end )
477 section = trim( line.substr( 0, end ) );
479 aResult.push( section );
481 OutputDebugStringFormat( TEXT("Section: %s"), section.c_str() );
486 fclose( fp );
489 OutputDebugStringFormat( TEXT("*** Done Section Names ***") );
491 return aResult;
494 static std::queue< std::_tstring > getProfileKeys( const std::_tstring& aFileName, const std::_tstring& aSectionName )
496 FILE *fp = _tfopen( aFileName.c_str(), _T("r") );
497 std::queue< std::_tstring > aResult;
499 OutputDebugStringFormat( TEXT("*** Retrieving Key Names for [%s] ***"), aSectionName.c_str() );
501 if ( fp )
503 std::_tstring line;
504 std::_tstring section;
506 while ( readLine( fp, line ) )
508 line = trim( line );
510 if ( line.length() && line[0] == '[' )
512 line.erase( 0, 1 );
513 std::_tstring::size_type end = line.find( ']', 0 );
515 if ( std::_tstring::npos != end )
516 section = trim( line.substr( 0, end ) );
518 else
521 std::_tstring::size_type iEqualSign = line.find( '=', 0 );
523 if ( iEqualSign != std::_tstring::npos )
525 std::_tstring keyname = line.substr( 0, iEqualSign );
526 keyname = trim( keyname );
528 if ( 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) )
530 aResult.push( keyname );
532 OutputDebugStringFormat( keyname.c_str() );
539 fclose( fp );
542 OutputDebugStringFormat( TEXT("*** Done Key Names for [%s] ***"), aSectionName.c_str() );
544 return aResult;
547 extern "C" UINT __stdcall InstallPatchedFiles( MSIHANDLE handle )
549 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
550 std::_tstring sBasisInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") );
551 std::_tstring sProgramDir = sBasisInstDir + TEXT("program\\");
552 std::_tstring sPatchFile = sProgramDir + TEXT("patchlist.txt");
554 std::queue< std::_tstring > aSectionNames;
555 std::queue< std::_tstring > aKeyNames;
557 OutputDebugStringA( "Starting Custom Action" );
559 // std::_tstring mystr;
560 // mystr = "Patchfile: " + sPatchFile;
561 // MessageBox( NULL, mystr.c_str(), "Patchfile", MB_OK );
563 aSectionNames = getProfileSections( sPatchFile );
564 while ( !aSectionNames.empty() )
566 std::_tstring sSectionName = aSectionNames.front();
567 if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
568 // mystr = "Section: " + sSectionName;
569 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
571 aKeyNames = getProfileKeys( sPatchFile, sSectionName );
572 while ( !aKeyNames.empty() )
574 std::_tstring sKeyName = aKeyNames.front();
575 std::_tstring sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
577 if ( sValue.length() )
579 std::_tstring sFileName1 = sKeyName;
580 std::_tstring sExtension = sValue;
581 std::_tstring sFileName2;
583 sFileName1 = strip( sFileName1, '\"' );
584 sExtension = strip( sExtension, '\"' );
586 sFileName1 = sInstDir + sSectionName + sFileName1;
587 sFileName2 = sFileName1 + sExtension;
589 // mystr = "Convert: " + sFileName1 + " to " + sFileName2;
590 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
592 SwapFiles( sFileName1, sFileName2 );
595 aKeyNames.pop();
598 aSectionNames.pop();
601 return ERROR_SUCCESS;
604 extern "C" UINT __stdcall UninstallPatchedFiles( MSIHANDLE handle )
606 TCHAR szValue[8192];
607 DWORD nValueSize = sizeof(szValue);
608 HKEY hKey;
610 std::_tstring sInstDir;
611 std::_tstring sBasisInstDir;
613 std::_tstring sProductKey = GetMsiProperty( handle, TEXT("FINDPRODUCT") );
615 if ( ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER, sProductKey.c_str(), &hKey ) )
617 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("BASISINSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
619 sBasisInstDir = szValue;
621 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
623 sInstDir = szValue;
625 RegCloseKey( hKey );
627 else if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, sProductKey.c_str(), &hKey ) )
629 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("BASISINSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
631 sBasisInstDir = szValue;
633 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
635 sInstDir = szValue;
637 RegCloseKey( hKey );
639 else
640 return ERROR_SUCCESS;
642 std::_tstring sProgramDir = sBasisInstDir + TEXT("program\\");
643 std::_tstring sPatchFile = sProgramDir + TEXT("patchlist.txt");
645 std::queue< std::_tstring > aSectionNames;
646 std::queue< std::_tstring > aKeyNames;
648 // std::_tstring mystr;
649 // mystr = "Patchfile: " + sPatchFile;
650 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
652 aSectionNames = getProfileSections( sPatchFile );
653 while ( !aSectionNames.empty() )
655 std::_tstring sSectionName = aSectionNames.front();
656 if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
657 // mystr = "Section: " + sSectionName;
658 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
660 aKeyNames = getProfileKeys( sPatchFile, sSectionName );
661 while( !aKeyNames.empty() )
663 std::_tstring sKeyName = aKeyNames.front();
664 std::_tstring sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
666 if ( sValue.length() )
668 std::_tstring sFileName1 = sKeyName;
669 std::_tstring sExtension = sValue;
670 std::_tstring sFileName2;
672 sFileName1 = strip( sFileName1, '\"' );
673 sExtension = strip( sExtension, '\"' );
675 sFileName1 = sInstDir + sSectionName + sFileName1;
676 sFileName2 = sFileName1 + sExtension;
678 // mystr = "Convert: " + sFileName1 + " to " + sFileName2;
679 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
681 SwapFiles( sFileName2, sFileName1 );
684 aKeyNames.pop();
687 aSectionNames.pop();
690 return ERROR_SUCCESS;
693 extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle )
695 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") );
696 std::_tstring sResourceDir = sInstDir + TEXT("program\\resource\\");
697 std::_tstring sPattern = sResourceDir + TEXT("vcl*.res");
699 WIN32_FIND_DATA aFindFileData;
700 HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
702 if ( IsValidHandle(hFind) )
704 BOOL fSuccess = false;
705 bool fRenameSucceeded;
709 std::_tstring sResourceFile = sResourceDir + aFindFileData.cFileName;
710 std::_tstring sIntermediate = sResourceFile + TEXT(".tmp");
712 fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING );
713 if ( fRenameSucceeded )
715 MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 );
716 fSuccess = FindNextFile( hFind, &aFindFileData );
718 } while ( fSuccess && fRenameSucceeded );
720 if ( !fRenameSucceeded )
722 MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1"));
723 SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING );
726 FindClose( hFind );
730 return ERROR_SUCCESS;
733 extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle )
735 std::_tstring mystr;
737 // 1. Reading Product Code from setup.ini of installed Office
739 std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("OFFICEINSTALLLOCATION"));
740 // MessageBox(NULL, sInstallPath.c_str(), "BASISINSTALLLOCATION", MB_OK);
741 std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini");
743 TCHAR szProductCode[32767];
745 GetPrivateProfileString(
746 TEXT("Bootstrap"),
747 TEXT("ProductCode"),
748 TEXT("NOTFOUND"),
749 szProductCode,
750 elementsof(szProductCode),
751 sSetupiniPath.c_str()
754 if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) )
756 // No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory.
757 // MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK);
758 return ERROR_SUCCESS;
761 // 2. Converting Product code
763 std::_tstring productCode = TEXT(szProductCode);
764 productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2));
765 mystr = TEXT("Changed product code: ") + productCode;
766 // MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK);
768 // 3. Setting path in the Windows registry to find installed features
770 std::_tstring registryKey;
771 HKEY registryRoot;
773 if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) )
775 registryRoot = HKEY_LOCAL_MACHINE;
776 registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode;
777 mystr = registryKey;
778 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
780 else
782 registryRoot = HKEY_CURRENT_USER;
783 registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode;
784 mystr = registryKey;
785 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
788 // 4. Collecting all installed features from Windows registry
790 HKEY hKey;
791 if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS)
793 int counter = 0;
794 // DWORD counter = 0;
795 LONG lEnumResult;
799 TCHAR szValueName[8192];
800 DWORD nValueNameSize = sizeof(szValueName);
801 LPDWORD pValueNameSize = &nValueNameSize;
802 TCHAR szValueData[8192];
803 DWORD nValueDataSize = sizeof(szValueData);
805 lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize);
807 if ( ERROR_SUCCESS == lEnumResult )
809 std::_tstring sValueName = szValueName;
810 std::_tstring sValueData = szValueData;
812 // mystr = sValueName;
813 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
814 // mystr = sValueData;
815 // MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK );
817 // Does this feature exist in this patch?
818 if ( IsSetMsiProperty(handle, sValueName) )
820 // Feature is not installed, if szValueData starts with a "square" (ascii 6)
821 if ( 6 == szValueData[0] )
823 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
824 // mystr = TEXT("Do NOT install: ") + sValueName;
825 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
827 else
829 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
830 // mystr = TEXT("Do install: ") + sValueName;
831 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
836 counter = counter + 1;
838 } while ( ERROR_SUCCESS == lEnumResult );
840 RegCloseKey( hKey );
843 return ERROR_SUCCESS;
846 extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle )
848 std::_tstring mystr;
849 std::_tstring sValueName;
851 sValueName = TEXT("gm_o_Onlineupdate");
853 if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")))
855 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
856 // mystr = TEXT("OnlineUpdate wird installiert!");
857 // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK);
859 else
861 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
862 // mystr = TEXT("OnlineUpdate wird NICHT installiert!");
863 // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK);
866 return ERROR_SUCCESS;
869 extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle )
871 // Checking existence of file "updchk.uno.dll", which shows, that
872 // Online Update functionality is always available. Then the dialog
873 // that offers the Online Update is superfluous.
875 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("BASISINSTALLLOCATION") );
876 std::_tstring sProgramDir = sInstDir + TEXT("program\\");
877 std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll");
879 WIN32_FIND_DATA data;
880 HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data);
881 if (hdl != INVALID_HANDLE_VALUE) // the file exists
883 // std::_tstring mystr;
884 // mystr = "Found file: " + sSearchFile;
885 // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK );
887 // And finally setting property SHOW_ONLINEUPDATE_DIALOG
888 // to hide this dialog
889 UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
891 // Setting SELECT_OU_FEATURE to 1, which is probably superfluous
892 // because this is already the default value. But only this
893 // guarantees, that CustomAction SetNewFeatureState always sets
894 // the correct FeatureState for "gm_o_Onlineupdate", if it is
895 // already installed.
896 SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"));
898 else
900 // std::_tstring mystr;
901 // mystr = "Did not find file: " + sSearchFile;
902 // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK );
904 // If the file does not exist, the Online Update dialog
905 // has to be shown.
906 SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
907 FindClose(hdl);
910 return ERROR_SUCCESS;