Click here to Skip to main content
6,290,721 members and growing! (7,281 online)
Email Password   helpLost your password?
Desktop Development » Files and Folders » Utilities     Intermediate License: The Code Project Open License (CPOL)

Dual Pane File Manager

By Jeff Gaines

A dual pane file manager for Windows XP
C#, .NET, WinXP, Visual Studio, Dev
Posted:7 Jul 2006
Updated:3 Dec 2008
Views:47,447
Bookmarked:88 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
20 votes for this article.
Popularity: 5.44 Rating: 4.18 out of 5
1 vote, 5.0%
1
1 vote, 5.0%
2
2 votes, 10.0%
3
4 votes, 20.0%
4
12 votes, 60.0%
5
Sample Image - maximum width is 600 pixels

Introduction

I seem to spend a fair bit of time managing files on my PC and don't find Windows Explorer the easiest tool to use. The best file manager I have ever used came with a DOS program called Brooklyn Bridge, which sold me completely on the concept of dual panes. The files I want to copy/move are on the left, the place I want to move them to is on the right. Mark the files, press the right keys (no menus in those days) and job done. Unfortunately it is not Y2K compliant and I haven't been able to find an alternative that I can get on with.

I also like to keep notes about files, so I can remind myself what they are, and I also want the ability to search those notes for a file I “know” that I have somewhere. Although this is possible in Explorer, I prefer those notes to be in my database so I can back it up and re-use it after a re-install. Having tried several file managers, none seemed to do what I wanted so I took the plunge and wrote my own.

This project is the result, it is not the first attempt, it's probably not the one hundredth attempt, but it's the one that works and doesn't (seem to) leak memory.

NET and Files/Folders

There are several classes in .NET relating to file/folder handling, and the DriveInfo class has been added in version 2. However, there is still no .NET way to find the correct icon for any of these, or to find the proper mask for the icon – so that shares and system folders show up properly. There is also no .NET way to show the Explorer Context Menu. What I have done is to use the .NET classes as far as possible and fallen back on the API where I couldn't find a .NET solution.

Application Structure

At the top level, there is a Windows Form - JFileManager. This has the main menu and a Splitter Control. Within the Splitter Control sit two instances of a User Control called cFiler, the one on the left is the source and the one on the right the destination.

In turn, the cFiler control contains further controls - a cFilerTS, a  cFilerTV and a cFilerLV. Each of these controls is self contained so the cFiler brings them all together and communicates between them. 

Speed of Application

I was anxious to ensure the program ran at a reasonable speed.

The first obvious bottleneck was getting the drive information which is used three times in each of the cFiler controls, making six times for the two controls. What I did was to set up all the information that was needed in a class called cJDriveInfoCollection which contains a HashTable in turn containing the CJDriveInfo. This is set up the first time it is called – and can be refreshed when needed. The class is static and I found it easier to use a HashTable than a Collections class.

The second bottleneck was setting the cSysTreeView to a new path. Since information is only added to a node when it is expanded, keeping a HashTable linking paths to nodes didn't seem practical. In the end, I decided to keep a HashTable of drives, so that the start node for any path could easily be found, and then work my way down the cSysTreeView finding the next node, expanding it (to get the folders added) and then continuing down. I ran some tests using the deepest nested folder I had but despite as much optimization as I was capable of, it takes just over two seconds to get to this node from the root node. I have left the test in (although the menu option is disabled) - if you want to try some tweaks to speed this up, I would be delighted to hear them!

When you close the TreeView pane, it is no longer kept up to date which speeds things up when you use it in that mode. It is updated when the TreeView pane is opened again.

Acknowledgements

Programming is a hobby for me. I have had a lot of help from various people over the years, generously and freely given, for which I am grateful.

I have acknowledged specific contributions in the source code.

Using the Code

I have tried to document the code as completely as possible, as it stands this is a complete application but there may be useful bits that can be pulled out and used in other projects.

Class Example

This is the cJDriveInfo class:

using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace JFileManager
{
	/// <summary>
	/// Provides additional information about drives
	/// </summary>
	public class cJDriveInfo
	{
	public string DisplayName = "";
	public string Path = "";
	public ObjectType ObjectType = ObjectType.DRIVE;
	public DriveType DriveType = DriveType.Unknown;
	public string TypeName = "";
	public int IconIndex = 0;
	public int SelectedIconIndex = 0;
	public long TotalSize = 0L;
	public long AvailableFreeSpace = 0L;
	public Image Image = null;
	public bool IsReady = false;
	public int Mask;
	public int StateMask;
	public int State;
	public bool HasChildren = false;
	public string VolumeLabel = "";
	public int Index;

	public cJDriveInfo(string strPath)
	: this(new DriveInfo(strPath))
	{
	}

	public cJDriveInfo(DriveInfo drivInfo)
	{
	this.Path = drivInfo.RootDirectory.ToString();
	this.DriveType = drivInfo.DriveType;
	this.IsReady = drivInfo.IsReady;

	this.GetSHFileInfo();

	// We won't get this info if drive is not ready
	try
	{
	this.TotalSize = drivInfo.TotalSize;
	this.AvailableFreeSpace = drivInfo.AvailableFreeSpace;
	// Display Name
	this.VolumeLabel = drivInfo.VolumeLabel;
	string strDrive = drivInfo.RootDirectory.ToString().Replace("\\", "");
	this.DisplayName = this.VolumeLabel + " (" + strDrive + ")";
	}
	catch
	{
	this.TotalSize = 0L;
	this.AvailableFreeSpace = 0L;
	}

	// Image Masks
	cCommon.GetLVImageMask(this.Path, out this.Mask, out this.StateMask, 
                               out this.State);

	// Sub-folders
	this.HasChildren = (cCommon.DirectorySubFolderCount(this.Path) > 0);
	}

	private void GetSHFileInfo()
	{
	SHFILEINFO shfi = new SHFILEINFO();

	UInt32 uFlags = (UInt32)(SHGFI.SHGFI_ICON | SHGFI.SHGFI_SMALLICON | 
                          SHGFI.SHGFI_TYPENAME | SHGFI.SHGFI_ADDOVERLAYS |
                          SHGFI.SHGFI_SYSICONINDEX | SHGFI.SHGFI_DISPLAYNAME);
	IntPtr ipTemp = cCommon.SHGetFileInfo(this.Path, 0, out shfi, 
                               Marshal.SizeOf(shfi), uFlags);

	// Check result
	if (ipTemp != IntPtr.Zero)
	{
	this.DisplayName = shfi.szDisplayName;
	this.TypeName = shfi.szTypeName;
	this.IconIndex = shfi.iIcon;
	this.Image = cCommon.ImageFromIcon(shfi.hIcon);
	}

	if (shfi.hIcon != IntPtr.Zero)
	cCommon.DestroyIcon(shfi.hIcon);

	// Selected Icon
	uFlags = (uint)(SHGFI.SHGFI_ICON | SHGFI.SHGFI_SMALLICON | 
                          SHGFI.SHGFI_ADDOVERLAYS | SHGFI.SHGFI_SYSICONINDEX |
                          SHGFI.SHGFI_OPENICON);
	ipTemp = cCommon.SHGetFileInfo(this.Path, 0, out shfi, 
                               Marshal.SizeOf(shfi), uFlags);

	if (ipTemp != IntPtr.Zero)
	{
	this.SelectedIconIndex = shfi.iIcon;
	}

	if (shfi.hIcon != IntPtr.Zero)
	cCommon.DestroyIcon(shfi.hIcon);
	}
	}
}

As you can see, its properties are obtained partly from the inbuilt DriveInfo class and partly from the API.

Memory Leaks

Using the API means moving out of the shelter of .NET’s memory management. I learnt (not quickly I have to confess) to read the help that comes with Visual Studio, especially when using the API!
Early versions of this program had massive memory leaks and so I read the help file for every API call I used and found the following relating to SHGetFileInfo:

If SHGetFileInfo returns an icon handle in the hIcon member of the SHFILEINFO structure pointed to by psfi, you are responsible for freeing it with DestroyIcon when you no longer need it.

Whoops!

My fault, I really should read the help more closely. I hope that I have picked up all the memory issues now.

History

  • 7th July, 2006
    • This is version 3.1, the latest version in a project I have been working on for a few years on and off. It is getting there but I would certainly appreciate any feedback.
  • 28th July, 2006
    • I have called this version 3.3 just to differentiate it from the earlier version.
    • I have updated this article to try and make it more readable.
    • I have dropped the earlier cJDirectoryInfo and cJFileInfo classes in the interest of optimization. The information is now set up directly in the cTNode and cLVItem classes.
    • I have set up the classes cFilerTScFilerTV and cFilerLV to be self contained and to sit in cFiler.
    • I have corrected a couple of errors such as shortcuts picking up the wrong icons along with some silly mistakes, some of which were pointed out in emails (I do appreciate that, I think it is impossible to produce a program without bugs unless somebody else tries it).
    • I added a try/catch block when reading LastWriteTime as it seems to have problems with some of my CD-Rs.
    • I wanted to pick up changes to removable media and tried a variety of approaches - WM_DEVICECHANGE is not propagated if you have CD AutoPlay off. I tried timers but was worried about resource issues. In the end, I decided to check removable devices when you hover over them (in the TreeView or ListView), I'd be interested in feedback on this approach. I've just realized that I don't update the DropDown with the fresh information, I will have a look at that for a later version.
    • I have had a general clean up and tried to make sure that functions are not duplicated.
    • I have added a class cUserFileAccessRights to indicate the user's access rights to folders (used in drag and drop). This class was written by Bruce Hatt here. It's an enormously useful class and has no equivalent in .NET.
  • 2nd December, 2008
    • The source has been updated to version 5. It now incorporates favourites and runs faster.
    • I have removed the note keeping functions. If you use them, you will need to add them back from the old source.

License

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

About the Author

Jeff Gaines


Member
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 were available and all were expensive).
Retired and living in the New Forest where I do some voluntary work and computer programming to keep my mind active.

Location: United Kingdom United Kingdom

Other popular Files and Folders articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 33 (Total in Forum: 33) (Refresh)FirstPrevNext
GeneralBeen There Pinmemberthund3rstruck10:58 5 Dec '08  
QuestionLooks like good work, But could not find EXE (or application) to run PinmemberHarshdeep Mehta (4700787)6:58 4 Dec '08  
GeneralIt's a cool project, but PinmemberAlexey Prosyankin2:31 4 Dec '08  
GeneralRe: It's a cool project, but PinmemberJeff Gaines2:52 4 Dec '08  
GeneralRe: It's a cool project, but PinmemberAlexey Prosyankin3:36 4 Dec '08  
GeneralRe: It's a cool project, but PinmemberAlexey Prosyankin4:37 4 Dec '08  
GeneralRe: It's a cool project, but PinmemberJeff Gaines23:29 4 Dec '08  
GeneralRe: It's a cool project, but PinmemberAlexey Prosyankin1:17 5 Dec '08  
GeneralWindows Explorer Context Menu PinmemberDoncp17:25 27 Nov '08  
GeneralRe: Windows Explorer Context Menu PinmemberDoncp6:54 28 Nov '08  
GeneralRe: Windows Explorer Context Menu PinmemberJeff Gaines1:09 29 Nov '08  
GeneralSuggestion [modified] Pinmemberfaroo280:23 20 Aug '06  
GeneralRe: Suggestion PinmemberJeff Gaines7:34 20 Aug '06  
GeneralGreat Works !! But a bit slow ... Pinmemberbuster2239:17 2 Aug '06  
GeneralRe: Great Works !! But a bit slow ... PinmemberJeff Gaines10:10 2 Aug '06  
GeneralRe: Great Works !! But a bit slow ... Pinmemberfaroo287:11 13 Jun '08  
GeneralPowerDesk PinmemberTed Ferenc23:10 29 Jul '06  
GeneralDirectory Opus PinmemberLeo Davidson2:41 31 Jul '06  
GeneralRe: Directory Opus PinmemberTed Ferenc4:38 31 Jul '06  
GeneralRe: Directory Opus Pinmembersimon.proctor4:53 31 Jul '06  
GeneralRe: Directory Opus PinmemberMAP Tiger0:25 1 Aug '06  
GeneralRe: PowerDesk Pinmemberjeff@jgaines.co.uk23:45 31 Jul '06  
GeneralRe: PowerDesk Pinmemberumeca745:44 24 Aug '06  
GeneralSuper! PinmemberDoncp12:04 29 Jul '06  
GeneralRe: Super! Pinmemberjeff@jgaines.co.uk13:45 29 Jul '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 3 Dec 2008
Editor: Deeksha Shenoy
Copyright 2006 by Jeff Gaines
Everything else Copyright © CodeProject, 1999-2009
Web09 | Advertise on the Code Project