// ## MenuContainer.h // Classic Shell (c) 2009-2016, Ivo Beltchev // Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author // MenuCommands.cpp - handles the commands and actions of CMenuContainer #include "stdafx.h" #include "MenuContainer.h" #include "ClassicStartMenuDLL.h" #include "Settings.h" #include "SettingsUI.h" #include "SettingsUIHelper.h" #include "Translations.h" #include "LogManager.h" #include "FNVHash.h" #include "ResourceHelper.h" #include "MetroLinkManager.h" #include "ProgramsTree.h" #include "resource.h" #include #include #include #include #include static CString g_RenameText; static POINT g_RenamePos; // Dialog proc for the Rename dialog box static INT_PTR CALLBACK RenameDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg==WM_INITDIALOG) { // translate text SetWindowText(hwndDlg,FindTranslation(L"Menu.RenameTitle",L"Rename")); SetDlgItemText(hwndDlg,IDC_LABEL,FindTranslation(L"Menu.RenamePrompt",L"&New name:")); SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Menu.RenameOK",L"OK")); SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Menu.RenameCancel",L"Cancel")); SetDlgItemText(hwndDlg,IDC_EDITNAME,g_RenameText); // position near the item SetWindowPos(hwndDlg,NULL,g_RenamePos.x,g_RenamePos.y,0,0,SWP_NOZORDER|SWP_NOSIZE); SendMessage(hwndDlg,DM_REPOSITION,0,0); return TRUE; } if (uMsg==WM_COMMAND && wParam==IDOK) { wchar_t buf[1024]; GetDlgItemText(hwndDlg,IDC_EDITNAME,buf,_countof(buf)); g_RenameText=buf; EndDialog(hwndDlg,1); return TRUE; } if (uMsg==WM_COMMAND && wParam==IDCANCEL) { EndDialog(hwndDlg,0); return TRUE; } return FALSE; } static void SetShutdownPrivileges( void ) { HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) { TOKEN_PRIVILEGES tp={1}; if (LookupPrivilegeValue(NULL,L"SeShutdownPrivilege",&tp.Privileges[0].Luid)) tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL); CloseHandle(hToken); } } static void DoSearchSubst( wchar_t *buf, int size, const wchar_t *search ) { wchar_t search2[256]; char utf8[1024]; WcsToMbs(utf8,_countof(utf8),search,CP_UTF8); int len=0; for (const char *c=utf8;*c;c++) { if ((*c>='a' && *c<='z') || (*c>='A' && *c<='Z') || (*c>='0' && *c<='9')) { search2[len++]=*c; } else if (len<_countof(search2)-4) { len+=Sprintf(search2+len,_countof(search2)-len,L"%%%02X",(unsigned char)*c); } else break; } search2[len]=0; DWORD_PTR args[100]={(DWORD_PTR)search,(DWORD_PTR)search2}; wchar_t *pBuf=buf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_ARGUMENT_ARRAY|FORMAT_MESSAGE_FROM_STRING,buf,0,0,(LPWSTR)&pBuf,0,(va_list*)args); Strcpy(buf,size,pBuf); LocalFree(pBuf); } static DWORD CALLBACK ExecuteCommandThread( void *param ) { CoInitialize(NULL); const wchar_t *command=(wchar_t*)param; wchar_t exe[_MAX_PATH]; const wchar_t *args=NULL; CComString strExe, strArgs; if (SUCCEEDED(SHEvaluateSystemCommandTemplate(command,&strExe,NULL,&strArgs))) { args=strArgs; Strcpy(exe,_countof(exe),strExe); } else { args=SeparateArguments(command,exe); } SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_FLAG_LOG_USAGE}; execute.lpFile=exe; execute.lpParameters=args; execute.nShow=SW_SHOWNORMAL; ShellExecuteEx(&execute); free(param); CoUninitialize(); return 0; } void CMenuContainer::ExecuteCommand( const wchar_t *command, bool bElevated, bool bEnvSubst ) { wchar_t text[1024]; if (bEnvSubst) { Strcpy(text,_countof(text),command); DoEnvironmentSubst(text,_countof(text)); command=text; } if (bElevated) { wchar_t cmdLine[1024]; Sprintf(cmdLine,_countof(cmdLine),L"-runas %s",command); wchar_t exe[_MAX_PATH]; GetModuleFileName(_AtlBaseModule.GetModuleInstance(),exe,_countof(exe)); PathRemoveFileSpec(exe); PathAppend(exe,L"ClassicStartMenu.exe"); RECT rc; if (m_bDestroyed) ::GetWindowRect(g_TaskBar,&rc); else GetWindowRect(&rc); ::SetForegroundWindow(g_OwnerWindow); ::SetWindowPos(g_OwnerWindow,HWND_TOPMOST,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,0); ShellExecute(g_OwnerWindow,L"runas",exe,cmdLine,NULL,SW_SHOWNORMAL); } else { CreateThread(NULL,0,ExecuteCommandThread,_wcsdup(command),0,NULL); } } // Dialog proc for the Log Off dialog box static INT_PTR CALLBACK LogOffDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg==WM_INITDIALOG) { // translate text SendDlgItemMessage(hwndDlg,IDC_STATICICON1,STM_SETICON,lParam,0); SetWindowText(hwndDlg,FindTranslation(L"Menu.LogoffTitle",L"Log Off Windows")); SetDlgItemText(hwndDlg,IDC_PROMPT,FindTranslation(L"Menu.LogoffPrompt",L"Are you sure you want to log off?")); SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Menu.LogoffYes",L"&Log Off")); SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Menu.LogoffNo",L"&No")); return TRUE; } if (uMsg==WM_COMMAND && wParam==IDOK) { EndDialog(hwndDlg,1); return TRUE; } if (uMsg==WM_COMMAND && wParam==IDCANCEL) { EndDialog(hwndDlg,0); return TRUE; } return FALSE; } struct ShortcutParams { ShortcutParams( void ) { memset(this,0,sizeof(*this)); } wchar_t target[_MAX_PATH+1]; wchar_t temp[_MAX_PATH]; wchar_t fname[_MAX_PATH+1]; }; static DWORD WINAPI NewShortcutThread( void *param ) { ShortcutParams *pParams=(ShortcutParams*)param; HANDLE hFile=CreateFile(pParams->fname,0,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile!=INVALID_HANDLE_VALUE) { // run the shortcut wizard wchar_t cmdLine[1024]; Sprintf(cmdLine,_countof(cmdLine),L"rundll32.exe appwiz.cpl,NewLinkHere %s",pParams->fname); STARTUPINFO startupInfo={sizeof(startupInfo)}; PROCESS_INFORMATION processInfo; memset(&processInfo,0,sizeof(processInfo)); wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\rundll32.exe"; DoEnvironmentSubst(exe,_countof(exe)); if (CreateProcess(exe,cmdLine,NULL,NULL,FALSE,0,NULL,pParams->temp,&startupInfo,&processInfo)) { CloseHandle(processInfo.hThread); WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); // see what the file was renamed to struct { DWORD FileNameLength; wchar_t FileName[_MAX_PATH]; } nameInfo={0}; BOOL bInfo=GetFileInformationByHandleEx(hFile,FileNameInfo,&nameInfo,sizeof(nameInfo)); CloseHandle(hFile); if (bInfo) { // move to the final target folder int len=Sprintf(pParams->fname,_countof(pParams->fname)-1,L"%s\\%s",pParams->temp,PathFindFileName(nameInfo.FileName)); pParams->fname[len+1]=0; SHFILEOPSTRUCT shfop={g_OwnerWindow,FO_MOVE,pParams->fname,pParams->target}; SHFileOperation(&shfop); } } else CloseHandle(hFile); DeleteFile(pParams->fname); } delete pParams; return 0; } static DWORD WINAPI SleepThread( void *param ) { SetSuspendState((BOOL)(intptr_t)param,FALSE,FALSE); return 0; } void CMenuContainer::CloseSubMenus( int flags, CMenuContainer *pAfter ) { if (s_MenuMode==MODE_JUMPLIST && !(flags&CLOSE_KEEP_MODE)) { if (pAfter && !pAfter->m_bSubMenu) { pAfter->SetMenuMode(MODE_NORMAL); } } for (int i=(int)s_Menus.size()-((flags&CLOSE_SKIP_LAST)?2:1);i>=0 && s_Menus[i]!=pAfter;i--) if (!s_Menus[i]->m_bDestroyed) { if ((flags&CLOSE_SKIP_SEARCH) && (s_Menus[i]->m_Options&CONTAINER_SEARCH)) continue; if ((flags&CLOSE_ONLY_SEARCH) && !(s_Menus[i]->m_Options&CONTAINER_SEARCH)) continue; if (flags&CLOSE_POST) { s_Menus[i]->ShowWindow(SW_HIDE); s_Menus[i]->PostMessage(WM_CLOSE); s_Menus[i]->m_bClosing=true; } else s_Menus[i]->DestroyWindow(); } } void CMenuContainer::OpenSubMenu( int index, TActivateType type, bool bShift ) { const MenuItem &item=m_Items[index]; if (m_bTwoColumns && s_bWin7Style) { if (item.bHasJumpList) { SetActiveWindow(); CloseSubMenus(CLOSE_KEEP_MODE,this); OpenJumpList(index,type==ACTIVATE_OPEN_KBD); return; } if (item.id==MENU_SEARCH_BOX) { SetActiveWindow(); CloseSubMenus(CLOSE_KEEP_MODE,this); OpenSearchList(); return; } if (item.id==MENU_PROGRAMS && GetSettingInt(L"ProgramsStyle")==PROGRAMS_INLINE) { SetActiveWindow(); CloseSubMenus(CLOSE_KEEP_MODE,this); SetMenuMode(s_MenuMode==MODE_PROGRAMS?MODE_NORMAL:MODE_PROGRAMS); if (s_MenuMode==MODE_NORMAL) SetHotItem(m_ProgramButtonIndex); return; } } // open a submenu - create a new menu object const StdMenuItem *pSubMenu=item.pStdItem?item.pStdItem->submenu:NULL; bool bOpenUp=false; int options=(type==ACTIVATE_OPEN_SEARCH)?CONTAINER_DRAG|CONTAINER_SEARCH:CONTAINER_DRAG|CONTAINER_DROP; if (item.id==MENU_CONTROLPANEL) options|=CONTAINER_CONTROLPANEL; if (item.id==MENU_DOCUMENTS) options|=CONTAINER_DOCUMENTS; if (item.id==MENU_APPS) options|=CONTAINER_APPS; if (item.bPrograms) options|=CONTAINER_PROGRAMS; if (item.bLink || (m_Options&CONTAINER_LINK)) options|=CONTAINER_LINK; if ((m_Options&CONTAINER_TRACK) || item.id==MENU_PROGRAMS || item.id==MENU_APPS) options|=CONTAINER_TRACK; if (item.id==MENU_PROGRAMS && GetSettingInt(L"PinnedPrograms")==PINNED_PROGRAMS_PINNED) options|=CONTAINER_ALLPROGRAMS; if (item.id==MENU_RECENT_PROGRAMS) options|=CONTAINER_RECENT; if (m_Options&CONTAINER_OPENUP_REC) { options|=CONTAINER_OPENUP_REC; bOpenUp=true; } if (m_Options&CONTAINER_SORTZA_REC) options|=CONTAINER_SORTZA|CONTAINER_SORTZA_REC; if (item.pStdItem) { if (item.pStdItem->settings&StdMenuItem::MENU_OPENUP) bOpenUp=true; if (item.pStdItem->settings&StdMenuItem::MENU_OPENUP_REC) options|=CONTAINER_OPENUP_REC; if (item.pStdItem->settings&StdMenuItem::MENU_SORTZA) options|=CONTAINER_SORTZA; if (item.pStdItem->settings&StdMenuItem::MENU_SORTZA_REC) options|=CONTAINER_SORTZA_REC; if (item.pStdItem->settings&StdMenuItem::MENU_SORTONCE) options|=CONTAINER_SORTONCE; if (item.pStdItem->settings&StdMenuItem::MENU_ITEMS_FIRST) options|=CONTAINER_ITEMS_FIRST; if (item.pStdItem->settings&StdMenuItem::MENU_TRACK) options|=CONTAINER_TRACK; if (item.pStdItem->settings&StdMenuItem::MENU_NOTRACK) options&=~CONTAINER_TRACK; if (item.pStdItem->settings&StdMenuItem::MENU_MULTICOLUMN) options|=CONTAINER_MULTICOL_REC; if (item.pStdItem->settings&StdMenuItem::MENU_NOEXTENSIONS) options|=CONTAINER_NOEXTENSIONS; if (item.pStdItem->settings&StdMenuItem::MENU_SINGLE_EXPAND) options|=CONTAINER_NOSUBFOLDERS; } if (item.id==MENU_NETWORK) options|=CONTAINER_NOPATH; if (item.bHasJumpList) options=CONTAINER_JUMPLIST|CONTAINER_DRAG|CONTAINER_DROP; else if (item.id==MENU_COMPUTER && !s_bWin7Style) { if (GetSettingInt(L"Computer")==3) options|=CONTAINER_NOSUBFOLDERS; } else if (item.pItem1 && item.pItemInfo) { CString PATH; { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); if (item.bLink) PATH=item.pItemInfo->GetTargetPATH(); if (PATH.IsEmpty()) PATH=item.pItemInfo->PATH; } if (!PATH.IsEmpty()) { for (int i=0;g_SpecialFolders[i].folder;i++) { if (PATH==g_SpecialFolders[i].PATH) { if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NOSUBFOLDERS) options|=CONTAINER_NOSUBFOLDERS; if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NONEWFOLDER) options|=CONTAINER_NONEWFOLDER; if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NOPATH) options|=CONTAINER_NOPATH; if (g_SpecialFolders[i].settings&SpecialFolder::FOLDER_NODROP) options&=~CONTAINER_DROP; break; } } } } if (m_Options&CONTAINER_NOEXTENSIONS) options|=CONTAINER_NOEXTENSIONS; if (item.id==MENU_PROGRAMS || item.id==MENU_APPS || (m_Options&CONTAINER_MULTICOL_REC)) options|=CONTAINER_MULTICOL_REC; if ((options&CONTAINER_MULTICOL_REC) && !bShift) options|=CONTAINER_MULTICOLUMN; if (options&CONTAINER_SEARCH) options&=~(CONTAINER_MULTICOL_REC|CONTAINER_MULTICOLUMN); CMenuContainer *pMenu=new CSubMenuContainer(this,index,options,pSubMenu,item.pItem1,item.pItem2); if (type==ACTIVATE_OPEN_SEARCH) { pMenu->InitSearchItems(); } else { s_JumpAppInfo=item.bHasJumpList?item.pItemInfo:NULL; pMenu->InitItems(); } RECT itemRect; GetItemRect(index,itemRect); MapWindowPoints(NULL,&itemRect); RECT border={-s_Skin.Submenu_padding.left+s_Skin.Submenu_offset,-s_Skin.Submenu_padding.top,s_Skin.Submenu_padding.right-s_Skin.Submenu_offset,s_Skin.Submenu_padding.bottom}; if (s_bRTL) { // swap and change signs int q=border.left; border.left=-border.right; border.right=-q; } AdjustWindowRect(&border,s_SubmenuStyle,FALSE); if (m_bSubMenu) pMenu->m_MaxWidth=s_MenuLimits.right-s_MenuLimits.left; else if (s_bExpandRight) pMenu->m_MaxWidth=s_MenuLimits.right-itemRect.right-border.left; else pMenu->m_MaxWidth=itemRect.left+border.right-s_MenuLimits.left; DWORD animFlags=AW_TOPMOST; { bool bDef; int anim=GetSettingInt(L"SubMenuAnimation",bDef); if (bDef) { DWORD fade; SystemParametersInfo(SPI_GETMENUFADE,NULL,&fade,0); anim=fade?1:2; } if (anim==3) animFlags|=((rand()=0 && !GetSettingBool(L"SubMenuAnimationAlways"))) animate=FALSE; else SystemParametersInfo(SPI_GETMENUANIMATION,NULL,&animate,0); // destroy old submenus SetActiveWindow(); CloseSubMenus(CLOSE_SKIP_LAST,this); // open submenu HWND parent=GetParent(); pMenu->Create(parent,NULL,s_SubmenuStyle,WS_EX_TOOLWINDOW|WS_EX_TOPMOST|(s_bRTL?WS_EX_LAYOUTRTL:0)); if (GetSettingBool(L"MenuShadow") && s_Skin.Submenu_shadow==MenuSkin::SHADOW_ON) SetClassLong(pMenu->m_hWnd,GCL_STYLE,GetClassLong(pMenu->m_hWnd,GCL_STYLE)|CS_DROPSHADOW); else SetClassLong(pMenu->m_hWnd,GCL_STYLE,GetClassLong(pMenu->m_hWnd,GCL_STYLE)&~CS_DROPSHADOW); if (!parent && s_TaskBar) { // place sub-menus in front of the taskbar if (type==ACTIVATE_OPEN_SEARCH) pMenu->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); else pMenu->SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); } RECT rc2; pMenu->GetWindowRect(&rc2); // position new menu int w=rc2.right-rc2.left; int h=rc2.bottom-rc2.top; if (s_bExpandRight) { if (itemRect.right+border.left+w<=s_MenuLimits.right) { // right rc2.left=itemRect.right+border.left; rc2.right=rc2.left+w; animFlags|=AW_HOR_POSITIVE; pMenu->m_Options|=CONTAINER_LEFT; } else if (itemRect.left+border.right-w>=s_MenuLimits.left) { // left rc2.right=itemRect.left+border.right; rc2.left=rc2.right-w; animFlags|=AW_HOR_NEGATIVE; } else { // right again rc2.right=s_MenuLimits.right; rc2.left=rc2.right-w; if (!s_bRTL) { int minx=m_bSubMenu?s_MenuLimits.left:(itemRect.right+border.left); if (rc2.leftm_Options|=CONTAINER_LEFT; } } else { if (itemRect.left+border.right-w>=s_MenuLimits.left) { // left rc2.right=itemRect.left+border.right; rc2.left=rc2.right-w; animFlags|=AW_HOR_NEGATIVE; } else if (itemRect.right+border.left+w<=s_MenuLimits.right) { // right rc2.left=itemRect.right+border.left; rc2.right=rc2.left+w; animFlags|=AW_HOR_POSITIVE; pMenu->m_Options|=CONTAINER_LEFT; } else { // left again rc2.left=s_MenuLimits.left; rc2.right=rc2.left+w; if (s_bRTL) { int maxx=m_bSubMenu?s_MenuLimits.right:(itemRect.left+border.right); if (rc2.right>maxx) { rc2.left=maxx-w; rc2.right=maxx; } } animFlags|=AW_HOR_NEGATIVE; } } if (s_bRTL) animFlags^=(AW_HOR_POSITIVE|AW_HOR_NEGATIVE); // RTL flips the animation if (bOpenUp) { if (itemRect.bottom+border.bottom-h>=s_MenuLimits.top) { // up rc2.bottom=itemRect.bottom+border.bottom; rc2.top=rc2.bottom-h; } else if (itemRect.top+border.top+h<=s_MenuLimits.bottom) { // down rc2.top=itemRect.top+border.top; rc2.bottom=rc2.top+h; pMenu->m_Options|=CONTAINER_TOP; } else { // up again rc2.top=s_MenuLimits.top-pMenu->m_ExtraBorder; rc2.bottom=rc2.top+h; } } else { if (itemRect.top+border.top+h<=s_MenuLimits.bottom) { // down rc2.top=itemRect.top+border.top; rc2.bottom=rc2.top+h; pMenu->m_Options|=CONTAINER_TOP; } else if (itemRect.bottom+border.bottom-h>=s_MenuLimits.top) { // up rc2.bottom=itemRect.bottom+border.bottom; rc2.top=rc2.bottom-h; } else { // down again rc2.bottom=s_MenuLimits.bottom+pMenu->m_ExtraBorder; rc2.top=rc2.bottom-h; pMenu->m_Options|=CONTAINER_TOP; } } SetSubmenu(index); m_SubShowTime=0; InvalidateItem(index); if (type!=ACTIVATE_OPEN_SEARCH) SetHotItem(index); UpdateWindow(); if (type!=ACTIVATE_OPEN_SEARCH) { pMenu->SetFocus(); int hotItem=-1; if (type==ACTIVATE_OPEN_KBD) { bool bLast=item.id==MENU_SHUTDOWN_BUTTON && GetSettingBool(L"SelectLastShutdown"); for (int i=0;i<(int)pMenu->m_Items.size();i++) if (pMenu->CanSelectItem(i)) { hotItem=i; if (!bLast) break; } } pMenu->SetHotItem(hotItem); } int speed=0; if (animate) { speed=GetSettingInt(L"SubMenuAnimationSpeed"); if (speed<=0) speed=MENU_ANIM_SPEED_SUBMENU; else if (speed>=10000) speed=10000; } pMenu->AnimateMenu(animFlags,speed,rc2); if (s_Tooltip.m_hWnd) s_Tooltip.SetWindowPos(HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); } class ExitGuard { public: ExitGuard( void ) { m_bArmed=true; } ~ExitGuard( void ) { Assert(!m_bArmed); } void Disarm( void ) { m_bArmed=false; } private: bool m_bArmed; }; #ifndef EWX_HYBRID_SHUTDOWN #define EWX_HYBRID_SHUTDOWN 0x00400000 #endif #define EWX_INSTALL_UPDATES 0x00100000 // undocumented switch to install updates on shutdown static bool ExecuteSysCommand( TMenuID menuCommand ) { CComPtr pShellDisp; HRESULT hr; switch (menuCommand) { case MENU_TASKBAR: // show taskbar properties hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->TrayProperties(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to TrayProperties, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_FEATURES: hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->ControlPanelItem(CComBSTR(L"appwiz.cpl")); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to ControlPanelItem(appwiz.cpl), 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_SECURITY: { CComPtr pShellDisp4; hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch4,(void**)&pShellDisp4); if (SUCCEEDED(hr)) { hr=pShellDisp4->WindowsSecurity(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to WindowsSecurity, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); } return true; case MENU_SEARCH_FILES: // show the search UI hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->FindFiles(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to FindFiles, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_SEARCH_PRINTER: // search for network printers hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->FindPrinter(CComBSTR(L""),CComBSTR(L""),CComBSTR(L"")); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to FindPrinter, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_SEARCH_COMPUTERS: // search for computers hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->FindComputer(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to FindComputer, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_SEARCH_PEOPLE: // search for people using Windows Mail { SHELLEXECUTEINFO execute={sizeof(execute),SEE_MASK_DOENVSUBST,NULL,L"open"}; execute.lpFile=L"%ProgramFiles%\\Windows Mail\\wab.exe"; execute.lpParameters=L"/find"; execute.lpDirectory=L"%ProgramFiles%\\Windows Mail"; execute.nShow=SW_SHOWNORMAL; ShellExecuteEx(&execute); } return true; case MENU_HELP: // show Windows help hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->Help(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to Help, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_RUN: // show the Run box if (GetWinVersion()>=WIN_VER_WIN10) { ShellExecute(NULL,NULL,L"shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL); } else { hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->FileRun(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to FileRun, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); } return true; case MENU_LOGOFF: // log off ExitWindowsEx(EWX_LOGOFF,0); return true; case MENU_LOGOFF_CONFIRM: { HMODULE hShell32=GetModuleHandle(L"Shell32.dll"); HICON icon=LoadIcon(hShell32,MAKEINTRESOURCE(45)); INT_PTR res=DialogBoxParam(g_Instance,MAKEINTRESOURCE(IsLanguageRTL()?IDD_LOGOFFR:IDD_LOGOFF),NULL,LogOffDlgProc,(LPARAM)icon); DestroyIcon(icon); if (res) ExitWindowsEx(EWX_LOGOFF,0); } return true; case MENU_RESTART: // restart case MENU_RESTART_NOUPDATE: SetShutdownPrivileges(); ExitWindowsEx(EWX_REBOOT,SHTDN_REASON_FLAG_PLANNED); return true; case MENU_RESTART_ADVANCED: // advanced restart if (GetWinVersion()>=WIN_VER_WIN8) { STARTUPINFO startupInfo={sizeof(startupInfo)}; PROCESS_INFORMATION processInfo; memset(&processInfo,0,sizeof(processInfo)); wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\shutdown.exe"; DoEnvironmentSubst(exe,_countof(exe)); if (CreateProcess(exe,L"shutdown.exe /r /o /t 0",NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { CloseHandle(processInfo.hThread); CloseHandle(processInfo.hProcess); } } else ExitWindowsEx(EWX_REBOOT,SHTDN_REASON_FLAG_PLANNED); return true; case MENU_RESTART_UPDATE: // update and restart { UINT flags=EWX_REBOOT; if (GetWinVersion()>=WIN_VER_WIN8) flags|=EWX_INSTALL_UPDATES; SetShutdownPrivileges(); ExitWindowsEx(flags,SHTDN_REASON_FLAG_PLANNED); } return true; case MENU_SWITCHUSER: // switch_user if (GetWinVersion()>=WIN_VER_WIN10) { // on Windows 10 this value must be set to 1. For some reason non-admin code has permissions to do so CRegKey regSwitch; if (regSwitch.Create(HKEY_LOCAL_MACHINE,L"Software\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\UserSwitch",NULL,0,KEY_SET_VALUE)==ERROR_SUCCESS) regSwitch.SetDWORDValue(L"Enabled",1); } WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE); // same as "disconnect" return true; case MENU_LOCK: // lock LockWorkStation(); return true; case MENU_SHUTDOWN: // shutdown case MENU_SHUTDOWN_NOUPDATE: SetShutdownPrivileges(); ExitWindowsEx(EWX_SHUTDOWN,SHTDN_REASON_FLAG_PLANNED); return true; case MENU_SHUTDOWN_UPDATE: // update and shutdown SetShutdownPrivileges(); ExitWindowsEx(EWX_SHUTDOWN|EWX_INSTALL_UPDATES,SHTDN_REASON_FLAG_PLANNED); return true; case MENU_SHUTDOWN_HYBRID: // hybrid shutdown SetShutdownPrivileges(); { UINT flags=EWX_SHUTDOWN; if (GetWinVersion()>=WIN_VER_WIN8) { CRegKey regPower; if (regPower.Open(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Power",KEY_READ)==ERROR_SUCCESS) { DWORD val; if (regPower.QueryDWORDValue(L"HiberbootEnabled",val)==ERROR_SUCCESS && val==1) flags|=EWX_HYBRID_SHUTDOWN; } } ExitWindowsEx(flags,SHTDN_REASON_FLAG_PLANNED); } return true; case MENU_SLEEP: if (GetSystemMetrics(SM_REMOTESESSION)) { WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE); Sleep(250); } CreateThread(NULL,0,SleepThread,(void*)FALSE,0,NULL); return true; case MENU_HIBERNATE: if (GetSystemMetrics(SM_REMOTESESSION)) { WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE); Sleep(250); } CreateThread(NULL,0,SleepThread,(void*)TRUE,0,NULL); return true; case MENU_DISCONNECT: // disconnect the current Terminal Services session (remote desktop) WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,WTS_CURRENT_SESSION,FALSE); return true; case MENU_UNDOCK: // undock the PC hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->EjectPC(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to EjectPC, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_MONITOROFF: ::SendMessage(g_TaskBar,WM_SYSCOMMAND,SC_MONITORPOWER,2); return true; case MENU_SHUTDOWN_BOX: // shutdown - ask to shutdown, log off, sleep, etc hr=CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp); if (SUCCEEDED(hr)) { hr=pShellDisp->ShutdownWindows(); if (FAILED(hr)) LOG_MENU(LOG_EXECUTE,L"Failed to ShutdownWindows, 0x08%x",hr); } else LOG_MENU(LOG_EXECUTE,L"Failed to create dispatch, 0x08%x",hr); return true; case MENU_PCSETTINGS: if (GetWinVersion()>=WIN_VER_WIN8) { ShellExecute(NULL,NULL,L"shell:appsfolder\\windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel",NULL,NULL,SW_SHOWNORMAL); } return true; default: return false; } } STARTMENUAPI bool DllExecuteNamedCommand( const wchar_t *command ) { static struct NamedCommand { const wchar_t *name; TMenuID command; } s_NamedCommands[]= { {L"help",MENU_HELP}, {L"run",MENU_RUN}, {L"logoff",MENU_LOGOFF}, {L"undock",MENU_UNDOCK}, {L"monitor_off",MENU_MONITOROFF}, {L"disconnect",MENU_DISCONNECT}, {L"shutdown_box",MENU_SHUTDOWN_BOX}, {L"windows_security",MENU_SECURITY}, {L"taskbar_settings",MENU_TASKBAR}, {L"search_files",MENU_SEARCH_FILES}, {L"search_printer",MENU_SEARCH_PRINTER}, {L"search_computers",MENU_SEARCH_COMPUTERS}, {L"search_people",MENU_SEARCH_PEOPLE}, {L"sleep",MENU_SLEEP}, {L"hibernate",MENU_HIBERNATE}, {L"restart",MENU_RESTART}, {L"shutdown",MENU_SHUTDOWN}, {L"switch_user",MENU_SWITCHUSER}, {L"lock",MENU_LOCK}, {L"programs_features",MENU_FEATURES}, {L"confirm_logoff",MENU_LOGOFF_CONFIRM}, {L"advanced_boot",MENU_RESTART_ADVANCED}, {L"update_restart",MENU_RESTART_UPDATE}, {L"update_shutdown",MENU_SHUTDOWN_UPDATE}, {L"hybrid_shutdown",MENU_SHUTDOWN_HYBRID}, }; TMenuID menuCommand=MENU_NO; for (int i=0;i<_countof(s_NamedCommands);i++) { if (wcscmp(command,s_NamedCommands[i].name)==0) { menuCommand=s_NamedCommands[i].command; break; } } switch (menuCommand) { case MENU_NO: return false; case MENU_HELP: if (SHRestricted(REST_NOSMHELP)) return false; break; case MENU_RUN: if (SHRestricted(REST_NORUN)) return false; break; case MENU_LOGOFF: case MENU_LOGOFF_CONFIRM: if (SHRestricted(REST_STARTMENULOGOFF)==1) return false; break; case MENU_DISCONNECT: if (SHRestricted(REST_NODISCONNECT)) return false; break; case MENU_UNDOCK: if (SHRestricted(REST_NOSMEJECTPC)) return false; break; case MENU_SEARCH_COMPUTERS: if (SHRestricted(REST_HASFINDCOMPUTERS)) return false; break; case MENU_SWITCHUSER: { CComPtr pShellDisp; if (SUCCEEDED(CoCreateInstance(CLSID_Shell,NULL,CLSCTX_SERVER,IID_IShellDispatch2,(void**)&pShellDisp))) { long val; if (SUCCEEDED(pShellDisp->IsRestricted(CComBSTR(L"System"),CComBSTR(L"HideFastUserSwitching"),&val)) && val) return false; } } break; case MENU_TASKBAR: if (SHRestricted(REST_NOSETTASKBAR)) return false; break; case MENU_FEATURES: if (SHRestricted(REST_NOSETFOLDERS) || SHRestricted(REST_NOCONTROLPANEL)) return false; break; case MENU_RESTART: case MENU_SHUTDOWN: case MENU_RESTART_ADVANCED: case MENU_RESTART_UPDATE: case MENU_SHUTDOWN_UPDATE: case MENU_SHUTDOWN_HYBRID: if (SHRestricted(REST_NOCLOSE)) return false; break; } ExecuteSysCommand(menuCommand); return true; } static HRESULT CreatePinLink( PCIDLIST_ABSOLUTE sourcePidl, const wchar_t *name, const wchar_t *iconPath, int iconIndex ) { wchar_t path[_MAX_PATH]; Sprintf(path,_countof(path),L"%s\\%s.lnk",CMenuContainer::s_PinFolder,name); wchar_t finalPath[_MAX_PATH]; PathYetAnotherMakeUniqueName(finalPath,path,NULL,PathFindFileName(path)); HRESULT hr; { CComPtr pLink; hr=pLink.CoCreateInstance(CLSID_ShellLink); if (FAILED(hr)) return hr; hr=pLink->SetIDList(sourcePidl); if (FAILED(hr)) return hr; if (iconPath) { hr=pLink->SetIconLocation(iconPath,iconIndex); if (FAILED(hr)) return hr; } CComQIPtr pFile=pLink; if (!pFile) return E_FAIL; hr=pFile->Save(finalPath,TRUE); } { // reopen the link and set the "no new" property. without reopening the original properties are lost CComPtr pLink; hr=pLink.CoCreateInstance(CLSID_ShellLink); CComQIPtr pFile=pLink; hr=pFile->Load(finalPath,STGM_READWRITE); CComQIPtr pStore=pLink; if (pStore) { PROPVARIANT val; InitPropVariantFromBoolean(TRUE,&val); pStore->SetValue(PKEY_AppUserModel_ExcludeFromShowInNewInstall,val); PropVariantClear(&val); pStore->Commit(); } hr=pFile->Save(finalPath,TRUE); } HANDLE h=CreateFile(finalPath,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (h!=INVALID_HANDLE_VALUE) { FILETIME curTime; GetSystemTimeAsFileTime(&curTime); SetFileTime(h,&curTime,&curTime,&curTime); CloseHandle(h); } return S_OK; } // This function "activates" an item. The item can be activated in multiple ways: // ACTIVATE_SELECT - select the item, make sure it is visible // ACTIVATE_OPEN - if the item is a submenu, it is opened. otherwise the item is just selected (but all submenus are closed first) // ACTIVATE_OPEN_KBD - same as above, but when done with a keyboard // ACTIVATE_OPEN_SEARCH - opens the search results submenu // ACTIVATE_EXECUTE - executes the item. it can be a shell item or a command item // ACTIVATE_MENU - shows the context menu for the item // ACTIVATE_RENAME - renames the item // ACTIVATE_DELETE - deletes the item // ACTIVATE_PROPERTIES - shows the properties of the item void CMenuContainer::ActivateItem( int index, TActivateType type, const POINT *pPt, ActivateData *pData ) { LOG_MENU(LOG_EXECUTE,L"Activate Item, ptr=%p, index=%d, type=%d",this,index,type); if (index<0) { if (type==ACTIVATE_SELECT) { if (!(m_Options&CONTAINER_SEARCH)) SetFocus(); SetHotItem(-1); return; } else if (type==ACTIVATE_MENU) { index=0; type=ACTIVATE_MENU_BACKGROUND; } else return; } // make a const copy of the item and use it instead. the m_Items array can be reallocated at any time const MenuItem item=m_Items[index]; CAbsolutePidl pItemPidl1, pItemPidl2; pItemPidl1.Clone(item.pItem1); pItemPidl2.Clone(item.pItem2); ((MenuItem&)item).pItem1=NULL; // hack to ensure the pidls are not used anywhere here ((MenuItem&)item).pItem2=NULL; if (type==ACTIVATE_SELECT) { // set the hot item if (item.id==MENU_SEARCH_BOX) { m_SearchBox.SetFocus(); SetHotItem(-1); } else { if (item.id==MENU_PROGRAMS_TREE && m_pProgramsTree && m_pProgramsTree->m_hWnd) m_pProgramsTree->SetFocus(); else if (!(m_Options&CONTAINER_SEARCH) && (m_bSubMenu || s_MenuMode!=MODE_SEARCH)) SetFocus(); SetHotItem(index,false,true); } if (m_ScrollHeight>0 && indexrc.top-m_ScrollButtonSize) pos=rc.top-m_ScrollButtonSize; else if (postotal) pos=total; if (m_ScrollOffset!=pos) { m_ScrollOffset=pos; UpdateScroll(); Invalidate(); } } if (m_SearchScrollCount>m_SearchScrollHeight && index>=m_OriginalCount) { // scroll the search results to make this item visible int idx=index-m_OriginalCount; int pos=m_SearchScrollPos; if (pos>idx) pos=idx; if (pos+m_SearchScrollHeightbNoModifiers) && GetKeyState(VK_SHIFT)<0; bool bCtrl=(!pData || !pData->bNoModifiers) && GetKeyState(VK_CONTROL)<0; if (type==ACTIVATE_OPEN || type==ACTIVATE_OPEN_KBD || type==ACTIVATE_OPEN_SEARCH) { if (item.id==MENU_SEARCH_BOX && type!=ACTIVATE_OPEN_SEARCH) return; s_HotPos=GetMessagePos(); if (!item.bFolder && item.id!=MENU_SEARCH_BOX) { SetActiveWindow(); // destroy old submenus CloseSubMenus(0,this); // just select the item ActivateItem(index,ACTIVATE_SELECT,NULL); return; } OpenSubMenu(index,type,bShift); return; } bool bKeepOpen=(type==ACTIVATE_EXECUTE) && bShift && !bCtrl && (!item.bMetroLink || GetWinVersion()>=WIN_VER_WIN10); bool bTrackRecent=false; if (s_RecentPrograms!=RECENT_PROGRAMS_NONE) { if (item.id==MENU_RECENT) bTrackRecent=true; else if (!m_bSubMenu || (m_Options&CONTAINER_TRACK)) bTrackRecent=item.id==MENU_NO && (!item.bFolder || item.bHasJumpList) && !item.pStdItem && (item.categoryHash&15)<=CSearchManager::CATEGORY_SETTING; } CString searchText; for (CMenuContainer *pSearchMenu=this;pSearchMenu;pSearchMenu=pSearchMenu->m_pParent) if (pSearchMenu->m_SearchBox.m_hWnd) { pSearchMenu->m_SearchBox.GetWindowText(searchText); break; } if (type==ACTIVATE_EXECUTE) { if (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP) return; if (item.bFolder && pItemPidl1 && !item.bSplit && !GetSettingBool(L"EnableExplorer")) return; if (item.id==MENU_SEARCH_BOX) { // the search button was pressed m_SearchBox.SetFocus(); CloseSubMenus(CLOSE_POST,this); m_SearchBox.SetWindowText(L""); return; } if (item.id==MENU_SEARCH_CATEGORY) { if (bCtrl || (pData && pData->bArrow)) { for (std::list::const_iterator it=s_SearchResults.indexed.begin();it!=s_SearchResults.indexed.end();++it) { if (item.categoryHash==it->categoryHash) { if (bKeepOpen) LockSetForegroundWindow(LSFW_LOCK); else { LockSetForegroundWindow(LSFW_UNLOCK); FadeOutItem(index); CloseSubMenus(CLOSE_POST,NULL); } PlayMenuSound(SOUND_COMMAND); g_SearchManager.LaunchExternalSearch(it->search,it->categoryHash,searchText); break; } } } else { m_SearchCategoryHash=(m_SearchCategoryHash==item.categoryHash)?CSearchManager::CATEGORY_INVALID:item.categoryHash; RefreshSearch(); } return; } if (item.jumpIndex>=0) { if (item.id==MENU_NO) { if (bKeepOpen) LockSetForegroundWindow(LSFW_LOCK); else { LockSetForegroundWindow(LSFW_UNLOCK); FadeOutItem(index); CloseSubMenus(CLOSE_POST,NULL); } PlayMenuSound(SOUND_COMMAND); ExecuteJumpItem(s_JumpAppInfo,s_JumpList.groups[LOWORD(item.jumpIndex)].items[HIWORD(item.jumpIndex)],g_OwnerWindow); } return; } if (g_LogCategories&LOG_ITEMS) { LOG_MENU(LOG_EXECUTE,L"item.bLink: %d",item.bLink?1:0); LOG_MENU(LOG_EXECUTE,L"item.bMetroLink: %d",item.bMetroLink?1:0); LOG_MENU(LOG_EXECUTE,L"item.bMetroApp: %d",item.bMetroApp?1:0); if (!item.pItemInfo) { LOG_MENU(LOG_EXECUTE,L"No pItemInfo"); } else { { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); LOG_MENU(LOG_EXECUTE,L"bLink: %d",item.pItemInfo->IsLink()?1:0); LOG_MENU(LOG_EXECUTE,L"bMetroLink: %d",item.pItemInfo->IsMetroLink()?1:0); LOG_MENU(LOG_EXECUTE,L"bMetroApp: %d",item.pItemInfo->IsMetroApp()?1:0); LOG_MENU(LOG_EXECUTE,L"bProtectedLink: %d",item.pItemInfo->IsProtectedLink()?1:0); LOG_MENU(LOG_EXECUTE,L"bNoPin: %d",item.pItemInfo->IsNoPin()?1:0); LOG_MENU(LOG_EXECUTE,L"bNoNew: %d",item.pItemInfo->IsNoNew()?1:0); LOG_MENU(LOG_EXECUTE,L"path: %s",item.pItemInfo->GetPath()); LOG_MENU(LOG_EXECUTE,L"PATH: %s",item.pItemInfo->PATH); LOG_MENU(LOG_EXECUTE,L"targetPATH: %s",item.pItemInfo->GetTargetPATH()); LOG_MENU(LOG_EXECUTE,L"appid: %s",item.pItemInfo->GetAppid()); LOG_MENU(LOG_EXECUTE,L"metroName: %s",item.pItemInfo->GetMetroName()); LOG_MENU(LOG_EXECUTE,L"iconPath: %s",item.pItemInfo->GetIconPath()); } if (item.pItemInfo->smallIcon) { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ICONS); LOG_MENU(LOG_EXECUTE,L"smallIcon: %s",item.pItemInfo->smallIcon->GetPath()); } if (item.pItemInfo->largeIcon) { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ICONS); LOG_MENU(LOG_EXECUTE,L"largeIcon: %s",item.pItemInfo->largeIcon->GetPath()); } } } if (item.bMetroLink) { LockSetForegroundWindow(LSFW_UNLOCK); FadeOutItem(index); PlayMenuSound(SOUND_COMMAND); ExecuteMetroLink(item.pItemInfo); if (bTrackRecent) { CString path; { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); path=item.pItemInfo->GetPath(); } AddMRUShortcut(path); } g_ItemManager.RemoveNewItem(pItemPidl1,NULL,false); if (!(m_Options&CONTAINER_LINK)) g_SearchManager.AddItemRank(item.nameHash); // close all menus when launching Metro apps CloseSubMenus(CLOSE_POST,NULL); return; } if (!pItemPidl1) { if (item.idsubmenu && !item.pStdItem->command && item.id!=MENU_SHUTDOWN_BUTTON) return; // non-executable item } // when executing an item close the whole menu if (!bKeepOpen) { if (g_TopWin7Menu && s_bAllPrograms) { // send, don't post. the top menu must be closed immediately. otherwise its closing may interfere with launching the command ::SendMessage(g_TopWin7Menu,WM_CLOSE,0,0); } else { s_bPreventClosing=true; // hack: prevents any other closing behavior to occur while the item is being executed CloseSubMenus(CLOSE_POST,NULL); s_bPreventClosing=false; } } } if (type==ACTIVATE_MENU || type==ACTIVATE_MENU_BACKGROUND) { // when showing the context menu close all submenus if (!(m_Options&CONTAINER_SEARCH)) SetActiveWindow(); if (s_MenuMode==MODE_NORMAL) CloseSubMenus(0,this); if (m_bTwoColumns && s_MenuMode==MODE_JUMPLIST && indexcommand && *item.pStdItem->command) || item.id==MENU_SEARCH_EXECUTE || item.bStartScreen || !pItemPidl1; // this is a special executable command if (type==ACTIVATE_EXECUTE && bCommand) { if (item.bStartScreen) { g_WSMHMonitor=MonitorFromWindow(m_hWnd,MONITOR_DEFAULTTONULL); ::PostMessage(g_ProgWin,WM_SYSCOMMAND,SC_TASKLIST,'WSMH'); return; } if (bKeepOpen) LockSetForegroundWindow(LSFW_LOCK); else { LockSetForegroundWindow(LSFW_UNLOCK); if (item.id!=MENU_SLEEP && item.id!=MENU_HIBERNATE) FadeOutItem(index); // flush all messages to close the menus // m_hWnd is not valid after this point MSG msg; while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } PlayMenuSound(SOUND_COMMAND); // special handling for command items TMenuID menuCommand=(item.id==MENU_SHUTDOWN_BUTTON)?s_ShutdownCommand:item.id; // translate command switch (menuCommand) { case MENU_SEARCH_FILES: if (!GetSettingString(L"SearchFilesCommand").IsEmpty()) menuCommand=MENU_SEARCH_FILES_CUSTOM; break; case MENU_LOGOFF: // log off if (GetSettingBool(L"ConfirmLogOff")) menuCommand=MENU_LOGOFF_CONFIRM; break; case MENU_RESTART: if (GetWinVersion()>=WIN_VER_WIN8 && bShift) menuCommand=MENU_RESTART_ADVANCED; else if (s_bHasUpdates && GetWinVersion()>=WIN_VER_WIN8) menuCommand=MENU_RESTART_UPDATE; else menuCommand=MENU_RESTART_NOUPDATE; break; case MENU_SHUTDOWN: if (s_bHasUpdates) menuCommand=MENU_SHUTDOWN_UPDATE; else if (GetWinVersion()>=WIN_VER_WIN8 && !bShift && GetSettingBool(L"HybridShutdown")) menuCommand=MENU_SHUTDOWN_HYBRID; else menuCommand=MENU_SHUTDOWN_NOUPDATE; break; } switch (menuCommand) { case MENU_CLASSIC_SETTINGS: // show our settings #ifdef PREVENT_CLOSING EditSettings(true,0); #else EditSettings(false,0); #endif break; case MENU_MORE_RESULTS: g_SearchManager.LaunchExternalSearch(NULL,CSearchManager::CATEGORY_INVALID,searchText); break; case MENU_SEARCH_INTERNET: g_SearchManager.LaunchInternetSearch(searchText); break; case MENU_SEARCH_EXECUTE: ExecuteCommand(item.name,bShift && bCtrl,true); break; case MENU_SEARCH_FILES_CUSTOM: ExecuteCommand(GetSettingString(L"SearchFilesCommand"),bShift && bCtrl,true); break; default: if (!ExecuteSysCommand(menuCommand) && item.pStdItem && item.pStdItem->command && *item.pStdItem->command) { wchar_t buf[1024]; Strcpy(buf,_countof(buf),item.pStdItem->command); DoEnvironmentSubst(buf,_countof(buf)); if (!searchText.IsEmpty() && (wcswcs(buf,L"%1") || wcswcs(buf,L"%2"))) DoSearchSubst(buf,_countof(buf),searchText); ExecuteCommand(buf,bShift && bCtrl,false); } } return; } bool bHasMenu=false; if (pItemPidl1) bHasMenu=true; else if (type==ACTIVATE_MENU && (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP || item.id==MENU_SEARCH_CATEGORY)) bHasMenu=true; else if (type==ACTIVATE_MENU && item.id==MENU_APPS && (g_ItemManager.HasNewApps(true) || (pData && pData->bProgramsTree))) bHasMenu=true; if (!bHasMenu) return; bool bUninstallPolicy=GetUninstallPolicy(); bool _bProtectedLink=false; bool _bMetroApp=false; bool _bExplicitAppId=false; bool _bIsLink=false; CString _path; CItemManager::TLocation _location=CItemManager::LOCATION_UNKNOWN; CString _appId; if (item.pItemInfo && item.id!=MENU_APPS) { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); _bProtectedLink=item.pItemInfo->IsProtectedLink(); _bMetroApp=item.pItemInfo->IsMetroApp(); _path=item.pItemInfo->GetPath(); _location=item.pItemInfo->GetLocation(); _appId=item.pItemInfo->GetAppid(); _bIsLink=item.pItemInfo->IsLink(); _bExplicitAppId=item.pItemInfo->IsExplicitAppId(); } // create a context menu for the selected item. the context menu can be shown (ACTIVATE_MENU) or its default // item can be executed automatically (ACTIVATE_EXECUTE) CComPtr pMenu; HMENU menu=CreatePopupMenu(); CComPtr pSecondaryMenu; int secondaryCmd=CMD_LAST; CComPtr pItem; int insertBefore=-1, insertSecondary=-1; if (item.id==MENU_APPS) { insertBefore=0; if (g_ItemManager.HasNewApps(true)) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight")); else if (!pData || !pData->bProgramsTree) return; } else if (item.id==MENU_EMPTY || item.id==MENU_EMPTY_TOP || item.id==MENU_SEARCH_CATEGORY || type==ACTIVATE_MENU_BACKGROUND) { insertBefore=0; } else { bool bQueryMenu=true; if (item.jumpIndex>=0) { const CJumpItem &jumpItem=s_JumpList.groups[LOWORD(item.jumpIndex)].items[HIWORD(item.jumpIndex)]; // only items or links with no arguments can have a context menu bQueryMenu=((type==ACTIVATE_MENU || type==ACTIVATE_PROPERTIES) && (jumpItem.type==CJumpItem::TYPE_ITEM || (jumpItem.type==CJumpItem::TYPE_LINK && !jumpItem.bHasArguments)) && !_path.IsEmpty()); } if (bQueryMenu) { SHCreateItemFromIDList(pItemPidl1,IID_IShellItem,(void**)&pItem); CComQIPtr pItem2=pItem; if (pItem2 && ((item.categoryHash&CSearchManager::CATEGORY_MASK)!=CSearchManager::CATEGORY_ITEM || (GetSettingInt(L"CompatibilityFixes")&COMPATIBILITY_UPDATE_ITEMS))) // don't update search items because we don't have the right bind context for them pItem2->Update(NULL); if (!pItem || FAILED(pItem->BindToHandler(NULL,BHID_SFUIObject,IID_IContextMenu,(void**)&pMenu))) { DestroyMenu(menu); return; } UINT flags=CMF_DEFAULTONLY; if (type==ACTIVATE_MENU) { flags=CMF_NORMAL|CMF_CANRENAME; if (bShift) flags|=CMF_EXTENDEDVERBS; } if (type==ACTIVATE_DELETE || type==ACTIVATE_PROPERTIES) flags=CMF_NORMAL; if (type==ACTIVATE_RENAME) flags=CMF_NORMAL|CMF_CANRENAME; if (type==ACTIVATE_EXECUTE && bShift && bCtrl) flags|=CMF_EXTENDEDVERBS; HRESULT hr=pMenu->QueryContextMenu(menu,0,CMD_LAST,CMD_MAX,flags); if (FAILED(hr)) { DestroyMenu(menu); return; } secondaryCmd=CMD_LAST+LOWORD(hr)+10; } if (item.bFolder && pItemPidl2) { // context menu for a double folder - remove most commands, add Open All Users int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"open")==0) { if (GetSettingBool(L"EnableExplorer")) { if (!s_bNoCommonFolders) InsertMenu(menu,i+1,MF_BYPOSITION|MF_STRING,CMD_OPEN_ALL,FindTranslation(L"Menu.OpenAll",L"O&pen All Users")); InsertMenu(menu,i+2,MF_BYPOSITION|MF_SEPARATOR,0,0); i+=2; n+=2; continue; } } else if (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0) { if (item.id!=MENU_PROGRAMS) continue; } else if (_stricmp(command,"properties")==0) { insertBefore=i; continue; } DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } } else if (type==ACTIVATE_MENU && item.id==MENU_RECENT) { // context menu for a recent item - leave just open and runas bool bHasUninstall=false; int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"properties")==0) { insertBefore=i; continue; } if (item.bMetroLink) { if (_stricmp(command,"pin_classic")==0 || _stricmp(command,"properties")==0) continue; } else { if (bShift) { if (_stricmp(command,"delete")!=0 && _stricmp(command,"rename")!=0) continue; } else { if (_stricmp(command,"open")==0 || _stricmp(command,"opencontaining")==0 || _stricmp(command,"runas")==0 || _stricmp(command,"runasuser")==0 || _stricmp(command,"taskbarpin")==0 || _stricmp(command,"taskbarunpin")==0 || _stricmp(command,"pin_classic")==0 || _stricmp(command,"properties")==0) continue; if (_stricmp(command,"uninstall")==0) { bHasUninstall=true; if (item.bMetroApp && bUninstallPolicy && !IsProtectedApp(_appId)) continue; } } } DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } if (insertBefore==-1) insertBefore=n; if (item.bMetroLink) { InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); SetMenuDefaultItem(menu,0,TRUE); insertBefore++; if (GetWinVersion()0) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEMRU,FindTranslation(L"Menu.RemoveList",L"Remove &from this list")); if (s_RecentPrograms==RECENT_PROGRAMS_RECENT) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEALL,FindTranslation(L"Menu.RemoveAll",L"C&lear recent items list")); if (pItemPidl1 && GetSettingBool(L"EnableExplorer")) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore")); InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); } else if (type==ACTIVATE_MENU && item.bMetroLink && (_bProtectedLink || (m_Options&(CONTAINER_APPS|CONTAINER_SEARCH)))) { // context menu for a Metro link - just open, properties and Explore int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"properties")==0 || _stricmp(command,"pin_classic")==0) { insertBefore=i; continue; } DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); SetMenuDefaultItem(menu,0,TRUE); insertBefore++; if (GetWinVersion()m_OriginalCount))) { // context menu for a search item - remove delete, rename and link int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"properties")==0) { insertBefore=i; continue; } if (_stricmp(command,"delete")!=0 && _stricmp(command,"rename")!=0) continue; DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } bool last=insertBefore==-1; if (last) insertBefore=n; CSearchManager::TItemCategory cat=(CSearchManager::TItemCategory)(item.categoryHash&CSearchManager::CATEGORY_MASK); if (pItemPidl1 && (cat<=CSearchManager::CATEGORY_FILE || cat==CSearchManager::CATEGORY_AUTOCOMPLETE)) { bool bExplore=GetSettingBool(L"EnableExplorer"); bool bPin=!s_PinFolder.IsEmpty() && (cat==CSearchManager::CATEGORY_SETTING || cat==CSearchManager::CATEGORY_METROSETTING); if (bExplore || bPin) { if (n>0) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); if (bPin) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PINSETTING,FindTranslation(L"Menu.PinStartCs",L"Pin to Start menu (Classic Shell)")); if (bExplore) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore")); if (!last) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); } } } else if (item.jumpIndex>=0) { // context menu for a jumplist item - just properties int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"properties")==0) continue; DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } insertBefore=0; const CJumpGroup &group=s_JumpList.groups[LOWORD(item.jumpIndex)]; InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); SetMenuDefaultItem(menu,0,TRUE); if (group.type!=CJumpGroup::TYPE_TASKS) { InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); if (group.type==CJumpGroup::TYPE_PINNED) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PIN,FindTranslation(L"JumpList.Unpin",L"&Unpin from this list")); else { InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_PIN,FindTranslation(L"JumpList.Pin",L"P&in to this list")); InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_DELETEMRU,FindTranslation(L"JumpList.Remove",L"Remove &from this list")); } if (n>0) { InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); if (GetSettingBool(L"EnableExplorer")) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,FindTranslation(L"Menu.Explore",L"&Explore")); } } } else { bool bHasUninstall=false; int n=GetMenuItemCount(menu); for (int i=0;iCMD_MAX || FAILED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"properties")==0) { insertBefore=i; continue; } bool bDelete=false; if (item.pStdItem && (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0)) bDelete=true; else if (item.bMetroLink && _stricmp(command,"rename")==0) bDelete=true; else if (_stricmp(command,"uninstall")==0) { bHasUninstall=true; if ((!item.bMetroApp && !item.bMetroLink) || !bUninstallPolicy || IsProtectedApp(_appId)) bDelete=true; } else if (item.bStartScreen) { if (_stricmp(command,"rename")==0 || _stricmp(command,"delete")==0) EnableMenuItem(menu,i,MF_GRAYED|MF_BYPOSITION); else if (_stricmp(command,"pin_classic")==0 && IsSettingLocked(L"StartScreenShortcut")) EnableMenuItem(menu,i,MF_GRAYED|MF_BYPOSITION); else if (_stricmp(command,"open")==0 || _stricmp(command,"opencontaining")==0 || _stricmp(command,"runas")==0) bDelete=true; } if (bDelete) { DeleteMenu(menu,i,MF_BYPOSITION); i--; n--; } } if (insertBefore==-1) insertBefore=n; if (item.bMetroLink) { InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_OPEN,FindTranslation(L"Menu.Open",L"&Open")); SetMenuDefaultItem(menu,0,TRUE); insertBefore++; if (GetWinVersion()=0) { pSecondaryMenu=GetMetroPinMenu(_appId); if (pSecondaryMenu) { pSecondaryMenu->QueryContextMenu(menu,insertSecondary,secondaryCmd,CMD_MAX,CMF_NORMAL); } } s_HotPos=GetMessagePos(); int res=0; if (type==ACTIVATE_EXECUTE) { // just pick the default item res=GetMenuDefaultItem(menu,FALSE,0); if (bShift && bCtrl) { // find the runas verb if available res=-1; char command[256]; int n=GetMenuItemCount(menu); for (int i=0;i=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) { if (_stricmp(command,"runas")==0) { res=id; break; } } } if (res==-1) { CComString pName; if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName))) { ExecuteCommand(pName,true,false); DestroyMenu(menu); s_HotPos=GetMessagePos(); return; } res=0; } } if (res<0) res=0; } else if (type==ACTIVATE_RENAME || type==ACTIVATE_DELETE || type==ACTIVATE_PROPERTIES) { if ((type==ACTIVATE_RENAME || type==ACTIVATE_DELETE) && item.bStartScreen) res=0; else if (type==ACTIVATE_DELETE && item.id==MENU_RECENT) res=CMD_DELETEMRU; else if ((type==ACTIVATE_RENAME || type==ACTIVATE_DELETE) && item.bMetroLink && (_bProtectedLink || (m_Options&(CONTAINER_APPS|CONTAINER_SEARCH)))) res=0; else { const char *name; switch (type) { case ACTIVATE_RENAME: name="rename"; break; case ACTIVATE_DELETE: name="delete"; break; case ACTIVATE_PROPERTIES: name="properties"; break; } char command[256]; int n=GetMenuItemCount(menu); for (int i=0;i=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) { if (_stricmp(command,name)==0) { res=id; break; } } } if (res<0) res=0; } } else { if (!GetSettingBool(L"EnableExplorer")) { // disable the Open verb char command[256]; int n=GetMenuItemCount(menu); for (int i=0;i=CMD_LAST && id<=CMD_MAX && SUCCEEDED(pMenu->GetCommandString(id-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) { if ((item.bFolder && !item.bSplit && pItemPidl1 && _stricmp(command,"open")==0) || _stricmp(command,"opencontaining")==0) { EnableMenuItem(menu,i,MF_BYPOSITION|MF_GRAYED); } } } } // show the context menu m_pMenu2=pMenu; m_pMenu3=pMenu; HBITMAP shellBmp=NULL; HBITMAP newFolderBmp=NULL; HBITMAP newShortcutBmp=NULL; if ((item.id==MENU_NO || item.id==MENU_EMPTY || type==ACTIVATE_MENU_BACKGROUND || (item.id==MENU_APPS && pData && pData->bProgramsTree)) && item.jumpIndex<0 && index0) { if (GetSettingBool(L"CascadingMenu")) { menu2=CreatePopupMenu(); subMenuIdx=insertBefore; insertBefore=0; } } bool bSort=false, bAutoSort=false, bNew=false, bMarkOld=false; if (pData && pData->bProgramsTree) { bNew=!(item.pItemInfo && _location==CItemManager::LOCATION_METRO) && !pData->bApps && GetSettingBool(L"ShowNewFolder"); bSort=true; bAutoSort=pData->bAutoSort; } else { int n=0; for (std::vector::const_iterator it=m_Items.begin();it!=m_Items.end();++it) if (it->id==MENU_NO) n++; if (n>1) bSort=true; // more than 1 movable items wchar_t path[_MAX_PATH]; if (!(m_Options&CONTAINER_APPS) && !(item.pItemInfo && _location==CItemManager::LOCATION_METRO) && !(m_Options&CONTAINER_NONEWFOLDER) && GetSettingBool(L"ShowNewFolder") && SHGetPathFromIDList(m_Path1[item.priority==2?1:0],path)) bNew=true; bAutoSort=(m_Options&CONTAINER_AUTOSORT)!=0; } bMarkOld=item.bNew && pItemPidl1; if (bSort) InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_SORT,FindTranslation(L"Menu.SortByName",L"Sort &by Name")); if (m_FolderHash[0]) InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_AUTOSORT,FindTranslation(L"Menu.AutoArrange",L"&Auto Arrange")); if (bAutoSort) { EnableMenuItem(menu2,CMD_SORT,MF_BYCOMMAND|MF_GRAYED); CheckMenuItem(menu2,CMD_AUTOSORT,MF_BYCOMMAND|MF_CHECKED); } if (bNew) { InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_NEWFOLDER,FindTranslation(L"Menu.NewFolder",L"New Folder")); InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_NEWSHORTCUT,FindTranslation(L"Menu.NewShortcut",L"New Shortcut")); } if (bMarkOld) InsertMenu(menu2,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight")); if (menu!=menu2 && GetMenuItemCount(menu2)==0) { DestroyMenu(menu2); menu2=menu; } else InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_SEPARATOR,0,0); if (bNew || menu!=menu2) { int size=GetSystemMetrics(SM_CXSMICON); if (bNew) { HMODULE hShell32=GetModuleHandle(L"shell32.dll"); HICON hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(319),IMAGE_ICON,size,size,LR_DEFAULTCOLOR); if (hIcon) { newFolderBmp=BitmapFromIcon(hIcon,size,NULL,true); MENUITEMINFO mii={sizeof(mii)}; mii.fMask=MIIM_BITMAP; mii.hbmpItem=newFolderBmp; SetMenuItemInfo(menu2,CMD_NEWFOLDER,FALSE,&mii); } hIcon=(HICON)LoadImage(hShell32,MAKEINTRESOURCE(16769),IMAGE_ICON,size,size,LR_DEFAULTCOLOR); if (hIcon) { newShortcutBmp=BitmapFromIcon(hIcon,size,NULL,true); MENUITEMINFO mii={sizeof(mii)}; mii.fMask=MIIM_BITMAP; mii.hbmpItem=newShortcutBmp; SetMenuItemInfo(menu2,CMD_NEWSHORTCUT,FALSE,&mii); } } if (menu!=menu2) { InsertMenu(menu,subMenuIdx,MF_BYPOSITION|MF_POPUP,(UINT_PTR)menu2,FindTranslation(L"Menu.Organize",L"Organize Start menu")); HICON hIcon=(HICON)LoadImage(g_Instance,MAKEINTRESOURCE(IDI_APPICON),IMAGE_ICON,size,size,LR_DEFAULTCOLOR); if (hIcon) { shellBmp=BitmapFromIcon(hIcon,size,NULL,true); MENUITEMINFO mii={sizeof(mii)}; mii.fMask=MIIM_BITMAP; mii.hbmpItem=shellBmp; SetMenuItemInfo(menu,subMenuIdx,TRUE,&mii); } } } } if (item.id==MENU_SEARCH_CATEGORY) { InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_TOGGLE,item.categoryHash==m_SearchCategoryHash?FindTranslation(L"Menu.Collapse",L"Coll&apse"):FindTranslation(L"Menu.Expand",L"Exp&and")); if (item.categoryHash>=CSearchManager::CATEGORY_FILE) { wchar_t text[256]; Sprintf(text,_countof(text),L"%s\t(Ctrl+Enter)",FindTranslation(L"Menu.MoreResults",L"See more results")); InsertMenu(menu,1,MF_BYPOSITION|MF_STRING,CMD_EXPLORE,text); } SetMenuDefaultItem(menu,(pData && pData->bArrow)?1:0,TRUE); } if (item.id==MENU_PROGRAMS) { bool bNew; if (s_bWin7Style && GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro")) bNew=g_ItemManager.HasNewPrograms(true) || g_ItemManager.HasNewApps(true); else bNew=g_ItemManager.HasNewPrograms(true); if (bNew) InsertMenu(menu,insertBefore++,MF_BYPOSITION|MF_STRING,CMD_MARKOLD,FindTranslation(L"Menu.RemoveHighlight",L"Remove highlight")); } if (pData && pData->bProgramsTree && item.bFolder && type==ACTIVATE_MENU) { InsertMenu(menu,0,MF_BYPOSITION|MF_STRING,CMD_TOGGLE,pData->bExpanded?FindTranslation(L"Menu.Collapse",L"Coll&apse"):FindTranslation(L"Menu.Expand",L"Exp&and")); SetMenuDefaultItem(menu,0,TRUE); InsertMenu(menu,1,MF_BYPOSITION|MF_SEPARATOR,0,0); } // remove multiple separators { bool bSeparator=true; int n=GetMenuItemCount(menu); for (int i=0;i0 && bSeparator) DeleteMenu(menu,n-1,MF_BYPOSITION); } TPMPARAMS params={sizeof(params)}, *pParams=NULL; POINT pt2; if (pPt) pt2=*pPt; else { GetItemRect(index,params.rcExclude); MapWindowPoints(NULL,¶ms.rcExclude); pt2.x=params.rcExclude.left; pt2.y=params.rcExclude.top; pParams=¶ms; } SetContextItem(index); InvalidateItem(index); KillTimer(TIMER_HOVER); res=0; if (GetMenuItemCount(menu)>0) { LOG_MENU(LOG_EXECUTE,L"Open context menu, ptr=%p",this); res=TrackPopupMenuEx(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD|TPM_VERTICAL|(IsLanguageRTL()?TPM_LAYOUTRTL:0),pt2.x,pt2.y,m_hWnd,pParams); LOG_MENU(LOG_EXECUTE,L"Select context menu, ptr=%p, index=%d",this,res); } SetContextItem(-1); if (m_HotItem<0 && !m_bDestroyed) SetHotItem(index); if (m_pMenu2) m_pMenu2.Release(); if (m_pMenu3) m_pMenu3.Release(); if (newFolderBmp) DeleteObject(newFolderBmp); if (newShortcutBmp) DeleteObject(newShortcutBmp); if (shellBmp) DeleteObject(shellBmp); } ExitGuard guard; // no returns are allowed until the end cleanup if (pData) pData->command=res; if (type==ACTIVATE_EXECUTE) { if (bKeepOpen) LockSetForegroundWindow(LSFW_LOCK); else { LockSetForegroundWindow(LSFW_UNLOCK); FadeOutItem(index); } PlayMenuSound(SOUND_COMMAND); } if (res==CMD_PINSETTING) { CSearchManager::TItemCategory cat=(CSearchManager::TItemCategory)(item.categoryHash&CSearchManager::CATEGORY_MASK); if (cat==CSearchManager::CATEGORY_SETTING) CreatePinLink(pItemPidl1,item.name,NULL,0); else if (cat==CSearchManager::CATEGORY_METROSETTING) CreatePinLink(pItemPidl1,item.name,L"%windir%\\ImmersiveControlPanel\\systemsettings.exe",0); m_bRefreshItems=true; } // handle our standard commands if (item.jumpIndex>=0 && res!=CMD_EXPLORE && resbProgramsTree) { m_pProgramsTree->OrderElements(pData->hTreeItem,TreeView_GetParent(m_pProgramsTree->m_hWnd,pData->hTreeItem),std::vector(),false,true); } else { std::vector items; for (int i=0;i=WIN_VER_WIN8 && GetSettingBool(L"AllProgramsMetro")); if (m_pProgramsTree) m_pProgramsTree->ClearAllNew(); } else g_ItemManager.RemoveNewItem(pItemPidl1,pItemPidl2,item.bFolder); PostRefreshMessage(); } if (res==CMD_AUTOSORT) { if (pData && pData->bProgramsTree) { m_pProgramsTree->OrderElements(pData->hTreeItem,TreeView_GetParent(m_pProgramsTree->m_hWnd,pData->hTreeItem),std::vector(),!pData->bAutoSort,true); } else { if (m_FolderHash[0]) { CRegKey regOrder; if (regOrder.Open(HKEY_CURRENT_USER,L"Software\\IvoSoft\\ClassicStartMenu\\Order")!=ERROR_SUCCESS) regOrder.Create(HKEY_CURRENT_USER,L"Software\\IvoSoft\\ClassicStartMenu\\Order"); wchar_t name[100]; Sprintf(name,_countof(name),L"%08X",m_FolderHash[0]); if (m_Options&CONTAINER_AUTOSORT) regOrder.SetBinaryValue(name,NULL,0); else { DWORD cAuto='AUTO'; regOrder.SetBinaryValue(name,&cAuto,4); } if (m_FolderHash[1]) { Sprintf(name,_countof(name),L"%08X",m_FolderHash[1]); if (m_Options&CONTAINER_AUTOSORT) regOrder.SetBinaryValue(name,NULL,0); else { DWORD cAuto='AUTO'; regOrder.SetBinaryValue(name,&cAuto,4); } } } PostRefreshMessage(); } res=0; } if (res==CMD_NEWFOLDER) { g_RenameText=item.name; if (pPt) g_RenamePos=*pPt; else { g_RenamePos.x=item.itemRect.left; g_RenamePos.y=item.itemRect.top; ClientToScreen(&g_RenamePos); } bool bAllPrograms=s_bAllPrograms; for (std::vector::iterator it=s_Menus.begin();it!=s_Menus.end();++it) (*it)->EnableWindow(FALSE); // disable all menus if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE); CComPtr pFolder; // have to use IShellFolder for renaming because it's the only one that supports changing the display name if (pItemPidl1) { PCUITEMID_CHILD pidl; SHBindToParent(pItemPidl1,IID_IShellFolder,(void**)&pFolder,&pidl); } else if (pData && pData->bProgramsTree) { CComPtr pDesktop; if (SUCCEEDED(SHGetDesktopFolder(&pDesktop))) pDesktop->BindToObject(pData->parent,NULL,IID_IShellFolder,(void**)&pFolder); } else { CComPtr pDesktop; if (SUCCEEDED(SHGetDesktopFolder(&pDesktop))) pDesktop->BindToObject(m_Path1[0],NULL,IID_IShellFolder,(void**)&pFolder); } if (pFolder) { CComPtr pMenu2; HMENU menu2=CreatePopupMenu(); std::vector items; { CComPtr pEnum; if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL; PITEMID_CHILD child; while (pEnum && pEnum->Next(1,&child,NULL)==S_OK) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str))) { CComString pName; StrRetToStr(&str,child,&pName); items.push_back(CalcFNVHash(pName)); } ILFree(child); } } s_bPreventClosing=true; if (SUCCEEDED(pFolder->CreateViewObject(g_OwnerWindow,IID_IContextMenu,(void**)&pMenu2))) { if (SUCCEEDED(pMenu2->QueryContextMenu(menu2,0,1,32767,CMF_NORMAL))) { CMINVOKECOMMANDINFOEX info={sizeof(info),CMIC_MASK_UNICODE}; info.lpVerb="NewFolder"; info.lpVerbW=L"NewFolder"; info.nShow=SW_SHOWNORMAL; info.fMask|=CMIC_MASK_NOASYNC; info.hwnd=g_OwnerWindow; pMenu2->InvokeCommand((CMINVOKECOMMANDINFO*)&info); } } DestroyMenu(menu2); HideTemp(false); s_bPreventClosing=false; PITEMID_CHILD newPidl=NULL; unsigned int newHash=0; { CComPtr pEnum; if (pFolder->EnumObjects(NULL,SHCONTF_FOLDERS,&pEnum)!=S_OK) pEnum=NULL; PITEMID_CHILD child; while (pEnum && pEnum->Next(1,&child,NULL)==S_OK) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FORPARSING,&str))) { CComString pName; StrRetToStr(&str,child,&pName); unsigned int hash=CalcFNVHash(pName); if (std::find(items.begin(),items.end(),hash)==items.end()) { if (SUCCEEDED(pFolder->GetDisplayNameOf(child,SHGDN_INFOLDER|SHGDN_FOREDITING,&str))) { CComString pName2; StrRetToStr(&str,child,&pName2); g_RenameText=pName2; } else g_RenameText=pName; pName.MakeUpper(); newHash=CalcFNVHash(pName,item.priority==2?CalcFNVHash(L"\\"):FNV_HASH0); newPidl=child; break; } } ILFree(child); } } if (!pData || !pData->bProgramsTree) { PostRefreshMessage(); if (!m_bDestroyed) PostMessage(MCM_SETCONTEXTITEM,newHash); } // show the Rename dialog box s_bPreventClosing=true; if (newPidl && DialogBox(g_Instance,MAKEINTRESOURCE(s_bRTL?IDD_RENAMER:IDD_RENAME),g_OwnerWindow,RenameDlgProc)) { PITEMID_CHILD newPidl2=NULL; if (SUCCEEDED(pFolder->SetNameOf(g_OwnerWindow,newPidl,g_RenameText,SHGDN_INFOLDER,&newPidl2))) { ILFree(newPidl); newPidl=newPidl2; if (!pData || !pData->bProgramsTree) { PostRefreshMessage(); StringUpper(g_RenameText); newHash=CalcFNVHash(g_RenameText,item.priority==2?CalcFNVHash(L"\\"):FNV_HASH0); if (!m_bDestroyed) PostMessage(MCM_SETCONTEXTITEM,newHash); } } } if (newPidl && pData && pData->bProgramsTree) { CComPtr pNewItem; if (SUCCEEDED(SHCreateItemWithParent(NULL,pFolder,newPidl,IID_IShellItem,(void**)&pNewItem))) { CAbsolutePidl newAbsPidl; if (SUCCEEDED(SHGetIDListFromObject(pNewItem,&newAbsPidl))) pData->pNewItemInfo=g_ItemManager.GetItemInfo(pNewItem,newAbsPidl,0); } } if (newPidl) ILFree(newPidl); for (std::vector::iterator it=s_Menus.begin();it!=s_Menus.end();++it) if (!(*it)->m_bDestroyed) (*it)->EnableWindow(TRUE); // enable all menus if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE); if (!m_bDestroyed) { SetForegroundWindow(m_hWnd); SetActiveWindow(); if (pData && pData->bProgramsTree) m_pProgramsTree->SetFocus(); else SetFocus(); Invalidate(); if (m_HotItem<0) SetHotItem(index); } HideTemp(false); s_bPreventClosing=false; } SetContextItem(-1); res=0; } if (res==CMD_NEWSHORTCUT) { wchar_t target[_MAX_PATH+1]; if (pData && pData->bProgramsTree) SHGetPathFromIDList(pData->parent,target); else SHGetPathFromIDList(m_Path1[0],target); target[Strlen(target)+1]=0; wchar_t fname[_MAX_PATH+1]; // first try in the original folder PathMakeUniqueName(fname,_countof(fname)-1,L"scut.lnk",L"New Shortcut.lnk",target); HANDLE hFile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); // just run the shortcut wizard wchar_t cmdLine[1024]; Sprintf(cmdLine,_countof(cmdLine),L"rundll32.exe appwiz.cpl,NewLinkHere %s",fname); STARTUPINFO startupInfo={sizeof(startupInfo)}; PROCESS_INFORMATION processInfo; memset(&processInfo,0,sizeof(processInfo)); wchar_t exe[_MAX_PATH]=L"%windir%\\system32\\rundll32.exe"; DoEnvironmentSubst(exe,_countof(exe)); if (CreateProcess(exe,cmdLine,NULL,NULL,FALSE,0,NULL,target,&startupInfo,&processInfo)) { CloseHandle(processInfo.hThread); CloseHandle(processInfo.hProcess); } } else if (GetLastError()==ERROR_ACCESS_DENIED) { // there was a problem, most likely UAC didn't let us create a folder // create a temp folder just for us wchar_t temp[_MAX_PATH]; GetTempPath(_countof(temp),temp); Strcat(temp,_countof(temp),L"ClassicShell"); CreateDirectory(temp,NULL); // make a unique link file and keep a handle to the file PathMakeUniqueName(fname,_countof(fname)-1,L"scut.lnk",L"New Shortcut.lnk",temp); HANDLE hFile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); // wait for the wizard to finish in a separate thread and close the menu // otherwise it appears behind the menu ShortcutParams *pParams=new ShortcutParams; memcpy(pParams->target,target,sizeof(target)); memcpy(pParams->temp,temp,sizeof(temp)); memcpy(pParams->fname,fname,sizeof(fname)); CreateThread(NULL,0,NewShortcutThread,pParams,0,NULL); } } res=0; } if (res==CMD_DELETEMRU && item.id==MENU_RECENT && s_RecentPrograms!=RECENT_PROGRAMS_NONE) { if (s_RecentPrograms==RECENT_PROGRAMS_RECENT) { CComString pName; if (_bMetroApp) DeleteMRUAppId(_appId); else if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName))) DeleteMRUShortcut(pName); } else if (s_RecentPrograms==RECENT_PROGRAMS_FREQUENT) { RemoveMFUShortcut(item.mfuHash,_bMetroApp); } PostRefreshMessage(); res=0; } if (res==CMD_DELETEALL && item.id==MENU_RECENT && s_RecentPrograms==RECENT_PROGRAMS_RECENT) { DeleteMRUShortcut(NULL); PostRefreshMessage(); res=0; } if (res==CMD_EXPLORE) { if (item.id==MENU_SEARCH_CATEGORY) { for (std::list::const_iterator it=s_SearchResults.indexed.begin();it!=s_SearchResults.indexed.end();++it) { if (item.categoryHash==it->categoryHash) { FadeOutItem(index); PlayMenuSound(SOUND_COMMAND); g_SearchManager.LaunchExternalSearch(it->search,it->categoryHash,searchText); break; } } } else { SHOpenFolderAndSelectItems(pItemPidl1,0,NULL,0); } res=0; } if (res==CMD_UNINSTALL) { UninstallMetroApp(g_OwnerWindow,item.name,_appId); res=0; } if (item.id==MENU_SEARCH_CATEGORY && res==CMD_TOGGLE) { m_SearchCategoryHash=(m_SearchCategoryHash==item.categoryHash)?CSearchManager::CATEGORY_INVALID:item.categoryHash; RefreshSearch(); res=0; } // handle the shell commands if (res>=CMD_LAST) { // handle special verbs char command[256]; if (FAILED(pMenu->GetCommandString(res-CMD_LAST,GCS_VERBA,NULL,command,_countof(command)))) command[0]=0; if (_stricmp(command,"rename")==0) { // show the Rename dialog box CComPtr pFolder; // have to use IShellFolder for renaming because it's the only one that supports changing the display name PCUITEMID_CHILD pidl; s_bPreventClosing=true; STRRET str; if (SUCCEEDED(SHBindToParent(pItemPidl1,IID_IShellFolder,(void**)&pFolder,&pidl)) && SUCCEEDED(pFolder->GetDisplayNameOf(pidl,SHGDN_FOREDITING,&str))) { CComString pName; StrRetToStr(&str,pidl,&pName); g_RenameText=pName; } else g_RenameText=item.name; if (pPt) g_RenamePos=*pPt; else { g_RenamePos.x=item.itemRect.left; g_RenamePos.y=item.itemRect.top; ClientToScreen(&g_RenamePos); } for (std::vector::iterator it=s_Menus.begin();it!=s_Menus.end();++it) (*it)->EnableWindow(FALSE); // disable all menus bool bAllPrograms=s_bAllPrograms; if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE); SetContextItem(index); InvalidateItem(index); bool bRenamed=DialogBox(g_Instance,MAKEINTRESOURCE(s_bRTL?IDD_RENAMER:IDD_RENAME),g_OwnerWindow,RenameDlgProc)!=0; SetContextItem(-1); if (m_HotItem<0) SetHotItem(index); if (bRenamed) { if (GetWinVersion()>=WIN_VER_WIN8) { SetForegroundWindow(m_hWnd); SetActiveWindow(); if (pData && pData->bProgramsTree) m_pProgramsTree->SetFocus(); else SetFocus(); } // perform the rename operation PITEMID_CHILD newPidl; if (SUCCEEDED(pFolder->SetNameOf(g_OwnerWindow,pidl,g_RenameText,SHGDN_INFOLDER,&newPidl))) { STRRET str; if (SUCCEEDED(pFolder->GetDisplayNameOf(newPidl,SHGDN_INFOLDER|SHGDN_FORPARSING,&str))) { CComString pName; StrRetToStr(&str,newPidl,&pName); pName.MakeUpper(); m_Items[index].name=g_RenameText; m_Items[index].nameHash=CalcFNVHash(pName); if (!(m_Options&CONTAINER_AUTOSORT) && (!pData || !pData->bProgramsTree)) { std::vector items; for (int i=0;iGetDisplayNameOf(newPidl,SHGDN_FORPARSING,&str))) { CComString pPath; StrRetToStr(&str,newPidl,&pPath); CComPtr pLink; pLink.CoCreateInstance(CLSID_ShellLink); CComQIPtr pFile=pLink; if (pFile && SUCCEEDED(pFile->Load(pPath,STGM_READWRITE))) { CComQIPtr pStore=pLink; if (pStore) { PROPVARIANT val; InitPropVariantFromString(_appId,&val); if (SUCCEEDED(pStore->SetValue(PKEY_AppUserModel_ID,val)) && SUCCEEDED(pStore->Commit())) pFile->Save(pPath,TRUE); PropVariantClear(&val); } } } if (pData) { CComPtr pNewItem; if (SUCCEEDED(SHCreateItemWithParent(NULL,pFolder,newPidl,IID_IShellItem,(void**)&pNewItem))) { CAbsolutePidl newAbsPidl; if (SUCCEEDED(SHGetIDListFromObject(pNewItem,&newAbsPidl))) pData->pNewItemInfo=g_ItemManager.GetItemInfo(pNewItem,newAbsPidl,0); } } } ILFree(newPidl); } if (!pData || !pData->bProgramsTree) PostRefreshMessage(); } for (std::vector::iterator it=s_Menus.begin();it!=s_Menus.end();++it) if (!(*it)->m_bDestroyed) (*it)->EnableWindow(TRUE); // enable all menus if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE); if (!m_bDestroyed) { SetForegroundWindow(m_hWnd); SetActiveWindow(); if (pData && pData->bProgramsTree) m_pProgramsTree->SetFocus(); else SetFocus(); } HideTemp(false); s_bPreventClosing=false; s_HotPos=GetMessagePos(); res=CMD_RENAME; } else if (_stricmp(command,"uninstall")==0 && _bMetroApp && !_appId.IsEmpty()) { UninstallMetroApp(g_OwnerWindow,item.name,_appId); } else { bool bRefreshMain=_stricmp(command,"pin_classic")==0; bool bRefresh=(_stricmp(command,"delete")==0 || _stricmp(command,"link")==0); if (item.bStartScreen && _stricmp(command,"pin_classic")==0) { { CSettingsLockWrite lock; CSetting *pSetting=FindSetting(L"StartScreenShortcut"); if (!pSetting->IsLocked()) { pSetting->value=CComVariant(0); pSetting->flags&=~CSetting::FLAG_DEFAULT; } } SaveSettings(); } IContextMenu *pInvokeMenu=pMenu; int verbOffset=CMD_LAST; if (pSecondaryMenu && res>=secondaryCmd) { pInvokeMenu=pSecondaryMenu; verbOffset=secondaryCmd; } CMINVOKECOMMANDINFOEX info={sizeof(info),CMIC_MASK_UNICODE|CMIC_MASK_FLAG_LOG_USAGE}; info.lpVerb=MAKEINTRESOURCEA(res-verbOffset); info.lpVerbW=MAKEINTRESOURCEW(res-verbOffset); info.nShow=SW_SHOWNORMAL; wchar_t dir[_MAX_PATH]; if (SHGetPathFromIDList(pItemPidl1,dir)) { PathRemoveFileSpec(dir); if (GetFileAttributes(dir)!=INVALID_FILE_ATTRIBUTES) info.lpDirectoryW=dir; } if (pPt) { info.fMask|=CMIC_MASK_PTINVOKE; info.ptInvoke=*pPt; } if (type==ACTIVATE_MENU) { if (bCtrl) info.fMask|=CMIC_MASK_CONTROL_DOWN; if (bShift) info.fMask|=CMIC_MASK_SHIFT_DOWN; } if (bRefresh || bRefreshMain) info.fMask|=CMIC_MASK_NOASYNC; // wait for delete/link commands to finish so we can refresh the menu if ((type!=ACTIVATE_MENU && type!=ACTIVATE_DELETE) || GetWinVersion()::iterator it=s_Menus.begin();it!=s_Menus.end();++it) (*it)->EnableWindow(FALSE); // disable all menus bool bAllPrograms=s_bAllPrograms; if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,FALSE); info.hwnd=g_OwnerWindow; RECT rc; GetWindowRect(&rc); ::SetForegroundWindow(g_OwnerWindow); ::SetWindowPos(g_OwnerWindow,HWND_TOPMOST,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,0); LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, command='%S'",this,command); HRESULT hr=pInvokeMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info); LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr); if (type==ACTIVATE_EXECUTE && SUCCEEDED(hr)) { if (bTrackRecent) { if (_bMetroApp) AddMRUAppId(_appId); else if (_path.IsEmpty()) { CComString pName; if (SUCCEEDED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName))) AddMRUShortcut(pName); } else AddMRUShortcut(_path); } g_ItemManager.RemoveNewItem(pItemPidl1,NULL,false); if (!(m_Options&CONTAINER_LINK)) { // update item ranks CComString pName; if (_bMetroApp) { CString APPID=_appId; APPID.MakeUpper(); g_SearchManager.AddItemRank(CalcFNVHash(APPID)); } else if (SUCCEEDED(pItem->GetDisplayName(SIGDN_PARENTRELATIVEPARSING,&pName))) // can't use item.name because the extension may be removed { pName.MakeUpper(); g_SearchManager.AddItemRank(CalcFNVHash(pName)); } } } for (std::vector::iterator it=s_Menus.begin();it!=s_Menus.end();++it) if (!(*it)->m_bDestroyed) (*it)->EnableWindow(TRUE); // enable all menus if (bAllPrograms) ::EnableWindow(g_TopWin7Menu,TRUE); if (bRefreshMain && m_bSubMenu) { CMenuContainer *pMain=s_Menus[0]; if (!pMain->m_bSubMenu && !pMain->m_bDestroyed) { SetForegroundWindow(pMain->m_hWnd); pMain->SetActiveWindow(); pMain->SetFocus(); CloseSubMenus(CLOSE_POST,pMain); pMain->PostRefreshMessage(); } } else if ((bRefresh || bKeepOpen || bRefreshMain) && !m_bDestroyed) { SetForegroundWindow(m_hWnd); SetActiveWindow(); if (m_Options&CONTAINER_SEARCH) { m_pParent->m_SearchBox.SetFocus(); SetWindowPos(HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); } else if (pData && pData->bProgramsTree) m_pProgramsTree->SetFocus(); else SetFocus(); } HideTemp(false); s_bPreventClosing=false; if (!bKeepOpen && !bRefresh && !bRefreshMain) { HWND active=GetActiveWindow(); if (active!=m_hWnd && active!=g_OwnerWindow) { // if after all the window is not active, then another application was launched - close all menus CloseSubMenus(CLOSE_POST,NULL); if (g_TopWin7Menu && s_bAllPrograms) ::PostMessage(g_TopWin7Menu,WM_CLOSE,0,0); } } if (_stricmp(command,"delete")==0) res=CMD_DELETE; if ((bRefresh && (!pData || !pData->bProgramsTree)) || (bRefreshMain && !m_bSubMenu)) { if (bRefreshMain && !m_bSubMenu && (s_MenuMode==MODE_SEARCH || s_MenuMode==MODE_JUMPLIST)) m_bRefreshItems=true; else PostRefreshMessage(); // refresh the menu after an item was deleted or created } } } DestroyMenu(menu); s_HotPos=GetMessagePos(); if (pData && res) pData->command=res; LOG_MENU(LOG_EXECUTE,L"Exit activate, ptr=%p",this); guard.Disarm(); } void CMenuContainer::ActivateTreeItem( const void *treeItem, RECT &itemRect, TActivateType type, const POINT *pPt, ActivateData *pData ) { AddRef(); // prevent the menu from being deleted while processing the operation Assert(pData && pData->bProgramsTree); const CProgramsTree::CTreeItem *pTreeItem=(CProgramsTree::CTreeItem*)treeItem; MenuItem &item=m_Items[m_ProgramTreeIndex]; item.id=MENU_NO; if (pTreeItem->bApps) item.id=MENU_APPS; else if (pTreeItem->bEmpty) item.id=MENU_EMPTY; item.name=pTreeItem->name; item.pItemInfo=pTreeItem->pItemInfo1; RECT rc=item.itemRect; item.itemRect=itemRect; item.pItem1=pTreeItem->pItemInfo1?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo1->GetPidl():NULL; item.pItem2=pTreeItem->pItemInfo2?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo2->GetPidl():NULL; item.bFolder=pTreeItem->bFolder; item.bMetroLink=false; item.bMetroApp=false; item.bNew=pTreeItem->bNew; if (pTreeItem->pItemInfo1) { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); item.bMetroLink=pTreeItem->pItemInfo1->IsMetroLink(); item.bMetroApp=pTreeItem->pItemInfo1->IsMetroApp(); } pData->bApps=pTreeItem->bApps; ActivateItem(m_ProgramTreeIndex,type,pPt,pData); item.id=MENU_PROGRAMS_TREE; item.itemRect=rc; item.name.Empty(); item.pItemInfo=NULL; item.pItem1=NULL; item.pItem2=NULL; Release(); } void CMenuContainer::DragTreeItem( const void *treeItem, bool bApp ) { const CProgramsTree::CTreeItem *pTreeItem=(CProgramsTree::CTreeItem*)treeItem; MenuItem &item=m_Items[m_ProgramTreeIndex]; item.id=MENU_NO; item.name=pTreeItem->name; item.pItemInfo=pTreeItem->pItemInfo1; item.pItem1=pTreeItem->pItemInfo1->GetPidl(); item.pItem2=pTreeItem->pItemInfo2?(PIDLIST_ABSOLUTE)pTreeItem->pItemInfo2->GetPidl():NULL; item.bFolder=pTreeItem->bFolder; item.bMetroLink=false; item.bMetroApp=false; if (pTreeItem->pItemInfo1) { CItemManager::RWLock lock(&g_ItemManager,false,CItemManager::RWLOCK_ITEMS); item.bMetroLink=pTreeItem->pItemInfo1->IsMetroLink(); item.bMetroApp=pTreeItem->pItemInfo1->IsMetroApp(); } DragOut(m_ProgramTreeIndex,bApp); item.id=MENU_PROGRAMS_TREE; item.name.Empty(); item.pItemInfo=NULL; item.pItem1=NULL; item.pItem2=NULL; } void CMenuContainer::RunUserCommand( bool bPicture ) { CString command=GetSettingString(bPicture?L"UserPictureCommand":L"UserNameCommand"); if (!command.IsEmpty()) ExecuteCommand(command,false,true); } static DWORD WINAPI FaderThreadProc( void *param ) { ((CMenuFader*)param)->Create(); MSG msg; while (GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } void CMenuContainer::FadeOutItem( int index ) { int speed=GetSettingInt(L"MenuFadeSpeed"); if (speed<=0) return; RECT rc; HBITMAP bmp=NULL; HRGN region=NULL; if (index==m_ProgramTreeIndex) { HWND tree=m_pProgramsTree->m_hWnd; HTREEITEM hItem=TreeView_GetSelection(tree); TreeView_GetItemRect(tree,hItem,&rc,FALSE); BITMAPINFO dib={sizeof(dib)}; dib.bmiHeader.biWidth=rc.right-rc.left; dib.bmiHeader.biHeight=rc.top-rc.bottom; dib.bmiHeader.biPlanes=1; dib.bmiHeader.biBitCount=32; dib.bmiHeader.biCompression=BI_RGB; HDC hdc=CreateCompatibleDC(NULL); if (s_bRTL) SetLayout(hdc,LAYOUT_RTL); unsigned int *bits; bmp=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&bits,NULL,0); HGDIOBJ bmp0=SelectObject(hdc,bmp); SetViewportOrgEx(hdc,-rc.left,-rc.top,NULL); m_pProgramsTree->SendMessage(WM_PRINTCLIENT,(WPARAM)hdc,PRF_CLIENT); SelectObject(hdc,bmp0); DeleteDC(hdc); m_pProgramsTree->MapWindowPoints(NULL,&rc); } else { GetItemRect(index,rc); BITMAPINFO dib={sizeof(dib)}; dib.bmiHeader.biWidth=rc.right-rc.left; dib.bmiHeader.biHeight=rc.top-rc.bottom; dib.bmiHeader.biPlanes=1; dib.bmiHeader.biBitCount=32; dib.bmiHeader.biCompression=BI_RGB; HDC hdc=CreateCompatibleDC(NULL); if (s_bRTL) SetLayout(hdc,LAYOUT_RTL); unsigned int *bits; bmp=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&bits,NULL,0); HGDIOBJ bmp0=SelectObject(hdc,bmp); SetViewportOrgEx(hdc,-rc.left,-rc.top,NULL); // create a region from the opaque pixels of the selection bitmap MenuSkin::TItemDrawType drawType=m_Items[index].drawType; if (drawType==MenuSkin::COLUMN1_NEW) drawType=MenuSkin::COLUMN1_ITEM; else if (drawType==MenuSkin::COLUMN2_NEW) drawType=MenuSkin::COLUMN2_ITEM; else if (drawType==MenuSkin::SUBMENU_NEW) drawType=MenuSkin::SUBMENU_ITEM; const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[drawType]; if (settings.bmpSelection.GetBitmap() && settings.bmpSelection.bIs32) { HDC hdc2=CreateCompatibleDC(hdc); SetLayout(hdc2,0); HGDIOBJ bmp02=SelectObject(hdc2,settings.bmpSelection.GetBitmap()); FillRect(hdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUSH)); RECT rSrc={0,0,settings.selSlicesX[0]+settings.selSlicesX[1]+settings.selSlicesX[2],settings.selSlicesY[0]+settings.selSlicesY[1]+settings.selSlicesY[2]}; RECT rMargins={settings.selSlicesX[0],settings.selSlicesY[0],settings.selSlicesX[2],settings.selSlicesY[2]}; if (m_Items[index].id==MENU_SHUTDOWN_BUTTON) { rSrc.right+=settings.selSlicesX[3]+settings.selSlicesX[4]+settings.selSlicesX[5]; rMargins.right=settings.selSlicesX[5]; } int w=dib.bmiHeader.biWidth; int h=-dib.bmiHeader.biHeight; if (rMargins.left>w) rMargins.left=w; if (rMargins.right>w) rMargins.right=w; if (rMargins.top>h) rMargins.top=h; if (rMargins.bottom>h) rMargins.bottom=h; MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,false); SelectObject(hdc2,bmp02); DeleteDC(hdc2); SelectObject(hdc,bmp0); for (int y=0;y>24)>=32) { if (minx==-1) minx=x; // first non-transparent pixel if (maxx=0) { maxx++; HRGN r=CreateRectRgn(minx,y,maxx,y+1); AddTrackedObject(r); if (!region) region=r; else { CombineRgn(region,region,r,RGN_OR); DeleteObject(r); } } } SelectObject(hdc,bmp); } DrawBackground(hdc,rc); SelectObject(hdc,bmp0); DeleteDC(hdc); MapWindowPoints(NULL,&rc); } if (bmp) { CMenuFader *pFader=new CMenuFader(bmp,region,speed,rc); CreateThread(NULL,0,FaderThreadProc,pFader,0,NULL); } } /////////////////////////////////////////////////////////////////////////////// CMenuFader::CMenuFader( HBITMAP bmp, HRGN region, int duration, RECT &rect ) { m_Bitmap=bmp; m_Region=region; m_Duration=duration; m_Rect=rect; s_Faders.push_back(this); } CMenuFader::~CMenuFader( void ) { if (m_Bitmap) DeleteObject(m_Bitmap); if (m_Region) DeleteObject(m_Region); s_Faders.erase(std::find(s_Faders.begin(),s_Faders.end(),this)); } void CMenuFader::Create( void ) { bool bRtl=false; if (m_Rect.left>m_Rect.right) { bRtl=true; int q=m_Rect.left; m_Rect.left=m_Rect.right; m_Rect.right=q; } CWindowImpl::Create(NULL,&m_Rect,NULL,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_TOPMOST|WS_EX_LAYERED|(bRtl?WS_EX_LAYOUTRTL:0)); ShowWindow(SW_SHOWNOACTIVATE); if (m_Region) { SetWindowRgn(m_Region); m_Region=NULL; } SetTimer(1,20); m_Time0=0; m_LastTime=0; PostMessage(WM_TIMER,0,0); SetLayeredWindowAttributes(m_hWnd,0,255,LWA_ALPHA); } LRESULT CMenuFader::OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { RECT rc; GetClientRect(&rc); HDC hdc=(HDC)wParam; // draw the background HDC hdc2=CreateCompatibleDC(hdc); HGDIOBJ bmp0=SelectObject(hdc2,m_Bitmap); BitBlt(hdc,0,0,rc.right,rc.bottom,hdc2,0,0,SRCCOPY); SelectObject(hdc2,bmp0); DeleteDC(hdc2); return 1; } LRESULT CMenuFader::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { if (m_Time0==0) m_Time0=GetMessageTime(); int t=GetMessageTime()-m_Time0; const int MAX_DELTA=80; // allow at most 80ms between redraws. if more, slow down time if (t>MAX_DELTA+m_LastTime) { m_Time0+=t-MAX_DELTA-m_LastTime; t=MAX_DELTA+m_LastTime; } m_LastTime=t; if (tSendMessage(WM_CLOSE); }