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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_shell.hxx" 30 #include "internal/config.hxx" 31 #include "internal/global.hxx" 32 #include "internal/shlxthdl.hxx" 33 #include "classfactory.hxx" 34 #include "internal/registry.hxx" 35 #include "internal/fileextensions.hxx" 36 #include "internal/utilities.hxx" 37 38 #include <tchar.h> 39 #include <string> 40 #include <shlobj.h> 41 42 //--------------------------- 43 // Module global 44 //--------------------------- 45 long g_DllRefCnt = 0; 46 HINSTANCE g_hModule = NULL; 47 48 namespace /* private */ 49 { 50 const char* GUID_PLACEHOLDER = "{GUID}"; 51 const char* EXTENSION_PLACEHOLDER = "{EXT}"; 52 const char* FORWARDKEY_PLACEHOLDER = "{FWDKEY}"; 53 54 const char* CLSID_ENTRY = "CLSID\\{GUID}\\InProcServer32"; 55 const char* SHELLEX_IID_ENTRY = "{EXT}\\shellex\\{GUID}"; 56 const char* SHELLEX_ENTRY = "{EXT}\\shellex"; 57 const char* PROPSHEET_ENTRY = "{EXT}\\CLSID\\{GUID}\\InProcServer32"; 58 const char* EXTENSION_CLSID = "{EXT}\\CLSID"; 59 const char* EXTENSION_CLSID_GUID = "{EXT}\\CLSID\\{GUID}"; 60 const char* FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1"; 61 const char* FORWARD_PROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers"; 62 const char* FORWARD_SHELLEX_ENTRY = "{FWDKEY}\\shellex"; 63 64 const char* SHELL_EXTENSION_APPROVED_KEY_NAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; 65 66 //--------------------------- 67 // "String Placeholder" -> 68 // "String Replacement" 69 //--------------------------- 70 void SubstitutePlaceholder(std::string& String, const std::string& Placeholder, const std::string& Replacement) 71 { 72 std::string::size_type idx = String.find(Placeholder); 73 std::string::size_type len = Placeholder.length(); 74 75 while (std::string::npos != idx) 76 { 77 String.replace(idx, len, Replacement); 78 idx = String.find(Placeholder); 79 } 80 } 81 82 /* Make the registry entry 83 HKCR\CLSID\{GUID} 84 InProcServer32 = Path\shlxthdl.dll 85 ThreadingModel = Apartment 86 */ 87 HRESULT RegisterComComponent(const char* FilePath, const CLSID& Guid) 88 { 89 std::string ClsidEntry = CLSID_ENTRY; 90 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid)); 91 92 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath)) 93 return E_FAIL; 94 95 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Apartment")) 96 return E_FAIL; 97 98 return S_OK; 99 } 100 101 HRESULT UnregisterComComponent(const CLSID& Guid) 102 { 103 std::string tmp = "CLSID\\"; 104 tmp += ClsidToString(Guid); 105 return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL; 106 } 107 108 HRESULT RegisterColumnHandler(const char* ModuleFileName) 109 { 110 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER))) 111 return E_FAIL; 112 113 std::string tmp = "Folder\\shellex\\ColumnHandlers\\"; 114 tmp += ClsidToString(CLSID_COLUMN_HANDLER); 115 116 return SetRegistryKey( 117 HKEY_CLASSES_ROOT, 118 tmp.c_str(), 119 "", 120 WStringToString(COLUMN_HANDLER_DESCRIPTIVE_NAME).c_str()) ? S_OK : E_FAIL; 121 } 122 123 HRESULT UnregisterColumnHandler() 124 { 125 std::string tmp = "Folder\\shellex\\ColumnHandlers\\"; 126 tmp += ClsidToString(CLSID_COLUMN_HANDLER); 127 128 if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str())) 129 return E_FAIL; 130 131 return UnregisterComComponent(CLSID_COLUMN_HANDLER); 132 } 133 134 HRESULT RegisterInfotipHandler(const char* ModuleFileName) 135 { 136 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER))) 137 return E_FAIL; 138 139 std::string iid = ClsidToString(IID_IQueryInfo); 140 std::string tmp; 141 142 for(size_t i = 0; i < OOFileExtensionTableSize; i++) 143 { 144 tmp = SHELLEX_IID_ENTRY; 145 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 146 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); 147 148 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_INFOTIP_HANDLER).c_str())) 149 return E_FAIL; 150 } 151 return S_OK; 152 } 153 154 HRESULT UnregisterInfotipHandler() 155 { 156 std::string iid = ClsidToString(IID_IQueryInfo); 157 std::string tmp; 158 159 for (size_t i = 0; i < OOFileExtensionTableSize; i++) 160 { 161 tmp = SHELLEX_IID_ENTRY; 162 163 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 164 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); 165 166 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); 167 168 // if there are no further subkey below .ext\\shellex 169 // delete the whole subkey 170 tmp = SHELLEX_ENTRY; 171 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 172 173 bool HasSubKeys = true; 174 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) 175 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); 176 } 177 return UnregisterComComponent(CLSID_INFOTIP_HANDLER); 178 } 179 180 HRESULT RegisterPropSheetHandler(const char* ModuleFileName) 181 { 182 std::string ExtEntry; 183 std::string FwdKeyEntry; 184 185 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER))) 186 return E_FAIL; 187 188 for (size_t i = 0; i < OOFileExtensionTableSize; i++) 189 { 190 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; 191 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); 192 193 if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), "", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str())) 194 return E_FAIL; 195 } 196 return S_OK; 197 } 198 199 HRESULT UnregisterPropSheetHandler() 200 { 201 std::string ExtEntry; 202 std::string FwdKeyEntry; 203 204 for (size_t i = 0; i < OOFileExtensionTableSize; i++) 205 { 206 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; 207 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); 208 209 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); 210 211 FwdKeyEntry = FORWARD_PROPSHEET_ENTRY; 212 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); 213 214 bool HasSubKeys = true; 215 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) 216 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); 217 218 FwdKeyEntry = FORWARD_SHELLEX_ENTRY; 219 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); 220 221 HasSubKeys = true; 222 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) 223 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); 224 } 225 226 return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER); 227 } 228 229 HRESULT RegisterThumbviewerHandler(const char* ModuleFileName) 230 { 231 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER))) 232 return E_FAIL; 233 234 std::string iid = ClsidToString(IID_IExtractImage); 235 std::string tmp; 236 237 for(size_t i = 0; i < OOFileExtensionTableSize; i++) 238 { 239 tmp = SHELLEX_IID_ENTRY; 240 241 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 242 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); 243 244 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str())) 245 return E_FAIL; 246 } 247 return S_OK; 248 } 249 250 HRESULT UnregisterThumbviewerHandler() 251 { 252 std::string iid = ClsidToString(IID_IExtractImage); 253 std::string tmp; 254 255 for (size_t i = 0; i < OOFileExtensionTableSize; i++) 256 { 257 tmp = SHELLEX_IID_ENTRY; 258 259 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 260 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); 261 262 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); 263 264 // if there are no further subkey below .ext\\shellex 265 // delete the whole subkey 266 tmp = SHELLEX_ENTRY; 267 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); 268 269 bool HasSubKeys = true; 270 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) 271 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); 272 } 273 return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER); 274 } 275 276 /** Approving/Unapproving the Shell Extension, it's important under Windows 277 NT/2000/XP, see MSDN: Creating Shell Extension Handlers */ 278 HRESULT ApproveShellExtension(CLSID clsid, const std::wstring& Description) 279 { 280 bool bRet = SetRegistryKey( 281 HKEY_LOCAL_MACHINE, 282 SHELL_EXTENSION_APPROVED_KEY_NAME, 283 ClsidToString(clsid).c_str(), 284 WStringToString(Description).c_str()); 285 286 return bRet ? S_OK : E_FAIL; 287 } 288 289 HRESULT UnapproveShellExtension(CLSID Clsid) 290 { 291 HKEY hkey; 292 293 LONG rc = RegOpenKeyA( 294 HKEY_LOCAL_MACHINE, 295 SHELL_EXTENSION_APPROVED_KEY_NAME, 296 &hkey); 297 298 if (ERROR_SUCCESS == rc) 299 { 300 rc = RegDeleteValueA( 301 hkey, 302 ClsidToString(Clsid).c_str()); 303 304 rc = RegCloseKey(hkey); 305 } 306 307 return rc == ERROR_SUCCESS ? S_OK : E_FAIL; 308 } 309 310 } // namespace /* private */ 311 312 313 //--------------------- 314 // COM exports 315 //--------------------- 316 317 extern "C" STDAPI DllRegisterServer() 318 { 319 TCHAR ModuleFileName[MAX_PATH]; 320 321 GetModuleFileName( 322 GetModuleHandle(MODULE_NAME), 323 ModuleFileName, 324 sizeof(ModuleFileName)); 325 326 std::string module_path = WStringToString(ModuleFileName); 327 HRESULT hr = S_OK; 328 329 if (SUCCEEDED(RegisterColumnHandler(module_path.c_str()))) 330 ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME); 331 else 332 hr = E_FAIL; 333 334 if (SUCCEEDED(RegisterInfotipHandler(module_path.c_str()))) 335 ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME); 336 else 337 hr = E_FAIL; 338 339 if (SUCCEEDED(RegisterPropSheetHandler(module_path.c_str()))) 340 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME); 341 else 342 hr = E_FAIL; 343 344 if (SUCCEEDED(RegisterThumbviewerHandler(module_path.c_str()))) 345 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVAE_NAME); 346 else 347 hr = E_FAIL; 348 349 // notify the Shell that something has changed 350 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); 351 352 return hr; 353 } 354 355 extern "C" STDAPI DllUnregisterServer() 356 { 357 HRESULT hr = S_OK; 358 359 if (FAILED(UnregisterColumnHandler())) 360 hr = E_FAIL; 361 362 UnapproveShellExtension(CLSID_COLUMN_HANDLER); 363 364 if (FAILED(UnregisterInfotipHandler())) 365 hr = E_FAIL; 366 367 UnapproveShellExtension(CLSID_INFOTIP_HANDLER); 368 369 if (FAILED(UnregisterPropSheetHandler())) 370 hr = E_FAIL; 371 372 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER); 373 374 if (FAILED(UnregisterThumbviewerHandler())) 375 hr = E_FAIL; 376 377 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER); 378 379 // notify the Shell that something has changed 380 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); 381 382 return hr; 383 } 384 385 extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) 386 { 387 *ppv = 0; 388 389 if ((rclsid != CLSID_INFOTIP_HANDLER) && 390 (rclsid != CLSID_COLUMN_HANDLER) && 391 (rclsid != CLSID_PROPERTYSHEET_HANDLER) && 392 (rclsid != CLSID_THUMBVIEWER_HANDLER)) 393 return CLASS_E_CLASSNOTAVAILABLE; 394 395 if ((riid != IID_IUnknown) && (riid != IID_IClassFactory)) 396 return E_NOINTERFACE; 397 398 if ( rclsid == CLSID_INFOTIP_HANDLER ) 399 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" ); 400 else if ( rclsid == CLSID_COLUMN_HANDLER ) 401 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" ); 402 else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER ) 403 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" ); 404 else if ( rclsid == CLSID_THUMBVIEWER_HANDLER ) 405 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" ); 406 407 IUnknown* pUnk = new CClassFactory(rclsid); 408 if (0 == pUnk) 409 return E_OUTOFMEMORY; 410 411 *ppv = pUnk; 412 return S_OK; 413 } 414 415 extern "C" STDAPI DllCanUnloadNow(void) 416 { 417 if (CClassFactory::IsLocked() || g_DllRefCnt > 0) 418 return S_FALSE; 419 420 return S_OK; 421 } 422 423 BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/) 424 { 425 g_hModule = hInst; 426 return TRUE; 427 } 428