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
33 #include <systools/win32/extended_max_path.hxx>
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
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
))
84 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), L
"ThreadingModel", L
"Apartment"))
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
)))
102 std::wstring tmp
= L
"Folder\\shellex\\ColumnHandlers\\";
103 tmp
+= ClsidToString(CLSID_COLUMN_HANDLER
);
105 return SetRegistryKey(
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()))
120 return UnregisterComComponent(CLSID_COLUMN_HANDLER
);
123 HRESULT
RegisterInfotipHandler(const wchar_t* ModuleFileName
)
125 if (FAILED(RegisterComComponent(ModuleFileName
, CLSID_INFOTIP_HANDLER
)))
128 std::wstring iid
= ClsidToString(IID_IQueryInfo
);
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()))
143 HRESULT
UnregisterInfotipHandler()
145 std::wstring iid
= ClsidToString(IID_IQueryInfo
);
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
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
)))
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 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
)))
215 std::wstring iid
= ClsidToString(IID_IExtractImage
);
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()))
231 HRESULT
UnregisterThumbviewerHandler()
233 std::wstring iid
= ClsidToString(IID_IExtractImage
);
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
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(
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 */
281 STDAPI
DllRegisterServer()
283 WCHAR ModuleFileName
[EXTENDED_MAX_PATH
];
286 GetCurrentModuleHandle(),
288 std::size(ModuleFileName
));
292 if (SUCCEEDED(RegisterColumnHandler(ModuleFileName
)))
293 ApproveShellExtension(CLSID_COLUMN_HANDLER
, COLUMN_HANDLER_DESCRIPTIVE_NAME
);
297 if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName
)))
298 ApproveShellExtension(CLSID_INFOTIP_HANDLER
, INFOTIP_HANDLER_DESCRIPTIVE_NAME
);
302 if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName
)))
303 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
, PROPSHEET_HANDLER_DESCRIPTIVE_NAME
);
307 if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName
)))
308 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER
, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME
);
312 // notify the Shell that something has changed
313 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, nullptr, nullptr);
318 STDAPI
DllUnregisterServer()
322 if (FAILED(UnregisterColumnHandler()))
325 UnapproveShellExtension(CLSID_COLUMN_HANDLER
);
327 if (FAILED(UnregisterInfotipHandler()))
330 UnapproveShellExtension(CLSID_INFOTIP_HANDLER
);
332 if (FAILED(UnregisterPropSheetHandler()))
335 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
);
337 if (FAILED(UnregisterThumbviewerHandler()))
340 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER
);
342 // notify the Shell that something has changed
343 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, nullptr, nullptr);
348 STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, LPVOID
* ppv
)
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
);
375 STDAPI
DllCanUnloadNow()
377 if (CClassFactory::IsLocked() || g_DllRefCnt
> 0)
383 BOOL WINAPI
DllMain(HINSTANCE hInst
, ULONG
/*ul_reason_for_call*/, LPVOID
/*lpReserved*/)
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */