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