xref: /trunk/main/setup_native/source/win32/customactions/reg64/reg64.cxx (revision a3cdc23e488c57f3433f22cd4458e65c27aa499c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #define UNICODE
23 
24 #ifdef _MSC_VER
25 #pragma warning(push, 1) /* disable warnings within system headers */
26 #endif
27 #define WIN32_LEAN_AND_MEAN
28 #include <windows.h>
29 #include <msiquery.h>
30 #ifdef _MSC_VER
31 #pragma warning(pop)
32 #endif
33 
34 #include <malloc.h>
35 //#include <string>
36 //#include <map>
37 #include <strsafe.h>
38 
39 // 10.11.2009 tkr: MinGW doesn't know anything about RegDeleteKeyExW if WINVER < 0x0502.
40 extern "C" {
41 WINADVAPI LONG WINAPI RegDeleteKeyExW(HKEY,LPCWSTR,REGSAM,DWORD);
42 }
43 
44 // 06.11.2009 tkr: to provide windows xp as build systems for mingw we need to define KEY_WOW64_64KEY
45 // in mingw 3.13 KEY_WOW64_64KEY isn't available < Win2003 systems.
46 // Also defined in setup_native\source\win32\customactions\reg64\reg64.cxx,source\win32\customactions\shellextensions\shellextensions.cxx and
47 // extensions\source\activex\main\so_activex.cpp
48 
49 #ifndef KEY_WOW64_64KEY
50     #define KEY_WOW64_64KEY (0x0100)
51 #endif
52 
53 
54 #define TABLE_NAME L"Reg64"
55 #define INSTALLLOCATION L"[INSTALLLOCATION]"
56 
57 bool isInstall4AllUsers;
58 wchar_t * sBasisInstallLocation;
59 
60 
61 enum OPERATION {
62     SET,
63     REMOVE
64 };
65 
66 #ifdef DEBUG
67 inline void OutputDebugStringFormat( const wchar_t* pFormat, ... )
68 {
69     wchar_t    buffer[1024];
70     va_list args;
71 
72     va_start( args, pFormat );
73     StringCchVPrintf( buffer, sizeof(buffer), pFormat, args );
74     OutputDebugString( buffer );
75 }
76 #else
77 static inline void OutputDebugStringFormat( const wchar_t*, ... )
78 {
79 }
80 #endif
81 
82 bool WriteRegistry( MSIHANDLE & hMSI, OPERATION op, const wchar_t* componentName)
83 {
84     INSTALLSTATE current_state;
85     INSTALLSTATE comp_state;
86     UINT ret = MsiGetComponentState( hMSI, componentName, &current_state, &comp_state );
87     if ( ERROR_SUCCESS == ret )
88     {
89         if (current_state == INSTALLSTATE_ABSENT)
90             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_ABSENT");
91         else if (current_state == INSTALLSTATE_DEFAULT)
92             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_DEFAULT");
93         else if (current_state == INSTALLSTATE_LOCAL)
94             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_LOCAL");
95         else if (current_state == INSTALLSTATE_REMOVED)
96             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_REMOVED");
97         else if (current_state == INSTALLSTATE_SOURCE)
98             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_SOURCE");
99         else if (current_state == INSTALLSTATE_UNKNOWN)
100             OutputDebugStringFormat(L"WriteRegistry - current_state: INSTALLSTATE_UNKNOWN");
101 
102         if (comp_state == INSTALLSTATE_ABSENT)
103             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_ABSENT");
104         else if (comp_state == INSTALLSTATE_DEFAULT)
105             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_DEFAULT");
106         else if (comp_state == INSTALLSTATE_LOCAL)
107             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_LOCAL");
108         else if (comp_state == INSTALLSTATE_REMOVED)
109             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_REMOVED");
110         else if (comp_state == INSTALLSTATE_SOURCE)
111             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_SOURCE");
112         else if (comp_state == INSTALLSTATE_UNKNOWN)
113             OutputDebugStringFormat(L"WriteRegistry - comp_state: INSTALLSTATE_UNKNOWN");
114 
115         switch (op)
116         {
117             case SET :
118                 if ( comp_state == INSTALLSTATE_LOCAL || ( current_state == INSTALLSTATE_LOCAL && comp_state == INSTALLSTATE_UNKNOWN ) )
119                 {
120                     return true;
121                 }
122                 break;
123             case REMOVE:
124                 OutputDebugStringFormat(L"WriteRegistry - Remove\n" );
125                 if ( current_state == INSTALLSTATE_LOCAL && (comp_state == INSTALLSTATE_ABSENT || comp_state == INSTALLSTATE_REMOVED) )
126                 {
127                     OutputDebugStringFormat(L"WriteRegistry - To be removed\n" );
128                     return true;
129                 }
130         }
131     } else
132     {
133         if (ERROR_INVALID_HANDLE == ret) OutputDebugStringFormat(L"WriteRegistry - Invalid handle");
134         if (ERROR_UNKNOWN_FEATURE  == ret) OutputDebugStringFormat(L"WriteRegistry - Unknown feature");
135     }
136 
137     return false;
138 }
139 
140 BOOL UnicodeEquals( wchar_t* pStr1, wchar_t* pStr2 )
141 {
142     if ( pStr1 == NULL && pStr2 == NULL )
143         return TRUE;
144     else if ( pStr1 == NULL || pStr2 == NULL )
145         return FALSE;
146 
147     while( *pStr1 == *pStr2 && *pStr1 && *pStr2 )
148         pStr1++, pStr2++;
149 
150     return ( *pStr1 == 0 && *pStr2 == 0 );
151 }
152 
153 BOOL GetMsiProp( MSIHANDLE hMSI, const wchar_t* pPropName, wchar_t** ppValue )
154 {
155     OutputDebugStringFormat(L"GetMsiProp - START\n" );
156     DWORD sz = 0;
157     UINT ret = MsiGetProperty( hMSI, pPropName, L"", &sz );
158     if ( ret == ERROR_MORE_DATA )
159     {
160         sz++;
161         DWORD nbytes = sz * sizeof( wchar_t );
162         wchar_t* buff = reinterpret_cast<wchar_t*>( malloc( nbytes ) );
163         ZeroMemory( buff, nbytes );
164         MsiGetProperty( hMSI, pPropName, buff, &sz );
165 
166         OutputDebugStringFormat(L"GetMsiProp - Value" );
167         OutputDebugStringFormat( buff );
168         *ppValue = buff;
169 
170         return TRUE;
171     } else if (ret  == ERROR_INVALID_HANDLE)
172     {
173         OutputDebugStringFormat(L"GetMsiProp - ERROR_INVALID_HANDLE" );
174     } else if (ret == ERROR_INVALID_PARAMETER)
175     {
176         OutputDebugStringFormat(L"GetMsiProp - ERROR_INVALID_PARAMETER" );
177     } else if (ret == ERROR_SUCCESS)
178     {
179         OutputDebugStringFormat(L"GetMsiProp - ERROR_SUCCESS" );
180     }
181 
182 
183     OutputDebugStringFormat(L"GetMsiProp - ENDE\n" );
184     return FALSE;
185 }
186 
187 bool IsInstallForAllUsers( MSIHANDLE hMSI )
188 {
189     OutputDebugStringFormat(L"IsInstallForAllUsers - START\n" );
190     bool bResult = FALSE;
191     wchar_t* pVal = NULL;
192     if ( GetMsiProp( hMSI, L"ALLUSERS", &pVal ) && pVal )
193     {
194         bResult = UnicodeEquals( pVal , L"1" );
195         free( pVal );
196     }
197 
198     OutputDebugStringFormat(L"IsInstallForAllUsers - ENDE\n" );
199     return bResult;
200 }
201 
202 wchar_t* GetBasisInstallLocation( MSIHANDLE hMSI )
203 {
204     OutputDebugStringFormat(L"GetBasisInstallLocation - START\n" );
205     bool bResult = FALSE;
206     wchar_t* pVal = NULL;
207     GetMsiProp( hMSI, L"INSTALLLOCATION", &pVal);
208 
209     OutputDebugStringFormat(L"GetBasisInstallLocation - ENDE\n" );
210 
211     return pVal;
212 }
213 
214 
215 bool QueryReg64Table(MSIHANDLE& rhDatabase, MSIHANDLE& rhView)
216 {
217     OutputDebugStringFormat(L"QueryReg64Table - START\n" );
218     int const arraysize = 400;
219     wchar_t szSelect[arraysize];
220     StringCbPrintfW(szSelect, arraysize * sizeof(wchar_t), L"SELECT * FROM %s",TABLE_NAME);
221     OutputDebugStringFormat( szSelect );
222 
223     UINT ret = MsiDatabaseOpenView(rhDatabase,szSelect,&rhView);
224     if (ret != ERROR_SUCCESS)
225     {
226         if ( ret == ERROR_BAD_QUERY_SYNTAX)
227             OutputDebugStringFormat(L"QueryReg64Table - MsiDatabaseOpenView - FAILED - ERROR_BAD_QUERY_SYNTAX\n" );
228         if ( ret == ERROR_INVALID_HANDLE)
229             OutputDebugStringFormat(L"QueryReg64Table - MsiDatabaseOpenView - FAILED - ERROR_INVALID_HANDLE\n" );
230         return false;
231     }
232     // execute query - not a parameter query so second parameter is NULL.
233     if (MsiViewExecute(rhView,NULL) != ERROR_SUCCESS)
234     {
235         OutputDebugStringFormat(L"QueryReg64Table - MsiViewExecute - FAILED\n" );
236         return false;
237     }
238 
239     OutputDebugStringFormat(L"QueryReg64Table - ENDE\n" );
240     return true;
241 }
242 
243 //---------------------------------------
244 bool DeleteRegistryKey(HKEY RootKey, const wchar_t* KeyName)
245 {
246     int rc = RegDeleteKeyExW(
247         RootKey, KeyName, KEY_WOW64_64KEY, 0);
248 
249     return (ERROR_SUCCESS == rc);
250 }
251 
252 
253 //---------------------------------------
254 //
255 //---------------------------------------
256 
257 bool SetRegistryKey(HKEY RootKey, const wchar_t* KeyName, const wchar_t* ValueName, const wchar_t* Value)
258 {
259     HKEY hSubKey;
260 
261     // open or create the desired key
262     int rc = RegCreateKeyEx(
263         RootKey, KeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_WOW64_64KEY, 0, &hSubKey, 0);
264 
265     if (ERROR_SUCCESS == rc)
266     {
267         OutputDebugStringFormat(L"SetRegistryKey - Created\n" );
268         rc = RegSetValueEx(
269             hSubKey, ValueName, 0, REG_SZ, reinterpret_cast<const BYTE*>(Value), (wcslen(Value) + 1) * sizeof(wchar_t));
270 
271         RegCloseKey(hSubKey);
272     } else {
273         OutputDebugStringFormat(L"SetRegistryKey - FAILED\n" );
274     }
275 
276 
277     return (ERROR_SUCCESS == rc);
278 }
279 
280 bool DoRegEntries( MSIHANDLE& rhMSI, OPERATION op, MSIHANDLE& rhView)
281 {
282     OutputDebugStringFormat(L"DoRegEntries - START\n" );
283 
284     MSIHANDLE hRecord;
285 
286     long lRoot;
287     wchar_t  szKey[255];
288     wchar_t  szName[255];
289     wchar_t  szValue[1024];
290     wchar_t  szComponent[255];
291 
292     // read records until there are no more records
293     while (MsiViewFetch(rhView,&hRecord) == ERROR_SUCCESS)
294     {
295         DWORD    dwKey = 255;
296         DWORD    dwName = 255;
297         DWORD    dwValue = 1024;
298         DWORD    dwComponent = 255;
299 
300         szKey[0] = '\0';
301         szName[0] = '\0';
302         szValue[0] = '\0';
303         szComponent[0] = '\0';
304 
305         lRoot = MsiRecordGetInteger(hRecord,2);
306         MsiRecordGetString(hRecord,3,szKey,&dwKey);
307 
308         if (!MsiRecordIsNull(hRecord, 4))
309             MsiRecordGetString(hRecord,4,szName,&dwName);
310 
311         if (!MsiRecordIsNull(hRecord, 5))
312         {
313             MsiRecordGetString(hRecord,5,szValue,&dwValue);
314 
315 
316             wchar_t* nPos = wcsstr(szValue , INSTALLLOCATION);
317             if ( NULL != nPos)
318             {
319 
320                 DWORD nPrefixSize = nPos - szValue;
321 
322                 DWORD nPropSize = wcslen(sBasisInstallLocation);
323                 DWORD nPostfixSize = dwValue - wcslen( INSTALLLOCATION );
324 
325                 DWORD nNewValueBytes = (nPropSize + nPostfixSize + 1) * sizeof( wchar_t );
326                 wchar_t* newValue = reinterpret_cast<wchar_t*>( malloc( nNewValueBytes ) );
327                 ZeroMemory( newValue, nNewValueBytes );
328 
329                 // prefix
330                 wcsncpy(newValue, szValue, nPrefixSize);
331 
332                 // basis location
333                 wcsncat(newValue, sBasisInstallLocation, nPropSize * sizeof( wchar_t ));
334 
335                 // postfix
336                 wcsncat(newValue, nPos + ( wcslen( INSTALLLOCATION ) ), nPropSize * sizeof( wchar_t ));
337 
338                 wcsncpy(szValue, newValue, nNewValueBytes <=1024? nNewValueBytes: 1024);
339 
340                 free(newValue);
341             }
342 
343         }
344 
345 
346         MsiRecordGetString(hRecord,6,szComponent,&dwComponent);
347 
348         OutputDebugStringFormat(L"****** DoRegEntries *******" );
349         OutputDebugStringFormat(L"Root:" );
350         HKEY key = HKEY_CURRENT_USER;
351         switch (lRoot)
352         {
353             case(-1):
354                     if (isInstall4AllUsers)
355                     {
356                         key = HKEY_LOCAL_MACHINE;
357                         OutputDebugStringFormat(L"HKEY_LOCAL_MACHINE" );
358                     }
359                     else
360                     {
361                         key = HKEY_CURRENT_USER;
362                         OutputDebugStringFormat(L"HKEY_CURRENT_USER" );
363                     }
364                 break;
365             case(0):
366                     key = HKEY_CLASSES_ROOT;
367                     OutputDebugStringFormat(L"HKEY_CLASSES_ROOT" );
368                 break;
369             case(1):
370                     key = HKEY_CURRENT_USER;
371                     OutputDebugStringFormat(L"HKEY_CURRENT_USER" );
372                 break;
373             case(2):
374                     key = HKEY_LOCAL_MACHINE;
375                     OutputDebugStringFormat(L"HKEY_LOCAL_MACHINE" );
376                 break;
377             case(3):
378                     key = HKEY_USERS;
379                     OutputDebugStringFormat(L"HKEY_USERS" );
380                 break;
381             default:
382                     OutputDebugStringFormat(L"Unknown Root!" );
383                 break;
384         }
385 
386         OutputDebugStringFormat(L"Key:");
387         OutputDebugStringFormat( szKey );
388         OutputDebugStringFormat(L"Name:");
389         OutputDebugStringFormat( szName );
390         OutputDebugStringFormat(L"Value:");
391         OutputDebugStringFormat( szValue);
392         OutputDebugStringFormat(L"Component:");
393         OutputDebugStringFormat( szComponent );
394         OutputDebugStringFormat(L"*******************" );
395         switch (op)
396         {
397             case SET:
398 
399                     if (WriteRegistry(rhMSI, SET, szComponent))
400                     {
401                         OutputDebugStringFormat(L"DoRegEntries - Write\n" );
402                         SetRegistryKey(key, szKey, szName, szValue);
403                     }
404                 break;
405             case REMOVE:
406                     OutputDebugStringFormat(L"DoRegEntries - PreRemove\n" );
407                     if (WriteRegistry(rhMSI, REMOVE, szComponent))
408                     {
409                         OutputDebugStringFormat(L"DoRegEntries - Remove\n" );
410                         DeleteRegistryKey(key, szKey);
411                     }
412                 break;
413         }
414     }
415 
416     MsiCloseHandle(rhView);
417 
418 
419     OutputDebugStringFormat(L"DoRegEntries - ENDE\n" );
420 
421     return true;
422 }
423 
424 
425 bool Reg64(MSIHANDLE& rhMSI, OPERATION op)
426 {
427     isInstall4AllUsers = IsInstallForAllUsers(rhMSI);
428     sBasisInstallLocation = GetBasisInstallLocation(rhMSI);
429 
430     if (NULL == sBasisInstallLocation)
431     {
432         OutputDebugStringFormat(L"BASISINSTALLLOCATION is NULL\n" );
433         return false;
434     }
435 
436     MSIHANDLE hView;
437     MSIHANDLE hDatabase = MsiGetActiveDatabase(rhMSI);
438 
439     QueryReg64Table(hDatabase, hView);
440     OutputDebugStringFormat(L"Do something\n" );
441     DoRegEntries( rhMSI, op, hView);
442     OutputDebugStringFormat(L"Something done\n" );
443 
444     MsiCloseHandle(hView);
445     MsiCloseHandle(hDatabase);
446     free(sBasisInstallLocation);
447 
448     return true;
449 }
450 
451 extern "C" UINT __stdcall InstallReg64(MSIHANDLE hMSI)
452 {
453     OutputDebugStringFormat(L"InstallReg64\n" );
454     Reg64(hMSI, SET);
455     return ERROR_SUCCESS;
456 }
457 
458 extern "C" UINT __stdcall DeinstallReg64(MSIHANDLE hMSI)
459 {
460     OutputDebugStringFormat(L"DeinstallReg64\n" );
461     Reg64(hMSI, REMOVE);
462     return ERROR_SUCCESS;
463 }
464 
465 /* vim: set noet sw=4 ts=4: */
466