132b1fd08SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
332b1fd08SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
432b1fd08SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
532b1fd08SAndrew Rist  * distributed with this work for additional information
632b1fd08SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
732b1fd08SAndrew Rist  * to you under the Apache License, Version 2.0 (the
832b1fd08SAndrew Rist  * "License"); you may not use this file except in compliance
932b1fd08SAndrew Rist  * with the License.  You may obtain a copy of the License at
1032b1fd08SAndrew Rist  *
1132b1fd08SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
1232b1fd08SAndrew Rist  *
1332b1fd08SAndrew Rist  * Unless required by applicable law or agreed to in writing,
1432b1fd08SAndrew Rist  * software distributed under the License is distributed on an
1532b1fd08SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1632b1fd08SAndrew Rist  * KIND, either express or implied.  See the License for the
1732b1fd08SAndrew Rist  * specific language governing permissions and limitations
1832b1fd08SAndrew Rist  * under the License.
1932b1fd08SAndrew Rist  *
2032b1fd08SAndrew Rist  *************************************************************/
2132b1fd08SAndrew Rist 
2232b1fd08SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #define _WIN32_WINDOWS 0x0410
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #ifdef _MSC_VER
27cdf0e10cSrcweir #pragma warning(push, 1) /* disable warnings within system headers */
28cdf0e10cSrcweir #endif
29cdf0e10cSrcweir #define WIN32_LEAN_AND_MEAN
30cdf0e10cSrcweir #include <windows.h>
31cdf0e10cSrcweir #include <msiquery.h>
32cdf0e10cSrcweir #ifdef _MSC_VER
33cdf0e10cSrcweir #pragma warning(pop)
34cdf0e10cSrcweir #endif
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include <malloc.h>
37cdf0e10cSrcweir #include <assert.h>
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #ifdef UNICODE
40cdf0e10cSrcweir #define _UNICODE
41cdf0e10cSrcweir #define _tstring	wstring
42cdf0e10cSrcweir #else
43cdf0e10cSrcweir #define _tstring	string
44cdf0e10cSrcweir #endif
45cdf0e10cSrcweir #include <tchar.h>
46cdf0e10cSrcweir #include <string>
47cdf0e10cSrcweir #include <queue>
48cdf0e10cSrcweir #include <stdio.h>
49cdf0e10cSrcweir 
50cdf0e10cSrcweir #include <systools/win32/uwinapi.h>
51cdf0e10cSrcweir #include <../tools/seterror.hxx>
52cdf0e10cSrcweir 
53cdf0e10cSrcweir #define	WININIT_FILENAME	"wininit.ini"
54cdf0e10cSrcweir #define RENAME_SECTION		"rename"
55cdf0e10cSrcweir 
56cdf0e10cSrcweir #ifdef DEBUG
OutputDebugStringFormat(LPCTSTR pFormat,...)57cdf0e10cSrcweir inline void OutputDebugStringFormat( LPCTSTR pFormat, ... )
58cdf0e10cSrcweir {
59cdf0e10cSrcweir 	_TCHAR	buffer[1024];
60cdf0e10cSrcweir 	va_list	args;
61cdf0e10cSrcweir 
62cdf0e10cSrcweir 	va_start( args, pFormat );
63cdf0e10cSrcweir 	_vsntprintf( buffer, elementsof(buffer), pFormat, args );
64cdf0e10cSrcweir 	OutputDebugString( buffer );
65cdf0e10cSrcweir }
66cdf0e10cSrcweir #else
OutputDebugStringFormat(LPCTSTR,...)67cdf0e10cSrcweir static inline void OutputDebugStringFormat( LPCTSTR, ... )
68cdf0e10cSrcweir {
69cdf0e10cSrcweir }
70cdf0e10cSrcweir #endif
71cdf0e10cSrcweir 
GetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)72cdf0e10cSrcweir static std::_tstring GetMsiProperty( MSIHANDLE handle, const std::_tstring& sProperty )
73cdf0e10cSrcweir {
74cdf0e10cSrcweir 	std::_tstring	result;
75cdf0e10cSrcweir 	TCHAR	szDummy[1] = TEXT("");
76cdf0e10cSrcweir 	DWORD	nChars = 0;
77cdf0e10cSrcweir 
78cdf0e10cSrcweir 	if ( MsiGetProperty( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA )
79cdf0e10cSrcweir 	{
80cdf0e10cSrcweir 		DWORD nBytes = ++nChars * sizeof(TCHAR);
81cdf0e10cSrcweir 		LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes));
82cdf0e10cSrcweir 		ZeroMemory( buffer, nBytes );
83cdf0e10cSrcweir 		MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars);
84cdf0e10cSrcweir 		result = buffer;
85cdf0e10cSrcweir 	}
86cdf0e10cSrcweir 
87cdf0e10cSrcweir 	return	result;
88cdf0e10cSrcweir }
89cdf0e10cSrcweir 
90cdf0e10cSrcweir // The provided GUID must be without surounding '{}'
GetGuidPart(const std::_tstring & guid,int index)91cdf0e10cSrcweir static std::_tstring GetGuidPart(const std::_tstring& guid, int index)
92cdf0e10cSrcweir {
93cdf0e10cSrcweir 	assert((guid.length() == 36) && "No GUID or wrong format!");
94cdf0e10cSrcweir 	assert(((index > -1) && (index < 5)) && "Out of range!");
95cdf0e10cSrcweir 
96cdf0e10cSrcweir 	if (index == 0) return std::_tstring(guid.c_str(), 8);
97cdf0e10cSrcweir 	if (index == 1) return std::_tstring(guid.c_str() + 9, 4);
98cdf0e10cSrcweir 	if (index == 2) return std::_tstring(guid.c_str() + 14, 4);
99cdf0e10cSrcweir 	if (index == 3) return std::_tstring(guid.c_str() + 19, 4);
100cdf0e10cSrcweir 	if (index == 4) return std::_tstring(guid.c_str() + 24, 12);
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 	return std::_tstring();
103cdf0e10cSrcweir }
104cdf0e10cSrcweir 
Swap(char * p1,char * p2)105cdf0e10cSrcweir static void Swap(char* p1, char* p2)
106cdf0e10cSrcweir {
107cdf0e10cSrcweir 	char tmp = *p1;
108cdf0e10cSrcweir 	*p1 = *p2;
109cdf0e10cSrcweir 	*p2 = tmp;
110cdf0e10cSrcweir }
111cdf0e10cSrcweir 
Invert(const std::_tstring & str)112cdf0e10cSrcweir static std::_tstring Invert(const std::_tstring& str)
113cdf0e10cSrcweir {
114cdf0e10cSrcweir 	char* buff = reinterpret_cast<char*>(_alloca(str.length()));
115cdf0e10cSrcweir 	strncpy(buff, str.c_str(), str.length());
116cdf0e10cSrcweir 
117cdf0e10cSrcweir 	char* front = buff;
118cdf0e10cSrcweir 	char* back = buff + str.length() - 1;
119cdf0e10cSrcweir 
120cdf0e10cSrcweir 	while (front < back)
121cdf0e10cSrcweir 		Swap(front++, back--);
122cdf0e10cSrcweir 
123cdf0e10cSrcweir 	return std::_tstring(buff, str.length());
124cdf0e10cSrcweir }
125cdf0e10cSrcweir 
126cdf0e10cSrcweir // Convert the upgrade code (which is a GUID) according
127cdf0e10cSrcweir // to the way the windows installer does when writing it
128cdf0e10cSrcweir // to the registry
129cdf0e10cSrcweir // The first 8 bytes will be inverted, from the the last
130cdf0e10cSrcweir // 8 bytes always the nibbles will be inverted for further
131cdf0e10cSrcweir // details look in the MSDN under compressed registry keys
ConvertGuid(const std::_tstring & guid)132cdf0e10cSrcweir static std::_tstring ConvertGuid(const std::_tstring& guid)
133cdf0e10cSrcweir {
134cdf0e10cSrcweir 	std::_tstring convertedGuid;
135cdf0e10cSrcweir 
136cdf0e10cSrcweir 	std::_tstring part = GetGuidPart(guid, 0);
137cdf0e10cSrcweir 	convertedGuid = Invert(part);
138cdf0e10cSrcweir 
139cdf0e10cSrcweir 	part = GetGuidPart(guid, 1);
140cdf0e10cSrcweir 	convertedGuid += Invert(part);
141cdf0e10cSrcweir 
142cdf0e10cSrcweir 	part = GetGuidPart(guid, 2);
143cdf0e10cSrcweir 	convertedGuid += Invert(part);
144cdf0e10cSrcweir 
145cdf0e10cSrcweir 	part = GetGuidPart(guid, 3);
146cdf0e10cSrcweir 	convertedGuid += Invert(std::_tstring(part.c_str(), 2));
147cdf0e10cSrcweir 	convertedGuid += Invert(std::_tstring(part.c_str() + 2, 2));
148cdf0e10cSrcweir 
149cdf0e10cSrcweir 	part = GetGuidPart(guid, 4);
150cdf0e10cSrcweir 	int pos = 0;
151cdf0e10cSrcweir 	for (int i = 0; i < 6; i++)
152cdf0e10cSrcweir 	{
153cdf0e10cSrcweir 		convertedGuid += Invert(std::_tstring(part.c_str() + pos, 2));
154cdf0e10cSrcweir 		pos += 2;
155cdf0e10cSrcweir 	}
156cdf0e10cSrcweir 	return convertedGuid;
157cdf0e10cSrcweir }
158cdf0e10cSrcweir 
IsSetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)159cdf0e10cSrcweir static inline bool IsSetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
160cdf0e10cSrcweir {
161cdf0e10cSrcweir 	std::_tstring value = GetMsiProperty(handle, sProperty);
162cdf0e10cSrcweir 	return (value.length() > 0);
163cdf0e10cSrcweir }
164cdf0e10cSrcweir 
UnsetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)165cdf0e10cSrcweir static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
166cdf0e10cSrcweir {
167cdf0e10cSrcweir 	MsiSetProperty(handle, sProperty.c_str(), NULL);
168cdf0e10cSrcweir }
169cdf0e10cSrcweir 
SetMsiProperty(MSIHANDLE handle,const std::_tstring & sProperty)170cdf0e10cSrcweir static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
171cdf0e10cSrcweir {
172cdf0e10cSrcweir 	MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
173cdf0e10cSrcweir }
174cdf0e10cSrcweir 
MoveFileEx9x(LPCSTR lpExistingFileNameA,LPCSTR lpNewFileNameA,DWORD dwFlags)175cdf0e10cSrcweir static BOOL MoveFileEx9x( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
176cdf0e10cSrcweir {
177cdf0e10cSrcweir 	BOOL	fSuccess = FALSE;	// assume failure
178cdf0e10cSrcweir 
179cdf0e10cSrcweir 	// Windows 9x has a special mechanism to move files after reboot
180cdf0e10cSrcweir 
181cdf0e10cSrcweir 	if ( dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT )
182cdf0e10cSrcweir 	{
183cdf0e10cSrcweir 		CHAR	szExistingFileNameA[MAX_PATH];
184cdf0e10cSrcweir 		CHAR	szNewFileNameA[MAX_PATH] = "NUL";
185cdf0e10cSrcweir 
186cdf0e10cSrcweir 		// Path names in WININIT.INI must be in short path name form
187cdf0e10cSrcweir 
188cdf0e10cSrcweir 		if (
189cdf0e10cSrcweir 			GetShortPathNameA( lpExistingFileNameA, szExistingFileNameA, MAX_PATH ) &&
190cdf0e10cSrcweir 			(!lpNewFileNameA || GetShortPathNameA( lpNewFileNameA, szNewFileNameA, MAX_PATH ))
191cdf0e10cSrcweir 			)
192cdf0e10cSrcweir 		{
193cdf0e10cSrcweir 			CHAR	szBuffer[32767];	// The buffer size must not exceed 32K
194cdf0e10cSrcweir 			DWORD	dwBufLen = GetPrivateProfileSectionA( RENAME_SECTION, szBuffer, elementsof(szBuffer), WININIT_FILENAME );
195cdf0e10cSrcweir 
196cdf0e10cSrcweir 			CHAR	szRename[MAX_PATH];	// This is enough for at most to times 67 chracters
197cdf0e10cSrcweir 			strcpy( szRename, szNewFileNameA );
198cdf0e10cSrcweir 			strcat( szRename, "=" );
199cdf0e10cSrcweir 			strcat( szRename, szExistingFileNameA );
200cdf0e10cSrcweir 			size_t	lnRename = strlen(szRename);
201cdf0e10cSrcweir 
202cdf0e10cSrcweir 			if ( dwBufLen + lnRename + 2 <= elementsof(szBuffer) )
203cdf0e10cSrcweir 			{
204cdf0e10cSrcweir 				CopyMemory( &szBuffer[dwBufLen], szRename, lnRename );
205cdf0e10cSrcweir 				szBuffer[dwBufLen + lnRename ] = 0;
206cdf0e10cSrcweir 				szBuffer[dwBufLen + lnRename + 1 ] = 0;
207cdf0e10cSrcweir 
208cdf0e10cSrcweir 				fSuccess = WritePrivateProfileSectionA( RENAME_SECTION, szBuffer, WININIT_FILENAME );
209cdf0e10cSrcweir 			}
210cdf0e10cSrcweir 			else
211cdf0e10cSrcweir 				SetLastError( ERROR_BUFFER_OVERFLOW );
212cdf0e10cSrcweir 		}
213cdf0e10cSrcweir 	}
214cdf0e10cSrcweir 	else
215cdf0e10cSrcweir 	{
216cdf0e10cSrcweir 
217cdf0e10cSrcweir 		fSuccess = MoveFileA( lpExistingFileNameA, lpNewFileNameA );
218cdf0e10cSrcweir 
219cdf0e10cSrcweir 		if ( !fSuccess && GetLastError() != ERROR_ACCESS_DENIED &&
220cdf0e10cSrcweir 			0 != (dwFlags & (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) )
221cdf0e10cSrcweir 		{
222cdf0e10cSrcweir 			BOOL	bFailIfExist = 0 == (dwFlags & MOVEFILE_REPLACE_EXISTING);
223cdf0e10cSrcweir 
224cdf0e10cSrcweir 			fSuccess = CopyFileA( lpExistingFileNameA, lpNewFileNameA, bFailIfExist );
225cdf0e10cSrcweir 
226cdf0e10cSrcweir 			if ( fSuccess )
227cdf0e10cSrcweir 				fSuccess = DeleteFileA( lpExistingFileNameA );
228cdf0e10cSrcweir 		}
229cdf0e10cSrcweir 
230cdf0e10cSrcweir 	}
231cdf0e10cSrcweir 
232cdf0e10cSrcweir 	return fSuccess;
233cdf0e10cSrcweir }
234cdf0e10cSrcweir 
MoveFileExImpl(LPCSTR lpExistingFileNameA,LPCSTR lpNewFileNameA,DWORD dwFlags)235cdf0e10cSrcweir static BOOL MoveFileExImpl( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags )
236cdf0e10cSrcweir {
237cdf0e10cSrcweir 	if ( 0 > ((LONG)GetVersion())) // High order bit indicates Win 9x
238cdf0e10cSrcweir 		return MoveFileEx9x( lpExistingFileNameA, lpNewFileNameA, dwFlags );
239cdf0e10cSrcweir 	else
240cdf0e10cSrcweir 		return MoveFileExA( lpExistingFileNameA, lpNewFileNameA, dwFlags );
241cdf0e10cSrcweir }
242cdf0e10cSrcweir 
SwapFiles(const std::_tstring & sFileName1,const std::_tstring & sFileName2)243cdf0e10cSrcweir static bool SwapFiles( const std::_tstring& sFileName1, const std::_tstring& sFileName2 )
244cdf0e10cSrcweir {
245cdf0e10cSrcweir 	std::_tstring	sTempFileName = sFileName1 + TEXT(".tmp");
246cdf0e10cSrcweir 
247cdf0e10cSrcweir 	bool fSuccess = true;
248cdf0e10cSrcweir 
249cdf0e10cSrcweir 	//Try to move the original file to a temp file
250cdf0e10cSrcweir 	fSuccess = MoveFileExImpl( sFileName1.c_str(), sTempFileName.c_str(), MOVEFILE_REPLACE_EXISTING);
251cdf0e10cSrcweir 
252cdf0e10cSrcweir 	std::_tstring	mystr;
253cdf0e10cSrcweir 
254cdf0e10cSrcweir 	if ( fSuccess )
255cdf0e10cSrcweir 	{
256cdf0e10cSrcweir 		fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
257cdf0e10cSrcweir 
258cdf0e10cSrcweir 		if ( fSuccess )
259cdf0e10cSrcweir 		{
260cdf0e10cSrcweir 			fSuccess = MoveFileExImpl( sTempFileName.c_str(), sFileName2.c_str(),
261cdf0e10cSrcweir 										MOVEFILE_REPLACE_EXISTING );
262cdf0e10cSrcweir 			if ( !fSuccess )
263cdf0e10cSrcweir 			{
264cdf0e10cSrcweir 				MoveFileExImpl( sFileName1.c_str(), sFileName2.c_str(), MOVEFILE_REPLACE_EXISTING );
265cdf0e10cSrcweir 			}
266cdf0e10cSrcweir 		}
267cdf0e10cSrcweir 		else
268cdf0e10cSrcweir 		{
269cdf0e10cSrcweir 			MoveFileExImpl( sTempFileName.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING  );
270cdf0e10cSrcweir 		}
271cdf0e10cSrcweir 	}
272cdf0e10cSrcweir 	else
273cdf0e10cSrcweir 	{
274cdf0e10cSrcweir 		//It could be that there is no original file and therefore copying the original to a temp
275cdf0e10cSrcweir 		// file failed. Examine if there is no original and if so then move file2 to file1
276cdf0e10cSrcweir 
277cdf0e10cSrcweir 		WIN32_FIND_DATA data;
278cdf0e10cSrcweir 		HANDLE hdl = FindFirstFile(sFileName1.c_str(), &data);
279cdf0e10cSrcweir 		if (hdl == INVALID_HANDLE_VALUE)
280cdf0e10cSrcweir 		{
281cdf0e10cSrcweir 			fSuccess = MoveFileExImpl( sFileName2.c_str(), sFileName1.c_str(), MOVEFILE_REPLACE_EXISTING );
282cdf0e10cSrcweir 
283cdf0e10cSrcweir 			// if ( fSuccess )
284cdf0e10cSrcweir 			// {
285cdf0e10cSrcweir 			//	mystr = "Success";
286cdf0e10cSrcweir 			//	MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
287cdf0e10cSrcweir 			// }
288cdf0e10cSrcweir 			// else
289cdf0e10cSrcweir 			// {
290cdf0e10cSrcweir 			//	char buff[256];
291cdf0e10cSrcweir 			//	wsprintf(buff, "Failure %d", GetLastError());
292cdf0e10cSrcweir 			//	MessageBox( NULL, buff, "Titel", MB_OK );
293cdf0e10cSrcweir 			// }
294cdf0e10cSrcweir 		}
295cdf0e10cSrcweir 		else
296cdf0e10cSrcweir 		{
297cdf0e10cSrcweir 			FindClose(hdl);
298cdf0e10cSrcweir 		}
299cdf0e10cSrcweir 	}
300cdf0e10cSrcweir 
301cdf0e10cSrcweir 	OutputDebugStringFormat( TEXT("%s <-> %s: %s"), sFileName1.c_str(), sFileName2.c_str(), fSuccess ? TEXT("OK") : TEXT("FAILED") );
302cdf0e10cSrcweir 
303cdf0e10cSrcweir 	if (!fSuccess )
304cdf0e10cSrcweir 	{
305cdf0e10cSrcweir 		DWORD	dwError = GetLastError();
306cdf0e10cSrcweir 		LPVOID lpMsgBuf;
307cdf0e10cSrcweir 		if ( FormatMessage(
308cdf0e10cSrcweir 			FORMAT_MESSAGE_ALLOCATE_BUFFER |
309cdf0e10cSrcweir 			FORMAT_MESSAGE_FROM_SYSTEM |
310cdf0e10cSrcweir 			FORMAT_MESSAGE_IGNORE_INSERTS,
311cdf0e10cSrcweir 			NULL,
312cdf0e10cSrcweir 			GetLastError(),
313cdf0e10cSrcweir 			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
314cdf0e10cSrcweir 			(LPTSTR) &lpMsgBuf,
315cdf0e10cSrcweir 			0,
316cdf0e10cSrcweir 			NULL ))
317cdf0e10cSrcweir 		{
318cdf0e10cSrcweir 			OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError, lpMsgBuf );
319cdf0e10cSrcweir 			LocalFree( lpMsgBuf );
320cdf0e10cSrcweir 		}
321cdf0e10cSrcweir 		else
322cdf0e10cSrcweir 			OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError );
323cdf0e10cSrcweir         SetMsiErrorCode( dwError );
324cdf0e10cSrcweir 	}
325cdf0e10cSrcweir 
326cdf0e10cSrcweir 	return fSuccess;
327cdf0e10cSrcweir }
328cdf0e10cSrcweir 
strip(const std::_tstring & s,_TCHAR c)329cdf0e10cSrcweir static std::_tstring strip( const std::_tstring& s, _TCHAR c )
330cdf0e10cSrcweir {
331cdf0e10cSrcweir 	std::_tstring	result = s;
332cdf0e10cSrcweir 
333cdf0e10cSrcweir 	std::_tstring::size_type f;
334cdf0e10cSrcweir 
335cdf0e10cSrcweir 	do
336cdf0e10cSrcweir 	{
337cdf0e10cSrcweir 		f = result.find( c );
338cdf0e10cSrcweir 		if ( f != std::_tstring::npos )
339cdf0e10cSrcweir 			result.erase( f, 1 );
340cdf0e10cSrcweir 	} while ( f != std::_tstring::npos );
341cdf0e10cSrcweir 
342cdf0e10cSrcweir 	return result;
343cdf0e10cSrcweir }
344cdf0e10cSrcweir 
trim(const std::_tstring & rString)345cdf0e10cSrcweir static std::_tstring trim( const std::_tstring& rString )
346cdf0e10cSrcweir {
347cdf0e10cSrcweir 	std::_tstring temp = rString;
348cdf0e10cSrcweir 
349cdf0e10cSrcweir 	while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' )
350cdf0e10cSrcweir 		temp.erase( 0, 1 );
351cdf0e10cSrcweir 
352cdf0e10cSrcweir 	std::_tstring::size_type	len = temp.length();
353cdf0e10cSrcweir 
354cdf0e10cSrcweir 	while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' )
355cdf0e10cSrcweir 	{
356cdf0e10cSrcweir 		temp.erase( len - 1, 1 );
357cdf0e10cSrcweir 		len = temp.length();
358cdf0e10cSrcweir 	}
359cdf0e10cSrcweir 
360cdf0e10cSrcweir 	return temp;
361cdf0e10cSrcweir }
362cdf0e10cSrcweir 
readLine(FILE * fp,std::_tstring & rLine)363cdf0e10cSrcweir static bool readLine( FILE *fp, std::_tstring& rLine )
364cdf0e10cSrcweir {
365cdf0e10cSrcweir 	_TCHAR szBuffer[1024];
366cdf0e10cSrcweir 	bool	bSuccess = false;
367cdf0e10cSrcweir 	bool	bEOL = false;
368cdf0e10cSrcweir 	std::_tstring	line;
369cdf0e10cSrcweir 
370cdf0e10cSrcweir 
371cdf0e10cSrcweir 	while ( !bEOL && _fgetts( szBuffer, sizeof(szBuffer), fp ) )
372cdf0e10cSrcweir 	{
373cdf0e10cSrcweir 		int	len = _tcslen(szBuffer);
374cdf0e10cSrcweir 
375cdf0e10cSrcweir 		bSuccess = true;
376cdf0e10cSrcweir 
377cdf0e10cSrcweir 		while ( len && szBuffer[len - 1] == '\n' )
378cdf0e10cSrcweir 		{
379cdf0e10cSrcweir 			szBuffer[--len] = 0;
380cdf0e10cSrcweir 			bEOL = true;
381cdf0e10cSrcweir 		}
382cdf0e10cSrcweir 
383cdf0e10cSrcweir 		line.append( szBuffer );
384cdf0e10cSrcweir 	}
385cdf0e10cSrcweir 
386cdf0e10cSrcweir 	rLine = line;
387cdf0e10cSrcweir 	return bSuccess;
388cdf0e10cSrcweir }
389cdf0e10cSrcweir 
390cdf0e10cSrcweir 
getProfileString(const std::_tstring & aFileName,const std::_tstring & aSectionName,const std::_tstring & aKeyName,const std::_tstring & aDefault=_T (""))391cdf0e10cSrcweir static std::_tstring getProfileString(
392cdf0e10cSrcweir 	const std::_tstring& aFileName,
393cdf0e10cSrcweir 	const std::_tstring& aSectionName,
394cdf0e10cSrcweir 	const std::_tstring& aKeyName,
395cdf0e10cSrcweir 	const std::_tstring& aDefault = _T("") )
396cdf0e10cSrcweir {
397cdf0e10cSrcweir 	FILE	*fp = _tfopen( aFileName.c_str(), _T("r") );
398cdf0e10cSrcweir 	std::_tstring	retValue = aDefault.length() ? aDefault : _T("");
399cdf0e10cSrcweir 
400cdf0e10cSrcweir 	if ( fp )
401cdf0e10cSrcweir 	{
402cdf0e10cSrcweir 		std::_tstring line;
403cdf0e10cSrcweir 		std::_tstring section;
404cdf0e10cSrcweir 
405cdf0e10cSrcweir 		while ( readLine( fp, line ) )
406cdf0e10cSrcweir 		{
407cdf0e10cSrcweir 			line = trim( line );
408cdf0e10cSrcweir 
409cdf0e10cSrcweir 			if ( line.length() && line[0] == '[' )
410cdf0e10cSrcweir 			{
411cdf0e10cSrcweir 				line.erase( 0, 1 );
412cdf0e10cSrcweir 				std::_tstring::size_type end = line.find( ']', 0 );
413cdf0e10cSrcweir 
414cdf0e10cSrcweir 				if ( std::_tstring::npos != end )
415cdf0e10cSrcweir 					section = trim( line.substr( 0, end ) );
416cdf0e10cSrcweir 			}
417cdf0e10cSrcweir 			else
418cdf0e10cSrcweir 			{
419cdf0e10cSrcweir 
420cdf0e10cSrcweir 				std::_tstring::size_type iEqualSign = line.find( '=', 0 );
421cdf0e10cSrcweir 
422cdf0e10cSrcweir 				if ( iEqualSign != std::_tstring::npos )
423cdf0e10cSrcweir 				{
424cdf0e10cSrcweir 					std::_tstring	keyname = line.substr( 0, iEqualSign );
425cdf0e10cSrcweir 					keyname = trim( keyname );
426cdf0e10cSrcweir 
427cdf0e10cSrcweir 					std::_tstring	value = line.substr( iEqualSign + 1 /*, std::_tstring::npos */ );
428cdf0e10cSrcweir 					value = trim( value );
429cdf0e10cSrcweir 
430cdf0e10cSrcweir 					if (
431cdf0e10cSrcweir 						0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) &&
432cdf0e10cSrcweir 						0 == _tcsicmp( keyname.c_str(), aKeyName.c_str() )
433cdf0e10cSrcweir 						 )
434cdf0e10cSrcweir 					{
435cdf0e10cSrcweir 						retValue = value;
436cdf0e10cSrcweir 						break;
437cdf0e10cSrcweir 					}
438cdf0e10cSrcweir 				}
439cdf0e10cSrcweir 			}
440cdf0e10cSrcweir 		}
441cdf0e10cSrcweir 
442cdf0e10cSrcweir 		fclose( fp );
443cdf0e10cSrcweir 	}
444cdf0e10cSrcweir 
445cdf0e10cSrcweir 	return retValue;
446cdf0e10cSrcweir }
447cdf0e10cSrcweir 
getProfileSections(const std::_tstring & aFileName)448cdf0e10cSrcweir static std::queue< std::_tstring > getProfileSections( const std::_tstring& aFileName )
449cdf0e10cSrcweir {
450cdf0e10cSrcweir 	FILE	*fp = _tfopen( aFileName.c_str(), _T("r") );
451cdf0e10cSrcweir 	std::queue< std::_tstring >	aResult;
452cdf0e10cSrcweir 
453cdf0e10cSrcweir 	OutputDebugStringFormat( TEXT("*** Retrieving Section Names ****") );
454cdf0e10cSrcweir 
455cdf0e10cSrcweir 	if ( fp )
456cdf0e10cSrcweir 	{
457cdf0e10cSrcweir 		std::_tstring line;
458cdf0e10cSrcweir 		std::_tstring section;
459cdf0e10cSrcweir 
460cdf0e10cSrcweir 		while ( readLine( fp, line ) )
461cdf0e10cSrcweir 		{
462cdf0e10cSrcweir 			line = trim( line );
463cdf0e10cSrcweir 
464cdf0e10cSrcweir 			if ( line.length() && line[0] == '[' )
465cdf0e10cSrcweir 			{
466cdf0e10cSrcweir 				line.erase( 0, 1 );
467cdf0e10cSrcweir 				std::_tstring::size_type end = line.find( ']', 0 );
468cdf0e10cSrcweir 
469cdf0e10cSrcweir 				if ( std::_tstring::npos != end )
470cdf0e10cSrcweir 					section = trim( line.substr( 0, end ) );
471cdf0e10cSrcweir 
472cdf0e10cSrcweir 				aResult.push( section );
473cdf0e10cSrcweir 
474cdf0e10cSrcweir 				OutputDebugStringFormat( TEXT("Section: %s"), section.c_str() );
475cdf0e10cSrcweir 
476cdf0e10cSrcweir 			}
477cdf0e10cSrcweir 		}
478cdf0e10cSrcweir 
479cdf0e10cSrcweir 		fclose( fp );
480cdf0e10cSrcweir 	}
481cdf0e10cSrcweir 
482cdf0e10cSrcweir 	OutputDebugStringFormat( TEXT("*** Done Section Names ***") );
483cdf0e10cSrcweir 
484cdf0e10cSrcweir 	return aResult;
485cdf0e10cSrcweir }
486cdf0e10cSrcweir 
getProfileKeys(const std::_tstring & aFileName,const std::_tstring & aSectionName)487cdf0e10cSrcweir static std::queue< std::_tstring > getProfileKeys( const std::_tstring& aFileName, const std::_tstring& aSectionName )
488cdf0e10cSrcweir {
489cdf0e10cSrcweir 	FILE	*fp = _tfopen( aFileName.c_str(), _T("r") );
490cdf0e10cSrcweir 	std::queue< std::_tstring >	aResult;
491cdf0e10cSrcweir 
492cdf0e10cSrcweir 	OutputDebugStringFormat( TEXT("*** Retrieving Key Names for [%s] ***"), aSectionName.c_str() );
493cdf0e10cSrcweir 
494cdf0e10cSrcweir 	if ( fp )
495cdf0e10cSrcweir 	{
496cdf0e10cSrcweir 		std::_tstring line;
497cdf0e10cSrcweir 		std::_tstring section;
498cdf0e10cSrcweir 
499cdf0e10cSrcweir 		while ( readLine( fp, line ) )
500cdf0e10cSrcweir 		{
501cdf0e10cSrcweir 			line = trim( line );
502cdf0e10cSrcweir 
503cdf0e10cSrcweir 			if ( line.length() && line[0] == '[' )
504cdf0e10cSrcweir 			{
505cdf0e10cSrcweir 				line.erase( 0, 1 );
506cdf0e10cSrcweir 				std::_tstring::size_type end = line.find( ']', 0 );
507cdf0e10cSrcweir 
508cdf0e10cSrcweir 				if ( std::_tstring::npos != end )
509cdf0e10cSrcweir 					section = trim( line.substr( 0, end ) );
510cdf0e10cSrcweir 			}
511cdf0e10cSrcweir 			else
512cdf0e10cSrcweir 			{
513cdf0e10cSrcweir 
514cdf0e10cSrcweir 				std::_tstring::size_type iEqualSign = line.find( '=', 0 );
515cdf0e10cSrcweir 
516cdf0e10cSrcweir 				if ( iEqualSign != std::_tstring::npos )
517cdf0e10cSrcweir 				{
518cdf0e10cSrcweir 					std::_tstring	keyname = line.substr( 0, iEqualSign );
519cdf0e10cSrcweir 					keyname = trim( keyname );
520cdf0e10cSrcweir 
521cdf0e10cSrcweir 					if ( 0 == _tcsicmp( section.c_str(), aSectionName.c_str() ) )
522cdf0e10cSrcweir 					{
523cdf0e10cSrcweir 						aResult.push( keyname );
524cdf0e10cSrcweir 
525cdf0e10cSrcweir 						OutputDebugStringFormat( keyname.c_str() );
526cdf0e10cSrcweir 
527cdf0e10cSrcweir 					}
528cdf0e10cSrcweir 				}
529cdf0e10cSrcweir 			}
530cdf0e10cSrcweir 		}
531cdf0e10cSrcweir 
532cdf0e10cSrcweir 		fclose( fp );
533cdf0e10cSrcweir 	}
534cdf0e10cSrcweir 
535cdf0e10cSrcweir 	OutputDebugStringFormat( TEXT("*** Done Key Names for [%s] ***"), aSectionName.c_str() );
536cdf0e10cSrcweir 
537cdf0e10cSrcweir 	return aResult;
538cdf0e10cSrcweir }
539cdf0e10cSrcweir 
InstallPatchedFiles(MSIHANDLE handle)540cdf0e10cSrcweir extern "C" UINT __stdcall InstallPatchedFiles( MSIHANDLE handle )
541cdf0e10cSrcweir {
542cdf0e10cSrcweir 	std::_tstring	sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
543910823aeSJürgen Schmidt //	std::_tstring	sProgramDir = sInstDir + TEXT("Basis\\program\\");
544910823aeSJürgen Schmidt 	std::_tstring	sProgramDir = sInstDir + TEXT("program\\");
545cdf0e10cSrcweir 	std::_tstring	sPatchFile = sProgramDir + TEXT("patchlist.txt");
546cdf0e10cSrcweir 
547cdf0e10cSrcweir 	std::queue< std::_tstring > aSectionNames;
548cdf0e10cSrcweir 	std::queue< std::_tstring > aKeyNames;
549cdf0e10cSrcweir 
550cdf0e10cSrcweir 	OutputDebugStringA( "Starting Custom Action" );
551cdf0e10cSrcweir 
552cdf0e10cSrcweir 	// std::_tstring	mystr;
553cdf0e10cSrcweir 	// mystr = "Patchfile: " + sPatchFile;
554cdf0e10cSrcweir 	// MessageBox( NULL, mystr.c_str(), "Patchfile", MB_OK );
555cdf0e10cSrcweir 
556cdf0e10cSrcweir 	aSectionNames = getProfileSections( sPatchFile );
557cdf0e10cSrcweir 	while ( !aSectionNames.empty() )
558cdf0e10cSrcweir 	{
559cdf0e10cSrcweir 		std::_tstring	sSectionName = aSectionNames.front();
560cdf0e10cSrcweir 		if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
561cdf0e10cSrcweir 		// mystr = "Section: " + sSectionName;
562cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
563cdf0e10cSrcweir 
564cdf0e10cSrcweir 		aKeyNames = getProfileKeys( sPatchFile, sSectionName );
565cdf0e10cSrcweir 		while ( !aKeyNames.empty() )
566cdf0e10cSrcweir 		{
567cdf0e10cSrcweir 			std::_tstring	sKeyName = aKeyNames.front();
568cdf0e10cSrcweir 			std::_tstring	sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
569cdf0e10cSrcweir 
570cdf0e10cSrcweir 			if ( sValue.length() )
571cdf0e10cSrcweir 			{
572cdf0e10cSrcweir 				std::_tstring	sFileName1 = sKeyName;
573cdf0e10cSrcweir 				std::_tstring	sExtension = sValue;
574cdf0e10cSrcweir 				std::_tstring	sFileName2;
575cdf0e10cSrcweir 
576cdf0e10cSrcweir 				sFileName1 = strip( sFileName1, '\"' );
577cdf0e10cSrcweir 				sExtension = strip( sExtension, '\"' );
578cdf0e10cSrcweir 
579cdf0e10cSrcweir 				sFileName1 = sInstDir + sSectionName + sFileName1;
580cdf0e10cSrcweir 				sFileName2 = sFileName1 + sExtension;
581cdf0e10cSrcweir 
582cdf0e10cSrcweir 				// mystr = "Convert: " + sFileName1 + " to " + sFileName2;
583cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
584cdf0e10cSrcweir 
585cdf0e10cSrcweir 				SwapFiles( sFileName1, sFileName2 );
586cdf0e10cSrcweir 			}
587cdf0e10cSrcweir 
588cdf0e10cSrcweir 			aKeyNames.pop();
589cdf0e10cSrcweir 		}
590cdf0e10cSrcweir 
591cdf0e10cSrcweir 		aSectionNames.pop();
592cdf0e10cSrcweir 	}
593cdf0e10cSrcweir 
594cdf0e10cSrcweir 	return ERROR_SUCCESS;
595cdf0e10cSrcweir }
596cdf0e10cSrcweir 
UninstallPatchedFiles(MSIHANDLE handle)597cdf0e10cSrcweir extern "C" UINT __stdcall UninstallPatchedFiles( MSIHANDLE handle )
598cdf0e10cSrcweir {
599cdf0e10cSrcweir 	TCHAR	szValue[8192];
600cdf0e10cSrcweir 	DWORD	nValueSize = sizeof(szValue);
601cdf0e10cSrcweir 	HKEY	hKey;
602cdf0e10cSrcweir 
603cdf0e10cSrcweir 	std::_tstring	sInstDir;
604cdf0e10cSrcweir 
605cdf0e10cSrcweir 	std::_tstring	sProductKey = GetMsiProperty( handle, TEXT("FINDPRODUCT") );
606cdf0e10cSrcweir 
607cdf0e10cSrcweir 	if ( ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER,  sProductKey.c_str(), &hKey ) )
608cdf0e10cSrcweir 	{
609cdf0e10cSrcweir 		if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
610cdf0e10cSrcweir 		{
611cdf0e10cSrcweir 			sInstDir = szValue;
612cdf0e10cSrcweir 		}
613cdf0e10cSrcweir 		RegCloseKey( hKey );
614cdf0e10cSrcweir 	}
615cdf0e10cSrcweir 	else if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE,  sProductKey.c_str(), &hKey ) )
616cdf0e10cSrcweir 	{
617cdf0e10cSrcweir 		if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("INSTALLLOCATION"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
618cdf0e10cSrcweir 		{
619cdf0e10cSrcweir 			sInstDir = szValue;
620cdf0e10cSrcweir 		}
621cdf0e10cSrcweir 		RegCloseKey( hKey );
622cdf0e10cSrcweir 	}
623cdf0e10cSrcweir 	else
624cdf0e10cSrcweir 		return ERROR_SUCCESS;
625cdf0e10cSrcweir 
626*28b67305SJürgen Schmidt //	std::_tstring	sProgramDir = sInstDir + TEXT("Basis\\program\\");
627*28b67305SJürgen Schmidt 	std::_tstring	sProgramDir = sInstDir + TEXT("program\\");
628cdf0e10cSrcweir 	std::_tstring	sPatchFile = sProgramDir + TEXT("patchlist.txt");
629cdf0e10cSrcweir 
630cdf0e10cSrcweir 	std::queue< std::_tstring >	aSectionNames;
631cdf0e10cSrcweir 	std::queue< std::_tstring >	aKeyNames;
632cdf0e10cSrcweir 
633cdf0e10cSrcweir 	// std::_tstring	mystr;
634cdf0e10cSrcweir 	// mystr = "Patchfile: " + sPatchFile;
635cdf0e10cSrcweir 	// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
636cdf0e10cSrcweir 
637cdf0e10cSrcweir 	aSectionNames = getProfileSections( sPatchFile );
638cdf0e10cSrcweir 	while ( !aSectionNames.empty() )
639cdf0e10cSrcweir 	{
640cdf0e10cSrcweir 		std::_tstring	sSectionName = aSectionNames.front();
641cdf0e10cSrcweir 		if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
642cdf0e10cSrcweir 		// mystr = "Section: " + sSectionName;
643cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
644cdf0e10cSrcweir 
645cdf0e10cSrcweir 		aKeyNames = getProfileKeys( sPatchFile, sSectionName );
646cdf0e10cSrcweir 		while( !aKeyNames.empty() )
647cdf0e10cSrcweir 		{
648cdf0e10cSrcweir 			std::_tstring	sKeyName = aKeyNames.front();
649cdf0e10cSrcweir 			std::_tstring	sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
650cdf0e10cSrcweir 
651cdf0e10cSrcweir 			if ( sValue.length() )
652cdf0e10cSrcweir 			{
653cdf0e10cSrcweir 				std::_tstring	sFileName1 = sKeyName;
654cdf0e10cSrcweir 				std::_tstring	sExtension = sValue;
655cdf0e10cSrcweir 				std::_tstring	sFileName2;
656cdf0e10cSrcweir 
657cdf0e10cSrcweir 				sFileName1 = strip( sFileName1, '\"' );
658cdf0e10cSrcweir 				sExtension = strip( sExtension, '\"' );
659cdf0e10cSrcweir 
660cdf0e10cSrcweir 				sFileName1 = sInstDir + sSectionName + sFileName1;
661cdf0e10cSrcweir 				sFileName2 = sFileName1 + sExtension;
662cdf0e10cSrcweir 
663cdf0e10cSrcweir 				// mystr = "Convert: " + sFileName1 + " to " + sFileName2;
664cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
665cdf0e10cSrcweir 
666cdf0e10cSrcweir 				SwapFiles( sFileName2, sFileName1 );
667cdf0e10cSrcweir 			}
668cdf0e10cSrcweir 
669cdf0e10cSrcweir 			aKeyNames.pop();
670cdf0e10cSrcweir 		}
671cdf0e10cSrcweir 
672cdf0e10cSrcweir 		aSectionNames.pop();
673cdf0e10cSrcweir 	}
674cdf0e10cSrcweir 
675cdf0e10cSrcweir 	return ERROR_SUCCESS;
676cdf0e10cSrcweir }
677cdf0e10cSrcweir 
IsOfficeRunning(MSIHANDLE handle)678cdf0e10cSrcweir extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle )
679cdf0e10cSrcweir {
680cdf0e10cSrcweir 	std::_tstring	sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
681*28b67305SJürgen Schmidt //	std::_tstring	sResourceDir = sInstDir + TEXT("Basis\\program\\resource\\");
682*28b67305SJürgen Schmidt 	std::_tstring	sResourceDir = sInstDir + TEXT("program\\resource\\");
683cdf0e10cSrcweir 	std::_tstring	sPattern = sResourceDir + TEXT("vcl*.res");
684cdf0e10cSrcweir 
685cdf0e10cSrcweir 	WIN32_FIND_DATA	aFindFileData;
686cdf0e10cSrcweir 	HANDLE	hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
687cdf0e10cSrcweir 
688cdf0e10cSrcweir 	if ( IsValidHandle(hFind) )
689cdf0e10cSrcweir 	{
690cdf0e10cSrcweir 		BOOL	fSuccess = false;
691cdf0e10cSrcweir 		bool	fRenameSucceeded;
692cdf0e10cSrcweir 
693cdf0e10cSrcweir 		do
694cdf0e10cSrcweir 		{
695cdf0e10cSrcweir 			std::_tstring	sResourceFile = sResourceDir + aFindFileData.cFileName;
696cdf0e10cSrcweir 			std::_tstring	sIntermediate = sResourceFile + TEXT(".tmp");
697cdf0e10cSrcweir 
698cdf0e10cSrcweir 			fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING );
699cdf0e10cSrcweir 			if ( fRenameSucceeded )
700cdf0e10cSrcweir 			{
701cdf0e10cSrcweir 				MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 );
702cdf0e10cSrcweir 				fSuccess = FindNextFile( hFind, &aFindFileData );
703cdf0e10cSrcweir 			}
704cdf0e10cSrcweir 		} while ( fSuccess && fRenameSucceeded );
705cdf0e10cSrcweir 
706cdf0e10cSrcweir 		if ( !fRenameSucceeded )
707cdf0e10cSrcweir         {
708cdf0e10cSrcweir 			MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1"));
709cdf0e10cSrcweir             SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING );
710cdf0e10cSrcweir         }
711cdf0e10cSrcweir 
712cdf0e10cSrcweir 		FindClose( hFind );
713cdf0e10cSrcweir 	}
714cdf0e10cSrcweir 
715cdf0e10cSrcweir 
716cdf0e10cSrcweir 	return ERROR_SUCCESS;
717cdf0e10cSrcweir }
718cdf0e10cSrcweir 
SetFeatureState(MSIHANDLE handle)719cdf0e10cSrcweir extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle )
720cdf0e10cSrcweir {
721cdf0e10cSrcweir 	std::_tstring	mystr;
722cdf0e10cSrcweir 
723cdf0e10cSrcweir 	// 1. Reading Product Code from setup.ini of installed Office
724cdf0e10cSrcweir 
725cdf0e10cSrcweir 	std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
726cdf0e10cSrcweir 	// MessageBox(NULL, sInstallPath.c_str(), "INSTALLLOCATION", MB_OK);
727cdf0e10cSrcweir 	std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini");
728cdf0e10cSrcweir 
729cdf0e10cSrcweir 	TCHAR szProductCode[32767];
730cdf0e10cSrcweir 
731cdf0e10cSrcweir 	GetPrivateProfileString(
732cdf0e10cSrcweir 		TEXT("Bootstrap"),
733cdf0e10cSrcweir 		TEXT("ProductCode"),
734cdf0e10cSrcweir 		TEXT("NOTFOUND"),
735cdf0e10cSrcweir 		szProductCode,
736cdf0e10cSrcweir 		elementsof(szProductCode),
737cdf0e10cSrcweir 		sSetupiniPath.c_str()
738cdf0e10cSrcweir 		);
739cdf0e10cSrcweir 
740cdf0e10cSrcweir 	if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) )
741cdf0e10cSrcweir 	{
742cdf0e10cSrcweir 		// No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory.
743cdf0e10cSrcweir 		// MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK);
744cdf0e10cSrcweir 		return ERROR_SUCCESS;
745cdf0e10cSrcweir 	}
746cdf0e10cSrcweir 
747cdf0e10cSrcweir 	// 2. Converting Product code
748cdf0e10cSrcweir 
749cdf0e10cSrcweir 	std::_tstring productCode = TEXT(szProductCode);
750cdf0e10cSrcweir 	productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2));
751cdf0e10cSrcweir 	mystr = TEXT("Changed product code: ") + productCode;
752cdf0e10cSrcweir 	// MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK);
753cdf0e10cSrcweir 
754cdf0e10cSrcweir 	// 3. Setting path in the Windows registry to find installed features
755cdf0e10cSrcweir 
756cdf0e10cSrcweir 	std::_tstring registryKey;
757cdf0e10cSrcweir 	HKEY registryRoot;
758cdf0e10cSrcweir 
759cdf0e10cSrcweir 	if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) )
760cdf0e10cSrcweir 	{
761cdf0e10cSrcweir 		registryRoot = HKEY_LOCAL_MACHINE;
762cdf0e10cSrcweir 		registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode;
763cdf0e10cSrcweir 		mystr = registryKey;
764cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
765cdf0e10cSrcweir 	}
766cdf0e10cSrcweir 	else
767cdf0e10cSrcweir 	{
768cdf0e10cSrcweir 		registryRoot = HKEY_CURRENT_USER;
769cdf0e10cSrcweir 		registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode;
770cdf0e10cSrcweir 		mystr = registryKey;
771cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
772cdf0e10cSrcweir 	}
773cdf0e10cSrcweir 
774cdf0e10cSrcweir 	// 4. Collecting all installed features from Windows registry
775cdf0e10cSrcweir 
776cdf0e10cSrcweir 	HKEY hKey;
777cdf0e10cSrcweir 	if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS)
778cdf0e10cSrcweir 	{
779cdf0e10cSrcweir 		int counter = 0;
780cdf0e10cSrcweir 		// DWORD counter = 0;
781cdf0e10cSrcweir 		LONG lEnumResult;
782cdf0e10cSrcweir 
783cdf0e10cSrcweir 		do
784cdf0e10cSrcweir 		{
785cdf0e10cSrcweir 			TCHAR szValueName[8192];
786cdf0e10cSrcweir 			DWORD nValueNameSize = sizeof(szValueName);
787cdf0e10cSrcweir 			LPDWORD pValueNameSize = &nValueNameSize;
788cdf0e10cSrcweir 			TCHAR szValueData[8192];
789cdf0e10cSrcweir 			DWORD nValueDataSize = sizeof(szValueData);
790cdf0e10cSrcweir 
791cdf0e10cSrcweir 			lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize);
792cdf0e10cSrcweir 
793cdf0e10cSrcweir 			if ( ERROR_SUCCESS == lEnumResult )
794cdf0e10cSrcweir 			{
795cdf0e10cSrcweir 				std::_tstring sValueName = szValueName;
796cdf0e10cSrcweir 				std::_tstring sValueData = szValueData;
797cdf0e10cSrcweir 
798cdf0e10cSrcweir 				// mystr = sValueName;
799cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
800cdf0e10cSrcweir 				// mystr = sValueData;
801cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK );
802cdf0e10cSrcweir 
803cdf0e10cSrcweir 				// Does this feature exist in this patch?
804cdf0e10cSrcweir 				if ( IsSetMsiProperty(handle, sValueName) )
805cdf0e10cSrcweir 				{
806cdf0e10cSrcweir 					// Feature is not installed, if szValueData starts with a "square" (ascii 6)
807cdf0e10cSrcweir 					if ( 6 == szValueData[0] )
808cdf0e10cSrcweir 					{
809cdf0e10cSrcweir 						MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
810cdf0e10cSrcweir 						// mystr = TEXT("Do NOT install: ") + sValueName;
811cdf0e10cSrcweir 						// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
812cdf0e10cSrcweir 					}
813cdf0e10cSrcweir 					else
814cdf0e10cSrcweir 					{
815cdf0e10cSrcweir 						MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
816cdf0e10cSrcweir 						// mystr = TEXT("Do install: ") + sValueName;
817cdf0e10cSrcweir 						// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
818cdf0e10cSrcweir 					}
819cdf0e10cSrcweir 				}
820cdf0e10cSrcweir 			}
821cdf0e10cSrcweir 
822cdf0e10cSrcweir 			counter = counter + 1;
823cdf0e10cSrcweir 
824cdf0e10cSrcweir 		} while ( ERROR_SUCCESS == lEnumResult );
825cdf0e10cSrcweir 
826cdf0e10cSrcweir 		RegCloseKey( hKey );
827cdf0e10cSrcweir 	}
828cdf0e10cSrcweir 
829cdf0e10cSrcweir 	return ERROR_SUCCESS;
830cdf0e10cSrcweir }
831cdf0e10cSrcweir 
SetNewFeatureState(MSIHANDLE handle)832cdf0e10cSrcweir extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle )
833cdf0e10cSrcweir {
834cdf0e10cSrcweir 	std::_tstring mystr;
835cdf0e10cSrcweir     std::_tstring sValueName;
836cdf0e10cSrcweir 
837cdf0e10cSrcweir     sValueName = TEXT("gm_o_Onlineupdate");
838cdf0e10cSrcweir 
839cdf0e10cSrcweir     if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")))
840cdf0e10cSrcweir     {
841cdf0e10cSrcweir         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
842cdf0e10cSrcweir         // mystr = TEXT("OnlineUpdate wird installiert!");
843cdf0e10cSrcweir         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK);
844cdf0e10cSrcweir     }
845cdf0e10cSrcweir     else
846cdf0e10cSrcweir     {
847cdf0e10cSrcweir         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
848cdf0e10cSrcweir         // mystr = TEXT("OnlineUpdate wird NICHT installiert!");
849cdf0e10cSrcweir         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK);
850cdf0e10cSrcweir     }
851cdf0e10cSrcweir 
852cdf0e10cSrcweir 	return ERROR_SUCCESS;
853cdf0e10cSrcweir }
854cdf0e10cSrcweir 
ShowOnlineUpdateDialog(MSIHANDLE handle)855cdf0e10cSrcweir extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle )
856cdf0e10cSrcweir {
857cdf0e10cSrcweir     // Checking existence of file "updchk.uno.dll", which shows, that
858cdf0e10cSrcweir     // Online Update functionality is always available. Then the dialog
859cdf0e10cSrcweir     // that offers the Online Update is superfluous.
860cdf0e10cSrcweir 
861cdf0e10cSrcweir     std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
862*28b67305SJürgen Schmidt //    std::_tstring sProgramDir = sInstDir + TEXT("Basis\\program\\");
863*28b67305SJürgen Schmidt     std::_tstring sProgramDir = sInstDir + TEXT("program\\");
864cdf0e10cSrcweir     std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll");
865cdf0e10cSrcweir 
866cdf0e10cSrcweir     WIN32_FIND_DATA data;
867cdf0e10cSrcweir     HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data);
868cdf0e10cSrcweir     if (hdl != INVALID_HANDLE_VALUE)  // the file exists
869cdf0e10cSrcweir     {
870cdf0e10cSrcweir         // std::_tstring mystr;
871cdf0e10cSrcweir         // mystr = "Found file: " + sSearchFile;
872cdf0e10cSrcweir         // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK );
873cdf0e10cSrcweir 
874cdf0e10cSrcweir         // And finally setting property SHOW_ONLINEUPDATE_DIALOG
875cdf0e10cSrcweir         // to hide this dialog
876cdf0e10cSrcweir         UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
877cdf0e10cSrcweir 
878cdf0e10cSrcweir         // Setting SELECT_OU_FEATURE to 1, which is probably superfluous
879cdf0e10cSrcweir         // because this is already the default value. But only this
880cdf0e10cSrcweir         // guarantees, that CustomAction SetNewFeatureState always sets
881cdf0e10cSrcweir         // the correct FeatureState for "gm_o_Onlineupdate", if it is
882cdf0e10cSrcweir         // already installed.
883cdf0e10cSrcweir         SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"));
884cdf0e10cSrcweir     }
885cdf0e10cSrcweir     else
886cdf0e10cSrcweir     {
887cdf0e10cSrcweir         // std::_tstring mystr;
888cdf0e10cSrcweir         // mystr = "Did not find file: " + sSearchFile;
889cdf0e10cSrcweir         // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK );
890cdf0e10cSrcweir 
891cdf0e10cSrcweir         // If the file does not exist, the Online Update dialog
892cdf0e10cSrcweir         // has to be shown.
893cdf0e10cSrcweir         SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
894cdf0e10cSrcweir         FindClose(hdl);
895cdf0e10cSrcweir     }
896cdf0e10cSrcweir 
897cdf0e10cSrcweir 	return ERROR_SUCCESS;
898cdf0e10cSrcweir }
899