Add your own alternative version
Stats
89.6K views 6.1K downloads 67 bookmarked
Posted
10 Dec 2007
|
Comments and Discussions
|
|
If I use it for moving files in my projects, UI is blocked for the length of the operation.
|
|
|
|
|
This does not open ShellContextMenu,
arrFI[0] = new FileInfo(@"c:\");
ShellContextMenu menu = new ShellContextMenu();
|
|
|
|
|
Thanks a lot ,I've been searching for this like forever !!! 
|
|
|
|
|
Method ShellContextMenu.ShowContextMenu first calls User32.dll DestroyMenu then calls IContextMenu.InvokeCommand, using the menu id of the previous destroyed menu.
Changed the order of calls, then it worked.
private void ShowContextMenu(Point pointScreen)
{
...
uint nSelected = TrackPopupMenuEx(
pMenu,
TPM.RETURNCMD,
pointScreen.X,
pointScreen.Y,
this.Handle,
IntPtr.Zero);
if (nSelected != 0)
{
InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen);
}
DestroyMenu(pMenu);
pMenu = IntPtr.Zero;
...
}
ShellContextMenu.InvokeContextMenuDefault does it in the right order.
|
|
|
|
|
This is a bug in author's code. I don't know how to fix it, but founded other code module/class for showing Explorer's context menu: Gong Solutions Shell Library. You should see source code of this project. It is really work!
|
|
|
|
|
Could you please tell me how can I add one more personal option to the context menu?
I want to have smthng like "Add to..." and when the users click on it, i want to show a form created from me in the same solution... But I want to keep the rest of the shell menu..
Thank you in advance...
|
|
|
|
|
Paste this code after pMenu = CreatePopupMenu();
int nResult = _oContextMenu.QueryContextMenu(
pMenu,
0,
CMD_FIRST,
CMD_LAST,
CMF.EXPLORE |
CMF.NORMAL |
((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); in void ShowContextMenu(Point pointScreen) (ShellContextMenu.cs):
MENUITEMINFO mii = new MENUITEMINFO();
mii.cbSize = Marshal.SizeOf(mii);
mii.fMask = MIIM.STRING | MIIM.ID;
mii.fState = MFS.DEFAULT;
mii.fType = MFT.BYCOMMAND;
mii.wID = 500;
mii.dwItemData = IntPtr.Zero;
mii.dwTypeData = "Your_Item_Name";
InsertMenuItem(pMenu, (uint)(GetMenuItemCount(pMenu) + 1), true, ref mii);
You'll need API-functions' declaration:
[DllImport("user32",
SetLastError = true,
CharSet = CharSet.Auto)]
private static extern bool InsertMenuItem(
IntPtr hMenu,
uint uItem,
bool fByPosition,
ref MENUITEMINFO lpmii);
[DllImport("user32.dll")]
private static extern int GetMenuItemCount(IntPtr hMenu);
How to handle clicking your item:
uint nSelected = TrackPopupMenuEx(
pMenu,
TPM.RETURNCMD,
pointScreen.X,
pointScreen.Y,
this.Handle,
IntPtr.Zero);
DestroyMenu(pMenu);
pMenu = IntPtr.Zero;
if (nSelected != 0)
{
if (nSelected == 500)
else
InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen);
}
modified 23-Jul-12 6:06am.
|
|
|
|
|
I have been playing a bit with the code but can't quite figure out how to place "my menu" items before / or on top of the explorer one? I figure it has something to do with the InsertMenuItem method? No matter what I set "uint" to be,
in example set to: (uint)(GetMenuItemCount(pMenu) + 1)
it still ends up last.
Could you maybe help me? I would be very grateful 
|
|
|
|
|
Does not work correctly on Windows Server 2008 64 bit or Win7 64 bit (I suspect the same with Vista 64 bit)
Try bringing up the context menu a few times (right clicking a file) it works the first few times then falls over.
I can't get any useful debug information from it, all I know is its memory access violation.
Can anyone else test and try confirm, I am unable to find a working .Net Explorer Context menu that works under 64 bit.
modified on Saturday, June 19, 2010 9:07 AM
|
|
|
|
|
For 64bit there is an unhandled overflow exception in WndProc which crashes the app.
Solution see http://www.codeproject.com/Messages/3541887/Re-Does-not-work-on-64-bit.aspx[^]
public static uint HiWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() & 0xffffffffL);
if ((param32 & 0x80000000) == 0x80000000)
return (param32 >> 16);
else
return (param32 >> 16) & 0xffff;
}
and
public static uint LoWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() & 0xffffffffL);
return (param32 & 0xffff);
}
|
|
|
|
|
I had same problem, but I changed
public static uint HiWord(IntPtr ptr)
to
public static long HiWord(IntPtr ptr)
And same for the LoWord function too
And its working perfectly
|
|
|
|
|
Excellent work, however i had to modify it for my evil purposes, the GetPIDLs overloads for DirectoryInfo and FileInfo were unnecessary and it made it not possible to get the menu of files and folders at the same time, i modified it to take string[] yet the drives menus where non functional so i added a check to GetParentFolder for drive paths to have parent folder "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" which is "My Computer"'s guid, and for desktop items like "My computer, My Documents, Desktop" i added an overload to ShowContextMenu and GetPIDLs that takes CSIDL that gets the PIDLs using SHGetSpecialFolderLocation, the rest of the CSIDL are quite useless so i just ignored them.
|
|
|
|
|
@mansatan
sorry, I speak English so badly that C#
would be nice if you give us the changes to uses directories and files
thank you in advance
(and thank you google for the translation,
which should not be great but better than this I could do)
@+
|
|
|
|
|
That does not seem to be too hard to do, I would just override:
public void ShowContextMenu
with parameters that accept a FileInfo array and a DirectoryInfo array.
If you look in the current ShowContextMenu methods, the method GetPIDLs is called for the DirectoryInfo and FileInfo arrays passed as parameters. Just call both for the directorys and files passed to your new method, and combine them in the _arrPIDLs array.
P.S. I did not test this, but it seems as though it should work. 
|
|
|
|
|
@mansatan or anyone
Your reply Here is over a year old,but I am hoping you or someone can show a little example of how to get this to work with drives. 
|
|
|
|
|
Hey, did you ever solver this for drives?
|
|
|
|
|
 I used the original FileBrowser to come up with this:
private IShellFolder GetRootFolder()
{
IntPtr folderEnumPtr = IntPtr.Zero;
IEnumIDList folderEnum = null;
IntPtr pidlSubItem;
int celtFetched;
IntPtr winHandle = IntPtr.Zero;
IShellFolder oParentFolder = null;
SHCONTF folderFlag =
SHCONTF.FOLDERS |
SHCONTF.INCLUDEHIDDEN;
IntPtr tempPidl;
SHFILEINFO info;
if (_oRootFolder == null)
{
info = new SHFILEINFO();
tempPidl = IntPtr.Zero;
SHGetSpecialFolderLocation(IntPtr.Zero, CSIDL.DRIVES, out tempPidl);
SHGetFileInfo(tempPidl, 0, ref info, cbFileInfo, SHGFI.PIDL | SHGFI.DISPLAYNAME | SHGFI.TYPENAME);
string sysfolderName = info.szTypeName;
string mycompName = info.szDisplayName;
try
{
oParentFolder = GetDesktopFolder();
if (oParentFolder.EnumObjects(winHandle, folderFlag, out folderEnumPtr) == S_OK)
{
folderEnum = (IEnumIDList)Marshal.GetTypedObjectForIUnknown(folderEnumPtr, typeof(IEnumIDList));
while (folderEnum.Next(1, out pidlSubItem, out celtFetched) == S_OK && celtFetched == 1)
{
IntPtr shellFolderPtr;
if (oParentFolder.BindToObject(
pidlSubItem,
IntPtr.Zero,
ref IID_IShellFolder,
out shellFolderPtr) == S_OK)
{
IntPtr strr = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4);
Marshal.WriteInt32(strr, 0, 0);
StringBuilder buf = new StringBuilder(MAX_PATH);
string txt = "";
if (oParentFolder.GetDisplayNameOf(
pidlSubItem,
SHGNO.INFOLDER,
strr) == S_OK)
{
StrRetToBuf(strr, pidlSubItem, buf, MAX_PATH);
txt = buf.ToString();
}
Marshal.FreeCoTaskMem(strr);
if (txt == mycompName)
{
_oRootFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(shellFolderPtr, typeof(IShellFolder));
break;
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (folderEnum != null)
{
Marshal.ReleaseComObject(folderEnum);
Marshal.Release(folderEnumPtr);
}
}
}
return _oRootFolder;
}
so if Parent is null then use that like this:
if (arrFI[n].Parent == null)
oParentFolder = GetRootFolder();
else
...
modified 2-Mar-18 8:30am.
|
|
|
|
|
Hello,
Can you please post your code here ?
|
|
|
|
|
i use this Shell ContextMenu but i can't use Send to of it,Please Help me
sorry if my english is not good
|
|
|
|
|
Good to know this trick.
Thanks!
Jm
|
|
|
|
|
This is really great, looking forward to use it, only problem is that it can't handle every situation, like it states, files / folders need to be in the same location, and only one type of object can be passed onto it at a time.
Keep up the good work.
|
|
|
|
|
Does someone know how to handle the first limitation (that the files need to be in the same folder) ? Thanks 
|
|
|
|
|
|
did not enjoy mansatan lol, that's some C++ tips, has anyone been able to take zabkat's tips and port to C#? if ur looking for a challenge that might be a good one!
|
|
|
|
|
I've been looking for articles relating to shell folder things like this, and this is part of what I'm looking for. Very simple implementation and execution that covers what I would need it to do nicely.
I was going to use a more thorough source code sample for my research into mimicking a Vista Explorer-esque interface in .NET, but your code should be a nice and simple alternative for me to look at as well! Thanks!
I was disappointed when I saw you haven't written any other articles. I'll be sure to check them out when you do. 
|
|
|
|
|
|
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
|