| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_shell.hxx" |
| #include "internal/config.hxx" |
| #include "internal/global.hxx" |
| #include "internal/shlxthdl.hxx" |
| #include "classfactory.hxx" |
| #include "internal/registry.hxx" |
| #include "internal/fileextensions.hxx" |
| #include "internal/utilities.hxx" |
| |
| #include <tchar.h> |
| #include <string> |
| #include <shlobj.h> |
| |
| //--------------------------- |
| // Module global |
| //--------------------------- |
| long g_DllRefCnt = 0; |
| HINSTANCE g_hModule = NULL; |
| |
| namespace /* private */ |
| { |
| const char* GUID_PLACEHOLDER = "{GUID}"; |
| const char* EXTENSION_PLACEHOLDER = "{EXT}"; |
| const char* FORWARDKEY_PLACEHOLDER = "{FWDKEY}"; |
| |
| const char* CLSID_ENTRY = "CLSID\\{GUID}\\InProcServer32"; |
| const char* SHELLEX_IID_ENTRY = "{EXT}\\shellex\\{GUID}"; |
| const char* SHELLEX_ENTRY = "{EXT}\\shellex"; |
| const char* PROPSHEET_ENTRY = "{EXT}\\CLSID\\{GUID}\\InProcServer32"; |
| const char* EXTENSION_CLSID = "{EXT}\\CLSID"; |
| const char* EXTENSION_CLSID_GUID = "{EXT}\\CLSID\\{GUID}"; |
| const char* FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1"; |
| const char* FORWARD_PROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers"; |
| const char* FORWARD_SHELLEX_ENTRY = "{FWDKEY}\\shellex"; |
| |
| const char* SHELL_EXTENSION_APPROVED_KEY_NAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; |
| |
| //--------------------------- |
| // "String Placeholder" -> |
| // "String Replacement" |
| //--------------------------- |
| void SubstitutePlaceholder(std::string& String, const std::string& Placeholder, const std::string& Replacement) |
| { |
| std::string::size_type idx = String.find(Placeholder); |
| std::string::size_type len = Placeholder.length(); |
| |
| while (std::string::npos != idx) |
| { |
| String.replace(idx, len, Replacement); |
| idx = String.find(Placeholder); |
| } |
| } |
| |
| /* Make the registry entry |
| HKCR\CLSID\{GUID} |
| InProcServer32 = Path\shlxthdl.dll |
| ThreadingModel = Apartment |
| */ |
| HRESULT RegisterComComponent(const char* FilePath, const CLSID& Guid) |
| { |
| std::string ClsidEntry = CLSID_ENTRY; |
| SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid)); |
| |
| if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath)) |
| return E_FAIL; |
| |
| if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Apartment")) |
| return E_FAIL; |
| |
| return S_OK; |
| } |
| |
| HRESULT UnregisterComComponent(const CLSID& Guid) |
| { |
| std::string tmp = "CLSID\\"; |
| tmp += ClsidToString(Guid); |
| return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL; |
| } |
| |
| HRESULT RegisterColumnHandler(const char* ModuleFileName) |
| { |
| if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER))) |
| return E_FAIL; |
| |
| std::string tmp = "Folder\\shellex\\ColumnHandlers\\"; |
| tmp += ClsidToString(CLSID_COLUMN_HANDLER); |
| |
| return SetRegistryKey( |
| HKEY_CLASSES_ROOT, |
| tmp.c_str(), |
| "", |
| WStringToString(COLUMN_HANDLER_DESCRIPTIVE_NAME).c_str()) ? S_OK : E_FAIL; |
| } |
| |
| HRESULT UnregisterColumnHandler() |
| { |
| std::string tmp = "Folder\\shellex\\ColumnHandlers\\"; |
| tmp += ClsidToString(CLSID_COLUMN_HANDLER); |
| |
| if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str())) |
| return E_FAIL; |
| |
| return UnregisterComComponent(CLSID_COLUMN_HANDLER); |
| } |
| |
| HRESULT RegisterInfotipHandler(const char* ModuleFileName) |
| { |
| if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER))) |
| return E_FAIL; |
| |
| std::string iid = ClsidToString(IID_IQueryInfo); |
| std::string tmp; |
| |
| for(size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| tmp = SHELLEX_IID_ENTRY; |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); |
| |
| if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_INFOTIP_HANDLER).c_str())) |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| |
| HRESULT UnregisterInfotipHandler() |
| { |
| std::string iid = ClsidToString(IID_IQueryInfo); |
| std::string tmp; |
| |
| for (size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| tmp = SHELLEX_IID_ENTRY; |
| |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); |
| |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); |
| |
| // if there are no further subkey below .ext\\shellex |
| // delete the whole subkey |
| tmp = SHELLEX_ENTRY; |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| |
| bool HasSubKeys = true; |
| if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); |
| } |
| return UnregisterComComponent(CLSID_INFOTIP_HANDLER); |
| } |
| |
| HRESULT RegisterPropSheetHandler(const char* ModuleFileName) |
| { |
| std::string ExtEntry; |
| std::string FwdKeyEntry; |
| |
| if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER))) |
| return E_FAIL; |
| |
| for (size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; |
| SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); |
| |
| if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), "", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str())) |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| |
| HRESULT UnregisterPropSheetHandler() |
| { |
| std::string ExtEntry; |
| std::string FwdKeyEntry; |
| |
| for (size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; |
| SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); |
| |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); |
| |
| FwdKeyEntry = FORWARD_PROPSHEET_ENTRY; |
| SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); |
| |
| bool HasSubKeys = true; |
| if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); |
| |
| FwdKeyEntry = FORWARD_SHELLEX_ENTRY; |
| SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); |
| |
| HasSubKeys = true; |
| if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); |
| } |
| |
| return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER); |
| } |
| |
| HRESULT RegisterThumbviewerHandler(const char* ModuleFileName) |
| { |
| if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER))) |
| return E_FAIL; |
| |
| std::string iid = ClsidToString(IID_IExtractImage); |
| std::string tmp; |
| |
| for(size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| tmp = SHELLEX_IID_ENTRY; |
| |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); |
| |
| if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str())) |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| |
| HRESULT UnregisterThumbviewerHandler() |
| { |
| std::string iid = ClsidToString(IID_IExtractImage); |
| std::string tmp; |
| |
| for (size_t i = 0; i < OOFileExtensionTableSize; i++) |
| { |
| tmp = SHELLEX_IID_ENTRY; |
| |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); |
| |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); |
| |
| // if there are no further subkey below .ext\\shellex |
| // delete the whole subkey |
| tmp = SHELLEX_ENTRY; |
| SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi); |
| |
| bool HasSubKeys = true; |
| if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) |
| DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); |
| } |
| return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER); |
| } |
| |
| /** Approving/Unapproving the Shell Extension, it's important under Windows |
| NT/2000/XP, see MSDN: Creating Shell Extension Handlers */ |
| HRESULT ApproveShellExtension(CLSID clsid, const std::wstring& Description) |
| { |
| bool bRet = SetRegistryKey( |
| HKEY_LOCAL_MACHINE, |
| SHELL_EXTENSION_APPROVED_KEY_NAME, |
| ClsidToString(clsid).c_str(), |
| WStringToString(Description).c_str()); |
| |
| return bRet ? S_OK : E_FAIL; |
| } |
| |
| HRESULT UnapproveShellExtension(CLSID Clsid) |
| { |
| HKEY hkey; |
| |
| LONG rc = RegOpenKeyA( |
| HKEY_LOCAL_MACHINE, |
| SHELL_EXTENSION_APPROVED_KEY_NAME, |
| &hkey); |
| |
| if (ERROR_SUCCESS == rc) |
| { |
| rc = RegDeleteValueA( |
| hkey, |
| ClsidToString(Clsid).c_str()); |
| |
| rc = RegCloseKey(hkey); |
| } |
| |
| return rc == ERROR_SUCCESS ? S_OK : E_FAIL; |
| } |
| |
| } // namespace /* private */ |
| |
| |
| //--------------------- |
| // COM exports |
| //--------------------- |
| |
| extern "C" STDAPI DllRegisterServer() |
| { |
| TCHAR ModuleFileName[MAX_PATH]; |
| |
| GetModuleFileName( |
| GetModuleHandle(MODULE_NAME), |
| ModuleFileName, |
| sizeof(ModuleFileName)); |
| |
| std::string module_path = WStringToString(ModuleFileName); |
| HRESULT hr = S_OK; |
| |
| if (SUCCEEDED(RegisterColumnHandler(module_path.c_str()))) |
| ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME); |
| else |
| hr = E_FAIL; |
| |
| if (SUCCEEDED(RegisterInfotipHandler(module_path.c_str()))) |
| ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME); |
| else |
| hr = E_FAIL; |
| |
| if (SUCCEEDED(RegisterPropSheetHandler(module_path.c_str()))) |
| ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME); |
| else |
| hr = E_FAIL; |
| |
| if (SUCCEEDED(RegisterThumbviewerHandler(module_path.c_str()))) |
| ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVAE_NAME); |
| else |
| hr = E_FAIL; |
| |
| // notify the Shell that something has changed |
| SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); |
| |
| return hr; |
| } |
| |
| extern "C" STDAPI DllUnregisterServer() |
| { |
| HRESULT hr = S_OK; |
| |
| if (FAILED(UnregisterColumnHandler())) |
| hr = E_FAIL; |
| |
| UnapproveShellExtension(CLSID_COLUMN_HANDLER); |
| |
| if (FAILED(UnregisterInfotipHandler())) |
| hr = E_FAIL; |
| |
| UnapproveShellExtension(CLSID_INFOTIP_HANDLER); |
| |
| if (FAILED(UnregisterPropSheetHandler())) |
| hr = E_FAIL; |
| |
| UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER); |
| |
| if (FAILED(UnregisterThumbviewerHandler())) |
| hr = E_FAIL; |
| |
| UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER); |
| |
| // notify the Shell that something has changed |
| SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); |
| |
| return hr; |
| } |
| |
| extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) |
| { |
| *ppv = 0; |
| |
| if ((rclsid != CLSID_INFOTIP_HANDLER) && |
| (rclsid != CLSID_COLUMN_HANDLER) && |
| (rclsid != CLSID_PROPERTYSHEET_HANDLER) && |
| (rclsid != CLSID_THUMBVIEWER_HANDLER)) |
| return CLASS_E_CLASSNOTAVAILABLE; |
| |
| if ((riid != IID_IUnknown) && (riid != IID_IClassFactory)) |
| return E_NOINTERFACE; |
| |
| if ( rclsid == CLSID_INFOTIP_HANDLER ) |
| OutputDebugStringFormat( "DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" ); |
| else if ( rclsid == CLSID_COLUMN_HANDLER ) |
| OutputDebugStringFormat( "DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" ); |
| else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER ) |
| OutputDebugStringFormat( "DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" ); |
| else if ( rclsid == CLSID_THUMBVIEWER_HANDLER ) |
| OutputDebugStringFormat( "DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" ); |
| |
| IUnknown* pUnk = new CClassFactory(rclsid); |
| if (0 == pUnk) |
| return E_OUTOFMEMORY; |
| |
| *ppv = pUnk; |
| return S_OK; |
| } |
| |
| extern "C" STDAPI DllCanUnloadNow(void) |
| { |
| if (CClassFactory::IsLocked() || g_DllRefCnt > 0) |
| return S_FALSE; |
| |
| return S_OK; |
| } |
| |
| BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/) |
| { |
| g_hModule = hInst; |
| return TRUE; |
| } |