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