Environment: Windows NT 4.0 SP5, VC 6 SP3
This is the second in a series of (probably four) articles on context menu extensions.
Despite the GUI orientation of Windows programs, it is sometimes necessary to pass command line parameters to a program. The most prominent example of this in my experience has been ATL services: in order to register the COM objects within, one had to run the executable with the command line parameter "/regserver" or "/service". Up until now, there were only a few rather cumbersome methods to accomplish this task.
- Command Prompt: Open up a command prompt, go to the directory where the executable lives, then type in the executable with all the parameters needed. This was made a bit easier by the "Command Prompt Here" PowerToy, but is still a hassle.
- Run Dialog: Using the Run Dialog from the start menu will work, but either the executable has to be in the path, or you have to provide a full path.
- Shortcuts: Create a shortcut to the executable and specify the command line parameters within the property dialog of the shortcut.
- Batch Files: Write an old-fashioned batch file to get the job done.
As I have mentioned in my previous article and some of the comments posted on it, I am extremely lazy when it comes to repetitive tasks. I don't want to do something that takes three clicks if I can get it done in one. With this in mind, I created this context menu extension that, with a couple mouse clicks and minimal typing, accomplishes the same thing as the above methods.
By simply selecting "Run with Parameters" from the context menu, you are presented with a snappy dialog that allows you to specify the command-line parameters. The extension features auto-completion (a la Netscape and MSIE), a drop-down history list, and just for nostalgia's sake, a blinking DOS prompt.
The code is fairly well documented, so I'm not going to go into much detail here, but I will give an overview. The IContextMenu/IShellExtInit part of the code is pretty boilerplate, it simply adds the menu item, provides help text, and responds when the user selects the item. The code for the dialog is a bit more complicated, mainly due to the mechanism that saves the history list to the registry. This method was inspired by seeing the way various Norton programs store history lists, so I guess I don't get points for originality.
The commands are stored in the registry like so:
As the name implies, the strings will appear in the drop-down combobox in the order specified by the "Order" key. In this example, /regserver followed by -install followed by /service, etc. When the user types a parameter not in the list, the value is saved to the next available key (in this case "f") and its name prefixed on to the order string (e.g. "fadbce"). If the history list is full, the last item in the order string (here, "e") is appropriated and moved to the beginning of the queue. In the above example, the key "e" would receive the new parameter value and the "Order" key would become "eadbc". When the user selects one of the items already in the list, the key name is simply moved to the head of the order string. So, if the user selects "/unregserver", the order string would become "cadbe".
The autocomplete feature is fairly straightforward. In response to the CBN_EDITCHANGE message from the combobox, the program checks to see if the entered string is a prefix to any of the strings in the list portion. If so, the remainder of the match is appended and masked off with a selection. The special cases occur when the user is backspacing, deleting, or typing in the middle of the string. By subclassing the window procedure of the combobox's edit control, I intercept any WM_CHAR or WM_KEYDOWN messages, checking to see if the user has pressed the backspace or delete key. If so, autocompletion is disabled until the next keystroke. The (dwStartSel == nTextLen) check in the CBN_EDITCHANGE handler makes sure that tue user is not typing in the middle of the string.
As this is a pure ATL project, none of the convenient MFC wrapper classes are available (CComboBox, CStatic), so all communication with these controls is accomplished with low-level SendMessage calls. It's not all that bad once you get used to it.
Build Versions and RegisteringThere are several build configurations you need to consider in the project:
- bin\ReleaseUMinDependency\ - Unicode
- bin\DebugU\ - Unicode
- bin\ReleaseUMinSize\ - Unicode
To register the file, simply select the appropriate version of the DLL (remember that Unicode builds will not work correctly on Win95/98), copy it to an appropriate location (Windows System Directory recommended), and run "RegSvr32 CmdLineExt.dll" from the command line. The item "Run with Parameters" will now appear when you right-click on executables!