Provides support for displaying the context menu of a shell item.

Use this class to display a context menu for a shell item, either as a popup menu, or as a main menu.

To display a popup menu, simply call ShowContextMenu(...)/> with the parent control and the position at which the menu should be shown.

To display a shell context menu in a Form's main menu, call the Populate method to populate the menu. In addition, you must intercept a number of special messages that will be sent to the menu's parent form. To do this, you must override Form.WndProc like so:

protected override void WndProc(ref Message m) { if ((m_ContextMenu == null) || (!m_ContextMenu.HandleMenuMessage(ref m))) { base.WndProc(ref m); } }

Where m_ContextMenu is the ShellContextMenu being shown.

Standard menu commands can also be invoked from this class, for example InvokeDelete and InvokeRename.
Example #1
0
 public MessageWindow(ShellContextMenu parent)
 {
     m_Parent = parent;
 }
    /// <summary>
    /// Does setup required for the UI when navigation occurs to a new folder
    /// </summary>
    private void SetupUIOnSelectOrNavigate() {
      Dispatcher.BeginInvoke(DispatcherPriority.Background, (ThreadStart)(() => {
        btnDefSave.Items.Clear();
        var selItemsCount = _ShellListView.GetSelectedCount();
        var selectedItem = this._ShellListView.GetFirstSelectedItem();

        if (selectedItem == null) {
          btnOpenWith.IsEnabled = false;
        } else {
          var mnu = new ShellContextMenu(this._ShellListView, false);

          try {
            var tempPoint = btnOpenWith.PointToScreen(new WIN.Point(0, 0));
            var itemMenuCount = mnu.ShowContextMenu(new System.Drawing.Point((int)tempPoint.X, (int)tempPoint.Y + (int)btnOpenWith.ActualHeight), 1, false);
            btnOpenWith.IsEnabled = itemMenuCount > 0 && selItemsCount == 1;
          } catch {
            btnOpenWith.IsEnabled = false;
          }
        }

        btnNewItem.IsEnabled = this._ShellListView.CurrentFolder.IsFileSystem || this._ShellListView.CurrentFolder.ParsingName == KnownFolders.Libraries.ParsingName;
        if (selectedItem != null && selectedItem.IsFileSystem && IsPreviewPaneEnabled && !selectedItem.IsFolder && selItemsCount == 1)
          this.Previewer.FileName = selectedItem.ParsingName;
        else if (!String.IsNullOrEmpty(this.Previewer.FileName))
          this.Previewer.FileName = null;

        //Set up ribbon contextual tabs on selection changed
        SetUpRibbonTabsVisibilityOnSelectOrNavigate(selItemsCount, selectedItem);
        SetUpButtonsStateOnSelectOrNavigate(selItemsCount, selectedItem);
      }));
    }
 public MessageWindow(ShellContextMenu parent) {
   m_Parent = parent;
 }
    private void btnOpenWith_DropDownOpened(object sender, EventArgs e) {
      var mnu = new ShellContextMenu(this._ShellListView, false);

      var controlPos = btnOpenWith.TransformToAncestor(Application.Current.MainWindow).Transform(new WIN.Point(0, 0));
      var tempPoint = PointToScreen(new WIN.Point(controlPos.X, controlPos.Y));
      mnu.ShowContextMenu(new System.Drawing.Point((int)tempPoint.X, (int)tempPoint.Y + (int)btnOpenWith.ActualHeight), 1);
      btnOpenWith.IsDropDownOpen = false;
    }
Example #5
0
    protected override void WndProc(ref Message m) {
      try {
        if (m.Msg == (Int32)WM.WM_PARENTNOTIFY && User32.LOWORD((Int32)m.WParam) == (Int32)WM.WM_MBUTTONDOWN) OnItemMiddleClick();
        base.WndProc(ref m);

        if (m.Msg == ShellNotifications.WM_SHNOTIFY) {
          this.ProcessShellNotifications(ref m);
        }

        #region m.Msg == 78

        if (m.Msg == 78) {
          #region Starting

          var nmhdrHeader = (NMHEADER)(m.GetLParam(typeof(NMHEADER)));
          if (nmhdrHeader.hdr.code == (Int32)HDN.HDN_DROPDOWN)
            Column_OnClick(nmhdrHeader.iItem);
          //F.MessageBox.Show(nmhdrHeader.iItem.ToString());
          else if (nmhdrHeader.hdr.code == (Int32)HDN.HDN_BEGINTRACKW)
            if (this.View != ShellViewStyle.Details) m.Result = (IntPtr)1;

          /*
else if (nmhdrHeader.hdr.code == (int)HDN.HDN_BEGINTRACKW)
if (this.View != ShellViewStyle.Details) m.Result = (IntPtr)1;
*/

          #endregion Starting

          var nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
          switch (nmhdr.code) {
            case WNM.LVN_GETEMPTYMARKUP:
              if (this._IsDisplayEmptyText) {
                var nmlvem = (NMLVEMPTYMARKUP)m.GetLParam(typeof(NMLVEMPTYMARKUP));
                nmlvem.dwFlags = 0x1;
                nmlvem.szMarkup = "Working on it...";
                Marshal.StructureToPtr(nmlvem, m.LParam, false);
                m.Result = (IntPtr)1;
              } else {
                m.Result = IntPtr.Zero;
              }
              break;

            case WNM.LVN_ENDLABELEDITW:

              #region Case

              var nmlvedit = (NMLVDISPINFO)m.GetLParam(typeof(NMLVDISPINFO));
              if (!String.IsNullOrEmpty(nmlvedit.item.pszText)) {
                var item = this.Items[nmlvedit.item.iItem];
                RenameShellItem(item.ComInterface, nmlvedit.item.pszText, (item.DisplayName != Path.GetFileName(item.ParsingName)) && !item.IsFolder, item.Extension);
                this.EndLabelEdit();
              }

              this._EditorSubclass?.DestroyHandle();
              break;

            #endregion Case

            case WNM.LVN_GETDISPINFOW:

              #region Case

              var nmlv = (NMLVDISPINFO)m.GetLParam(typeof(NMLVDISPINFO));
              if (Items.Count == 0 || Items.Count - 1 < nmlv.item.iItem)
                break;
              var currentItem = this.IsSearchNavigating ? Items[nmlv.item.iItem].Clone() : Items[nmlv.item.iItem];

              if ((nmlv.item.mask & LVIF.LVIF_TEXT) == LVIF.LVIF_TEXT) {
                if (nmlv.item.iSubItem == 0) {
                  nmlv.item.pszText = currentItem.DisplayName;
                  Marshal.StructureToPtr(nmlv, m.LParam, false);
                } else {
                  if ((View == ShellViewStyle.List || View == ShellViewStyle.SmallIcon || View == ShellViewStyle.Details) || (this.View == ShellViewStyle.Tile && this.AllAvailableColumns.Count >= nmlv.item.iSubItem)) {
                    var currentCollumn = this.View == ShellViewStyle.Tile
                        ? this.AllAvailableColumns.Values.ToArray()[nmlv.item.iSubItem]
                        : this.Collumns[nmlv.item.iSubItem];


                    Object valueCached;
                    if (currentItem.ColumnValues.TryGetValue(currentCollumn.pkey, out valueCached)) {
                      String val = String.Empty;
                      if (valueCached != null) {
                        if (currentCollumn.CollumnType == typeof(DateTime))
                          val = ((DateTime)valueCached).ToString(Thread.CurrentThread.CurrentUICulture);
                        else if (currentCollumn.CollumnType == typeof(Int64))
                          val = $"{Math.Ceiling(Convert.ToDouble(valueCached.ToString()) / 1024):# ### ### ##0} KB";
                        else if (currentCollumn.CollumnType == typeof(PerceivedType))
                          val = ((PerceivedType)valueCached).ToString();
                        else if (currentCollumn.CollumnType == typeof(FileAttributes))
                          val = this.GetFilePropertiesString(valueCached);
                        else
                          val = valueCached.ToString();
                      }

                      nmlv.item.pszText = val.Trim();
                    } else {
                      var temp = currentItem;
                      var isi2 = (IShellItem2)temp.ComInterface;
                      var guid = new Guid(InterfaceGuids.IPropertyStore);
                      IPropertyStore propStore = null;
                      isi2.GetPropertyStore(GetPropertyStoreOptions.FastPropertiesOnly, ref guid, out propStore);
                      PROPERTYKEY pk = currentCollumn.pkey;
                      var pvar = new PropVariant();
                      if (propStore != null && propStore.GetValue(ref pk, pvar) == HResult.S_OK) {
                        if (pvar.Value == null) {
                          if (this.IconSize == 16) {
                            this.SmallImageList.EnqueueSubitemsGet(Tuple.Create(nmlv.item.iItem, nmlv.item.iSubItem, pk));
                          } else {
                            this.LargeImageList.EnqueueSubitemsGet(Tuple.Create(nmlv.item.iItem, nmlv.item.iSubItem, pk));
                          }
                        } else {
                          var val = String.Empty;
                          if (currentCollumn.CollumnType == typeof(DateTime))
                            val = ((DateTime)pvar.Value).ToString(Thread.CurrentThread.CurrentUICulture);
                          else if (currentCollumn.CollumnType == typeof(Int64))
                            val =
                                $"{Math.Ceiling(Convert.ToDouble(pvar.Value.ToString()) / 1024):# ### ### ##0} KB";
                          else if (currentCollumn.CollumnType == typeof(PerceivedType))
                            val = ((PerceivedType)pvar.Value).ToString();
                          else if (currentCollumn.CollumnType == typeof(FileAttributes))
                            val = this.GetFilePropertiesString(pvar.Value);
                          else
                            val = pvar.Value.ToString();

                          nmlv.item.pszText = val.Trim();
                          pvar.Dispose();
                        }
                      }
                    }
                  }

                  Marshal.StructureToPtr(nmlv, m.LParam, false);
                }
              }

              if ((nmlv.item.mask & LVIF.LVIF_COLUMNS) == LVIF.LVIF_COLUMNS && this.CurrentFolder?.ParsingName.Equals(KnownFolders.Computer.ParsingName) == false) {
                int[] columns = null;
                var refGuidPDL = typeof(IPropertyDescriptionList).GUID;
                var refGuidPD = typeof(IPropertyDescription).GUID;
                var iShellItem2 = (IShellItem2)currentItem.ComInterface;

                var ptrPDL = IntPtr.Zero;
                iShellItem2.GetPropertyDescriptionList(SpecialProperties.PropListTileInfo, ref refGuidPDL,
                        out ptrPDL);
                IPropertyDescriptionList propertyDescriptionList = (IPropertyDescriptionList)Marshal.GetObjectForIUnknown(ptrPDL);
                var descriptionsCount = 0u;
                propertyDescriptionList.GetCount(out descriptionsCount);
                nmlv.item.cColumns = (int)descriptionsCount;
                columns = new int[nmlv.item.cColumns];
                Marshal.Copy(nmlv.item.puColumns, columns, 0, nmlv.item.cColumns);
                for (uint i = 0; i < descriptionsCount; i++) {
                  IPropertyDescription propertyDescription = null;
                  propertyDescriptionList.GetAt(i, ref refGuidPD, out propertyDescription);
                  PROPERTYKEY pkey;
                  propertyDescription.GetPropertyKey(out pkey);
                  Collumns column = null;
                  if (this.AllAvailableColumns.TryGetValue(pkey, out column)) {
                    columns[i] = column.Index;
                  } else {
                    columns[i] = 0;
                  }
                }
                Marshal.Copy(columns, 0, nmlv.item.puColumns, nmlv.item.cColumns);
                Marshal.StructureToPtr(nmlv, m.LParam, false);
              }
              break;

            #endregion Case

            case WNM.LVN_COLUMNCLICK:

              #region Case

              var nlcv = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
              var sortOrder = SortOrder.Ascending;
              if (this.LastSortedColumnId == this.Collumns[nlcv.iSubItem].ID) {
                sortOrder = this.LastSortOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
              }
              if (!this.IsGroupsEnabled) {
                SetSortCollumn(true, this.Collumns[nlcv.iSubItem], sortOrder);
              } else if (this.LastGroupCollumn == this.Collumns[nlcv.iSubItem]) {
                this.SetGroupOrder();
              } else {
                SetSortCollumn(true, this.Collumns[nlcv.iSubItem], sortOrder);
                this.SetGroupOrder(false);
              }
              break;

            #endregion Case

            case WNM.LVN_GETINFOTIP:

              #region Case

              var nmGetInfoTip = (NMLVGETINFOTIP)m.GetLParam(typeof(NMLVGETINFOTIP));
              if (this.Items.Count == 0)
                break;
              if (ToolTip == null)
                ToolTip = new ToolTip(this);

              var itemInfotip = this.Items[nmGetInfoTip.iItem];
              Char[] charBuf = ("\0").ToCharArray();
              Marshal.Copy(charBuf, 0, nmGetInfoTip.pszText, Math.Min(charBuf.Length, nmGetInfoTip.cchTextMax));
              Marshal.StructureToPtr(nmGetInfoTip, m.LParam, false);

              if (ToolTip.IsVisible)
                ToolTip.HideTooltip();

              ToolTip.CurrentItem = itemInfotip;
              ToolTip.ItemIndex = nmGetInfoTip.iItem;
              ToolTip.Type = nmGetInfoTip.dwFlags;
              ToolTip.Left = -500;
              ToolTip.Top = -500;
              ToolTip.ShowTooltip();

              break;

            #endregion Case

            case WNM.LVN_ODFINDITEM:

              #region Case

              if (this.ToolTip != null && this.ToolTip.IsVisible)
                this.ToolTip.HideTooltip();
              var findItem = (NMLVFINDITEM)m.GetLParam(typeof(NMLVFINDITEM));
              KeyJumpString = findItem.lvfi.psz;

              KeyJumpKeyDown?.Invoke(this, new KeyEventArgs(Keys.A));
              Int32 startindex = this.GetFirstSelectedItemIndex() + (KeyJumpString.Length > 1 ? 0 : 1);
              Int32 selind = GetFirstIndexOf(KeyJumpString, startindex);
              if (selind != -1) {
                m.Result = (IntPtr)(selind);
                if (IsGroupsEnabled)
                  this.SelectItemByIndex(selind, true, true);
              } else {
                int selindOver = GetFirstIndexOf(KeyJumpString, 0);
                if (selindOver != -1) {
                  m.Result = (IntPtr)(selindOver);
                  if (IsGroupsEnabled)
                    this.SelectItemByIndex(selindOver, true, true);
                }
              }
              break;

            #endregion Case

            case -175:

              #region Case

              var nmlvLe = (NMLVDISPINFO)m.GetLParam(typeof(NMLVDISPINFO));

              if (this.ToolTip != null && this.ToolTip.IsVisible)
                this.ToolTip.HideTooltip();

              this.IsFocusAllowed = false;
              this._IsCanceledOperation = false;
              this._ItemForRename = nmlvLe.item.iItem;
              this.BeginItemLabelEdit?.Invoke(this, new RenameEventArgs(this._ItemForRename));
              m.Result = (IntPtr)0;

              var editControl = User32.SendMessage(this.LVHandle, 0x1018, 0, 0);
              var indexLastDot = this.Items[this._ItemForRename].DisplayName.LastIndexOf(".", StringComparison.Ordinal);
              User32.SendMessage(editControl, 0x00B1, 0, indexLastDot);
              break;

            #endregion Case

            case WNM.LVN_ITEMACTIVATE:

              #region Case

              if (this.ToolTip != null && this.ToolTip.IsVisible) this.ToolTip.HideTooltip();
              if (_ItemForRealNameIsAny && this.IsRenameInProgress) {
                this.EndLabelEdit();
              } else {
                var iac = (NMITEMACTIVATE)m.GetLParam(typeof(NMITEMACTIVATE));
                var selectedItem = Items[iac.iItem];
                if (selectedItem.IsFolder) {
                  Navigate_Full(selectedItem, true);
                } else if (selectedItem.IsLink || selectedItem.ParsingName.EndsWith(".lnk")) {
                  var shellLink = new ShellLink(selectedItem.ParsingName);
                  var newSho = FileSystemListItem.ToFileSystemItem(this.LVHandle, shellLink.TargetPIDL);
                  if (newSho.IsFolder)
                    Navigate_Full(newSho, true);
                } else {
                  StartProcessInCurrentDirectory(selectedItem);
                }
              }
              break;

            #endregion Case

            case WNM.LVN_BEGINSCROLL:

              #region Case


              this.EndLabelEdit();
              this.LargeImageList.ResetEvent.Reset();
              _ResetEvent.Reset();
              _ResetTimer.Stop();
              this.ToolTip?.HideTooltip();
              break;

            #endregion Case

            case WNM.LVN_ENDSCROLL:

              #region Case

              _ResetTimer.Start();
              //this.resetEvent.Set();

              break;

            #endregion Case

            case -100:

              #region Case

              F.MessageBox.Show("AM");
              break;

            #endregion Case

            case WNM.LVN_ITEMCHANGED:

              #region Case

              var nlv = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
              if ((nlv.uChanged & LVIF.LVIF_STATE) == LVIF.LVIF_STATE) {
                this._IsDragSelect = nlv.uNewState;
                if (nlv.iItem != _LastItemForRename)
                  _LastItemForRename = -1;
                if (!_SelectionTimer.Enabled)
                  _SelectionTimer.Start();
              }

              break;

            #endregion Case

            case WNM.LVN_ODSTATECHANGED:

              #region Case

              OnSelectionChanged();
              break;

            #endregion Case

            case WNM.LVN_KEYDOWN:

              #region Case

              var nkd = (NMLVKEYDOWN)m.GetLParam(typeof(NMLVKEYDOWN));
              if (!ShellView_KeyDown((Keys)((int)nkd.wVKey))) {
                m.Result = (IntPtr)1;
                break;
              }

              if (nkd.wVKey == (short)Keys.F2 && !(System.Windows.Input.Keyboard.FocusedElement is System.Windows.Controls.TextBox)) {
                RenameSelectedItem();
              }

              if (!_ItemForRealNameIsAny && !this.IsRenameInProgress && !(System.Windows.Input.Keyboard.FocusedElement is System.Windows.Controls.TextBox)) {
                switch (nkd.wVKey) {
                  case (short)Keys.Enter:
                    if (this._IsCanceledOperation) {
                      //this.IsRenameInProgress = false;
                      break;
                    }
                    var selectedItem = this.GetFirstSelectedItem();
                    if (selectedItem.IsFolder) {
                      Navigate(selectedItem, false, false, this.IsNavigationInProgress);
                    } else if (selectedItem.IsLink && selectedItem.ParsingName.EndsWith(".lnk")) {
                      var shellLink = new ShellLink(selectedItem.ParsingName);
                      var newSho = new FileSystemListItem();
                      newSho.Initialize(this.LVHandle, shellLink.TargetPIDL);
                      if (newSho.IsFolder)
                        Navigate(newSho, false, false, this.IsNavigationInProgress);
                      else
                        StartProcessInCurrentDirectory(newSho);

                      shellLink.Dispose();
                    } else {
                      StartProcessInCurrentDirectory(selectedItem);
                    }
                    break;
                }

                this.Focus();
              } else {
                switch (nkd.wVKey) {
                  case (Int16)Keys.Enter:
                    if (!this.IsRenameInProgress)
                      this.EndLabelEdit();
                    this.Focus();
                    break;

                  case (Int16)Keys.Escape:
                    this.EndLabelEdit(true);
                    this.Focus();
                    break;

                  default:
                    break;
                }
                if (System.Windows.Input.Keyboard.FocusedElement is System.Windows.Controls.TextBox) {
                  m.Result = (IntPtr)1;
                  break;
                }
              }
              break;

            #endregion Case

            case WNM.LVN_GROUPINFO: //TODO: Deal with this useless code

              #region Case

              //RedrawWindow();
              break;

            #endregion Case

            case WNM.LVN_HOTTRACK:

              #region Case

              var nlvHotTrack = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
              if (ToolTip != null && nlvHotTrack.iItem != ToolTip.ItemIndex && ToolTip.ItemIndex > -1) {
                ToolTip.HideTooltip();
                this.Focus();
              }

              break;

            #endregion Case

            case WNM.LVN_BEGINDRAG:

              #region Case

              this._DraggedItemIndexes.Clear();
              var dataObjPtr = IntPtr.Zero;
              _DataObject = this.SelectedItems.ToArray().GetIDataObject(out dataObjPtr);
              //uint ef = 0;
              var ishell2 = (DataObject.IDragSourceHelper2)new DragDropHelper();
              ishell2.SetFlags(1);
              var wp = new DataObject.Win32Point() { X = Cursor.Position.X, Y = Cursor.Position.Y };
              ishell2.InitializeFromWindow(this.Handle, ref wp, _DataObject);
              DoDragDrop(_DataObject, F.DragDropEffects.All | F.DragDropEffects.Link);
              //Shell32.SHDoDragDrop(this.Handle, dataObject, null, unchecked((uint)F.DragDropEffects.All | (uint)F.DragDropEffects.Link), out ef);
              break;

            #endregion Case

            case WNM.NM_RCLICK:

              #region Case

              var nmhdrHdn = (NMHEADER)(m.GetLParam(typeof(NMHEADER)));
              var itemActivate = (NMITEMACTIVATE)m.GetLParam(typeof(NMITEMACTIVATE));
              this.ToolTip?.HideTooltip();

              if (nmhdrHdn.iItem != -1 && nmhdrHdn.hdr.hwndFrom == this.LVHandle) {
                //Workaround for cases where on right click over an ites the item is not actually selected
                if (this.GetSelectedCount() == 0) {
                  this.SelectItemByIndex(nmhdrHdn.iItem);
                }
                var selitems = this.SelectedItems;
                var cm = new ShellContextMenu(selitems.ToArray(), SVGIO.SVGIO_SELECTION, this);
                cm.ShowContextMenu(this, itemActivate.ptAction, CMF.CANRENAME);
              } else if (nmhdrHdn.iItem == -1) {
                var cm = new ShellContextMenu(new IListItemEx[1] { this.CurrentFolder }, SVGIO.SVGIO_BACKGROUND, this);
                cm.ShowContextMenu(this, itemActivate.ptAction, 0, true);
              } else {
                this.ColumnHeaderRightClick?.Invoke(this, new MouseEventArgs(F.MouseButtons.Right, 1, MousePosition.X, MousePosition.Y, 0));
              }
              break;

            #endregion Case

            case WNM.NM_CLICK: //TODO: Deal with this useless code

              #region Case

              break;

            #endregion Case

            case WNM.NM_SETFOCUS:

              #region Case

              if (IsGroupsEnabled)
                RedrawWindow();
              ShellView_GotFocus();
              this.IsFocusAllowed = true;
              break;

            #endregion Case

            case WNM.NM_KILLFOCUS:

              #region Case

              if (this._ItemForRename != -1 && !this.IsRenameInProgress)
                EndLabelEdit();
              if (IsGroupsEnabled)
                RedrawWindow();
              this.ToolTip?.HideTooltip();
              //OnLostFocus();
              if (this.IsRenameInProgress) {
                this.Focus(false);
              }
              break;

            #endregion Case

            case CustomDraw.NM_CUSTOMDRAW:
              this.ProcessCustomDraw(ref m, ref nmhdr);
              break;
          }
        }

        #endregion m.Msg == 78
      } catch {
      }
    }