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