Introduction
This article will present a Windows shell extension designed to change file extensions in a flexible and easy way. Using this extension the user can manage filenames and extensions in a separate manner.
By default, Explorer hides file extensions from the user, which is OK until there comes a need to change a file's extension. In Windows OS, a file extension determines the file type and the application which opens the selected file, but sometimes we find a file with an extensions that does not match the actual file content. One of the most common examples are text files made in UNIX-like operating systems. UNIX-like systems usually use Line feed character (0xAh) as a new line delimiter, as opposed to Windows's Carriage Return+Line feed character pair (0xDh 0xAh). Viewed in Windows's Notepad, UNIX-made *.txt files usually appear as a blob of text without proper line endings. For huge files, this makes text difficult to read, and makes it almost impossible to correct all line endings by hand. A quick fix is to open it in Wordpad, or to rename file extension from *.txt to *.rtf. Personally, I use the second option. Another example is well-known to Manga fans: the famous *.cbz files which are simply zipped images with an archive's extension changed from *.zip to *.cbz. The bottom line is, it is not convenient to change extensions for many files by hand.
The idea for this code also originated from the way filenames are handled in Windows XP. In Windows XP, when a file is selected for renaming, assuming that extensions are not hidden, both filename and extension parts are selected, and a user must highlight only the extension part to change it. And, it only works for a single file. In Vista, when both parts are visible, by default the name part is highlighted.
The Code
One of the articles that sparked an inspiration for this code was Shell Renamer, and the code core was taken from the article How to Use Submenus in a Context Menu Shell Extension, so it is recommended to read it first, as this article is built on top of it.
This code is compiled using Visual C++ 2005 Express edition, Platform SDK 2003 R2, WTL 8.0 and ResEdit, so anybody should be able to build the project.
Since this is a shell extension, the code uses a simple exception handling to prevent any undesired events that would crash the Windows Explorer. The renaming is done through the Win32 SHFileOperation
function, and files are operated one at a time, so that Explorer can provide an "Undo" step for each an every of the processed files. To enable the "Undo" action in Explorer, the fFlags
member is set to FOF_ALLOWUNDO. To format SHFILEOPSTRUCT
properly, an extra terminating null '\0' must to be added to the filename buffer's end.
SHFILEOPSTRUCT lpFileOp;
memset(&lpFileOp,0,sizeof(lpFileOp));
lpFileOp.hwnd=NULL;
lpFileOp.fFlags=FOF_ALLOWUNDO;
lpFileOp.wFunc=FO_RENAME;
fname+='\0';
lpFileOp.pFrom=fname;
toname=splitter.drive+splitter.dir+splitter.filename+_T(".")+newext;
lpFileOp.pTo=toname;
if (0!=SHFileOperation(&lpFileOp)) {return false;}
As a consequence of using SHFileOperation
, an attempt to change the extension of a shortcut results in target path resolving, and the rename operation is made on the target. Another strange thing in that case is that dialog is not modal in respect to the Explorer owner window.
By default, the file extension of the first right-clicked file is selected as a new extension. Extensions are displayed in the shell menu entry in the uppercase, however, the actual string case is left for the user to decide, since there are some programs where the user can choose between an upper and lowercase extension when saving files (eg. mp3 and MP3).
New extensions are checked for invalid characters, and default Windows Explorer behaviour is simulated:
If you don't see any balloon tip, look under registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced and set the DWORD value EnableBalloonTips
to 1 to enable system-wide balloon tips.
The position of menu entry in the shell context menu depends solely on the alphabetic order of string value in the *.rgs file. For this shell extension, a project's CLSID (A5096FA1-32DC-4392-A829-445558F0F4B5) was used to position the menu entry somewhere in the middle of the shell context menu:
If the string value on the right side was, for example, AAAAAAAAAA_go_to_the_top__
, the menu entry would be positioned at the top of the shell context menu:
NoRemove *
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
{A5096FA1-32DC-4392-A829-445558F0F4B5} = s '{AAAAAAAAAA_go_to_the_top__}'
}
}
}
You also need to match the CLSID-entry in the *.rgs file:
NoRemove CLSID
{
ForceRemove { AAAAAAAAAA_go_to_the_top__} = s 'ChangeExtMenuExt Class'
{
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
}
}
GUI Layout and XP Style Awareness
The menu entry has an easy-to-spot menu bitmap inserted, to provide a quick visual landmark.
Another important issue with this shell extension, since it is dialog-based, is enabling the WinXP theme for visual consistency. In order to have a dialog which has the XP theme enabled, it was necessary to set the following values in stdafx.h before any of the #includes
:
#define VC_EXTRALEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#endif
#define _ATL_APARTMENT_THREADED
#define ISOLATION_AWARE_ENABLED 1
These snapshots demonstrate the difference in appearance:
Theme-aware: |
Not theme-aware: |
|
|
The XP theme awareness topic is further discussed in articles The Complete Idiot's Guide to Writing Shell Extensions - Part II, Applying Windows XP Visual Styles to Applications and Using Windows XP Visual Styles on MSDN.
To provide a user with some nice and interactive GUI, instead of a "Help" button, I used the WTL CBitmapHyperLink class.
BEWARE! — if you don't put any HTML help file (*.chm) in the debug version DLL's directory (where hlppath
variable points to), you will get a nasty Explorer crash in one of the CBitmapHyperlink
's ASSERTs. In the release version this doesn't happen.
Instead of an "About" button, I decided to put a nice clickable icon. I leave it as a reader's excercise to implement a more fancy owner-drawn button.
Recommended Reading
The Complete Idiot's Guide to Writing Shell Extensions by Michael Dunn.
New Graphical Interface: Enhance Your Programs with New Windows XP Shell Features by Dino Esposito (MSDN, URL may change).
Bugs and Issues
Please report any issues and bugs you find in this article's message board.