diff --git a/References/GongShell.XML b/References/GongShell.XML deleted file mode 100644 index 4b8bb166608..00000000000 --- a/References/GongShell.XML +++ /dev/null @@ -1,1795 +0,0 @@ - - - - GongShell - - - - - Provides a toolbar showing common places in the computer's - filesystem. - - - - Use the control to display a - toolbar listing common places in the computer's filesystem, - similar to that on the far left-side of the standard file - open/save dialogs. - - - - - Required designer variable. - - - - - Clean up any resources being used. - - true if managed resources should be disposed; otherwise, false. - - - - Required method for Designer support - do not modify - the contents of this method with the code editor. - - - - - Initializes a new instance of the - class. - - - - - Adds a new folder to the toolbar. - - - - A representing the folder to be added. - - - - true if the item was sucessfully added, false otherwise. - - - - - Overrides the method. - - - - - - A that should be automatically - navigated when the user clicks on an entry in the toolbar. - - - - - Occurs when the control wants to - know if it should include an item. - - - - This event allows the items displayed in the - control to be filtered. - - - - - This property does not apply to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - This property is not relevant to the - class. - - - - - Required designer variable. - - - - - Clean up any resources being used. - - true if managed resources should be disposed; otherwise, false. - - - - Required method for Designer support - do not modify - the contents of this method with the code editor. - - - - - A filename combo box suitable for use in file Open/Save dialogs. - - - - - This control extends the class to provide - auto-completion of filenames based on the folder selected in a - . The control also automatically navigates - the ShellView control when the user types a folder path. - - - - - - Determines whether the specified key is a regular input key or a - special key that requires preprocessing. - - - - One of the values. - - - - true if the specified key is a regular input key; otherwise, false. - - - - - Raises the event. - - - - A that contains the event data. - - - - - Raises the event. - - - - A that contains the event data. - - - - - Raises the event. - - - - An that contains the event data. - - - - - Initializes a new instance of the - class. - - - - - Gets/sets the control that the - should look for auto-completion - hints. - - - - - Occurs when a file name is entered into the - and the Return key pressed. - - - - - Provides a drop-down list displaying the Windows Shell namespace. - - - - The class displays a view of the Windows - Shell namespace in a drop-down list similar to that displayed in - a file open/save dialog. - - - - - Initializes a new instance of the class. - - - - - Gets/sets a value indicating whether the combo box is editable. - - - - - Gets/sets a value indicating whether the full file system path - should be displayed in the main portion of the control. - - - - - Gets/sets the folder that the should - display as the root folder. - - - - - Gets/sets the folder currently selected in the - . - - - - - Gets/sets a whose navigation should be - controlled by the combo box. - - - - - Occurs when the 's - property changes. - - - - - Occurs when the control wants to know - if it should include a folder in its view. - - - - This event allows the folders displayed in the - control to be filtered. - - - - - Represents an item in the Windows Shell namespace. - - - - - Initializes a new instance of the class. - - - - Takes a containing the location of the ShellItem. - This constructor accepts URIs using two schemes: - - - file: A file or folder in the computer's filesystem, e.g. - file:///D:/Folder - - shell: A virtual folder, or a file or folder referenced from - a virtual folder, e.g. shell:///Personal/file.txt - - - - A containing the location of the ShellItem. - - - - - Initializes a new instance of the class. - - - - Takes a containing the location of the ShellItem. - This constructor accepts URIs using two schemes: - - - file: A file or folder in the computer's filesystem, e.g. - file:///D:/Folder - - shell: A virtual folder, or a file or folder referenced from - a virtual folder, e.g. shell:///Personal/file.txt - - - - A string containing a Uri with the location of the ShellItem. - - - - - Initializes a new instance of the class. - - - - Takes an containing the - location of the folder. - - - - An containing the - location of the folder. - - - - - Initializes a new instance of the class. - - - - Creates a ShellItem which is a named child of . - - - - The parent folder of the item. - - - - The name of the child item. - - - - - Initializes a new instance of the class. - - - - An representing the folder. - - - - - Compares two s. The comparison is carried - out by display order. - - - - The item to compare. - - - - 0 if the two items are equal. A negative number if - is before in - display order. A positive number if - comes after in - display order. - - - - - Determines whether two s refer to - the same shell folder. - - - - The item to compare. - - - - if the two objects refer to the same - folder, otherwise. - - - - - Returns the name of the item in the specified style. - - - - The style of display name to return. - - - - A string containing the display name of the item. - - - - - Returns an enumerator detailing the child items of the - . - - - - This method returns all child item including hidden - items. - - - - An enumerator over all child items. - - - - - Returns an enumerator detailing the child items of the - . - - - - A filter describing the types of child items to be included. - - - - An enumerator over all child items. - - - - - Returns an enumerator detailing the child items of the - . - - - - This method returns all child item including hidden - items. - - - - An enumerator over all child items. - - - - - Returns an representing the - item. This object is used in drag and drop operations. - - - - - Returns an representing the - item. This object is used in drag and drop operations. - - - - - Returns an representing the - item. - - - - - Gets the index in the system image list of the icon representing - the item. - - - - The type of icon to retrieve. - - - - Flags detailing additional information to be conveyed by the icon. - - - - - - - Tests whether the is the immediate parent - of another item. - - - - The potential child item. - - - - - Tests whether the is the parent of - another item. - - - - The potential child item. - - - - - Returns a string representation of the . - - - - - Returns a URI representation of the . - - - - - Tests if two s refer to the same folder. - - - - The first folder. - - - - The second folder. - - - - - Tests if two s refer to the same folder. - - - - The first folder. - - - - The second folder. - - - - - Gets a child item. - - - - The name of the child item. - - - - - Gets the underlying COM interface. - - - - - Gets the normal display name of the item. - - - - - Gets the file system path of the item. - - - - - Gets a value indicating whether the item has subfolders. - - - - - Gets a value indicating whether the item is a file system item. - - - - - Gets a value indicating whether the item is a file system item - or the child of a file system item. - - - - - Gets a value indicating whether the item is a folder. - - - - - Gets a value indicating whether the item is read-only. - - - - - Gets the item's parent. - - - - - Gets the item's parsing name. - - - - - Gets a PIDL representing the item. - - - - - Gets the item's shell icon. - - - - - Gets the item's tooltip text. - - - - - Gets the Desktop folder. - - - - - Enumerates the types of shell icons. - - - - The system large icon type - - - The system shell icon type - - - The system small icon type - - - - Enumerates the optional styles that can be applied to shell icons. - - - - The icon is displayed opened. - - - Get the overlay for the icon as well. - - - - 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 - 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 - 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 - 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 being shown. - - - Standard menu commands can also be invoked from this class, for - example and . - - - - - Initialises a new instance of the - class. - - - - The item to which the context menu should refer. - - - - - Initialises a new instance of the - class. - - - - The items to which the context menu should refer. - - - - - Handles context menu messages when the - is displayed on a Form's main menu bar. - - - - - To display a shell context menu in a Form's main menu, call the - method to populate the menu with the shell - item's menu items. 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 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 being shown. - - - - - The message to handle. - - - - if the message was a Shell Context Menu - message, if not. If the method returns false, - then the message should be passed down to the base class's - method. - - - - - Invokes the Delete command on the shell item. - - - - - Invokes the Rename command on the shell item. - - - - - Populates a with the context menu items for - a shell item. - - - - If this method is being used to populate a Form's main menu - then you need to call in the - Form's message handler. - - - - The menu to populate. - - - - - Shows a context menu for a shell item. - - - - The parent control. - - - - The position on that the menu - should be displayed at. - - - - - Gets the underlying COM interface. - - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Provides a toolbar suitable for use in file Open/Save dialogs. - - - - This control provides a toolbar containing a - and the various navigation buttons as - found in a standard file dialog. By setting the - property, the toolbar will automatically - control the navigation of a ShellView> control in response to the - user's actions. - - - - - Required designer variable. - - - - - Clean up any resources being used. - - true if managed resources should be disposed; otherwise, false. - - - - Required method for Designer support - do not modify - the contents of this method with the code editor. - - - - - Initializes a new instance of the FileDialogToolbar control. - - - - - Gets/sets the root folder displayed in the toolbar's drop-down - folder list. - - - - - Gets/sets the folder currently selected in the toolbar's combo box. - - - - - Gets/sets a whose navigation should be - controlled by the toolbar. - - - - - Occurs when the needs to know - what items it should display in its drop-down list. - - - - - A file-filter combo box suitable for use in open/save file dialogs. - - - - - This control extends the class to provide - automatic filtering of shell items according to wildcard patterns. - By setting the control's property, the control - will automatically filter items in a ShellView. - - - - The property accepts a filter string - similar to that accepted by the standard - class, for example: - "Text files (*.txt)|*.txt|All files (*.*)|*.*" - - - - The currently selected filter is selected by the - property. This should be set to one of the filter patterns specified - in , e.g. "*.txt". - - - - - - Initializes a new instance of the - class. - - - - - Generates a object equivalent to the - provided wildcard. - - - - The wildcard to generate a regex for. - - - - A regex equivalent to the wildcard. - - - - - Raises the event. - - - - An EventArgs that contains the event data. - - - - - Gets or sets the current filter string, which determines the - items that appear in the control's . - - - - - This property does not apply to . - - - - - Gets/sets the filter string which determines the choices that - appear in the control's drop-down list. - - - - - For each filtering option, the filter string contains a - description of the filter, followed by the vertical bar (|) and - the filter pattern. The strings for different filtering options - are separated by the vertical bar. - - - - If the filter itself does not appear in the description then - it will be automatically added when the control is displayed. - For example, in the example below the "Video files" entry will - be displayed as "Video files (*.avi, *.wmv)". Beacuse the "All - files" entry already has the filter string present in its - description, it will not be added again. - - - - - "Video files|*.avi, *.wmv|All files (*.*)|*.*" - - - - - - - This property does not apply to . - - - - - Gets/sets the control that the - should filter the items of. - - - - - Provides a tree view of a computer's folders. - - - - - The control allows you to embed Windows - Explorer functionality in your Windows Forms applications. The - control provides a tree view of the computer's folders, as it would - appear in the left-hand pane in Explorer. - - - - - - Initializes a new instance of the class. - - - - - Refreses the contents of the . - - - - - Gets/sets a value indicating whether drag/drop operations are - allowed on the control. - - - - - Gets or sets a value indicating whether a tree node label takes on - the appearance of a hyperlink as the mouse pointer passes over it. - - - - - Gets or sets the root folder that is displayed in the - . - - - - - Gets/sets a whose navigation should be - controlled by the treeview. - - - - - Gets or sets the selected folder in the - . - - - - - Gets or sets a value indicating whether hidden folders should - be displayed in the tree. - - - - - Occurs when the property changes. - - - - - This property does not apply to the - class. - - - - Describes whether hidden files/folders should be displayed in a - control. - - - - Hidden files/folders should not be displayed. - - - - - Hidden files/folders should be displayed. - - - - - The Windows Explorer "Show hidden files" setting should be used - to determine whether to show hidden files/folders. - - - - - Listens for notifications of changes in the Windows Shell Namespace. - - - - - Initializes a new instance of the - class. - - - - - Initializes a new instance of the - class. - - - - - Overrides the method. - - - - - - Occurs when a drive is added. - - - - - Occurs when a drive is removed. - - - - - Occurs when a folder is created. - - - - - Occurs when a folder is deleted. - - - - - Occurs when a folder is renamed. - - - - - Occurs when a folder's contents are updated. - - - - - Occurs when a non-folder item is created. - - - - - Occurs when a non-folder item is deleted. - - - - - Occurs when a non-folder item is renamed. - - - - - Occurs when a non-folder item is updated. - - - - - Occurs when the shared state for a folder changes. - - - - - Provides information of changes in the Windows Shell Namespace. - - - - - Initializes a new instance of the - class. - - - - The ShellItem that has changed. - - - - - The ShellItem that has changed. - - - - - Provides information of changes in the Windows Shell Namespace. - - - - - Initializes a new instance of the - class. - - - - The ShellItem before the change - - - - The ShellItem after the change - - - - - The ShellItem before the change. - - - - - The ShellItem after the change. - - - - - Represents the method that handles change notifications from - - - - - The source of the event. - - - - A that contains the data - for the event. - - - - - Represents the method that handles change notifications from - - - - - The source of the event. - - - - A that contains the data - for the event. - - - - - Specifies how list items are displayed in a - control. - - - - - Each item appears as a full-sized icon with a label below it. - - - - - Each item appears as a small icon with a label to its right. - - - - - Each item appears as a small icon with a label to its right. - Items are arranged in columns with no column headers. - - - - - Each item appears on a separate line with further information - about each item arranged in columns. The left-most column - contains a small icon and label. - - - - - Each item appears with a thumbnail picture of the file's content. - - - - - Each item appears as a full-sized icon with the item label and - file information to the right of it. - - - - - Each item appears in a thumbstrip at the bottom of the control, - with a large preview of the seleted item appearing above. - - - - - Provides a view of a computer's files and folders. - - - - - The control allows you to embed Windows - Explorer functionality in your Windows Forms applications. The - control provides a view of a single folder's contents, as it would - appear in the right-hand pane in Explorer. - - - - When a new control is added to a form, - it displays the contents of the Desktop folder. Other folders - can be displayed by calling one of the Navigate methods or setting - the property. - - - - - - Initializes a new instance of the class. - - - - - Creates a new folder in the folder currently being browsed. - - - - - Deletes the item currently selected in the . - - - - - Navigates to the specified . - - - - The folder to navigate to. - - - - - Navigates to the specified filesystem directory. - - - - The path of the directory to navigate to. - - - - is not a valid folder. - - - - - Navigates to the specified standard location. - - - - The to which to navigate. - - - - Standard locations are virtual folders which may be located in - different places in different versions of Windows. For example - the "My Documents" folder is normally located at C:\My Documents - on Windows 98, but is located in the user's "Documents and - Settings" folder in Windows XP. Using a standard - to refer to such folders - ensures that your application will behave correctly on all - versions of Windows. - - - - - Navigates the control to the previous folder - in the navigation history. - - - - - The WebBrowser control maintains a history list of all the folders - visited during a session. You can use the - method to implement a Back button similar to the one in - Windows Explorer, which will allow your users to return to a - previous folder in the navigation history. - - - - Use the property to determine whether - the navigation history is available and contains a previous page. - This property is useful, for example, to change the enabled state - of a Back button when the ShellView control navigates to or leaves - the beginning of the navigation history. - - - - - There is no history to navigate backwards through. - - - - - Navigates the control backwards to the - requested folder in the navigation history. - - - - The WebBrowser control maintains a history list of all the folders - visited during a session. You can use the - method to implement a drop-down menu on a Back button similar - to the one in Windows Explorer, which will allow your users to return - to a previous folder in the navigation history. - - - - The folder to navigate to. - - - - The requested folder is not present in the - 's 'back' history. - - - - - Navigates the control to the next folder - in the navigation history. - - - - - The WebBrowser control maintains a history list of all the folders - visited during a session. You can use the - method to implement a Forward button similar to the one - in Windows Explorer, allowing your users to return to the next - folder in the navigation history after navigating backward. - - - - Use the property to determine - whether the navigation history is available and contains a folder - located after the current one. This property is useful, for - example, to change the enabled state of a Forward button - when the ShellView control navigates to or leaves the end of the - navigation history. - - - - - There is no history to navigate forwards through. - - - - - Navigates the control forwards to the - requested folder in the navigation history. - - - - The WebBrowser control maintains a history list of all the folders - visited during a session. You can use the - method to implement a drop-down menu - on a Forward button similar to the one in Windows Explorer, - which will allow your users to return to a folder in the 'forward' - navigation history. - - - - The folder to navigate to. - - - - The requested folder is not present in the - 's 'forward' history. - - - - - Navigates to the parent of the currently displayed folder. - - - - - Navigates to the folder currently selected in the - . - - - - If the 's - property is set, and more than one item is selected in the - ShellView, the first Folder found will be navigated to. - - - - if a selected folder could be - navigated to, otherwise. - - - - - Refreshes the contents of the . - - - - - Begins a rename on the item currently selected in the - . - - - - - Selects all items in the . - - - - - Overrides - - - - - - - Creates the actual shell view control. - - - - - Overrides . - - - - - - - - Overrides . - - - - - - - Overrides - - - - - - - - Overrides - - - - - - Gets a value indicating whether a new folder can be created in - the folder currently being browsed by th . - - - - - Gets a value indicating whether a previous page in navigation - history is available, which allows the - method to succeed. - - - - - Gets a value indicating whether a subsequent page in navigation - history is available, which allows the - method to succeed. - - - - - Gets a value indicating whether the folder currently being browsed - by the has parent folder which can be - navigated to by calling . - - - - - Gets the control's underlying COM IShellView interface. - - - - - Gets/sets a describing the folder - currently being browsed by the . - - - - - Gets the 's navigation history. - - - - - Gets a list of the items currently selected in the - - - - - A array detailing the items currently - selected in the control. If no items are currently selected, - an empty array is returned. - - - - - Gets/sets a value indicating whether multiple items can be selected - by the user. - - - - - Gets/sets a value indicating whether a "WebView" is displayed on - the left of the control. - - - - The WebView is a strip of HTML that appears to the left of a - Windows Explorer window when the window has no Explorer Bar. - It displays general system tasks and locations, as well as - information about the items selected in the window. - - - Important: When is set to - , the - event will not occur. This is due to a limitation in the - underlying windows control. - - - - - - Gets/sets a control that the - should use to display folder details. - - - - - Gets or sets how items are displayed in the control. - - - - - Occurs when the control wants to know - if it should include an item in its view. - - - - This event allows the items displayed in the - control to be filtered. You may want to to only list files with - a certain extension, for example. - - - - - Occurs when the control navigates to a - new folder. - - - - - Occurs when the control is about to - navigate to a new folder. - - - - - Occurs when the 's current selection - changes. - - - - Important: When is set to - , this event will not occur. This is due to - a limitation in the underlying windows control. - - - - - This property does not apply to . - - - - - This property does not apply to . - - - - - This property does not apply to . - - - - - Provides information for FilterItem events. - - - - - Initializes a new instance of the - class. - - - - The item to be filtered. - - - - - Gets/sets a value which will determine whether the item will be - included in the . - - - - - The item to be filtered. - - - - - Provides information for the - event. - - - - - Initializes a new instance of the - class. - - - - The folder being navigated to. - - - - - Gets/sets a value indicating whether the navigation should be - cancelled. - - - - - The folder being navigated to. - - - - - Exception raised when a user aborts a Shell operation. - - - - - Initializes a new instance of the - class. - - - - The inner exception. - - - - - Represents the method that will handle FilterItem events. - - - - - Represents the method that will handle the - event. - - - - - Holds a 's navigation history. - - - - - Clears the shell history. - - - - - Gets the list of folders in the 's - Back history. - - - - - Gets the list of folders in the 's - Forward history. - - - - diff --git a/References/GongShell.dll b/References/GongShell.dll deleted file mode 100644 index ee48480b75d..00000000000 Binary files a/References/GongShell.dll and /dev/null differ diff --git a/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 48b1713e164..9a7c16fd598 100755 --- a/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -16,7 +16,6 @@ - diff --git a/src/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs b/src/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs index a80a9f71362..da6091dc100 100644 --- a/src/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs +++ b/src/BizHawk.Client.EmuHawk/Extensions/ToolExtensions.cs @@ -2,6 +2,7 @@ using System.IO; using System.Collections.Generic; using System.Windows.Forms; + using BizHawk.Common; using BizHawk.Emulation.Common; using BizHawk.Client.Common; @@ -113,16 +114,20 @@ public static ToolStripItem[] RecentMenu(this RecentFiles recent, IMainFormForTo tsmiCopyFile.Click += (o, ev) => { Clipboard.SetFileDropList(lame); }; tsdd.Items.Add(tsmiCopyFile); - var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" }; - tsmiTest.Click += (o, ev) => + if (!OSTailoredCode.IsUnixHost) { - var si = new GongSolutions.Shell.ShellItem(hf.FullPathWithoutMember); - var scm = new GongSolutions.Shell.ShellContextMenu(si); - var tsddi = o as ToolStripDropDownItem; - tsddi.Owner.Update(); - scm.ShowContextMenu(tsddi.Owner, new System.Drawing.Point(0, 0)); - }; - tsdd.Items.Add(tsmiTest); + var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" }; + tsmiTest.Click += (o, ev) => + { + var tsddi = o as ToolStripDropDownItem; + tsddi.Owner.Update(); + using var menu = new ContextMenu(); + using var dummy = new Control(); + Win32ShellContextMenu.ShowContextMenu( + hf.FullPathWithoutMember, menu.Handle, dummy.Handle, tsddi.Owner.Location.X, tsddi.Owner.Location.Y); + }; + tsdd.Items.Add(tsmiTest); + } tsdd.Items.Add(new ToolStripSeparator()); } diff --git a/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs b/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs new file mode 100644 index 00000000000..3b1d6dc4da5 --- /dev/null +++ b/src/BizHawk.Common/Win32/Win32ShellContextMenu.cs @@ -0,0 +1,284 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace BizHawk.Common +{ + public class Win32ShellContextMenu + { + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] + public interface IShellItem + { + IntPtr BindToHandler(IntPtr pbc, + [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid); + + [PreserveSig] + int GetParent(out IShellItem ppsi); + + IntPtr GetDisplayName(uint sigdnName); + + uint GetAttributes(uint sfgaoMask); + + int Compare(IShellItem psi, uint hint); + } + + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214F2-0000-0000-C000-000000000046")] + public interface IEnumIDList + { + [PreserveSig] + int Next(uint celt, out IntPtr rgelt, out uint pceltFetched); + + [PreserveSig] + int Skip(uint celt); + + [PreserveSig] + int Reset(); + + IEnumIDList Clone(); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214E6-0000-0000-C000-000000000046")] + public interface IShellFolder + { + void ParseDisplayName( + [In] IntPtr hwnd, + [In] IntPtr pbc, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, + [Out] out uint pchEaten, + [Out] out IntPtr ppidl, + [In, Out] ref uint pdwAttributes); + + [PreserveSig] + int EnumObjects( + [In] IntPtr hwnd, + [In] SHCONTF grfFlags, + [Out] out IEnumIDList ppenumIDList); + + void BindToObject(IntPtr pidl, IntPtr pbc, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + out IntPtr ppv); + + void BindToStorage(IntPtr pidl, IntPtr pbc, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + out IntPtr ppv); + + [PreserveSig] + short CompareIDs(uint lParam, IntPtr pidl1, IntPtr pidl2); + + IntPtr CreateViewObject(IntPtr hwndOwner, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid); + + void GetAttributesOf(uint cidl, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] apidl, + ref uint rgfInOut); + + void GetUIObjectOf(IntPtr hwndOwner, uint cidl, + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] IntPtr[] apidl, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + uint rgfReserved, + out IntPtr ppv); + + void GetDisplayNameOf(IntPtr pidl, int uFlags, out STRRET pName); + + void SetNameOf(IntPtr hwnd, IntPtr pidl, string pszName, SHCONTF uFlags, out IntPtr ppidlOut); + + public enum SHCONTF + { + FOLDERS = 0x0020, + NONFOLDERS = 0x0040, + INCLUDEHIDDEN = 0x0080, + INIT_ON_FIRST_NEXT = 0x0100, + NETPRINTERSRCH = 0x0200, + SHAREABLE = 0x0400, + STORAGE = 0x0800 + } + + [StructLayout(LayoutKind.Explicit, Size = 264)] + public struct STRRET + { + [FieldOffset(0)] + public uint uType; + [FieldOffset(4)] + public IntPtr pOleStr; + [FieldOffset(4)] + public IntPtr pStr; + [FieldOffset(4)] + public uint uOffset; + [FieldOffset(4)] + public IntPtr cStr; + } + } + + [Flags] + public enum TPM + { + TPM_LEFTBUTTON = 0x0000, + TPM_RIGHTBUTTON = 0x0002, + TPM_LEFTALIGN = 0x0000, + TPM_CENTERALIGN = 0x000, + TPM_RIGHTALIGN = 0x000, + TPM_TOPALIGN = 0x0000, + TPM_VCENTERALIGN = 0x0010, + TPM_BOTTOMALIGN = 0x0020, + TPM_HORIZONTAL = 0x0000, + TPM_VERTICAL = 0x0040, + TPM_NONOTIFY = 0x0080, + TPM_RETURNCMD = 0x0100, + TPM_RECURSE = 0x0001, + TPM_HORPOSANIMATION = 0x0400, + TPM_HORNEGANIMATION = 0x0800, + TPM_VERPOSANIMATION = 0x1000, + TPM_VERNEGANIMATION = 0x2000, + TPM_NOANIMATION = 0x4000, + TPM_LAYOUTRTL = 0x8000, + } + + [Flags] + public enum CMF : uint + { + NORMAL = 0x00000000, + DEFAULTONLY = 0x00000001, + VERBSONLY = 0x00000002, + EXPLORE = 0x00000004, + NOVERBS = 0x00000008, + CANRENAME = 0x00000010, + NODEFAULT = 0x00000020, + INCLUDESTATIC = 0x00000040, + EXTENDEDVERBS = 0x00000100, + RESERVED = 0xffff0000, + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct CMINVOKECOMMANDINFO + { + public int cbSize; + public int fMask; + public IntPtr hwnd; + public string lpVerb; + public string lpParameters; + public string lpDirectory; + public int nShow; + public int dwHotKey; + public IntPtr hIcon; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct CMINVOKECOMMANDINFO_ByIndex + { + public int cbSize; + public int fMask; + public IntPtr hwnd; + public int iVerb; + public string lpParameters; + public string lpDirectory; + public int nShow; + public int dwHotKey; + public IntPtr hIcon; + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214e4-0000-0000-c000-000000000046")] + public interface IContextMenu + { + [PreserveSig] + int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, CMF uFlags); + + void InvokeCommand(ref CMINVOKECOMMANDINFO pici); + + [PreserveSig] + int GetCommandString(int idcmd, uint uflags, int reserved, + [MarshalAs(UnmanagedType.LPStr)] StringBuilder commandstring, + int cch); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214f4-0000-0000-c000-000000000046")] + public interface IContextMenu2 : IContextMenu + { + [PreserveSig] + new int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, CMF uFlags); + + void InvokeCommand(ref CMINVOKECOMMANDINFO_ByIndex pici); + + [PreserveSig] + new int GetCommandString(int idcmd, uint uflags, int reserved, + [MarshalAs(UnmanagedType.LPStr)] StringBuilder commandstring, + int cch); + + [PreserveSig] + int HandleMenuMsg(int uMsg, IntPtr wParam, IntPtr lParam); + } + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + public static extern IShellItem SHCreateItemFromParsingName( + [In] string pszPath, + [In] IntPtr pbc, + [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); + + [DllImport("shell32.dll", PreserveSig = false)] + public static extern IntPtr SHGetIDListFromObject([In, MarshalAs(UnmanagedType.IUnknown)] object punk); + + [DllImport("shell32.dll", EntryPoint = "#16")] + public static extern IntPtr ILFindLastID(IntPtr pidl); + + [DllImport("user32.dll")] + public static extern int TrackPopupMenuEx(IntPtr hmenu, TPM fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); + + private IContextMenu ComInterface { get; } + private IContextMenu2 ComInterface2 { get; } + + private static Guid SFObject = new("3981e224-f559-11d3-8e3a-00c04f6837d5"); + + private Win32ShellContextMenu(string path) + { + var uri = new Uri(path); + + // gongshell supported shell schemes, although that seems complicated to support and very edge case, so not bothering for now --cpp + if (uri.Scheme != "file") + { + throw new NotSupportedException("Non-file Uri schemes are unsupported"); + } + + var shellItem = SHCreateItemFromParsingName(uri.LocalPath, IntPtr.Zero, typeof(IShellItem).GUID); + + var pidls = new IntPtr[1]; + pidls[0] = ILFindLastID(SHGetIDListFromObject(shellItem)); + shellItem.GetParent(out var parent); + + var result = parent.BindToHandler(IntPtr.Zero, SFObject, typeof(IShellFolder).GUID); + + var shellFolder = (IShellFolder)Marshal.GetObjectForIUnknown(result); + shellFolder.GetUIObjectOf(IntPtr.Zero, 1, pidls, typeof(IContextMenu).GUID, 0, out result); + + ComInterface = (IContextMenu)Marshal.GetObjectForIUnknown(result); + ComInterface2 = (IContextMenu2)ComInterface; + } + + public static void ShowContextMenu(string path, IntPtr handle, IntPtr hwnd, int x, int y) + { + var ctxMenu = new Win32ShellContextMenu(path); + const int CmdFirst = 0x8000; + ctxMenu.ComInterface.QueryContextMenu(handle, 0, CmdFirst, int.MaxValue, CMF.EXPLORE); + int command = TrackPopupMenuEx(handle, TPM.TPM_RETURNCMD, x, y, hwnd, IntPtr.Zero); + if (command > 0) + { + const int SW_SHOWNORMAL = 1; + CMINVOKECOMMANDINFO_ByIndex invoke = default; + invoke.cbSize = Marshal.SizeOf(invoke); + invoke.iVerb = command - CmdFirst; + invoke.nShow = SW_SHOWNORMAL; + ctxMenu.ComInterface2.InvokeCommand(ref invoke); + } + } + } +}