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