using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace JFileManager
{
/// <summary>
/// Shows the Explorer Context Menu
/// </summary>
public class cContextMenu
{
public const int MAX_SHELL_ID = 0x7FFF;
public const int MIN_SHELL_ID = 1;
private cContextMenu()
{
//
// No instances, all static
//
}
/// <summary>
/// Takes an ArrayList of IntPtr and returns an array of IntPtr
/// </summary>
/// <param name="alPIDLS">ArrayList of PIDLs</param>
/// <returns>IntPtr[]</returns>
private static IntPtr[] ArrayListToIPArray(ArrayList alPIDLS)
{
int intPos = 0;
IntPtr[] ipReturn = null;
if (alPIDLS.Count > 0)
{
ipReturn = new IntPtr[alPIDLS.Count];
IEnumerator ie = alPIDLS.GetEnumerator();
while (ie.MoveNext())
ipReturn[intPos++] = (IntPtr)ie.Current;
}
return ipReturn;
}
/// <summary>
/// Creates an IntPtr[] from a string[] of file/folder names
/// </summary>
/// <param name="hwnd">Parent window handle</param>
/// <param name="strFiles">string[] of file/folder names</param>
/// <param name="ParentFolder">IShellFolder to be returned</param>
/// <returns>An IntPtr[] of ItemIDLists for strFiles</returns>
private static IntPtr[] CreatePIDLList(IntPtr hwnd, string[] strFiles, ref IShellFolder ParentFolder)
{
ArrayList alPIDLS = new ArrayList();
int intCount;
IntPtr ipChild = new IntPtr();
IntPtr[] ipList = new IntPtr[0];
string strParent = "";
string strChild = "";
for (intCount = 0; intCount <= strFiles.GetUpperBound(0); intCount++)
{
cCommon.SplitObjectPath(strFiles[intCount], out strParent, out strChild);
ipChild = cCommon.GetChildIDList(hwnd, strParent, strChild, ref ParentFolder);
alPIDLS.Add(ipChild);
}
return ArrayListToIPArray(alPIDLS);
}
private static int MAKEINTRESOURCE(int res)
{
return 0x0000FFFF & res;
}
/// <summary>
/// Shows Explorer Context Menu for an object who's PIDL is known
/// </summary>
/// <param name="hwnd">Parent window handle</param>
/// <param name="ipPIDL">IntPtr to the object's ItemIDList</param>
/// <param name="pt">Position where context menu should be shown</param>
/// <param name="icm3">IContextMenu3 to be set for owner draw items on context menu</param>
/// <returns>true</returns>
public static bool ShowContextMenu(IntPtr hwnd, IntPtr ipPIDL, Point pt, ref IContextMenu3 icm3)
{
uint rgfReserved = 0;
IntPtr ipParent = new IntPtr();
IShellFolder DesktopFolder = null;
IShellFolder ParentFolder = null;
IUnknown iu;
REFIID IID_IShellFolder = new REFIID("000214E6-0000-0000-c000-000000000046");
REFIID IID_IContextMenu = new REFIID("000214E4-0000-0000-c000-000000000046");
cCommon.SHGetDesktopFolder(ref DesktopFolder);
// BindToObject
// Retrieves an IShellFolder object for a subfolder
// If ipPIDL is the DeskTop then ParentFolder will be null
ParentFolder = null;
DesktopFolder.BindToObject(ipParent, IntPtr.Zero, ref IID_IShellFolder, ref ParentFolder);
iu = null;
if (ParentFolder != null)
ParentFolder.GetUIObjectOf(hwnd, 1, ref ipPIDL, ref IID_IContextMenu, out rgfReserved, ref iu);
else
DesktopFolder.GetUIObjectOf(hwnd, 1, ref ipPIDL, ref IID_IContextMenu, out rgfReserved, ref iu);
return ShowMenu(hwnd, pt, iu, ref icm3);
}
/// <summary>
/// Shows Context Menu for one file/folder
/// </summary>
/// <param name="hwnd">Parent window handle</param>
/// <param name="ipPIDL">IntPtr to the object's ItemIDList</param>
/// <param name="pt">Position where context menu should be shown</param>
/// <param name="icm3">IContextMenu3 to be set for owner draw items on context menu</param>
/// <returns>true</returns>
public static bool ShowContextMenu(IntPtr hwnd, string strFQFileName, Point pt, ref IContextMenu3 icm3)
{
uint rgfReserved = 0;
IntPtr ipChild = new IntPtr();
IShellFolder ParentFolder = null;
IUnknown iu;
REFIID IID_IContextMenu = new REFIID("000214E4-0000-0000-c000-000000000046");
string strParent = "";
string strChild = "";
bool blnOK = cCommon.SplitObjectPath(strFQFileName, out strParent, out strChild);
if (!blnOK)
return false;
ipChild = cCommon.GetChildIDList(hwnd, strParent, strChild, ref ParentFolder);
iu = null;
ParentFolder.GetUIObjectOf(hwnd, 1, ref ipChild, ref IID_IContextMenu, out rgfReserved, ref iu);
return ShowMenu(hwnd, pt, iu, ref icm3);
}
/// <summary>
/// Shows Context Menu for String Array of files/folders
/// </summary>
/// <param name="hwnd">Parent window handle</param>
/// <param name="ipPIDL">IntPtr to the object's ItemIDList</param>
/// <param name="pt">Position where context menu should be shown</param>
/// <param name="icm3">IContextMenu3 to be set for owner draw items on context menu</param>
/// <returns>true</returns>
public static bool ShowContextMenu(IntPtr hwnd, string[] strFiles, Point pt, ref IContextMenu3 icm3)
{
if (strFiles.GetUpperBound(0) < 0)
return false;
uint rgfReserved = 0;
IShellFolder ParentFolder = null;
IUnknown iu = null;
REFIID IID_IContextMenu = new REFIID("000214E4-0000-0000-c000-000000000046");
IntPtr[] ipList = CreatePIDLList(hwnd, strFiles, ref ParentFolder);
if (ipList.GetUpperBound(0) < 0)
return false;
ParentFolder.GetUIObjectOf(hwnd, (uint)ipList.GetUpperBound(0) + 1, ref ipList[0], ref IID_IContextMenu, out rgfReserved, ref iu);
return ShowMenu(hwnd, pt, iu, ref icm3);
}
/// <summary>
/// Shows the context menu after all the background work is complete
/// </summary>
/// <param name="hwnd">Parent window handle</param>
/// /// <param name="pt">Position where context menu should be shown</param>
/// <param name="iu">IUnknown created during background work</param>
/// <param name="icm3">IContextMenu3 to be set for owner draw items on context menu</param>
/// <returns>true</returns>
private static bool ShowMenu(IntPtr hwnd, Point pt, IUnknown iu, ref IContextMenu3 icm3)
{
// Casting to an IcontextMenu2 does this: pContextMenu->QueryInterface(IID_IContextMenu2, (VOID**)&pContextMenu2);
// Advice provided by Mattias Sj�gren [MVP] http://www.msjogren.net/dotnet/
// We need this to deal with 'Send To' and 'Open With' which have owner draw sub menus
CMINVOKECOMMANDINFO CI = new CMINVOKECOMMANDINFO();
icm3 = (IContextMenu3)iu;
RECT mRect;
if (icm3 != null)
{
IntPtr hMenu = cCommon.CreatePopupMenu();
icm3.QueryContextMenu((uint)hMenu, 0, MIN_SHELL_ID, MAX_SHELL_ID, (ushort)(CMF.CMF_EXPLORE | CMF.CMF_CANRENAME));
int cmdID = cCommon.TrackPopupMenu(hMenu, ((int)TPM.TPM_RETURNCMD | (int)TPM.TPM_LEFTALIGN), pt.X, pt.Y, 0, hwnd, out mRect);
if (cmdID != 0)
{
CI.cbSize = (uint)Marshal.SizeOf(CI);
CI.hwnd = hwnd;
CI.lpVerb = (IntPtr)MAKEINTRESOURCE(cmdID - 1);
CI.lpParameters = IntPtr.Zero;
CI.lpDirectory = IntPtr.Zero;
CI.nShow = (int)SW.SW_SHOWNORMAL;
icm3.InvokeCommand(ref CI);
}
}
return true;
}
}
}