1 /*
2  * PROJECT:     ReactOS shell extensions
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Quick Launch Toolbar (Taskbar Shell Extension)
5  * COPYRIGHT:   Copyright Shriraj Sawant a.k.a SR13 <sr.official@hotmail.com>
6  */
7 
8 #define WIN32_NO_STATUS
9 #define _INC_WINDOWS
10 #define COM_NO_WINDOWS_H
11 
12 #define COBJMACROS
13 
14 #include <windef.h>
15 #include <winbase.h>
16 #include <winreg.h>
17 #include <wingdi.h>
18 #include <winnls.h>
19 #include <wincon.h>
20 #include <shellapi.h>
21 #include <shlobj.h>
22 #include <shlobj_undoc.h>
23 #include <shlwapi.h>
24 #include <shlguid_undoc.h>
25 #include <atlbase.h>
26 #include <atlcom.h>
27 #include <atlwin.h>
28 
29 #include <undocshell.h>
30 #include <shellutils.h>
31 
32 #include "CQuickLaunchBand.h"
33 
34 extern "C"
35 HRESULT WINAPI RSHELL_CISFBand_CreateInstance(REFIID riid, void** ppv);
36 
37 // {260CB95D-4544-44F6-A079-575BAA60B72F}
38 const GUID CLSID_QuickLaunchBand = { 0x260cb95d, 0x4544, 0x44f6, { 0xa0, 0x79, 0x57, 0x5b, 0xaa, 0x60, 0xb7, 0x2f } };
39 
40 // Componenet Category Registration
41 HRESULT RegisterComCat()
42 {
43     CComPtr<ICatRegister> pcr;
44     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ICatRegister, &pcr));
45     if (SUCCEEDED(hr))
46     {
47         CATID catid = CATID_DeskBand;
48         hr = pcr->RegisterClassImplCategories(CLSID_QuickLaunchBand, 1, &catid);
49     }
50     return hr;
51 }
52 
53 HRESULT UnregisterComCat()
54 {
55     CComPtr<ICatRegister> pcr;
56     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ICatRegister, &pcr));
57     if (SUCCEEDED(hr))
58     {
59         CATID catid = CATID_DeskBand;
60         hr = pcr->UnRegisterClassImplCategories(CLSID_QuickLaunchBand, 1, &catid);
61     }
62     return hr;
63 }
64 
65 // Pidl Browser
66 /*++
67 * @name PidlBrowse
68 *
69 * Opens a folder browser dialog,
70 * allowing the user to select a folder for enumeration.
71 *
72 * @param hwnd
73 *        A handle to browser dialog window.
74 * @param nCSIDL
75 *        A CSIDL representing the root from which the browse folder dialog shows the files and folders.
76 *
77 * @return The PIDL to selected folder.
78 *
79 *--*/
80 LPITEMIDLIST PidlBrowse(HWND hwnd, int nCSIDL)
81 {
82     CComHeapPtr<ITEMIDLIST> pidlRoot;
83 
84     WCHAR path[MAX_PATH];
85 
86     if (nCSIDL)
87     {
88         SHGetSpecialFolderLocation(hwnd, nCSIDL, &pidlRoot);
89     }
90 
91     BROWSEINFO bi = { hwnd, pidlRoot, path, L"Choose a folder", 0, NULL, 0, 0 };
92     LPITEMIDLIST pidlSelected = SHBrowseForFolder(&bi);
93 
94     return pidlSelected;
95 }
96 
97 // CQuickLaunchBand
98 
99 CQuickLaunchBand::CQuickLaunchBand() {}
100 
101 CQuickLaunchBand::~CQuickLaunchBand() {}
102 
103 /*****************************************************************************/
104 // ATL Construct
105 /*++
106 * @name FinalConstruct
107 *
108 * Creates an instance of CISFBand, and initializes its Shell Folder Band for enumeration.
109 *
110 * @return The error code.
111 *
112 *--*/
113 HRESULT CQuickLaunchBand::FinalConstruct()
114 {
115     HRESULT hr = RSHELL_CISFBand_CreateInstance(IID_PPV_ARG(IUnknown, &m_punkISFB));
116     if (FAILED_UNEXPECTEDLY(hr))
117         return hr;
118 
119     CComPtr<IShellFolderBand> pISFB;
120     hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IShellFolderBand, &pISFB));
121     if (FAILED_UNEXPECTEDLY(hr))
122         return hr;
123 
124     CComPtr<IShellFolder> pISF;
125     hr = SHGetDesktopFolder(&pISF);
126     if (FAILED_UNEXPECTEDLY(hr))
127         return hr;
128 
129     CComHeapPtr<ITEMIDLIST> pidl(PidlBrowse(m_hWndBro, CSIDL_DESKTOP));
130     if (pidl == NULL)
131         return E_FAIL;
132     pISFB->InitializeSFB(pISF, pidl);
133 
134     return hr;
135 }
136 
137 // IObjectWithSite
138 STDMETHODIMP CQuickLaunchBand::SetSite(IUnknown *pUnkSite)
139 {
140     // Internal CISFBand Calls
141     CComPtr<IObjectWithSite> pIOWS;
142     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pIOWS));
143     if (FAILED(hr))
144         return hr;
145 
146     return pIOWS->SetSite(pUnkSite);
147 }
148 
149 STDMETHODIMP CQuickLaunchBand::GetSite(IN REFIID riid, OUT VOID **ppvSite)
150 {
151     CComPtr<IObjectWithSite> pIOWS;
152     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pIOWS));
153     if (FAILED(hr))
154         return hr;
155 
156     return pIOWS->GetSite(riid, ppvSite);
157 }
158 
159 /*****************************************************************************/
160 // IDeskBand
161 STDMETHODIMP CQuickLaunchBand::GetWindow(OUT HWND *phwnd)
162 {
163     // Internal CISFBand Calls
164     CComPtr<IDeskBand> pIDB;
165     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
166     if (FAILED(hr))
167         return hr;
168 
169     return pIDB->GetWindow(phwnd);
170 }
171 
172 STDMETHODIMP CQuickLaunchBand::ContextSensitiveHelp(IN BOOL fEnterMode)
173 {
174     // Internal CISFBand Calls
175     CComPtr<IDeskBand> pIDB;
176     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
177     if (FAILED(hr))
178         return hr;
179 
180     return pIDB->ContextSensitiveHelp(fEnterMode);
181 }
182 
183 STDMETHODIMP CQuickLaunchBand::ShowDW(IN BOOL bShow)
184 {
185     // Internal CISFBand Calls
186     CComPtr<IDeskBand> pIDB;
187     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
188     if (FAILED(hr))
189         return hr;
190 
191     return pIDB->ShowDW(bShow);
192 }
193 
194 STDMETHODIMP CQuickLaunchBand::CloseDW(IN DWORD dwReserved)
195 {
196     // Internal CISFBand Calls
197     CComPtr<IDeskBand> pIDB;
198     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
199     if (FAILED(hr))
200         return hr;
201 
202     return pIDB->CloseDW(dwReserved);
203 }
204 
205 STDMETHODIMP CQuickLaunchBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
206 {
207     // Internal CISFBand Calls
208     CComPtr<IDeskBand> pIDB;
209     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
210     if (FAILED(hr))
211         return hr;
212 
213     return pIDB->ResizeBorderDW(prcBorder, punkToolbarSite, fReserved);
214 }
215 
216 STDMETHODIMP CQuickLaunchBand::GetBandInfo(IN DWORD dwBandID, IN DWORD dwViewMode, IN OUT DESKBANDINFO *pdbi)
217 {
218     // Internal CISFBand Calls
219     CComPtr<IDeskBand> pIDB;
220     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IDeskBand, &pIDB));
221     if (FAILED(hr))
222         return hr;
223 
224     return pIDB->GetBandInfo(dwBandID, dwViewMode, pdbi);
225 }
226 
227 /*****************************************************************************/
228 // IPersistStream
229 STDMETHODIMP CQuickLaunchBand::GetClassID(OUT CLSID *pClassID)
230 {
231     // Internal CISFBand Calls
232     CComPtr<IPersistStream> pIPS;
233     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IPersistStream, &pIPS));
234     if (FAILED(hr))
235         return hr;
236 
237     return pIPS->GetClassID(pClassID);
238 }
239 
240 STDMETHODIMP CQuickLaunchBand::IsDirty()
241 {
242     // Internal CISFBand Calls
243     CComPtr<IPersistStream> pIPS;
244     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IPersistStream, &pIPS));
245     if (FAILED(hr))
246         return hr;
247 
248     return pIPS->IsDirty();
249 }
250 
251 STDMETHODIMP CQuickLaunchBand::Load(IN IStream *pStm)
252 {
253     CComPtr<IPersistStream> pIPS;
254     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IPersistStream, &pIPS));
255     if (FAILED(hr))
256         return hr;
257 
258     return pIPS->Load(pStm);
259 }
260 
261 STDMETHODIMP CQuickLaunchBand::Save(IN IStream *pStm, IN BOOL fClearDirty)
262 {
263     // Internal CISFBand Calls
264     CComPtr<IPersistStream> pIPS;
265     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IPersistStream, &pIPS));
266     if (FAILED(hr))
267         return hr;
268 
269     return pIPS->Save(pStm, fClearDirty);
270 }
271 
272 STDMETHODIMP CQuickLaunchBand::GetSizeMax(OUT ULARGE_INTEGER *pcbSize)
273 {
274     CComPtr<IPersistStream> pIPS;
275     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IPersistStream, &pIPS));
276     if (FAILED(hr))
277         return hr;
278 
279     return pIPS->GetSizeMax(pcbSize);
280 }
281 
282 /*****************************************************************************/
283 // IWinEventHandler
284 STDMETHODIMP CQuickLaunchBand::ContainsWindow(IN HWND hWnd)
285 {
286     return E_NOTIMPL;
287 }
288 
289 STDMETHODIMP CQuickLaunchBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
290 {
291      // Internal CISFBand Calls
292      CComPtr<IWinEventHandler> pWEH;
293      HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IWinEventHandler, &pWEH));
294      if (FAILED(hr))
295          return hr;
296 
297      return pWEH->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
298 }
299 
300 STDMETHODIMP CQuickLaunchBand::IsWindowOwner(HWND hWnd)
301 {
302     // Internal CISFBand Calls
303     CComPtr<IWinEventHandler> pWEH;
304     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IWinEventHandler, &pWEH));
305     if (FAILED(hr))
306         return hr;
307 
308     return pWEH->IsWindowOwner(hWnd);
309 }
310 
311 /*****************************************************************************/
312 // *** IOleCommandTarget methods ***
313 STDMETHODIMP CQuickLaunchBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
314 {
315     // Internal CISFBand Calls
316     CComPtr<IOleCommandTarget> pOCT;
317     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOCT));
318     if (FAILED(hr))
319         return hr;
320 
321     return pOCT->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
322 }
323 
324 STDMETHODIMP CQuickLaunchBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
325 {
326     // Internal CISFBand Calls
327     CComPtr<IOleCommandTarget> pOCT;
328     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOCT));
329     if (FAILED(hr))
330         return hr;
331 
332     return pOCT->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
333 }
334 
335 /*****************************************************************************/
336 // *** IContextMenu ***
337 STDMETHODIMP CQuickLaunchBand::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
338 {
339     // Internal CISFBand Calls
340     CComPtr<IContextMenu> pICM;
341     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IContextMenu, &pICM));
342     if (FAILED(hr))
343         return hr;
344 
345     return pICM->GetCommandString(idCmd, uFlags, pwReserved, pszName, cchMax);
346 }
347 
348 STDMETHODIMP CQuickLaunchBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
349 {
350     // Internal CISFBand Calls
351     CComPtr<IContextMenu> pICM;
352     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IContextMenu, &pICM));
353     if (FAILED(hr))
354         return hr;
355 
356     return pICM->InvokeCommand(pici);
357 }
358 
359 STDMETHODIMP CQuickLaunchBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
360 {
361     // Internal CISFBand Calls
362     CComPtr<IContextMenu> pICM;
363     HRESULT hr = m_punkISFB->QueryInterface(IID_PPV_ARG(IContextMenu, &pICM));
364     if (FAILED(hr))
365         return hr;
366 
367     return pICM->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
368 }
369