1*32b1fd08SAndrew Rist /**************************************************************
2*32b1fd08SAndrew Rist  *
3*32b1fd08SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*32b1fd08SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*32b1fd08SAndrew Rist  * distributed with this work for additional information
6*32b1fd08SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*32b1fd08SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*32b1fd08SAndrew Rist  * "License"); you may not use this file except in compliance
9*32b1fd08SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*32b1fd08SAndrew Rist  *
11*32b1fd08SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*32b1fd08SAndrew Rist  *
13*32b1fd08SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*32b1fd08SAndrew Rist  * software distributed under the License is distributed on an
15*32b1fd08SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*32b1fd08SAndrew Rist  * KIND, either express or implied.  See the License for the
17*32b1fd08SAndrew Rist  * specific language governing permissions and limitations
18*32b1fd08SAndrew Rist  * under the License.
19*32b1fd08SAndrew Rist  *
20*32b1fd08SAndrew Rist  *************************************************************/
21*32b1fd08SAndrew Rist 
22cdf0e10cSrcweir #undef UNICODE
23cdf0e10cSrcweir #undef _UNICODE
24cdf0e10cSrcweir 
25cdf0e10cSrcweir #pragma once
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #ifdef _MSC_VER
28cdf0e10cSrcweir #pragma warning(push, 1) /* disable warnings within system headers */
29cdf0e10cSrcweir #endif
30cdf0e10cSrcweir #define WIN32_LEAN_AND_MEAN
31cdf0e10cSrcweir #include <windows.h>
32cdf0e10cSrcweir #include <msiquery.h>
33cdf0e10cSrcweir #include <imagehlp.h>
34cdf0e10cSrcweir #include <tchar.h>
35cdf0e10cSrcweir #include <strsafe.h>
36cdf0e10cSrcweir #ifdef _MSC_VER
37cdf0e10cSrcweir #pragma warning(pop)
38cdf0e10cSrcweir #endif
39cdf0e10cSrcweir 
40cdf0e10cSrcweir #include <malloc.h>
41cdf0e10cSrcweir #include <time.h>
42cdf0e10cSrcweir #include <string>
43cdf0e10cSrcweir #include <hash_map>
44cdf0e10cSrcweir 
45cdf0e10cSrcweir const DWORD PE_Signature = 0x00004550;
46cdf0e10cSrcweir typedef std::pair< std::string, bool > StringPair;
47cdf0e10cSrcweir typedef	std::hash_map< std::string, bool > ExcludeLibsMap;
48cdf0e10cSrcweir 
49cdf0e10cSrcweir #ifdef DEBUG
OutputDebugStringFormat(LPCSTR pFormat,...)50cdf0e10cSrcweir static void OutputDebugStringFormat( LPCSTR pFormat, ... )
51cdf0e10cSrcweir {
52cdf0e10cSrcweir 	CHAR    buffer[1024];
53cdf0e10cSrcweir 	va_list args;
54cdf0e10cSrcweir 
55cdf0e10cSrcweir 	va_start( args, pFormat );
56cdf0e10cSrcweir 	StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args );
57cdf0e10cSrcweir 	OutputDebugStringA( buffer );
58cdf0e10cSrcweir }
59cdf0e10cSrcweir #else
OutputDebugStringFormat(LPCSTR,...)60cdf0e10cSrcweir static void OutputDebugStringFormat( LPCSTR, ... )
61cdf0e10cSrcweir {
62cdf0e10cSrcweir }
63cdf0e10cSrcweir #endif
64cdf0e10cSrcweir 
IsValidHandle(HANDLE handle)65cdf0e10cSrcweir static bool IsValidHandle( HANDLE handle )
66cdf0e10cSrcweir {
67cdf0e10cSrcweir 	return NULL != handle && INVALID_HANDLE_VALUE != handle;
68cdf0e10cSrcweir }
69cdf0e10cSrcweir 
GetMsiProperty(MSIHANDLE handle,const std::string & sProperty)70cdf0e10cSrcweir static std::string GetMsiProperty(MSIHANDLE handle, const std::string& sProperty)
71cdf0e10cSrcweir {
72cdf0e10cSrcweir 	std::string result;
73cdf0e10cSrcweir     TCHAR		szDummy[1] = TEXT("");
74cdf0e10cSrcweir     DWORD		nChars = 0;
75cdf0e10cSrcweir 
76cdf0e10cSrcweir     if (MsiGetProperty(handle, sProperty.c_str(), szDummy, &nChars) == ERROR_MORE_DATA)
77cdf0e10cSrcweir     {
78cdf0e10cSrcweir         DWORD nBytes = ++nChars * sizeof(TCHAR);
79cdf0e10cSrcweir         LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
80cdf0e10cSrcweir         ZeroMemory( buffer, nBytes );
81cdf0e10cSrcweir         MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
82cdf0e10cSrcweir         result = buffer;
83cdf0e10cSrcweir     }
84cdf0e10cSrcweir     return result;
85cdf0e10cSrcweir }
86cdf0e10cSrcweir 
rebaseImage(const std::string & filePath,LPVOID address)87cdf0e10cSrcweir static BOOL rebaseImage( const std::string& filePath, LPVOID address )
88cdf0e10cSrcweir {
89cdf0e10cSrcweir 	ULONG ulOldImageSize;
90cdf0e10cSrcweir 	ULONG_PTR lpOldImageBase;
91cdf0e10cSrcweir 	ULONG ulNewImageSize;
92cdf0e10cSrcweir 	ULONG_PTR lpNewImageBase = reinterpret_cast<ULONG_PTR>(address);
93cdf0e10cSrcweir 
94cdf0e10cSrcweir 	BOOL bResult = ReBaseImage(
95cdf0e10cSrcweir 		filePath.c_str(),
96cdf0e10cSrcweir 		"",
97cdf0e10cSrcweir 		TRUE,
98cdf0e10cSrcweir 		FALSE,
99cdf0e10cSrcweir 		FALSE,
100cdf0e10cSrcweir 		0,
101cdf0e10cSrcweir 		&ulOldImageSize,
102cdf0e10cSrcweir 		&lpOldImageBase,
103cdf0e10cSrcweir 		&ulNewImageSize,
104cdf0e10cSrcweir 		&lpNewImageBase,
105cdf0e10cSrcweir 		(ULONG)time(NULL) );
106cdf0e10cSrcweir 
107cdf0e10cSrcweir 	return bResult;
108cdf0e10cSrcweir }
109cdf0e10cSrcweir 
rebaseImage(MSIHANDLE,const std::string & sFilePath,LPVOID address)110cdf0e10cSrcweir static BOOL rebaseImage( MSIHANDLE /*handle*/, const std::string& sFilePath, LPVOID address )
111cdf0e10cSrcweir {
112cdf0e10cSrcweir 	std::string	mystr;
113cdf0e10cSrcweir 	mystr = "Full file: " + sFilePath;
114cdf0e10cSrcweir 
115cdf0e10cSrcweir 	BOOL bResult = rebaseImage( sFilePath, address );
116cdf0e10cSrcweir 
117cdf0e10cSrcweir 	if ( !bResult )
118cdf0e10cSrcweir 	{
119cdf0e10cSrcweir 		OutputDebugStringFormat( "Rebasing library %s failed", mystr.c_str() );
120cdf0e10cSrcweir 	}
121cdf0e10cSrcweir 
122cdf0e10cSrcweir 	return bResult;
123cdf0e10cSrcweir }
124cdf0e10cSrcweir 
rebaseImagesInFolder(MSIHANDLE handle,const std::string & sPath,LPVOID address,ExcludeLibsMap & rExcludeMap)125cdf0e10cSrcweir static BOOL rebaseImagesInFolder( MSIHANDLE handle, const std::string& sPath, LPVOID address, ExcludeLibsMap& rExcludeMap )
126cdf0e10cSrcweir {
127cdf0e10cSrcweir 	std::string     sDir     = sPath;
128cdf0e10cSrcweir 	std::string	    sPattern = sPath + TEXT("*.dll");
129cdf0e10cSrcweir 	WIN32_FIND_DATA	aFindFileData;
130cdf0e10cSrcweir 
131cdf0e10cSrcweir 	HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
132cdf0e10cSrcweir 	if ( IsValidHandle(hFind) )
133cdf0e10cSrcweir 	{
134cdf0e10cSrcweir 		BOOL fSuccess = false;
135cdf0e10cSrcweir 
136cdf0e10cSrcweir 		do
137cdf0e10cSrcweir 		{
138cdf0e10cSrcweir 			std::string sFileName = aFindFileData.cFileName;
139cdf0e10cSrcweir 			if ( rExcludeMap.find( sFileName ) == rExcludeMap.end() )
140cdf0e10cSrcweir 			{
141cdf0e10cSrcweir 				OutputDebugStringFormat( "Rebase library: %s", sFileName.c_str() );
142cdf0e10cSrcweir                 std::string	sLibFile = sDir +  sFileName;
143cdf0e10cSrcweir                 rebaseImage( handle, sLibFile, address );
144cdf0e10cSrcweir 			}
145cdf0e10cSrcweir 			else
146cdf0e10cSrcweir 			{
147cdf0e10cSrcweir 				OutputDebugStringFormat( "Exclude library %s from rebase", sFileName.c_str() );
148cdf0e10cSrcweir 			}
149cdf0e10cSrcweir 
150cdf0e10cSrcweir 			fSuccess = FindNextFile( hFind, &aFindFileData );
151cdf0e10cSrcweir 		}
152cdf0e10cSrcweir 		while ( fSuccess );
153cdf0e10cSrcweir 
154cdf0e10cSrcweir 		FindClose( hFind );
155cdf0e10cSrcweir 	}
156cdf0e10cSrcweir 
157cdf0e10cSrcweir 	return ERROR_SUCCESS;
158cdf0e10cSrcweir }
159cdf0e10cSrcweir 
rebaseImages(MSIHANDLE handle,LPVOID pAddress,ExcludeLibsMap & rMap)160cdf0e10cSrcweir static BOOL rebaseImages( MSIHANDLE handle, LPVOID pAddress, ExcludeLibsMap& rMap )
161cdf0e10cSrcweir {
162cdf0e10cSrcweir 	std::string sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
163cdf0e10cSrcweir 
164cdf0e10cSrcweir 	std::string sBasisDir  = sInstallPath + TEXT("Basis\\program\\");
165cdf0e10cSrcweir 	std::string sOfficeDir = sInstallPath + TEXT("program\\");
166cdf0e10cSrcweir 	std::string sUreDir    = sInstallPath + TEXT("URE\\bin\\");
167cdf0e10cSrcweir 
168cdf0e10cSrcweir 	BOOL bResult = rebaseImagesInFolder( handle, sBasisDir, pAddress, rMap );
169cdf0e10cSrcweir 	bResult &= rebaseImagesInFolder( handle, sOfficeDir, pAddress, rMap );
170cdf0e10cSrcweir 	bResult &= rebaseImagesInFolder( handle, sUreDir, pAddress, rMap );
171cdf0e10cSrcweir 
172cdf0e10cSrcweir 	return bResult;
173cdf0e10cSrcweir }
174cdf0e10cSrcweir 
IsServerSystem(MSIHANDLE)175cdf0e10cSrcweir static BOOL IsServerSystem( MSIHANDLE /*handle*/ )
176cdf0e10cSrcweir {
177cdf0e10cSrcweir 	OSVERSIONINFOEX osVersionInfoEx;
178cdf0e10cSrcweir 	osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
179cdf0e10cSrcweir 	GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&osVersionInfoEx));
180cdf0e10cSrcweir 
181cdf0e10cSrcweir 	if ( osVersionInfoEx.wProductType != VER_NT_WORKSTATION )
182cdf0e10cSrcweir 	{
183cdf0e10cSrcweir         OutputDebugStringFormat( "Server system detected. No rebase necessary!" );
184cdf0e10cSrcweir 		return TRUE;
185cdf0e10cSrcweir 	}
186cdf0e10cSrcweir 	else
187cdf0e10cSrcweir     {
188cdf0e10cSrcweir         OutputDebugStringFormat( "Client system detected. Rebase necessary!" );
189cdf0e10cSrcweir         return FALSE;
190cdf0e10cSrcweir     }
191cdf0e10cSrcweir }
192cdf0e10cSrcweir 
InitExcludeFromRebaseList(MSIHANDLE handle,ExcludeLibsMap & rMap)193cdf0e10cSrcweir static void InitExcludeFromRebaseList( MSIHANDLE handle, ExcludeLibsMap& rMap )
194cdf0e10cSrcweir {
195cdf0e10cSrcweir 	size_t      nPos( 0 );
196cdf0e10cSrcweir     const TCHAR cDelim = ',';
197cdf0e10cSrcweir 	std::string sLibsExcluded = GetMsiProperty(handle, TEXT("EXCLUDE_FROM_REBASE"));
198cdf0e10cSrcweir 
199cdf0e10cSrcweir     while ( nPos < sLibsExcluded.size() )
200cdf0e10cSrcweir 	{
201cdf0e10cSrcweir 	    size_t nDelPos = sLibsExcluded.find_first_of( cDelim, nPos );
202cdf0e10cSrcweir 
203cdf0e10cSrcweir 		std::string sExcludedLibName;
204cdf0e10cSrcweir 		if ( nDelPos != std::string::npos )
205cdf0e10cSrcweir 		{
206cdf0e10cSrcweir 			sExcludedLibName = sLibsExcluded.substr( nPos, nDelPos - nPos );
207cdf0e10cSrcweir 		    nPos = nDelPos+1;
208cdf0e10cSrcweir 		}
209cdf0e10cSrcweir 		else
210cdf0e10cSrcweir 		{
211cdf0e10cSrcweir 			sExcludedLibName = sLibsExcluded.substr( nPos );
212cdf0e10cSrcweir 			nPos = sLibsExcluded.size();
213cdf0e10cSrcweir 		}
214cdf0e10cSrcweir 
215cdf0e10cSrcweir 		if ( sExcludedLibName.size() > 0 )
216cdf0e10cSrcweir 		{
217cdf0e10cSrcweir 			OutputDebugStringFormat( "Insert library %s into exclude from rebase list", sExcludedLibName.c_str() );
218cdf0e10cSrcweir 			rMap.insert( StringPair( sExcludedLibName, true ));
219cdf0e10cSrcweir 		}
220cdf0e10cSrcweir 	}
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
RebaseLibrariesOnProperties(MSIHANDLE handle)223cdf0e10cSrcweir extern "C" BOOL __stdcall RebaseLibrariesOnProperties( MSIHANDLE handle )
224cdf0e10cSrcweir {
225cdf0e10cSrcweir 	static LPVOID pDefault = reinterpret_cast<LPVOID>(0x10000000);
226cdf0e10cSrcweir 
227cdf0e10cSrcweir 	OutputDebugStringFormat( "RebaseLibrariesOnProperties has been called" );
228cdf0e10cSrcweir 	std::string sDontOptimizeLibs = GetMsiProperty(handle, TEXT("DONTOPTIMIZELIBS"));
229cdf0e10cSrcweir 	if ( sDontOptimizeLibs.length() > 0 && sDontOptimizeLibs == "1" )
230cdf0e10cSrcweir 	{
231cdf0e10cSrcweir         OutputDebugStringFormat( "Don't optimize libraries set. No rebase necessary!" );
232cdf0e10cSrcweir 		return TRUE;
233cdf0e10cSrcweir 	}
234cdf0e10cSrcweir 
235cdf0e10cSrcweir 	if ( !IsServerSystem( handle ))
236cdf0e10cSrcweir 	{
237cdf0e10cSrcweir 		ExcludeLibsMap aExcludeLibsMap;
238cdf0e10cSrcweir 		InitExcludeFromRebaseList( handle, aExcludeLibsMap );
239cdf0e10cSrcweir 
240cdf0e10cSrcweir 		return rebaseImages( handle, pDefault, aExcludeLibsMap );
241cdf0e10cSrcweir 	}
242cdf0e10cSrcweir 
243cdf0e10cSrcweir 	return TRUE;
244cdf0e10cSrcweir }
245