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
{
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();
try
{
this.TotalSize = drivInfo.TotalSize;
this.AvailableFreeSpace = drivInfo.AvailableFreeSpace;
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
cFilerTS, cFilerTV 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.
| You must Sign In to use this message board. |
|
|
 |
|
 |
I understand your pain. Windows Explorer is sheer garbage. I considered writing a replacement app but there are some outstanding free products out there already such as Xplorer2 Lite and Total Commander. When it comes to Buy, Build, Re-use I had to go with buy; except Xplorer2 if freeware so in this case I bought without paying - Got to love Free (as in beer) stuff!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Jeff,
Your article seems to be convincing. Would it be possible for you to upload compiled application, which i can run directly on my .Net Framework machine.
Thanks,
Harshdeep Mehta "Everything is possible, it just depends on how you play the game."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It's a cool project, but I'm personally feeling lack of "New" menu item, that is a standard explorer context menu item. After doing quick scan of this application I can't find the way how to add file or folder into some directory. So, I hope that you find way how to add this feature or point out the way how to add file or folder in your application. Thanks, anyway for your project!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Sorry, but I have yet another question to you. When I've been trying to open context menu item "Edit" with some file I have got such error message: "[here application path]. An attempt was made to reference a token that doesn't exist."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am not seeing that here, is the file name legal? Does Explorer handle it correctly? Perhaps it's worth setting a breakpoint and debugging it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
First of all I want to noticed that I use for testing Windows Vista. On my computer this bug was repeatedly reproduced. I have created a new text file. Then open it via explorer context menu. When I have been trying to open this file using your file manager and menu item "Edit" or "Open" I have got mentioned above error on the second attempt. On the first attempt was nothing occured. Really it's a Windows kernel error. You can find more about it here
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
First, I want to say (again) how much I like the File Manager. I use it all the time.
I have just downloaded csscript which has a CSharp scripting engine. One of the scripts creates an entry (Cmd) in Explorer's context menu:
RegistryKey shell = Registry.ClassesRoot.CreateSubKey(@"*\shell \Cmd\command"); shell.SetValue("", "cmd.exe"); shell.Close();
Now you can open command-prompt in a directory of your choice just by right clicking any file in that directory and selecting item 'Cmd' from the context menu.
Is there a way to do that with your File Manager?
Thanks, Don
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The actual problem:
When the context menu is displayed, it DOES show the "Cmd" item. But, when you click it, the directory that comes up is the directory where the File Manager executable is located, instead of the directory that contains the file that I right-clicked.
Don
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
If you look at the Context Manager class in the file manager you can see it passes a file or folder name. I would think that cssscript is picking up the working directory. There is an option to open a command prompt in the file manager or you can save the following as a .reg file:
***** Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Folder\shell\Menu Text] @="Command Prompt"
[HKEY_CLASSES_ROOT\Folder\shell\Menu Text\Command] @="C:\\WINDOWS\\system32\\cmd.exe /k cd \"%1\"" *****
and then double click it to merge it with the register.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Great work Jeff I have one suggestion, In most of the dual pane file managers, the tabbing of folders is supported, however these tabs are horizontal and as your number of tabs increases then you have to scroll them to get to the right one (See Total commander), This scrolling is annoying.
So if there is a small favorite folders pane for each of the pane in dual pane mode, then it would be nice
plus if u follow Total commander then u dont need two panes i.e one for browsing directory structure and one for looking the contents of the particular selected directory. may be you can support both types of behaviour.
Thanks
-- modified at 5:27 Sunday 20th August, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Many thanks for your comments  I am working on version 3.4 at the moment and have added saving settings and a favourites menu in each pane, I want to test it just a little more before I upload it. You can 'turn off' the TreeViews and just work with the ListViews if you prefer, it speeds things up a bit as the TreeViews are not updated in this mode.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Great Works ! 
But, as many controls I have seen, It's slow when a folder has many files. The best example is certainly the folder I386 of the WindowsXP CD. I suggest that you turn your listview into a VirtualListView ... It will speed up your listview ! If you need help about VirtualListView, let me know at nicolas_mercier@videotron.qc.ca
BuSTeR
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks BuSTeR 
I am working on a Virtual TreeView at the moment - it's based around the Extended ListView at: http://www.codeproject.com/cs/miscctrl/Extended_List_View_2.asp
so far it loads 53,000 nodes in 2.4 seconds - against 53 seconds for the Windows Forms TreeView.
I will look at a Virtual ListView as well, do you have a specific recommendation?
I have also managed to cut down the time to navigate from an activated folder in the ListView to showing it in the TreeView from 2.4 seconds to about 0.5 seconds. There aren't enough hours in the day!!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Like you I hate Windows Explorer.
For years I have used PowerDesk Standard, freeware and pro versions available, PowerDesk[^]
But is far more fun wrting your own! PowerDesk is worth looking it, even just for some ideas, it has some superb features.
"Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for - in order to get to the job you need to pay for the clothes and the car, and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Directory Opus does even more. I wrote an introduction to it here which covers many of the features:
http://www.pretentiousname.com/opus/
Official site is www.dopus.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It looks impressive.
But PowerDesk has one main advantage, it is free, and the free version does what I want.
"Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for - in order to get to the job you need to pay for the clothes and the car, and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Well i think i was in search for this type of explorer a long ago but just realized n of course installed it too n directory Opus is quite good than the other explorers.
Thanks mate. u made my day.
MAP Tiger Tiger Softwares
Software Designer and Developer VB.NET, ASP.NET, VFP
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello Ted I do use Powerdesk Pro and it is much better (for me) than Explorer. I do find it a bit resource hungry and it seems to freeze now and then. As you say, much more fun rolling your own 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
I really like it! A few questions: 1. Why do you disable the "Map Network drives" when in Single Pane mode? (I suspect I will operate in S.P. most of the time) 2. Is there a way to change the TreeView (in panel 1) highlite to a darker color when a directory in panel 2 is selected? I know that's the way Explorer works, but I have a hard time seeing it. 3. Have you considered saving the last used settings dynamically? (So they don't have to be reset when running the program again).
Thanks, Don
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Don, thanks for your comments  1: I set the tools menu to disable in single pane mode before I added the network drive options. I will change that in the next version, thanks for finding it, shows the power of external testing! 2: The default for a TV when it doesn't have focus is not to highlight the selected node at all, which is a pain. I guess it could be given a different colour in the LostFocus event. Not sure how that would work though as there is no other indication of which pane has the focus - perhaps there should be? 3: The settings could be saved. I work in Administrator mode so can write a file anywhere. For sensible people who work as non-administrators it would either have to go in the registry or in an ini/xml file in their 'My Documents' folder. I'll have look at that. What would you save? The history, last folders visited, layout - or all of it? Regards Jeff
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|