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
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
84 static inline void OutputDebugStringFormat( const wchar_t*, ... )
85 {
86 }
87 #endif
88 
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 
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 
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 
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 
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 
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 //---------------------------------------
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 
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 
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 
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 
461 extern "C" UINT __stdcall InstallReg64(MSIHANDLE hMSI)
462 {
463 	OutputDebugStringFormat(L"InstallReg64\n" );
464 	Reg64(hMSI, SET);
465 	return ERROR_SUCCESS;
466 }
467 
468 extern "C" UINT __stdcall DeinstallReg64(MSIHANDLE hMSI)
469 {
470 	OutputDebugStringFormat(L"DeinstallReg64\n" );
471 	Reg64(hMSI, REMOVE);
472 	return ERROR_SUCCESS;
473 }