[BROWSEUI] -CBandSiteMenu: Add preliminary support for adding and removing bands...
[reactos.git] / reactos / dll / win32 / browseui / shellbars / CBandSiteMenu.cpp
1 /*
2 * Band site menu
3 *
4 * Copyright 2007 Hervé Poussineua
5 * Copyright 2009 Andrew Hill
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "shellbars.h"
23 #include <strsafe.h>
24
25 #define IDM_DESKBAND_BEGINCUSTOM 0x10
26 #define IDM_DESKBAND_ENDCUSTOM 0x25
27
28 CBandSiteMenu::CBandSiteMenu():
29 m_menuDsa(NULL),
30 m_hmenu(NULL)
31 {
32 }
33
34 CBandSiteMenu::~CBandSiteMenu()
35 {
36 if (m_hmenu)
37 DestroyMenu(m_hmenu);
38
39 if (m_menuDsa)
40 DSA_Destroy(m_menuDsa);
41
42 m_BandSite = NULL;
43 }
44
45
46 HRESULT CBandSiteMenu::CreateMenuPart()
47 {
48 WCHAR wszBandName[MAX_PATH];
49 WCHAR wszBandGUID[MAX_PATH];
50 WCHAR wRegKey[MAX_PATH];
51 UINT cBands;
52 DWORD dwDataSize;
53 CATID category = CATID_DeskBand;
54 HMENU hmenuToolbars;
55 DWORD dwRead;
56 CComPtr<IEnumGUID> pEnumGUID;
57 HRESULT hr;
58
59 if (m_hmenu)
60 DestroyMenu(m_hmenu);
61
62 if (m_menuDsa)
63 DSA_Destroy(m_menuDsa);
64
65 /* Load the template we will fill in */
66 m_hmenu = LoadMenuW(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCEW(IDM_TASKBAR_TOOLBARS));
67 if (!m_hmenu)
68 return HRESULT_FROM_WIN32(GetLastError());
69
70 m_menuDsa = DSA_Create(sizeof(GUID), 5);
71 if (!m_menuDsa)
72 return E_OUTOFMEMORY;
73
74 /* Get the handle of the submenu where the available items will be shown */
75 hmenuToolbars = GetSubMenu(m_hmenu, 0);
76
77 /* Create the category enumerator */
78 hr = SHEnumClassesOfCategories(1, &category, 0, NULL, &pEnumGUID);
79 if (FAILED_UNEXPECTEDLY(hr))
80 return hr;
81
82 /* Enumerate the classes in the CATID_DeskBand category */
83 cBands = 0;
84 do
85 {
86 GUID iter;
87 pEnumGUID->Next(1, &iter, &dwRead);
88 if (!dwRead)
89 continue;
90
91 if (!StringFromGUID2(iter, wszBandGUID, MAX_PATH))
92 continue;
93
94 /* Get the band name */
95 StringCchPrintfW(wRegKey, MAX_PATH, L"CLSID\\%s", wszBandGUID);
96 dwDataSize = MAX_PATH;
97 SHGetValue(HKEY_CLASSES_ROOT, wRegKey, NULL, NULL, wszBandName, &dwDataSize);
98
99 /* Insert it */
100 InsertMenu(hmenuToolbars, cBands, MF_BYPOSITION, DSA_GetItemCount(m_menuDsa), wszBandName);
101 DSA_AppendItem(m_menuDsa, &iter);
102 cBands++;
103 }
104 while (dwRead > 0);
105
106 return S_OK;
107 }
108
109 HRESULT STDMETHODCALLTYPE CBandSiteMenu::SetOwner(IUnknown *pOwner)
110 {
111 TRACE("CBandSiteMenu::SetOwner(%p, %p)\n", this, pOwner);
112
113 /* Cache the menu that will be merged every time QueryContextMenu is called */
114 CreateMenuPart();
115
116 return pOwner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite));
117 }
118
119 HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu(
120 HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
121 {
122 CComPtr<IPersist> pBand;
123 CLSID BandCLSID;
124 DWORD dwBandID;
125 UINT uBand = 0;
126
127 TRACE("CBandSiteMenu::QueryContextMenu(%p, %p, %u, %u, %u, 0x%x)\n", this, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
128
129 /* First Merge the menu with the available bands */
130 Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
131
132 HMENU hmenuToolbars = GetSubMenu(hmenu, indexMenu);
133
134 /* Enumerate all present bands and mark them as checked in the menu */
135 while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
136 {
137 if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
138 continue;
139
140 if (FAILED(pBand->GetClassID(&BandCLSID)))
141 continue;
142
143 /* Try to find the clsid of the band in the dsa */
144 UINT count = DSA_GetItemCount(m_menuDsa);
145 for (UINT i = 0; i < count; i++)
146 {
147 GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_menuDsa, i);
148 if (memcmp(pdsaGUID, &BandCLSID, sizeof(GUID)) == 0)
149 {
150 /* The index in the dsa is also the index in the menu */
151 CheckMenuItem(hmenuToolbars, i, MF_CHECKED | MF_BYPOSITION);
152 }
153 }
154
155 uBand++;
156 }
157
158 return S_OK;
159 }
160
161 HRESULT STDMETHODCALLTYPE CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
162 {
163 /* FIXME: do we need to handle this and how? */
164 if (HIWORD(lpici->lpVerb) != NULL)
165 return E_FAIL;
166
167 /* Get the GUID of the item that was clicked */
168 UINT uID = LOWORD(lpici->lpVerb);
169 GUID *pguidToolbar = (GUID *)DSA_GetItemPtr(m_menuDsa, uID);
170 if (!pguidToolbar)
171 return E_FAIL;
172
173 /* Try to find if a band with a guid is present. If it is remove it and return */
174 CComPtr<IPersist> pBand;
175 CLSID BandCLSID;
176 DWORD dwBandID;
177 UINT uBand = 0;
178 while (SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)))
179 {
180 if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand))))
181 continue;
182
183 if (FAILED(pBand->GetClassID(&BandCLSID)))
184 continue;
185
186 if (memcmp(pguidToolbar, &BandCLSID, sizeof(GUID)) == 0)
187 {
188 /* We found it, remove it */
189 m_BandSite->RemoveBand(dwBandID);
190 return S_OK;
191 }
192
193 uBand++;
194 }
195
196 /* It is not present. Add it. */
197 CComPtr<IDeskBand> pDeskBand;
198 HRESULT hRet = CoCreateInstance(*pguidToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pDeskBand));
199 if (FAILED(hRet))
200 return hRet;
201
202 hRet = m_BandSite->AddBand(pDeskBand);
203 if (FAILED_UNEXPECTEDLY(hRet))
204 return hRet;
205
206 return S_OK;
207 }
208
209 HRESULT STDMETHODCALLTYPE CBandSiteMenu::GetCommandString(UINT_PTR idCmd, UINT uType,
210 UINT *pwReserved, LPSTR pszName, UINT cchMax)
211 {
212 FIXME("CBandSiteMenu::GetCommandString is UNIMPLEMENTED (%p, %p, %u, %p, %p, %u)\n", this, idCmd, uType, pwReserved, pszName, cchMax);
213 return E_NOTIMPL;
214 }
215
216 HRESULT STDMETHODCALLTYPE CBandSiteMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
217 {
218 FIXME("CBandSiteMenu::HandleMenuMsg is UNIMPLEMENTED (%p, %u, %p, %p)\n", this, uMsg, wParam, lParam);
219 return E_NOTIMPL;
220 }
221
222 HRESULT STDMETHODCALLTYPE CBandSiteMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
223 {
224 FIXME("CBandSiteMenu::HandleMenuMsg2 is UNIMPLEMENTED(%p, %u, %p, %p, %p)\n", this, uMsg, wParam, lParam, plResult);
225 return E_NOTIMPL;
226 }
227
228 extern "C"
229 HRESULT WINAPI CBandSiteMenu_CreateInstance(REFIID riid, void **ppv)
230 {
231 return ShellObjectCreator<CBandSiteMenu>(riid, ppv);
232 }