1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <shlxthdl.hxx>
23 #include "classfactory.hxx"
24 #include <registry.hxx>
25 #include <fileextensions.hxx>
26 #include <utilities.hxx>
31 #include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer
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
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
))
82 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), L
"ThreadingModel", L
"Apartment"))
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
)))
100 std::wstring tmp
= L
"Folder\\shellex\\ColumnHandlers\\";
101 tmp
+= ClsidToString(CLSID_COLUMN_HANDLER
);
103 return SetRegistryKey(
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()))
118 return UnregisterComComponent(CLSID_COLUMN_HANDLER
);
121 HRESULT
RegisterInfotipHandler(const wchar_t* ModuleFileName
)
123 if (FAILED(RegisterComComponent(ModuleFileName
, CLSID_INFOTIP_HANDLER
)))
126 std::wstring iid
= ClsidToString(IID_IQueryInfo
);
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()))
141 HRESULT
UnregisterInfotipHandler()
143 std::wstring iid
= ClsidToString(IID_IQueryInfo
);
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
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
)))
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()))
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
);
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
)))
219 std::wstring iid
= ClsidToString(IID_IExtractImage
);
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()))
235 HRESULT
UnregisterThumbviewerHandler()
237 std::wstring iid
= ClsidToString(IID_IExtractImage
);
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
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(
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
)
278 LONG rc
= RegOpenKeyW(
280 SHELL_EXTENSION_APPROVED_KEY_NAME
,
283 if (ERROR_SUCCESS
== rc
)
285 rc
= RegDeleteValueW(
287 ClsidToString(Clsid
).c_str());
289 rc
|= RegCloseKey(hkey
);
292 return rc
== ERROR_SUCCESS
? S_OK
: E_FAIL
;
295 } // namespace /* private */
301 STDAPI
DllRegisterServer()
303 WCHAR ModuleFileName
[MAX_PATH
];
306 GetModuleHandleW(MODULE_NAME
),
308 sizeof(ModuleFileName
)/sizeof(ModuleFileName
[0]));
312 if (SUCCEEDED(RegisterColumnHandler(ModuleFileName
)))
313 ApproveShellExtension(CLSID_COLUMN_HANDLER
, COLUMN_HANDLER_DESCRIPTIVE_NAME
);
317 if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName
)))
318 ApproveShellExtension(CLSID_INFOTIP_HANDLER
, INFOTIP_HANDLER_DESCRIPTIVE_NAME
);
322 if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName
)))
323 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
, PROPSHEET_HANDLER_DESCRIPTIVE_NAME
);
327 if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName
)))
328 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER
, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME
);
332 // notify the Shell that something has changed
333 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, nullptr, nullptr);
338 STDAPI
DllUnregisterServer()
342 if (FAILED(UnregisterColumnHandler()))
345 UnapproveShellExtension(CLSID_COLUMN_HANDLER
);
347 if (FAILED(UnregisterInfotipHandler()))
350 UnapproveShellExtension(CLSID_INFOTIP_HANDLER
);
352 if (FAILED(UnregisterPropSheetHandler()))
355 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
);
357 if (FAILED(UnregisterThumbviewerHandler()))
360 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER
);
362 // notify the Shell that something has changed
363 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, nullptr, nullptr);
368 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
* ppv
)
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
);
395 STDAPI
DllCanUnloadNow()
397 if (CClassFactory::IsLocked() || g_DllRefCnt
> 0)
403 BOOL WINAPI
DllMain(HINSTANCE hInst
, ULONG
/*ul_reason_for_call*/, LPVOID
/*lpReserved*/)
409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */