diff --git a/dll/win32/browseui/shellbars/CBandSiteMenu.cpp b/dll/win32/browseui/shellbars/CBandSiteMenu.cpp index 01a31e9f54c93..300a2ccb40732 100644 --- a/dll/win32/browseui/shellbars/CBandSiteMenu.cpp +++ b/dll/win32/browseui/shellbars/CBandSiteMenu.cpp @@ -22,9 +22,20 @@ #include "shellbars.h" #include +/* The menu consists of 3 parts. The first is loaded from the resources, + the second is populated with the classes of the CATID_DeskBand comcat + and the third part consists of the entries for each CISFBand in the band side. + The first 5 ids are reserved for the resource menu, the following ids will be + for the CATID_DeskBand classes and the rest for the CISFBands. + The ids for the CISFBand menu items are not continuous, in this range + each menu id is calculated by adding the band id to the last id for the CATID_DeskBand range */ +#define FIRST_COMCAT_MENU_ID 0x5 + CBandSiteMenu::CBandSiteMenu(): - m_menuDsa(NULL), - m_hmenu(NULL) + m_comcatDsa(NULL), + m_hmenu(NULL), + m_DesktopPidl(NULL), + m_QLaunchPidl(NULL) { } @@ -33,14 +44,37 @@ CBandSiteMenu::~CBandSiteMenu() if (m_hmenu) DestroyMenu(m_hmenu); - if (m_menuDsa) - DSA_Destroy(m_menuDsa); + if (m_comcatDsa) + DSA_Destroy(m_comcatDsa); + + if (m_DesktopPidl) + ILFree(m_DesktopPidl); + + if (m_QLaunchPidl) + ILFree(m_QLaunchPidl); m_BandSite = NULL; } +HRESULT WINAPI CBandSiteMenu::FinalConstruct() +{ + HRESULT hr = SHGetFolderLocation(0, CSIDL_DESKTOP, NULL, 0, &m_DesktopPidl); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + WCHAR buffer[MAX_PATH]; + hr = SHGetFolderPathAndSubDirW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, L"Microsoft\\Internet Explorer\\Quick Launch", buffer); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; -HRESULT CBandSiteMenu::CreateMenuPart() + m_QLaunchPidl = ILCreateFromPathW(buffer); + if (m_QLaunchPidl == NULL) + return E_FAIL; + + return S_OK; +} + +HRESULT CBandSiteMenu::_CreateMenuPart() { WCHAR wszBandName[MAX_PATH]; WCHAR wszBandGUID[MAX_PATH]; @@ -56,16 +90,16 @@ HRESULT CBandSiteMenu::CreateMenuPart() if (m_hmenu) DestroyMenu(m_hmenu); - if (m_menuDsa) - DSA_Destroy(m_menuDsa); + if (m_comcatDsa) + DSA_Destroy(m_comcatDsa); /* Load the template we will fill in */ m_hmenu = LoadMenuW(GetModuleHandleW(L"browseui.dll"), MAKEINTRESOURCEW(IDM_TASKBAR_TOOLBARS)); if (!m_hmenu) return HRESULT_FROM_WIN32(GetLastError()); - m_menuDsa = DSA_Create(sizeof(GUID), 5); - if (!m_menuDsa) + m_comcatDsa = DSA_Create(sizeof(GUID), 5); + if (!m_comcatDsa) return E_OUTOFMEMORY; /* Get the handle of the submenu where the available items will be shown */ @@ -94,8 +128,8 @@ HRESULT CBandSiteMenu::CreateMenuPart() SHGetValue(HKEY_CLASSES_ROOT, wRegKey, NULL, NULL, wszBandName, &dwDataSize); /* Insert it */ - InsertMenu(hmenuToolbars, cBands, MF_BYPOSITION, DSA_GetItemCount(m_menuDsa), wszBandName); - DSA_AppendItem(m_menuDsa, &iter); + InsertMenu(hmenuToolbars, cBands, MF_BYPOSITION, DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID, wszBandName); + DSA_AppendItem(m_comcatDsa, &iter); cBands++; } while (dwRead > 0); @@ -103,12 +137,197 @@ HRESULT CBandSiteMenu::CreateMenuPart() return S_OK; } +HRESULT CBandSiteMenu::_CreateNewISFBand(HWND hwnd, REFIID riid, void** ppv) +{ + WCHAR path[MAX_PATH]; + WCHAR message[256]; + BROWSEINFOW bi = { hwnd, NULL, path }; + + if (LoadStringW(GetModuleHandleW(L"browseui.dll"), IDS_BROWSEFORNEWTOOLAR, message, _countof(message))) + bi.lpszTitle = message; + else + bi.lpszTitle = L"Choose a folder"; + + LPITEMIDLIST pidlSelected = SHBrowseForFolderW(&bi); + if (pidlSelected == NULL) + return S_FALSE; + + CComPtr pISFB; + HRESULT hr = CISFBand_CreateInstance(IID_IShellFolderBand, (PVOID*)&pISFB); + if (FAILED_UNEXPECTEDLY(hr)) + goto done; + + hr = pISFB->InitializeSFB(NULL, pidlSelected); + if (FAILED_UNEXPECTEDLY(hr)) + goto done; + + hr = pISFB->QueryInterface(riid, ppv); + +done: + ILFree(pidlSelected); + return hr; +} + +HRESULT CBandSiteMenu::_CreateBuiltInISFBand(UINT uID, REFIID riid, void** ppv) +{ + LPITEMIDLIST pidl; + HRESULT hr; + + pidl = (uID == IDM_TASKBAR_TOOLBARS_DESKTOP) ? m_DesktopPidl : m_QLaunchPidl; + + CComPtr pISFB; + hr = CISFBand_CreateInstance(IID_IShellFolderBand, (PVOID*)&pISFB); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = pISFB->InitializeSFB(NULL, pidl); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return pISFB->QueryInterface(riid, ppv); +} + +HRESULT CBandSiteMenu::_AddISFBandToMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, IUnknown* pBand, DWORD dwBandID, UINT *newMenuId) +{ + CComPtr psfb; + HRESULT hr = pBand->QueryInterface(IID_PPV_ARG(IShellFolderBand, &psfb)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + BANDINFOSFB bi = {ISFB_MASK_IDLIST}; + hr = psfb->GetBandInfoSFB(&bi); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (!bi.pidl) + return E_OUTOFMEMORY; + + WCHAR buffer[MAX_PATH]; + hr = ILGetDisplayNameEx(NULL, bi.pidl, buffer, ILGDN_INFOLDER) ? S_OK : E_FAIL; + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + UINT id = idCmdFirst + DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID + dwBandID; + if (id >= idCmdLast) + return E_FAIL; + + *newMenuId = id; + InsertMenu(hmenu, indexMenu, MF_BYPOSITION, id, buffer); + return S_OK; +} + +UINT CBandSiteMenu::_GetMenuIdFromISFBand(IUnknown *pBand) +{ + UINT ret = UINT_MAX; + + CComPtr psfb; + HRESULT hr = pBand->QueryInterface(IID_PPV_ARG(IShellFolderBand, &psfb)); + if (FAILED_UNEXPECTEDLY(hr)) + return ret; + + BANDINFOSFB bi = {ISFB_MASK_IDLIST}; + hr = psfb->GetBandInfoSFB(&bi); + if (FAILED_UNEXPECTEDLY(hr)) + return ret; + + CComPtr psfDesktop; + LPITEMIDLIST pidl = bi.pidl; + if (!pidl) + return ret; + + if (pidl->mkid.cb == 0) + { + ret = IDM_TASKBAR_TOOLBARS_DESKTOP; + goto done; + } + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED_UNEXPECTEDLY(hr)) + goto done; + + hr = psfDesktop->CompareIDs(0, pidl, m_QLaunchPidl); + if (FAILED_UNEXPECTEDLY(hr)) + goto done; + + if (HRESULT_CODE(hr) == 0) + ret = IDM_TASKBAR_TOOLBARS_QUICKLAUNCH; + +done: + if (pidl) + ILFree(pidl); + + return ret; +} + +UINT CBandSiteMenu::_GetMenuIdFromBand(CLSID *BandCLSID) +{ + /* Try to find the clsid of the band in the dsa */ + UINT count = DSA_GetItemCount(m_comcatDsa); + for (UINT i = 0; i < count; i++) + { + GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_comcatDsa, i); + if (IsEqualGUID(*pdsaGUID, *BandCLSID)) + { + /* The index in the dsa is also the index in the menu */ + return i + FIRST_COMCAT_MENU_ID; + } + } + + return UINT_MAX; +} + +UINT CBandSiteMenu::_GetBandIdFromClsid(CLSID* pclsid) +{ + CComPtr pBand; + CLSID BandCLSID; + DWORD dwBandID; + + for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++) + { + if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand)))) + continue; + + if (FAILED(pBand->GetClassID(&BandCLSID))) + continue; + + if (IsEqualGUID(*pclsid, BandCLSID)) + return dwBandID; + } + + return UINT_MAX; +} + +UINT CBandSiteMenu::_GetBandIdForBuiltinISFBand(UINT uID) +{ + CComPtr pBand; + CLSID BandCLSID; + DWORD dwBandID; + + for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++) + { + if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand)))) + continue; + + if (FAILED(pBand->GetClassID(&BandCLSID))) + continue; + + if (!IsEqualGUID(BandCLSID, CLSID_ISFBand)) + continue; + + UINT menuID = _GetMenuIdFromISFBand(pBand); + if (menuID == uID) + return dwBandID; + } + + return UINT_MAX; +} + HRESULT STDMETHODCALLTYPE CBandSiteMenu::SetOwner(IUnknown *pOwner) { TRACE("CBandSiteMenu::SetOwner(%p, %p)\n", this, pOwner); /* Cache the menu that will be merged every time QueryContextMenu is called */ - CreateMenuPart(); + _CreateMenuPart(); return pOwner->QueryInterface(IID_PPV_ARG(IBandSite, &m_BandSite)); } @@ -119,11 +338,12 @@ HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu( CComPtr pBand; CLSID BandCLSID; DWORD dwBandID; + UINT idMax; TRACE("CBandSiteMenu::QueryContextMenu(%p, %p, %u, %u, %u, 0x%x)\n", this, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags); /* First Merge the menu with the available bands */ - Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS); + idMax = Shell_MergeMenus(hmenu, m_hmenu, indexMenu, idCmdFirst, idCmdLast, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS); HMENU hmenuToolbars = GetSubMenu(hmenu, indexMenu); @@ -136,63 +356,107 @@ HRESULT STDMETHODCALLTYPE CBandSiteMenu::QueryContextMenu( if (FAILED(pBand->GetClassID(&BandCLSID))) continue; - /* Try to find the clsid of the band in the dsa */ - UINT count = DSA_GetItemCount(m_menuDsa); - for (UINT i = 0; i < count; i++) + UINT menuID; + if (IsEqualGUID(BandCLSID, CLSID_ISFBand)) { - GUID* pdsaGUID = (GUID*)DSA_GetItemPtr(m_menuDsa, i); - if (memcmp(pdsaGUID, &BandCLSID, sizeof(GUID)) == 0) + menuID = _GetMenuIdFromISFBand(pBand); + if (menuID == UINT_MAX) { - /* The index in the dsa is also the index in the menu */ - CheckMenuItem(hmenuToolbars, i, MF_CHECKED | MF_BYPOSITION); + HRESULT hr; + hr = _AddISFBandToMenu(hmenuToolbars, 0, idCmdFirst, idCmdLast, pBand, dwBandID, &menuID); + if (SUCCEEDED(hr) && menuID > idMax) + idMax = menuID; + menuID -= idCmdFirst; } } + else + { + menuID = _GetMenuIdFromBand(&BandCLSID); + } + + if (menuID != UINT_MAX) + CheckMenuItem(hmenuToolbars, menuID + idCmdFirst, MF_CHECKED); } - return S_OK; + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idMax - idCmdFirst +1)); } HRESULT STDMETHODCALLTYPE CBandSiteMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) { + HRESULT hRet; + DWORD dwBandID; + /* FIXME: do we need to handle this and how? */ if (HIWORD(lpici->lpVerb) != NULL) return E_FAIL; - /* Get the GUID of the item that was clicked */ UINT uID = LOWORD(lpici->lpVerb); - GUID *pguidToolbar = (GUID *)DSA_GetItemPtr(m_menuDsa, uID); - if (!pguidToolbar) - return E_FAIL; + if (uID == IDM_TASKBAR_TOOLBARS_NEW) + { + CComPtr pDeskBand; + hRet = _CreateNewISFBand(lpici->hwnd, IID_PPV_ARG(IDeskBand, &pDeskBand)); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; - /* Try to find if a band with a guid is present. If it is remove it and return */ - CComPtr pBand; - CLSID BandCLSID; - DWORD dwBandID; - for (UINT uBand = 0; SUCCEEDED(m_BandSite->EnumBands(uBand, &dwBandID)); uBand++) + hRet = m_BandSite->AddBand(pDeskBand); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; + + return S_OK; + } + else if (uID > (UINT)DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID ) { - if (FAILED(m_BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IPersist, &pBand)))) - continue; + dwBandID = uID - (DSA_GetItemCount(m_comcatDsa) + FIRST_COMCAT_MENU_ID ); - if (FAILED(pBand->GetClassID(&BandCLSID))) - continue; + m_BandSite->RemoveBand(dwBandID); - if (memcmp(pguidToolbar, &BandCLSID, sizeof(GUID)) == 0) + return S_OK; + } + else if (uID == IDM_TASKBAR_TOOLBARS_DESKTOP || uID == IDM_TASKBAR_TOOLBARS_QUICKLAUNCH) + { + dwBandID = _GetBandIdForBuiltinISFBand(uID); + if (dwBandID != UINT_MAX) { - /* We found it, remove it */ m_BandSite->RemoveBand(dwBandID); - return S_OK; } + else + { + CComPtr pDeskBand; + hRet = _CreateBuiltInISFBand(uID, IID_PPV_ARG(IDeskBand, &pDeskBand)); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; + + hRet = m_BandSite->AddBand(pDeskBand); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; + } + return S_OK; } - /* It is not present. Add it. */ - CComPtr pDeskBand; - HRESULT hRet = CoCreateInstance(*pguidToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pDeskBand)); - if (FAILED(hRet)) - return hRet; + /* Get the GUID of the item that was clicked */ + GUID *pguidToolbar = (GUID *)DSA_GetItemPtr(m_comcatDsa, uID - FIRST_COMCAT_MENU_ID); + if (!pguidToolbar) + return E_FAIL; - hRet = m_BandSite->AddBand(pDeskBand); - if (FAILED_UNEXPECTEDLY(hRet)) - return hRet; + /* Try to find if a band with a guid is present. If it is, remove it and return */ + dwBandID = _GetBandIdFromClsid(pguidToolbar); + if (dwBandID != UINT_MAX) + { + /* We found it, remove it */ + m_BandSite->RemoveBand(dwBandID); + } + else + { + /* It is not present. Add it. */ + CComPtr pDeskBand; + hRet = CoCreateInstance(*pguidToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pDeskBand)); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; + + hRet = m_BandSite->AddBand(pDeskBand); + if (FAILED_UNEXPECTEDLY(hRet)) + return hRet; + } return S_OK; } diff --git a/dll/win32/browseui/shellbars/CBandSiteMenu.h b/dll/win32/browseui/shellbars/CBandSiteMenu.h index d4d27acdc73fd..f05107b5297f2 100644 --- a/dll/win32/browseui/shellbars/CBandSiteMenu.h +++ b/dll/win32/browseui/shellbars/CBandSiteMenu.h @@ -29,14 +29,24 @@ class CBandSiteMenu : public IShellService { CComPtr m_BandSite; - HDSA m_menuDsa; + HDSA m_comcatDsa; HMENU m_hmenu; + LPITEMIDLIST m_DesktopPidl; + LPITEMIDLIST m_QLaunchPidl; - HRESULT CreateMenuPart(); + HRESULT _CreateMenuPart(); + HRESULT _CreateNewISFBand(HWND hwnd, REFIID riid, void** ppv); + HRESULT _CreateBuiltInISFBand(UINT uID, REFIID riid, void** ppv); + HRESULT _AddISFBandToMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, IUnknown* pBand, DWORD dwBandID, UINT *newMenuId); + UINT _GetMenuIdFromISFBand(IUnknown *pBand); + UINT _GetMenuIdFromBand(CLSID *BandCLSID); + UINT _GetBandIdFromClsid(CLSID* pclsid); + UINT _GetBandIdForBuiltinISFBand(UINT uID); public: CBandSiteMenu(); ~CBandSiteMenu(); + HRESULT WINAPI FinalConstruct(); // *** IShellService methods *** virtual HRESULT STDMETHODCALLTYPE SetOwner(IUnknown *);