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 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 67 static inline void OutputDebugStringFormat( LPCTSTR, ... ) 68 { 69 } 70 #endif 71 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 '{}' 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 105 static void Swap(char* p1, char* p2) 106 { 107 char tmp = *p1; 108 *p1 = *p2; 109 *p2 = tmp; 110 } 111 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 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 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 165 static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) 166 { 167 MsiSetProperty(handle, sProperty.c_str(), NULL); 168 } 169 170 static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) 171 { 172 MsiSetProperty(handle, sProperty.c_str(), TEXT("1")); 173 } 174 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 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 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 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 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 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 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 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 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 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 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 sPatchFile = sProgramDir + TEXT("patchlist.txt"); 628 629 std::queue< std::_tstring > aSectionNames; 630 std::queue< std::_tstring > aKeyNames; 631 632 // std::_tstring mystr; 633 // mystr = "Patchfile: " + sPatchFile; 634 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); 635 636 aSectionNames = getProfileSections( sPatchFile ); 637 while ( !aSectionNames.empty() ) 638 { 639 std::_tstring sSectionName = aSectionNames.front(); 640 if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); } 641 // mystr = "Section: " + sSectionName; 642 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); 643 644 aKeyNames = getProfileKeys( sPatchFile, sSectionName ); 645 while( !aKeyNames.empty() ) 646 { 647 std::_tstring sKeyName = aKeyNames.front(); 648 std::_tstring sValue = getProfileString( sPatchFile, sSectionName, sKeyName ); 649 650 if ( sValue.length() ) 651 { 652 std::_tstring sFileName1 = sKeyName; 653 std::_tstring sExtension = sValue; 654 std::_tstring sFileName2; 655 656 sFileName1 = strip( sFileName1, '\"' ); 657 sExtension = strip( sExtension, '\"' ); 658 659 sFileName1 = sInstDir + sSectionName + sFileName1; 660 sFileName2 = sFileName1 + sExtension; 661 662 // mystr = "Convert: " + sFileName1 + " to " + sFileName2; 663 // MessageBox( NULL, mystr.c_str(), "Titel", MB_OK ); 664 665 SwapFiles( sFileName2, sFileName1 ); 666 } 667 668 aKeyNames.pop(); 669 } 670 671 aSectionNames.pop(); 672 } 673 674 return ERROR_SUCCESS; 675 } 676 677 extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle ) 678 { 679 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") ); 680 std::_tstring sResourceDir = sInstDir + TEXT("Basis\\program\\resource\\"); 681 std::_tstring sPattern = sResourceDir + TEXT("vcl*.res"); 682 683 WIN32_FIND_DATA aFindFileData; 684 HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData ); 685 686 if ( IsValidHandle(hFind) ) 687 { 688 BOOL fSuccess = false; 689 bool fRenameSucceeded; 690 691 do 692 { 693 std::_tstring sResourceFile = sResourceDir + aFindFileData.cFileName; 694 std::_tstring sIntermediate = sResourceFile + TEXT(".tmp"); 695 696 fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING ); 697 if ( fRenameSucceeded ) 698 { 699 MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 ); 700 fSuccess = FindNextFile( hFind, &aFindFileData ); 701 } 702 } while ( fSuccess && fRenameSucceeded ); 703 704 if ( !fRenameSucceeded ) 705 { 706 MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1")); 707 SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING ); 708 } 709 710 FindClose( hFind ); 711 } 712 713 714 return ERROR_SUCCESS; 715 } 716 717 extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle ) 718 { 719 std::_tstring mystr; 720 721 // 1. Reading Product Code from setup.ini of installed Office 722 723 std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION")); 724 // MessageBox(NULL, sInstallPath.c_str(), "INSTALLLOCATION", MB_OK); 725 std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini"); 726 727 TCHAR szProductCode[32767]; 728 729 GetPrivateProfileString( 730 TEXT("Bootstrap"), 731 TEXT("ProductCode"), 732 TEXT("NOTFOUND"), 733 szProductCode, 734 elementsof(szProductCode), 735 sSetupiniPath.c_str() 736 ); 737 738 if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) ) 739 { 740 // No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory. 741 // MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK); 742 return ERROR_SUCCESS; 743 } 744 745 // 2. Converting Product code 746 747 std::_tstring productCode = TEXT(szProductCode); 748 productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2)); 749 mystr = TEXT("Changed product code: ") + productCode; 750 // MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK); 751 752 // 3. Setting path in the Windows registry to find installed features 753 754 std::_tstring registryKey; 755 HKEY registryRoot; 756 757 if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) ) 758 { 759 registryRoot = HKEY_LOCAL_MACHINE; 760 registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode; 761 mystr = registryKey; 762 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK ); 763 } 764 else 765 { 766 registryRoot = HKEY_CURRENT_USER; 767 registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode; 768 mystr = registryKey; 769 // MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK ); 770 } 771 772 // 4. Collecting all installed features from Windows registry 773 774 HKEY hKey; 775 if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS) 776 { 777 int counter = 0; 778 // DWORD counter = 0; 779 LONG lEnumResult; 780 781 do 782 { 783 TCHAR szValueName[8192]; 784 DWORD nValueNameSize = sizeof(szValueName); 785 LPDWORD pValueNameSize = &nValueNameSize; 786 TCHAR szValueData[8192]; 787 DWORD nValueDataSize = sizeof(szValueData); 788 789 lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize); 790 791 if ( ERROR_SUCCESS == lEnumResult ) 792 { 793 std::_tstring sValueName = szValueName; 794 std::_tstring sValueData = szValueData; 795 796 // mystr = sValueName; 797 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); 798 // mystr = sValueData; 799 // MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK ); 800 801 // Does this feature exist in this patch? 802 if ( IsSetMsiProperty(handle, sValueName) ) 803 { 804 // Feature is not installed, if szValueData starts with a "square" (ascii 6) 805 if ( 6 == szValueData[0] ) 806 { 807 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature 808 // mystr = TEXT("Do NOT install: ") + sValueName; 809 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); 810 } 811 else 812 { 813 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature 814 // mystr = TEXT("Do install: ") + sValueName; 815 // MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK ); 816 } 817 } 818 } 819 820 counter = counter + 1; 821 822 } while ( ERROR_SUCCESS == lEnumResult ); 823 824 RegCloseKey( hKey ); 825 } 826 827 return ERROR_SUCCESS; 828 } 829 830 extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle ) 831 { 832 std::_tstring mystr; 833 std::_tstring sValueName; 834 835 sValueName = TEXT("gm_o_Onlineupdate"); 836 837 if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"))) 838 { 839 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature 840 // mystr = TEXT("OnlineUpdate wird installiert!"); 841 // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK); 842 } 843 else 844 { 845 MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature 846 // mystr = TEXT("OnlineUpdate wird NICHT installiert!"); 847 // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK); 848 } 849 850 return ERROR_SUCCESS; 851 } 852 853 extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle ) 854 { 855 // Checking existence of file "updchk.uno.dll", which shows, that 856 // Online Update functionality is always available. Then the dialog 857 // that offers the Online Update is superfluous. 858 859 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") ); 860 std::_tstring sProgramDir = sInstDir + TEXT("Basis\\program\\"); 861 std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll"); 862 863 WIN32_FIND_DATA data; 864 HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data); 865 if (hdl != INVALID_HANDLE_VALUE) // the file exists 866 { 867 // std::_tstring mystr; 868 // mystr = "Found file: " + sSearchFile; 869 // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK ); 870 871 // And finally setting property SHOW_ONLINEUPDATE_DIALOG 872 // to hide this dialog 873 UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG")); 874 875 // Setting SELECT_OU_FEATURE to 1, which is probably superfluous 876 // because this is already the default value. But only this 877 // guarantees, that CustomAction SetNewFeatureState always sets 878 // the correct FeatureState for "gm_o_Onlineupdate", if it is 879 // already installed. 880 SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")); 881 } 882 else 883 { 884 // std::_tstring mystr; 885 // mystr = "Did not find file: " + sSearchFile; 886 // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK ); 887 888 // If the file does not exist, the Online Update dialog 889 // has to be shown. 890 SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG")); 891 FindClose(hdl); 892 } 893 894 return ERROR_SUCCESS; 895 } 896