![]() |
Desktop Development »
Files and Folders »
Utilities
Intermediate
License: The Code Project Open License (CPOL)
Windows Explorer in XP: Now with Checkboxes and FullrowselectBy The EveratorCustomizing XP with Vista features |
C#, .NET, WinXP, Win32, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
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:
Fullrowselect: you can't get the selection color to encompass all columns in the file list. Which would have been helpful if your selection criteria depends on, for instance, the file date.
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.
Then:
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.
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 TrpBase.
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
{
MaintainStyle, // maintain wanted visibility of fullrowselect and
// checkboxes (timer)
HitCheckedRows, // perform action based on checked items
HitSelectedRows // perform action based on selected items
}//enAction
public enum enChangeState
{
TrueMirror, // set "mirror" to true if hit
FalseMirror, // set "mirror" to false if hit
InverseSelf, // toggle self from true to false or vice versa
ClearSelf, // set self to false
Dummy // used by enAction.MaintainStyle (none above applies)
}//enChangeState
The 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.
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 ) //one at a time....
{
m_bBusy = true;
if (nAction != enAction.MaintainStyle)
{
m_hMainForm.Enabled = false;
Application.DoEvents();
}
fnActionWinClass ( "CabinetWClass", nAction, nChangeState );
fnActionWinClass ( "ExploreWClass", nAction, nChangeState );
if (nAction != enAction.MaintainStyle)
{
m_hMainForm.Enabled = true;
Application.DoEvents();
}
m_bBusy = false;
}//!Busy
}
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.
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 )
{//winclass found
while ( ( hShell = FindWindowEx ( hMain, hShell,
"SHELLDLL_DefView", null ) ) > 0 )
{//shell found
// if listview is not found directly under the shell,
// look three levels down
bool bListFound = false;
while ( ( hList = FindWindowEx ( hShell, hList,
"SysListView32", null ) ) > 0 )
{
bListFound = true;
fnStyleOrAction(hList,nAction,nChangeState);
}//Syslistview32 found under shell
if (!bListFound)
{//check next three levels
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)
{
fnStyleOrAction(hList, nAction,
nChangeState);
}//listview found on third level
}//check third level
}//check second level
}//check first level
}//check next three levels
}//shell found
}//winclass found
}//fnActionWinClass
The actual programming may be rather pedestrian, but finding the information needed was an interesting exercise in software forensics.
CabinetWClass, ExploreWClass, SHELLDLL_DefView, DUIViewWndClassName, DirectUIHWND, CtrlNotifySink and SysListView32 (a ListView subclass). Where Google couldn't help me, the Microsoft utility Spy++ could. 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
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 8 Jan 2009 Editor: Sean Ewington |
Copyright 2009 by The Everator Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |