Bump version to 5.0-14
[LibreOffice.git] / shell / source / win32 / shlxthandler / shlxthdl.cxx
blobfb6c1f44af42dee011922fd2a36daba051dc7591
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 "internal/config.hxx"
21 #include "internal/global.hxx"
22 #include "internal/shlxthdl.hxx"
23 #include "classfactory.hxx"
24 #include "internal/registry.hxx"
25 #include "internal/fileextensions.hxx"
26 #include "internal/utilities.hxx"
28 #include <tchar.h>
29 #include <string>
30 #include <shlobj.h>
33 // Module global
35 long g_DllRefCnt = 0;
36 HINSTANCE g_hModule = NULL;
38 namespace /* private */
40 const char* GUID_PLACEHOLDER = "{GUID}";
41 const char* EXTENSION_PLACEHOLDER = "{EXT}";
42 const char* FORWARDKEY_PLACEHOLDER = "{FWDKEY}";
44 const char* CLSID_ENTRY = "CLSID\\{GUID}\\InProcServer32";
45 const char* SHELLEX_IID_ENTRY = "{EXT}\\shellex\\{GUID}";
46 const char* SHELLEX_ENTRY = "{EXT}\\shellex";
47 const char* PROPSHEET_ENTRY = "{EXT}\\CLSID\\{GUID}\\InProcServer32";
48 const char* EXTENSION_CLSID = "{EXT}\\CLSID";
49 const char* EXTENSION_CLSID_GUID = "{EXT}\\CLSID\\{GUID}";
50 const char* FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1";
51 const char* FORWARD_PROPSHEET_ENTRY = "{FWDKEY}\\shellex\\PropertySheetHandlers";
52 const char* FORWARD_SHELLEX_ENTRY = "{FWDKEY}\\shellex";
54 const char* SHELL_EXTENSION_APPROVED_KEY_NAME = "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
57 // "String Placeholder" ->
58 // "String Replacement"
60 void SubstitutePlaceholder(std::string& String, const std::string& Placeholder, const std::string& Replacement)
62 std::string::size_type idx = String.find(Placeholder);
63 std::string::size_type len = Placeholder.length();
65 while (std::string::npos != idx)
67 String.replace(idx, len, Replacement);
68 idx = String.find(Placeholder);
72 /* Make the registry entry
73 HKCR\CLSID\{GUID}
74 InProcServer32 = Path\shlxthdl.dll
75 ThreadingModel = Apartment
77 HRESULT RegisterComComponent(const char* FilePath, const CLSID& Guid)
79 std::string ClsidEntry = CLSID_ENTRY;
80 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid));
82 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath))
83 return E_FAIL;
85 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Apartment"))
86 return E_FAIL;
88 return S_OK;
91 HRESULT UnregisterComComponent(const CLSID& Guid)
93 std::string tmp = "CLSID\\";
94 tmp += ClsidToString(Guid);
95 return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
98 HRESULT RegisterColumnHandler(const char* ModuleFileName)
100 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER)))
101 return E_FAIL;
103 std::string tmp = "Folder\\shellex\\ColumnHandlers\\";
104 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
106 return SetRegistryKey(
107 HKEY_CLASSES_ROOT,
108 tmp.c_str(),
110 WStringToString(COLUMN_HANDLER_DESCRIPTIVE_NAME).c_str()) ? S_OK : E_FAIL;
113 HRESULT UnregisterColumnHandler()
115 std::string tmp = "Folder\\shellex\\ColumnHandlers\\";
116 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
118 if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()))
119 return E_FAIL;
121 return UnregisterComComponent(CLSID_COLUMN_HANDLER);
124 HRESULT RegisterInfotipHandler(const char* ModuleFileName)
126 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER)))
127 return E_FAIL;
129 std::string iid = ClsidToString(IID_IQueryInfo);
130 std::string tmp;
132 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
134 tmp = SHELLEX_IID_ENTRY;
135 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
136 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
138 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_INFOTIP_HANDLER).c_str()))
139 return E_FAIL;
141 return S_OK;
144 HRESULT UnregisterInfotipHandler()
146 std::string iid = ClsidToString(IID_IQueryInfo);
147 std::string tmp;
149 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
151 tmp = SHELLEX_IID_ENTRY;
153 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
154 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
156 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
158 // if there are no further subkey below .ext\\shellex
159 // delete the whole subkey
160 tmp = SHELLEX_ENTRY;
161 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
163 bool HasSubKeys = true;
164 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
165 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
167 return UnregisterComComponent(CLSID_INFOTIP_HANDLER);
170 HRESULT RegisterPropSheetHandler(const char* ModuleFileName)
172 std::string FwdKeyEntry;
174 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER)))
175 return E_FAIL;
177 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
179 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
180 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
182 if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), "", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str()))
183 return E_FAIL;
185 return S_OK;
188 HRESULT UnregisterPropSheetHandler()
190 std::string FwdKeyEntry;
192 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
194 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
195 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
197 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
199 FwdKeyEntry = FORWARD_PROPSHEET_ENTRY;
200 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
202 bool HasSubKeys = true;
203 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
204 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
206 FwdKeyEntry = FORWARD_SHELLEX_ENTRY;
207 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
209 HasSubKeys = true;
210 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
211 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
214 return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER);
217 HRESULT RegisterThumbviewerHandler(const char* ModuleFileName)
219 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER)))
220 return E_FAIL;
222 std::string iid = ClsidToString(IID_IExtractImage);
223 std::string tmp;
225 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
227 tmp = SHELLEX_IID_ENTRY;
229 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
230 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
232 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), "", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str()))
233 return E_FAIL;
235 return S_OK;
238 HRESULT UnregisterThumbviewerHandler()
240 std::string iid = ClsidToString(IID_IExtractImage);
241 std::string tmp;
243 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
245 tmp = SHELLEX_IID_ENTRY;
247 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
248 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
250 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
252 // if there are no further subkey below .ext\\shellex
253 // delete the whole subkey
254 tmp = SHELLEX_ENTRY;
255 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
257 bool HasSubKeys = true;
258 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
259 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
261 return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER);
264 /** Approving/Unapproving the Shell Extension, it's important under Windows
265 NT/2000/XP, see MSDN: Creating Shell Extension Handlers */
266 HRESULT ApproveShellExtension(const CLSID& clsid, const std::wstring& Description)
268 bool bRet = SetRegistryKey(
269 HKEY_LOCAL_MACHINE,
270 SHELL_EXTENSION_APPROVED_KEY_NAME,
271 ClsidToString(clsid).c_str(),
272 WStringToString(Description).c_str());
274 return bRet ? S_OK : E_FAIL;
277 HRESULT UnapproveShellExtension(const CLSID& Clsid)
279 HKEY hkey;
281 LONG rc = RegOpenKeyA(
282 HKEY_LOCAL_MACHINE,
283 SHELL_EXTENSION_APPROVED_KEY_NAME,
284 &hkey);
286 if (ERROR_SUCCESS == rc)
288 rc = RegDeleteValueA(
289 hkey,
290 ClsidToString(Clsid).c_str());
292 rc |= RegCloseKey(hkey);
295 return rc == ERROR_SUCCESS ? S_OK : E_FAIL;
298 } // namespace /* private */
302 // COM exports
305 extern "C" STDAPI DllRegisterServer()
307 TCHAR ModuleFileName[MAX_PATH];
309 GetModuleFileName(
310 GetModuleHandle(MODULE_NAME),
311 ModuleFileName,
312 sizeof(ModuleFileName));
314 std::string module_path = WStringToString(ModuleFileName);
315 HRESULT hr = S_OK;
317 if (SUCCEEDED(RegisterColumnHandler(module_path.c_str())))
318 ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME);
319 else
320 hr = E_FAIL;
322 if (SUCCEEDED(RegisterInfotipHandler(module_path.c_str())))
323 ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME);
324 else
325 hr = E_FAIL;
327 if (SUCCEEDED(RegisterPropSheetHandler(module_path.c_str())))
328 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME);
329 else
330 hr = E_FAIL;
332 if (SUCCEEDED(RegisterThumbviewerHandler(module_path.c_str())))
333 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME);
334 else
335 hr = E_FAIL;
337 // notify the Shell that something has changed
338 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
340 return hr;
343 extern "C" STDAPI DllUnregisterServer()
345 HRESULT hr = S_OK;
347 if (FAILED(UnregisterColumnHandler()))
348 hr = E_FAIL;
350 UnapproveShellExtension(CLSID_COLUMN_HANDLER);
352 if (FAILED(UnregisterInfotipHandler()))
353 hr = E_FAIL;
355 UnapproveShellExtension(CLSID_INFOTIP_HANDLER);
357 if (FAILED(UnregisterPropSheetHandler()))
358 hr = E_FAIL;
360 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER);
362 if (FAILED(UnregisterThumbviewerHandler()))
363 hr = E_FAIL;
365 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER);
367 // notify the Shell that something has changed
368 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
370 return hr;
373 extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
375 *ppv = 0;
377 if ((rclsid != CLSID_INFOTIP_HANDLER) &&
378 (rclsid != CLSID_COLUMN_HANDLER) &&
379 (rclsid != CLSID_PROPERTYSHEET_HANDLER) &&
380 (rclsid != CLSID_THUMBVIEWER_HANDLER))
381 return CLASS_E_CLASSNOTAVAILABLE;
383 if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
384 return E_NOINTERFACE;
386 if ( rclsid == CLSID_INFOTIP_HANDLER )
387 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" );
388 else if ( rclsid == CLSID_COLUMN_HANDLER )
389 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" );
390 else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER )
391 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" );
392 else if ( rclsid == CLSID_THUMBVIEWER_HANDLER )
393 OutputDebugStringFormat( "DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" );
395 IUnknown* pUnk = new CClassFactory(rclsid);
396 *ppv = pUnk;
397 return S_OK;
400 extern "C" STDAPI DllCanUnloadNow()
402 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
403 return S_FALSE;
405 return S_OK;
408 BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/)
410 g_hModule = hInst;
411 return TRUE;
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */