cid#1640468 Dereference after null check
[LibreOffice.git] / shell / source / win32 / shlxthandler / shlxthdl.cxx
blobb487e31a57ac332a19c67f1ca175ff89968c1a87
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 #include <systools/win32/extended_max_path.hxx>
35 // Module global
37 LONG g_DllRefCnt = 0;
38 HINSTANCE g_hModule = nullptr;
40 namespace /* private */
42 const wchar_t* const GUID_PLACEHOLDER = L"{GUID}";
43 const wchar_t* const EXTENSION_PLACEHOLDER = L"{EXT}";
44 const wchar_t* const FORWARDKEY_PLACEHOLDER = L"{FWDKEY}";
46 const wchar_t* const CLSID_ENTRY = L"CLSID\\{GUID}\\InProcServer32";
47 const wchar_t* const SHELLEX_IID_ENTRY = L"{EXT}\\shellex\\{GUID}";
48 const wchar_t* const SHELLEX_ENTRY = L"{EXT}\\shellex";
49 const wchar_t* const FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1";
50 const wchar_t* const FORWARD_PROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers";
51 const wchar_t* const FORWARD_SHELLEX_ENTRY = L"{FWDKEY}\\shellex";
53 const wchar_t* const SHELL_EXTENSION_APPROVED_KEY_NAME = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
56 // "String Placeholder" ->
57 // "String Replacement"
59 void SubstitutePlaceholder(std::wstring& String, const std::wstring& Placeholder, const std::wstring& Replacement)
61 std::wstring::size_type idx = String.find(Placeholder);
62 std::wstring::size_type len = Placeholder.length();
64 while (std::wstring::npos != idx)
66 String.replace(idx, len, Replacement);
67 idx = String.find(Placeholder);
71 /* Make the registry entry
72 HKCR\CLSID\{GUID}
73 InProcServer32 = Path\shlxthdl.dll
74 ThreadingModel = Apartment
76 HRESULT RegisterComComponent(const wchar_t* FilePath, const CLSID& Guid)
78 std::wstring ClsidEntry = CLSID_ENTRY;
79 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid));
81 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"", FilePath))
82 return E_FAIL;
84 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"ThreadingModel", L"Apartment"))
85 return E_FAIL;
87 return S_OK;
90 HRESULT UnregisterComComponent(const CLSID& Guid)
92 std::wstring tmp = L"CLSID\\";
93 tmp += ClsidToString(Guid);
94 return DeleteRegistryTree(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
97 HRESULT RegisterColumnHandler(const wchar_t* ModuleFileName)
99 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER)))
100 return E_FAIL;
102 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
103 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
105 return SetRegistryKey(
106 HKEY_CLASSES_ROOT,
107 tmp.c_str(),
108 L"",
109 COLUMN_HANDLER_DESCRIPTIVE_NAME) ? S_OK : E_FAIL;
112 HRESULT UnregisterColumnHandler()
114 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
115 tmp += ClsidToString(CLSID_COLUMN_HANDLER);
117 if (!DeleteRegistryTree(HKEY_CLASSES_ROOT, tmp.c_str()))
118 return E_FAIL;
120 return UnregisterComComponent(CLSID_COLUMN_HANDLER);
123 HRESULT RegisterInfotipHandler(const wchar_t* ModuleFileName)
125 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER)))
126 return E_FAIL;
128 std::wstring iid = ClsidToString(IID_IQueryInfo);
129 std::wstring tmp;
131 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
133 tmp = SHELLEX_IID_ENTRY;
134 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
135 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
137 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_INFOTIP_HANDLER).c_str()))
138 return E_FAIL;
140 return S_OK;
143 HRESULT UnregisterInfotipHandler()
145 std::wstring iid = ClsidToString(IID_IQueryInfo);
146 std::wstring tmp;
148 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
150 tmp = SHELLEX_IID_ENTRY;
152 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
153 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
155 DeleteRegistryTree(HKEY_CLASSES_ROOT, tmp.c_str());
157 // if there are no further subkey below .ext\\shellex
158 // delete the whole subkey
159 tmp = SHELLEX_ENTRY;
160 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
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 DeleteRegistryTree(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
196 FwdKeyEntry = FORWARD_PROPSHEET_ENTRY;
197 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
199 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
201 FwdKeyEntry = FORWARD_SHELLEX_ENTRY;
202 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
204 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
207 return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER);
210 HRESULT RegisterThumbviewerHandler(const wchar_t* ModuleFileName)
212 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER)))
213 return E_FAIL;
215 std::wstring iid = ClsidToString(IID_IExtractImage);
216 std::wstring tmp;
218 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
220 tmp = SHELLEX_IID_ENTRY;
222 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
223 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
225 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str()))
226 return E_FAIL;
228 return S_OK;
231 HRESULT UnregisterThumbviewerHandler()
233 std::wstring iid = ClsidToString(IID_IExtractImage);
234 std::wstring tmp;
236 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
238 tmp = SHELLEX_IID_ENTRY;
240 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
241 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
243 DeleteRegistryTree(HKEY_CLASSES_ROOT, tmp.c_str());
245 // if there are no further subkey below .ext\\shellex
246 // delete the whole subkey
247 tmp = SHELLEX_ENTRY;
248 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
250 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
252 return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER);
255 /** Approving/Unapproving the Shell Extension, it's important under Windows
256 NT/2000/XP, see MSDN: Creating Shell Extension Handlers */
257 HRESULT ApproveShellExtension(const CLSID& clsid, const std::wstring& Description)
259 bool bRet = SetRegistryKey(
260 HKEY_LOCAL_MACHINE,
261 SHELL_EXTENSION_APPROVED_KEY_NAME,
262 ClsidToString(clsid).c_str(),
263 Description.c_str());
265 return bRet ? S_OK : E_FAIL;
268 HRESULT UnapproveShellExtension(const CLSID& Clsid)
270 LSTATUS rc = RegDeleteKeyValueW(HKEY_LOCAL_MACHINE, SHELL_EXTENSION_APPROVED_KEY_NAME,
271 ClsidToString(Clsid).c_str());
272 return rc == ERROR_SUCCESS ? S_OK : E_FAIL;
275 } // namespace /* private */
278 // COM exports
281 STDAPI DllRegisterServer()
283 WCHAR ModuleFileName[EXTENDED_MAX_PATH];
285 GetModuleFileNameW(
286 GetCurrentModuleHandle(),
287 ModuleFileName,
288 std::size(ModuleFileName));
290 HRESULT hr = S_OK;
292 if (SUCCEEDED(RegisterColumnHandler(ModuleFileName)))
293 ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME);
294 else
295 hr = E_FAIL;
297 if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName)))
298 ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME);
299 else
300 hr = E_FAIL;
302 if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName)))
303 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME);
304 else
305 hr = E_FAIL;
307 if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName)))
308 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME);
309 else
310 hr = E_FAIL;
312 // notify the Shell that something has changed
313 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
315 return hr;
318 STDAPI DllUnregisterServer()
320 HRESULT hr = S_OK;
322 if (FAILED(UnregisterColumnHandler()))
323 hr = E_FAIL;
325 UnapproveShellExtension(CLSID_COLUMN_HANDLER);
327 if (FAILED(UnregisterInfotipHandler()))
328 hr = E_FAIL;
330 UnapproveShellExtension(CLSID_INFOTIP_HANDLER);
332 if (FAILED(UnregisterPropSheetHandler()))
333 hr = E_FAIL;
335 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER);
337 if (FAILED(UnregisterThumbviewerHandler()))
338 hr = E_FAIL;
340 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER);
342 // notify the Shell that something has changed
343 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
345 return hr;
348 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
350 *ppv = nullptr;
352 if ((rclsid != CLSID_INFOTIP_HANDLER) &&
353 (rclsid != CLSID_COLUMN_HANDLER) &&
354 (rclsid != CLSID_PROPERTYSHEET_HANDLER) &&
355 (rclsid != CLSID_THUMBVIEWER_HANDLER))
356 return CLASS_E_CLASSNOTAVAILABLE;
358 if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
359 return E_NOINTERFACE;
361 if ( rclsid == CLSID_INFOTIP_HANDLER )
362 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" );
363 else if ( rclsid == CLSID_COLUMN_HANDLER )
364 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" );
365 else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER )
366 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" );
367 else if ( rclsid == CLSID_THUMBVIEWER_HANDLER )
368 OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" );
370 IUnknown* pUnk = new CClassFactory(rclsid);
371 *ppv = pUnk;
372 return S_OK;
375 STDAPI DllCanUnloadNow()
377 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
378 return S_FALSE;
380 return S_OK;
383 BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/)
385 g_hModule = hInst;
386 return TRUE;
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */