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, ¤t_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 }