I know where the scissors are kept, where the spare light bulbs are, and where my first aid box is. I also know where I keep files on my computer.
I don't find Windows Explorer very useful for managing files. To me, a file manager has a "source" on the left and a "destination" on the right, with the ability to quickly copy or move files from source to destination, and to create shortcuts.
Jeff's File Manager (a dual pane file manager) is my attempt to produce a tool that lets me manage my files. It does many of the things that Windows Explorer does; it has a context menu (in fact, the Explorer context menu), and I can drag and drop files/folders. In some respects, it goes a bit further than Explorer in that it shows ghosted icons for empty CD/DVD drives. If you accidentally click on an empty CD/DVD drive, it won't open it and crash it into the door on your computer (I imagine Microsoft Vista/Win7 programmers don't have computers with doors on), it will just beep at you and tell you access is denied.
It doesn't show "My Documents" or the control panel, nor does it show the network - although it will show mapped network drives, in fact it will show anything with a drive letter.
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. In fact, it makes quite extensive use of the Windows API, and we can only hope that eventually Microsoft will extend the .NET Framework to give us easier access to the various interfaces that are needed for an app like this.
At the top level, there is a Windows Form:
FormFileManager. This has the main menu and a
Splitter control. Within the
Splitter control sits two instances of a User Control called
JExplorerFS, the one on the left is the source and the one on the right, the destination.
In turn, the
JExplorerFS control contains further controls - a
JCrumbToolBar (inherited from
JTreeViewFS (inherited from
System.Windows.Forms.TreeView), and a
JListViewFS (inherited from
System.Windows.Forms.ListView). Each of these controls is self contained so the
JExplorerFS brings them all together and communicates between them.
The main from contains a standard ToolBar for quick access to functions, and each of the
JExplorerFS controls has its own ToolBar.
Using the Application
If you treat it like two instances of Windows Explorer running side by side, you won't go far wrong - except there are buttons to allow you to copy/move files from the source to destination.
The main toolbar allows you to change the layout, compare file names between folders, compare files between folders, copy, move, and create shortcuts, copy and move with a rename, flip panes, and map/unmap network drives.
The toolbars in the source and destination panes are fairly self explanatory. There is an option to "Save File Icon" in the Tools menu. Ironically, it works with most things except file icons, and the various solutions I found on the Internet to save icons don't seem to work. However, it will save other graphics formats. The options I use most frequently are duplicated in toolbar buttons.
The two buttons that might need explaining are:
This has nothing to do with Windows Favourites; it is a place to keep a note of the folders you use most. Click the main button to add the current folder, use the drop down to go to any listed folder.
- External Applications
The program uses Windows file associations, so double clicking a file will open it in accordance with its file association (double clicking an executable will run it). If you want to open a file with a different application, you can add the application path (click the main button) and then use the drop down to pass whatever parameters are needed. You can pass no parameters (the application will just open), a working directory, the currently selected directory, or the full path of the currently selected file.
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
JExplorerFS 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
JDriveData which a
List<DriveInfo> and a
List<JTagData>. These are set up the first time they are called – and can be refreshed when needed. The class is
static and I found it easier to use a
List<T> than a
The second bottleneck was setting the
JTreeViewFS to a new path. Because, information is only added to a node when it is expanded (and deleted when it is collapsed).
I decided to keep a
Dictionary<string, TreeNode> to link file paths to a
Dictionary is updated each time a
TreeNode is expanded or collapsed. Finding a specific folder is a case of finding its root in the
Dictionary, then expanding it and looking again until the required path is found. It can be slow; setting the
JTreeViewFS to a directory from, say, the favourites list means it has to start at the lowest common denominator (which in the worst case might be the root node) and work through expanding nodes as it goes. It's currently as quick as I can make it. It is certainly quicker to navigate by selecting the appropriate directory in the
TreeView than any other means.
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. There is a basic readme, called JGFileManager.txt, included.
This is the
internal class JDriveData
private static List<DriveInfo> m_DriveList = null;
private static List<JTagData> m_TagDataList = null;
private static void GetDriveData(bool refresh)
if (refresh || m_DriveList == null)
m_DriveList = new List<DriveInfo>();
DriveInfo driveArray = DriveInfo.GetDrives();
foreach (DriveInfo current in driveArray)
private static void GetDriveTagDataList(bool refresh)
if (refresh || m_TagDataList == null)
m_TagDataList = new List<JTagData>();
List<DriveInfo> driveArray = DriveList;
foreach (DriveInfo current in driveArray)
tagData = new JTagData(current);
internal static List<DriveInfo> DriveList
if (m_DriveList == null)
internal static void RefreshDriveData()
internal static List<JTagData> DriveTagDataList
if (m_TagDataList == null)
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 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.
My fault, I really should read the help more closely. I hope that I have picked up all the memory issues now.
- 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
cJFileInfo classes in the interest of optimization. The information is now set up directly in the
- I have set up the classes
cFilerLV to be self contained and to sit in
- 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
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
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 done 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.
- 20th December, 2010
- This is quite a major re-write which I have been doing over the last couple of years, so it is difficult to make a direct comparison with previous versions.
- I have added a Crumb-Bar, which seems to be the modern trend.
- I have done everything I can think of to make it as quick as possible, including the use of a
Dictionary<string, TreeNode> in the
- I have added a thumbnail view.