public string Popup(FileSystemInfoEx[] items, Point pt)
        {
            if (items.Length > 0 && !_contextMenuVisible)
            {
                //0.15: Fixed ShellFolder not freed correctly.
                using (ShellFolder2 parentShellFolder = items[0].Parent != null ?
                                                        items[0].Parent.ShellFolder :
                                                        DirectoryInfoEx.DesktopDirectory.ShellFolder)
                    try
                    {
                        _contextMenuVisible = true;

                        ///Debug.WriteLine(items[0].Parent.FullName);

                        IntPtr        ptrContextMenu     = IntPtr.Zero;
                        IntPtr        ptrContextMenu2    = IntPtr.Zero;
                        IntPtr        PtrContextMenu3    = IntPtr.Zero;
                        IntPtr        contextMenu        = IntPtr.Zero;
                        List <IntPtr> menuPtrConstructed = new List <IntPtr>();
                        PIDL[]        pidls = IOTools.GetPIDL(items, true);

                        if (ContextMenuHelper.GetIContextMenu(parentShellFolder, IOTools.GetPIDLPtr(pidls),
                                                              out ptrContextMenu, out _iContextMenu))
                        {
                            try
                            {
                                queryMenuItemsEventArgs = new QueryMenuItemsEventArgs(items);
                                if (OnQueryMenuItems != null)
                                {
                                    OnQueryMenuItems(this, queryMenuItemsEventArgs);
                                }

                                contextMenu = ShellAPI.CreatePopupMenu();

                                if (queryMenuItemsEventArgs.QueryContextMenu)
                                {
                                    _iContextMenu.QueryContextMenu(contextMenu, 0, ShellAPI.CMD_FIRST,
                                                                   ShellAPI.CMD_LAST, ShellAPI.CMF.EXPLORE | ShellAPI.CMF.CANRENAME |
                                                                   ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMF.EXTENDEDVERBS : 0));
                                }

                                #region obsolute
                                //for (uint i = 0; i < queryMenuItemsEventArgs.ExtraMenuItems.Length; i++)
                                //{
                                //    string caption = queryMenuItemsEventArgs.ExtraMenuItems[i];
                                //    if (caption != "---")
                                //    {
                                //        ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION,
                                //            ShellAPI.CMD_LAST + i + 1, caption);
                                //        if (queryMenuItemsEventArgs.DefaultItem == i)
                                //            ShellAPI.SetMenuDefaultItem(contextMenu, i, true);
                                //    }
                                //    else ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION |
                                //        ShellAPI.MFT.SEPARATOR, 0, "-");
                                //}
                                #endregion

                                //0.11: Added ContextMenuWrapper OnQueryMenuItems event now support multilevel directory. (e.g. @"Tools\Add")
                                ContextMenuHelperEx.ConstructCustomMenu(contextMenu, queryMenuItemsEventArgs.ExtraMenuItems, out menuPtrConstructed);

                                if (queryMenuItemsEventArgs.QueryContextMenu2)
                                {
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu2,
                                                               out ptrContextMenu2);
                                        _iContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(
                                            ptrContextMenu2, typeof(IContextMenu2));
                                    }
                                    catch (Exception) { }
                                }

                                if (queryMenuItemsEventArgs.QueryContextMenu3)
                                {
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu3,
                                                               out PtrContextMenu3);

                                        _iContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(
                                            PtrContextMenu3, typeof(IContextMenu3));
                                    }
                                    catch (Exception) { }
                                }


                                uint GMDI_USEDISABLED  = 0x0001;
                                uint GMDI_GOINTOPOPUPS = 0x0002;
                                uint intDefaultItem    = (uint)ShellAPI.GetMenuDefaultItem(contextMenu, false, GMDI_USEDISABLED);

                                string strDefaultCommand = intDefaultItem >= ShellAPI.CMD_FIRST ?
                                                           ContextMenuHelper.GetCommandString(_iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, true) : null;



                                if (queryMenuItemsEventArgs.QueryContextMenu) //No need to Disable if query is not carried out in first place.
                                {
                                    //0.11: Added queryMenuItemsEventArgs.GrayedItems / HiddenItems
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                                                         queryMenuItemsEventArgs.GrayedItems, ContextMenuHelperEx.DisabledMethods.Gray);
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                                                         queryMenuItemsEventArgs.HiddenItems, ContextMenuHelperEx.DisabledMethods.Remove);
                                }

                                //0.17: Added DefaultItem and DefaultCommand in BeforePopup
                                bool cont = true;
                                if (OnBeforePopup != null)
                                {
                                    BeforePopupEventArgs args = new BeforePopupEventArgs
                                                                    (contextMenu, _iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, strDefaultCommand);
                                    OnBeforePopup(this, args);
                                    cont = args.ContinuePopup;
                                }

                                if (cont)
                                {
                                    //0.18 Fixed Context menu disappear in some case. (By cwharmon)
                                    //http://www.codeproject.com/KB/files/DirectoryInfoEx.aspx#xx3475961xx
                                    ShellAPI.SetForegroundWindow(this.Handle);

                                    uint selected = ShellAPI.TrackPopupMenuEx(contextMenu, ShellAPI.TPM.RETURNCMD,
                                                                              pt.X, pt.Y, this.Handle, IntPtr.Zero);

                                    uint msg = 0;
                                    ShellAPI.PostMessage(this.Handle, msg, IntPtr.Zero, IntPtr.Zero);

                                    if (OnMouseHover != null)
                                    {
                                        OnMouseHover(this, new MouseHoverEventArgs("", "", 0));
                                    }

                                    if (selected > ShellAPI.CMD_LAST)
                                    {
                                        return(removeCheckedSymbol(queryMenuItemsEventArgs.ExtraMenuItems[selected - ShellAPI.CMD_LAST - 1]));
                                    }

                                    if (selected >= ShellAPI.CMD_FIRST)
                                    {
                                        string command = ContextMenuHelper.GetCommandString(_iContextMenu,
                                                                                            selected - ShellAPI.CMD_FIRST, true);
                                        if (command == null)
                                        {
                                            return(null);
                                        }

                                        if (OnBeforeInvokeCommand != null)
                                        {
                                            InvokeCommandEventArgs args =
                                                new InvokeCommandEventArgs(command, "", selected, items);
                                            OnBeforeInvokeCommand(this, args);
                                            if (!args.ContinueInvoke)
                                            {
                                                return(command);
                                            }
                                        }

                                        if (command == "rename")
                                        {
                                            return("rename");
                                        }
                                        else
                                        {
                                            //if (items.Length == 1 && items[0] is DirectoryInfoEx)
                                            ContextMenuHelper.InvokeCommand(_iContextMenu,
                                                                            selected - ShellAPI.CMD_FIRST,
                                                                            (items[0].Parent != null) ? items[0].Parent.FullName :
                                                                            items[0].FullName, pt);
                                            //else
                                            //ContextMenuHelper.InvokeCommand(items[0].Parent,
                                            //    IOTools.GetPIDLPtr(items, true), selected - ShellAPI.CMD_FIRST,
                                            //    pt);
                                        }
                                    }
                                }
                            }
                            finally
                            {
                                IOTools.FreePIDL(pidls);

                                if (_iContextMenu != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu);
                                    _iContextMenu = null;
                                }

                                if (_iContextMenu2 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu2);
                                    _iContextMenu2 = null;
                                }

                                if (_iContextMenu3 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu3);
                                    _iContextMenu3 = null;
                                }

                                foreach (IntPtr menuPtr in menuPtrConstructed)
                                {
                                    ShellAPI.DestroyMenu(menuPtr);
                                }
                                menuPtrConstructed.Clear();

                                if (contextMenu != null)
                                {
                                    ShellAPI.DestroyMenu(contextMenu);
                                }

                                if (ptrContextMenu != IntPtr.Zero)
                                {
                                    Marshal.Release(ptrContextMenu);
                                }

                                if (ptrContextMenu2 != IntPtr.Zero)
                                {
                                    Marshal.Release(ptrContextMenu2);
                                }

                                if (PtrContextMenu3 != IntPtr.Zero)
                                {
                                    Marshal.Release(PtrContextMenu3);
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (OnAfterPopup != null)
                        {
                            AfterPopupEventArgs args = new AfterPopupEventArgs();
                            OnAfterPopup(this, args);
                        }
                        _contextMenuVisible = false;
                    }
            }

            return(null);
        }
        public string Popup(FileSystemInfoEx[] items, Point pt)
        {
            if (items.Length > 0 && !_contextMenuVisible)
            {
                //0.15: Fixed ShellFolder not freed correctly.
                using (ShellFolder2 parentShellFolder = items[0].Parent != null ?
                        items[0].Parent.ShellFolder :
                        DirectoryInfoEx.DesktopDirectory.ShellFolder)
                    try
                    {
                        _contextMenuVisible = true;

                        ///Debug.WriteLine(items[0].Parent.FullName);

                        IntPtr ptrContextMenu = IntPtr.Zero;
                        IntPtr ptrContextMenu2 = IntPtr.Zero;
                        IntPtr PtrContextMenu3 = IntPtr.Zero;
                        IntPtr contextMenu = IntPtr.Zero;
                        List<IntPtr> menuPtrConstructed = new List<IntPtr>();
                        PIDL[] pidls = IOTools.GetPIDL(items, true);

                        if (ContextMenuHelper.GetIContextMenu(parentShellFolder, IOTools.GetPIDLPtr(pidls),
                            out ptrContextMenu, out _iContextMenu))
                            try
                            {

                                queryMenuItemsEventArgs = new QueryMenuItemsEventArgs(items);
                                if (OnQueryMenuItems != null)
                                    OnQueryMenuItems(this, queryMenuItemsEventArgs);

                                contextMenu = ShellAPI.CreatePopupMenu();

                                if (queryMenuItemsEventArgs.QueryContextMenu)
                                    _iContextMenu.QueryContextMenu(contextMenu, 0, ShellAPI.CMD_FIRST,
                                        ShellAPI.CMD_LAST, ShellAPI.CMF.EXPLORE | ShellAPI.CMF.CANRENAME |
                                        ((Control.ModifierKeys & Keys.Shift) != 0 ? ShellAPI.CMF.EXTENDEDVERBS : 0));

                                #region obsolute
                                //for (uint i = 0; i < queryMenuItemsEventArgs.ExtraMenuItems.Length; i++)
                                //{
                                //    string caption = queryMenuItemsEventArgs.ExtraMenuItems[i];
                                //    if (caption != "---")
                                //    {
                                //        ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION,
                                //            ShellAPI.CMD_LAST + i + 1, caption);
                                //        if (queryMenuItemsEventArgs.DefaultItem == i)
                                //            ShellAPI.SetMenuDefaultItem(contextMenu, i, true);
                                //    }
                                //    else ShellAPI.InsertMenu(contextMenu, i, ShellAPI.MFT.BYPOSITION |
                                //        ShellAPI.MFT.SEPARATOR, 0, "-");
                                //}
                                #endregion

                                //0.11: Added ContextMenuWrapper OnQueryMenuItems event now support multilevel directory. (e.g. @"Tools\Add")
                                ContextMenuHelperEx.ConstructCustomMenu(contextMenu, queryMenuItemsEventArgs.ExtraMenuItems, out menuPtrConstructed);

                                if (queryMenuItemsEventArgs.QueryContextMenu2)
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu2,
                                            out ptrContextMenu2);
                                        _iContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(
                                        ptrContextMenu2, typeof(IContextMenu2));
                                    }
                                    catch (Exception) { }

                                if (queryMenuItemsEventArgs.QueryContextMenu3)
                                    try
                                    {
                                        Marshal.QueryInterface(ptrContextMenu, ref ShellAPI.IID_IContextMenu3,
                                    out PtrContextMenu3);

                                        _iContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(
                                         PtrContextMenu3, typeof(IContextMenu3));
                                    }
                                    catch (Exception) { }

                                uint GMDI_USEDISABLED = 0x0001;
                                uint GMDI_GOINTOPOPUPS = 0x0002;
                                uint intDefaultItem = (uint)ShellAPI.GetMenuDefaultItem(contextMenu, false, GMDI_USEDISABLED);

                                string strDefaultCommand = intDefaultItem >= ShellAPI.CMD_FIRST ?
                                    ContextMenuHelper.GetCommandString(_iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, true) : null;

                                if (queryMenuItemsEventArgs.QueryContextMenu) //No need to Disable if query is not carried out in first place.
                                {
                                    //0.11: Added queryMenuItemsEventArgs.GrayedItems / HiddenItems
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                        queryMenuItemsEventArgs.GrayedItems, ContextMenuHelperEx.DisabledMethods.Gray);
                                    ContextMenuHelperEx.DisableMenuItems(contextMenu, _iContextMenu,
                                        queryMenuItemsEventArgs.HiddenItems, ContextMenuHelperEx.DisabledMethods.Remove);
                                }

                                //0.17: Added DefaultItem and DefaultCommand in BeforePopup
                                bool cont = true;
                                if (OnBeforePopup != null)
                                {
                                    BeforePopupEventArgs args = new BeforePopupEventArgs
                                        (contextMenu, _iContextMenu, intDefaultItem - ShellAPI.CMD_FIRST, strDefaultCommand);
                                    OnBeforePopup(this, args);
                                    cont = args.ContinuePopup;
                                }

                                if (cont)
                                {
                                    //0.18 Fixed Context menu disappear in some case. (By cwharmon)
                                    //http://www.codeproject.com/KB/files/DirectoryInfoEx.aspx#xx3475961xx
                                    ShellAPI.SetForegroundWindow(this.Handle);

                                    uint selected = ShellAPI.TrackPopupMenuEx(contextMenu, ShellAPI.TPM.RETURNCMD,
                                                        pt.X, pt.Y, this.Handle, IntPtr.Zero);

                                    uint msg = 0;
                                    ShellAPI.PostMessage(this.Handle, msg, IntPtr.Zero, IntPtr.Zero);

                                    if (OnMouseHover != null)
                                        OnMouseHover(this, new MouseHoverEventArgs("", "", 0));

                                    if (selected > ShellAPI.CMD_LAST)
                                    {
                                        return removeCheckedSymbol(queryMenuItemsEventArgs.ExtraMenuItems[selected - ShellAPI.CMD_LAST - 1]);

                                    }

                                    if (selected >= ShellAPI.CMD_FIRST)
                                    {
                                        string command = ContextMenuHelper.GetCommandString(_iContextMenu,
                                            selected - ShellAPI.CMD_FIRST, true);
                                        if (command == null) return null;

                                        if (OnBeforeInvokeCommand != null)
                                        {
                                            InvokeCommandEventArgs args =
                                                new InvokeCommandEventArgs(command, "", selected, items);
                                            OnBeforeInvokeCommand(this, args);
                                            if (!args.ContinueInvoke)
                                                return command;
                                        }

                                        if (command == "rename")
                                            return "rename";
                                        else
                                        {
                                            //if (items.Length == 1 && items[0] is DirectoryInfoEx)
                                            ContextMenuHelper.InvokeCommand(_iContextMenu,
                                                selected - ShellAPI.CMD_FIRST,
                                                (items[0].Parent != null) ? items[0].Parent.FullName :
                                                items[0].FullName, pt);
                                            //else
                                            //ContextMenuHelper.InvokeCommand(items[0].Parent,
                                            //    IOTools.GetPIDLPtr(items, true), selected - ShellAPI.CMD_FIRST,
                                            //    pt);

                                        }

                                    }
                                }
                            }
                            finally
                            {
                                IOTools.FreePIDL(pidls);

                                if (_iContextMenu != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu);
                                    _iContextMenu = null;
                                }

                                if (_iContextMenu2 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu2);
                                    _iContextMenu2 = null;
                                }

                                if (_iContextMenu3 != null)
                                {
                                    Marshal.ReleaseComObject(_iContextMenu3);
                                    _iContextMenu3 = null;
                                }

                                foreach (IntPtr menuPtr in menuPtrConstructed)
                                    ShellAPI.DestroyMenu(menuPtr);
                                menuPtrConstructed.Clear();

                                if (contextMenu != null)
                                    ShellAPI.DestroyMenu(contextMenu);

                                if (ptrContextMenu != IntPtr.Zero)
                                    Marshal.Release(ptrContextMenu);

                                if (ptrContextMenu2 != IntPtr.Zero)
                                    Marshal.Release(ptrContextMenu2);

                                if (PtrContextMenu3 != IntPtr.Zero)
                                    Marshal.Release(PtrContextMenu3);
                            }

                    }
                    finally
                    {

                        if (OnAfterPopup != null)
                        {
                            AfterPopupEventArgs args = new AfterPopupEventArgs();
                            OnAfterPopup(this, args);
                        }
                        _contextMenuVisible = false;
                    }

            }

            return null;
        }