xref: /AOO41X/main/setup_native/source/win32/customactions/patch/swappatchfiles.cxx (revision d3e0dd8eb215533c15e891ee35bd141abe9397ee)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #define _WIN32_WINDOWS 0x0410
25 
26 #ifdef _MSC_VER
27 #pragma warning(push, 1) /* disable warnings within system headers */
28 #endif
29 #define WIN32_LEAN_AND_MEAN
30 #include <windows.h>
31 #include <msiquery.h>
32 #ifdef _MSC_VER
33 #pragma warning(pop)
34 #endif
35 
36 #include <malloc.h>
37 #include <assert.h>
38 
39 #ifdef UNICODE
40 #define _UNICODE
41 #define _tstring    wstring
42 #else
43 #define _tstring    string
44 #endif
45 #include <tchar.h>
46 #include <string>
47 #include <queue>
48 #include <stdio.h>
49 
50 #include <systools/win32/uwinapi.h>
51 #include <../tools/seterror.hxx>
52 
53 #define WININIT_FILENAME    "wininit.ini"
54 #define RENAME_SECTION      "rename"
55 
56 #ifdef DEBUG
OutputDebugStringFormat(LPCTSTR pFormat,...)57 inline void OutputDebugStringFormat( LPCTSTR pFormat, ... )
58 {
59     _TCHAR  buffer[1024];
60     va_list args;
61 
62     va_start( args, pFormat );
63     _vsntprintf( buffer, elementsof(buffer), pFormat, args );
64     OutputDebugString( buffer );
65 }
66 #else
OutputDebugStringFormat(LPCTSTR,...)67 static inline void OutputDebugStringFormat( LPCTSTR, ... )
68 {
69 }
70 #endif
71 
GetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)72 static std::_tstring GetMsiProperty( MSIHANDLE handle, const std::_tstring& sProperty )
73 {
74     std::_tstring   result;
75     TCHAR   szDummy[1] = TEXT("");
76     DWORD   nChars = 0;
77 
78     if ( MsiGetProperty( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA )
79     {
80         DWORD nBytes = ++nChars * sizeof(TCHAR);
81         LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
82         ZeroMemory( buffer, nBytes );
83         MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
84         result = buffer;
85     }
86 
87     return  result;
88 }
89 
90 // The provided GUID must be without surounding '{}'
GetGuidPart(const std::_tstring & guid,int index)91 static std::_tstring GetGuidPart(const std::_tstring& guid, int index)
92 {
93     assert((guid.length() == 36) && "No GUID or wrong format!");
94     assert(((index > -1) && (index < 5)) && "Out of range!");
95 
96     if (index == 0) return std::_tstring(guid.c_str(), 8);
97     if (index == 1) return std::_tstring(guid.c_str() + 9, 4);
98     if (index == 2) return std::_tstring(guid.c_str() + 14, 4);
99     if (index == 3) return std::_tstring(guid.c_str() + 19, 4);
100     if (index == 4) return std::_tstring(guid.c_str() + 24, 12);
101 
102     return std::_tstring();
103 }
104 
Swap(char * p1,char * p2)105 static void Swap(char* p1, char* p2)
106 {
107     char tmp = *p1;
108     *p1 = *p2;
109     *p2 = tmp;
110 }
111 
Invert(const std::_tstring & str)112 static std::_tstring Invert(const std::_tstring& str)
113 {
114     char* buff = reinterpret_cast<char*>(_alloca(str.length()));
115     strncpy(buff, str.c_str(), str.length());
116 
117     char* front = buff;
118     char* back = buff + str.length() - 1;
119 
120     while (front < back)
121         Swap(front++, back--);
122 
123     return std::_tstring(buff, str.length());
124 }
125 
126 // Convert the upgrade code (which is a GUID) according
127 // to the way the windows installer does when writing it
128 // to the registry
129 // The first 8 bytes will be inverted, from the the last
130 // 8 bytes always the nibbles will be inverted for further
131 // details look in the MSDN under compressed registry keys
ConvertGuid(const std::_tstring & guid)132 static std::_tstring ConvertGuid(const std::_tstring& guid)
133 {
134     std::_tstring convertedGuid;
135 
136     std::_tstring part = GetGuidPart(guid, 0);
137     convertedGuid = Invert(part);
138 
139     part = GetGuidPart(guid, 1);
140     convertedGuid += Invert(part);
141 
142     part = GetGuidPart(guid, 2);
143     convertedGuid += Invert(part);
144 
145     part = GetGuidPart(guid, 3);
146     convertedGuid += Invert(std::_tstring(part.c_str(), 2));
147     convertedGuid += Invert(std::_tstring(part.c_str() + 2, 2));
148 
149     part = GetGuidPart(guid, 4);
150     int pos = 0;
151     for (int i = 0; i < 6; i++)
152     {
153         convertedGuid += Invert(std::_tstring(part.c_str() + pos, 2));
154         pos += 2;
155     }
156     return convertedGuid;
157 }
158 
IsSetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)159 static inline bool IsSetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
160 {
161     std::_tstring value = GetMsiProperty(handle, sProperty);
162     return (value.length() > 0);
163 }
164 
UnsetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)165 static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
166 {
167     MsiSetProperty(handle, sProperty.c_str(), NULL);
168 }
169 
SetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)170 static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
171 {
172     MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
173 }
174 
MoveFileEx9x(LPCSTR lpExistingFileNameA,LPCSTR lpNewFileNameA,DWORD dwFlags)175 static BOOL MoveFileEx9x( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
176 {
177     BOOL    fSuccess = FALSE;   // assume failure
178 
179     // Windows 9x has a special mechanism to move files after reboot
180 
181     if ( dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT )
182     {
183         CHAR    szExistingFileNameA[MAX_PATH];
184         CHAR    szNewFileNameA[MAX_PATH] = "NUL";
185 
186         // Path names in WININIT.INI must be in short path name form
187 
188         if (
189             GetShortPathNameA( lpExistingFileNameA, szExistingFileNameA, MAX_PATH ) &&
190             (!lpNewFileNameA || GetShortPathNameA( lpNewFileNameA, szNewFileNameA, MAX_PATH ))
191             )
192         {
193             CHAR    szBuffer[32767];    // The buffer size must not exceed 32K
194             DWORD   dwBufLen = GetPrivateProfileSectionA( RENAME_SECTION, szBuffer, elementsof(szBuffer), WININIT_FILENAME );
195 
196             CHAR    szRename[MAX_PATH]; // This is enough for at most to times 67 chracters
197             strcpy( szRename, szNewFileNameA );
198             strcat( szRename, "=" );
199             strcat( szRename, szExistingFileNameA );
200             size_t  lnRename = strlen(szRename);
201 
202             if ( dwBufLen + lnRename + 2 <= elementsof(szBuffer) )
203             {
204                 CopyMemory( &szBuffer[dwBufLen], szRename, lnRename );
205                 szBuffer[dwBufLen + lnRename ] = 0;
206                 szBuffer[dwBufLen + lnRename + 1 ] = 0;
207 
208                 fSuccess = WritePrivateProfileSectionA( RENAME_SECTION, szBuffer, WININIT_FILENAME );
209             }
210             else
211                 SetLastError( ERROR_BUFFER_OVERFLOW );
212         }
213     }
214     else
215     {
216 
217         fSuccess = MoveFileA( lpExistingFileNameA, lpNewFileNameA );
218 
219         if ( !fSuccess && GetLastError() != ERROR_ACCESS_DENIED &&
220             0 != (dwFlags & (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) )
221         {
222             BOOL    bFailIfExist = 0 == (dwFlags & MOVEFILE_REPLACE_EXISTING);
223 
224             fSuccess = CopyFileA( lpExistingFileNameA, lpNewFileNameA, bFailIfExist );
225 
226             if ( fSuccess )
227                 fSuccess = DeleteFileA( lpExistingFileNameA );
228         }
229 
230     }
231 
232     return fSuccess;
233 }
234 
MoveFileExImpl(LPCSTR lpExistingFileNameA,LPCSTR lpNewFileNameA,DWORD dwFlags)235 static BOOL MoveFileExImpl( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
236 {
237     if ( 0 > ((LONG)GetVersion())) // High order bit indicates Win 9x
238         return MoveFileEx9x( lpExistingFileNameA, lpNewFileNameA, dwFlags );
239     else
240         return MoveFileExA( lpExistingFileNameA, lpNewFileNameA, dwFlags );
241 }
242 
SwapFiles(const std::_tstring & sFileName1,const std::_tstring & sFileName2)243 static bool SwapFiles( const std::_tstring& sFileName1, const std::_tstring& sFileName2 )
244 {
245     std::_tstring   sTempFileName = sFileName1 + TEXT(".tmp");
246 
247     bool fSuccess = true;
248 
249     //Try to move the original file to a temp file
250     fSuccess = MoveFileExImpl( sFileName1.c_str(), sTempFileName.c_str(), MOVEFILE_REPLACE_EXISTING);
251 
252     std::_tstring   mystr;
253 
254     if ( fSuccess )
255     {
256         fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
257 
258         if ( fSuccess )
259         {
260             fSuccess = MoveFileExImpl( sTempFileName.c_str(), sFileName2.c_str(),
261                                         MOVEFILE_REPLACE_EXISTING );
262             if ( !fSuccess )
263             {
264                 MoveFileExImpl( sFileName1.c_str(), sFileName2.c_str(), MOVEFILE_REPLACE_EXISTING );
265             }
266         }
267         else
268         {
269             MoveFileExImpl( sTempFileName.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING  );
270         }
271     }
272     else
273     {
274         //It could be that there is no original file and therefore copying the original to a temp
275         // file failed. Examine if there is no original and if so then move file2 to file1
276 
277         WIN32_FIND_DATA data;
278         HANDLE hdl = FindFirstFile(sFileName1.c_str(), &data);
279         if (hdl == INVALID_HANDLE_VALUE)
280         {
281             fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
282 
283             // if ( fSuccess )
284             // {
285             //  mystr = "Success";
286             //  MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
287             // }
288             // else
289             // {
290             //  char buff[256];
291             //  wsprintf(buff, "Failure %d", GetLastError());
292             //  MessageBox( NULL, buff, "Titel", MB_OK );
293             // }
294         }
295         else
296         {
297             FindClose(hdl);
298         }
299     }
300 
301     OutputDebugStringFormat( TEXT("%s <-> %s: %s"), sFileName1.c_str(), sFileName2.c_str(), fSuccess ? TEXT("OK") : TEXT("FAILED") );
302 
303     if (!fSuccess )
304     {
305         DWORD   dwError = GetLastError();
306         LPVOID lpMsgBuf;
307         if ( FormatMessage(
308             FORMAT_MESSAGE_ALLOCATE_BUFFER |
309             FORMAT_MESSAGE_FROM_SYSTEM |
310             FORMAT_MESSAGE_IGNORE_INSERTS,
311             NULL,
312             GetLastError(),
313             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
314             (LPTSTR) &lpMsgBuf,
315             0,
316             NULL ))
317         {
318             OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError, lpMsgBuf );
319             LocalFree( lpMsgBuf );
320         }
321         else
322             OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError );
323         SetMsiErrorCode( dwError );
324     }
325 
326     return fSuccess;
327 }
328 
strip(const std::_tstring & s,_TCHAR c)329 static std::_tstring strip( const std::_tstring& s, _TCHAR c )
330 {
331     std::_tstring   result = s;
332 
333     std::_tstring::size_type f;
334 
335     do
336     {
337         f = result.find( c );
338         if ( f != std::_tstring::npos )
339             result.erase( f, 1 );
340     } while ( f != std::_tstring::npos );
341 
342     return result;
343 }
344 
trim(const std::_tstring & rString)345 static std::_tstring trim( const std::_tstring& rString )
346 {
347     std::_tstring temp = rString;
348 
349     while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' )
350         temp.erase( 0, 1 );
351 
352     std::_tstring::size_type    len = temp.length();
353 
354     while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' )
355     {
356         temp.erase( len - 1, 1 );
357         len = temp.length();
358     }
359 
360     return temp;
361 }
362 
readLine(FILE * fp,std::_tstring & rLine)363 static bool readLine( FILE *fp, std::_tstring& rLine )
364 {
365     _TCHAR szBuffer[1024];
366     bool    bSuccess = false;
367     bool    bEOL = false;
368     std::_tstring   line;
369 
370 
371     while ( !bEOL && _fgetts( szBuffer, sizeof(szBuffer), fp ) )
372     {
373         int len = _tcslen(szBuffer);
374 
375         bSuccess = true;
376 
377         while ( len && szBuffer[len - 1] == '\n' )
378         {
379             szBuffer[--len] = 0;
380             bEOL = true;
381         }
382 
383         line.append( szBuffer );
384     }
385 
386     rLine = line;
387     return bSuccess;
388 }
389 
390 
getProfileString(const std::_tstring & aFileName,const std::_tstring & aSectionName,const std::_tstring & aKeyName,const std::_tstring & aDefault=_T (""))391 static std::_tstring getProfileString(
392     const std::_tstring& aFileName,
393     const std::_tstring& aSectionName,
394     const std::_tstring& aKeyName,
395     const std::_tstring& aDefault = _T("") )
396 {
397     FILE    *fp = _tfopen( aFileName.c_str(), _T("r") );
398     std::_tstring   retValue = aDefault.length() ? aDefault : _T("");
399 
400     if ( fp )
401     {
402         std::_tstring line;
403         std::_tstring section;
404 
405         while ( readLine( fp, line ) )
406         {
407             line = trim( line );
408 
409             if ( line.length() && line[0] == '[' )
410             {
411                 line.erase( 0, 1 );
412                 std::_tstring::size_type end = line.find( ']', 0 );
413 
414                 if ( std::_tstring::npos != end )
415                     section = trim( line.substr( 0, end ) );
416             }
417             else
418             {
419 
420                 std::_tstring::size_type iEqualSign = line.find( '=', 0 );
421 
422                 if ( iEqualSign != std::_tstring::npos )
423                 {
424                     std::_tstring   keyname = line.substr( 0, iEqualSign );
425                     keyname = trim( keyname );
426 
427                     std::_tstring   value = line.substr( iEqualSign + 1 /*, std::_tstring::npos */ );
428                     value = trim( value );
429 
430                     if (
431                         0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) &&
432                         0 == _tcsicmp( keyname.c_str(), aKeyName.c_str() )
433                          )
434                     {
435                         retValue = value;
436                         break;
437                     }
438                 }
439             }
440         }
441 
442         fclose( fp );
443     }
444 
445     return retValue;
446 }
447 
getProfileSections(const std::_tstring & aFileName)448 static std::queue< std::_tstring > getProfileSections( const std::_tstring& aFileName )
449 {
450     FILE    *fp = _tfopen( aFileName.c_str(), _T("r") );
451     std::queue< std::_tstring > aResult;
452 
453     OutputDebugStringFormat( TEXT("*** Retrieving Section Names ****") );
454 
455     if ( fp )
456     {
457         std::_tstring line;
458         std::_tstring section;
459 
460         while ( readLine( fp, line ) )
461         {
462             line = trim( line );
463 
464             if ( line.length() && line[0] == '[' )
465             {
466                 line.erase( 0, 1 );
467                 std::_tstring::size_type end = line.find( ']', 0 );
468 
469                 if ( std::_tstring::npos != end )
470                     section = trim( line.substr( 0, end ) );
471 
472                 aResult.push( section );
473 
474                 OutputDebugStringFormat( TEXT("Section: %s"), section.c_str() );
475 
476             }
477         }
478 
479         fclose( fp );
480     }
481 
482     OutputDebugStringFormat( TEXT("*** Done Section Names ***") );
483 
484     return aResult;
485 }
486 
getProfileKeys(const std::_tstring & aFileName,const std::_tstring & aSectionName)487 static std::queue< std::_tstring > getProfileKeys( const std::_tstring& aFileName, const std::_tstring& aSectionName )
488 {
489     FILE    *fp = _tfopen( aFileName.c_str(), _T("r") );
490     std::queue< std::_tstring > aResult;
491 
492     OutputDebugStringFormat( TEXT("*** Retrieving Key Names for [%s] ***"), aSectionName.c_str() );
493 
494     if ( fp )
495     {
496         std::_tstring line;
497         std::_tstring section;
498 
499         while ( readLine( fp, line ) )
500         {
501             line = trim( line );
502 
503             if ( line.length() && line[0] == '[' )
504             {
505                 line.erase( 0, 1 );
506                 std::_tstring::size_type end = line.find( ']', 0 );
507 
508                 if ( std::_tstring::npos != end )
509                     section = trim( line.substr( 0, end ) );
510             }
511             else
512             {
513 
514                 std::_tstring::size_type iEqualSign = line.find( '=', 0 );
515 
516                 if ( iEqualSign != std::_tstring::npos )
517                 {
518                     std::_tstring   keyname = line.substr( 0, iEqualSign );
519                     keyname = trim( keyname );
520 
521                     if ( 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) )
522                     {
523                         aResult.push( keyname );
524 
525                         OutputDebugStringFormat( keyname.c_str() );
526 
527                     }
528                 }
529             }
530         }
531 
532         fclose( fp );
533     }
534 
535     OutputDebugStringFormat( TEXT("*** Done Key Names for [%s] ***"), aSectionName.c_str() );
536 
537     return aResult;
538 }
539 
InstallPatchedFiles(MSIHANDLE handle)540 extern "C" UINT __stdcall InstallPatchedFiles( MSIHANDLE handle )
541 {
542     std::_tstring   sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
543 //  std::_tstring   sProgramDir = sInstDir + TEXT("Basis\\program\\");
544     std::_tstring   sProgramDir = sInstDir + TEXT("program\\");
545     std::_tstring   sPatchFile = sProgramDir + TEXT("patchlist.txt");
546 
547     std::queue< std::_tstring > aSectionNames;
548     std::queue< std::_tstring > aKeyNames;
549 
550     OutputDebugStringA( "Starting Custom Action" );
551 
552     // std::_tstring    mystr;
553     // mystr = "Patchfile: " + sPatchFile;
554     // MessageBox( NULL, mystr.c_str(), "Patchfile", MB_OK );
555 
556     aSectionNames = getProfileSections( sPatchFile );
557     while ( !aSectionNames.empty() )
558     {
559         std::_tstring   sSectionName = aSectionNames.front();
560         if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
561         // mystr = "Section: " + sSectionName;
562         // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
563 
564         aKeyNames = getProfileKeys( sPatchFile, sSectionName );
565         while ( !aKeyNames.empty() )
566         {
567             std::_tstring   sKeyName = aKeyNames.front();
568             std::_tstring   sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
569 
570             if ( sValue.length() )
571             {
572                 std::_tstring   sFileName1 = sKeyName;
573                 std::_tstring   sExtension = sValue;
574                 std::_tstring   sFileName2;
575 
576                 sFileName1 = strip( sFileName1, '\"' );
577                 sExtension = strip( sExtension, '\"' );
578 
579                 sFileName1 = sInstDir + sSectionName + sFileName1;
580                 sFileName2 = sFileName1 + sExtension;
581 
582                 // mystr = "Convert: " + sFileName1 + " to " + sFileName2;
583                 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
584 
585                 SwapFiles( sFileName1, sFileName2 );
586             }
587 
588             aKeyNames.pop();
589         }
590 
591         aSectionNames.pop();
592     }
593 
594     return ERROR_SUCCESS;
595 }
596 
UninstallPatchedFiles(MSIHANDLE handle)597 extern "C" UINT __stdcall UninstallPatchedFiles( MSIHANDLE handle )
598 {
599     TCHAR   szValue[8192];
600     DWORD   nValueSize = sizeof(szValue);
601     HKEY    hKey;
602 
603     std::_tstring   sInstDir;
604 
605     std::_tstring   sProductKey = GetMsiProperty( handle, TEXT("FINDPRODUCT") );
606 
607     if ( ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER,  sProductKey.c_str(), &hKey ) )
608     {
609         if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
610         {
611             sInstDir = szValue;
612         }
613         RegCloseKey( hKey );
614     }
615     else if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE,  sProductKey.c_str(), &hKey ) )
616     {
617         if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
618         {
619             sInstDir = szValue;
620         }
621         RegCloseKey( hKey );
622     }
623     else
624         return ERROR_SUCCESS;
625 
626 //  std::_tstring   sProgramDir = sInstDir + TEXT("Basis\\program\\");
627     std::_tstring   sProgramDir = sInstDir + TEXT("program\\");
628     std::_tstring   sPatchFile = sProgramDir + TEXT("patchlist.txt");
629 
630     std::queue< std::_tstring > aSectionNames;
631     std::queue< std::_tstring > aKeyNames;
632 
633     // std::_tstring    mystr;
634     // mystr = "Patchfile: " + sPatchFile;
635     // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
636 
637     aSectionNames = getProfileSections( sPatchFile );
638     while ( !aSectionNames.empty() )
639     {
640         std::_tstring   sSectionName = aSectionNames.front();
641         if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
642         // mystr = "Section: " + sSectionName;
643         // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
644 
645         aKeyNames = getProfileKeys( sPatchFile, sSectionName );
646         while( !aKeyNames.empty() )
647         {
648             std::_tstring   sKeyName = aKeyNames.front();
649             std::_tstring   sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
650 
651             if ( sValue.length() )
652             {
653                 std::_tstring   sFileName1 = sKeyName;
654                 std::_tstring   sExtension = sValue;
655                 std::_tstring   sFileName2;
656 
657                 sFileName1 = strip( sFileName1, '\"' );
658                 sExtension = strip( sExtension, '\"' );
659 
660                 sFileName1 = sInstDir + sSectionName + sFileName1;
661                 sFileName2 = sFileName1 + sExtension;
662 
663                 // mystr = "Convert: " + sFileName1 + " to " + sFileName2;
664                 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
665 
666                 SwapFiles( sFileName2, sFileName1 );
667             }
668 
669             aKeyNames.pop();
670         }
671 
672         aSectionNames.pop();
673     }
674 
675     return ERROR_SUCCESS;
676 }
677 
IsOfficeRunning(MSIHANDLE handle)678 extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle )
679 {
680     std::_tstring   sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
681 //  std::_tstring   sResourceDir = sInstDir + TEXT("Basis\\program\\resource\\");
682     std::_tstring   sResourceDir = sInstDir + TEXT("program\\resource\\");
683     std::_tstring   sPattern = sResourceDir + TEXT("vcl*.res");
684 
685     WIN32_FIND_DATA aFindFileData;
686     HANDLE  hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
687 
688     if ( IsValidHandle(hFind) )
689     {
690         BOOL    fSuccess = false;
691         bool    fRenameSucceeded;
692 
693         do
694         {
695             std::_tstring   sResourceFile = sResourceDir + aFindFileData.cFileName;
696             std::_tstring   sIntermediate = sResourceFile + TEXT(".tmp");
697 
698             fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING );
699             if ( fRenameSucceeded )
700             {
701                 MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 );
702                 fSuccess = FindNextFile( hFind, &aFindFileData );
703             }
704         } while ( fSuccess && fRenameSucceeded );
705 
706         if ( !fRenameSucceeded )
707         {
708             MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1"));
709             SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING );
710         }
711 
712         FindClose( hFind );
713     }
714 
715 
716     return ERROR_SUCCESS;
717 }
718 
SetFeatureState(MSIHANDLE handle)719 extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle )
720 {
721     std::_tstring   mystr;
722 
723     // 1. Reading Product Code from setup.ini of installed Office
724 
725     std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
726     // MessageBox(NULL, sInstallPath.c_str(), "INSTALLLOCATION", MB_OK);
727     std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini");
728 
729     TCHAR szProductCode[32767];
730 
731     GetPrivateProfileString(
732         TEXT("Bootstrap"),
733         TEXT("ProductCode"),
734         TEXT("NOTFOUND"),
735         szProductCode,
736         elementsof(szProductCode),
737         sSetupiniPath.c_str()
738         );
739 
740     if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) )
741     {
742         // No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory.
743         // MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK);
744         return ERROR_SUCCESS;
745     }
746 
747     // 2. Converting Product code
748 
749     std::_tstring productCode = TEXT(szProductCode);
750     productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2));
751     mystr = TEXT("Changed product code: ") + productCode;
752     // MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK);
753 
754     // 3. Setting path in the Windows registry to find installed features
755 
756     std::_tstring registryKey;
757     HKEY registryRoot;
758 
759     if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) )
760     {
761         registryRoot = HKEY_LOCAL_MACHINE;
762         registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode;
763         mystr = registryKey;
764         // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
765     }
766     else
767     {
768         registryRoot = HKEY_CURRENT_USER;
769         registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode;
770         mystr = registryKey;
771         // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
772     }
773 
774     // 4. Collecting all installed features from Windows registry
775 
776     HKEY hKey;
777     if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS)
778     {
779         int counter = 0;
780         // DWORD counter = 0;
781         LONG lEnumResult;
782 
783         do
784         {
785             TCHAR szValueName[8192];
786             DWORD nValueNameSize = sizeof(szValueName);
787             LPDWORD pValueNameSize = &nValueNameSize;
788             TCHAR szValueData[8192];
789             DWORD nValueDataSize = sizeof(szValueData);
790 
791             lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize);
792 
793             if ( ERROR_SUCCESS == lEnumResult )
794             {
795                 std::_tstring sValueName = szValueName;
796                 std::_tstring sValueData = szValueData;
797 
798                 // mystr = sValueName;
799                 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
800                 // mystr = sValueData;
801                 // MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK );
802 
803                 // Does this feature exist in this patch?
804                 if ( IsSetMsiProperty(handle, sValueName) )
805                 {
806                     // Feature is not installed, if szValueData starts with a "square" (ascii 6)
807                     if ( 6 == szValueData[0] )
808                     {
809                         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
810                         // mystr = TEXT("Do NOT install: ") + sValueName;
811                         // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
812                     }
813                     else
814                     {
815                         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
816                         // mystr = TEXT("Do install: ") + sValueName;
817                         // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
818                     }
819                 }
820             }
821 
822             counter = counter + 1;
823 
824         } while ( ERROR_SUCCESS == lEnumResult );
825 
826         RegCloseKey( hKey );
827     }
828 
829     return ERROR_SUCCESS;
830 }
831 
SetNewFeatureState(MSIHANDLE handle)832 extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle )
833 {
834     std::_tstring mystr;
835     std::_tstring sValueName;
836 
837     sValueName = TEXT("gm_o_Onlineupdate");
838 
839     if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")))
840     {
841         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
842         // mystr = TEXT("OnlineUpdate wird installiert!");
843         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK);
844     }
845     else
846     {
847         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
848         // mystr = TEXT("OnlineUpdate wird NICHT installiert!");
849         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK);
850     }
851 
852     return ERROR_SUCCESS;
853 }
854 
ShowOnlineUpdateDialog(MSIHANDLE handle)855 extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle )
856 {
857     // Checking existence of file "updchk.uno.dll", which shows, that
858     // Online Update functionality is always available. Then the dialog
859     // that offers the Online Update is superfluous.
860 
861     std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
862 //    std::_tstring sProgramDir = sInstDir + TEXT("Basis\\program\\");
863     std::_tstring sProgramDir = sInstDir + TEXT("program\\");
864     std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll");
865 
866     WIN32_FIND_DATA data;
867     HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data);
868     if (hdl != INVALID_HANDLE_VALUE)  // the file exists
869     {
870         // std::_tstring mystr;
871         // mystr = "Found file: " + sSearchFile;
872         // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK );
873 
874         // And finally setting property SHOW_ONLINEUPDATE_DIALOG
875         // to hide this dialog
876         UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
877 
878         // Setting SELECT_OU_FEATURE to 1, which is probably superfluous
879         // because this is already the default value. But only this
880         // guarantees, that CustomAction SetNewFeatureState always sets
881         // the correct FeatureState for "gm_o_Onlineupdate", if it is
882         // already installed.
883         SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"));
884     }
885     else
886     {
887         // std::_tstring mystr;
888         // mystr = "Did not find file: " + sSearchFile;
889         // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK );
890 
891         // If the file does not exist, the Online Update dialog
892         // has to be shown.
893         SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
894         FindClose(hdl);
895     }
896 
897     return ERROR_SUCCESS;
898 }
899