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