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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_desktop.hxx" 24 25 #define UNICODE 1 26 #define _UNICODE 1 27 28 #define WIN // scope W32 API 29 30 #if defined _MSC_VER 31 #pragma warning(push, 1) 32 #endif 33 #include <windows.h> 34 #if defined _MSC_VER 35 #pragma warning(pop) 36 #endif 37 #include <tchar.h> 38 #include <assert.h> 39 #include <shlwapi.h> 40 #include <new> 41 #include <time.h> 42 #include <mbctype.h> 43 #include <locale.h> 44 #include <Msiquery.h> 45 #include <MsiDefs.h> 46 #include "strsafe.h" 47 48 #include "setup.hxx" 49 #include "aoo_msi.hxx" 50 51 #include "resource.h" 52 53 //-------------------------------------------------------------------------- 54 55 #define MAX_STR_LENGTH 32000 56 #define MAX_TEXT_LENGTH 1024 57 #define MAX_LANGUAGE_LEN 80 58 #define MAX_STR_CAPTION 256 59 #define VERSION_SIZE 80 60 #define SECTION_SETUP TEXT( "Setup" ) 61 #define SECTION_LANGUAGE TEXT( "Languages" ) 62 #define PRODUCT_NAME_VAR TEXT( "%PRODUCTNAME" ) 63 #define PRODUCT_VERSION TEXT( "ProductVersion" ) 64 #define ERROR_SHOW_USAGE -2 65 #define ERROR_SETUP_TO_OLD -3 66 #define ERROR_SETUP_NOT_FOUND -4 67 68 #define PARAM_SETUP_USED TEXT( " SETUP_USED=1 " ) 69 #define PARAM_PACKAGE TEXT( "/I " ) 70 #define PARAM_MINOR_UPGRADE TEXT( "/FVOMUS " ) 71 #define PARAM_ADMIN TEXT( "/A " ) 72 #define PARAM_TRANSFORM TEXT( " TRANSFORMS=" ) 73 #define PARAM_REBOOT TEXT( " REBOOT=Force" ) 74 #define PARAM_PATCH TEXT( " /update " ) 75 #define PARAM_REG_ALL_MSO_TYPES TEXT( "REGISTER_ALL_MSO_TYPES=1 " ) 76 #define PARAM_REG_NO_MSO_TYPES TEXT( "REGISTER_NO_MSO_TYPES=1 " ) 77 #define PARAM_SILENTINSTALL TEXT( " /Q" ) 78 79 #define PARAM_RUNNING TEXT( "ignore_running" ) 80 #define CMDLN_REG_ALL_MSO_TYPES TEXT( "msoreg=1" ) 81 #define CMDLN_REG_NO_MSO_TYPES TEXT( "msoreg=0" ) 82 83 #define ADVAPI32_DLL TEXT( "advapi32.dll" ) 84 #define PROFILE_NAME TEXT( "setup.ini" ) 85 86 #define RUNTIME_X64_NAME TEXT( "redist\\vcredist_x64.exe" ) 87 #define RUNTIME_X86_NAME TEXT( "redist\\vcredist_x86.exe" ) 88 // Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.6161 89 #define PRODUCTCODE_X86 TEXT( "{9BE518E6-ECC6-35A9-88E4-87755C07200F}" ) 90 // Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161 91 #define PRODUCTCODE_X64 TEXT( "{5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}" ) 92 93 #define ADVAPI32API_CheckTokenMembership "CheckTokenMembership" 94 95 typedef BOOL (WINAPI* PFnCheckTokenMembership)(HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember); 96 97 #ifdef DEBUG 98 inline void OutputDebugStringFormat( LPCTSTR pFormat, ... ) 99 { 100 TCHAR buffer[1024]; 101 va_list args; 102 103 va_start( args, pFormat ); 104 StringCchVPrintf( buffer, sizeof(buffer), pFormat, args ); 105 OutputDebugString( buffer ); 106 } 107 #else 108 static inline void OutputDebugStringFormat( LPCTSTR, ... ) 109 { 110 } 111 #endif 112 113 //-------------------------------------------------------------------------- 114 115 const TCHAR sMsiExe[] = TEXT( "\\msiexec.exe" ); 116 const TCHAR sDelayReboot[] = TEXT( " /c:\"msiinst /delayreboot\"" ); 117 const TCHAR sMsiQuiet[] = TEXT( " /q" ); 118 const TCHAR sMemMapName[] = TEXT( "Global\\MsiErrorObject" ); 119 120 //-------------------------------------------------------------------------- 121 SetupApp::SetupApp() 122 { 123 m_uiRet = ERROR_SUCCESS; 124 125 // Get OS version 126 OSVERSIONINFO sInfoOS; 127 128 ZeroMemory( &sInfoOS, sizeof(OSVERSIONINFO) ); 129 sInfoOS.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); 130 131 GetVersionEx( &sInfoOS ); 132 133 m_nOSVersion = sInfoOS.dwMajorVersion; 134 m_nMinorVersion = sInfoOS.dwMinorVersion; 135 m_bIsWin9x = ( VER_PLATFORM_WIN32_NT != sInfoOS.dwPlatformId ); 136 m_bNeedReboot = false; 137 m_bAdministrative = false; 138 139 m_hInst = NULL; 140 m_hMapFile = NULL; 141 m_pAppTitle = NULL; 142 m_pCmdLine = NULL; 143 144 m_pDatabase = NULL; 145 m_pReqVersion = NULL; 146 m_pProductName = NULL; 147 m_pAdvertise = NULL; 148 m_pTmpName = NULL; 149 m_pLogFile = NULL; 150 m_pModuleFile = NULL; 151 m_pPatchFiles = NULL; 152 m_pMSIErrorCode = NULL; 153 m_pUpgradeKey = NULL; 154 m_pProductVersion = NULL; 155 156 m_pErrorText = new TCHAR[ MAX_TEXT_LENGTH ]; 157 m_pErrorText[0] = '\0'; 158 159 m_nLanguageID = 0; 160 m_nLanguageCount = 0; 161 m_ppLanguageList = NULL; 162 163 m_bQuiet = false; 164 m_bRegNoMsoTypes = false; 165 m_bRegAllMsoTypes = false; 166 m_bIsMinorUpgrade = false; 167 m_bSupportsPatch = false; 168 169 m_bIgnoreAlreadyRunning = false; 170 } 171 172 //-------------------------------------------------------------------------- 173 SetupApp::~SetupApp() 174 { 175 if ( m_ppLanguageList ) 176 { 177 for ( int i = 0; i < m_nLanguageCount; i++ ) 178 if ( m_ppLanguageList[i] ) 179 delete m_ppLanguageList[ i ]; 180 delete [] m_ppLanguageList; 181 } 182 183 time_t aTime; 184 time( &aTime ); 185 tm *pTime = localtime( &aTime ); // Convert time to struct tm form 186 187 Log( TEXT( "End: %s\n\r\n\r\n" ), _tasctime( pTime ) ); 188 189 if ( m_pLogFile ) fclose( m_pLogFile ); 190 191 if ( m_pTmpName ) 192 { 193 _tremove( m_pTmpName ); 194 free( m_pTmpName ); 195 } 196 197 if ( m_pMSIErrorCode ) UnmapViewOfFile( m_pMSIErrorCode ); 198 if ( m_hMapFile ) CloseHandle( m_hMapFile ); 199 200 if ( m_pAppTitle ) delete [] m_pAppTitle; 201 if ( m_pDatabase ) delete [] m_pDatabase; 202 if ( m_pReqVersion ) delete [] m_pReqVersion; 203 if ( m_pProductName ) delete [] m_pProductName; 204 if ( m_pAdvertise ) delete [] m_pAdvertise; 205 if ( m_pLogFile ) delete [] m_pLogFile; 206 if ( m_pErrorText ) delete [] m_pErrorText; 207 if ( m_pModuleFile ) delete [] m_pModuleFile; 208 if ( m_pPatchFiles ) delete [] m_pPatchFiles; 209 if ( m_pUpgradeKey ) delete [] m_pUpgradeKey; 210 if ( m_pProductVersion ) delete [] m_pProductVersion; 211 } 212 213 //-------------------------------------------------------------------------- 214 boolean SetupApp::Initialize( HINSTANCE hInst ) 215 { 216 m_pCmdLine = WIN::GetCommandLine(); 217 m_hInst = hInst; 218 219 // Load our AppTitle (caption) 220 m_pAppTitle = new TCHAR[ MAX_STR_CAPTION ]; 221 m_pAppTitle[0] = '\0'; 222 WIN::LoadString( hInst, IDS_APP_TITLE, m_pAppTitle, MAX_STR_CAPTION ); 223 224 // Obtain path we are running from 225 m_pModuleFile = new TCHAR[ MAX_PATH ]; 226 m_pModuleFile[ 0 ] = '\0'; 227 228 if ( 0 == WIN::GetModuleFileName( hInst, m_pModuleFile, MAX_PATH ) ) 229 { 230 SetError( WIN::GetLastError() ); 231 return false; 232 } 233 234 if ( ! GetCmdLineParameters( &m_pCmdLine ) ) 235 return false; 236 237 m_hMapFile = CreateFileMapping( 238 INVALID_HANDLE_VALUE, // use paging file 239 NULL, // default security 240 PAGE_READWRITE, // read/write access 241 0, // max. object size 242 sizeof( int ), // buffer size 243 sMemMapName ); 244 if ( m_hMapFile ) 245 { 246 m_pMSIErrorCode = (int*) MapViewOfFile( m_hMapFile, // handle to map object 247 FILE_MAP_ALL_ACCESS, // read/write permission 248 0, 249 0, 250 sizeof( int ) ); 251 if ( m_pMSIErrorCode ) 252 *m_pMSIErrorCode = 0; 253 else 254 OutputDebugStringFormat( TEXT("Could not map view of file (%d).\n"), GetLastError() ); 255 } 256 else 257 OutputDebugStringFormat( TEXT("Could not create file mapping object (%d).\n"), GetLastError() ); 258 259 Log( TEXT("Starting: %s\r\n"), m_pModuleFile ); 260 Log( TEXT(" CommandLine=<%s>\r\n"), m_pCmdLine ); 261 262 if ( m_bQuiet ) 263 Log( TEXT(" Using quiet install mode\r\n") ); 264 265 time_t aTime; 266 time( &aTime ); 267 tm* pTime = localtime( &aTime ); 268 Log( TEXT(" Begin: %s\n"), _tasctime( pTime ) ); 269 270 return true; 271 } 272 273 //-------------------------------------------------------------------------- 274 boolean SetupApp::GetProfileSection( LPCTSTR pFileName, LPCTSTR pSection, 275 DWORD& rSize, LPTSTR *pRetBuf ) 276 { 277 if ( !rSize || !*pRetBuf ) 278 { 279 rSize = 512; 280 *pRetBuf = new TCHAR[ rSize ]; 281 } 282 283 DWORD nRet = GetPrivateProfileSection( pSection, *pRetBuf, rSize, pFileName ); 284 285 if ( nRet && ( nRet + 2 > rSize ) ) // buffer was too small, retry with bigger one 286 { 287 if ( nRet < 32767 - 2 ) 288 { 289 delete [] (*pRetBuf); 290 rSize = nRet + 2; 291 *pRetBuf = new TCHAR[ rSize ]; 292 293 nRet = GetPrivateProfileSection( pSection, *pRetBuf, rSize, pFileName ); 294 } 295 } 296 297 if ( !nRet ) 298 { 299 SetError( WIN::GetLastError() ); 300 301 TCHAR sBuf[80]; 302 StringCchPrintf( sBuf, 80, TEXT("ERROR: GetPrivateProfileSection(): GetLastError returned %u\r\n"), GetError() ); 303 Log( sBuf ); 304 return false; 305 } 306 else if ( nRet + 2 > rSize ) 307 { 308 SetError( ERROR_OUTOFMEMORY ); 309 Log( TEXT( "ERROR: GetPrivateProfileSection() out of memory\r\n" ) ); 310 return false; 311 } 312 313 Log( TEXT( " GetProfileSection read %s\r\n" ), pSection ); 314 315 return true; 316 } 317 318 //-------------------------------------------------------------------------- 319 boolean SetupApp::ReadProfile() 320 { 321 boolean bRet = false; 322 TCHAR *sProfilePath = 0; 323 324 if ( GetPathToFile( PROFILE_NAME, &sProfilePath ) ) 325 { 326 DWORD nSize = 0; 327 LPTSTR pRetBuf = NULL; 328 329 Log( TEXT( " Open ini file: <%s>\r\n" ), sProfilePath ); 330 331 bRet = GetProfileSection( sProfilePath, SECTION_SETUP, nSize, &pRetBuf ); 332 333 if ( !bRet ) 334 { 335 LPTSTR pTmpFile = CopyIniFile( sProfilePath ); 336 delete [] sProfilePath; 337 sProfilePath = pTmpFile; 338 339 if ( sProfilePath ) 340 { 341 SetError( ERROR_SUCCESS ); 342 343 Log( TEXT( " Could not open inifile, copied ini file to: <%s>\r\n" ), sProfilePath ); 344 bRet = GetProfileSection( sProfilePath, SECTION_SETUP, nSize, &pRetBuf ); 345 } 346 } 347 348 if ( bRet ) 349 { 350 LPTSTR pCurLine = pRetBuf; 351 while ( *pCurLine ) 352 { 353 LPTSTR pName = 0; 354 LPTSTR pValue = 0; 355 356 pCurLine += GetNameValue( pCurLine, &pName, &pValue ); 357 358 if ( lstrcmpi( TEXT( "database" ), pName ) == 0 ) 359 { 360 m_pDatabase = pValue; 361 Log( TEXT( " Database = %s\r\n" ), pValue ); 362 } 363 else if ( lstrcmpi( TEXT( "msiversion" ), pName ) == 0 ) 364 { 365 m_pReqVersion = pValue; 366 Log( TEXT( " msiversion = %s\r\n" ), pValue ); 367 } 368 else if ( lstrcmpi( TEXT( "productname" ), pName ) == 0 ) 369 { 370 m_pProductName = pValue; 371 Log( TEXT( " productname = %s\r\n" ), pValue ); 372 m_pAppTitle = SetProdToAppTitle( m_pProductName ); 373 } 374 else if ( lstrcmpi( TEXT( "upgradekey" ), pName ) == 0 ) 375 { 376 m_pUpgradeKey = pValue; 377 Log( TEXT( " upgradekey = %s\r\n" ), pValue ); 378 } 379 else if ( lstrcmpi( TEXT( "productversion" ), pName ) == 0 ) 380 { 381 m_pProductVersion = pValue; 382 Log( TEXT( " productversion = %s\r\n" ), pValue ); 383 } 384 else if ( lstrcmpi( TEXT( "productcode" ), pName ) == 0 ) 385 { 386 delete [] pValue; 387 } 388 else 389 { 390 Log( TEXT( "Warning: unknown entry in profile <%s>\r\n" ), pName ); 391 delete [] pValue; 392 } 393 } 394 } 395 396 if ( bRet && ( !m_pDatabase || !m_pReqVersion || !m_pProductName ) ) 397 { 398 Log( TEXT( "ERROR: incomplete 'Setup' section in profile\r\n" ) ); 399 SetError( ERROR_INVALID_DATA ); 400 bRet = false; 401 } 402 403 if ( bRet ) 404 bRet = GetProfileSection( sProfilePath, SECTION_LANGUAGE, nSize, &pRetBuf ); 405 406 if ( bRet ) 407 { 408 LPTSTR pName = 0; 409 LPTSTR pValue = 0; 410 LPTSTR pCurLine = pRetBuf; 411 LPTSTR pLastChar; 412 int nNext = 0; 413 414 // first line in this section should be the language count 415 nNext = GetNameValue( pCurLine, &pName, &pValue ); 416 if ( lstrcmpi( TEXT( "count" ), pName ) == 0 ) 417 { 418 Log( TEXT( " Languages = %s\r\n" ), pValue ); 419 m_nLanguageCount = _tcstol( pValue, &pLastChar, 10 ); 420 pCurLine += nNext; 421 delete [] pValue; 422 } 423 424 m_ppLanguageList = new LanguageData*[ m_nLanguageCount ]; 425 426 for ( int i=0; i < m_nLanguageCount; i++ ) 427 { 428 if ( !*pCurLine ) 429 { 430 m_nLanguageCount = i; 431 break; 432 } 433 434 pCurLine += GetNameValue( pCurLine, &pName, &pValue ); 435 m_ppLanguageList[ i ] = new LanguageData( pValue ); 436 Log( TEXT( " Language = %s\r\n" ), pValue ); 437 438 if ( m_ppLanguageList[ i ]->m_pTransform ) 439 Log( TEXT( " Transform = %s\r\n" ), m_ppLanguageList[ i ]->m_pTransform ); 440 441 delete [] pValue; 442 } 443 } 444 445 if ( pRetBuf ) 446 delete [] pRetBuf; 447 } 448 449 if ( sProfilePath && ! m_pTmpName ) 450 delete [] sProfilePath; 451 452 return bRet; 453 } 454 455 //-------------------------------------------------------------------------- 456 void SetupApp::AddFileToPatchList( TCHAR* pPath, TCHAR* pFile ) 457 { 458 if ( m_pPatchFiles == NULL ) 459 { 460 m_pPatchFiles = new TCHAR[ MAX_STR_LENGTH ]; 461 StringCchCopy( m_pPatchFiles, MAX_STR_LENGTH, TEXT("\"") ); 462 } 463 else 464 StringCchCat( m_pPatchFiles, MAX_STR_LENGTH, TEXT(";") ); 465 466 StringCchCat( m_pPatchFiles, MAX_STR_LENGTH, pPath ); 467 StringCchCat( m_pPatchFiles, MAX_STR_LENGTH, pFile ); 468 } 469 470 //-------------------------------------------------------------------------- 471 boolean SetupApp::GetPatches() 472 { 473 boolean bRet = true; 474 475 int nPatternLen = lstrlen( m_pModuleFile ) + 7; // 1 for null terminator, 1 for back slash, 5 for extensions 476 TCHAR* pPattern = new TCHAR[ nPatternLen ]; 477 TCHAR* pBaseDir = new TCHAR[ nPatternLen ]; 478 479 // find 'setup.exe' in the path so we can remove it 480 TCHAR *pFilePart = 0; 481 if ( 0 == GetFullPathName( m_pModuleFile, nPatternLen, pPattern, &pFilePart ) ) 482 { 483 SetError( WIN::GetLastError() ); 484 bRet = false; 485 } 486 else 487 { 488 if ( pFilePart ) 489 *pFilePart = '\0'; 490 StringCchCopy( pBaseDir, nPatternLen, pPattern ); 491 StringCchCat( pPattern, nPatternLen, TEXT("*.msp") ); 492 493 WIN32_FIND_DATA aFindFileData; 494 495 HANDLE hFindPatches = FindFirstFile( pPattern, &aFindFileData ); 496 497 if ( hFindPatches != INVALID_HANDLE_VALUE ) 498 { 499 if ( ! IsPatchInstalled( pBaseDir, aFindFileData.cFileName ) ) 500 AddFileToPatchList( pBaseDir, aFindFileData.cFileName ); 501 502 while ( FindNextFile( hFindPatches, &aFindFileData ) ) 503 { 504 if ( ! IsPatchInstalled( pBaseDir, aFindFileData.cFileName ) ) 505 AddFileToPatchList( pBaseDir, aFindFileData.cFileName ); 506 } 507 508 if ( m_pPatchFiles != NULL ) 509 StringCchCat( m_pPatchFiles, MAX_STR_LENGTH, TEXT("\"") ); 510 511 FindClose( hFindPatches ); 512 } 513 } 514 515 delete [] pPattern; 516 delete [] pBaseDir; 517 518 return bRet; 519 } 520 521 //-------------------------------------------------------------------------- 522 boolean SetupApp::GetPathToFile( TCHAR* pFileName, TCHAR** pPath ) 523 { 524 // generate the path to the file = szModuleFile + FileName 525 // note: FileName is a relative path 526 527 boolean bRet = true; 528 529 int nTempPath = lstrlen( m_pModuleFile ) + lstrlen( pFileName ) + 2; // 1 for null terminator, 1 for back slash 530 TCHAR* pTempPath = new TCHAR[ nTempPath ]; 531 532 // find 'setup.exe' in the path so we can remove it 533 TCHAR *pFilePart = 0; 534 if ( 0 == GetFullPathName( m_pModuleFile, nTempPath, pTempPath, &pFilePart ) ) 535 { 536 SetError( WIN::GetLastError() ); 537 bRet = false; 538 } 539 else 540 { 541 if ( pFilePart ) 542 *pFilePart = '\0'; 543 544 StringCchCat( pTempPath, nTempPath, pFileName ); 545 546 int nPath = 2 * nTempPath; 547 *pPath = new TCHAR[ nPath ]; 548 549 // normalize the path 550 int nReturn = GetFullPathName( pTempPath, nPath, *pPath, &pFilePart ); 551 552 if ( nReturn > nPath ) 553 { 554 // try again, with larger buffer 555 delete [] (*pPath); 556 nPath = nReturn; 557 *pPath = new TCHAR[ nPath ]; 558 559 nReturn = GetFullPathName( pTempPath, nPath, *pPath, &pFilePart ); 560 } 561 562 if ( 0 == nReturn ) 563 { 564 // error -- invalid path 565 SetError( WIN::GetLastError() ); 566 bRet = false; 567 } 568 } 569 570 if ( bRet ) // check for the file's existence 571 { 572 DWORD dwFileAttrib = GetFileAttributes( *pPath ); 573 574 if (0xFFFFFFFF == dwFileAttrib) 575 { 576 StringCchCopy( m_pErrorText, MAX_TEXT_LENGTH, pFileName ); 577 SetError( ERROR_FILE_NOT_FOUND ); 578 bRet = false; 579 } 580 } 581 582 delete [] pTempPath; 583 return bRet; 584 } 585 586 //-------------------------------------------------------------------------- 587 int SetupApp::GetNameValue( TCHAR* pLine, TCHAR** pName, TCHAR** pValue ) 588 { 589 int nRet = lstrlen( pLine ) + 1; 590 *pValue = 0; 591 592 if ( nRet == 1 ) 593 return nRet; 594 595 LPTSTR pChar = pLine; 596 LPTSTR pLast = NULL; 597 598 // Skip leading spaces. 599 while (' ' == *pChar || '\t' == *pChar) 600 pChar = CharNext( pChar ); 601 602 *pName = pChar; 603 604 // look for the end of the name 605 while( *pChar && (' ' != *pChar) && 606 ( '\t' != *pChar ) && ( '=' != *pChar ) ) 607 pChar = CharNext( pChar ); 608 609 if ( ! *pChar ) 610 return nRet; 611 612 pLast = pChar; 613 pChar = CharNext( pChar ); 614 *pLast = '\0'; 615 616 // look for the start of the value 617 while( ( ' ' == *pChar ) || ( '\t' == *pChar ) || 618 ( '=' == *pChar ) ) 619 pChar = CharNext( pChar ); 620 621 int nValueLen = lstrlen( pChar ) + 1; 622 *pValue = new TCHAR[ nValueLen ]; 623 624 if ( *pValue ) 625 StringCchCopy( *pValue, nValueLen, pChar ); 626 627 return nRet; 628 } 629 630 //-------------------------------------------------------------------------- 631 boolean SetupApp::ChooseLanguage( long& rLanguage ) 632 { 633 rLanguage = 0; 634 635 if ( m_bQuiet ) 636 return true; 637 638 // When there are none or only one language, there is nothing 639 // to do here 640 if ( m_nLanguageCount > 1 ) 641 { 642 TCHAR *sString = new TCHAR[ MAX_LANGUAGE_LEN ]; 643 644 LANGID nUserDefLang = GetUserDefaultLangID(); 645 LANGID nSysDefLang = GetSystemDefaultLangID(); 646 647 int nUserPrimary = PRIMARYLANGID( nUserDefLang ); 648 int nSysPrimary = PRIMARYLANGID( nSysDefLang ); 649 650 long nUserIndex = -1; 651 long nUserPrimIndex = -1; 652 long nSystemIndex = -1; 653 long nSystemPrimIndex = -1; 654 long nParamIndex = -1; 655 656 for ( long i=0; i<GetLanguageCount(); i++ ) 657 { 658 long nLanguage = GetLanguageID( i ); 659 int nPrimary = PRIMARYLANGID( nLanguage ); 660 GetLanguageName( nLanguage, sString ); 661 Log( TEXT( " Info: found Language: %s\r\n" ), sString ); 662 663 if ( nLanguage == nUserDefLang ) 664 nUserIndex = i; 665 if ( nPrimary == nUserPrimary ) 666 nUserPrimIndex = i; 667 if ( nLanguage == nSysDefLang ) 668 nSystemIndex = i; 669 if ( nPrimary == nSysPrimary ) 670 nSystemPrimIndex = i; 671 if ( m_nLanguageID && ( nLanguage == m_nLanguageID ) ) 672 nParamIndex = i; 673 } 674 675 if ( m_nLanguageID && ( nParamIndex == -1 ) ) 676 { 677 Log( TEXT( "Warning: Language chosen with parameter -lang not found.\r\n" ) ); 678 } 679 680 if ( nParamIndex != -1 ) 681 { 682 Log( TEXT( "Info: Found language chosen with parameter -lang.\r\n" ) ); 683 rLanguage = GetLanguageID( nParamIndex ); 684 } 685 else if ( nUserIndex != -1 ) 686 { 687 Log( TEXT( "Info: Found user default language.\r\n" ) ); 688 rLanguage = GetLanguageID( nUserIndex ); 689 } 690 else if ( nUserPrimIndex != -1 ) 691 { 692 Log( TEXT( "Info: Found user default primary language.\r\n" ) ); 693 rLanguage = GetLanguageID( nUserPrimIndex ); 694 } 695 else if ( nSystemIndex != -1 ) 696 { 697 Log( TEXT( "Info: Found system default language.\r\n" ) ); 698 rLanguage = GetLanguageID( nSystemIndex ); 699 } 700 else if ( nSystemPrimIndex != -1 ) 701 { 702 Log( TEXT( "Info: Found system default primary language.\r\n" ) ); 703 rLanguage = GetLanguageID( nSystemPrimIndex ); 704 } 705 else 706 { 707 Log( TEXT( "Info: Use default language from ini file.\r\n" ) ); 708 rLanguage = GetLanguageID( 0 ); 709 } 710 delete [] sString; 711 } 712 713 return true; 714 } 715 716 717 //-------------------------------------------------------------------------- 718 LPCTSTR SetupApp::GetPathToMSI() 719 { 720 LPTSTR sMsiPath = NULL; 721 HKEY hInstKey = NULL; 722 TCHAR *sMsiFolder = getInstallerLocation(); 723 DWORD nMsiFolderSize = MAX_PATH + 1; 724 725 if ( sMsiFolder[0] == '\0' ) // use the default location 726 { 727 Log( TEXT( " Could not find path to msiexec.exe in registry" ) ); 728 729 DWORD nRet = WIN::GetSystemDirectory( sMsiFolder, nMsiFolderSize ); 730 if ( nRet > nMsiFolderSize ) 731 { 732 delete [] sMsiFolder; 733 sMsiFolder = new TCHAR[ nRet ]; 734 nMsiFolderSize = nRet; 735 736 nRet = WIN::GetSystemDirectory( sMsiFolder, nMsiFolderSize ); 737 } 738 if ( 0 == nRet ) 739 { 740 sMsiFolder[0] = '\0'; 741 SetError( WIN::GetLastError() ); 742 } 743 nMsiFolderSize = nRet; 744 } 745 746 if ( sMsiFolder[0] != '\0' ) 747 { 748 int nLength = lstrlen( sMsiExe ) + lstrlen( sMsiFolder ) + 1; 749 sMsiPath = new TCHAR[ nLength ]; 750 751 if ( FAILED( StringCchCopy( sMsiPath, nLength, sMsiFolder ) ) || 752 FAILED( StringCchCat( sMsiPath, nLength, sMsiExe ) ) ) 753 { 754 delete [] sMsiPath; 755 sMsiPath = NULL; 756 } 757 } 758 759 if ( ! sMsiPath ) 760 Log( TEXT( "ERROR: Can't build path to msiexec.exe!" ) ); 761 762 return sMsiPath; 763 } 764 765 //-------------------------------------------------------------------------- 766 boolean SetupApp::LaunchInstaller( LPCTSTR pParam ) 767 { 768 LPCTSTR sMsiPath = GetPathToMSI(); 769 770 if ( !sMsiPath ) 771 { 772 Log( TEXT( "ERROR: msiexec not found!" ) ); 773 SetError( ERROR_FILE_NOT_FOUND ); 774 return false; 775 } 776 777 STARTUPINFO aSUI; 778 PROCESS_INFORMATION aPI; 779 780 Log( TEXT( " Will install using <%s>\r\n" ), sMsiPath ); 781 Log( TEXT( " Parameters are: %s\r\n" ), pParam ); 782 783 OutputDebugStringFormat( TEXT( " Will install using <%s>\r\n" ), sMsiPath ); 784 OutputDebugStringFormat( TEXT( " Parameters are: %s\r\n" ), pParam ); 785 786 ZeroMemory( (void*)&aPI, sizeof( PROCESS_INFORMATION ) ); 787 ZeroMemory( (void*)&aSUI, sizeof( STARTUPINFO ) ); 788 789 aSUI.cb = sizeof(STARTUPINFO); 790 aSUI.dwFlags = STARTF_USESHOWWINDOW; 791 aSUI.wShowWindow = SW_SHOW; 792 793 DWORD nCmdLineLength = lstrlen( sMsiPath ) + lstrlen( pParam ) + 2; 794 TCHAR *sCmdLine = new TCHAR[ nCmdLineLength ]; 795 796 if ( FAILED( StringCchCopy( sCmdLine, nCmdLineLength, sMsiPath ) ) || 797 FAILED( StringCchCat( sCmdLine, nCmdLineLength, TEXT( " " ) ) ) || 798 FAILED( StringCchCat( sCmdLine, nCmdLineLength, pParam ) ) ) 799 { 800 delete [] sCmdLine; 801 SetError( ERROR_INSTALL_FAILURE ); 802 return false; 803 } 804 805 if ( !WIN::CreateProcess( NULL, sCmdLine, NULL, NULL, FALSE, 806 CREATE_DEFAULT_ERROR_MODE, NULL, NULL, 807 &aSUI, &aPI ) ) 808 { 809 Log( TEXT( "ERROR: Could not create process %s.\r\n" ), sCmdLine ); 810 SetError( WIN::GetLastError() ); 811 delete [] sCmdLine; 812 return false; 813 } 814 815 DWORD nResult = WaitForProcess( aPI.hProcess ); 816 bool bRet = true; 817 818 if( ERROR_SUCCESS != nResult ) 819 { 820 Log( TEXT( "ERROR: While waiting for %s.\r\n" ), sCmdLine ); 821 SetError( nResult ); 822 bRet = false; 823 } 824 else 825 { 826 GetExitCodeProcess( aPI.hProcess, &nResult ); 827 SetError( nResult ); 828 829 if ( nResult != ERROR_SUCCESS ) 830 { 831 TCHAR sBuf[80]; 832 StringCchPrintf( sBuf, 80, TEXT("Warning: msiexec returned %u.\r\n"), nResult ); 833 Log( sBuf ); 834 } 835 else 836 Log( TEXT( " Installation completed successfully.\r\n" ) ); 837 } 838 839 CloseHandle( aPI.hProcess ); 840 841 delete [] sCmdLine; 842 843 return bRet; 844 } 845 846 //-------------------------------------------------------------------------- 847 boolean SetupApp::Install( long nLanguage ) 848 { 849 LPTSTR pTransform = NULL; 850 851 if ( nLanguage ) // look for transformation 852 { 853 for ( int i = 0; i < m_nLanguageCount; i++ ) 854 { 855 if ( m_ppLanguageList[i]->m_nLanguageID == nLanguage ) 856 { 857 if ( m_ppLanguageList[i]->m_pTransform ) 858 { 859 if ( !GetPathToFile( m_ppLanguageList[i]->m_pTransform, 860 &pTransform ) ) 861 { 862 Log( TEXT( "ERROR: Could not find transform <%s\r\n" ), m_ppLanguageList[i]->m_pTransform ); 863 return false; 864 } 865 } 866 break; 867 } 868 } 869 } 870 871 TCHAR *pDataBasePath = NULL; 872 873 if ( ! GetPathToFile( m_pDatabase, &pDataBasePath ) ) 874 { 875 Log( TEXT( "ERROR: Could not find database <%s\r\n" ), m_pDatabase ); 876 SetError( ERROR_INSTALL_SOURCE_ABSENT ); 877 return false; 878 } 879 880 // we will always use the parameter setup used 881 int nParLen = lstrlen( PARAM_SETUP_USED ); 882 883 if ( m_bRegNoMsoTypes ) 884 nParLen += lstrlen( PARAM_REG_NO_MSO_TYPES ); 885 else if ( m_bRegAllMsoTypes ) 886 nParLen += lstrlen( PARAM_REG_ALL_MSO_TYPES ); 887 888 if ( m_pAdvertise ) 889 nParLen += lstrlen( m_pAdvertise ) + 1; // one for the space 890 else if ( m_bIsMinorUpgrade ) 891 nParLen += lstrlen( PARAM_MINOR_UPGRADE ); 892 else 893 nParLen += lstrlen( PARAM_PACKAGE ); 894 895 nParLen += lstrlen( pDataBasePath ) + 3; // two quotes, one null 896 897 if ( NeedReboot() ) 898 nParLen += lstrlen( PARAM_REBOOT ); 899 900 if ( m_pPatchFiles ) 901 { 902 nParLen += lstrlen( PARAM_PATCH ); 903 nParLen += lstrlen( m_pPatchFiles ); 904 } 905 906 if ( pTransform ) 907 { 908 nParLen += lstrlen( PARAM_TRANSFORM ); 909 nParLen += lstrlen( pTransform ) + 2; // two quotes 910 } 911 912 if ( m_pCmdLine ) 913 nParLen += lstrlen( m_pCmdLine ) + 1; // one for the space; 914 915 TCHAR *pParams = new TCHAR[ nParLen ]; 916 917 StringCchCopy( pParams, nParLen, PARAM_SETUP_USED ); 918 919 if ( m_bRegNoMsoTypes ) 920 StringCchCat( pParams, nParLen, PARAM_REG_NO_MSO_TYPES ); 921 else if ( m_bRegAllMsoTypes ) 922 StringCchCat( pParams, nParLen, PARAM_REG_ALL_MSO_TYPES ); 923 924 if ( m_pAdvertise ) 925 StringCchCat( pParams, nParLen, m_pAdvertise ); 926 else if ( IsAdminInstall() ) 927 StringCchCat( pParams, nParLen, PARAM_ADMIN ); 928 else if ( m_bIsMinorUpgrade ) 929 StringCchCat( pParams, nParLen, PARAM_MINOR_UPGRADE ); 930 else 931 StringCchCat( pParams, nParLen, PARAM_PACKAGE ); 932 933 StringCchCat( pParams, nParLen, TEXT( "\"" ) ); 934 StringCchCat( pParams, nParLen, pDataBasePath ); 935 StringCchCat( pParams, nParLen, TEXT( "\"" ) ); 936 937 if ( NeedReboot() ) 938 StringCchCat( pParams, nParLen, PARAM_REBOOT ); 939 940 if ( m_pPatchFiles ) 941 { 942 StringCchCat( pParams, nParLen, PARAM_PATCH ); 943 StringCchCat( pParams, nParLen, m_pPatchFiles ); 944 } 945 946 if ( pTransform ) 947 { 948 StringCchCat( pParams, nParLen, PARAM_TRANSFORM ); 949 StringCchCat( pParams, nParLen, TEXT( "\"" ) ); 950 StringCchCat( pParams, nParLen, pTransform ); 951 StringCchCat( pParams, nParLen, TEXT( "\"" ) ); 952 } 953 954 if ( m_pCmdLine ) 955 { 956 StringCchCat( pParams, nParLen, TEXT( " " ) ); 957 StringCchCat( pParams, nParLen, m_pCmdLine ); 958 } 959 960 return LaunchInstaller( pParams ); 961 } 962 963 //-------------------------------------------------------------------------- 964 UINT SetupApp::GetError() const 965 { 966 UINT nErr = 0; 967 968 if ( m_pMSIErrorCode ) 969 nErr = (UINT) *m_pMSIErrorCode; 970 971 if ( nErr == 0 ) 972 nErr = m_uiRet; 973 974 if ( nErr != 0 ) 975 OutputDebugStringFormat( TEXT("Setup will return error (%d).\n"), nErr ); 976 return nErr; 977 } 978 979 //-------------------------------------------------------------------------- 980 void SetupApp::DisplayError( UINT nErr ) const 981 { 982 TCHAR sError[ MAX_TEXT_LENGTH ] = {0}; 983 TCHAR sTmp[ MAX_TEXT_LENGTH ] = {0}; 984 985 UINT nMsgType = MB_OK | MB_ICONERROR; 986 987 switch ( nErr ) 988 { 989 case ERROR_SUCCESS: break; // 0 990 991 case ERROR_FILE_NOT_FOUND: // 2 992 WIN::LoadString( m_hInst, IDS_FILE_NOT_FOUND, sTmp, MAX_TEXT_LENGTH ); 993 StringCchPrintf( sError, MAX_TEXT_LENGTH, sTmp, m_pErrorText ); 994 break; 995 case ERROR_INVALID_DATA: // 13 996 WIN::LoadString( m_hInst, IDS_INVALID_PROFILE, sError, MAX_TEXT_LENGTH ); 997 break; 998 case ERROR_OUTOFMEMORY: WIN::LoadString( m_hInst, IDS_OUTOFMEM, sError, MAX_TEXT_LENGTH ); 999 break; 1000 case ERROR_INSTALL_USEREXIT: 1001 WIN::LoadString( m_hInst, IDS_USER_CANCELED, sError, MAX_TEXT_LENGTH ); 1002 break; 1003 case ERROR_INSTALL_ALREADY_RUNNING: // 1618 1004 WIN::LoadString( m_hInst, IDS_ALREADY_RUNNING, sError, MAX_TEXT_LENGTH ); 1005 break; 1006 case ERROR_INSTALL_SOURCE_ABSENT: 1007 WIN::LoadString( m_hInst, IDS_NOMSI, sError, MAX_TEXT_LENGTH ); 1008 break; 1009 case ERROR_DS_INSUFF_ACCESS_RIGHTS: // 8344 1010 WIN::LoadString( m_hInst, IDS_REQUIRES_ADMIN_PRIV, sError, MAX_TEXT_LENGTH ); 1011 break; 1012 case E_ABORT: WIN::LoadString( m_hInst, IDS_UNKNOWN_ERROR, sError, MAX_TEXT_LENGTH ); 1013 break; 1014 case ERROR_INVALID_PARAMETER: // 87 1015 WIN::LoadString( m_hInst, IDS_INVALID_PARAM, sTmp, MAX_TEXT_LENGTH ); 1016 StringCchPrintf( sError, MAX_TEXT_LENGTH, sTmp, m_pErrorText ); 1017 break; 1018 1019 case ERROR_SETUP_TO_OLD: // - 3 1020 WIN::LoadString( m_hInst, IDS_SETUP_TO_OLD, sTmp, MAX_TEXT_LENGTH ); 1021 StringCchPrintf( sError, MAX_TEXT_LENGTH, sTmp, m_pReqVersion, m_pErrorText ); 1022 break; 1023 case ERROR_SETUP_NOT_FOUND: // - 4 1024 WIN::LoadString( m_hInst, IDS_SETUP_NOT_FOUND, sTmp, MAX_TEXT_LENGTH ); 1025 StringCchPrintf( sError, MAX_TEXT_LENGTH, sTmp, m_pReqVersion ); 1026 break; 1027 case ERROR_SHOW_USAGE: // - 2 1028 nMsgType = MB_OK | MB_ICONINFORMATION; 1029 WIN::LoadString( m_hInst, IDS_USAGE, sError, MAX_TEXT_LENGTH ); 1030 break; 1031 1032 default: WIN::LoadString( m_hInst, IDS_UNKNOWN_ERROR, sError, MAX_TEXT_LENGTH ); 1033 break; 1034 } 1035 1036 if ( sError[0] ) 1037 { 1038 if ( !m_bQuiet ) 1039 { 1040 ConvertNewline( sError ); 1041 WIN::MessageBox( NULL, sError, m_pAppTitle, nMsgType ); 1042 } 1043 1044 Log( TEXT( "ERROR: %s\r\n" ), sError ); 1045 } 1046 } 1047 1048 //-------------------------------------------------------------------------- 1049 long SetupApp::GetLanguageID( long nIndex ) const 1050 { 1051 if ( nIndex >=0 && nIndex < m_nLanguageCount ) 1052 return m_ppLanguageList[ nIndex ]->m_nLanguageID; 1053 else 1054 return 0; 1055 } 1056 1057 //-------------------------------------------------------------------------- 1058 void SetupApp::GetLanguageName( long nLanguage, LPTSTR sName ) const 1059 { 1060 switch ( nLanguage ) 1061 { 1062 case 1028: WIN::LoadString( m_hInst, IDS_LANGUAGE_ZH_TW, sName, MAX_LANGUAGE_LEN ); break; 1063 case 1029: WIN::LoadString( m_hInst, IDS_LANGUAGE_CS, sName, MAX_LANGUAGE_LEN ); break; 1064 case 1030: WIN::LoadString( m_hInst, IDS_LANGUAGE_DA, sName, MAX_LANGUAGE_LEN ); break; 1065 case 1031: WIN::LoadString( m_hInst, IDS_LANGUAGE_DE_DE, sName, MAX_LANGUAGE_LEN ); break; 1066 case 1032: WIN::LoadString( m_hInst, IDS_LANGUAGE_EL, sName, MAX_LANGUAGE_LEN ); break; 1067 case 1033: WIN::LoadString( m_hInst, IDS_LANGUAGE_EN_US, sName, MAX_LANGUAGE_LEN ); break; 1068 case 1034: WIN::LoadString( m_hInst, IDS_LANGUAGE_ES, sName, MAX_LANGUAGE_LEN ); break; 1069 case 1035: WIN::LoadString( m_hInst, IDS_LANGUAGE_FI, sName, MAX_LANGUAGE_LEN ); break; 1070 case 1036: WIN::LoadString( m_hInst, IDS_LANGUAGE_FR_FR, sName, MAX_LANGUAGE_LEN ); break; 1071 case 1037: WIN::LoadString( m_hInst, IDS_LANGUAGE_HE, sName, MAX_LANGUAGE_LEN ); break; 1072 case 1038: WIN::LoadString( m_hInst, IDS_LANGUAGE_HU, sName, MAX_LANGUAGE_LEN ); break; 1073 case 1040: WIN::LoadString( m_hInst, IDS_LANGUAGE_IT_IT, sName, MAX_LANGUAGE_LEN ); break; 1074 case 1041: WIN::LoadString( m_hInst, IDS_LANGUAGE_JA, sName, MAX_LANGUAGE_LEN ); break; 1075 case 1042: WIN::LoadString( m_hInst, IDS_LANGUAGE_KO, sName, MAX_LANGUAGE_LEN ); break; 1076 case 1043: WIN::LoadString( m_hInst, IDS_LANGUAGE_NL_NL, sName, MAX_LANGUAGE_LEN ); break; 1077 case 1044: WIN::LoadString( m_hInst, IDS_LANGUAGE_NO_NO, sName, MAX_LANGUAGE_LEN ); break; 1078 case 1045: WIN::LoadString( m_hInst, IDS_LANGUAGE_PL, sName, MAX_LANGUAGE_LEN ); break; 1079 case 1046: WIN::LoadString( m_hInst, IDS_LANGUAGE_PT_BR, sName, MAX_LANGUAGE_LEN ); break; 1080 case 1049: WIN::LoadString( m_hInst, IDS_LANGUAGE_RU, sName, MAX_LANGUAGE_LEN ); break; 1081 case 1051: WIN::LoadString( m_hInst, IDS_LANGUAGE_SK, sName, MAX_LANGUAGE_LEN ); break; 1082 case 1053: WIN::LoadString( m_hInst, IDS_LANGUAGE_SV_SE, sName, MAX_LANGUAGE_LEN ); break; 1083 case 1054: WIN::LoadString( m_hInst, IDS_LANGUAGE_TH, sName, MAX_LANGUAGE_LEN ); break; 1084 case 1055: WIN::LoadString( m_hInst, IDS_LANGUAGE_TR, sName, MAX_LANGUAGE_LEN ); break; 1085 case 1061: WIN::LoadString( m_hInst, IDS_LANGUAGE_ET, sName, MAX_LANGUAGE_LEN ); break; 1086 case 2052: WIN::LoadString( m_hInst, IDS_LANGUAGE_ZH_CN, sName, MAX_LANGUAGE_LEN ); break; 1087 case 2070: WIN::LoadString( m_hInst, IDS_LANGUAGE_PT_PT, sName, MAX_LANGUAGE_LEN ); break; 1088 1089 default: 1090 { 1091 TCHAR sTmp[ MAX_LANGUAGE_LEN ] = {0}; 1092 1093 WIN::LoadString( m_hInst, IDS_UNKNOWN_LANG, sTmp, MAX_LANGUAGE_LEN ); 1094 StringCchPrintf( sName, MAX_LANGUAGE_LEN, sTmp, nLanguage ); 1095 } 1096 } 1097 } 1098 1099 //-------------------------------------------------------------------------- 1100 boolean SetupApp::CheckVersion() 1101 { 1102 boolean bRet = false; 1103 1104 Log( TEXT( " Looking for installed MSI with version >= %s\r\n" ), m_pReqVersion ); 1105 1106 DLLVERSIONINFO aInfo; 1107 1108 aInfo.cbSize = sizeof( DLLVERSIONINFO ); 1109 if ( NOERROR == aoo_MsiDllGetVersion( &aInfo ) ) 1110 { 1111 TCHAR pMsiVersion[ VERSION_SIZE ]; 1112 StringCchPrintf( pMsiVersion, VERSION_SIZE, TEXT("%d.%d.%4d"), 1113 aInfo.dwMajorVersion, 1114 aInfo.dwMinorVersion, 1115 aInfo.dwBuildNumber ); 1116 if ( _tcsncmp( pMsiVersion, m_pReqVersion, _tcslen( pMsiVersion ) ) < 0 ) 1117 { 1118 StringCchCopy( m_pErrorText, MAX_TEXT_LENGTH, pMsiVersion ); 1119 SetError( (UINT) ERROR_SETUP_TO_OLD ); 1120 Log( TEXT( "Warning: Old MSI version found <%s>, update needed!\r\n" ), pMsiVersion ); 1121 } 1122 else 1123 { 1124 Log( TEXT( " Found MSI version <%s>, no update needed\r\n" ), pMsiVersion ); 1125 bRet = true; 1126 } 1127 if ( aInfo.dwMajorVersion >= 3 ) 1128 m_bSupportsPatch = true; 1129 else 1130 Log( TEXT("Warning: Patching not supported! MSI-Version <%s>\r\n"), pMsiVersion ); 1131 } 1132 1133 return bRet; 1134 } 1135 1136 //-------------------------------------------------------------------------- 1137 boolean SetupApp::CheckForUpgrade() 1138 { 1139 // When we have patch files we will never try an Minor upgrade 1140 if ( m_pPatchFiles ) return true; 1141 1142 if ( !m_pUpgradeKey || ( _tcslen( m_pUpgradeKey ) == 0 ) ) 1143 { 1144 Log( TEXT( " No Upgrade Key Found -> continue with standard installation!\r\n" ) ); 1145 return true; 1146 } 1147 1148 HKEY hInstKey = NULL; 1149 1150 if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, m_pUpgradeKey, 0, KEY_READ, &hInstKey ) ) 1151 { 1152 Log( TEXT( " Found Upgrade Key in Registry (HKLM) -> will try minor upgrade!\r\n" ) ); 1153 m_bIsMinorUpgrade = true; 1154 } 1155 else if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_CURRENT_USER, m_pUpgradeKey, 0, KEY_READ, &hInstKey ) ) 1156 { 1157 Log( TEXT( " Found Upgrade Key in Registry (HKCU) -> will try minor upgrade!\r\n" ) ); 1158 m_bIsMinorUpgrade = true; 1159 } 1160 else 1161 { 1162 Log( TEXT( " Didn't Find Upgrade Key in Registry -> continue with standard installation!\r\n" ) ); 1163 return true; 1164 } 1165 1166 if ( m_pProductVersion && ( _tcslen( m_pProductVersion ) > 0 ) ) 1167 { 1168 TCHAR *sProductVersion = new TCHAR[ MAX_PATH + 1 ]; 1169 DWORD nSize = MAX_PATH + 1; 1170 1171 sProductVersion[0] = '\0'; 1172 1173 // get product version 1174 if ( ERROR_SUCCESS == RegQueryValueEx( hInstKey, PRODUCT_VERSION, NULL, NULL, (LPBYTE)sProductVersion, &nSize ) ) 1175 { 1176 if ( lstrcmpi( sProductVersion, m_pProductVersion ) == 0 ) 1177 { 1178 Log( TEXT( " Same Product Version already installed, no minor upgrade!\r\n" ) ); 1179 m_bIsMinorUpgrade = false; 1180 } 1181 } 1182 1183 delete [] sProductVersion; 1184 } 1185 1186 return true; 1187 } 1188 1189 //-------------------------------------------------------------------------- 1190 boolean SetupApp::IsTerminalServerInstalled() const 1191 { 1192 boolean bIsTerminalServer = false; 1193 1194 const TCHAR sSearchStr[] = TEXT("Terminal Server"); 1195 const TCHAR sKey[] = TEXT("System\\CurrentControlSet\\Control\\ProductOptions"); 1196 const TCHAR sValue[] = TEXT("ProductSuite"); 1197 1198 DWORD dwSize = 0; 1199 HKEY hKey = 0; 1200 DWORD dwType = 0; 1201 1202 if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, sKey, 0, KEY_READ, &hKey ) && 1203 ERROR_SUCCESS == RegQueryValueEx( hKey, sValue, NULL, &dwType, NULL, &dwSize ) && 1204 dwSize > 0 && 1205 REG_MULTI_SZ == dwType ) 1206 { 1207 TCHAR* sSuiteList = new TCHAR[ (dwSize*sizeof(byte)/sizeof(TCHAR)) + 1 ]; 1208 1209 ZeroMemory(sSuiteList, dwSize); 1210 1211 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, sValue, NULL, &dwType, (LPBYTE)sSuiteList, &dwSize) ) 1212 { 1213 DWORD nMulti = 0; 1214 DWORD nSrch = lstrlen( sSearchStr ); 1215 const TCHAR *sSubString = sSuiteList; 1216 1217 while (*sSubString) 1218 { 1219 nMulti = lstrlen( sSubString ); 1220 if ( nMulti == nSrch && 0 == lstrcmp( sSearchStr, sSubString ) ) 1221 { 1222 bIsTerminalServer = true; 1223 break; 1224 } 1225 1226 sSubString += (nMulti + 1); 1227 } 1228 } 1229 delete [] sSuiteList; 1230 } 1231 1232 if ( hKey ) 1233 RegCloseKey( hKey ); 1234 1235 return bIsTerminalServer; 1236 } 1237 1238 //-------------------------------------------------------------------------- 1239 boolean SetupApp::AlreadyRunning() const 1240 { 1241 if ( m_bIgnoreAlreadyRunning ) 1242 { 1243 Log( TEXT("Ignoring already running MSI instance!\r\n") ); 1244 return false; 1245 } 1246 1247 const TCHAR *sMutexName = NULL; 1248 const TCHAR sGUniqueName[] = TEXT( "Global\\_MSISETUP_{EA8130C1-8D3D-4338-9309-1A52D530D846}" ); 1249 const TCHAR sUniqueName[] = TEXT( "_MSISETUP_{EA8130C1-8D3D-4338-9309-1A52D530D846}" ); 1250 1251 if ( IsWin9x() ) 1252 sMutexName = sUniqueName; 1253 else if ( ( GetOSVersion() < 5 ) && ! IsTerminalServerInstalled() ) 1254 sMutexName = sUniqueName; 1255 else 1256 sMutexName = sGUniqueName; 1257 1258 HANDLE hMutex = 0; 1259 1260 hMutex = WIN::CreateMutex( NULL, FALSE, sMutexName ); 1261 1262 if ( !hMutex || ERROR_ALREADY_EXISTS == WIN::GetLastError() ) 1263 { 1264 if ( !hMutex ) 1265 Log( TEXT( "ERROR: AlreadyRunning() could not create mutex!\r\n" ) ); 1266 else 1267 Log( TEXT( "ERROR: There's already a setup running!\r\n" ) ); 1268 1269 return true; 1270 } 1271 Log( TEXT( " No running Setup found\r\n" ) ); 1272 1273 return false; 1274 } 1275 1276 //-------------------------------------------------------------------------- 1277 DWORD SetupApp::WaitForProcess( HANDLE hHandle ) 1278 { 1279 DWORD nResult = NOERROR; 1280 boolean bLoop = true; 1281 1282 MSG aMsg; 1283 ZeroMemory( (void*) &aMsg, sizeof(MSG) ); 1284 1285 while ( bLoop ) 1286 { 1287 switch ( WIN::MsgWaitForMultipleObjects( 1, &hHandle, false, 1288 INFINITE, QS_ALLINPUT ) ) 1289 { 1290 case WAIT_OBJECT_0: bLoop = false; 1291 break; 1292 1293 case (WAIT_OBJECT_0 + 1): 1294 { 1295 if ( WIN::PeekMessage( &aMsg, NULL, NULL, NULL, PM_REMOVE ) ) 1296 { 1297 WIN::TranslateMessage( &aMsg ); 1298 WIN::DispatchMessage( &aMsg ); 1299 } 1300 break; 1301 } 1302 1303 default: 1304 { 1305 nResult = WIN::GetLastError(); 1306 bLoop = false; 1307 } 1308 } 1309 } 1310 1311 return nResult; 1312 } 1313 1314 //-------------------------------------------------------------------------- 1315 void SetupApp::Log( LPCTSTR pMessage, LPCTSTR pText ) const 1316 { 1317 if ( m_pLogFile ) 1318 { 1319 static boolean bInit = false; 1320 1321 if ( !bInit ) 1322 { 1323 bInit = true; 1324 if ( ! IsWin9x() ) 1325 _ftprintf( m_pLogFile, TEXT("%c"), 0xfeff ); 1326 1327 _tsetlocale( LC_ALL, TEXT("") ); 1328 _ftprintf( m_pLogFile, TEXT("\nCodepage=%s\nMultiByte Codepage=[%d]\n"), 1329 _tsetlocale( LC_ALL, NULL ), _getmbcp() ); 1330 } 1331 if ( pText ) 1332 { 1333 _ftprintf( m_pLogFile, pMessage, pText ); 1334 OutputDebugStringFormat( pMessage, pText ); 1335 } 1336 else 1337 { 1338 _ftprintf( m_pLogFile, pMessage ); 1339 OutputDebugStringFormat( pMessage ); 1340 } 1341 1342 fflush( m_pLogFile ); 1343 } 1344 } 1345 1346 //-------------------------------------------------------------------------- 1347 DWORD SetupApp::GetNextArgument( LPCTSTR pStr, LPTSTR *pArg, LPTSTR *pNext, 1348 boolean bStripQuotes ) 1349 { 1350 boolean bInQuotes = false; 1351 boolean bFoundArgEnd = false; 1352 LPCTSTR pChar = pStr; 1353 LPCTSTR pFirst = NULL; 1354 1355 if ( NULL == pChar ) 1356 return ERROR_NO_MORE_ITEMS; 1357 1358 while ( ' ' == (*pChar) || '\t' == (*pChar) ) 1359 pChar = CharNext( pChar ); 1360 1361 if ( '\0' == (*pChar) ) 1362 return ERROR_NO_MORE_ITEMS; 1363 1364 int nCount = 1; 1365 pFirst = pChar; 1366 1367 while ( ! bFoundArgEnd ) 1368 { 1369 if ( '\0' == (*pChar) ) 1370 bFoundArgEnd = true; 1371 else if ( !bInQuotes && ' ' == (*pChar) ) 1372 bFoundArgEnd = true; 1373 else if ( !bInQuotes && '\t' == (*pChar) ) 1374 bFoundArgEnd = true; 1375 else 1376 { 1377 if ( '\"' == (*pChar) ) 1378 { 1379 bInQuotes = !bInQuotes; 1380 if ( bStripQuotes ) 1381 { 1382 if ( pChar == pFirst ) 1383 pFirst = CharNext( pFirst ); 1384 nCount -= 1; 1385 } 1386 } 1387 1388 pChar = CharNext( pChar ); 1389 nCount += 1; 1390 } 1391 } 1392 1393 if ( pArg ) 1394 { 1395 *pArg = new TCHAR[ nCount ]; 1396 StringCchCopyN ( *pArg, nCount, pFirst, nCount-1 ); 1397 } 1398 1399 if ( pNext ) 1400 *pNext = CharNext( pChar ); 1401 1402 return ERROR_SUCCESS; 1403 } 1404 1405 //-------------------------------------------------------------------------- 1406 boolean SetupApp::GetCmdLineParameters( LPTSTR *pCmdLine ) 1407 { 1408 int nRet = ERROR_SUCCESS; 1409 LPTSTR pStart = NULL; 1410 LPTSTR pNext = NULL; 1411 1412 if ( GetNextArgument( *pCmdLine, NULL, &pNext ) != ERROR_SUCCESS ) 1413 { 1414 SetError( ERROR_NO_MORE_ITEMS ); 1415 return false; 1416 } 1417 1418 int nSize = lstrlen( *pCmdLine ) + 2; 1419 TCHAR *pNewCmdLine = new TCHAR[ nSize ]; 1420 pNewCmdLine[0] = '\0'; 1421 1422 while ( GetNextArgument( pNext, &pStart, &pNext ) == ERROR_SUCCESS ) 1423 { 1424 boolean bDeleteStart = true; 1425 1426 if ( (*pStart) == '/' || (*pStart) == '-' ) 1427 { 1428 LPTSTR pSub = CharNext( pStart ); 1429 if ( (*pSub) == 'l' || (*pSub) == 'L' ) 1430 { 1431 pSub = CharNext( pSub ); 1432 if ( (*pSub) == 'a' || (*pSub) == 'A' ) 1433 { // --- handle the lang parameter --- 1434 LPTSTR pLanguage = NULL; 1435 LPTSTR pLastChar; 1436 if ( GetNextArgument( pNext, &pLanguage, &pNext, true ) != ERROR_SUCCESS ) 1437 { 1438 StringCchCopy( m_pErrorText, MAX_TEXT_LENGTH, pStart ); 1439 nRet = ERROR_INVALID_PARAMETER; 1440 break; 1441 } 1442 1443 m_nLanguageID = _tcstol( pLanguage, &pLastChar, 10 ); 1444 delete [] pLanguage; 1445 } 1446 else 1447 { // --- handle the l(og) parameter --- 1448 boolean bAppend = false; 1449 LPTSTR pFileName = NULL; 1450 1451 while ( *pSub ) 1452 { 1453 if ( *pSub == '+' ) 1454 { 1455 bAppend = true; 1456 break; 1457 } 1458 pSub = CharNext( pSub ); 1459 } 1460 1461 if ( GetNextArgument( pNext, &pFileName, &pNext, true ) != ERROR_SUCCESS ) 1462 { 1463 StringCchCopy( m_pErrorText, MAX_TEXT_LENGTH, pStart ); 1464 nRet = ERROR_INVALID_PARAMETER; 1465 break; 1466 } 1467 1468 if ( FAILED( StringCchCat( pNewCmdLine, nSize, pStart ) ) ) 1469 { 1470 nRet = ERROR_OUTOFMEMORY; 1471 break; 1472 } 1473 // we need to append a '+' otherwise msiexec would overwrite our log file 1474 if ( !bAppend && FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( "+" ) ) ) ) 1475 { 1476 nRet = ERROR_OUTOFMEMORY; 1477 break; 1478 } 1479 if ( FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( " \"" ) ) ) || 1480 FAILED( StringCchCat( pNewCmdLine, nSize, pFileName ) ) || 1481 FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( "\" " ) ) ) ) 1482 { 1483 nRet = ERROR_OUTOFMEMORY; 1484 break; 1485 } 1486 1487 if ( bAppend ) 1488 m_pLogFile = _tfopen( pFileName, TEXT( "ab" ) ); 1489 else 1490 m_pLogFile = _tfopen( pFileName, TEXT( "wb" ) ); 1491 1492 delete [] pFileName; 1493 } 1494 } 1495 else if ( (*pSub) == 'q' || (*pSub) == 'Q' ) 1496 { // --- Handle quiet file parameter --- 1497 pSub = CharNext( pSub ); 1498 if ( ! (*pSub) || (*pSub) == 'n' || (*pSub) == 'N' ) 1499 m_bQuiet = true; 1500 1501 if ( FAILED( StringCchCat( pNewCmdLine, nSize, pStart ) ) || 1502 FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( " " ) ) ) ) 1503 { 1504 nRet = ERROR_OUTOFMEMORY; 1505 break; 1506 } 1507 } 1508 else if ( _tcsnicmp( pSub, PARAM_RUNNING, _tcslen( PARAM_RUNNING ) ) == 0 ) 1509 { 1510 m_bIgnoreAlreadyRunning = true; 1511 } 1512 else if ( _tcsnicmp( pSub, CMDLN_REG_ALL_MSO_TYPES, _tcslen( CMDLN_REG_ALL_MSO_TYPES ) ) == 0 ) 1513 { 1514 m_bRegAllMsoTypes = true; 1515 } 1516 else if ( _tcsnicmp( pSub, CMDLN_REG_NO_MSO_TYPES, _tcslen( CMDLN_REG_NO_MSO_TYPES ) ) == 0 ) 1517 { 1518 m_bRegNoMsoTypes = true; 1519 } 1520 else if ( (*pSub) == 'i' || (*pSub) == 'I' || (*pSub) == 'f' || (*pSub) == 'F' || 1521 (*pSub) == 'p' || (*pSub) == 'P' || (*pSub) == 'x' || (*pSub) == 'X' || 1522 (*pSub) == 'y' || (*pSub) == 'Y' || (*pSub) == 'z' || (*pSub) == 'Z' ) 1523 { 1524 StringCchCopy( m_pErrorText, MAX_TEXT_LENGTH, pStart ); 1525 nRet = ERROR_INVALID_PARAMETER; 1526 break; 1527 } 1528 else if ( (*pSub) == 'a' || (*pSub) == 'A' ) 1529 { // --- Handle Administrative Installation --- 1530 SetAdminInstall( true ); 1531 } 1532 else if ( (*pSub) == 'j' || (*pSub) == 'J' ) 1533 { // --- Handle Administrative Installation --- 1534 m_pAdvertise = pStart; 1535 m_bQuiet = true; 1536 bDeleteStart = false; 1537 } 1538 else if ( (*pSub) == '?' || (*pSub) == 'h' || (*pSub) == 'H' ) 1539 { // --- Handle Show Usage --- 1540 nRet = ERROR_SHOW_USAGE; 1541 break; 1542 } 1543 else 1544 { 1545 if ( FAILED( StringCchCat( pNewCmdLine, nSize, pStart ) ) || 1546 FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( " " ) ) ) ) 1547 { 1548 nRet = ERROR_OUTOFMEMORY; 1549 break; 1550 } 1551 } 1552 } 1553 else 1554 { 1555 if ( FAILED( StringCchCat( pNewCmdLine, nSize, pStart ) ) || 1556 FAILED( StringCchCat( pNewCmdLine, nSize, TEXT( " " ) ) ) ) 1557 { 1558 nRet = ERROR_OUTOFMEMORY; 1559 break; 1560 } 1561 } 1562 1563 if ( bDeleteStart ) delete [] pStart; 1564 pStart = NULL; 1565 } 1566 1567 if ( pStart ) delete [] pStart; 1568 1569 *pCmdLine = pNewCmdLine; 1570 1571 if ( nRet != ERROR_SUCCESS ) 1572 { 1573 SetError( nRet ); 1574 return false; 1575 } 1576 else 1577 return true; 1578 } 1579 1580 //-------------------------------------------------------------------------- 1581 boolean SetupApp::IsAdmin() 1582 { 1583 if ( IsWin9x() ) 1584 return true; 1585 1586 PSID aPsidAdmin; 1587 SID_IDENTIFIER_AUTHORITY aAuthority = SECURITY_NT_AUTHORITY; 1588 1589 if ( !AllocateAndInitializeSid( &aAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, 1590 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, 1591 &aPsidAdmin ) ) 1592 return false; 1593 1594 BOOL bIsAdmin = FALSE; 1595 1596 if ( GetOSVersion() >= 5 ) 1597 { 1598 HMODULE hAdvapi32 = LoadLibrary( ADVAPI32_DLL ); 1599 1600 if ( !hAdvapi32 ) 1601 bIsAdmin = FALSE; 1602 else 1603 { 1604 PFnCheckTokenMembership pfnCheckTokenMembership = (PFnCheckTokenMembership) GetProcAddress( hAdvapi32, ADVAPI32API_CheckTokenMembership); 1605 if ( !pfnCheckTokenMembership || !pfnCheckTokenMembership( NULL, aPsidAdmin, &bIsAdmin ) ) 1606 bIsAdmin = FALSE; 1607 } 1608 FreeLibrary( hAdvapi32 ); 1609 } 1610 else 1611 { 1612 // NT4, check groups of user 1613 HANDLE hAccessToken = 0; 1614 UCHAR *szInfoBuffer = new UCHAR[ 1024 ]; // may need to resize if TokenInfo too big 1615 DWORD dwInfoBufferSize = 1024; 1616 DWORD dwRetInfoBufferSize = 0; 1617 UINT i=0; 1618 1619 if ( WIN::OpenProcessToken( WIN::GetCurrentProcess(), TOKEN_READ, &hAccessToken ) ) 1620 { 1621 bool bSuccess = false; 1622 bSuccess = WIN::GetTokenInformation( hAccessToken, TokenGroups, 1623 szInfoBuffer, dwInfoBufferSize, 1624 &dwRetInfoBufferSize ) == TRUE; 1625 1626 if( dwRetInfoBufferSize > dwInfoBufferSize ) 1627 { 1628 delete [] szInfoBuffer; 1629 szInfoBuffer = new UCHAR[ dwRetInfoBufferSize ]; 1630 dwInfoBufferSize = dwRetInfoBufferSize; 1631 bSuccess = WIN::GetTokenInformation( hAccessToken, TokenGroups, 1632 szInfoBuffer, dwInfoBufferSize, 1633 &dwRetInfoBufferSize ) == TRUE; 1634 } 1635 1636 WIN::CloseHandle( hAccessToken ); 1637 1638 if ( bSuccess ) 1639 { 1640 PTOKEN_GROUPS pGroups = (PTOKEN_GROUPS)(UCHAR*) szInfoBuffer; 1641 for( i=0; i<pGroups->GroupCount; i++ ) 1642 { 1643 if( WIN::EqualSid( aPsidAdmin, pGroups->Groups[i].Sid ) ) 1644 { 1645 bIsAdmin = TRUE; 1646 break; 1647 } 1648 } 1649 } 1650 1651 delete [] szInfoBuffer; 1652 } 1653 } 1654 1655 WIN::FreeSid( aPsidAdmin ); 1656 1657 return bIsAdmin ? true : false; 1658 } 1659 1660 //-------------------------------------------------------------------------- 1661 LPTSTR SetupApp::CopyIniFile( LPCTSTR pIniFile ) 1662 { 1663 m_pTmpName = _ttempnam( TEXT( "C:\\" ), TEXT( "Setup" ) ); 1664 1665 if ( !m_pTmpName ) 1666 { 1667 Log( TEXT( "ERROR: Could not create temp file\n" ) ); 1668 return NULL; 1669 } 1670 1671 FILE *pOut = _tfopen( m_pTmpName, TEXT( "wb" ) ); 1672 FILE *pIn = _tfopen( pIniFile, TEXT( "rb" ) ); 1673 1674 if ( pOut && pIn ) 1675 { 1676 size_t nRead, nWritten; 1677 BYTE pBuf[1024]; 1678 1679 nRead = fread( pBuf, sizeof( BYTE ), 1024, pIn ); 1680 while ( nRead && !ferror( pIn ) ) 1681 { 1682 nWritten = fwrite( pBuf, sizeof( BYTE ), nRead, pOut ); 1683 if ( nWritten != nRead ) 1684 { 1685 Log( TEXT( "ERROR: Could not write all bytes to temp file\n" ) ); 1686 break; 1687 } 1688 nRead = fread( pBuf, sizeof( BYTE ), 1024, pIn ); 1689 } 1690 } 1691 1692 if ( pOut ) fclose( pOut ); 1693 if ( pIn ) fclose( pIn ); 1694 1695 return m_pTmpName; 1696 } 1697 1698 //-------------------------------------------------------------------------- 1699 void SetupApp::ConvertNewline( LPTSTR pText ) const 1700 { 1701 int i=0; 1702 1703 while ( pText[i] != 0 ) 1704 { 1705 if ( ( pText[i] == '\\' ) && ( pText[i+1] == 'n' ) ) 1706 { 1707 pText[i] = 0x0d; 1708 pText[i+1] = 0x0a; 1709 i+=2; 1710 } 1711 else 1712 i+=1; 1713 } 1714 } 1715 1716 //-------------------------------------------------------------------------- 1717 LPTSTR SetupApp::SetProdToAppTitle( LPCTSTR pProdName ) 1718 { 1719 if ( !pProdName ) return m_pAppTitle; 1720 1721 LPTSTR pAppProdTitle = new TCHAR[ MAX_STR_CAPTION ]; 1722 pAppProdTitle[0] = '\0'; 1723 1724 WIN::LoadString( m_hInst, IDS_APP_PROD_TITLE, pAppProdTitle, MAX_STR_CAPTION ); 1725 1726 int nAppLen = lstrlen( pAppProdTitle ); 1727 int nProdLen = lstrlen( pProdName ); 1728 1729 if ( ( nAppLen == 0 ) || ( nProdLen == 0 ) ) 1730 { 1731 delete [] pAppProdTitle; 1732 return m_pAppTitle; 1733 } 1734 1735 int nLen = nAppLen + nProdLen + 3; 1736 1737 if ( nLen > STRSAFE_MAX_CCH ) return m_pAppTitle; 1738 1739 LPTSTR pIndex = _tcsstr( pAppProdTitle, PRODUCT_NAME_VAR ); 1740 1741 if ( pIndex ) 1742 { 1743 int nOffset = pIndex - pAppProdTitle; 1744 int nVarLen = lstrlen( PRODUCT_NAME_VAR ); 1745 1746 LPTSTR pNewTitle = new TCHAR[ nLen ]; 1747 pNewTitle[0] = '\0'; 1748 1749 if ( nOffset > 0 ) 1750 { 1751 StringCchCopyN( pNewTitle, nLen, pAppProdTitle, nOffset ); 1752 } 1753 1754 StringCchCat( pNewTitle, nLen, pProdName ); 1755 1756 if ( nOffset + nVarLen < nAppLen ) 1757 { 1758 StringCchCat( pNewTitle, nLen, pIndex + nVarLen ); 1759 } 1760 1761 delete [] m_pAppTitle; 1762 m_pAppTitle = pNewTitle; 1763 } 1764 1765 delete [] pAppProdTitle; 1766 1767 return m_pAppTitle; 1768 } 1769 1770 1771 //-------------------------------------------------------------------------- 1772 boolean SetupApp::IsPatchInstalled( TCHAR* pBaseDir, TCHAR* pFileName ) 1773 { 1774 if ( !m_bSupportsPatch ) 1775 return false; 1776 1777 PMSIHANDLE hSummaryInfo; 1778 int nLen = lstrlen( pBaseDir ) + lstrlen( pFileName ) + 1; 1779 TCHAR *szDatabasePath = new TCHAR [ nLen ]; 1780 TCHAR sBuf[80]; 1781 1782 StringCchCopy( szDatabasePath, nLen, pBaseDir ); 1783 StringCchCat( szDatabasePath, nLen, pFileName ); 1784 1785 UINT nRet = aoo_MsiGetSummaryInformation( NULL, szDatabasePath, 0, &hSummaryInfo ); 1786 1787 if ( nRet != ERROR_SUCCESS ) 1788 { 1789 StringCchPrintf( sBuf, 80, TEXT("ERROR: IsPatchInstalled: MsiGetSummaryInformation returned %u.\r\n"), nRet ); 1790 Log( sBuf ); 1791 return false; 1792 } 1793 1794 UINT uiDataType; 1795 LPTSTR szPatchID = new TCHAR[ 64 ]; 1796 DWORD cchValueBuf = 64; 1797 nRet = aoo_MsiSummaryInfoGetProperty( hSummaryInfo, PID_REVNUMBER, &uiDataType, NULL, NULL, szPatchID, &cchValueBuf ); 1798 1799 if ( nRet != ERROR_SUCCESS ) 1800 { 1801 StringCchPrintf( sBuf, 80, TEXT("ERROR: IsPatchInstalled: MsiSummaryInfoGetProperty returned %u.\r\n"), nRet ); 1802 Log( sBuf ); 1803 return false; 1804 } 1805 1806 nRet = aoo_MsiGetPatchInfo( szPatchID, INSTALLPROPERTY_LOCALPACKAGE, NULL, NULL ); 1807 1808 StringCchPrintf( sBuf, 80, TEXT(" GetPatchInfo for (%s) returned (%u)\r\n"), szPatchID, nRet ); 1809 Log( sBuf ); 1810 1811 delete []szPatchID; 1812 1813 if ( nRet == ERROR_BAD_CONFIGURATION ) 1814 return false; 1815 else if ( nRet == ERROR_INVALID_PARAMETER ) 1816 return false; 1817 else if ( nRet == ERROR_MORE_DATA ) 1818 return true; 1819 else if ( nRet == ERROR_SUCCESS ) 1820 return true; 1821 else if ( nRet == ERROR_UNKNOWN_PRODUCT ) 1822 return false; 1823 else if ( nRet == ERROR_UNKNOWN_PROPERTY ) 1824 return false; 1825 else return false; 1826 } 1827 1828 //-------------------------------------------------------------------------- 1829 boolean SetupApp::InstallRuntimes( TCHAR *sProductCode, TCHAR *sRuntimePath ) 1830 { 1831 INSTALLSTATE nRet = aoo_MsiQueryProductState( sProductCode ); 1832 OutputDebugStringFormat( TEXT( "MsiQueryProductState returned <%d>\r\n" ), nRet ); 1833 if ( nRet == INSTALLSTATE_DEFAULT ) 1834 return true; 1835 1836 Log( TEXT( " Will install runtime <%s>\r\n" ), sRuntimePath ); 1837 OutputDebugStringFormat( TEXT( " Will install runtime <%s>\r\n" ), sRuntimePath ); 1838 1839 STARTUPINFO aSUI; 1840 PROCESS_INFORMATION aPI; 1841 1842 ZeroMemory( (void*)&aPI, sizeof( PROCESS_INFORMATION ) ); 1843 ZeroMemory( (void*)&aSUI, sizeof( STARTUPINFO ) ); 1844 1845 aSUI.cb = sizeof(STARTUPINFO); 1846 aSUI.dwFlags = STARTF_USESHOWWINDOW; 1847 aSUI.wShowWindow = SW_SHOW; 1848 1849 DWORD nCmdLineLength = lstrlen( sRuntimePath ) + lstrlen( PARAM_SILENTINSTALL ) + 2; 1850 TCHAR *sCmdLine = new TCHAR[ nCmdLineLength ]; 1851 1852 if ( FAILED( StringCchCopy( sCmdLine, nCmdLineLength, sRuntimePath ) ) || 1853 FAILED( StringCchCat( sCmdLine, nCmdLineLength, PARAM_SILENTINSTALL ) ) ) 1854 { 1855 delete [] sCmdLine; 1856 SetError( ERROR_INSTALL_FAILURE ); 1857 return false; 1858 } 1859 1860 if ( !WIN::CreateProcess( NULL, sCmdLine, NULL, NULL, FALSE, 1861 CREATE_DEFAULT_ERROR_MODE, NULL, NULL, 1862 &aSUI, &aPI ) ) 1863 { 1864 Log( TEXT( "ERROR: Could not create process %s.\r\n" ), sCmdLine ); 1865 SetError( WIN::GetLastError() ); 1866 delete [] sCmdLine; 1867 return false; 1868 } 1869 1870 DWORD nResult = WaitForProcess( aPI.hProcess ); 1871 bool bRet = true; 1872 1873 if( ERROR_SUCCESS != nResult ) 1874 { 1875 Log( TEXT( "ERROR: While waiting for %s.\r\n" ), sCmdLine ); 1876 SetError( nResult ); 1877 bRet = false; 1878 } 1879 else 1880 { 1881 GetExitCodeProcess( aPI.hProcess, &nResult ); 1882 SetError( nResult ); 1883 1884 if ( nResult != ERROR_SUCCESS ) 1885 { 1886 TCHAR sBuf[80]; 1887 StringCchPrintf( sBuf, 80, TEXT("Warning: install runtime returned %u.\r\n"), nResult ); 1888 Log( sBuf ); 1889 } 1890 else 1891 Log( TEXT( " Installation of runtime completed successfully.\r\n" ) ); 1892 } 1893 1894 CloseHandle( aPI.hProcess ); 1895 1896 delete [] sCmdLine; 1897 1898 return bRet; 1899 } 1900 1901 //-------------------------------------------------------------------------- 1902 boolean SetupApp::InstallRuntimes() 1903 { 1904 TCHAR *sRuntimePath = 0; 1905 SYSTEM_INFO siSysInfo; 1906 1907 HMODULE hKernel32 = ::LoadLibrary(_T("Kernel32.dll")); 1908 if ( hKernel32 != NULL ) 1909 { 1910 typedef void (CALLBACK* pfnGetNativeSystemInfo_t)(LPSYSTEM_INFO); 1911 pfnGetNativeSystemInfo_t pfnGetNativeSystemInfo; 1912 pfnGetNativeSystemInfo = (pfnGetNativeSystemInfo_t)::GetProcAddress(hKernel32, "GetNativeSystemInfo"); 1913 if ( pfnGetNativeSystemInfo != NULL ) 1914 { 1915 pfnGetNativeSystemInfo(&siSysInfo); 1916 } 1917 else 1918 { 1919 // GetNativeSystemInfo does not exist. Maybe the code is running under Windows 2000. 1920 // Use GetSystemInfo instead. 1921 GetSystemInfo(&siSysInfo); 1922 } 1923 FreeLibrary(hKernel32); 1924 } 1925 else 1926 { 1927 // Failed to check Kernel32.dll. There may be something wrong. 1928 // Use GetSystemInfo instead anyway. 1929 GetSystemInfo(&siSysInfo); 1930 } 1931 1932 OutputDebugStringFormat( TEXT( "found architecture<%d>\r\n" ), siSysInfo.wProcessorArchitecture ); 1933 1934 if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) 1935 { 1936 if ( GetPathToFile( RUNTIME_X64_NAME, &sRuntimePath ) ) 1937 InstallRuntimes( PRODUCTCODE_X64, sRuntimePath ); 1938 else 1939 Log( TEXT( "ERROR: no installer for x64 runtime libraries found!" ) ); 1940 1941 if ( sRuntimePath ) 1942 { 1943 delete [] sRuntimePath; 1944 sRuntimePath = 0; 1945 } 1946 } 1947 1948 if ( GetPathToFile( RUNTIME_X86_NAME, &sRuntimePath ) ) 1949 InstallRuntimes( PRODUCTCODE_X86, sRuntimePath ); 1950 else 1951 Log( TEXT( "ERROR: no installer for x86 runtime libraries found!" ) ); 1952 1953 if ( sRuntimePath ) 1954 delete [] sRuntimePath; 1955 1956 return true; 1957 } 1958 1959 //-------------------------------------------------------------------------- 1960 //-------------------------------------------------------------------------- 1961 LanguageData::LanguageData( LPTSTR pData ) 1962 { 1963 m_nLanguageID = 0; 1964 m_pTransform = NULL; 1965 1966 LPTSTR pLastChar; 1967 1968 m_nLanguageID = _tcstol( pData, &pLastChar, 10 ); 1969 1970 if ( *pLastChar == ',' ) 1971 { 1972 pLastChar += 1; 1973 int nLen = lstrlen( pLastChar ) + 1; 1974 m_pTransform = new TCHAR [ nLen ]; 1975 StringCchCopy( m_pTransform, nLen, pLastChar ); 1976 } 1977 } 1978 1979 //-------------------------------------------------------------------------- 1980 LanguageData::~LanguageData() 1981 { 1982 if ( m_pTransform ) delete [] m_pTransform; 1983 } 1984 1985 //-------------------------------------------------------------------------- 1986