[QCKLNCH] Remove qcklnch (#61)
[reactos.git] / dll / win32 / browseui / shellbars / CISFBand.cpp
1 /*
2 * PROJECT: ReactOS shell extensions
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/shellext/qcklnch/CISFBand.cpp
5 * PURPOSE: Quick Launch Toolbar (Taskbar Shell Extension)
6 * PROGRAMMERS: Shriraj Sawant a.k.a SR13 <sr.official@hotmail.com>
7 */
8
9 #include "shellbars.h"
10 #include <commoncontrols.h>
11 #include <strsafe.h>
12
13 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
14 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
15
16 // ***Extras***
17 /*++
18 * @name _ILIsDesktop
19 *
20 * Checks whether the given PIDL is of Desktop folder or not.
21 *
22 * @param pidl
23 * PIDL to be checked.
24 *
25 * @return True if PIDL is of Desktop, otherwise false.
26 *
27 *--*/
28 static BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
29 {
30 return (pidl == NULL || pidl->mkid.cb == 0);
31 }
32
33 //*****************************************************************************************
34 // *** CISFBand ***
35
36 CISFBand::CISFBand() :
37 m_BandID(0),
38 m_pidl(NULL),
39 m_textFlag(true),
40 m_iconFlag(true)
41 {
42 }
43
44 CISFBand::~CISFBand()
45 {
46 CloseDW(0);
47 }
48
49 // Toolbar
50 /*++
51 * @name CreateSimpleToolbar
52 *
53 * Creates a toolbar and fills it up with buttons for enumerated objects.
54 *
55 * @param hWndParent
56 * Handle to the parent window, which receives the appropriate messages from child toolbar.
57 *
58 * @return The error code.
59 *
60 *--*/
61 HRESULT CISFBand::CreateSimpleToolbar(HWND hWndParent)
62 {
63 // Declare and initialize local constants.
64 const DWORD buttonStyles = BTNS_AUTOSIZE;
65
66 // Create the toolbar.
67 m_hWnd = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
68 WS_CHILD | TBSTYLE_FLAT | TBSTYLE_LIST | CCS_NORESIZE | CCS_NODIVIDER, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
69 hWndParent, NULL, 0, NULL);
70 if (m_hWnd == NULL)
71 return E_FAIL;
72
73 // Set the image list.
74 HIMAGELIST* piml;
75 HRESULT hr = SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&piml);
76 if (FAILED_UNEXPECTEDLY(hr))
77 {
78 DestroyWindow();
79 return hr;
80 }
81 SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
82
83 // Enumerate objects
84 CComPtr<IEnumIDList> pEndl;
85 LPITEMIDLIST pidl;
86 STRRET stret;
87 hr = m_pISF->EnumObjects(0, SHCONTF_FOLDERS, &pEndl);
88 if (FAILED_UNEXPECTEDLY(hr))
89 {
90 DestroyWindow();
91 return hr;
92 }
93
94 for (int i=0; pEndl->Next(1, &pidl, NULL) != S_FALSE; i++)
95 {
96 WCHAR sz[MAX_PATH];
97 int index = SHMapPIDLToSystemImageListIndex(m_pISF, pidl, NULL);
98 hr = m_pISF->GetDisplayNameOf(pidl, SHGDN_NORMAL, &stret);
99 if (FAILED_UNEXPECTEDLY(hr))
100 {
101 StringCchCopyW(sz, MAX_PATH, L"<Unknown-Name>");
102 }
103 else
104 StrRetToBuf(&stret, pidl, sz, _countof(sz));
105
106 TBBUTTON tb = { MAKELONG(index, 0), i, TBSTATE_ENABLED, buttonStyles,{ 0 }, (DWORD_PTR)pidl, (INT_PTR)sz };
107 SendMessage(m_hWnd, TB_INSERTBUTTONW, i, (LPARAM)&tb);
108 }
109
110 // Resize the toolbar, and then show it.
111 SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0);
112
113 return hr;
114 }
115
116 /*****************************************************************************/
117
118 // *** IObjectWithSite ***
119 STDMETHODIMP CISFBand::SetSite(IUnknown *pUnkSite)
120 {
121 HRESULT hr;
122 HWND hwndParent;
123
124 TRACE("CISFBand::SetSite(0x%p)\n", pUnkSite);
125
126 hr = IUnknown_GetWindow(pUnkSite, &hwndParent);
127 if (FAILED(hr))
128 {
129 TRACE("Querying site window failed: 0x%x\n", hr);
130 return hr;
131 }
132 m_Site = pUnkSite;
133
134 hr = CreateSimpleToolbar(hwndParent);
135 if (FAILED_UNEXPECTEDLY(hr))
136 return hr;
137
138 return S_OK;
139 }
140
141 STDMETHODIMP CISFBand::GetSite(IN REFIID riid, OUT VOID **ppvSite)
142 {
143 TRACE("CISFBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
144
145 HRESULT hr;
146 if (m_Site != NULL)
147 {
148 hr = m_Site->QueryInterface(riid, ppvSite);
149 if (FAILED(hr)) return hr;
150 }
151
152 *ppvSite = NULL;
153 return E_FAIL;
154 }
155
156 /*****************************************************************************/
157 // *** IDeskBand ***
158 STDMETHODIMP CISFBand::GetWindow(OUT HWND *phwnd)
159 {
160 if (!m_hWnd)
161 return E_FAIL;
162 if (!phwnd)
163 return E_POINTER;
164 *phwnd = m_hWnd;
165
166 return S_OK;
167 }
168
169 STDMETHODIMP CISFBand::ContextSensitiveHelp(IN BOOL fEnterMode)
170 {
171 /* FIXME: Implement */
172 return E_NOTIMPL;
173 }
174
175 STDMETHODIMP CISFBand::ShowDW(IN BOOL bShow)
176 {
177 if (m_hWnd)
178 {
179 ShowWindow(bShow ? SW_SHOW : SW_HIDE);
180 return S_OK;
181 }
182
183 return E_FAIL;
184 }
185
186 STDMETHODIMP CISFBand::CloseDW(IN DWORD dwReserved)
187 {
188 if (m_hWnd)
189 {
190 ShowWindow(SW_HIDE);
191
192 TBBUTTON tb;
193 for (int i = 0; SendMessage(m_hWnd, TB_GETBUTTON, i, (LPARAM)&tb); i++)
194 {
195 CoTaskMemFree((LPITEMIDLIST)tb.dwData);
196 }
197
198 DestroyWindow();
199 m_hWnd = NULL;
200 return S_OK;
201 }
202
203 return E_FAIL;
204 }
205
206 STDMETHODIMP CISFBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
207 {
208 /* No need to implement this method */
209
210 return E_NOTIMPL;
211 }
212
213 STDMETHODIMP CISFBand::GetBandInfo(IN DWORD dwBandID, IN DWORD dwViewMode, IN OUT DESKBANDINFO *pdbi)
214 {
215 TRACE("CTaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, m_hWnd);
216
217 if (m_hWnd && pdbi)
218 {
219 m_BandID = dwBandID;
220
221 RECT actualRect;
222 POINTL actualSize;
223 POINTL idealSize;
224 POINTL maxSize;
225 POINTL itemSize;
226
227 GetWindowRect(&actualRect);
228 actualSize.x = actualRect.right - actualRect.left;
229 actualSize.y = actualRect.bottom - actualRect.top;
230
231 // Obtain the ideal size, to be used as min and max
232 SendMessageW(m_hWnd, TB_AUTOSIZE, 0, 0);
233 SendMessageW(m_hWnd, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&maxSize));
234
235 idealSize = maxSize;
236 SendMessageW(m_hWnd, TB_GETIDEALSIZE, FALSE, reinterpret_cast<LPARAM>(&idealSize));
237
238 // Obtain the button size, to be used as the integral size
239 DWORD size = SendMessageW(m_hWnd, TB_GETBUTTONSIZE, 0, 0);
240 itemSize.x = GET_X_LPARAM(size);
241 itemSize.y = GET_Y_LPARAM(size);
242
243 if (pdbi->dwMask & DBIM_MINSIZE)
244 {
245 pdbi->ptMinSize.x = -1;
246 pdbi->ptMinSize.y = idealSize.y;
247 }
248 if (pdbi->dwMask & DBIM_MAXSIZE)
249 {
250 pdbi->ptMaxSize = maxSize;
251 }
252 if (pdbi->dwMask & DBIM_INTEGRAL)
253 {
254 pdbi->ptIntegral = itemSize;
255 }
256 if (pdbi->dwMask & DBIM_ACTUAL)
257 {
258 pdbi->ptActual = actualSize;
259 }
260 if (pdbi->dwMask & DBIM_TITLE)
261 wcscpy(pdbi->wszTitle, L"Quick Launch");
262 if (pdbi->dwMask & DBIM_MODEFLAGS)
263 {
264 pdbi->dwModeFlags = DBIMF_NORMAL | DBIMF_VARIABLEHEIGHT | DBIMF_USECHEVRON | DBIMF_NOMARGINS | DBIMF_BKCOLOR | DBIMF_ADDTOFRONT;
265 }
266 if (pdbi->dwMask & DBIM_BKCOLOR)
267 pdbi->dwMask &= ~DBIM_BKCOLOR;
268
269 return S_OK;
270 }
271
272 return E_FAIL;
273 }
274
275 /*****************************************************************************/
276 // *** IPersistStream ***
277 STDMETHODIMP CISFBand::GetClassID(OUT CLSID *pClassID)
278 {
279 *pClassID = CLSID_ISFBand;
280
281 return S_OK;
282 }
283
284 STDMETHODIMP CISFBand::IsDirty()
285 {
286 /* The object hasn't changed since the last save! */
287
288 return S_FALSE;
289 }
290
291 STDMETHODIMP CISFBand::Load(IN IStream *pStm)
292 {
293 TRACE("CISFBand::Load called\n");
294 /* Nothing to do */
295
296 return S_OK;
297 }
298
299 STDMETHODIMP CISFBand::Save(IN IStream *pStm, IN BOOL fClearDirty)
300 {
301 /* Nothing to do */
302
303 return S_OK;
304 }
305
306 STDMETHODIMP CISFBand::GetSizeMax(OUT ULARGE_INTEGER *pcbSize)
307 {
308 TRACE("CISFBand::GetSizeMax called\n");
309
310 return S_OK;
311 }
312
313 /*****************************************************************************/
314 // *** IWinEventHandler ***
315 STDMETHODIMP CISFBand::ContainsWindow(IN HWND hWnd)
316 {
317 if (hWnd == m_hWnd || IsChild(hWnd))
318 {
319 TRACE("CISFBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
320 return S_OK;
321 }
322
323 return S_FALSE;
324 }
325
326 STDMETHODIMP CISFBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
327 {
328 switch (uMsg)
329 {
330 case WM_COMMAND:
331 {
332 TBBUTTON tb;
333 bool chk = SendMessage(m_hWnd, TB_GETBUTTON, LOWORD(wParam), (LPARAM)&tb);
334 if (chk)
335 SHInvokeDefaultCommand(m_hWnd, m_pISF, (LPITEMIDLIST)tb.dwData);
336
337 *theResult = TRUE;
338 break;
339 }
340 case WM_NOTIFY:
341 {
342 switch (((LPNMHDR)lParam)->code)
343 {
344 case NM_RCLICK:
345 {
346 HRESULT hr;
347 POINT pt = ((LPNMMOUSE)lParam)->pt;
348 CComPtr<IContextMenu> picm;
349 HMENU fmenu = CreatePopupMenu();
350 TBBUTTON tb;
351
352 bool chk = SendMessage(m_hWnd, TB_GETBUTTON, ((LPNMMOUSE)lParam)->dwItemSpec, (LPARAM)&tb);
353 LPITEMIDLIST pidl = (LPITEMIDLIST)tb.dwData;
354
355 if (chk)
356 {
357 ClientToScreen(&pt);
358 hr = m_pISF->GetUIObjectOf(m_hWnd, 1, &pidl, IID_NULL_PPV_ARG(IContextMenu, &picm));
359 if (FAILED_UNEXPECTEDLY(hr))
360 return hr;
361
362 hr = picm->QueryContextMenu(fmenu, 0, 1, 0x7FFF, CMF_DEFAULTONLY);
363 if (FAILED_UNEXPECTEDLY(hr))
364 return hr;
365
366 int id = TrackPopupMenuEx(fmenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RETURNCMD, pt.x, pt.y, m_hWnd, 0);
367 if (id > 0)
368 {
369 CMINVOKECOMMANDINFOEX info = { 0 };
370 info.cbSize = sizeof(info);
371 info.fMask = CMIC_MASK_PTINVOKE;
372 if (GetKeyState(VK_CONTROL) < 0)
373 {
374 info.fMask |= CMIC_MASK_CONTROL_DOWN;
375 }
376 if (GetKeyState(VK_SHIFT) < 0)
377 {
378 info.fMask |= CMIC_MASK_SHIFT_DOWN;
379 }
380 info.hwnd = m_hWnd;
381 info.lpVerb = MAKEINTRESOURCEA(id - 1);
382 info.nShow = SW_SHOWNORMAL;
383 info.ptInvoke = pt;
384 picm->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);
385 }
386 }
387 DestroyMenu(fmenu);
388
389 *theResult = TRUE;
390 break;
391 }
392 default:
393 *theResult = FALSE;
394 }
395
396 break;
397 }
398 default:
399 *theResult = FALSE;
400 }
401
402 return S_OK;
403 }
404
405 STDMETHODIMP CISFBand::IsWindowOwner(HWND hWnd)
406 {
407 return (hWnd == m_hWnd) ? S_OK : S_FALSE;
408 }
409
410 /*****************************************************************************/
411 // *** IOleCommandTarget methods ***
412 STDMETHODIMP CISFBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
413 {
414 UNIMPLEMENTED;
415
416 return E_NOTIMPL;
417 }
418
419 STDMETHODIMP CISFBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
420 {
421 if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
422 {
423 return S_OK;
424 }
425
426 if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
427 {
428 return S_OK;
429 }
430
431 UNIMPLEMENTED;
432
433 return E_NOTIMPL;
434 }
435
436 /*****************************************************************************/
437 // *** IShellFolderBand ***
438 STDMETHODIMP CISFBand::GetBandInfoSFB(PBANDINFOSFB pbi)
439 {
440 return E_NOTIMPL;
441 }
442
443 STDMETHODIMP CISFBand::InitializeSFB(IShellFolder *psf, PCIDLIST_ABSOLUTE pidl)
444 {
445 if (_ILIsDesktop(pidl))
446 {
447 m_pISF = psf;
448 m_pidl = ILClone(pidl);
449 }
450 else
451 {
452 psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &m_pISF));
453 m_pidl = ILClone(pidl);
454 }
455
456 return S_OK;
457 }
458
459 STDMETHODIMP CISFBand::SetBandInfoSFB( PBANDINFOSFB pbi)
460 {
461 return E_NOTIMPL;
462 }
463
464 /*****************************************************************************/
465 // *** IContextMenu ***
466 STDMETHODIMP CISFBand::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
467 {
468 /*HRESULT hr = E_INVALIDARG;
469
470 if (idCmd == IDM_DISPLAY)
471 {
472 switch (uFlags)
473 {
474 case GCS_HELPTEXTW:
475 // Only useful for pre-Vista versions of Windows that
476 // have a Status bar.
477 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
478 cchMax,
479 L"Display File Name");
480 break;
481
482 case GCS_VERBW:
483 // GCS_VERBW is an optional feature that enables a caller
484 // to discover the canonical name for the verb that is passed in
485 // through idCommand.
486 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
487 cchMax,
488 L"DisplayFileName");
489 break;
490 }
491 }
492 return hr; */
493
494 return S_OK;
495 }
496
497 STDMETHODIMP CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
498 {
499 if (!HIWORD(pici->lpVerb))
500 {
501 switch (LOWORD(pici->lpVerb))
502 {
503 case IDM_LARGE_ICONS:
504 {
505 m_iconFlag = false;
506
507 HIMAGELIST* piml = (HIMAGELIST*) SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
508 HRESULT hr = SHGetImageList(SHIL_LARGE, IID_IImageList, (void**)&piml);
509 if (FAILED_UNEXPECTEDLY(hr)) return hr;
510 SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
511 hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
512 if (FAILED_UNEXPECTEDLY(hr)) return hr;
513 break;
514 }
515 case IDM_SMALL_ICONS:
516 {
517 m_iconFlag = true;
518
519 HIMAGELIST* piml = (HIMAGELIST*)SendMessage(m_hWnd, TB_GETIMAGELIST, 0, 0);
520 HRESULT hr = SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&piml);
521 if (FAILED_UNEXPECTEDLY(hr)) return hr;
522 SendMessage(m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)piml);
523 hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
524 if (FAILED_UNEXPECTEDLY(hr)) return hr;
525 break;
526 }
527 case IDM_SHOW_TEXT:
528 {
529 if (m_textFlag)
530 {
531 m_textFlag = false;
532 SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS);
533 HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
534 if (FAILED_UNEXPECTEDLY(hr)) return hr;
535 }
536 else
537 {
538 m_textFlag = true;
539 SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, 0);
540 HRESULT hr = IUnknown_Exec(m_Site, IID_IDeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
541 if (FAILED_UNEXPECTEDLY(hr)) return hr;
542 }
543 break;
544 }
545 default:
546 return E_FAIL;
547 }
548 }
549
550 return S_OK;
551 }
552
553 STDMETHODIMP CISFBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
554 {
555 HMENU qMenu = LoadMenu(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCE(IDM_POPUPMENU));
556
557 if(m_textFlag)
558 CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_CHECKED);
559 else
560 CheckMenuItem(qMenu, IDM_SHOW_TEXT, MF_UNCHECKED);
561
562 if (m_iconFlag)
563 {
564 CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_CHECKED);
565 CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_UNCHECKED);
566 }
567 else
568 {
569 CheckMenuItem(qMenu, IDM_LARGE_ICONS, MF_CHECKED);
570 CheckMenuItem(qMenu, IDM_SMALL_ICONS, MF_UNCHECKED);
571 }
572
573 UINT idMax = Shell_MergeMenus(hmenu, GetSubMenu(qMenu, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
574 DestroyMenu(qMenu);
575 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idMax - idCmdFirst +1));
576 }
577
578 /*****************************************************************************/
579 // C Constructor
580 extern "C"
581 HRESULT WINAPI CISFBand_CreateInstance(REFIID riid, void** ppv)
582 {
583 return ShellObjectCreator<CISFBand>(riid, ppv);
584 }
585