Reactos
1/*
2 * PROJECT: ReactOS shell extensions
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Quick Launch Toolbar (Taskbar Shell Extension)
5 * COPYRIGHT: Copyright 2014 Giannis Adamopoulos
6 */
7
8
9#include <stdio.h>
10#include <tchar.h>
11
12#define WIN32_NO_STATUS
13#define _INC_WINDOWS
14#define COM_NO_WINDOWS_H
15
16#define COBJMACROS
17
18#include <windef.h>
19#include <winbase.h>
20#include <winreg.h>
21#include <wingdi.h>
22#include <winnls.h>
23#include <wincon.h>
24#include <shellapi.h>
25#include <shlobj.h>
26#include <shlobj_undoc.h>
27#include <shlwapi.h>
28#include <shlguid_undoc.h>
29#include <uxtheme.h>
30#include <strsafe.h>
31
32#include <atlbase.h>
33#include <atlcom.h>
34#include <atlwin.h>
35#include <undocshell.h>
36#include <undocuser.h>
37
38#include <shellutils.h>
39
40#include <CQuickLaunchBand.h>
41
42#include <wine/debug.h>
43
44extern "C"
45{
46 extern HINSTANCE shell32_hInstance;
47
48 HRESULT WINAPI RSHELL_CStartMenu_CreateInstance(REFIID riid, void **ppv);
49 HRESULT WINAPI RSHELL_CMenuDeskBar_CreateInstance(REFIID riid, LPVOID *ppv);
50 HRESULT WINAPI RSHELL_CMenuSite_CreateInstance(REFIID riid, LPVOID *ppv);
51 HRESULT WINAPI RSHELL_CMenuBand_CreateInstance(REFIID riid, LPVOID *ppv);
52 HRESULT WINAPI RSHELL_CMergedFolder_CreateInstance(REFIID riid, LPVOID *ppv);
53}
54
55class CRShellModule : public CComModule
56{
57public:
58};
59
60CRShellModule gModule;
61CAtlWinModule gWinModule;
62
63HINSTANCE shell32_hInstance = NULL;
64
65static LSTATUS inline _RegSetStringValueW(HKEY hKey, LPCWSTR lpValueName, LPCWSTR lpStringData)
66{
67 DWORD dwStringDataLen = lstrlenW(lpStringData);
68
69 return RegSetValueExW(hKey, lpValueName, 0, REG_SZ, (BYTE *) lpStringData, 2 * (dwStringDataLen + 1));
70}
71
72static HRESULT RegisterComponent(REFGUID clsid, LPCWSTR szDisplayName)
73{
74 WCHAR szFilename[MAX_PATH];
75 WCHAR szClsid[MAX_PATH];
76 WCHAR szRoot[MAX_PATH];
77
78 if (!StringFromGUID2(clsid, szClsid, _countof(szClsid)))
79 return E_FAIL;
80
81 if (!GetModuleFileNameW(shell32_hInstance, szFilename, _countof(szFilename)))
82 return E_FAIL;
83
84 HRESULT hr = StringCchPrintfW(szRoot, 0x104u, L"CLSID\\%s", szClsid);
85 if (FAILED(hr))
86 return hr;
87
88 DWORD dwDisposition;
89 HKEY hkRoot;
90 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szRoot, 0, NULL, 0, KEY_WRITE, 0, &hkRoot, &dwDisposition) != 0)
91 return E_FAIL;
92
93 HKEY hkServer;
94
95 _RegSetStringValueW(hkRoot, NULL, szDisplayName);
96
97 if (RegCreateKeyExW(hkRoot, L"InprocServer32", 0, NULL, 0, KEY_SET_VALUE, 0, &hkServer, &dwDisposition) != 0)
98 {
99 RegCloseKey(hkRoot);
100 return E_FAIL;
101 }
102
103 _RegSetStringValueW(hkServer, NULL, szFilename);
104 _RegSetStringValueW(hkServer, L"ThreadingModel", L"Both");
105
106 RegCloseKey(hkServer);
107 RegCloseKey(hkRoot);
108 return S_OK;
109}
110
111static HRESULT UnregisterComponent(REFGUID clsid)
112{
113 WCHAR szClsid[MAX_PATH];
114 WCHAR szRoot[MAX_PATH];
115 HKEY hkRoot;
116
117 if (!StringFromGUID2(clsid, szClsid, _countof(szClsid)))
118 return E_FAIL;
119
120 HRESULT hr = StringCchPrintfW(szRoot, 0x104u, L"CLSID\\%s", szClsid);
121 if (FAILED(hr))
122 return hr;
123
124 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szRoot, 0, KEY_WRITE, &hkRoot) != 0)
125 return E_FAIL;
126
127 RegDeleteKeyW(hkRoot, L"InprocServer32");
128 RegCloseKey(hkRoot);
129
130 RegDeleteKeyW(HKEY_CLASSES_ROOT, szRoot);
131
132 return S_OK;
133}
134
135STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
136{
137 if (dwReason == DLL_PROCESS_ATTACH)
138 {
139 shell32_hInstance = hInstance;
140
141 gModule.Init(NULL, hInstance, NULL);
142 DisableThreadLibraryCalls(hInstance);
143 }
144 else if (dwReason == DLL_PROCESS_DETACH)
145 {
146 shell32_hInstance = NULL;
147 gModule.Term();
148 }
149 return TRUE;
150}
151
152HRESULT
153WINAPI
154DllCanUnloadNow(void)
155{
156 gModule.DllCanUnloadNow();
157 return S_FALSE;
158}
159
160STDAPI
161DllRegisterServer(void)
162{
163#if 0
164 RegisterComponent(CLSID_StartMenu, L"Shell Start Menu");
165 RegisterComponent(CLSID_MenuDeskBar, L"Shell Menu Desk Bar");
166 RegisterComponent(CLSID_MenuBand, L"Shell Menu Band");
167 RegisterComponent(CLSID_MenuBandSite, L"Shell Menu Band Site");
168 RegisterComponent(CLSID_MergedFolder, L"Merged Shell Folder");
169 RegisterComponent(CLSID_RebarBandSite, L"Shell Rebar Band Site");
170#endif
171 RegisterComponent(CLSID_QuickLaunchBand, L"Quick Launch");
172 RegisterComCat();
173 return S_OK;
174}
175
176STDAPI
177DllUnregisterServer(void)
178{
179#if 0
180 UnregisterComponent(CLSID_StartMenu);
181 UnregisterComponent(CLSID_MenuDeskBar);
182 UnregisterComponent(CLSID_MenuBand);
183 UnregisterComponent(CLSID_MenuBandSite);
184 UnregisterComponent(CLSID_MergedFolder);
185 UnregisterComponent(CLSID_RebarBandSite);
186#endif
187 UnregisterComponent(CLSID_QuickLaunchBand);
188 UnregisterComCat();
189 return S_OK;
190}
191
192class CRShellClassFactory :
193 public CComObjectRootEx<CComMultiThreadModelNoCS>,
194 public IClassFactory
195{
196private:
197 CLSID m_Clsid;
198
199public:
200 CRShellClassFactory() {}
201 virtual ~CRShellClassFactory() {}
202
203 HRESULT Initialize(REFGUID clsid)
204 {
205 m_Clsid = clsid;
206 return S_OK;
207 }
208
209 /* IClassFactory */
210 virtual HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
211 {
212 *ppvObject = NULL;
213
214 if (IsEqualCLSID(m_Clsid, CLSID_StartMenu))
215 return RSHELL_CStartMenu_CreateInstance(riid, ppvObject);
216
217 if (IsEqualCLSID(m_Clsid, CLSID_MenuDeskBar))
218 return RSHELL_CMenuDeskBar_CreateInstance(riid, ppvObject);
219
220 if (IsEqualCLSID(m_Clsid, CLSID_MenuBand))
221 return RSHELL_CMenuBand_CreateInstance(riid, ppvObject);
222
223 if (IsEqualCLSID(m_Clsid, CLSID_MenuBandSite))
224 return RSHELL_CMenuSite_CreateInstance(riid, ppvObject);
225
226 if (IsEqualCLSID(m_Clsid, CLSID_MergedFolder))
227 return RSHELL_CMergedFolder_CreateInstance(riid, ppvObject);
228
229 if (IsEqualCLSID(m_Clsid, CLSID_QuickLaunchBand))
230 return ShellObjectCreator<CQuickLaunchBand>(riid, ppvObject);
231
232 return E_NOINTERFACE;
233 }
234
235 virtual HRESULT WINAPI LockServer(BOOL fLock)
236 {
237 return E_NOTIMPL;
238 }
239
240 BEGIN_COM_MAP(CRShellClassFactory)
241 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
242 END_COM_MAP()
243};
244
245STDAPI
246DllGetClassObject(
247 REFCLSID rclsid,
248 REFIID riid,
249 LPVOID *ppv)
250{
251 if (!ppv)
252 return E_INVALIDARG;
253
254 *ppv = NULL;
255
256 return ShellObjectCreatorInit<CRShellClassFactory>(rclsid, riid, ppv);
257}
258
259VOID WINAPI ShowFolderOptionsDialog(UINT Page, BOOL Async)
260{
261 char buf[MAX_PATH];
262 wsprintfA(buf, "rundll32.exe shell32.dll,Options_RunDLL %u", Page);
263 WinExec(buf, SW_SHOW);
264}