* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "precomp.h"
+
+#include "CMergedFolder.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(CStartMenu);
+
+// TODO: declare these GUIDs and interfaces in the right place (whatever that may be)
+IID IID_IAugmentedShellFolder = { 0x91EA3F8C, 0xC99B, 0x11D0, { 0x98, 0x15, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72 } };
+IID IID_IAugmentedShellFolder2 = { 0x8DB3B3F4, 0x6CFE, 0x11D1, { 0x8A, 0xE9, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0 } };
+CLSID CLSID_MergedFolder = { 0x26FDC864, 0xBE88, 0x46E7, { 0x92, 0x35, 0x03, 0x2D, 0x8E, 0xA5, 0x16, 0x2E } };
//#define TEST_TRACKPOPUPMENU_SUBMENUS
-#include "precomp.h"
/* NOTE: The following constants *MUST NOT* be changed because
they're hardcoded and need to be the exact values
in order to get the start menu to work! */
+#define IDM_RUN 401
+#define IDM_LOGOFF 402
+#define IDM_UNDOCKCOMPUTER 410
+#define IDM_TASKBARANDSTARTMENU 413
+#define IDM_LASTSTARTMENU_SEPARATOR 450
+#define IDM_DOCUMENTS 501
+#define IDM_HELPANDSUPPORT 503
#define IDM_PROGRAMS 504
+#define IDM_CONTROLPANEL 505
+#define IDM_SHUTDOWN 506
#define IDM_FAVORITES 507
-#define IDM_DOCUMENTS 501
#define IDM_SETTINGS 508
-#define IDM_CONTROLPANEL 505
-#define IDM_SECURITY 5001
-#define IDM_NETWORKCONNECTIONS 557
#define IDM_PRINTERSANDFAXES 510
-#define IDM_TASKBARANDSTARTMENU 413
#define IDM_SEARCH 520
-#define IDM_HELPANDSUPPORT 503
-#define IDM_RUN 401
#define IDM_SYNCHRONIZE 553
-#define IDM_LOGOFF 402
+#define IDM_NETWORKCONNECTIONS 557
#define IDM_DISCONNECT 5000
-#define IDM_UNDOCKCOMPUTER 410
-#define IDM_SHUTDOWN 506
-#define IDM_LASTSTARTMENU_SEPARATOR 450
+#define IDM_SECURITY 5001
/*
* TODO:
CComPtr<IBandSite> m_pBandSite;
CComPtr<IDeskBar> m_pDeskBar;
CComPtr<ITrayPriv> m_pTrayPriv;
+ CComPtr<IShellFolder> m_psfPrograms;
+
+ LPITEMIDLIST m_pidlPrograms;
HRESULT OnInitMenu()
{
return S_OK;
hr = IUnknown_GetSite(m_pDeskBar, IID_PPV_ARG(ITrayPriv, &m_pTrayPriv));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
hr = IUnknown_GetWindow(m_pTrayPriv, &m_hwndTray);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
hr = m_pTrayPriv->AppendMenuW(&hmenu);
-#ifndef TEST_TRACKPOPUPMENU_SUBMENUS
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
hr = m_pShellMenu->SetMenu(hmenu, NULL, SMSET_BOTTOM);
-#else
- hr = m_pShellMenu->SetMenu(hmenu, m_hwndTray, SMSET_BOTTOM);
-#endif
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
return hr;
}
switch (psmd->uId)
{
- case IDM_PROGRAMS: iconIndex = -20; break;
- case IDM_FAVORITES: iconIndex = -173; break;
- case IDM_DOCUMENTS: iconIndex = -21; break;
- case IDM_SETTINGS: iconIndex = -22; break;
+ // Smaller "24x24" icons used for the start menu
+ // The bitmaps are still 32x32, but the image is centered
+ case IDM_FAVORITES: iconIndex = -322; break;
+ case IDM_SEARCH: iconIndex = -323; break;
+ case IDM_HELPANDSUPPORT: iconIndex = -324; break;
+ case IDM_LOGOFF: iconIndex = -325; break;
+ case IDM_PROGRAMS: iconIndex = -326; break;
+ case IDM_DOCUMENTS: iconIndex = -327; break;
+ case IDM_RUN: iconIndex = -328; break;
+ case IDM_SHUTDOWN: iconIndex = -329; break;
+ case IDM_SETTINGS: iconIndex = -330; break;
+
case IDM_CONTROLPANEL: iconIndex = -22; break;
- //case IDM_SECURITY: iconIndex = -21; break;
case IDM_NETWORKCONNECTIONS: iconIndex = -257; break;
case IDM_PRINTERSANDFAXES: iconIndex = -138; break;
case IDM_TASKBARANDSTARTMENU: iconIndex = -40; break;
- case IDM_SEARCH: iconIndex = -23; break;
- case IDM_HELPANDSUPPORT: iconIndex = -24; break;
- case IDM_RUN: iconIndex = -25; break;
+ //case IDM_SECURITY: iconIndex = -21; break;
//case IDM_SYNCHRONIZE: iconIndex = -21; break;
- case IDM_LOGOFF: iconIndex = -45; break;
//case IDM_DISCONNECT: iconIndex = -21; break;
//case IDM_UNDOCKCOMPUTER: iconIndex = -21; break;
- case IDM_SHUTDOWN: iconIndex = -28; break;
default:
return S_FALSE;
}
if (iconIndex)
{
+ if ((psminfo->dwMask & SMIM_TYPE) != 0)
+ psminfo->dwType = SMIT_STRING;
if ((psminfo->dwMask & SMIM_ICON) != 0)
psminfo->iIcon = Shell_GetCachedImageIndex(L"shell32.dll", iconIndex, FALSE);
+ if ((psminfo->dwMask & SMIM_FLAGS) != 0)
+ psminfo->dwFlags |= SMIF_ICON;
#ifdef TEST_TRACKPOPUPMENU_SUBMENUS
if ((psminfo->dwMask & SMIM_FLAGS) != 0)
psminfo->dwFlags |= SMIF_TRACKPOPUP;
#endif
}
+ else
+ {
+ if ((psminfo->dwMask & SMIM_TYPE) != 0)
+ psminfo->dwType = SMIT_SEPARATOR;
+ }
return S_OK;
}
int csidl = 0;
IShellMenu *pShellMenu;
- switch (psmd->uId)
- {
- case IDM_PROGRAMS: csidl = CSIDL_PROGRAMS; break;
- case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break;
- case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break;
- }
-
-#ifndef USE_BUILTIN_MENUBAND
+#if USE_SYSTEM_MENUBAND
hr = CoCreateInstance(CLSID_MenuBand,
NULL,
CLSCTX_INPROC_SERVER,
#else
hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &pShellMenu));
#endif
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
hr = pShellMenu->Initialize(this, 0, ANCESTORDEFAULT, SMINIT_VERTICAL);
+ switch (psmd->uId)
+ {
+ case IDM_PROGRAMS: csidl = CSIDL_PROGRAMS; break;
+ case IDM_FAVORITES: csidl = CSIDL_FAVORITES; break;
+ case IDM_DOCUMENTS: csidl = CSIDL_RECENT; break;
+ }
+
if (csidl)
{
- LPITEMIDLIST pidlStartMenu;
- IShellFolder *psfDestop, *psfStartMenu;
+ IShellFolder *psfStartMenu;
- hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu);
- hr = SHGetDesktopFolder(&psfDestop);
- hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu));
+ if (csidl == CSIDL_PROGRAMS && m_psfPrograms)
+ {
+ psfStartMenu = m_psfPrograms;
+ }
+ else
+ {
+ LPITEMIDLIST pidlStartMenu;
+ IShellFolder *psfDestop;
+ hr = SHGetFolderLocation(NULL, csidl, 0, 0, &pidlStartMenu);
+ hr = SHGetDesktopFolder(&psfDestop);
+ hr = psfDestop->BindToObject(pidlStartMenu, NULL, IID_PPV_ARG(IShellFolder, &psfStartMenu));
+ }
hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, 0);
}
HRESULT OnExec(LPSMDATA psmd)
{
+ // HACK: Instead of running explorer.exe with the path, we should be using ShellExecute to "open" the path directly!
+ // Remove once ShellExecute can handle CLSID path components.
+
if (psmd->uId == IDM_CONTROLPANEL)
- ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, NULL, 1);
+ ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", NULL, SW_SHOWNORMAL);
else if (psmd->uId == IDM_NETWORKCONNECTIONS)
- ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL, NULL, 1);
+ ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", NULL, SW_SHOWNORMAL);
else if (psmd->uId == IDM_PRINTERSANDFAXES)
- ShellExecuteW(NULL, L"open", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL, NULL, 1);
+ ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}", NULL, SW_SHOWNORMAL);
else
PostMessageW(m_hwndTray, WM_COMMAND, psmd->uId, 0);
IBandSite* pBandSite,
IDeskBar* pDeskBar)
{
- m_pShellMenu.Attach(pShellMenu);
- m_pBandSite.Attach(pBandSite);
- m_pDeskBar.Attach(pDeskBar);
+ m_pShellMenu = pShellMenu;
+ m_pBandSite = pBandSite;
+ m_pDeskBar = pDeskBar;
}
~CShellMenuCallback()
{
- m_pShellMenu.Release();
- m_pBandSite.Release();
- m_pDeskBar.Release();
+ }
+
+ HRESULT _SetProgramsFolder(IShellFolder * psf, LPITEMIDLIST pidl)
+ {
+ m_psfPrograms = psf;
+ m_pidlPrograms = pidl;
+ return S_OK;
}
HRESULT STDMETHODCALLTYPE CallbackSM(
case SMC_SFEXEC:
m_pTrayPriv->Execute(psmd->psf, psmd->pidlItem);
break;
+ case 0x10000000: // _FilterPIDL from CMenuSFToolbar
+ if (psmd->psf->CompareIDs(0, psmd->pidlItem, m_pidlPrograms) == 0)
+ return S_FALSE;
+ return S_OK;
}
return S_FALSE;
}
};
+HRESULT BindToDesktop(LPCITEMIDLIST pidl, IShellFolder ** ppsfResult)
+{
+ HRESULT hr;
+ CComPtr<IShellFolder> psfDesktop;
+
+ *ppsfResult = NULL;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ return hr;
+
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfResult));
+
+ return hr;
+}
+
+static HRESULT GetStartMenuFolder(IShellFolder ** ppsfStartMenu)
+{
+ HRESULT hr;
+ LPITEMIDLIST pidlUserStartMenu;
+ LPITEMIDLIST pidlCommonStartMenu;
+ CComPtr<IShellFolder> psfUserStartMenu;
+ CComPtr<IShellFolder> psfCommonStartMenu;
+ CComPtr<IAugmentedShellFolder> pasf;
+
+ *ppsfStartMenu = NULL;
+
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_STARTMENU, &pidlUserStartMenu);
+ if (FAILED(hr))
+ {
+ WARN("Failed to get the USER start menu folder. Trying to run with just the COMMON one.\n");
+
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommonStartMenu);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ TRACE("COMMON start menu obtained.\n");
+ hr = BindToDesktop(pidlCommonStartMenu, ppsfStartMenu);
+ ILFree(pidlCommonStartMenu);
+ return hr;
+ }
+
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommonStartMenu);
+ if (FAILED_UNEXPECTEDLY(hr))
+ {
+ WARN("Failed to get the COMMON start menu folder. Will use only the USER contents.\n");
+ hr = BindToDesktop(pidlUserStartMenu, ppsfStartMenu);
+ ILFree(pidlUserStartMenu);
+ return hr;
+ }
+
+ TRACE("Both COMMON and USER statr menu folders obtained, merging them...\n");
+
+ hr = BindToDesktop(pidlUserStartMenu, &psfUserStartMenu);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = BindToDesktop(pidlCommonStartMenu, &psfCommonStartMenu);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+#if !USE_SYSTEM_MERGED_FOLDERS
+ hr = CMergedFolder_Constructor(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
+#else
+ hr = CoCreateInstance(CLSID_MergedFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAugmentedShellFolder, &pasf));
+#endif
+ if (FAILED_UNEXPECTEDLY(hr))
+ {
+ *ppsfStartMenu = psfUserStartMenu.Detach();
+ ILFree(pidlCommonStartMenu);
+ ILFree(pidlUserStartMenu);
+ return hr;
+ }
+
+ hr = pasf->AddNameSpace(NULL, psfUserStartMenu, pidlUserStartMenu, 0xFF00);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = pasf->AddNameSpace(NULL, psfCommonStartMenu, pidlCommonStartMenu, 0);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = pasf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsfStartMenu));
+ pasf.Release();
+
+ ILFree(pidlCommonStartMenu);
+ ILFree(pidlUserStartMenu);
+
+ return hr;
+}
+
extern "C"
-HRESULT
+HRESULT WINAPI
CStartMenu_Constructor(REFIID riid, void **ppv)
{
- IShellMenu* pShellMenu;
- IBandSite* pBandSite;
- IDeskBar* pDeskBar;
- LPITEMIDLIST pidlStartMenu;
+ CComPtr<IShellMenu> pShellMenu;
+ CComPtr<IBandSite> pBandSite;
+ CComPtr<IDeskBar> pDeskBar;
HRESULT hr;
- IShellFolder *shellFolder;
- IShellFolder *psfStartMenu;
+ IShellFolder * psf;
+
+ LPITEMIDLIST pidlProgramsAbsolute;
+ LPITEMIDLIST pidlPrograms;
+ CComPtr<IShellFolder> psfPrograms;
-#ifndef USE_BUILTIN_MENUBAND
+#if USE_SYSTEM_MENUBAND
hr = CoCreateInstance(CLSID_MenuBand,
NULL,
CLSCTX_INPROC_SERVER,
#else
hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &pShellMenu));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
-#ifndef USE_BUILTIN_MENUSITE
+#if USE_SYSTEM_MENUSITE
hr = CoCreateInstance(CLSID_MenuBandSite,
NULL,
CLSCTX_INPROC_SERVER,
#else
hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
-#ifndef USE_BUILTIN_MENUDESKBAR
+#if USE_SYSTEM_MENUDESKBAR
hr = CoCreateInstance(CLSID_MenuDeskBar,
NULL,
CLSCTX_INPROC_SERVER,
#else
hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComObject<CShellMenuCallback> *pCallback;
hr = CComObject<CShellMenuCallback>::CreateInstance(&pCallback);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
pCallback->AddRef(); // CreateInstance returns object with 0 ref count */
pCallback->Initialize(pShellMenu, pBandSite, pDeskBar);
- pShellMenu->Initialize(pCallback, -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
+ pShellMenu->Initialize(pCallback, (UINT) -1, 0, SMINIT_TOPLEVEL | SMINIT_VERTICAL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = GetStartMenuFolder(&psf);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &pidlProgramsAbsolute);
if (FAILED(hr))
+ {
+ WARN("USER Programs folder not found.");
+ hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlProgramsAbsolute);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ }
+
+ pidlPrograms = ILClone(ILFindLastID(pidlProgramsAbsolute));
+ ILFree(pidlProgramsAbsolute);
+
+ hr = psf->BindToObject(pidlPrograms, NULL, IID_PPV_ARG(IShellFolder, &psfPrograms));
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
- /* FIXME: Use CLSID_MergedFolder class and IID_IAugmentedShellFolder2 interface here */
- /* CLSID_MergedFolder 26fdc864-be88-46e7-9235-032d8ea5162e */
- /* IID_IAugmentedShellFolder2 8db3b3f4-6cfe-11d1-8ae9-00c04fd918d0 */
- hr = SHGetFolderLocation(NULL, CSIDL_STARTMENU, 0, 0, &pidlStartMenu);
- hr = SHGetDesktopFolder(&shellFolder);
- hr = shellFolder->BindToObject(pidlStartMenu, NULL, IID_IShellFolder, (void**) &psfStartMenu);
+ hr = pCallback->_SetProgramsFolder(psfPrograms, pidlPrograms);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- hr = pShellMenu->SetShellFolder(psfStartMenu, NULL, NULL, 0);
+ hr = pShellMenu->SetShellFolder(psf, NULL, NULL, 0);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
hr = pDeskBar->SetClient(pBandSite);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pBandSite->AddBand(pShellMenu);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pDeskBar->QueryInterface(riid, ppv);