1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: setup.cpp,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #define WIN // scope W32 API
34 #pragma warning(push, 1)
55 //--------------------------------------------------------------------------
57 #define MAX_STR_LENGTH 32000
58 #define MAX_TEXT_LENGTH 1024
59 #define MAX_LANGUAGE_LEN 80
60 #define MAX_STR_CAPTION 256
61 #define VERSION_SIZE 80
62 #define SECTION_SETUP TEXT( "Setup" )
63 #define SECTION_LANGUAGE TEXT( "Languages" )
64 #define PRODUCT_NAME_VAR TEXT( "%PRODUCTNAME" )
65 #define PRODUCT_VERSION TEXT( "ProductVersion" )
66 #define ERROR_SHOW_USAGE -2
67 #define ERROR_SETUP_TO_OLD -3
68 #define ERROR_SETUP_NOT_FOUND -4
70 #define PARAM_SETUP_USED TEXT( " SETUP_USED=1 " )
71 #define PARAM_PACKAGE TEXT( "/I " )
72 #define PARAM_MINOR_UPGRADE TEXT( "/FVOMUS " )
73 #define PARAM_ADMIN TEXT( "/A " )
74 #define PARAM_TRANSFORM TEXT( " TRANSFORMS=" )
75 #define PARAM_REBOOT TEXT( " REBOOT=Force" )
76 #define PARAM_PATCH TEXT( " /update " )
77 #define PARAM_REG_ALL_MSO_TYPES TEXT( "REGISTER_ALL_MSO_TYPES=1 " )
78 #define PARAM_REG_NO_MSO_TYPES TEXT( "REGISTER_NO_MSO_TYPES=1 " )
80 #define PARAM_RUNNING TEXT( "ignore_running" )
81 #define CMDLN_REG_ALL_MSO_TYPES TEXT( "msoreg=1" )
82 #define CMDLN_REG_NO_MSO_TYPES TEXT( "msoreg=0" )
84 #define MSI_DLL TEXT( "msi.dll" )
85 #define ADVAPI32_DLL TEXT( "advapi32.dll" )
86 #define PROFILE_NAME TEXT( "setup.ini" )
88 #define MSIAPI_DllGetVersion "DllGetVersion"
89 #define ADVAPI32API_CheckTokenMembership "CheckTokenMembership"
91 typedef HRESULT (CALLBACK
* PFnDllGetVersion
)( DLLVERSIONINFO
*pdvi
);
92 typedef BOOL (WINAPI
* PFnCheckTokenMembership
)(HANDLE TokenHandle
, PSID SidToCheck
, PBOOL IsMember
);
95 inline void OutputDebugStringFormat( LPCTSTR pFormat
, ... )
100 va_start( args
, pFormat
);
101 StringCchVPrintf( buffer
, sizeof(buffer
), pFormat
, args
);
102 OutputDebugString( buffer
);
105 static inline void OutputDebugStringFormat( LPCTSTR
, ... )
110 //--------------------------------------------------------------------------
112 const TCHAR sInstKey
[] = TEXT( "Software\\Microsoft\\Windows\\CurrentVersion\\Installer" );
113 const TCHAR sInstLocValue
[] = TEXT( "InstallerLocation" );
114 const TCHAR sMsiDll
[] = TEXT( "\\msi.dll" );
115 const TCHAR sMsiExe
[] = TEXT( "\\msiexec.exe" );
116 const TCHAR sDelayReboot
[] = TEXT( " /c:\"msiinst /delayreboot\"" );
117 const TCHAR sMsiQuiet
[] = TEXT( " /q" );
118 const TCHAR sMemMapName
[] = TEXT( "Global\\MsiErrorObject" );
120 //--------------------------------------------------------------------------
121 SetupAppX::SetupAppX()
129 m_pReqVersion
= NULL
;
130 m_pProductName
= NULL
;
134 m_pModuleFile
= NULL
;
135 m_pPatchFiles
= NULL
;
136 m_pMSIErrorCode
= NULL
;
137 m_pUpgradeKey
= NULL
;
138 m_pProductVersion
= NULL
;
140 m_pErrorText
= new TCHAR
[ MAX_TEXT_LENGTH
];
141 m_pErrorText
[0] = '\0';
144 m_nLanguageCount
= 0;
145 m_ppLanguageList
= NULL
;
148 m_bRegNoMsoTypes
= false;
149 m_bRegAllMsoTypes
= false;
150 m_bIsMinorUpgrade
= false;
151 m_bSupportsPatch
= false;
153 m_bIgnoreAlreadyRunning
= false;
156 //--------------------------------------------------------------------------
157 SetupAppX::~SetupAppX()
159 if ( m_ppLanguageList
)
161 for ( int i
= 0; i
< m_nLanguageCount
; i
++ )
162 if ( m_ppLanguageList
[i
] )
163 delete m_ppLanguageList
[ i
];
164 delete [] m_ppLanguageList
;
169 tm
*pTime
= localtime( &aTime
); // Convert time to struct tm form
171 Log( TEXT( "End: %s\n\r\n\r\n" ), _tasctime( pTime
) );
173 if ( m_pLogFile
) fclose( m_pLogFile
);
177 _tremove( m_pTmpName
);
181 if ( m_pMSIErrorCode
) UnmapViewOfFile( m_pMSIErrorCode
);
182 if ( m_hMapFile
) CloseHandle( m_hMapFile
);
184 if ( m_pAppTitle
) delete [] m_pAppTitle
;
185 if ( m_pDatabase
) delete [] m_pDatabase
;
186 if ( m_pReqVersion
) delete [] m_pReqVersion
;
187 if ( m_pProductName
) delete [] m_pProductName
;
188 if ( m_pAdvertise
) delete [] m_pAdvertise
;
189 if ( m_pLogFile
) delete [] m_pLogFile
;
190 if ( m_pErrorText
) delete [] m_pErrorText
;
191 if ( m_pModuleFile
) delete [] m_pModuleFile
;
192 if ( m_pPatchFiles
) delete [] m_pPatchFiles
;
193 if ( m_pUpgradeKey
) delete [] m_pUpgradeKey
;
194 if ( m_pProductVersion
) delete [] m_pProductVersion
;
197 //--------------------------------------------------------------------------
198 boolean
SetupAppX::Initialize( HINSTANCE hInst
)
200 m_pCmdLine
= WIN::GetCommandLine();
203 // Load our AppTitle (caption)
204 m_pAppTitle
= new TCHAR
[ MAX_STR_CAPTION
];
205 m_pAppTitle
[0] = '\0';
206 WIN::LoadString( hInst
, IDS_APP_TITLE
, m_pAppTitle
, MAX_STR_CAPTION
);
208 // Obtain path we are running from
209 m_pModuleFile
= new TCHAR
[ MAX_PATH
];
210 m_pModuleFile
[ 0 ] = '\0';
212 if ( 0 == WIN::GetModuleFileName( hInst
, m_pModuleFile
, MAX_PATH
) )
214 SetError( WIN::GetLastError() );
218 if ( ! GetCmdLineParameters( &m_pCmdLine
) )
221 m_hMapFile
= CreateFileMapping(
222 INVALID_HANDLE_VALUE
, // use paging file
223 NULL
, // default security
224 PAGE_READWRITE
, // read/write access
225 0, // max. object size
226 sizeof( int ), // buffer size
230 m_pMSIErrorCode
= (int*) MapViewOfFile( m_hMapFile
, // handle to map object
231 FILE_MAP_ALL_ACCESS
, // read/write permission
235 if ( m_pMSIErrorCode
)
236 *m_pMSIErrorCode
= 0;
238 OutputDebugStringFormat( TEXT("Could not map view of file (%d).\n"), GetLastError() );
241 OutputDebugStringFormat( TEXT("Could not create file mapping object (%d).\n"), GetLastError() );
243 Log( TEXT("Starting: %s\r\n"), m_pModuleFile
);
244 Log( TEXT(" CommandLine=<%s>\r\n"), m_pCmdLine
);
247 Log( TEXT(" Using quiet install mode\r\n") );
251 tm
* pTime
= localtime( &aTime
);
252 Log( TEXT(" Begin: %s\n"), _tasctime( pTime
) );
257 //--------------------------------------------------------------------------
258 boolean
SetupAppX::GetProfileSection( LPCTSTR pFileName
, LPCTSTR pSection
,
259 DWORD
& rSize
, LPTSTR
*pRetBuf
)
261 if ( !rSize
|| !*pRetBuf
)
264 *pRetBuf
= new TCHAR
[ rSize
];
267 DWORD nRet
= GetPrivateProfileSection( pSection
, *pRetBuf
, rSize
, pFileName
);
269 if ( nRet
&& ( nRet
+ 2 > rSize
) ) // buffer was too small, retry with bigger one
271 if ( nRet
< 32767 - 2 )
273 delete [] (*pRetBuf
);
275 *pRetBuf
= new TCHAR
[ rSize
];
277 nRet
= GetPrivateProfileSection( pSection
, *pRetBuf
, rSize
, pFileName
);
283 SetError( WIN::GetLastError() );
286 StringCchPrintf( sBuf
, 80, TEXT("ERROR: GetPrivateProfileSection(): GetLastError returned %u\r\n"), GetError() );
290 else if ( nRet
+ 2 > rSize
)
292 SetError( ERROR_OUTOFMEMORY
);
293 Log( TEXT( "ERROR: GetPrivateProfileSection() out of memory\r\n" ) );
297 Log( TEXT( " GetProfileSection read %s\r\n" ), pSection
);
302 //--------------------------------------------------------------------------
303 boolean
SetupAppX::ReadProfile()
305 boolean bRet
= false;
306 TCHAR
*sProfilePath
= 0;
308 if ( GetPathToFile( PROFILE_NAME
, &sProfilePath
) )
311 LPTSTR pRetBuf
= NULL
;
313 Log( TEXT( " Open ini file: <%s>\r\n" ), sProfilePath
);
315 bRet
= GetProfileSection( sProfilePath
, SECTION_SETUP
, nSize
, &pRetBuf
);
319 LPTSTR pTmpFile
= CopyIniFile( sProfilePath
);
320 delete [] sProfilePath
;
321 sProfilePath
= pTmpFile
;
325 SetError( ERROR_SUCCESS
);
327 Log( TEXT( " Could not open inifile, copied ini file to: <%s>\r\n" ), sProfilePath
);
328 bRet
= GetProfileSection( sProfilePath
, SECTION_SETUP
, nSize
, &pRetBuf
);
334 LPTSTR pCurLine
= pRetBuf
;
340 pCurLine
+= GetNameValue( pCurLine
, &pName
, &pValue
);
342 if ( lstrcmpi( TEXT( "database" ), pName
) == 0 )
344 m_pDatabase
= pValue
;
345 Log( TEXT( " Database = %s\r\n" ), pValue
);
347 else if ( lstrcmpi( TEXT( "msiversion" ), pName
) == 0 )
349 m_pReqVersion
= pValue
;
350 Log( TEXT( " msiversion = %s\r\n" ), pValue
);
352 else if ( lstrcmpi( TEXT( "productname" ), pName
) == 0 )
354 m_pProductName
= pValue
;
355 Log( TEXT( " productname = %s\r\n" ), pValue
);
356 m_pAppTitle
= SetProdToAppTitle( m_pProductName
);
358 else if ( lstrcmpi( TEXT( "upgradekey" ), pName
) == 0 )
360 m_pUpgradeKey
= pValue
;
361 Log( TEXT( " upgradekey = %s\r\n" ), pValue
);
363 else if ( lstrcmpi( TEXT( "productversion" ), pName
) == 0 )
365 m_pProductVersion
= pValue
;
366 Log( TEXT( " productversion = %s\r\n" ), pValue
);
368 else if ( lstrcmpi( TEXT( "productcode" ), pName
) == 0 )
374 Log( TEXT( "Warning: unknown entry in profile <%s>\r\n" ), pName
);
380 if ( bRet
&& ( !m_pDatabase
|| !m_pReqVersion
|| !m_pProductName
) )
382 Log( TEXT( "ERROR: incomplete 'Setup' section in profile\r\n" ) );
383 SetError( ERROR_INVALID_DATA
);
388 bRet
= GetProfileSection( sProfilePath
, SECTION_LANGUAGE
, nSize
, &pRetBuf
);
394 LPTSTR pCurLine
= pRetBuf
;
398 // first line in this section should be the language count
399 nNext
= GetNameValue( pCurLine
, &pName
, &pValue
);
400 if ( lstrcmpi( TEXT( "count" ), pName
) == 0 )
402 Log( TEXT( " Languages = %s\r\n" ), pValue
);
403 m_nLanguageCount
= _tcstol( pValue
, &pLastChar
, 10 );
408 m_ppLanguageList
= new LanguageDataX
*[ m_nLanguageCount
];
410 for ( int i
=0; i
< m_nLanguageCount
; i
++ )
414 m_nLanguageCount
= i
;
418 pCurLine
+= GetNameValue( pCurLine
, &pName
, &pValue
);
419 m_ppLanguageList
[ i
] = new LanguageDataX( pValue
);
420 Log( TEXT( " Language = %s\r\n" ), pValue
);
422 if ( m_ppLanguageList
[ i
]->m_pTransform
)
423 Log( TEXT( " Transform = %s\r\n" ), m_ppLanguageList
[ i
]->m_pTransform
);
433 if ( sProfilePath
&& ! m_pTmpName
)
434 delete [] sProfilePath
;
439 //--------------------------------------------------------------------------
440 void SetupAppX::AddFileToPatchList( TCHAR
* pPath
, TCHAR
* pFile
)
442 if ( m_pPatchFiles
== NULL
)
444 m_pPatchFiles
= new TCHAR
[ MAX_STR_LENGTH
];
445 StringCchCopy( m_pPatchFiles
, MAX_STR_LENGTH
, TEXT("\"") );
448 StringCchCat( m_pPatchFiles
, MAX_STR_LENGTH
, TEXT(";") );
450 StringCchCat( m_pPatchFiles
, MAX_STR_LENGTH
, pPath
);
451 StringCchCat( m_pPatchFiles
, MAX_STR_LENGTH
, pFile
);
454 //--------------------------------------------------------------------------
455 boolean
SetupAppX::GetPatches()
459 int nPatternLen
= lstrlen( m_pModuleFile
) + 7; // 1 for null terminator, 1 for back slash, 5 for extensions
460 TCHAR
* pPattern
= new TCHAR
[ nPatternLen
];
461 TCHAR
* pBaseDir
= new TCHAR
[ nPatternLen
];
463 // find 'setup.exe' in the path so we can remove it
464 TCHAR
*pFilePart
= 0;
465 if ( 0 == GetFullPathName( m_pModuleFile
, nPatternLen
, pPattern
, &pFilePart
) )
467 SetError( WIN::GetLastError() );
474 StringCchCopy( pBaseDir
, nPatternLen
, pPattern
);
475 StringCchCat( pPattern
, nPatternLen
, TEXT("*.msp") );
477 WIN32_FIND_DATA aFindFileData
;
479 HANDLE hFindPatches
= FindFirstFile( pPattern
, &aFindFileData
);
481 if ( hFindPatches
!= INVALID_HANDLE_VALUE
)
483 if ( ! IsPatchInstalled( pBaseDir
, aFindFileData
.cFileName
) )
484 AddFileToPatchList( pBaseDir
, aFindFileData
.cFileName
);
486 while ( FindNextFile( hFindPatches
, &aFindFileData
) )
488 if ( ! IsPatchInstalled( pBaseDir
, aFindFileData
.cFileName
) )
489 AddFileToPatchList( pBaseDir
, aFindFileData
.cFileName
);
492 if ( m_pPatchFiles
!= NULL
)
493 StringCchCat( m_pPatchFiles
, MAX_STR_LENGTH
, TEXT("\"") );
495 FindClose( hFindPatches
);
505 //--------------------------------------------------------------------------
506 boolean
SetupAppX::GetPathToFile( TCHAR
* pFileName
, TCHAR
** pPath
)
508 // generate the path to the file = szModuleFile + FileName
509 // note: FileName is a relative path
513 int nTempPath
= lstrlen( m_pModuleFile
) + lstrlen( pFileName
) + 2; // 1 for null terminator, 1 for back slash
514 TCHAR
* pTempPath
= new TCHAR
[ nTempPath
];
516 // find 'setup.exe' in the path so we can remove it
517 TCHAR
*pFilePart
= 0;
518 if ( 0 == GetFullPathName( m_pModuleFile
, nTempPath
, pTempPath
, &pFilePart
) )
520 SetError( WIN::GetLastError() );
528 StringCchCat( pTempPath
, nTempPath
, pFileName
);
530 int nPath
= 2 * nTempPath
;
531 *pPath
= new TCHAR
[ nPath
];
533 // normalize the path
534 int nReturn
= GetFullPathName( pTempPath
, nPath
, *pPath
, &pFilePart
);
536 if ( nReturn
> nPath
)
538 // try again, with larger buffer
541 *pPath
= new TCHAR
[ nPath
];
543 nReturn
= GetFullPathName( pTempPath
, nPath
, *pPath
, &pFilePart
);
548 // error -- invalid path
549 SetError( WIN::GetLastError() );
554 if ( bRet
) // check for the file's existence
556 DWORD dwFileAttrib
= GetFileAttributes( *pPath
);
558 if (0xFFFFFFFF == dwFileAttrib
)
560 StringCchCopy( m_pErrorText
, MAX_TEXT_LENGTH
, pFileName
);
561 SetError( ERROR_FILE_NOT_FOUND
);
570 //--------------------------------------------------------------------------
571 int SetupAppX::GetNameValue( TCHAR
* pLine
, TCHAR
** pName
, TCHAR
** pValue
)
573 int nRet
= lstrlen( pLine
) + 1;
579 LPTSTR pChar
= pLine
;
582 // Skip leading spaces.
583 while (' ' == *pChar
|| '\t' == *pChar
)
584 pChar
= CharNext( pChar
);
588 // look for the end of the name
589 while( *pChar
&& (' ' != *pChar
) &&
590 ( '\t' != *pChar
) && ( '=' != *pChar
) )
591 pChar
= CharNext( pChar
);
597 pChar
= CharNext( pChar
);
600 // look for the start of the value
601 while( ( ' ' == *pChar
) || ( '\t' == *pChar
) ||
603 pChar
= CharNext( pChar
);
605 int nValueLen
= lstrlen( pChar
) + 1;
606 *pValue
= new TCHAR
[ nValueLen
];
609 StringCchCopy( *pValue
, nValueLen
, pChar
);
614 //--------------------------------------------------------------------------
615 boolean
SetupAppX::ChooseLanguage( long& rLanguage
)
622 // When there are none or only one language, there is nothing
624 if ( m_nLanguageCount
> 1 )
626 TCHAR
*sString
= new TCHAR
[ MAX_LANGUAGE_LEN
];
628 LANGID nUserDefLang
= GetUserDefaultLangID();
629 LANGID nSysDefLang
= GetSystemDefaultLangID();
631 int nUserPrimary
= PRIMARYLANGID( nUserDefLang
);
632 int nSysPrimary
= PRIMARYLANGID( nSysDefLang
);
634 long nUserIndex
= -1;
635 long nUserPrimIndex
= -1;
636 long nSystemIndex
= -1;
637 long nSystemPrimIndex
= -1;
638 long nParamIndex
= -1;
640 for ( long i
=0; i
<GetLanguageCount(); i
++ )
642 long nLanguage
= GetLanguageID( i
);
643 int nPrimary
= PRIMARYLANGID( nLanguage
);
644 GetLanguageName( nLanguage
, sString
);
645 Log( TEXT( " Info: found Language: %s\r\n" ), sString
);
647 if ( nLanguage
== nUserDefLang
)
649 if ( nPrimary
== nUserPrimary
)
651 if ( nLanguage
== nSysDefLang
)
653 if ( nPrimary
== nSysPrimary
)
654 nSystemPrimIndex
= i
;
655 if ( m_nLanguageID
&& ( nLanguage
== m_nLanguageID
) )
659 if ( m_nLanguageID
&& ( nParamIndex
== -1 ) )
661 Log( TEXT( "Warning: Language chosen with parameter -lang not found.\r\n" ) );
664 if ( nParamIndex
!= -1 )
666 Log( TEXT( "Info: Found language chosen with parameter -lang.\r\n" ) );
667 rLanguage
= GetLanguageID( nParamIndex
);
669 else if ( nUserIndex
!= -1 )
671 Log( TEXT( "Info: Found user default language.\r\n" ) );
672 rLanguage
= GetLanguageID( nUserIndex
);
674 else if ( nUserPrimIndex
!= -1 )
676 Log( TEXT( "Info: Found user default primary language.\r\n" ) );
677 rLanguage
= GetLanguageID( nUserPrimIndex
);
679 else if ( nSystemIndex
!= -1 )
681 Log( TEXT( "Info: Found system default language.\r\n" ) );
682 rLanguage
= GetLanguageID( nSystemIndex
);
684 else if ( nSystemPrimIndex
!= -1 )
686 Log( TEXT( "Info: Found system default primary language.\r\n" ) );
687 rLanguage
= GetLanguageID( nSystemPrimIndex
);
691 Log( TEXT( "Info: Use default language from ini file.\r\n" ) );
692 rLanguage
= GetLanguageID( 0 );
700 //--------------------------------------------------------------------------
701 HMODULE
SetupAppX::LoadMsiLibrary()
704 HKEY hInstKey
= NULL
;
706 // find registered location of Msi.dll
707 if ( ERROR_SUCCESS
== RegOpenKeyEx( HKEY_LOCAL_MACHINE
, sInstKey
, 0, KEY_READ
, &hInstKey
) )
709 long nRet
= ERROR_SUCCESS
;
710 TCHAR
*sMsiFolder
= new TCHAR
[ MAX_PATH
+ 1 ];
711 DWORD dwMsiFolderSize
= MAX_PATH
+ 1;
714 if ( ERROR_MORE_DATA
== ( nRet
= RegQueryValueEx( hInstKey
, sInstLocValue
, NULL
,
715 &dwType
, (BYTE
*)sMsiFolder
, &dwMsiFolderSize
) ) )
717 // try again with larger buffer
718 delete [] sMsiFolder
;
719 sMsiFolder
= new TCHAR
[ dwMsiFolderSize
];
721 nRet
= RegQueryValueEx( hInstKey
, sInstLocValue
, NULL
, &dwType
,
722 (BYTE
*)sMsiFolder
, &dwMsiFolderSize
);
725 if ( ERROR_SUCCESS
== nRet
&& dwType
== REG_SZ
&& dwMsiFolderSize
> 0 )
727 // load Msi.dll from registered location
728 int nLength
= lstrlen( sMsiDll
) + dwMsiFolderSize
+ 1; // use StringCchLength ?
729 TCHAR
*pMsiLocation
= new TCHAR
[ nLength
];
731 if ( SUCCEEDED( StringCchCopy( pMsiLocation
, nLength
, sMsiFolder
) ) &&
732 SUCCEEDED( StringCchCat( pMsiLocation
, nLength
, sMsiDll
) ) )
734 hMsi
= LoadLibrary( pMsiLocation
);
739 if ( !hMsi
) // use the default location
741 hMsi
= LoadLibrary( sMsiDll
);
747 //--------------------------------------------------------------------------
748 LPCTSTR
SetupAppX::GetPathToMSI()
750 LPTSTR sMsiPath
= NULL
;
751 HKEY hInstKey
= NULL
;
752 TCHAR
*sMsiFolder
= new TCHAR
[ MAX_PATH
+ 1 ];
753 DWORD nMsiFolderSize
= MAX_PATH
+ 1;
755 sMsiFolder
[0] = '\0';
757 // find registered location of Msi.dll
758 if ( ERROR_SUCCESS
== RegOpenKeyEx( HKEY_LOCAL_MACHINE
, sInstKey
, 0, KEY_READ
, &hInstKey
) )
760 LONG nRet
= ERROR_SUCCESS
;
763 if ( ERROR_MORE_DATA
== ( nRet
= RegQueryValueEx( hInstKey
, sInstLocValue
, NULL
,
764 &dwType
, (BYTE
*)sMsiFolder
, &nMsiFolderSize
) ) )
766 // try again with larger buffer
767 delete [] sMsiFolder
;
768 sMsiFolder
= new TCHAR
[ nMsiFolderSize
];
770 nRet
= RegQueryValueEx( hInstKey
, sInstLocValue
, NULL
, &dwType
,
771 (BYTE
*)sMsiFolder
, &nMsiFolderSize
);
774 if ( ERROR_SUCCESS
!= nRet
|| dwType
!= REG_SZ
|| nMsiFolderSize
== 0 )
775 sMsiFolder
[0] = '\0';
778 if ( sMsiFolder
[0] == '\0' ) // use the default location
780 Log( TEXT( " Could not find path to msiexec.exe in registry" ) );
782 DWORD nRet
= WIN::GetSystemDirectory( sMsiFolder
, nMsiFolderSize
);
783 if ( nRet
> nMsiFolderSize
)
785 delete [] sMsiFolder
;
786 sMsiFolder
= new TCHAR
[ nRet
];
787 nMsiFolderSize
= nRet
;
789 nRet
= WIN::GetSystemDirectory( sMsiFolder
, nMsiFolderSize
);
793 sMsiFolder
[0] = '\0';
794 SetError( WIN::GetLastError() );
796 nMsiFolderSize
= nRet
;
799 if ( sMsiFolder
[0] != '\0' )
801 int nLength
= lstrlen( sMsiExe
) + lstrlen( sMsiFolder
) + 1;
802 sMsiPath
= new TCHAR
[ nLength
];
804 if ( FAILED( StringCchCopy( sMsiPath
, nLength
, sMsiFolder
) ) ||
805 FAILED( StringCchCat( sMsiPath
, nLength
, sMsiExe
) ) )
813 Log( TEXT( "ERROR: Can't build path to msiexec.exe!" ) );
818 //--------------------------------------------------------------------------
819 boolean
SetupAppX::LaunchInstaller( LPCTSTR pParam
)
821 LPCTSTR sMsiPath
= GetPathToMSI();
825 Log( TEXT( "ERROR: msiexec not found!" ) );
826 SetError( ERROR_FILE_NOT_FOUND
);
831 PROCESS_INFORMATION aPI
;
833 Log( TEXT( " Will install using <%s>\r\n" ), sMsiPath
);
834 Log( TEXT( " Prameters are: %s\r\n" ), pParam
);
836 OutputDebugStringFormat( TEXT( " Will install using <%s>\r\n" ), sMsiPath
);
837 OutputDebugStringFormat( TEXT( " Prameters are: %s\r\n" ), pParam
);
839 ZeroMemory( (void*)&aPI
, sizeof( PROCESS_INFORMATION
) );
840 ZeroMemory( (void*)&aSUI
, sizeof( STARTUPINFO
) );
842 aSUI
.cb
= sizeof(STARTUPINFO
);
843 aSUI
.dwFlags
= STARTF_USESHOWWINDOW
;
844 aSUI
.wShowWindow
= SW_SHOW
;
846 DWORD nCmdLineLength
= lstrlen( sMsiPath
) + lstrlen( pParam
) + 2;
847 TCHAR
*sCmdLine
= new TCHAR
[ nCmdLineLength
];
849 if ( FAILED( StringCchCopy( sCmdLine
, nCmdLineLength
, sMsiPath
) ) ||
850 FAILED( StringCchCat( sCmdLine
, nCmdLineLength
, TEXT( " " ) ) ) ||
851 FAILED( StringCchCat( sCmdLine
, nCmdLineLength
, pParam
) ) )
854 SetError( ERROR_INSTALL_FAILURE
);
858 if ( !WIN::CreateProcess( NULL
, sCmdLine
, NULL
, NULL
, FALSE
,
859 CREATE_DEFAULT_ERROR_MODE
, NULL
, NULL
,
862 Log( TEXT( "ERROR: Could not create process %s.\r\n" ), sCmdLine
);
863 SetError( WIN::GetLastError() );
868 DWORD nResult
= WaitForProcess( aPI
.hProcess
);
871 if( ERROR_SUCCESS
!= nResult
)
873 Log( TEXT( "ERROR: While waiting for %s.\r\n" ), sCmdLine
);
879 GetExitCodeProcess( aPI
.hProcess
, &nResult
);
882 if ( nResult
!= ERROR_SUCCESS
)
885 StringCchPrintf( sBuf
, 80, TEXT("Warning: msiexec returned %u.\r\n"), nResult
);
889 Log( TEXT( " Installation completed successfully.\r\n" ) );
892 CloseHandle( aPI
.hProcess
);
899 //--------------------------------------------------------------------------
900 boolean
SetupAppX::Install( long nLanguage
)
902 LPTSTR pTransform
= NULL
;
904 if ( nLanguage
) // look for transformation
906 for ( int i
= 0; i
< m_nLanguageCount
; i
++ )
908 if ( m_ppLanguageList
[i
]->m_nLanguageID
== nLanguage
)
910 if ( m_ppLanguageList
[i
]->m_pTransform
)
912 if ( !GetPathToFile( m_ppLanguageList
[i
]->m_pTransform
,
915 Log( TEXT( "ERROR: Could not find transform <%s\r\n" ), m_ppLanguageList
[i
]->m_pTransform
);
924 TCHAR
*pDataBasePath
= NULL
;
926 if ( ! GetPathToFile( m_pDatabase
, &pDataBasePath
) )
928 Log( TEXT( "ERROR: Could not find database <%s\r\n" ), m_pDatabase
);
929 SetError( ERROR_INSTALL_SOURCE_ABSENT
);
933 // we will always use the parameter setup used
934 int nParLen
= lstrlen( PARAM_SETUP_USED
);
936 if ( m_bRegNoMsoTypes
)
937 nParLen
+= lstrlen( PARAM_REG_NO_MSO_TYPES
);
938 else if ( m_bRegAllMsoTypes
)
939 nParLen
+= lstrlen( PARAM_REG_ALL_MSO_TYPES
);
942 nParLen
+= lstrlen( m_pAdvertise
) + 1; // one for the space
943 else if ( m_bIsMinorUpgrade
)
944 nParLen
+= lstrlen( PARAM_MINOR_UPGRADE
);
946 nParLen
+= lstrlen( PARAM_PACKAGE
);
948 nParLen
+= lstrlen( pDataBasePath
) + 3; // two quotes, one null
951 nParLen
+= lstrlen( PARAM_REBOOT
);
955 nParLen
+= lstrlen( PARAM_PATCH
);
956 nParLen
+= lstrlen( m_pPatchFiles
);
961 nParLen
+= lstrlen( PARAM_TRANSFORM
);
962 nParLen
+= lstrlen( pTransform
) + 2; // two quotes
966 nParLen
+= lstrlen( m_pCmdLine
) + 1; // one for the space;
968 TCHAR
*pParams
= new TCHAR
[ nParLen
];
970 StringCchCopy( pParams
, nParLen
, PARAM_SETUP_USED
);
972 if ( m_bRegNoMsoTypes
)
973 StringCchCat( pParams
, nParLen
, PARAM_REG_NO_MSO_TYPES
);
974 else if ( m_bRegAllMsoTypes
)
975 StringCchCat( pParams
, nParLen
, PARAM_REG_ALL_MSO_TYPES
);
978 StringCchCat( pParams
, nParLen
, m_pAdvertise
);
979 else if ( IsAdminInstall() )
980 StringCchCat( pParams
, nParLen
, PARAM_ADMIN
);
981 else if ( m_bIsMinorUpgrade
)
982 StringCchCat( pParams
, nParLen
, PARAM_MINOR_UPGRADE
);
984 StringCchCat( pParams
, nParLen
, PARAM_PACKAGE
);
986 StringCchCat( pParams
, nParLen
, TEXT( "\"" ) );
987 StringCchCat( pParams
, nParLen
, pDataBasePath
);
988 StringCchCat( pParams
, nParLen
, TEXT( "\"" ) );
991 StringCchCat( pParams
, nParLen
, PARAM_REBOOT
);
995 StringCchCat( pParams
, nParLen
, PARAM_PATCH
);
996 StringCchCat( pParams
, nParLen
, m_pPatchFiles
);
1001 StringCchCat( pParams
, nParLen
, PARAM_TRANSFORM
);
1002 StringCchCat( pParams
, nParLen
, TEXT( "\"" ) );
1003 StringCchCat( pParams
, nParLen
, pTransform
);
1004 StringCchCat( pParams
, nParLen
, TEXT( "\"" ) );
1009 StringCchCat( pParams
, nParLen
, TEXT( " " ) );
1010 StringCchCat( pParams
, nParLen
, m_pCmdLine
);
1013 return LaunchInstaller( pParams
);
1016 //--------------------------------------------------------------------------
1017 UINT
SetupAppX::GetError() const
1021 if ( m_pMSIErrorCode
)
1022 nErr
= (UINT
) *m_pMSIErrorCode
;
1028 OutputDebugStringFormat( TEXT("Setup will return error (%d).\n"), nErr
);
1032 //--------------------------------------------------------------------------
1033 void SetupAppX::DisplayError( UINT nErr
) const
1035 TCHAR sError
[ MAX_TEXT_LENGTH
] = {0};
1036 TCHAR sTmp
[ MAX_TEXT_LENGTH
] = {0};
1038 UINT nMsgType
= MB_OK
| MB_ICONERROR
;
1042 case ERROR_SUCCESS
: break; // 0
1044 case ERROR_FILE_NOT_FOUND
: // 2
1045 WIN::LoadString( m_hInst
, IDS_FILE_NOT_FOUND
, sTmp
, MAX_TEXT_LENGTH
);
1046 StringCchPrintf( sError
, MAX_TEXT_LENGTH
, sTmp
, m_pErrorText
);
1048 case ERROR_INVALID_DATA
: // 13
1049 WIN::LoadString( m_hInst
, IDS_INVALID_PROFILE
, sError
, MAX_TEXT_LENGTH
);
1051 case ERROR_OUTOFMEMORY
: WIN::LoadString( m_hInst
, IDS_OUTOFMEM
, sError
, MAX_TEXT_LENGTH
);
1053 case ERROR_INSTALL_USEREXIT
:
1054 WIN::LoadString( m_hInst
, IDS_USER_CANCELLED
, sError
, MAX_TEXT_LENGTH
);
1056 case ERROR_INSTALL_ALREADY_RUNNING
: // 1618
1057 WIN::LoadString( m_hInst
, IDS_ALREADY_RUNNING
, sError
, MAX_TEXT_LENGTH
);
1059 case ERROR_INSTALL_SOURCE_ABSENT
:
1060 WIN::LoadString( m_hInst
, IDS_NOMSI
, sError
, MAX_TEXT_LENGTH
);
1062 case ERROR_DS_INSUFF_ACCESS_RIGHTS
: // 8344
1063 WIN::LoadString( m_hInst
, IDS_REQUIRES_ADMIN_PRIV
, sError
, MAX_TEXT_LENGTH
);
1065 case E_ABORT
: WIN::LoadString( m_hInst
, IDS_UNKNOWN_ERROR
, sError
, MAX_TEXT_LENGTH
);
1067 case ERROR_INVALID_PARAMETER
: // 87
1068 WIN::LoadString( m_hInst
, IDS_INVALID_PARAM
, sTmp
, MAX_TEXT_LENGTH
);
1069 StringCchPrintf( sError
, MAX_TEXT_LENGTH
, sTmp
, m_pErrorText
);
1072 case ERROR_SETUP_TO_OLD
: // - 3
1073 WIN::LoadString( m_hInst
, IDS_SETUP_TO_OLD
, sTmp
, MAX_TEXT_LENGTH
);
1074 StringCchPrintf( sError
, MAX_TEXT_LENGTH
, sTmp
, m_pReqVersion
, m_pErrorText
);
1076 case ERROR_SETUP_NOT_FOUND
: // - 4
1077 WIN::LoadString( m_hInst
, IDS_SETUP_NOT_FOUND
, sTmp
, MAX_TEXT_LENGTH
);
1078 StringCchPrintf( sError
, MAX_TEXT_LENGTH
, sTmp
, m_pReqVersion
);
1080 case ERROR_SHOW_USAGE
: // - 2
1081 nMsgType
= MB_OK
| MB_ICONINFORMATION
;
1082 WIN::LoadString( m_hInst
, IDS_USAGE
, sError
, MAX_TEXT_LENGTH
);
1085 default: WIN::LoadString( m_hInst
, IDS_UNKNOWN_ERROR
, sError
, MAX_TEXT_LENGTH
);
1093 ConvertNewline( sError
);
1094 WIN::MessageBox( NULL
, sError
, m_pAppTitle
, nMsgType
);
1097 Log( TEXT( "ERROR: %s\r\n" ), sError
);
1101 //--------------------------------------------------------------------------
1102 long SetupAppX::GetLanguageID( long nIndex
) const
1104 if ( nIndex
>=0 && nIndex
< m_nLanguageCount
)
1105 return m_ppLanguageList
[ nIndex
]->m_nLanguageID
;
1110 //--------------------------------------------------------------------------
1111 void SetupAppX::GetLanguageName( long nLanguage
, LPTSTR sName
) const
1113 switch ( nLanguage
)
1115 case 1028: WIN::LoadString( m_hInst
, IDS_LANGUAGE_ZH_TW
, sName
, MAX_LANGUAGE_LEN
); break;
1116 case 1029: WIN::LoadString( m_hInst
, IDS_LANGUAGE_CS
, sName
, MAX_LANGUAGE_LEN
); break;
1117 case 1030: WIN::LoadString( m_hInst
, IDS_LANGUAGE_DA
, sName
, MAX_LANGUAGE_LEN
); break;
1118 case 1031: WIN::LoadString( m_hInst
, IDS_LANGUAGE_DE_DE
, sName
, MAX_LANGUAGE_LEN
); break;
1119 case 1032: WIN::LoadString( m_hInst
, IDS_LANGUAGE_EL
, sName
, MAX_LANGUAGE_LEN
); break;
1120 case 1033: WIN::LoadString( m_hInst
, IDS_LANGUAGE_EN_US
, sName
, MAX_LANGUAGE_LEN
); break;
1121 case 1034: WIN::LoadString( m_hInst
, IDS_LANGUAGE_ES
, sName
, MAX_LANGUAGE_LEN
); break;
1122 case 1035: WIN::LoadString( m_hInst
, IDS_LANGUAGE_FI
, sName
, MAX_LANGUAGE_LEN
); break;
1123 case 1036: WIN::LoadString( m_hInst
, IDS_LANGUAGE_FR_FR
, sName
, MAX_LANGUAGE_LEN
); break;
1124 case 1037: WIN::LoadString( m_hInst
, IDS_LANGUAGE_HE
, sName
, MAX_LANGUAGE_LEN
); break;
1125 case 1038: WIN::LoadString( m_hInst
, IDS_LANGUAGE_HU
, sName
, MAX_LANGUAGE_LEN
); break;
1126 case 1040: WIN::LoadString( m_hInst
, IDS_LANGUAGE_IT_IT
, sName
, MAX_LANGUAGE_LEN
); break;
1127 case 1041: WIN::LoadString( m_hInst
, IDS_LANGUAGE_JA
, sName
, MAX_LANGUAGE_LEN
); break;
1128 case 1042: WIN::LoadString( m_hInst
, IDS_LANGUAGE_KO
, sName
, MAX_LANGUAGE_LEN
); break;
1129 case 1043: WIN::LoadString( m_hInst
, IDS_LANGUAGE_NL_NL
, sName
, MAX_LANGUAGE_LEN
); break;
1130 case 1044: WIN::LoadString( m_hInst
, IDS_LANGUAGE_NO_NO
, sName
, MAX_LANGUAGE_LEN
); break;
1131 case 1045: WIN::LoadString( m_hInst
, IDS_LANGUAGE_PL
, sName
, MAX_LANGUAGE_LEN
); break;
1132 case 1046: WIN::LoadString( m_hInst
, IDS_LANGUAGE_PT_BR
, sName
, MAX_LANGUAGE_LEN
); break;
1133 case 1049: WIN::LoadString( m_hInst
, IDS_LANGUAGE_RU
, sName
, MAX_LANGUAGE_LEN
); break;
1134 case 1051: WIN::LoadString( m_hInst
, IDS_LANGUAGE_SK
, sName
, MAX_LANGUAGE_LEN
); break;
1135 case 1053: WIN::LoadString( m_hInst
, IDS_LANGUAGE_SV_SE
, sName
, MAX_LANGUAGE_LEN
); break;
1136 case 1054: WIN::LoadString( m_hInst
, IDS_LANGUAGE_TH
, sName
, MAX_LANGUAGE_LEN
); break;
1137 case 1055: WIN::LoadString( m_hInst
, IDS_LANGUAGE_TR
, sName
, MAX_LANGUAGE_LEN
); break;
1138 case 1061: WIN::LoadString( m_hInst
, IDS_LANGUAGE_ET
, sName
, MAX_LANGUAGE_LEN
); break;
1139 case 2052: WIN::LoadString( m_hInst
, IDS_LANGUAGE_ZH_CN
, sName
, MAX_LANGUAGE_LEN
); break;
1140 case 2070: WIN::LoadString( m_hInst
, IDS_LANGUAGE_PT_PT
, sName
, MAX_LANGUAGE_LEN
); break;
1144 TCHAR sTmp
[ MAX_LANGUAGE_LEN
] = {0};
1146 WIN::LoadString( m_hInst
, IDS_UNKNOWN_LANG
, sTmp
, MAX_LANGUAGE_LEN
);
1147 StringCchPrintf( sName
, MAX_LANGUAGE_LEN
, sTmp
, nLanguage
);
1152 //--------------------------------------------------------------------------
1153 boolean
SetupAppX::CheckVersion()
1155 boolean bRet
= false;
1156 HMODULE hMsi
= LoadMsiLibrary();
1158 Log( TEXT( " Looking for installed MSI with version >= %s\r\n" ), m_pReqVersion
);
1162 Log( TEXT( "Error: No MSI found!\r\n" ) );
1163 SetError( (UINT
) ERROR_SETUP_NOT_FOUND
);
1167 PFnDllGetVersion pDllGetVersion
= (PFnDllGetVersion
) GetProcAddress( hMsi
, MSIAPI_DllGetVersion
);
1169 if ( pDllGetVersion
)
1171 DLLVERSIONINFO aInfo
;
1173 aInfo
.cbSize
= sizeof( DLLVERSIONINFO
);
1174 if ( NOERROR
== pDllGetVersion( &aInfo
) )
1176 TCHAR pMsiVersion
[ VERSION_SIZE
];
1177 StringCchPrintf( pMsiVersion
, VERSION_SIZE
, TEXT("%d.%d.%4d"),
1178 aInfo
.dwMajorVersion
,
1179 aInfo
.dwMinorVersion
,
1180 aInfo
.dwBuildNumber
);
1181 if ( _tcsncmp( pMsiVersion
, m_pReqVersion
, _tcslen( pMsiVersion
) ) < 0 )
1183 StringCchCopy( m_pErrorText
, MAX_TEXT_LENGTH
, pMsiVersion
);
1184 SetError( (UINT
) ERROR_SETUP_TO_OLD
);
1185 Log( TEXT( "Warning: Old MSI version found <%s>, update needed!\r\n" ), pMsiVersion
);
1189 Log( TEXT( " Found MSI version <%s>, no update needed\r\n" ), pMsiVersion
);
1192 if ( aInfo
.dwMajorVersion
>= 3 )
1193 m_bSupportsPatch
= true;
1195 Log( TEXT("Warning: Patching not supported! MSI-Version <%s>\r\n"), pMsiVersion
);
1199 FreeLibrary( hMsi
);
1205 //--------------------------------------------------------------------------
1206 boolean
SetupAppX::CheckForUpgrade()
1208 // When we have patch files we will never try an Minor upgrade
1209 if ( m_pPatchFiles
) return true;
1211 if ( !m_pUpgradeKey
|| ( _tcslen( m_pUpgradeKey
) == 0 ) )
1213 Log( TEXT( " No Upgrade Key Found -> continue with standard installation!\r\n" ) );
1217 HKEY hInstKey
= NULL
;
1219 if ( ERROR_SUCCESS
== RegOpenKeyEx( HKEY_LOCAL_MACHINE
, m_pUpgradeKey
, 0, KEY_READ
, &hInstKey
) )
1221 Log( TEXT( " Found Upgrade Key in Registry (HKLM) -> will try minor upgrade!\r\n" ) );
1222 m_bIsMinorUpgrade
= true;
1224 else if ( ERROR_SUCCESS
== RegOpenKeyEx( HKEY_CURRENT_USER
, m_pUpgradeKey
, 0, KEY_READ
, &hInstKey
) )
1226 Log( TEXT( " Found Upgrade Key in Registry (HKCU) -> will try minor upgrade!\r\n" ) );
1227 m_bIsMinorUpgrade
= true;
1231 Log( TEXT( " Didn't Find Upgrade Key in Registry -> continue with standard installation!\r\n" ) );
1235 if ( m_pProductVersion
&& ( _tcslen( m_pProductVersion
) > 0 ) )
1237 TCHAR
*sProductVersion
= new TCHAR
[ MAX_PATH
+ 1 ];
1238 DWORD nSize
= MAX_PATH
+ 1;
1240 sProductVersion
[0] = '\0';
1242 // get product version
1243 if ( ERROR_SUCCESS
== RegQueryValueEx( hInstKey
, PRODUCT_VERSION
, NULL
, NULL
, (LPBYTE
)sProductVersion
, &nSize
) )
1245 if ( lstrcmpi( sProductVersion
, m_pProductVersion
) == 0 )
1247 Log( TEXT( " Same Product Version already installed, no minor upgrade!\r\n" ) );
1248 m_bIsMinorUpgrade
= false;
1252 delete [] sProductVersion
;
1258 //--------------------------------------------------------------------------
1259 boolean
SetupAppX::IsTerminalServerInstalled() const
1261 boolean bIsTerminalServer
= false;
1263 const TCHAR sSearchStr
[] = TEXT("Terminal Server");
1264 const TCHAR sKey
[] = TEXT("System\\CurrentControlSet\\Control\\ProductOptions");
1265 const TCHAR sValue
[] = TEXT("ProductSuite");
1271 if ( ERROR_SUCCESS
== RegOpenKeyEx( HKEY_LOCAL_MACHINE
, sKey
, 0, KEY_READ
, &hKey
) &&
1272 ERROR_SUCCESS
== RegQueryValueEx( hKey
, sValue
, NULL
, &dwType
, NULL
, &dwSize
) &&
1274 REG_MULTI_SZ
== dwType
)
1276 TCHAR
* sSuiteList
= new TCHAR
[ (dwSize
*sizeof(byte
)/sizeof(TCHAR
)) + 1 ];
1278 ZeroMemory(sSuiteList
, dwSize
);
1280 if ( ERROR_SUCCESS
== RegQueryValueEx( hKey
, sValue
, NULL
, &dwType
, (LPBYTE
)sSuiteList
, &dwSize
) )
1283 DWORD nSrch
= lstrlen( sSearchStr
);
1284 const TCHAR
*sSubString
= sSuiteList
;
1288 nMulti
= lstrlen( sSubString
);
1289 if ( nMulti
== nSrch
&& 0 == lstrcmp( sSearchStr
, sSubString
) )
1291 bIsTerminalServer
= true;
1295 sSubString
+= (nMulti
+ 1);
1298 delete [] sSuiteList
;
1302 RegCloseKey( hKey
);
1304 return bIsTerminalServer
;
1307 //--------------------------------------------------------------------------
1308 boolean
SetupAppX::AlreadyRunning() const
1310 if ( m_bIgnoreAlreadyRunning
)
1312 Log( TEXT("Ignoring already running MSI instance!\r\n") );
1316 const TCHAR
*sMutexName
= NULL
;
1317 const TCHAR sGUniqueName
[] = TEXT( "Global\\_MSISETUP_{EA8130C1-8D3D-4338-9309-1A52D530D846}" );
1318 const TCHAR sUniqueName
[] = TEXT( "_MSISETUP_{EA8130C1-8D3D-4338-9309-1A52D530D846}" );
1321 sMutexName
= sUniqueName
;
1322 else if ( ( GetOSVersion() < 5 ) && ! IsTerminalServerInstalled() )
1323 sMutexName
= sUniqueName
;
1325 sMutexName
= sGUniqueName
;
1329 hMutex
= WIN::CreateMutex( NULL
, FALSE
, sMutexName
);
1331 if ( !hMutex
|| ERROR_ALREADY_EXISTS
== WIN::GetLastError() )
1334 Log( TEXT( "ERROR: AlreadyRunning() could not create mutex!\r\n" ) );
1336 Log( TEXT( "ERROR: There's already a setup running!\r\n" ) );
1340 Log( TEXT( " No running Setup found\r\n" ) );
1345 //--------------------------------------------------------------------------
1346 DWORD
SetupAppX::WaitForProcess( HANDLE hHandle
)
1348 DWORD nResult
= NOERROR
;
1349 boolean bLoop
= true;
1352 ZeroMemory( (void*) &aMsg
, sizeof(MSG
) );
1356 switch ( WIN::MsgWaitForMultipleObjects( 1, &hHandle
, false,
1357 INFINITE
, QS_ALLINPUT
) )
1359 case WAIT_OBJECT_0
: bLoop
= false;
1362 case (WAIT_OBJECT_0
+ 1):
1364 if ( WIN::PeekMessage( &aMsg
, NULL
, NULL
, NULL
, PM_REMOVE
) )
1366 WIN::TranslateMessage( &aMsg
);
1367 WIN::DispatchMessage( &aMsg
);
1374 nResult
= WIN::GetLastError();
1383 //--------------------------------------------------------------------------
1384 void SetupAppX::Log( LPCTSTR pMessage
, LPCTSTR pText
) const
1388 static boolean bInit
= false;
1394 _ftprintf( m_pLogFile
, TEXT("%c"), 0xfeff );
1396 _tsetlocale( LC_ALL
, TEXT("") );
1397 _ftprintf( m_pLogFile
, TEXT("\nCodepage=%s\nMultiByte Codepage=[%d]\n"),
1398 _tsetlocale( LC_ALL
, NULL
), _getmbcp() );
1402 _ftprintf( m_pLogFile
, pMessage
, pText
);
1403 OutputDebugStringFormat( pMessage
, pText
);
1407 _ftprintf( m_pLogFile
, pMessage
);
1408 OutputDebugStringFormat( pMessage
);
1411 fflush( m_pLogFile
);
1415 //--------------------------------------------------------------------------
1416 DWORD
SetupAppX::GetNextArgument( LPCTSTR pStr
, LPTSTR
*pArg
, LPTSTR
*pNext
,
1417 boolean bStripQuotes
)
1419 boolean bInQuotes
= false;
1420 boolean bFoundArgEnd
= false;
1421 LPCTSTR pChar
= pStr
;
1422 LPCTSTR pFirst
= NULL
;
1424 if ( NULL
== pChar
)
1425 return ERROR_NO_MORE_ITEMS
;
1427 while ( ' ' == (*pChar
) || '\t' == (*pChar
) )
1428 pChar
= CharNext( pChar
);
1430 if ( '\0' == (*pChar
) )
1431 return ERROR_NO_MORE_ITEMS
;
1436 while ( ! bFoundArgEnd
)
1438 if ( '\0' == (*pChar
) )
1439 bFoundArgEnd
= true;
1440 else if ( !bInQuotes
&& ' ' == (*pChar
) )
1441 bFoundArgEnd
= true;
1442 else if ( !bInQuotes
&& '\t' == (*pChar
) )
1443 bFoundArgEnd
= true;
1446 if ( '\"' == (*pChar
) )
1448 bInQuotes
= !bInQuotes
;
1451 if ( pChar
== pFirst
)
1452 pFirst
= CharNext( pFirst
);
1457 pChar
= CharNext( pChar
);
1464 *pArg
= new TCHAR
[ nCount
];
1465 StringCchCopyN ( *pArg
, nCount
, pFirst
, nCount
-1 );
1469 *pNext
= CharNext( pChar
);
1471 return ERROR_SUCCESS
;
1474 //--------------------------------------------------------------------------
1475 boolean
SetupAppX::GetCmdLineParameters( LPTSTR
*pCmdLine
)
1477 int nRet
= ERROR_SUCCESS
;
1478 LPTSTR pStart
= NULL
;
1479 LPTSTR pNext
= NULL
;
1481 if ( GetNextArgument( *pCmdLine
, NULL
, &pNext
) != ERROR_SUCCESS
)
1483 SetError( ERROR_NO_MORE_ITEMS
);
1487 int nSize
= lstrlen( *pCmdLine
) + 2;
1488 TCHAR
*pNewCmdLine
= new TCHAR
[ nSize
];
1489 pNewCmdLine
[0] = '\0';
1491 while ( GetNextArgument( pNext
, &pStart
, &pNext
) == ERROR_SUCCESS
)
1493 boolean bDeleteStart
= true;
1495 if ( (*pStart
) == '/' || (*pStart
) == '-' )
1497 LPTSTR pSub
= CharNext( pStart
);
1498 if ( (*pSub
) == 'l' || (*pSub
) == 'L' )
1500 pSub
= CharNext( pSub
);
1501 if ( (*pSub
) == 'a' || (*pSub
) == 'A' )
1502 { // --- handle the lang parameter ---
1503 LPTSTR pLanguage
= NULL
;
1505 if ( GetNextArgument( pNext
, &pLanguage
, &pNext
, true ) != ERROR_SUCCESS
)
1507 StringCchCopy( m_pErrorText
, MAX_TEXT_LENGTH
, pStart
);
1508 nRet
= ERROR_INVALID_PARAMETER
;
1512 m_nLanguageID
= _tcstol( pLanguage
, &pLastChar
, 10 );
1513 delete [] pLanguage
;
1516 { // --- handle the l(og) parameter ---
1517 boolean bAppend
= false;
1518 LPTSTR pFileName
= NULL
;
1527 pSub
= CharNext( pSub
);
1530 if ( GetNextArgument( pNext
, &pFileName
, &pNext
, true ) != ERROR_SUCCESS
)
1532 StringCchCopy( m_pErrorText
, MAX_TEXT_LENGTH
, pStart
);
1533 nRet
= ERROR_INVALID_PARAMETER
;
1537 if ( FAILED( StringCchCat( pNewCmdLine
, nSize
, pStart
) ) )
1539 nRet
= ERROR_OUTOFMEMORY
;
1542 // we need to append a '+' otherwise msiexec would overwrite our log file
1543 if ( !bAppend
&& FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( "+" ) ) ) )
1545 nRet
= ERROR_OUTOFMEMORY
;
1548 if ( FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( " \"" ) ) ) ||
1549 FAILED( StringCchCat( pNewCmdLine
, nSize
, pFileName
) ) ||
1550 FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( "\" " ) ) ) )
1552 nRet
= ERROR_OUTOFMEMORY
;
1557 m_pLogFile
= _tfopen( pFileName
, TEXT( "ab" ) );
1559 m_pLogFile
= _tfopen( pFileName
, TEXT( "wb" ) );
1561 delete [] pFileName
;
1564 else if ( (*pSub
) == 'q' || (*pSub
) == 'Q' )
1565 { // --- Handle quiet file parameter ---
1566 pSub
= CharNext( pSub
);
1567 if ( ! (*pSub
) || (*pSub
) == 'n' || (*pSub
) == 'N' )
1570 if ( FAILED( StringCchCat( pNewCmdLine
, nSize
, pStart
) ) ||
1571 FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( " " ) ) ) )
1573 nRet
= ERROR_OUTOFMEMORY
;
1577 else if ( _tcsnicmp( pSub
, PARAM_RUNNING
, _tcslen( PARAM_RUNNING
) ) == 0 )
1579 m_bIgnoreAlreadyRunning
= true;
1581 else if ( _tcsnicmp( pSub
, CMDLN_REG_ALL_MSO_TYPES
, _tcslen( CMDLN_REG_ALL_MSO_TYPES
) ) == 0 )
1583 m_bRegAllMsoTypes
= true;
1585 else if ( _tcsnicmp( pSub
, CMDLN_REG_NO_MSO_TYPES
, _tcslen( CMDLN_REG_NO_MSO_TYPES
) ) == 0 )
1587 m_bRegNoMsoTypes
= true;
1589 else if ( (*pSub
) == 'i' || (*pSub
) == 'I' || (*pSub
) == 'f' || (*pSub
) == 'F' ||
1590 (*pSub
) == 'p' || (*pSub
) == 'P' || (*pSub
) == 'x' || (*pSub
) == 'X' ||
1591 (*pSub
) == 'y' || (*pSub
) == 'Y' || (*pSub
) == 'z' || (*pSub
) == 'Z' )
1593 StringCchCopy( m_pErrorText
, MAX_TEXT_LENGTH
, pStart
);
1594 nRet
= ERROR_INVALID_PARAMETER
;
1597 else if ( (*pSub
) == 'a' || (*pSub
) == 'A' )
1598 { // --- Handle Adminstrative Installation ---
1599 SetAdminInstall( true );
1601 else if ( (*pSub
) == 'j' || (*pSub
) == 'J' )
1602 { // --- Handle Adminstrative Installation ---
1603 m_pAdvertise
= pStart
;
1605 bDeleteStart
= false;
1607 else if ( (*pSub
) == '?' || (*pSub
) == 'h' || (*pSub
) == 'H' )
1608 { // --- Handle Show Usage ---
1609 nRet
= ERROR_SHOW_USAGE
;
1614 if ( FAILED( StringCchCat( pNewCmdLine
, nSize
, pStart
) ) ||
1615 FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( " " ) ) ) )
1617 nRet
= ERROR_OUTOFMEMORY
;
1624 if ( FAILED( StringCchCat( pNewCmdLine
, nSize
, pStart
) ) ||
1625 FAILED( StringCchCat( pNewCmdLine
, nSize
, TEXT( " " ) ) ) )
1627 nRet
= ERROR_OUTOFMEMORY
;
1632 if ( bDeleteStart
) delete [] pStart
;
1636 if ( pStart
) delete [] pStart
;
1638 *pCmdLine
= pNewCmdLine
;
1640 if ( nRet
!= ERROR_SUCCESS
)
1649 //--------------------------------------------------------------------------
1650 boolean
SetupAppX::IsAdmin()
1656 SID_IDENTIFIER_AUTHORITY aAuthority
= SECURITY_NT_AUTHORITY
;
1658 if ( !AllocateAndInitializeSid( &aAuthority
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
1659 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0,
1663 BOOL bIsAdmin
= FALSE
;
1665 if ( GetOSVersion() >= 5 )
1667 HMODULE hAdvapi32
= LoadLibrary( ADVAPI32_DLL
);
1673 PFnCheckTokenMembership pfnCheckTokenMembership
= (PFnCheckTokenMembership
) GetProcAddress( hAdvapi32
, ADVAPI32API_CheckTokenMembership
);
1674 if ( !pfnCheckTokenMembership
|| !pfnCheckTokenMembership( NULL
, aPsidAdmin
, &bIsAdmin
) )
1677 FreeLibrary( hAdvapi32
);
1681 // NT4, check groups of user
1682 HANDLE hAccessToken
= 0;
1683 UCHAR
*szInfoBuffer
= new UCHAR
[ 1024 ]; // may need to resize if TokenInfo too big
1684 DWORD dwInfoBufferSize
= 1024;
1685 DWORD dwRetInfoBufferSize
= 0;
1688 if ( WIN::OpenProcessToken( WIN::GetCurrentProcess(), TOKEN_READ
, &hAccessToken
) )
1690 bool bSuccess
= false;
1691 bSuccess
= WIN::GetTokenInformation( hAccessToken
, TokenGroups
,
1692 szInfoBuffer
, dwInfoBufferSize
,
1693 &dwRetInfoBufferSize
) == TRUE
;
1695 if( dwRetInfoBufferSize
> dwInfoBufferSize
)
1697 delete [] szInfoBuffer
;
1698 szInfoBuffer
= new UCHAR
[ dwRetInfoBufferSize
];
1699 dwInfoBufferSize
= dwRetInfoBufferSize
;
1700 bSuccess
= WIN::GetTokenInformation( hAccessToken
, TokenGroups
,
1701 szInfoBuffer
, dwInfoBufferSize
,
1702 &dwRetInfoBufferSize
) == TRUE
;
1705 WIN::CloseHandle( hAccessToken
);
1709 PTOKEN_GROUPS pGroups
= (PTOKEN_GROUPS
)(UCHAR
*) szInfoBuffer
;
1710 for( i
=0; i
<pGroups
->GroupCount
; i
++ )
1712 if( WIN::EqualSid( aPsidAdmin
, pGroups
->Groups
[i
].Sid
) )
1720 delete [] szInfoBuffer
;
1724 WIN::FreeSid( aPsidAdmin
);
1726 return bIsAdmin
? true : false;
1729 //--------------------------------------------------------------------------
1730 LPTSTR
SetupAppX::CopyIniFile( LPCTSTR pIniFile
)
1732 m_pTmpName
= _ttempnam( TEXT( "C:\\" ), TEXT( "Setup" ) );
1736 Log( TEXT( "ERROR: Could not create temp file\n" ) );
1740 FILE *pOut
= _tfopen( m_pTmpName
, TEXT( "wb" ) );
1741 FILE *pIn
= _tfopen( pIniFile
, TEXT( "rb" ) );
1745 size_t nRead
, nWritten
;
1748 nRead
= fread( pBuf
, sizeof( BYTE
), 1024, pIn
);
1749 while ( nRead
&& !ferror( pIn
) )
1751 nWritten
= fwrite( pBuf
, sizeof( BYTE
), nRead
, pOut
);
1752 if ( nWritten
!= nRead
)
1754 Log( TEXT( "ERROR: Could not write all bytes to temp file\n" ) );
1757 nRead
= fread( pBuf
, sizeof( BYTE
), 1024, pIn
);
1761 if ( pOut
) fclose( pOut
);
1762 if ( pIn
) fclose( pIn
);
1767 //--------------------------------------------------------------------------
1768 void SetupAppX::ConvertNewline( LPTSTR pText
) const
1772 while ( pText
[i
] != 0 )
1774 if ( ( pText
[i
] == '\\' ) && ( pText
[i
+1] == 'n' ) )
1785 //--------------------------------------------------------------------------
1786 LPTSTR
SetupAppX::SetProdToAppTitle( LPCTSTR pProdName
)
1788 if ( !pProdName
) return m_pAppTitle
;
1790 LPTSTR pAppProdTitle
= new TCHAR
[ MAX_STR_CAPTION
];
1791 pAppProdTitle
[0] = '\0';
1793 WIN::LoadString( m_hInst
, IDS_APP_PROD_TITLE
, pAppProdTitle
, MAX_STR_CAPTION
);
1795 int nAppLen
= lstrlen( pAppProdTitle
);
1796 int nProdLen
= lstrlen( pProdName
);
1798 if ( ( nAppLen
== 0 ) || ( nProdLen
== 0 ) )
1800 delete [] pAppProdTitle
;
1804 int nLen
= nAppLen
+ nProdLen
+ 3;
1806 if ( nLen
> STRSAFE_MAX_CCH
) return m_pAppTitle
;
1808 LPTSTR pIndex
= _tcsstr( pAppProdTitle
, PRODUCT_NAME_VAR
);
1812 int nOffset
= pIndex
- pAppProdTitle
;
1813 int nVarLen
= lstrlen( PRODUCT_NAME_VAR
);
1815 LPTSTR pNewTitle
= new TCHAR
[ nLen
];
1816 pNewTitle
[0] = '\0';
1820 StringCchCopyN( pNewTitle
, nLen
, pAppProdTitle
, nOffset
);
1823 StringCchCat( pNewTitle
, nLen
, pProdName
);
1825 if ( nOffset
+ nVarLen
< nAppLen
)
1827 StringCchCat( pNewTitle
, nLen
, pIndex
+ nVarLen
);
1830 delete [] m_pAppTitle
;
1831 m_pAppTitle
= pNewTitle
;
1834 delete [] pAppProdTitle
;
1840 //--------------------------------------------------------------------------
1841 boolean
SetupAppX::IsPatchInstalled( TCHAR
* pBaseDir
, TCHAR
* pFileName
)
1843 if ( !m_bSupportsPatch
)
1846 PMSIHANDLE hSummaryInfo
;
1847 int nLen
= lstrlen( pBaseDir
) + lstrlen( pFileName
) + 1;
1848 TCHAR
*szDatabasePath
= new TCHAR
[ nLen
];
1851 StringCchCopy( szDatabasePath
, nLen
, pBaseDir
);
1852 StringCchCat( szDatabasePath
, nLen
, pFileName
);
1854 UINT nRet
= MsiGetSummaryInformation( NULL
, szDatabasePath
, 0, &hSummaryInfo
);
1856 if ( nRet
!= ERROR_SUCCESS
)
1858 StringCchPrintf( sBuf
, 80, TEXT("ERROR: IsPatchInstalled: MsiGetSummaryInformation returned %u.\r\n"), nRet
);
1864 LPTSTR szPatchID
= new TCHAR
[ 64 ];
1865 DWORD cchValueBuf
= 64;
1866 nRet
= MsiSummaryInfoGetProperty( hSummaryInfo
, PID_REVNUMBER
, &uiDataType
, NULL
, NULL
, szPatchID
, &cchValueBuf
);
1868 if ( nRet
!= ERROR_SUCCESS
)
1870 StringCchPrintf( sBuf
, 80, TEXT("ERROR: IsPatchInstalled: MsiSummaryInfoGetProperty returned %u.\r\n"), nRet
);
1875 nRet
= MsiGetPatchInfo( szPatchID
, INSTALLPROPERTY_LOCALPACKAGE
, NULL
, NULL
);
1877 StringCchPrintf( sBuf
, 80, TEXT(" GetPatchInfo for (%s) returned (%u)\r\n"), szPatchID
, nRet
);
1882 if ( nRet
== ERROR_BAD_CONFIGURATION
)
1884 else if ( nRet
== ERROR_INVALID_PARAMETER
)
1886 else if ( nRet
== ERROR_MORE_DATA
)
1888 else if ( nRet
== ERROR_SUCCESS
)
1890 else if ( nRet
== ERROR_UNKNOWN_PRODUCT
)
1892 else if ( nRet
== ERROR_UNKNOWN_PROPERTY
)
1899 //--------------------------------------------------------------------------
1900 //--------------------------------------------------------------------------
1901 LanguageDataX::LanguageDataX( LPTSTR pData
)
1904 m_pTransform
= NULL
;
1908 m_nLanguageID
= _tcstol( pData
, &pLastChar
, 10 );
1910 if ( *pLastChar
== ',' )
1913 int nLen
= lstrlen( pLastChar
) + 1;
1914 m_pTransform
= new TCHAR
[ nLen
];
1915 StringCchCopy( m_pTransform
, nLen
, pLastChar
);
1919 //--------------------------------------------------------------------------
1920 LanguageDataX::~LanguageDataX()
1922 if ( m_pTransform
) delete [] m_pTransform
;
1925 //--------------------------------------------------------------------------
1926 //--------------------------------------------------------------------------
1927 SetupApp
* Create_SetupAppX()
1929 return new SetupAppX
;
1932 //--------------------------------------------------------------------------