summaryrefslogtreecommitdiffstats
path: root/shell/source/win32/shlxthandler/shlxthdl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'shell/source/win32/shlxthandler/shlxthdl.cxx')
-rw-r--r--shell/source/win32/shlxthandler/shlxthdl.cxx409
1 files changed, 409 insertions, 0 deletions
diff --git a/shell/source/win32/shlxthandler/shlxthdl.cxx b/shell/source/win32/shlxthandler/shlxthdl.cxx
new file mode 100644
index 000000000..9a5b8a379
--- /dev/null
+++ b/shell/source/win32/shlxthandler/shlxthdl.cxx
@@ -0,0 +1,409 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <config.hxx>
+#include <global.hxx>
+#include <shlxthdl.hxx>
+#include "classfactory.hxx"
+#include <registry.hxx>
+#include <fileextensions.hxx>
+#include <utilities.hxx>
+
+#include <string>
+#include <shlobj.h>
+
+#include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer
+
+// Module global
+
+LONG g_DllRefCnt = 0;
+HINSTANCE g_hModule = nullptr;
+
+namespace /* private */
+{
+ const wchar_t* const GUID_PLACEHOLDER = L"{GUID}";
+ const wchar_t* const EXTENSION_PLACEHOLDER = L"{EXT}";
+ const wchar_t* const FORWARDKEY_PLACEHOLDER = L"{FWDKEY}";
+
+ const wchar_t* const CLSID_ENTRY = L"CLSID\\{GUID}\\InProcServer32";
+ const wchar_t* const SHELLEX_IID_ENTRY = L"{EXT}\\shellex\\{GUID}";
+ const wchar_t* const SHELLEX_ENTRY = L"{EXT}\\shellex";
+ const wchar_t* const FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1";
+ const wchar_t* const FORWARD_PROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers";
+ const wchar_t* const FORWARD_SHELLEX_ENTRY = L"{FWDKEY}\\shellex";
+
+ const wchar_t* const SHELL_EXTENSION_APPROVED_KEY_NAME = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
+
+
+ // "String Placeholder" ->
+ // "String Replacement"
+
+ void SubstitutePlaceholder(std::wstring& String, const std::wstring& Placeholder, const std::wstring& Replacement)
+ {
+ std::wstring::size_type idx = String.find(Placeholder);
+ std::wstring::size_type len = Placeholder.length();
+
+ while (std::wstring::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 wchar_t* FilePath, const CLSID& Guid)
+ {
+ std::wstring ClsidEntry = CLSID_ENTRY;
+ SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid));
+
+ if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"", FilePath))
+ return E_FAIL;
+
+ if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"ThreadingModel", L"Apartment"))
+ return E_FAIL;
+
+ return S_OK;
+ }
+
+ HRESULT UnregisterComComponent(const CLSID& Guid)
+ {
+ std::wstring tmp = L"CLSID\\";
+ tmp += ClsidToString(Guid);
+ return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
+ }
+
+ HRESULT RegisterColumnHandler(const wchar_t* ModuleFileName)
+ {
+ if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER)))
+ return E_FAIL;
+
+ std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
+ tmp += ClsidToString(CLSID_COLUMN_HANDLER);
+
+ return SetRegistryKey(
+ HKEY_CLASSES_ROOT,
+ tmp.c_str(),
+ L"",
+ COLUMN_HANDLER_DESCRIPTIVE_NAME) ? S_OK : E_FAIL;
+ }
+
+ HRESULT UnregisterColumnHandler()
+ {
+ std::wstring tmp = L"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 wchar_t* ModuleFileName)
+ {
+ if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER)))
+ return E_FAIL;
+
+ std::wstring iid = ClsidToString(IID_IQueryInfo);
+ std::wstring tmp;
+
+ for(size_t i = 0; i < OOFileExtensionTableSize; i++)
+ {
+ tmp = SHELLEX_IID_ENTRY;
+ SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
+ SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
+
+ if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_INFOTIP_HANDLER).c_str()))
+ return E_FAIL;
+ }
+ return S_OK;
+ }
+
+ HRESULT UnregisterInfotipHandler()
+ {
+ std::wstring iid = ClsidToString(IID_IQueryInfo);
+ std::wstring tmp;
+
+ for (size_t i = 0; i < OOFileExtensionTableSize; i++)
+ {
+ tmp = SHELLEX_IID_ENTRY;
+
+ SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
+ 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].ExtensionU);
+
+ 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 wchar_t* ModuleFileName)
+ {
+ std::wstring 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(), L"", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str()))
+ return E_FAIL;
+ }
+ return S_OK;
+ }
+
+ HRESULT UnregisterPropSheetHandler()
+ {
+ std::wstring 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 wchar_t* ModuleFileName)
+ {
+ if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER)))
+ return E_FAIL;
+
+ std::wstring iid = ClsidToString(IID_IExtractImage);
+ std::wstring tmp;
+
+ for(size_t i = 0; i < OOFileExtensionTableSize; i++)
+ {
+ tmp = SHELLEX_IID_ENTRY;
+
+ SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
+ SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
+
+ if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str()))
+ return E_FAIL;
+ }
+ return S_OK;
+ }
+
+ HRESULT UnregisterThumbviewerHandler()
+ {
+ std::wstring iid = ClsidToString(IID_IExtractImage);
+ std::wstring tmp;
+
+ for (size_t i = 0; i < OOFileExtensionTableSize; i++)
+ {
+ tmp = SHELLEX_IID_ENTRY;
+
+ SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
+ 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].ExtensionU);
+
+ 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(const CLSID& clsid, const std::wstring& Description)
+ {
+ bool bRet = SetRegistryKey(
+ HKEY_LOCAL_MACHINE,
+ SHELL_EXTENSION_APPROVED_KEY_NAME,
+ ClsidToString(clsid).c_str(),
+ Description.c_str());
+
+ return bRet ? S_OK : E_FAIL;
+ }
+
+ HRESULT UnapproveShellExtension(const CLSID& Clsid)
+ {
+ HKEY hkey;
+
+ LONG rc = RegOpenKeyW(
+ HKEY_LOCAL_MACHINE,
+ SHELL_EXTENSION_APPROVED_KEY_NAME,
+ &hkey);
+
+ if (ERROR_SUCCESS == rc)
+ {
+ rc = RegDeleteValueW(
+ hkey,
+ ClsidToString(Clsid).c_str());
+
+ rc |= RegCloseKey(hkey);
+ }
+
+ return rc == ERROR_SUCCESS ? S_OK : E_FAIL;
+ }
+
+} // namespace /* private */
+
+
+// COM exports
+
+
+STDAPI DllRegisterServer()
+{
+ WCHAR ModuleFileName[MAX_PATH];
+
+ GetModuleFileNameW(
+ GetCurrentModuleHandle(),
+ ModuleFileName,
+ sizeof(ModuleFileName)/sizeof(ModuleFileName[0]));
+
+ HRESULT hr = S_OK;
+
+ if (SUCCEEDED(RegisterColumnHandler(ModuleFileName)))
+ ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME);
+ else
+ hr = E_FAIL;
+
+ if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName)))
+ ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME);
+ else
+ hr = E_FAIL;
+
+ if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName)))
+ ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME);
+ else
+ hr = E_FAIL;
+
+ if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName)))
+ ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME);
+ else
+ hr = E_FAIL;
+
+ // notify the Shell that something has changed
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
+
+ return hr;
+}
+
+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, nullptr, nullptr);
+
+ return hr;
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+{
+ *ppv = nullptr;
+
+ 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 )
+ OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" );
+ else if ( rclsid == CLSID_COLUMN_HANDLER )
+ OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" );
+ else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER )
+ OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" );
+ else if ( rclsid == CLSID_THUMBVIEWER_HANDLER )
+ OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" );
+
+ IUnknown* pUnk = new CClassFactory(rclsid);
+ *ppv = pUnk;
+ return S_OK;
+}
+
+STDAPI DllCanUnloadNow()
+{
+ 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;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */