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
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
67cdf0e10cSrcweir static inline void OutputDebugStringFormat( LPCTSTR, ... )
68cdf0e10cSrcweir {
69cdf0e10cSrcweir }
70cdf0e10cSrcweir #endif
71cdf0e10cSrcweir 
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 '{}'
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 
105cdf0e10cSrcweir static void Swap(char* p1, char* p2)
106cdf0e10cSrcweir {
107cdf0e10cSrcweir 	char tmp = *p1;
108cdf0e10cSrcweir 	*p1 = *p2;
109cdf0e10cSrcweir 	*p2 = tmp;
110cdf0e10cSrcweir }
111cdf0e10cSrcweir 
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
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 
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 
165cdf0e10cSrcweir static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
166cdf0e10cSrcweir {
167cdf0e10cSrcweir 	MsiSetProperty(handle, sProperty.c_str(), NULL);
168cdf0e10cSrcweir }
169cdf0e10cSrcweir 
170cdf0e10cSrcweir static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty)
171cdf0e10cSrcweir {
172cdf0e10cSrcweir 	MsiSetProperty(handle, sProperty.c_str(), TEXT("1"));
173cdf0e10cSrcweir }
174cdf0e10cSrcweir 
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 
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 
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 
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 
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 
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 
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 
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 
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 
540cdf0e10cSrcweir extern "C" UINT __stdcall InstallPatchedFiles( MSIHANDLE handle )
541cdf0e10cSrcweir {
542cdf0e10cSrcweir 	std::_tstring	sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
543*910823aeSJürgen Schmidt //	std::_tstring	sProgramDir = sInstDir + TEXT("Basis\\program\\");
544*910823aeSJü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 
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 
626cdf0e10cSrcweir 	std::_tstring	sProgramDir = sInstDir + TEXT("Basis\\program\\");
627cdf0e10cSrcweir 	std::_tstring	sPatchFile = sProgramDir + TEXT("patchlist.txt");
628cdf0e10cSrcweir 
629cdf0e10cSrcweir 	std::queue< std::_tstring >	aSectionNames;
630cdf0e10cSrcweir 	std::queue< std::_tstring >	aKeyNames;
631cdf0e10cSrcweir 
632cdf0e10cSrcweir 	// std::_tstring	mystr;
633cdf0e10cSrcweir 	// mystr = "Patchfile: " + sPatchFile;
634cdf0e10cSrcweir 	// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
635cdf0e10cSrcweir 
636cdf0e10cSrcweir 	aSectionNames = getProfileSections( sPatchFile );
637cdf0e10cSrcweir 	while ( !aSectionNames.empty() )
638cdf0e10cSrcweir 	{
639cdf0e10cSrcweir 		std::_tstring	sSectionName = aSectionNames.front();
640cdf0e10cSrcweir 		if ( std::_tstring(TEXT("_root")) == sSectionName ) { sSectionName = TEXT(""); }
641cdf0e10cSrcweir 		// mystr = "Section: " + sSectionName;
642cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
643cdf0e10cSrcweir 
644cdf0e10cSrcweir 		aKeyNames = getProfileKeys( sPatchFile, sSectionName );
645cdf0e10cSrcweir 		while( !aKeyNames.empty() )
646cdf0e10cSrcweir 		{
647cdf0e10cSrcweir 			std::_tstring	sKeyName = aKeyNames.front();
648cdf0e10cSrcweir 			std::_tstring	sValue = getProfileString( sPatchFile, sSectionName, sKeyName );
649cdf0e10cSrcweir 
650cdf0e10cSrcweir 			if ( sValue.length() )
651cdf0e10cSrcweir 			{
652cdf0e10cSrcweir 				std::_tstring	sFileName1 = sKeyName;
653cdf0e10cSrcweir 				std::_tstring	sExtension = sValue;
654cdf0e10cSrcweir 				std::_tstring	sFileName2;
655cdf0e10cSrcweir 
656cdf0e10cSrcweir 				sFileName1 = strip( sFileName1, '\"' );
657cdf0e10cSrcweir 				sExtension = strip( sExtension, '\"' );
658cdf0e10cSrcweir 
659cdf0e10cSrcweir 				sFileName1 = sInstDir + sSectionName + sFileName1;
660cdf0e10cSrcweir 				sFileName2 = sFileName1 + sExtension;
661cdf0e10cSrcweir 
662cdf0e10cSrcweir 				// mystr = "Convert: " + sFileName1 + " to " + sFileName2;
663cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "Titel", MB_OK );
664cdf0e10cSrcweir 
665cdf0e10cSrcweir 				SwapFiles( sFileName2, sFileName1 );
666cdf0e10cSrcweir 			}
667cdf0e10cSrcweir 
668cdf0e10cSrcweir 			aKeyNames.pop();
669cdf0e10cSrcweir 		}
670cdf0e10cSrcweir 
671cdf0e10cSrcweir 		aSectionNames.pop();
672cdf0e10cSrcweir 	}
673cdf0e10cSrcweir 
674cdf0e10cSrcweir 	return ERROR_SUCCESS;
675cdf0e10cSrcweir }
676cdf0e10cSrcweir 
677cdf0e10cSrcweir extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle )
678cdf0e10cSrcweir {
679cdf0e10cSrcweir 	std::_tstring	sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
680cdf0e10cSrcweir 	std::_tstring	sResourceDir = sInstDir + TEXT("Basis\\program\\resource\\");
681cdf0e10cSrcweir 	std::_tstring	sPattern = sResourceDir + TEXT("vcl*.res");
682cdf0e10cSrcweir 
683cdf0e10cSrcweir 	WIN32_FIND_DATA	aFindFileData;
684cdf0e10cSrcweir 	HANDLE	hFind = FindFirstFile( sPattern.c_str(), &aFindFileData );
685cdf0e10cSrcweir 
686cdf0e10cSrcweir 	if ( IsValidHandle(hFind) )
687cdf0e10cSrcweir 	{
688cdf0e10cSrcweir 		BOOL	fSuccess = false;
689cdf0e10cSrcweir 		bool	fRenameSucceeded;
690cdf0e10cSrcweir 
691cdf0e10cSrcweir 		do
692cdf0e10cSrcweir 		{
693cdf0e10cSrcweir 			std::_tstring	sResourceFile = sResourceDir + aFindFileData.cFileName;
694cdf0e10cSrcweir 			std::_tstring	sIntermediate = sResourceFile + TEXT(".tmp");
695cdf0e10cSrcweir 
696cdf0e10cSrcweir 			fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING );
697cdf0e10cSrcweir 			if ( fRenameSucceeded )
698cdf0e10cSrcweir 			{
699cdf0e10cSrcweir 				MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 );
700cdf0e10cSrcweir 				fSuccess = FindNextFile( hFind, &aFindFileData );
701cdf0e10cSrcweir 			}
702cdf0e10cSrcweir 		} while ( fSuccess && fRenameSucceeded );
703cdf0e10cSrcweir 
704cdf0e10cSrcweir 		if ( !fRenameSucceeded )
705cdf0e10cSrcweir         {
706cdf0e10cSrcweir 			MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1"));
707cdf0e10cSrcweir             SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING );
708cdf0e10cSrcweir         }
709cdf0e10cSrcweir 
710cdf0e10cSrcweir 		FindClose( hFind );
711cdf0e10cSrcweir 	}
712cdf0e10cSrcweir 
713cdf0e10cSrcweir 
714cdf0e10cSrcweir 	return ERROR_SUCCESS;
715cdf0e10cSrcweir }
716cdf0e10cSrcweir 
717cdf0e10cSrcweir extern "C" UINT __stdcall SetFeatureState( MSIHANDLE handle )
718cdf0e10cSrcweir {
719cdf0e10cSrcweir 	std::_tstring	mystr;
720cdf0e10cSrcweir 
721cdf0e10cSrcweir 	// 1. Reading Product Code from setup.ini of installed Office
722cdf0e10cSrcweir 
723cdf0e10cSrcweir 	std::_tstring sInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION"));
724cdf0e10cSrcweir 	// MessageBox(NULL, sInstallPath.c_str(), "INSTALLLOCATION", MB_OK);
725cdf0e10cSrcweir 	std::_tstring sSetupiniPath = sInstallPath + TEXT("program\\setup.ini");
726cdf0e10cSrcweir 
727cdf0e10cSrcweir 	TCHAR szProductCode[32767];
728cdf0e10cSrcweir 
729cdf0e10cSrcweir 	GetPrivateProfileString(
730cdf0e10cSrcweir 		TEXT("Bootstrap"),
731cdf0e10cSrcweir 		TEXT("ProductCode"),
732cdf0e10cSrcweir 		TEXT("NOTFOUND"),
733cdf0e10cSrcweir 		szProductCode,
734cdf0e10cSrcweir 		elementsof(szProductCode),
735cdf0e10cSrcweir 		sSetupiniPath.c_str()
736cdf0e10cSrcweir 		);
737cdf0e10cSrcweir 
738cdf0e10cSrcweir 	if ( !_tcsicmp( szProductCode, TEXT("NOTFOUND") ) )
739cdf0e10cSrcweir 	{
740cdf0e10cSrcweir 		// No setup.ini or no "ProductCode" in setup.ini. This is an invalid directory.
741cdf0e10cSrcweir 		// MessageBox(NULL, "NOTFOUND set", "DEBUG", MB_OK);
742cdf0e10cSrcweir 		return ERROR_SUCCESS;
743cdf0e10cSrcweir 	}
744cdf0e10cSrcweir 
745cdf0e10cSrcweir 	// 2. Converting Product code
746cdf0e10cSrcweir 
747cdf0e10cSrcweir 	std::_tstring productCode = TEXT(szProductCode);
748cdf0e10cSrcweir 	productCode = ConvertGuid(std::_tstring(productCode.c_str() + 1, productCode.length() - 2));
749cdf0e10cSrcweir 	mystr = TEXT("Changed product code: ") + productCode;
750cdf0e10cSrcweir 	// MessageBox(NULL, mystr.c_str(), "ProductCode", MB_OK);
751cdf0e10cSrcweir 
752cdf0e10cSrcweir 	// 3. Setting path in the Windows registry to find installed features
753cdf0e10cSrcweir 
754cdf0e10cSrcweir 	std::_tstring registryKey;
755cdf0e10cSrcweir 	HKEY registryRoot;
756cdf0e10cSrcweir 
757cdf0e10cSrcweir 	if ( IsSetMsiProperty(handle, TEXT("ALLUSERS")) )
758cdf0e10cSrcweir 	{
759cdf0e10cSrcweir 		registryRoot = HKEY_LOCAL_MACHINE;
760cdf0e10cSrcweir 		registryKey = TEXT("Software\\Classes\\Installer\\Features\\") + productCode;
761cdf0e10cSrcweir 		mystr = registryKey;
762cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
763cdf0e10cSrcweir 	}
764cdf0e10cSrcweir 	else
765cdf0e10cSrcweir 	{
766cdf0e10cSrcweir 		registryRoot = HKEY_CURRENT_USER;
767cdf0e10cSrcweir 		registryKey = TEXT("Software\\Microsoft\\Installer\\Features\\") + productCode;
768cdf0e10cSrcweir 		mystr = registryKey;
769cdf0e10cSrcweir 		// MessageBox( NULL, mystr.c_str(), "ALLUSERS", MB_OK );
770cdf0e10cSrcweir 	}
771cdf0e10cSrcweir 
772cdf0e10cSrcweir 	// 4. Collecting all installed features from Windows registry
773cdf0e10cSrcweir 
774cdf0e10cSrcweir 	HKEY hKey;
775cdf0e10cSrcweir 	if (RegOpenKey(registryRoot, registryKey.c_str(), &hKey) == ERROR_SUCCESS)
776cdf0e10cSrcweir 	{
777cdf0e10cSrcweir 		int counter = 0;
778cdf0e10cSrcweir 		// DWORD counter = 0;
779cdf0e10cSrcweir 		LONG lEnumResult;
780cdf0e10cSrcweir 
781cdf0e10cSrcweir 		do
782cdf0e10cSrcweir 		{
783cdf0e10cSrcweir 			TCHAR szValueName[8192];
784cdf0e10cSrcweir 			DWORD nValueNameSize = sizeof(szValueName);
785cdf0e10cSrcweir 			LPDWORD pValueNameSize = &nValueNameSize;
786cdf0e10cSrcweir 			TCHAR szValueData[8192];
787cdf0e10cSrcweir 			DWORD nValueDataSize = sizeof(szValueData);
788cdf0e10cSrcweir 
789cdf0e10cSrcweir 			lEnumResult = RegEnumValue( hKey, counter, szValueName, pValueNameSize, NULL, NULL, (LPBYTE)szValueData, &nValueDataSize);
790cdf0e10cSrcweir 
791cdf0e10cSrcweir 			if ( ERROR_SUCCESS == lEnumResult )
792cdf0e10cSrcweir 			{
793cdf0e10cSrcweir 				std::_tstring sValueName = szValueName;
794cdf0e10cSrcweir 				std::_tstring sValueData = szValueData;
795cdf0e10cSrcweir 
796cdf0e10cSrcweir 				// mystr = sValueName;
797cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
798cdf0e10cSrcweir 				// mystr = sValueData;
799cdf0e10cSrcweir 				// MessageBox( NULL, mystr.c_str(), "ValueData", MB_OK );
800cdf0e10cSrcweir 
801cdf0e10cSrcweir 				// Does this feature exist in this patch?
802cdf0e10cSrcweir 				if ( IsSetMsiProperty(handle, sValueName) )
803cdf0e10cSrcweir 				{
804cdf0e10cSrcweir 					// Feature is not installed, if szValueData starts with a "square" (ascii 6)
805cdf0e10cSrcweir 					if ( 6 == szValueData[0] )
806cdf0e10cSrcweir 					{
807cdf0e10cSrcweir 						MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
808cdf0e10cSrcweir 						// mystr = TEXT("Do NOT install: ") + sValueName;
809cdf0e10cSrcweir 						// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
810cdf0e10cSrcweir 					}
811cdf0e10cSrcweir 					else
812cdf0e10cSrcweir 					{
813cdf0e10cSrcweir 						MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
814cdf0e10cSrcweir 						// mystr = TEXT("Do install: ") + sValueName;
815cdf0e10cSrcweir 						// MessageBox( NULL, mystr.c_str(), "ValueName", MB_OK );
816cdf0e10cSrcweir 					}
817cdf0e10cSrcweir 				}
818cdf0e10cSrcweir 			}
819cdf0e10cSrcweir 
820cdf0e10cSrcweir 			counter = counter + 1;
821cdf0e10cSrcweir 
822cdf0e10cSrcweir 		} while ( ERROR_SUCCESS == lEnumResult );
823cdf0e10cSrcweir 
824cdf0e10cSrcweir 		RegCloseKey( hKey );
825cdf0e10cSrcweir 	}
826cdf0e10cSrcweir 
827cdf0e10cSrcweir 	return ERROR_SUCCESS;
828cdf0e10cSrcweir }
829cdf0e10cSrcweir 
830cdf0e10cSrcweir extern "C" UINT __stdcall SetNewFeatureState( MSIHANDLE handle )
831cdf0e10cSrcweir {
832cdf0e10cSrcweir 	std::_tstring mystr;
833cdf0e10cSrcweir     std::_tstring sValueName;
834cdf0e10cSrcweir 
835cdf0e10cSrcweir     sValueName = TEXT("gm_o_Onlineupdate");
836cdf0e10cSrcweir 
837cdf0e10cSrcweir     if (IsSetMsiProperty(handle, TEXT("SELECT_OU_FEATURE")))
838cdf0e10cSrcweir     {
839cdf0e10cSrcweir         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_LOCAL); // do install this feature
840cdf0e10cSrcweir         // mystr = TEXT("OnlineUpdate wird installiert!");
841cdf0e10cSrcweir         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_LOCAL", MB_OK);
842cdf0e10cSrcweir     }
843cdf0e10cSrcweir     else
844cdf0e10cSrcweir     {
845cdf0e10cSrcweir         MsiSetFeatureState(handle,sValueName.c_str(),INSTALLSTATE_ABSENT); // do not install this feature
846cdf0e10cSrcweir         // mystr = TEXT("OnlineUpdate wird NICHT installiert!");
847cdf0e10cSrcweir         // MessageBox(NULL, mystr.c_str(), "INSTALLSTATE_ABSENT", MB_OK);
848cdf0e10cSrcweir     }
849cdf0e10cSrcweir 
850cdf0e10cSrcweir 	return ERROR_SUCCESS;
851cdf0e10cSrcweir }
852cdf0e10cSrcweir 
853cdf0e10cSrcweir extern "C" UINT __stdcall ShowOnlineUpdateDialog( MSIHANDLE handle )
854cdf0e10cSrcweir {
855cdf0e10cSrcweir     // Checking existence of file "updchk.uno.dll", which shows, that
856cdf0e10cSrcweir     // Online Update functionality is always available. Then the dialog
857cdf0e10cSrcweir     // that offers the Online Update is superfluous.
858cdf0e10cSrcweir 
859cdf0e10cSrcweir     std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") );
860cdf0e10cSrcweir     std::_tstring sProgramDir = sInstDir + TEXT("Basis\\program\\");
861cdf0e10cSrcweir     std::_tstring sSearchFile = sProgramDir + TEXT("updchk.uno.dll");
862cdf0e10cSrcweir 
863cdf0e10cSrcweir     WIN32_FIND_DATA data;
864cdf0e10cSrcweir     HANDLE hdl = FindFirstFile(sSearchFile.c_str(), &data);
865cdf0e10cSrcweir     if (hdl != INVALID_HANDLE_VALUE)  // the file exists
866cdf0e10cSrcweir     {
867cdf0e10cSrcweir         // std::_tstring mystr;
868cdf0e10cSrcweir         // mystr = "Found file: " + sSearchFile;
869cdf0e10cSrcweir         // MessageBox( NULL, mystr.c_str(), "Found file", MB_OK );
870cdf0e10cSrcweir 
871cdf0e10cSrcweir         // And finally setting property SHOW_ONLINEUPDATE_DIALOG
872cdf0e10cSrcweir         // to hide this dialog
873cdf0e10cSrcweir         UnsetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
874cdf0e10cSrcweir 
875cdf0e10cSrcweir         // Setting SELECT_OU_FEATURE to 1, which is probably superfluous
876cdf0e10cSrcweir         // because this is already the default value. But only this
877cdf0e10cSrcweir         // guarantees, that CustomAction SetNewFeatureState always sets
878cdf0e10cSrcweir         // the correct FeatureState for "gm_o_Onlineupdate", if it is
879cdf0e10cSrcweir         // already installed.
880cdf0e10cSrcweir         SetMsiProperty(handle, TEXT("SELECT_OU_FEATURE"));
881cdf0e10cSrcweir     }
882cdf0e10cSrcweir     else
883cdf0e10cSrcweir     {
884cdf0e10cSrcweir         // std::_tstring mystr;
885cdf0e10cSrcweir         // mystr = "Did not find file: " + sSearchFile;
886cdf0e10cSrcweir         // MessageBox( NULL, mystr.c_str(), "File not found", MB_OK );
887cdf0e10cSrcweir 
888cdf0e10cSrcweir         // If the file does not exist, the Online Update dialog
889cdf0e10cSrcweir         // has to be shown.
890cdf0e10cSrcweir         SetMsiProperty(handle, TEXT("SHOW_ONLINEUPDATE_DIALOG"));
891cdf0e10cSrcweir         FindClose(hdl);
892cdf0e10cSrcweir     }
893cdf0e10cSrcweir 
894cdf0e10cSrcweir 	return ERROR_SUCCESS;
895cdf0e10cSrcweir }
896