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