LibreOffice Module shell (master) 1
shlxthdl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
27
28#include <string>
29#include <shlobj.h>
30
31#include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer
32
33// Module global
34
36HINSTANCE g_hModule = nullptr;
37
38namespace /* private */
39{
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}";
43
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";
50
51 const wchar_t* const SHELL_EXTENSION_APPROVED_KEY_NAME = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
52
53
54 // "String Placeholder" ->
55 // "String Replacement"
56
57 void SubstitutePlaceholder(std::wstring& String, const std::wstring& Placeholder, const std::wstring& Replacement)
58 {
59 std::wstring::size_type idx = String.find(Placeholder);
60 std::wstring::size_type len = Placeholder.length();
61
62 while (std::wstring::npos != idx)
63 {
64 String.replace(idx, len, Replacement);
65 idx = String.find(Placeholder);
66 }
67 }
68
69 /* Make the registry entry
70 HKCR\CLSID\{GUID}
71 InProcServer32 = Path\shlxthdl.dll
72 ThreadingModel = Apartment
73 */
74 HRESULT RegisterComComponent(const wchar_t* FilePath, const CLSID& Guid)
75 {
76 std::wstring ClsidEntry = CLSID_ENTRY;
77 SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid));
78
79 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"", FilePath))
80 return E_FAIL;
81
82 if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"ThreadingModel", L"Apartment"))
83 return E_FAIL;
84
85 return S_OK;
86 }
87
88 HRESULT UnregisterComComponent(const CLSID& Guid)
89 {
90 std::wstring tmp = L"CLSID\\";
91 tmp += ClsidToString(Guid);
92 return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
93 }
94
95 HRESULT RegisterColumnHandler(const wchar_t* ModuleFileName)
96 {
97 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER)))
98 return E_FAIL;
99
100 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
102
103 return SetRegistryKey(
104 HKEY_CLASSES_ROOT,
105 tmp.c_str(),
106 L"",
107 COLUMN_HANDLER_DESCRIPTIVE_NAME) ? S_OK : E_FAIL;
108 }
109
110 HRESULT UnregisterColumnHandler()
111 {
112 std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\";
114
115 if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()))
116 return E_FAIL;
117
118 return UnregisterComComponent(CLSID_COLUMN_HANDLER);
119 }
120
121 HRESULT RegisterInfotipHandler(const wchar_t* ModuleFileName)
122 {
123 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER)))
124 return E_FAIL;
125
126 std::wstring iid = ClsidToString(IID_IQueryInfo);
127 std::wstring tmp;
128
129 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
130 {
131 tmp = SHELLEX_IID_ENTRY;
132 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
133 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
134
135 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_INFOTIP_HANDLER).c_str()))
136 return E_FAIL;
137 }
138 return S_OK;
139 }
140
141 HRESULT UnregisterInfotipHandler()
142 {
143 std::wstring iid = ClsidToString(IID_IQueryInfo);
144 std::wstring tmp;
145
146 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
147 {
148 tmp = SHELLEX_IID_ENTRY;
149
150 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
151 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
152
153 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
154
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);
159
160 bool HasSubKeys = true;
161 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
162 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
163 }
164 return UnregisterComComponent(CLSID_INFOTIP_HANDLER);
165 }
166
167 HRESULT RegisterPropSheetHandler(const wchar_t* ModuleFileName)
168 {
169 std::wstring FwdKeyEntry;
170
171 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER)))
172 return E_FAIL;
173
174 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
175 {
176 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
177 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
178
179 if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), L"", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str()))
180 return E_FAIL;
181 }
182 return S_OK;
183 }
184
185 HRESULT UnregisterPropSheetHandler()
186 {
187 std::wstring FwdKeyEntry;
188
189 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
190 {
191 FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY;
192 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
193
194 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
195
196 FwdKeyEntry = FORWARD_PROPSHEET_ENTRY;
197 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
198
199 bool HasSubKeys = true;
200 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
201 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
202
203 FwdKeyEntry = FORWARD_SHELLEX_ENTRY;
204 SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey);
205
206 HasSubKeys = true;
207 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys)
208 DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str());
209 }
210
211 return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER);
212 }
213
214 HRESULT RegisterThumbviewerHandler(const wchar_t* ModuleFileName)
215 {
216 if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER)))
217 return E_FAIL;
218
219 std::wstring iid = ClsidToString(IID_IExtractImage);
220 std::wstring tmp;
221
222 for(size_t i = 0; i < OOFileExtensionTableSize; i++)
223 {
224 tmp = SHELLEX_IID_ENTRY;
225
226 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
227 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
228
229 if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str()))
230 return E_FAIL;
231 }
232 return S_OK;
233 }
234
235 HRESULT UnregisterThumbviewerHandler()
236 {
237 std::wstring iid = ClsidToString(IID_IExtractImage);
238 std::wstring tmp;
239
240 for (size_t i = 0; i < OOFileExtensionTableSize; i++)
241 {
242 tmp = SHELLEX_IID_ENTRY;
243
244 SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU);
245 SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid);
246
247 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
248
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);
253
254 bool HasSubKeys = true;
255 if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys)
256 DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str());
257 }
258 return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER);
259 }
260
263 HRESULT ApproveShellExtension(const CLSID& clsid, const std::wstring& Description)
264 {
265 bool bRet = SetRegistryKey(
266 HKEY_LOCAL_MACHINE,
267 SHELL_EXTENSION_APPROVED_KEY_NAME,
268 ClsidToString(clsid).c_str(),
269 Description.c_str());
270
271 return bRet ? S_OK : E_FAIL;
272 }
273
274 HRESULT UnapproveShellExtension(const CLSID& Clsid)
275 {
276 HKEY hkey;
277
278 LONG rc = RegOpenKeyW(
279 HKEY_LOCAL_MACHINE,
280 SHELL_EXTENSION_APPROVED_KEY_NAME,
281 &hkey);
282
283 if (ERROR_SUCCESS == rc)
284 {
285 rc = RegDeleteValueW(
286 hkey,
287 ClsidToString(Clsid).c_str());
288
289 rc |= RegCloseKey(hkey);
290 }
291
292 return rc == ERROR_SUCCESS ? S_OK : E_FAIL;
293 }
294
295} // namespace /* private */
296
297
298// COM exports
299
300
302{
303 WCHAR ModuleFileName[MAX_PATH];
304
305 GetModuleFileNameW(
307 ModuleFileName,
308 sizeof(ModuleFileName)/sizeof(ModuleFileName[0]));
309
310 HRESULT hr = S_OK;
311
312 if (SUCCEEDED(RegisterColumnHandler(ModuleFileName)))
314 else
315 hr = E_FAIL;
316
317 if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName)))
319 else
320 hr = E_FAIL;
321
322 if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName)))
324 else
325 hr = E_FAIL;
326
327 if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName)))
329 else
330 hr = E_FAIL;
331
332 // notify the Shell that something has changed
333 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
334
335 return hr;
336}
337
339{
340 HRESULT hr = S_OK;
341
342 if (FAILED(UnregisterColumnHandler()))
343 hr = E_FAIL;
344
345 UnapproveShellExtension(CLSID_COLUMN_HANDLER);
346
347 if (FAILED(UnregisterInfotipHandler()))
348 hr = E_FAIL;
349
350 UnapproveShellExtension(CLSID_INFOTIP_HANDLER);
351
352 if (FAILED(UnregisterPropSheetHandler()))
353 hr = E_FAIL;
354
355 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER);
356
357 if (FAILED(UnregisterThumbviewerHandler()))
358 hr = E_FAIL;
359
360 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER);
361
362 // notify the Shell that something has changed
363 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
364
365 return hr;
366}
367
368STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
369{
370 *ppv = nullptr;
371
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;
377
378 if ((riid != IID_IUnknown) && (riid != IID_IClassFactory))
379 return E_NOINTERFACE;
380
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" );
389
390 IUnknown* pUnk = new CClassFactory(rclsid);
391 *ppv = pUnk;
392 return S_OK;
393}
394
396{
398 return S_FALSE;
399
400 return S_OK;
401}
402
403BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/)
404{
405 g_hModule = hInst;
406 return TRUE;
407}
408
409/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool IsLocked()
#define COLUMN_HANDLER_DESCRIPTIVE_NAME
Definition: config.hxx:23
#define INFOTIP_HANDLER_DESCRIPTIVE_NAME
Definition: config.hxx:24
#define PROPSHEET_HANDLER_DESCRIPTIVE_NAME
Definition: config.hxx:25
#define THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME
Definition: config.hxx:26
const FileExtensionEntry OOFileExtensionTable[]
const size_t OOFileExtensionTableSize
#define TRUE
#define MAX_PATH
const sal_uInt16 idx[]
int i
const wchar_t *typedef BOOL
Filepath_t ClsidToString(const CLSID &clsid)
Converts a GUID to its string representation.
Definition: registry.cxx:135
bool HasSubkeysRegistryKey(HKEY RootKey, const Filepath_char_t *KeyName, bool &bResult)
May be used to determine if the specified registry key has subkeys The function returns true on succe...
Definition: registry.cxx:115
bool DeleteRegistryKey(HKEY RootKey, const Filepath_char_t *KeyName)
Deletes the specified registry key and all of its subkeys Returns true on success.
Definition: registry.cxx:53
bool SetRegistryKey(HKEY RootKey, const Filepath_char_t *KeyName, const Filepath_char_t *ValueName, const Filepath_char_t *Value)
Sets a value of the specified registry key, an empty ValueName sets the default value Returns true on...
Definition: registry.cxx:31
LONG
HINSTANCE g_hModule
Definition: shlxthdl.cxx:36
STDAPI DllRegisterServer()
Definition: shlxthdl.cxx:301
STDAPI DllCanUnloadNow()
Definition: shlxthdl.cxx:395
STDAPI DllUnregisterServer()
Definition: shlxthdl.cxx:338
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
Definition: shlxthdl.cxx:368
BOOL WINAPI DllMain(HINSTANCE hInst, ULONG, LPVOID)
Definition: shlxthdl.cxx:403
LONG g_DllRefCnt
Definition: shlxthdl.cxx:35
const CLSID CLSID_PROPERTYSHEET_HANDLER
Definition: shlxthdl.hxx:35
const CLSID CLSID_THUMBVIEWER_HANDLER
Definition: shlxthdl.hxx:39
const CLSID CLSID_INFOTIP_HANDLER
Definition: shlxthdl.hxx:27
const CLSID CLSID_COLUMN_HANDLER
Definition: shlxthdl.hxx:31
return hr
HMODULE GetCurrentModuleHandle()
Definition: utilities.cxx:549
void OutputDebugStringFormatW(LPCWSTR pFormat,...)
Definition: utilities.hxx:78