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