Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / shell / source / win32 / shlxthandler / shlxthdl.cxx
blob24ca14a44c4b6ff6c83cb665b0613e1354881ad5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config.hxx>
21 #include <global.hxx>
22 #include <shlxthdl.hxx>
23 #include "classfactory.hxx"
24 #include <registry.hxx>
25 #include <fileextensions.hxx>
26 #include <utilities.hxx>
28 #include <string>
29 #include <shlobj.h>
31 #include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer
33 // Module global
35 long g_DllRefCnt = 0;
36 HINSTANCE g_hModule = nullptr;
38 namespace /* private */
40 const wchar_t* const GUID_PLACEHOLDER = L"{GUID}";
41 const wchar_t* const EXTENSION_PLACEHOLDER = L"{EXT}";
42 const wchar_t* const FORWARDKEY_PLACEHOLDER = L"{FWDKEY}";
44 const wchar_t* const CLSID_ENTRY = L"CLSID\\{GUID}\\InProcServer32";
45 const wchar_t* const SHELLEX_IID_ENTRY = L"{EXT}\\shellex\\{GUID}";
46 const wchar_t* const SHELLEX_ENTRY = L"{EXT}\\shellex";
47 const wchar_t* const FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1";
48 const wchar_t* const FORWARD_PROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers";
49 const wchar_t* const FORWARD_SHELLEX_ENTRY = L"{FWDKEY}\\shellex";
51 const wchar_t* const SHELL_EXTENSION_APPROVED_KEY_NAME = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
54 // "String Placeholder" ->
55 // "String Replacement"
57 void SubstitutePlaceholder(std::wstring& String, const std::wstring& Placeholder, const std::wstring& Replacement)
59 std::wstring::size_type idx = String.find(Placeholder);
60 std::wstring::size_type len = Placeholder.length();
62 while (std::wstring::npos != idx)
64 String.replace(idx, len, Replacement);
65 idx = String.find(Placeholder);
69 /* Make the registry entry
70 HKCR\CLSID\{GUID}
71 InProcServer32 = Path\shlxthdl.dll
72 ThreadingModel = Apartment
74 HRESULT RegisterComComponent(const wchar_t* FilePath, const CLSID& Guid)
76 std::wstring ClsidEntry = CLSID_ENTRY;
77 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid));
79 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"", FilePath))
80 return E_FAIL;
82 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"ThreadingModel", L"Apartment"))
83 return E_FAIL;
85 return S_OK;
88 HRESULT UnregisterComComponent(const CLSID& Guid)
90 std::wstring tmp = L"CLSID\\";
91 tmp += ClsidToString(Guid);
92 return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
95 HRESULT RegisterColumnHandler(const wchar_t* ModuleFileName)
97 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER)))
98 return E_FAIL;
100 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
101 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
103 return SetRegistryKey(
104 HKEY_CLASSES_ROOT,
105 tmp.c_str(),
106 L"",
107 COLUMN_HANDLER_DESCRIPTIVE_NAME) ? S_OK : E_FAIL;
110 HRESULT UnregisterColumnHandler()
112 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
113 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
115 if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()))
116 return E_FAIL;
118 return UnregisterComComponent(CLSID_COLUMN_HANDLER);
121 HRESULT RegisterInfotipHandler(const wchar_t* ModuleFileName)
123 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER)))
124 return E_FAIL;
126 std::wstring iid = ClsidToString(IID_IQueryInfo);
127 std::wstring tmp;
129 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
131 tmp = SHELLEX_IID_ENTRY;
132 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
133 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
135 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_INFOTIP_HANDLER).c_str()))
136 return E_FAIL;
138 return S_OK;
141 HRESULT UnregisterInfotipHandler()
143 std::wstring iid = ClsidToString(IID_IQueryInfo);
144 std::wstring tmp;
146 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
148 tmp = SHELLEX_IID_ENTRY;
150 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
151 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
153 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
155 // if there are no further subkey below .ext\\shellex
156 // delete the whole subkey
157 tmp = SHELLEX_ENTRY;
158 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
160 bool HasSubKeys = true;
161 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
162 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
164 return UnregisterComComponent(CLSID_INFOTIP_HANDLER);
167 HRESULT RegisterPropSheetHandler(const wchar_t* ModuleFileName)
169 std::wstring FwdKeyEntry;
171 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER)))
172 return E_FAIL;
174 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
176 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
177 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
179 if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), L"", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str()))
180 return E_FAIL;
182 return S_OK;
185 HRESULT UnregisterPropSheetHandler()
187 std::wstring FwdKeyEntry;
189 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
191 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
192 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
194 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
196 FwdKeyEntry = FORWARD_PROPSHEET_ENTRY;
197 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
199 bool HasSubKeys = true;
200 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
201 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
203 FwdKeyEntry = FORWARD_SHELLEX_ENTRY;
204 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
206 HasSubKeys = true;
207 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
208 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
211 return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER);
214 HRESULT RegisterThumbviewerHandler(const wchar_t* ModuleFileName)
216 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER)))
217 return E_FAIL;
219 std::wstring iid = ClsidToString(IID_IExtractImage);
220 std::wstring tmp;
222 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
224 tmp = SHELLEX_IID_ENTRY;
226 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
227 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
229 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str()))
230 return E_FAIL;
232 return S_OK;
235 HRESULT UnregisterThumbviewerHandler()
237 std::wstring iid = ClsidToString(IID_IExtractImage);
238 std::wstring tmp;
240 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
242 tmp = SHELLEX_IID_ENTRY;
244 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
245 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
247 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
249 // if there are no further subkey below .ext\\shellex
250 // delete the whole subkey
251 tmp = SHELLEX_ENTRY;
252 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
254 bool HasSubKeys = true;
255 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
256 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
258 return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER);
261 /** Approving/Unapproving the Shell Extension, it's important under Windows
262 NT/2000/XP, see MSDN: Creating Shell Extension Handlers */
263 HRESULT ApproveShellExtension(const CLSID& clsid, const std::wstring& Description)
265 bool bRet = SetRegistryKey(
266 HKEY_LOCAL_MACHINE,
267 SHELL_EXTENSION_APPROVED_KEY_NAME,
268 ClsidToString(clsid).c_str(),
269 Description.c_str());
271 return bRet ? S_OK : E_FAIL;
274 HRESULT UnapproveShellExtension(const CLSID& Clsid)
276 HKEY hkey;
278 LONG rc = RegOpenKeyW(
279 HKEY_LOCAL_MACHINE,
280 SHELL_EXTENSION_APPROVED_KEY_NAME,
281 &hkey);
283 if (ERROR_SUCCESS == rc)
285 rc = RegDeleteValueW(
286 hkey,
287 ClsidToString(Clsid).c_str());
289 rc |= RegCloseKey(hkey);
292 return rc == ERROR_SUCCESS ? S_OK : E_FAIL;
295 } // namespace /* private */
298 // COM exports
301 STDAPI DllRegisterServer()
303 WCHAR ModuleFileName[MAX_PATH];
305 GetModuleFileNameW(
306 GetModuleHandleW(MODULE_NAME),
307 ModuleFileName,
308 sizeof(ModuleFileName)/sizeof(ModuleFileName[0]));
310 HRESULT hr = S_OK;
312 if (SUCCEEDED(RegisterColumnHandler(ModuleFileName)))
313 ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME);
314 else
315 hr = E_FAIL;
317 if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName)))
318 ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME);
319 else
320 hr = E_FAIL;
322 if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName)))
323 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME);
324 else
325 hr = E_FAIL;
327 if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName)))
328 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME);
329 else
330 hr = E_FAIL;
332 // notify the Shell that something has changed
333 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
335 return hr;
338 STDAPI DllUnregisterServer()
340 HRESULT hr = S_OK;
342 if (FAILED(UnregisterColumnHandler()))
343 hr = E_FAIL;
345 UnapproveShellExtension(CLSID_COLUMN_HANDLER);
347 if (FAILED(UnregisterInfotipHandler()))
348 hr = E_FAIL;
350 UnapproveShellExtension(CLSID_INFOTIP_HANDLER);
352 if (FAILED(UnregisterPropSheetHandler()))
353 hr = E_FAIL;
355 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER);
357 if (FAILED(UnregisterThumbviewerHandler()))
358 hr = E_FAIL;
360 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER);
362 // notify the Shell that something has changed
363 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
365 return hr;
368 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
370 *ppv = nullptr;
372 if ((rclsid != CLSID_INFOTIP_HANDLER) &&
373 (rclsid != CLSID_COLUMN_HANDLER) &&
374 (rclsid != CLSID_PROPERTYSHEET_HANDLER) &&
375 (rclsid != CLSID_THUMBVIEWER_HANDLER))
376 return CLASS_E_CLASSNOTAVAILABLE;
378 if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
379 return E_NOINTERFACE;
381 if ( rclsid == CLSID_INFOTIP_HANDLER )
382 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" );
383 else if ( rclsid == CLSID_COLUMN_HANDLER )
384 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" );
385 else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER )
386 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" );
387 else if ( rclsid == CLSID_THUMBVIEWER_HANDLER )
388 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" );
390 IUnknown* pUnk = new CClassFactory(rclsid);
391 *ppv = pUnk;
392 return S_OK;
395 STDAPI DllCanUnloadNow()
397 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
398 return S_FALSE;
400 return S_OK;
403 BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/)
405 g_hModule = hInst;
406 return TRUE;
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */