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 #ifdef _MSC_VER 29 #pragma warning(push, 1) /* disable warnings within system headers */ 30 #endif 31 #define WIN32_LEAN_AND_MEAN 32 #include <windows.h> 33 #include <msiquery.h> 34 #ifdef _MSC_VER 35 #pragma warning(pop) 36 #endif 37 38 #include <malloc.h> 39 #include <string> 40 #include <strsafe.h> 41 42 //---------------------------------------------------------- 43 static const CHAR* g_Extensions[] = 44 { 45 ".doc", // Microsoft Word Text [0] 46 ".dot", // Microsoft Word Template 47 ".rtf", // rtf text 48 ".docx", // Office Word 2007 XML document 49 ".docm", // Office Word 2007 XML macro-enabled document 50 ".dotx", // Office Word 2007 XML template 51 ".dotm", // Office Word 2007 XML macro-enabled template 52 ".xlw", // Microsoft Excel 53 ".xls", // Microsoft Excel 54 ".xlt", // Microsoft Excel Template 55 ".xlsx", // Office Excel 2007 XML workbook 56 ".xlsm", // Office Excel 2007 XML macro-enabled workbook 57 ".xltx", // Office Excel 2007 XML template 58 ".xltm", // Office Excel 2007 XML macro-enabled template 59 ".xlsb", // Office Excel 2007 binary workbook (BIFF12) 60 ".ppt", // Microsoft Powerpoint 61 ".pps", // Microsoft Powerpoint 62 ".pot", // Microsoft Powerpoint Template 63 ".pptx", // Office PowerPoint 2007 XML presentation 64 ".pptm", // Office PowerPoint 2007 macro-enabled XML presentation 65 ".potx", // Office PowerPoint 2007 XML template 66 ".potm", // Office PowerPoint 2007 macro-enabled XML template 67 ".ppsx", // Office PowerPoint 2007 XML show 68 0 69 }; 70 71 static const int WORD_START = 0; 72 static const int EXCEL_START = 7; 73 static const int POWERPOINT_START = 15; 74 static const int POWERPOINT_END = 23; 75 76 // ".xlam", // Office Excel 2007 XML macro-enabled add-in 77 // ".ppam", // Office PowerPoint 2007 macro-enabled XML add-in 78 // ".ppsm", // Office PowerPoint 2007 macro-enabled XML show 79 80 //---------------------------------------------------------- 81 #ifdef DEBUG 82 inline void OutputDebugStringFormat( LPCSTR pFormat, ... ) 83 { 84 CHAR buffer[1024]; 85 va_list args; 86 87 va_start( args, pFormat ); 88 StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args ); 89 OutputDebugStringA( buffer ); 90 } 91 #else 92 static inline void OutputDebugStringFormat( LPCSTR, ... ) 93 { 94 } 95 #endif 96 97 //---------------------------------------------------------- 98 static BOOL CheckExtensionInRegistry( LPCSTR lpSubKey ) 99 { 100 BOOL bRet = false; 101 HKEY hKey = NULL; 102 LONG lResult = RegOpenKeyExA( HKEY_CLASSES_ROOT, lpSubKey, 0, KEY_QUERY_VALUE, &hKey ); 103 104 if ( ERROR_SUCCESS == lResult ) 105 { 106 CHAR szBuffer[1024]; 107 DWORD nSize = sizeof( szBuffer ); 108 109 lResult = RegQueryValueExA( hKey, "", NULL, NULL, (LPBYTE)szBuffer, &nSize ); 110 if ( ERROR_SUCCESS == lResult ) 111 { 112 szBuffer[nSize] = '\0'; 113 OutputDebugStringFormat( "Found value [%s] for key [%s].\n", szBuffer, lpSubKey ); 114 115 if ( strncmp( szBuffer, "WordPad.Document.1", 18 ) == 0 ) 116 { // We will replace registration for word pad 117 bRet = true; 118 } 119 else if ( strncmp( szBuffer, "OpenOffice.org.", 15 ) == 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