Windows Explorer is a great little program. Millions use it, few have any complaints. But unless you've moved to Vista, there are things you can't do in Windows Explorer:
With TrayProdder, these two features are no longer missing.
The ListView control of the Win32 API is heavily used in any number of run-of-the-mill Windows applications. It is of course also used in Windows Explorer. And CheckBoxes and FullRowSelect have been ListView properties since time immemorial, as far as I know. So it irked me that none of them can be changed in the settings for Windows Explorer (pre-Vista, that is). I scoured the web for some arcane registry key, but nooo....
What to do? Well, roll your own, of course!
Normally you will have TrayProdder running in the system tray (i.e the form above will be invisible). To show the form, just double-click the TP icon in the tray.
- check none, any or both of the two checkboxes Checkboxes and Full row select. This will prod any running instances of Windows Explorer to attain the desired features.
- click any of the eight buttons to make full use of both checkboxes and selection status. This will speed file selection to no end.
You can also click the ? button to show some overall information and - more importantly - command line options.
Please note: TrayProdder does not change the Windows Explorer executable or installation in any way, shape or form.
When you quit TrayProdder, everything resorts back to its original state. Nothing is permanently changed. You may well ask "how is it then even possible to make Explorer get up on its hind legs and do tricks like a circus pony?" The answer: TrayProdder does it's magic by lobbing messages over the process boundry to Explorer, right at the ListView controls in it. In the absence of hooks (technically "better" but way more invasive), a 5-times-a-second timer keeps Explorer reasonably synched to options chosen in TrayProdder.
Points of Interest
Using enums to Pass Task Information
The main form (class
TrpMain) is the controller for all the action of TrayProdder. Here we have a timer object/event that keeps checkboxes and fullrowselects active as new Explorer instances appear, and the event handlers for the eight button actions possible.
However, for the sake of modularization, the main form is kept clean of any actual low-level interaction with Explorer. That stuff is contained in an "engine" class named
So, we now need a way for
TrpMain to tell
TrpBase what to do. What better way than to define a couple of enums:
public enum enAction
public enum enChangeState
enAction enum defines the major task to be performed (at timer tick or button press). The
enChangeState is in effect an argument to
enAction, giving one of four possible things to do once you have hit on either a checked row or a selected row. The "mirror" moniker is just an awkward way of saying that if we hit a SELECTED row, we want to do something with it's CHECKED status. And vice versa. In effect, the two properties mirror each other.
The timer task (
MaintainSyle) does not need any supplemental argument but is given one (
Dummy), just for the sake of symmetry.
The Innards of the Engine
Now that we've defined an enum interface between the GUI (
trpMain) and the engine (
trpBase), we need a public method in
trpBase that can be called by
trpMain, using the enums above as arguments.
public void fnActionTop ( enAction nAction, enChangeState nChangeState )
if ( !m_bBusy )
m_bBusy = true;
if (nAction != enAction.MaintainStyle)
m_hMainForm.Enabled = false;
fnActionWinClass ( "CabinetWClass", nAction, nChangeState );
fnActionWinClass ( "ExploreWClass", nAction, nChangeState );
if (nAction != enAction.MaintainStyle)
m_hMainForm.Enabled = true;
m_bBusy = false;
Here we have a busy flag to ensure that the last action was completely taken care of, before any new action is possible. Since actions (except
MaintainStyle) may be time-consuming (say in lists of 4000 rows or more), we disable the main form until tbe action has ended. The duo "
CabinetWClass" and "
ExploreWClass" stems from the fact that any one of these can exist as a top level container in an instance of Explorer, depending on the way it's been invoked.
Finding ListView in a Nest of Containers
Here is what may be the hairiest piece of the TrayProdder source. It's called by
fnActionTop (above) to find the ListView lurking somewhere in the container structure of the specified top window class, and then taking the indicated action.
private void fnActionWinClass ( string sWinClass, enAction nAction,
enChangeState nChangeState )
int hMain = 0; int hShell = 0; int hList = 0;
int hLevel1 = 0; int hLevel2 = 0; int hLevel3 = 0;
while ( ( hMain = FindWindowEx ( 0, hMain, sWinClass, null ) ) > 0 )
while ( ( hShell = FindWindowEx ( hMain, hShell,
"SHELLDLL_DefView", null ) ) > 0 )
bool bListFound = false;
while ( ( hList = FindWindowEx ( hShell, hList,
"SysListView32", null ) ) > 0 )
bListFound = true;
hList = 0;
while ((hLevel1 = FindWindowEx(hShell, hLevel1,
"DUIViewWndClassName", null)) > 0)
while ((hLevel2 = FindWindowEx(hLevel1, hLevel2,
"DirectUIHWND", null)) > 0)
while ((hLevel3 = FindWindowEx(hLevel2,
hLevel3, "CtrlNotifySink", null)) > 0)
while ((hList = FindWindowEx(hLevel3,
hList, "SysListView32", null)) > 0)
The Real Challenge: Gathering Information
The actual programming may be rather pedestrian, but finding the information needed was an interesting exercise in software forensics.
- Google helped me figure out names of various Explorer container objects:
SysListView32 (a ListView subclass). Where Google couldn't help me, the Microsoft utility Spy++ could.
- Much of the message definitions came from ancient Microsoft C header files, such as COMMCTRL.H and WINUSER.H. A .NET developer is normally discouraged from mucking about too much with low-level stuff (for sound architectural reasons) so these may well be missing from his IDE. However, if you google any one of them, you'll easily find them on the web. Example: COMMCTRL.H
- Important insights, as well as core parts of the code (though somewhat modified), came from this page: Crossing the process boundry with .NET
Other parts of Windows could conceivably be customized in a similar, non-intrusive fashion. Any takers?
All source code for the project is contained in the zip file above. A ready-to-use executable can be found here: TrayProdder Home Page