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 #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 <strsafe.h> 37 38 //---------------------------------------------------------- 39 static const CHAR* g_Extensions[] = 40 { 41 ".doc", // Microsoft Word Text [0] 42 ".dot", // Microsoft Word Template 43 ".rtf", // rtf text 44 ".docx", // Office Word 2007 XML document 45 ".docm", // Office Word 2007 XML macro-enabled document 46 ".dotx", // Office Word 2007 XML template 47 ".dotm", // Office Word 2007 XML macro-enabled template 48 ".xlw", // Microsoft Excel 49 ".xls", // Microsoft Excel 50 ".xlt", // Microsoft Excel Template 51 ".xlsx", // Office Excel 2007 XML workbook 52 ".xlsm", // Office Excel 2007 XML macro-enabled workbook 53 ".xltx", // Office Excel 2007 XML template 54 ".xltm", // Office Excel 2007 XML macro-enabled template 55 ".xlsb", // Office Excel 2007 binary workbook (BIFF12) 56 ".ppt", // Microsoft Powerpoint 57 ".pps", // Microsoft Powerpoint 58 ".pot", // Microsoft Powerpoint Template 59 ".pptx", // Office PowerPoint 2007 XML presentation 60 ".pptm", // Office PowerPoint 2007 macro-enabled XML presentation 61 ".potx", // Office PowerPoint 2007 XML template 62 ".potm", // Office PowerPoint 2007 macro-enabled XML template 63 ".ppsx", // Office PowerPoint 2007 XML show 64 0 65 }; 66 67 static const int WORD_START = 0; 68 static const int EXCEL_START = 7; 69 static const int POWERPOINT_START = 15; 70 static const int POWERPOINT_END = 23; 71 72 // ".xlam", // Office Excel 2007 XML macro-enabled add-in 73 // ".ppam", // Office PowerPoint 2007 macro-enabled XML add-in 74 // ".ppsm", // Office PowerPoint 2007 macro-enabled XML show 75 76 //---------------------------------------------------------- 77 #ifdef DEBUG 78 inline void OutputDebugStringFormat( LPCSTR pFormat, ... ) 79 { 80 CHAR buffer[1024]; 81 va_list args; 82 83 va_start( args, pFormat ); 84 StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args ); 85 OutputDebugStringA( buffer ); 86 } 87 #else 88 static inline void OutputDebugStringFormat( LPCSTR, ... ) 89 { 90 } 91 #endif 92 93 //---------------------------------------------------------- 94 static BOOL CheckExtensionInRegistry( LPCSTR lpSubKey ) 95 { 96 BOOL bRet = false; 97 HKEY hKey = NULL; 98 LONG lResult = RegOpenKeyExA( HKEY_CLASSES_ROOT, lpSubKey, 0, KEY_QUERY_VALUE, &hKey ); 99 100 if ( ERROR_SUCCESS == lResult ) 101 { 102 CHAR szBuffer[1024]; 103 DWORD nSize = sizeof( szBuffer ); 104 105 lResult = RegQueryValueExA( hKey, "", NULL, NULL, (LPBYTE)szBuffer, &nSize ); 106 if ( ERROR_SUCCESS == lResult ) 107 { 108 szBuffer[nSize] = '\0'; 109 OutputDebugStringFormat( "Found value [%s] for key [%s].\n", szBuffer, lpSubKey ); 110 111 if ( strncmp( szBuffer, "WordPad.Document.1", 18 ) == 0 ) 112 { // We will replace registration for word pad 113 bRet = true; 114 } 115 else if ( strncmp( szBuffer, "OpenOffice.org.", 15 ) == 0 ) 116 { // We will replace registration for our (former) own types, too 117 bRet = true; 118 } 119 else if ( strncmp( szBuffer, "Apache OpenOffice.", 18 ) == 0 ) 120 { // We will replace registration for our own types, too 121 bRet = true; 122 } 123 else if ( strncmp( szBuffer, "ooostub.", 8 ) == 0 ) 124 { // We will replace registration for ooostub, too 125 bRet = true; 126 } 127 else 128 { 129 OutputDebugStringFormat( " Checking OpenWithList of [%s].\n", lpSubKey ); 130 HKEY hSubKey; 131 lResult = RegOpenKeyExA( hKey, "OpenWithList", 0, KEY_ENUMERATE_SUB_KEYS, &hSubKey ); 132 if ( ERROR_SUCCESS == lResult ) 133 { 134 DWORD nIndex = 0; 135 while ( ERROR_SUCCESS == lResult ) 136 { 137 nSize = sizeof( szBuffer ); 138 lResult = RegEnumKeyExA( hSubKey, nIndex++, szBuffer, &nSize, NULL, NULL, NULL, NULL ); 139 if ( ERROR_SUCCESS == lResult ) 140 { 141 OutputDebugStringFormat( " Found value [%s] in OpenWithList of [%s].\n", szBuffer, lpSubKey ); 142 if ( strncmp( szBuffer, "WordPad.exe", 11 ) == 0 ) 143 { // We will replace registration for word pad 144 bRet = true; 145 } 146 else if ( nSize > 0 ) 147 bRet = false; 148 } 149 } 150 } 151 else 152 { 153 OutputDebugStringFormat( " No OpenWithList found!\n" ); 154 } 155 } 156 } 157 else // no default value found -> return TRUE to register for that key 158 bRet = true; 159 160 RegCloseKey( hKey ); 161 } 162 else // no key found -> return TRUE to register for that key 163 bRet = true; 164 165 return bRet; 166 } 167 168 //---------------------------------------------------------- 169 static LONG DeleteSubKeyTree( HKEY RootKey, LPCSTR lpKey ) 170 { 171 HKEY hKey; 172 LONG rc = RegOpenKeyExA( RootKey, lpKey, 0, KEY_READ | DELETE, &hKey ); 173 174 if (ERROR_SUCCESS == rc) 175 { 176 LPCSTR lpSubKey; 177 DWORD nMaxSubKeyLen; 178 179 rc = RegQueryInfoKeyA( hKey, 0, 0, 0, 0, &nMaxSubKeyLen, 0, 0, 0, 0, 0, 0 ); 180 nMaxSubKeyLen++; // space for trailing '\0' 181 lpSubKey = reinterpret_cast<CHAR*>( _alloca( nMaxSubKeyLen*sizeof(CHAR) ) ); 182 183 while (ERROR_SUCCESS == rc) 184 { 185 DWORD nLen = nMaxSubKeyLen; 186 rc = RegEnumKeyExA( hKey, 0, (LPSTR)lpSubKey, &nLen, 0, 0, 0, 0); // always index zero 187 188 if ( ERROR_NO_MORE_ITEMS == rc ) 189 { 190 rc = RegDeleteKeyA( RootKey, lpKey ); 191 if ( rc == ERROR_SUCCESS ) 192 OutputDebugStringFormat( "deleted key [%s] from registry.\n", lpKey ); 193 else 194 OutputDebugStringFormat( "RegDeleteKeyA %s returned %ld.\n", lpKey, rc ); 195 break; 196 } 197 else if ( rc == ERROR_SUCCESS ) 198 { 199 rc = DeleteSubKeyTree( hKey, lpSubKey ); 200 if ( ERROR_SUCCESS != rc ) 201 OutputDebugStringFormat( "RegDeleteKeyA %s returned %ld.\n", lpSubKey, rc ); 202 } 203 204 } 205 RegCloseKey(hKey); 206 } 207 else 208 { 209 OutputDebugStringFormat( "RegOpenKeyExA %s returned %ld.\n", lpKey, rc ); 210 } 211 212 return rc; 213 } 214 215 //---------------------------------------------------------- 216 static BOOL RemoveExtensionInRegistry( LPCSTR lpSubKey ) 217 { 218 CHAR szBuffer[4096]; 219 DWORD nSize = sizeof( szBuffer ); 220 HKEY hKey = NULL; 221 HKEY hSubKey = NULL; 222 LONG lResult = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes", 0, KEY_QUERY_VALUE, &hKey ); 223 224 if ( ERROR_SUCCESS == lResult ) 225 { 226 lResult = RegOpenKeyExA( hKey, lpSubKey, 0, KEY_QUERY_VALUE, &hSubKey ); 227 228 if ( ERROR_SUCCESS == lResult ) 229 { 230 DWORD nSubKeys = 1; 231 szBuffer[0] = '\0'; 232 233 // we get the value of the default key fist and while we are on querying, 234 // we ask for the subkey count, too 235 lResult = RegQueryValueExA( hSubKey, "", NULL, NULL, (LPBYTE)szBuffer, &nSize ); 236 if ( ERROR_SUCCESS == lResult ) 237 RegQueryInfoKeyA( hSubKey, 0, 0, 0, &nSubKeys, 0, 0, 0, 0, 0, 0, 0 ); 238 RegCloseKey( hSubKey ); 239 240 // we will remove all key with an default value starting with ooostub but 241 // we have to be careful about MSO keys 242 if ( strncmp( szBuffer, "opendocument.", 13 ) == 0 ) 243 { 244 if ( nSubKeys == 0 ) 245 { 246 DeleteSubKeyTree( hKey, lpSubKey ); 247 } 248 else 249 { 250 lResult = RegOpenKeyExA( hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey ); 251 if ( ERROR_SUCCESS == lResult ) 252 RegDeleteValueA( hSubKey, "" ); 253 else 254 OutputDebugStringFormat( "Could not open key %s for deleting: RegOpenKeyEx returned %ld.\n", lpSubKey, lResult ); 255 } 256 } 257 } 258 259 RegCloseKey( hKey ); 260 } 261 262 return ( ERROR_SUCCESS == lResult ); 263 } 264 265 //---------------------------------------------------------- 266 bool GetMsiProp( MSIHANDLE handle, LPCSTR name, /*out*/std::string& value ) 267 { 268 DWORD sz = 0; 269 LPSTR dummy = ""; 270 if (MsiGetPropertyA(handle, name, dummy, &sz) == ERROR_MORE_DATA) 271 { 272 sz++; 273 DWORD nbytes = sz * sizeof(TCHAR); 274 LPSTR buff = reinterpret_cast<LPSTR>(_alloca(nbytes)); 275 ZeroMemory(buff, nbytes); 276 MsiGetPropertyA(handle, name, buff, &sz); 277 value = buff; 278 return true; 279 } 280 return false; 281 } 282 283 //---------------------------------------------------------- 284 bool IsSetMsiProp( MSIHANDLE handle, LPCSTR name ) 285 { 286 std::string val; 287 GetMsiProp( handle, name, val ); 288 return (val == "1"); 289 } 290 291 //---------------------------------------------------------- 292 static void registerForExtension( MSIHANDLE handle, const int nIndex, bool bRegister ) 293 { 294 CHAR sPropName[256]; 295 StringCchCopyA( sPropName, 256, "REGISTER_" ); 296 StringCchCatA( sPropName, 256, (g_Extensions[nIndex])+1 ); 297 CharUpperBuffA( sPropName+9, 4 ); 298 299 if ( bRegister ) { 300 MsiSetPropertyA( handle, sPropName, "1" ); 301 OutputDebugStringFormat( "Set MSI property %s.\n", sPropName ); 302 } else { 303 MsiSetPropertyA( handle, sPropName, "0" ); 304 OutputDebugStringFormat( "Unset MSI property %s.\n", sPropName ); 305 } 306 } 307 308 //---------------------------------------------------------- 309 static void registerForExtensions( MSIHANDLE handle, BOOL bRegisterAll ) 310 { // Check all file extensions 311 int nIndex = 0; 312 while ( g_Extensions[nIndex] != 0 ) 313 { 314 BOOL bRegister = bRegisterAll || CheckExtensionInRegistry( g_Extensions[nIndex] ); 315 if ( bRegister ) 316 registerForExtension( handle, nIndex, true ); 317 ++nIndex; 318 } 319 } 320 321 //---------------------------------------------------------- 322 static bool checkSomeExtensionInRegistry( const int nStart, const int nEnd ) 323 { // Check all file extensions 324 int nIndex = nStart; 325 bool bFound = false; 326 327 while ( !bFound && ( g_Extensions[nIndex] != 0 ) && ( nIndex < nEnd ) ) 328 { 329 bFound = ! CheckExtensionInRegistry( g_Extensions[nIndex] ); 330 331 if ( bFound ) 332 OutputDebugStringFormat( "Found registration for [%s].\n", g_Extensions[nIndex] ); 333 334 ++nIndex; 335 } 336 return bFound; 337 } 338 339 //---------------------------------------------------------- 340 static void registerSomeExtensions( MSIHANDLE handle, const int nStart, const int nEnd, bool bRegister ) 341 { // Check all file extensions 342 int nIndex = nStart; 343 344 while ( ( g_Extensions[nIndex] != 0 ) && ( nIndex < nEnd ) ) 345 { 346 registerForExtension( handle, nIndex++, bRegister ); 347 } 348 } 349 350 //---------------------------------------------------------- 351 //---------------------------------------------------------- 352 //---------------------------------------------------------- 353 extern "C" UINT __stdcall LookForRegisteredExtensions( MSIHANDLE handle ) 354 { 355 OutputDebugStringFormat( "LookForRegisteredExtensions: " ); 356 357 INSTALLSTATE current_state; 358 INSTALLSTATE future_state; 359 360 bool bWriterEnabled = false; 361 bool bCalcEnabled = false; 362 bool bImpressEnabled = false; 363 bool bRegisterNone = IsSetMsiProp( handle, "REGISTER_NO_MSO_TYPES" ); 364 365 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Wrt", ¤t_state, &future_state ) ) && 366 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) ) 367 bWriterEnabled = true; 368 369 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Writer is [%d], will be [%d]", current_state, future_state ); 370 if ( bWriterEnabled ) 371 OutputDebugStringFormat( "LookForRegisteredExtensions: Writer is enabled" ); 372 else 373 OutputDebugStringFormat( "LookForRegisteredExtensions: Writer is NOT enabled" ); 374 375 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Calc", ¤t_state, &future_state ) ) && 376 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) ) 377 bCalcEnabled = true; 378 379 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Calc is [%d], will be [%d]", current_state, future_state ); 380 if ( bCalcEnabled ) 381 OutputDebugStringFormat( "LookForRegisteredExtensions: Calc is enabled" ); 382 else 383 OutputDebugStringFormat( "LookForRegisteredExtensions: Calc is NOT enabled" ); 384 385 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Impress", ¤t_state, &future_state ) ) && 386 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) ) 387 bImpressEnabled = true; 388 389 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Impress is [%d], will be [%d]", current_state, future_state ); 390 if ( bImpressEnabled ) 391 OutputDebugStringFormat( "LookForRegisteredExtensions: Impress is enabled" ); 392 else 393 OutputDebugStringFormat( "LookForRegisteredExtensions: Impress is NOT enabled" ); 394 395 MsiSetPropertyA( handle, "SELECT_WORD", "" ); 396 MsiSetPropertyA( handle, "SELECT_EXCEL", "" ); 397 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "" ); 398 399 if ( ! bRegisterNone ) 400 { 401 if ( IsSetMsiProp( handle, "REGISTER_ALL_MSO_TYPES" ) ) 402 { 403 if ( bWriterEnabled ) 404 MsiSetPropertyA( handle, "SELECT_WORD", "1" ); 405 if ( bCalcEnabled ) 406 MsiSetPropertyA( handle, "SELECT_EXCEL", "1" ); 407 if ( bImpressEnabled ) 408 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "1" ); 409 } 410 else 411 { 412 if ( bWriterEnabled && ! checkSomeExtensionInRegistry( WORD_START, EXCEL_START ) ) 413 { 414 MsiSetPropertyA( handle, "SELECT_WORD", "1" ); 415 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for MicroSoft Word" ); 416 } 417 if ( bCalcEnabled && ! checkSomeExtensionInRegistry( EXCEL_START, POWERPOINT_START ) ) 418 { 419 MsiSetPropertyA( handle, "SELECT_EXCEL", "1" ); 420 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for MicroSoft Excel" ); 421 } 422 if ( bImpressEnabled && ! checkSomeExtensionInRegistry( POWERPOINT_START, POWERPOINT_END ) ) 423 { 424 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "1" ); 425 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for MicroSoft PowerPoint" ); 426 } 427 } 428 } 429 430 MsiSetPropertyA( handle, "FILETYPEDIALOGUSED", "1" ); 431 432 return ERROR_SUCCESS; 433 } 434 435 //---------------------------------------------------------- 436 extern "C" UINT __stdcall RegisterSomeExtensions( MSIHANDLE handle ) 437 { 438 OutputDebugStringFormat( "RegisterSomeExtensions: " ); 439 440 if ( IsSetMsiProp( handle, "SELECT_WORD" ) ) 441 { 442 registerSomeExtensions( handle, WORD_START, EXCEL_START, true ); 443 MsiSetFeatureState( handle, L"gm_p_Wrt_MSO_Reg", INSTALLSTATE_LOCAL ); 444 OutputDebugStringFormat( "RegisterSomeExtensions: Register for MicroSoft Word" ); 445 } 446 else 447 { 448 registerSomeExtensions( handle, WORD_START, EXCEL_START, false ); 449 MsiSetFeatureState( handle, L"gm_p_Wrt_MSO_Reg", INSTALLSTATE_ABSENT ); 450 } 451 452 if ( IsSetMsiProp( handle, "SELECT_EXCEL" ) ) 453 { 454 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, true ); 455 MsiSetFeatureState( handle, L"gm_p_Calc_MSO_Reg", INSTALLSTATE_LOCAL ); 456 OutputDebugStringFormat( "RegisterSomeExtensions: Register for MicroSoft Excel" ); 457 } 458 else 459 { 460 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, false ); 461 MsiSetFeatureState( handle, L"gm_p_Calc_MSO_Reg", INSTALLSTATE_ABSENT ); 462 } 463 464 if ( IsSetMsiProp( handle, "SELECT_POWERPOINT" ) ) 465 { 466 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, true ); 467 MsiSetFeatureState( handle, L"gm_p_Impress_MSO_Reg", INSTALLSTATE_LOCAL ); 468 OutputDebugStringFormat( "RegisterSomeExtensions: Register for MicroSoft PowerPoint" ); 469 } 470 else 471 { 472 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, false ); 473 MsiSetFeatureState( handle, L"gm_p_Impress_MSO_Reg", INSTALLSTATE_ABSENT ); 474 } 475 476 return ERROR_SUCCESS; 477 } 478 479 //---------------------------------------------------------- 480 extern "C" UINT __stdcall FindRegisteredExtensions( MSIHANDLE handle ) 481 { 482 if ( IsSetMsiProp( handle, "FILETYPEDIALOGUSED" ) ) 483 { 484 OutputDebugStringFormat( "FindRegisteredExtensions: FILETYPEDIALOGUSED!" ); 485 return ERROR_SUCCESS; 486 } 487 488 OutputDebugStringFormat( "FindRegisteredExtensions:" ); 489 490 bool bRegisterAll = IsSetMsiProp( handle, "REGISTER_ALL_MSO_TYPES" ); 491 492 if ( IsSetMsiProp( handle, "REGISTER_NO_MSO_TYPES" ) ) 493 { 494 OutputDebugStringFormat( "FindRegisteredExtensions: Register none!" ); 495 return ERROR_SUCCESS; 496 } 497 else if ( bRegisterAll ) 498 OutputDebugStringFormat( "FindRegisteredExtensions: Force all on" ); 499 else 500 OutputDebugStringFormat( "FindRegisteredExtensions: " ); 501 502 // setting the msi properties SELECT_* will force registering for all corresponding 503 // file types 504 if ( IsSetMsiProp( handle, "SELECT_WORD" ) ) 505 registerSomeExtensions( handle, WORD_START, EXCEL_START, true ); 506 if ( IsSetMsiProp( handle, "SELECT_EXCEL" ) ) 507 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, true ); 508 if ( IsSetMsiProp( handle, "SELECT_POWERPOINT" ) ) 509 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, true ); 510 511 registerForExtensions( handle, bRegisterAll ); 512 513 return ERROR_SUCCESS; 514 } 515 516 //---------------------------------------------------------- 517 extern "C" UINT __stdcall DeleteRegisteredExtensions( MSIHANDLE /*handle*/ ) 518 { 519 OutputDebugStringFormat( "DeleteRegisteredExtensions\n" ); 520 521 // remove all file extensions 522 int nIndex = 0; 523 while ( g_Extensions[nIndex] != 0 ) 524 { 525 RemoveExtensionInRegistry( g_Extensions[nIndex] ); 526 ++nIndex; 527 } 528 529 return ERROR_SUCCESS; 530 } 531