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