Click here to Skip to main content
15,892,298 members
Articles / Programming Languages / C#

Dual Pane File Manager

Rate me:
Please Sign up or sign in to vote.
4.64/5 (28 votes)
21 Dec 2010CPOL8 min read 140.7K   2.3K   119  
A dual pane file manager for Windows XP.
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;
		}

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Retired
United Kingdom United Kingdom
I have been a keen hobbyist programmer since getting my first computer - a Vic 20 (you had to be able to write programs then since few programs were available and all were expensive).
Retired and now living in Pewsey, Wiltshire, where I spend (far too much of) my time writing computer programs to keep my mind active.

Comments and Discussions