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