/// <summary> /// Displays shell shortcut menu. /// </summary> /// <param name="idlw">IDLWrapper object that specifies shell item</param> /// <param name="pntShow">location of the shortcut menu, in screen coordinates.</param> /// <param name="hwndParent">Handle of parent control. Parent control will get focus, and receives the messages about drawing 'Send to' submenues.</param> /// <param name="fCanRemove">set true to add 'remove this' menu item.</param> /// <returns> /// 0xFFFF user selected "Remove this item from menu". /// 0xFFFE user selected "Open containing folder". /// 0xFFFD If the user cancels the menu without making a selection, or if an error occurs /// </returns> public int Open(IDLWrapper idlw, Point pntShow, IntPtr hwndParent, bool fCanRemove) { const uint MF_STRING = 0x00000000; const uint MF_SEPARATOR = 0x00000800; const uint CMF_NORMAL = 0x00000000; const uint CMF_EXTENDEDVERBS = 0x00000100; const uint TPM_RETURNCMD = 0x0100; const uint S_OK = 0; const int COMMANDID_REMOVEITEM = 0xffff; // todo: move to const class const int COMMANDID_OPENPARENT = 0xfffe; const int COMMANDID_USERCANCEL = 0xfffd; IShellFolder shellFolderParent = null; try { // get IShellFolder IntPtr pIDLRelative; if(idlw.Available && S_OK == PInvoke.SHBindToParent(idlw.PIDL, ExplorerGUIDs.IID_IShellFolder, out shellFolderParent, out pIDLRelative) && shellFolderParent != null) { // get IContextMenu2 IntPtr[] pIDLs = new IntPtr[] { pIDLRelative }; uint reserved = 0; object oUnk; if(S_OK == shellFolderParent.GetUIObjectOf(IntPtr.Zero, (uint)pIDLs.Length, pIDLs, ExplorerGUIDs.IID_IContextMenu, ref reserved, out oUnk)) { pIContextMenu2 = oUnk as IContextMenu2; if(pIContextMenu2 != null) { using(ContextMenu contextMenu = new ContextMenu()) { int nResult = -1; uint uFlags = CMF_NORMAL; if((Control.ModifierKeys & Keys.Shift) == Keys.Shift) { uFlags |= CMF_EXTENDEDVERBS; } pIContextMenu2.QueryContextMenu(contextMenu.Handle, 0, 1, 0xffff, uFlags); // append optional menus if(fCanRemove) { // "Remove this item from menu" PInvoke.AppendMenu(contextMenu.Handle, MF_SEPARATOR, IntPtr.Zero, null); PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_REMOVEITEM), QTUtility.ResMain[25]); } if(idlw.HasPath && idlw.Path.Length > 3 && idlw.IsFileSystem /*&& ( idlw.IsFileSystemFolder || idlw.IsFileSystemFile )*/ ) { // "Open containing folder" if(!fCanRemove) { // separator PInvoke.AppendMenu(contextMenu.Handle, MF_SEPARATOR, IntPtr.Zero, null); } PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_OPENPARENT), QTUtility.ResMain[26]); } uint commandID = PInvoke.TrackPopupMenu(contextMenu.Handle, TPM_RETURNCMD, pntShow.X, pntShow.Y, 0, hwndParent, IntPtr.Zero); if(commandID != 0) { if(commandID == COMMANDID_REMOVEITEM) { return COMMANDID_REMOVEITEM; } else if(commandID == COMMANDID_OPENPARENT) { if(idlw.HasPath) { try { QTTabBarClass tabbar = InstanceManager.GetThreadTabBar(); if(tabbar != null) { using(IDLWrapper idlwParent = idlw.GetParent()) { if(idlwParent.Available) { tabbar.OpenNewTabOrWindow(idlwParent); } } } // DesktopTool will handle it by itself nResult = COMMANDID_OPENPARENT; } catch { System.Media.SystemSounds.Asterisk.Play(); } } } else { CMINVOKECOMMANDINFO cmInfo = new CMINVOKECOMMANDINFO { cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO)), fMask = 0, hwnd = hwndParent, lpVerb = (IntPtr)((commandID - 1) & 0xFFFF), lpParameters = IntPtr.Zero, lpDirectory = IntPtr.Zero, nShow = 1, //SW_SHOWNORMAL; dwHotKey = 0, hIcon = IntPtr.Zero }; // returns S_OK if successful, or an error value otherwise. // E_ABORT when user clicked "Open folder link target exists" of link file...( E_ABORT _HRESULT_TYPEDEF_(0x80004004L) ) nResult = pIContextMenu2.InvokeCommand(ref cmInfo); } } else { // 'if the user cancels the menu without making a selection, or if an error occurs' (MSDN) nResult = COMMANDID_USERCANCEL; } return nResult; } } } } // if failed to create shell context menu, show 'remove this' menu instead if(fCanRemove) { using(ContextMenu contextMenu = new ContextMenu()) { PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_REMOVEITEM), QTUtility.ResMain[25]); if(COMMANDID_REMOVEITEM == PInvoke.TrackPopupMenu(contextMenu.Handle, TPM_RETURNCMD, pntShow.X, pntShow.Y, 0, hwndParent, IntPtr.Zero)) { return COMMANDID_REMOVEITEM; } } } return COMMANDID_USERCANCEL; } catch { } finally { if(shellFolderParent != null) { Marshal.ReleaseComObject(shellFolderParent); } if(pIContextMenu2 != null) { Marshal.ReleaseComObject(pIContextMenu2); pIContextMenu2 = null; } } return -1; }
/// <summary> /// Displays shell shortcut menu. /// </summary> /// <param name="idlw">IDLWrapper object that specifies shell item</param> /// <param name="pntShow">location of the shortcut menu, in screen coordinates.</param> /// <param name="hwndParent">Handle of parent control. Parent control will get focus, and receives the messages about drawing 'Send to' submenues.</param> /// <param name="fCanRemove">set true to add 'remove this' menu item.</param> /// <returns> /// 0xFFFF user selected "Remove this item from menu". /// 0xFFFE user selected "Open containing folder". /// 0xFFFD If the user cancels the menu without making a selection, or if an error occurs /// </returns> public int Open(IDLWrapper idlw, Point pntShow, IntPtr hwndParent, bool fCanRemove) { const uint MF_STRING = 0x00000000; const uint MF_SEPARATOR = 0x00000800; const uint CMF_NORMAL = 0x00000000; const uint CMF_EXTENDEDVERBS = 0x00000100; const uint TPM_RETURNCMD = 0x0100; const uint S_OK = 0; const int COMMANDID_REMOVEITEM = 0xffff; // todo: move to const class const int COMMANDID_OPENPARENT = 0xfffe; const int COMMANDID_USERCANCEL = 0xfffd; IShellFolder shellFolderParent = null; try { // get IShellFolder IntPtr pIDLRelative; if (idlw.Available && S_OK == PInvoke.SHBindToParent(idlw.PIDL, ExplorerGUIDs.IID_IShellFolder, out shellFolderParent, out pIDLRelative) && shellFolderParent != null) { // get IContextMenu2 IntPtr[] pIDLs = new IntPtr[] { pIDLRelative }; uint reserved = 0; object oUnk; if (S_OK == shellFolderParent.GetUIObjectOf(IntPtr.Zero, (uint)pIDLs.Length, pIDLs, ExplorerGUIDs.IID_IContextMenu, ref reserved, out oUnk)) { pIContextMenu2 = oUnk as IContextMenu2; if (pIContextMenu2 != null) { using (ContextMenu contextMenu = new ContextMenu()) { int nResult = -1; uint uFlags = CMF_NORMAL; if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) { uFlags |= CMF_EXTENDEDVERBS; } pIContextMenu2.QueryContextMenu(contextMenu.Handle, 0, 1, 0xffff, uFlags); // append optional menus if (fCanRemove) { // "Remove this item from menu" PInvoke.AppendMenu(contextMenu.Handle, MF_SEPARATOR, IntPtr.Zero, null); PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_REMOVEITEM), QTUtility.ResMain[25]); } if (idlw.HasPath && idlw.Path.Length > 3 && idlw.IsFileSystem /*&& ( idlw.IsFileSystemFolder || idlw.IsFileSystemFile )*/) { // "Open containing folder" if (!fCanRemove) { // separator PInvoke.AppendMenu(contextMenu.Handle, MF_SEPARATOR, IntPtr.Zero, null); } PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_OPENPARENT), QTUtility.ResMain[26]); } uint commandID = PInvoke.TrackPopupMenu(contextMenu.Handle, TPM_RETURNCMD, pntShow.X, pntShow.Y, 0, hwndParent, IntPtr.Zero); if (commandID != 0) { if (commandID == COMMANDID_REMOVEITEM) { return(COMMANDID_REMOVEITEM); } else if (commandID == COMMANDID_OPENPARENT) { if (idlw.HasPath) { try { QTTabBarClass tabbar = InstanceManager.GetThreadTabBar(); if (tabbar != null) { using (IDLWrapper idlwParent = idlw.GetParent()) { if (idlwParent.Available) { tabbar.OpenNewTabOrWindow(idlwParent); } } } // DesktopTool will handle it by itself nResult = COMMANDID_OPENPARENT; } catch { System.Media.SystemSounds.Asterisk.Play(); } } } else { CMINVOKECOMMANDINFO cmInfo = new CMINVOKECOMMANDINFO { cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFO)), fMask = 0, hwnd = hwndParent, lpVerb = (IntPtr)((commandID - 1) & 0xFFFF), lpParameters = IntPtr.Zero, lpDirectory = IntPtr.Zero, nShow = 1, //SW_SHOWNORMAL; dwHotKey = 0, hIcon = IntPtr.Zero }; // returns S_OK if successful, or an error value otherwise. // E_ABORT when user clicked "Open folder link target exists" of link file...( E_ABORT _HRESULT_TYPEDEF_(0x80004004L) ) nResult = pIContextMenu2.InvokeCommand(ref cmInfo); } } else { // 'if the user cancels the menu without making a selection, or if an error occurs' (MSDN) nResult = COMMANDID_USERCANCEL; } return(nResult); } } } } // if failed to create shell context menu, show 'remove this' menu instead if (fCanRemove) { using (ContextMenu contextMenu = new ContextMenu()) { PInvoke.AppendMenu(contextMenu.Handle, MF_STRING, new IntPtr(COMMANDID_REMOVEITEM), QTUtility.ResMain[25]); if (COMMANDID_REMOVEITEM == PInvoke.TrackPopupMenu(contextMenu.Handle, TPM_RETURNCMD, pntShow.X, pntShow.Y, 0, hwndParent, IntPtr.Zero)) { return(COMMANDID_REMOVEITEM); } } } return(COMMANDID_USERCANCEL); } catch { } finally { if (shellFolderParent != null) { Marshal.ReleaseComObject(shellFolderParent); } if (pIContextMenu2 != null) { Marshal.ReleaseComObject(pIContextMenu2); pIContextMenu2 = null; } } return(-1); }