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>
10 #include <commoncontrols.h>
13 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
14 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
18 ** drag and drop support
20 ** handle change notifications
21 ** Fix position of the items context menu
22 ** Implement responding to theme change
30 * Checks whether the given PIDL is of Desktop folder or not.
35 * @return True if PIDL is of Desktop, otherwise false.
38 static BOOL
_ILIsDesktop(LPCITEMIDLIST pidl
)
40 return (pidl
== NULL
|| pidl
->mkid
.cb
== 0);
43 //*****************************************************************************************
46 CISFBand::CISFBand() :
62 * @name CreateSimpleToolbar
64 * Creates a toolbar and fills it up with buttons for enumerated objects.
67 * Handle to the parent window, which receives the appropriate messages from child toolbar.
69 * @return The error code.
72 HRESULT
CISFBand::CreateSimpleToolbar(HWND hWndParent
)
74 // Declare and initialize local constants.
75 const DWORD buttonStyles
= BTNS_AUTOSIZE
;
77 // Create the toolbar.
78 m_hWnd
= CreateWindowEx(0, TOOLBARCLASSNAME
, NULL
,
79 WS_CHILD
| TBSTYLE_FLAT
| TBSTYLE_LIST
| CCS_NORESIZE
| CCS_NODIVIDER
, CW_USEDEFAULT
, CW_USEDEFAULT
, 0, 0,
80 hWndParent
, NULL
, 0, NULL
);
85 SendMessage(m_hWnd
, TB_SETEXTENDEDSTYLE
, 0, TBSTYLE_EX_MIXEDBUTTONS
);
87 // Set the image list.
89 HRESULT hr
= SHGetImageList(SHIL_SMALL
, IID_IImageList
, (void**)&piml
);
90 if (FAILED_UNEXPECTEDLY(hr
))
95 SendMessage(m_hWnd
, TB_SETIMAGELIST
, 0, (LPARAM
)piml
);
98 CComPtr
<IEnumIDList
> pEndl
;
101 hr
= m_pISF
->EnumObjects(0, SHCONTF_FOLDERS
|SHCONTF_NONFOLDERS
, &pEndl
);
102 if (FAILED_UNEXPECTEDLY(hr
))
108 for (int i
=0; pEndl
->Next(1, &pidl
, NULL
) != S_FALSE
; i
++)
111 int index
= SHMapPIDLToSystemImageListIndex(m_pISF
, pidl
, NULL
);
112 hr
= m_pISF
->GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &stret
);
113 if (FAILED_UNEXPECTEDLY(hr
))
115 StringCchCopyW(sz
, MAX_PATH
, L
"<Unknown-Name>");
118 StrRetToBuf(&stret
, pidl
, sz
, _countof(sz
));
120 TBBUTTON tb
= { MAKELONG(index
, 0), i
, TBSTATE_ENABLED
, buttonStyles
,{ 0 }, (DWORD_PTR
)pidl
, (INT_PTR
)sz
};
121 SendMessage(m_hWnd
, TB_INSERTBUTTONW
, i
, (LPARAM
)&tb
);
124 // Resize the toolbar, and then show it.
125 SendMessage(m_hWnd
, TB_AUTOSIZE
, 0, 0);
130 /*****************************************************************************/
132 // *** IObjectWithSite ***
133 STDMETHODIMP
CISFBand::SetSite(IUnknown
*pUnkSite
)
138 TRACE("CISFBand::SetSite(0x%p)\n", pUnkSite
);
140 hr
= IUnknown_GetWindow(pUnkSite
, &hwndParent
);
143 TRACE("Querying site window failed: 0x%x\n", hr
);
148 hr
= CreateSimpleToolbar(hwndParent
);
149 if (FAILED_UNEXPECTEDLY(hr
))
155 STDMETHODIMP
CISFBand::GetSite(IN REFIID riid
, OUT VOID
**ppvSite
)
157 TRACE("CISFBand::GetSite(0x%p,0x%p)\n", riid
, ppvSite
);
162 hr
= m_Site
->QueryInterface(riid
, ppvSite
);
163 if (FAILED(hr
)) return hr
;
170 /*****************************************************************************/
172 STDMETHODIMP
CISFBand::GetWindow(OUT HWND
*phwnd
)
183 STDMETHODIMP
CISFBand::ContextSensitiveHelp(IN BOOL fEnterMode
)
185 /* FIXME: Implement */
189 STDMETHODIMP
CISFBand::ShowDW(IN BOOL bShow
)
193 ShowWindow(bShow
? SW_SHOW
: SW_HIDE
);
200 STDMETHODIMP
CISFBand::CloseDW(IN DWORD dwReserved
)
207 for (int i
= 0; SendMessage(m_hWnd
, TB_GETBUTTON
, i
, (LPARAM
)&tb
); i
++)
209 CoTaskMemFree((LPITEMIDLIST
)tb
.dwData
);
220 STDMETHODIMP
CISFBand::ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
222 /* No need to implement this method */
227 STDMETHODIMP
CISFBand::GetBandInfo(IN DWORD dwBandID
, IN DWORD dwViewMode
, IN OUT DESKBANDINFO
*pdbi
)
229 TRACE("CTaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID
, dwViewMode
, pdbi
, m_hWnd
);
241 GetWindowRect(&actualRect
);
242 actualSize
.x
= actualRect
.right
- actualRect
.left
;
243 actualSize
.y
= actualRect
.bottom
- actualRect
.top
;
245 // Obtain the ideal size, to be used as min and max
246 SendMessageW(m_hWnd
, TB_AUTOSIZE
, 0, 0);
247 SendMessageW(m_hWnd
, TB_GETMAXSIZE
, 0, reinterpret_cast<LPARAM
>(&maxSize
));
250 SendMessageW(m_hWnd
, TB_GETIDEALSIZE
, FALSE
, reinterpret_cast<LPARAM
>(&idealSize
));
252 // Obtain the button size, to be used as the integral size
253 DWORD size
= SendMessageW(m_hWnd
, TB_GETBUTTONSIZE
, 0, 0);
254 itemSize
.x
= GET_X_LPARAM(size
);
255 itemSize
.y
= GET_Y_LPARAM(size
);
257 if (pdbi
->dwMask
& DBIM_MINSIZE
)
260 pdbi
->ptMinSize
.x
= idealSize
.x
;
262 pdbi
->ptMinSize
.x
= -1;
263 pdbi
->ptMinSize
.y
= idealSize
.y
;
265 if (pdbi
->dwMask
& DBIM_MAXSIZE
)
267 pdbi
->ptMaxSize
= maxSize
;
269 if (pdbi
->dwMask
& DBIM_INTEGRAL
)
271 pdbi
->ptIntegral
= itemSize
;
273 if (pdbi
->dwMask
& DBIM_ACTUAL
)
275 pdbi
->ptActual
= actualSize
;
277 if (pdbi
->dwMask
& DBIM_TITLE
)
279 if (m_QLaunch
|| !ILGetDisplayNameEx(NULL
, m_pidl
, pdbi
->wszTitle
, ILGDN_INFOLDER
))
281 pdbi
->dwMask
&= ~DBIM_TITLE
;
284 if (pdbi
->dwMask
& DBIM_MODEFLAGS
)
286 pdbi
->dwModeFlags
= DBIMF_NORMAL
| DBIMF_VARIABLEHEIGHT
| DBIMF_USECHEVRON
| DBIMF_NOMARGINS
| DBIMF_BKCOLOR
;
289 pdbi
->dwModeFlags
|= DBIMF_ADDTOFRONT
;
292 if (pdbi
->dwMask
& DBIM_BKCOLOR
)
293 pdbi
->dwMask
&= ~DBIM_BKCOLOR
;
301 /*****************************************************************************/
302 // *** IPersistStream ***
303 STDMETHODIMP
CISFBand::GetClassID(OUT CLSID
*pClassID
)
305 *pClassID
= CLSID_ISFBand
;
310 STDMETHODIMP
CISFBand::IsDirty()
312 /* The object hasn't changed since the last save! */
317 STDMETHODIMP
CISFBand::Load(IN IStream
*pStm
)
319 TRACE("CISFBand::Load called\n");
325 STDMETHODIMP
CISFBand::Save(IN IStream
*pStm
, IN BOOL fClearDirty
)
332 STDMETHODIMP
CISFBand::GetSizeMax(OUT ULARGE_INTEGER
*pcbSize
)
334 TRACE("CISFBand::GetSizeMax called\n");
339 /*****************************************************************************/
340 // *** IWinEventHandler ***
341 STDMETHODIMP
CISFBand::ContainsWindow(IN HWND hWnd
)
343 if (hWnd
== m_hWnd
|| IsChild(hWnd
))
345 TRACE("CISFBand::ContainsWindow(0x%p) returns S_OK\n", hWnd
);
352 STDMETHODIMP
CISFBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
359 bool chk
= SendMessage(m_hWnd
, TB_GETBUTTON
, LOWORD(wParam
), (LPARAM
)&tb
);
361 SHInvokeDefaultCommand(m_hWnd
, m_pISF
, (LPITEMIDLIST
)tb
.dwData
);
368 switch (((LPNMHDR
)lParam
)->code
)
373 POINT pt
= ((LPNMMOUSE
)lParam
)->pt
;
374 CComPtr
<IContextMenu
> picm
;
375 HMENU fmenu
= CreatePopupMenu();
378 bool chk
= SendMessage(m_hWnd
, TB_GETBUTTON
, ((LPNMMOUSE
)lParam
)->dwItemSpec
, (LPARAM
)&tb
);
379 LPITEMIDLIST pidl
= (LPITEMIDLIST
)tb
.dwData
;
384 hr
= m_pISF
->GetUIObjectOf(m_hWnd
, 1, &pidl
, IID_NULL_PPV_ARG(IContextMenu
, &picm
));
385 if (FAILED_UNEXPECTEDLY(hr
))
388 hr
= picm
->QueryContextMenu(fmenu
, 0, 1, 0x7FFF, CMF_DEFAULTONLY
);
389 if (FAILED_UNEXPECTEDLY(hr
))
392 int id
= TrackPopupMenuEx(fmenu
, TPM_LEFTALIGN
| TPM_BOTTOMALIGN
| TPM_RETURNCMD
, pt
.x
, pt
.y
, m_hWnd
, 0);
395 CMINVOKECOMMANDINFOEX info
= { 0 };
396 info
.cbSize
= sizeof(info
);
397 info
.fMask
= CMIC_MASK_PTINVOKE
;
398 if (GetKeyState(VK_CONTROL
) < 0)
400 info
.fMask
|= CMIC_MASK_CONTROL_DOWN
;
402 if (GetKeyState(VK_SHIFT
) < 0)
404 info
.fMask
|= CMIC_MASK_SHIFT_DOWN
;
407 info
.lpVerb
= MAKEINTRESOURCEA(id
- 1);
408 info
.nShow
= SW_SHOWNORMAL
;
410 picm
->InvokeCommand((LPCMINVOKECOMMANDINFO
)&info
);
431 STDMETHODIMP
CISFBand::IsWindowOwner(HWND hWnd
)
433 return (hWnd
== m_hWnd
) ? S_OK
: S_FALSE
;
436 /*****************************************************************************/
437 // *** IOleCommandTarget methods ***
438 STDMETHODIMP
CISFBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
445 STDMETHODIMP
CISFBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
447 if (IsEqualIID(*pguidCmdGroup
, IID_IBandSite
))
452 if (IsEqualIID(*pguidCmdGroup
, IID_IDeskBand
))
462 /*****************************************************************************/
463 // *** IShellFolderBand ***
464 STDMETHODIMP
CISFBand::GetBandInfoSFB(PBANDINFOSFB pbi
)
466 if (pbi
->dwMask
== ISFB_MASK_IDLIST
)
468 pbi
->pidl
= ILClone(m_pidl
);
470 return E_OUTOFMEMORY
;
477 STDMETHODIMP
CISFBand::InitializeSFB(IShellFolder
*psf
, PCIDLIST_ABSOLUTE pidl
)
489 CComPtr
<IShellFolder
> psfDesktop
;
490 hr
= SHGetDesktopFolder(&psfDesktop
);
491 if (FAILED_UNEXPECTEDLY(hr
))
494 if (_ILIsDesktop(pidl
))
500 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &m_pISF
));
501 if (FAILED_UNEXPECTEDLY(hr
))
505 m_pidl
= ILClone(pidl
);
510 CComPtr
<IPersistFolder2
> ppf2
;
511 hr
= psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
512 if (FAILED_UNEXPECTEDLY(hr
))
515 hr
= ppf2
->GetCurFolder(&m_pidl
);
516 if (FAILED_UNEXPECTEDLY(hr
))
525 STDMETHODIMP
CISFBand::SetBandInfoSFB( PBANDINFOSFB pbi
)
527 if ((pbi
->dwMask
& ISFB_MASK_STATE
) &&
528 (pbi
->dwState
& ISFB_STATE_QLINKSMODE
) &&
529 (pbi
->dwStateMask
& ISFB_STATE_QLINKSMODE
))
534 SendMessage(m_hWnd
, TB_SETEXTENDEDSTYLE
, 0, TBSTYLE_EX_MIXEDBUTTONS
);
540 /*****************************************************************************/
541 // *** IContextMenu ***
542 STDMETHODIMP
CISFBand::GetCommandString(UINT_PTR idCmd
, UINT uFlags
, UINT
*pwReserved
, LPSTR pszName
, UINT cchMax
)
544 /*HRESULT hr = E_INVALIDARG;
546 if (idCmd == IDM_DISPLAY)
551 // Only useful for pre-Vista versions of Windows that
552 // have a Status bar.
553 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
555 L"Display File Name");
559 // GCS_VERBW is an optional feature that enables a caller
560 // to discover the canonical name for the verb that is passed in
561 // through idCommand.
562 hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName),
573 STDMETHODIMP
CISFBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici
)
575 if (!HIWORD(pici
->lpVerb
))
577 switch (LOWORD(pici
->lpVerb
))
579 case IDM_LARGE_ICONS
:
583 HIMAGELIST
* piml
= (HIMAGELIST
*) SendMessage(m_hWnd
, TB_GETIMAGELIST
, 0, 0);
584 HRESULT hr
= SHGetImageList(SHIL_LARGE
, IID_IImageList
, (void**)&piml
);
585 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
586 SendMessage(m_hWnd
, TB_SETIMAGELIST
, 0, (LPARAM
)piml
);
587 hr
= IUnknown_Exec(m_Site
, IID_IDeskBand
, DBID_BANDINFOCHANGED
, 0, NULL
, NULL
);
588 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
591 case IDM_SMALL_ICONS
:
595 HIMAGELIST
* piml
= (HIMAGELIST
*)SendMessage(m_hWnd
, TB_GETIMAGELIST
, 0, 0);
596 HRESULT hr
= SHGetImageList(SHIL_SMALL
, IID_IImageList
, (void**)&piml
);
597 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
598 SendMessage(m_hWnd
, TB_SETIMAGELIST
, 0, (LPARAM
)piml
);
599 hr
= IUnknown_Exec(m_Site
, IID_IDeskBand
, DBID_BANDINFOCHANGED
, 0, NULL
, NULL
);
600 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
603 case IDM_OPEN_FOLDER
:
605 SHELLEXECUTEINFO shexinfo
;
607 memset(&shexinfo
, 0x0, sizeof(shexinfo
));
609 shexinfo
.cbSize
= sizeof(shexinfo
);
610 shexinfo
.fMask
= SEE_MASK_IDLIST
;
611 shexinfo
.lpVerb
= _T("open");
612 shexinfo
.lpIDList
= m_pidl
;
613 shexinfo
.nShow
= SW_SHOW
;
615 if (!ShellExecuteEx(&shexinfo
))
625 SendMessage(m_hWnd
, TB_SETEXTENDEDSTYLE
, 0, TBSTYLE_EX_MIXEDBUTTONS
);
626 HRESULT hr
= IUnknown_Exec(m_Site
, IID_IDeskBand
, DBID_BANDINFOCHANGED
, 0, NULL
, NULL
);
627 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
632 SendMessage(m_hWnd
, TB_SETEXTENDEDSTYLE
, 0, 0);
633 HRESULT hr
= IUnknown_Exec(m_Site
, IID_IDeskBand
, DBID_BANDINFOCHANGED
, 0, NULL
, NULL
);
634 if (FAILED_UNEXPECTEDLY(hr
)) return hr
;
646 STDMETHODIMP
CISFBand::QueryContextMenu(HMENU hmenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
648 HMENU qMenu
= LoadMenu(GetModuleHandleW(L
"browseui.dll"), MAKEINTRESOURCE(IDM_POPUPMENU
));
651 CheckMenuItem(qMenu
, IDM_SHOW_TEXT
, MF_CHECKED
);
653 CheckMenuItem(qMenu
, IDM_SHOW_TEXT
, MF_UNCHECKED
);
657 CheckMenuItem(qMenu
, IDM_SMALL_ICONS
, MF_CHECKED
);
658 CheckMenuItem(qMenu
, IDM_LARGE_ICONS
, MF_UNCHECKED
);
662 CheckMenuItem(qMenu
, IDM_LARGE_ICONS
, MF_CHECKED
);
663 CheckMenuItem(qMenu
, IDM_SMALL_ICONS
, MF_UNCHECKED
);
666 if (_ILIsDesktop(m_pidl
))
667 DeleteMenu(qMenu
, IDM_OPEN_FOLDER
, MF_BYCOMMAND
);
669 UINT idMax
= Shell_MergeMenus(hmenu
, GetSubMenu(qMenu
, 0), indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
);
671 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, USHORT(idMax
- idCmdFirst
+1));
674 /*****************************************************************************/
677 HRESULT WINAPI
RSHELL_CISFBand_CreateInstance(REFIID riid
, void** ppv
)
679 return ShellObjectCreator
<CISFBand
>(riid
, ppv
);