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 .
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"
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
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
))
85 if (!SetRegistryKey(HKEY_CLASSES_ROOT
, ClsidEntry
.c_str(), "ThreadingModel", "Apartment"))
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
)))
103 std::string tmp
= "Folder\\shellex\\ColumnHandlers\\";
104 tmp
+= ClsidToString(CLSID_COLUMN_HANDLER
);
106 return SetRegistryKey(
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()))
121 return UnregisterComComponent(CLSID_COLUMN_HANDLER
);
124 HRESULT
RegisterInfotipHandler(const char* ModuleFileName
)
126 if (FAILED(RegisterComComponent(ModuleFileName
, CLSID_INFOTIP_HANDLER
)))
129 std::string iid
= ClsidToString(IID_IQueryInfo
);
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()))
144 HRESULT
UnregisterInfotipHandler()
146 std::string iid
= ClsidToString(IID_IQueryInfo
);
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
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
)))
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()))
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
);
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
)))
222 std::string iid
= ClsidToString(IID_IExtractImage
);
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()))
238 HRESULT
UnregisterThumbviewerHandler()
240 std::string iid
= ClsidToString(IID_IExtractImage
);
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
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(
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
)
281 LONG rc
= RegOpenKeyA(
283 SHELL_EXTENSION_APPROVED_KEY_NAME
,
286 if (ERROR_SUCCESS
== rc
)
288 rc
= RegDeleteValueA(
290 ClsidToString(Clsid
).c_str());
292 rc
|= RegCloseKey(hkey
);
295 return rc
== ERROR_SUCCESS
? S_OK
: E_FAIL
;
298 } // namespace /* private */
305 extern "C" STDAPI
DllRegisterServer()
307 TCHAR ModuleFileName
[MAX_PATH
];
310 GetModuleHandle(MODULE_NAME
),
312 sizeof(ModuleFileName
));
314 std::string module_path
= WStringToString(ModuleFileName
);
317 if (SUCCEEDED(RegisterColumnHandler(module_path
.c_str())))
318 ApproveShellExtension(CLSID_COLUMN_HANDLER
, COLUMN_HANDLER_DESCRIPTIVE_NAME
);
322 if (SUCCEEDED(RegisterInfotipHandler(module_path
.c_str())))
323 ApproveShellExtension(CLSID_INFOTIP_HANDLER
, INFOTIP_HANDLER_DESCRIPTIVE_NAME
);
327 if (SUCCEEDED(RegisterPropSheetHandler(module_path
.c_str())))
328 ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
, PROPSHEET_HANDLER_DESCRIPTIVE_NAME
);
332 if (SUCCEEDED(RegisterThumbviewerHandler(module_path
.c_str())))
333 ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER
, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME
);
337 // notify the Shell that something has changed
338 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, 0, 0);
343 extern "C" STDAPI
DllUnregisterServer()
347 if (FAILED(UnregisterColumnHandler()))
350 UnapproveShellExtension(CLSID_COLUMN_HANDLER
);
352 if (FAILED(UnregisterInfotipHandler()))
355 UnapproveShellExtension(CLSID_INFOTIP_HANDLER
);
357 if (FAILED(UnregisterPropSheetHandler()))
360 UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER
);
362 if (FAILED(UnregisterThumbviewerHandler()))
365 UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER
);
367 // notify the Shell that something has changed
368 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
, 0, 0);
373 extern "C" STDAPI
DllGetClassObject(REFCLSID rclsid
, REFIID riid
, void** ppv
)
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
);
400 extern "C" STDAPI
DllCanUnloadNow()
402 if (CClassFactory::IsLocked() || g_DllRefCnt
> 0)
408 BOOL WINAPI
DllMain(HINSTANCE hInst
, ULONG
/*ul_reason_for_call*/, LPVOID
/*lpReserved*/)
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */