1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swappatchfiles.cxx,v $
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
34 #pragma warning(push, 1) /* disable warnings within system headers */
36 #define WIN32_LEAN_AND_MEAN
48 #define _tstring wstring
50 #define _tstring string
57 #include <systools/win32/uwinapi.h>
58 #include <../tools/seterror.hxx>
60 #define WININIT_FILENAME "wininit.ini"
61 #define RENAME_SECTION "rename"
64 inline void OutputDebugStringFormat( LPCTSTR pFormat
, ... )
69 va_start( args
, pFormat
);
70 _vsntprintf( buffer
, elementsof(buffer
), pFormat
, args
);
71 OutputDebugString( buffer
);
74 static inline void OutputDebugStringFormat( LPCTSTR
, ... )
79 static std::_tstring
GetMsiProperty( MSIHANDLE handle
, const std::_tstring
& sProperty
)
82 TCHAR szDummy
[1] = TEXT("");
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
);
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
)
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());
125 char* back
= buff
+ str
.length() - 1;
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
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);
158 for (int i
= 0; i
< 6; i
++)
160 convertedGuid
+= Invert(std::_tstring(part
.c_str() + 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
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
);
218 SetLastError( ERROR_BUFFER_OVERFLOW
);
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
);
234 fSuccess
= DeleteFileA( lpExistingFileNameA
);
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
);
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
);
263 fSuccess
= MoveFileExImpl( sFileName2
.c_str(), sFileName1
.c_str(), MOVEFILE_REPLACE_EXISTING
);
267 fSuccess
= MoveFileExImpl( sTempFileName
.c_str(), sFileName2
.c_str(),
268 MOVEFILE_REPLACE_EXISTING
);
271 MoveFileExImpl( sFileName1
.c_str(), sFileName2
.c_str(), MOVEFILE_REPLACE_EXISTING
);
276 MoveFileExImpl( sTempFileName
.c_str(), sFileName1
.c_str(), MOVEFILE_REPLACE_EXISTING
);
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
);
292 // mystr = "Success";
293 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
298 // wsprintf(buff, "Failure %d", GetLastError());
299 // MessageBox( NULL, buff, "Titel", MB_OK );
308 OutputDebugStringFormat( TEXT("%s <-> %s: %s"), sFileName1
.c_str(), sFileName2
.c_str(), fSuccess
? TEXT("OK") : TEXT("FAILED") );
312 DWORD dwError
= GetLastError();
315 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
316 FORMAT_MESSAGE_FROM_SYSTEM
|
317 FORMAT_MESSAGE_IGNORE_INSERTS
,
320 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
325 OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError
, lpMsgBuf
);
326 LocalFree( lpMsgBuf
);
329 OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError
);
330 SetMsiErrorCode( dwError
);
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
);
352 static std::_tstring
trim( const std::_tstring
& rString
)
354 std::_tstring temp
= rString
;
356 while ( temp
.length() && temp
[0] == ' ' || temp
[0] == '\t' )
359 std::_tstring::size_type len
= temp
.length();
361 while ( len
&& temp
[len
-1] == ' ' || temp
[len
-1] == '\t' )
363 temp
.erase( len
- 1, 1 );
370 static bool readLine( FILE *fp
, std::_tstring
& rLine
)
372 _TCHAR szBuffer
[1024];
373 bool bSuccess
= false;
378 while ( !bEOL
&& _fgetts( szBuffer
, sizeof(szBuffer
), fp
) )
380 int len
= _tcslen(szBuffer
);
384 while ( len
&& szBuffer
[len
- 1] == '\n' )
390 line
.append( szBuffer
);
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("");
410 std::_tstring section
;
412 while ( readLine( fp
, line
) )
416 if ( line
.length() && line
[0] == '[' )
419 std::_tstring::size_type end
= line
.find( ']', 0 );
421 if ( std::_tstring::npos
!= end
)
422 section
= trim( line
.substr( 0, end
) );
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
);
438 0 == _tcsicmp( section
.c_str(), aSectionName
.c_str() ) &&
439 0 == _tcsicmp( keyname
.c_str(), aKeyName
.c_str() )
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 ****") );
465 std::_tstring section
;
467 while ( readLine( fp
, line
) )
471 if ( line
.length() && line
[0] == '[' )
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() );
489 OutputDebugStringFormat( TEXT("*** Done Section Names ***") );
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() );
504 std::_tstring section
;
506 while ( readLine( fp
, line
) )
510 if ( line
.length() && line
[0] == '[' )
513 std::_tstring::size_type end
= line
.find( ']', 0 );
515 if ( std::_tstring::npos
!= end
)
516 section
= trim( line
.substr( 0, end
) );
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() );
542 OutputDebugStringFormat( TEXT("*** Done Key Names for [%s] ***"), aSectionName
.c_str() );
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
);
601 return ERROR_SUCCESS
;
604 extern "C" UINT __stdcall
UninstallPatchedFiles( MSIHANDLE handle
)
607 DWORD nValueSize
= sizeof(szValue
);
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
) )
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
) )
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
);
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
);
730 return ERROR_SUCCESS
;
733 extern "C" UINT __stdcall
SetFeatureState( MSIHANDLE handle
)
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(
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
;
773 if ( IsSetMsiProperty(handle
, TEXT("ALLUSERS")) )
775 registryRoot
= HKEY_LOCAL_MACHINE
;
776 registryKey
= TEXT("Software\\Classes\\Installer\\Features\\") + productCode
;
778 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
782 registryRoot
= HKEY_CURRENT_USER
;
783 registryKey
= TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode
;
785 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
788 // 4. Collecting all installed features from Windows registry
791 if (RegOpenKey(registryRoot
, registryKey
.c_str(), &hKey
) == ERROR_SUCCESS
)
794 // DWORD counter = 0;
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 );
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
);
843 return ERROR_SUCCESS
;
846 extern "C" UINT __stdcall
SetNewFeatureState( MSIHANDLE handle
)
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);
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"));
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
906 SetMsiProperty(handle
, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
910 return ERROR_SUCCESS
;