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