WINDOWS SHELL
FOR MICROSOFT WINDOWS 3.0
VERSION 2.02




by




Greg McCain

June 5, 1992











Advisor: Charles Dana
Computer Science Department
School of Engineering
California Polytechnic State University
199


TABLE OF CONTENTS

ABSTRACT	iii
LIST OF FIGURES	iv
0. INTRODUCTION	1
I. FEATURES OF WINDOWS SHELL	2
I.A. THE COMMAND LINE	2
I.B. ALIASES	3
I.C. ENVIRONMENT VARIABLES	3
I.D. ACTION BAR	4
I.E. FILE LIST WINDOW	5
I.F. EXTERNAL COMMANDS	6
I.G. SHELL COMMANDS	8
II. DESIGN OF WINDOWS SHELL	9
II.A. GRAPHICAL OBJECTS OF THE WINDOWS SHELL	9
II.A.1 The WSTDIO Window	10
II.A.1.a Pertinent Data	10
II.A.1.b Painting The Display	12
II.A.1.c Obtaining Standard I/O Input	12
II.A.1.d Marking Text With The Mouse	14
II.A.1.e Command History	14
II.A.1.f Wstdio Message Directory	15
II.A.2 The ACTNBAR Window	16
II.A.3 The WINSHELL Window	17
II.B LOGICAL MODULES FOR COMMAND INTERPRETATION	17
II.B.1 The Command Prompt Path	18
II.B.2 The Action Button Command Path	19
II.B.3 The ALIAS.C Module	20
II.B.4 The INTERP.C Module	21
III. DEVELOPMENT PROCESS	22
APPENDIX A. THE EXTERNAL COMMANDS DLL INTERFACE	25
APPENDIX B. FUTURE ENHANCEMENTS	27


ABSTRACT

This document discusses the purpose, features, and design of a command line 
shell for Microsoft Windows 3.0/3.1, the Windows Shell.  The Windows Shell allows 
users to launch both DOS and Windows programs from a command line environment, 
as well as perform disk maintenance operations such as copy, deleting, and moving 
files.
The Windows Shell introduces several new features to the typical command shell 
environment, including interactive editing of Aliases and Environment variables,  an 
"Action Bar" to quickly execute a command, the ability to set "permanent" options in 
shell commands, and customizable fonts and screen colors.
The Windows Shell is designed according to an object oriented paradigm.  It is 
comprised of three major graphical objects, which includes the main WINSHELL 
window, the WSTDIO window, and the ACTNBAR window.  The task of interpreting and 
executing commands is done by the INTERP (or interpreter) module. 
A key design element of WINSHELL is the WSTDIO window, which provides a 
functional interface much like the normal C standard I/O functions for DOS and UNIX.  
Clients using this window need not implement their own task message loop; the 
WSTDIO window will handle messages transparently when it is invoked.  This frees 
the client from having to deal directly with Windows messages, allowing it to focus 
on the task at hand. 


LIST OF FIGURES

FIGURE 

1-1 The Command Line	2
1-2 The Alias Editor	3
1-3 The Environment Editor	4
1-4 Action Button Configuration	5
1-5 File List Window	5
1-6 Internal Commands	6
2-1 Graphical Object Design	9
2-2 Command Interpretation Paths	18


0. INTRODUCTION
The Windows 3.0 environment provides a graphical user interface for executing programs 
and file management.  While this is great for naive users, the graphical interface can be 
cumbersome to experienced users.  The Windows Shell is intended for experienced users, 
providing quick manipulation of files and directories, as well as executing Windows and DOS 
programs.  
The Windows Shell was developed on a IBM PS/2 model 70, running at 16 MHz and using a 
VGA display.  The shell has also been succesfully run on systems running Windows in SVGA 
and EGA mode.
This document is divided into three main sections.  The first presents the Windows Shell as 
seen by the user.  It discusses the feature of Windows Shell, how to access them, and what they 
can do for a user.  The second section presents the Windows Shell as seen by the programmer.  
This includes a discussion of the graphical objects seen in the Window Shell, as well as a 
discussion of how the command interpretation works.  The last section discusses the 
development process of the Windows Shell.  It describes the problems encountered in both 
design and implementation of the Windows Shell, and any other noteworthy considerations that 
were involved in the development process.
The document also provides the specifications of the DLL External Commands interface in 
Appendix A.  The interface is a major consideration when developing external commands for use 
with the Windows Shell.
I. FEATURES OF WINDOWS SHELL


I.A. THE COMMAND LINE
 
figure 1-1
The Windows Shell provides a command line interface to the windows environment.  The 
command line is similar in appearance to a DOS shell, with the following additions:
- The Windows Shell prompt allows for text marking, cutting, and pasting.
- The Windows Shell offers the "Action Bar" seen on the left side of the shell (see figure 
1-1.)
- The Windows Shell allows the user to configure the color and font used by each 
instance of the shell.
- The Windows Shell recognizes the '&' character to run a windows program minimized.
- The Windows Shell expands partial file names entered on the command line into the 
entire file name by pressing the TAB key.  If more than one file matches the partial 
name, the user will be given a choice of files.

I.B. ALIASES
Windows Shell allows the user to define aliases.  Aliases allow long or complex commands 
to be abbreviated for quick access.   The Alias Editor  (see figure 1-2 below) is provided for quick 
viewing and editing of aliases.

 
figure 1-2

I.C. ENVIRONMENT VARIABLES

Windows Shell provides the Environment Editor (see figure 1-3 below) for quick viewing and 
editing of environment variables.  Windows 3.0 provides environment variables similar to that 
of DOS and UNIX.  Unfortunately, the environment variables in the Windows Shell are not 
inherited by the programs it executes.  Each new task gets a copy of the environment that was 
recorded when windows was started.  However,  modifying the local environment variables in a 
given application can and will effect the application if it uses them the variables.  In the 
Windows Shell, it is sometimes useful to change the path or prompt environment variables.  
Hopefully future versions of Windows will provide inherited environment variables.

 
figure 1-3

I.D. ACTION BAR
The action bar is a column of eight buttons along the left side of the shell (see figure 1-1)  It 
allows users to execute a predefined command at the press of a button.  The following window 
is used to configure the action bar:

 
figure 1-4
The Button Configuration Window allows the users to define the text seen on the buttons and 
the command that is carries out.  The user can access text marked on the Windows Shell using 
the '=' character.  The '=' character is replaced by a string containing the marked text when the 
command is executed.  This makes it easy for a user to mark a block of text and perform actions 
upon it, such as deleting or editing files.  For example, to have a button which will delete any 
marked files, use the string:
del =
in a "button command" box, as seen in figure 1-4.

I.E. FILE LIST WINDOW

 
figure 1-5
The File List window lists the files in the current directory.  It can be activated using the 
View-File_List menu command, or by pressing Cntrl+F.  The File List allows you to select 
multiple files in the current directory, and to either move, copy, or delete the highlighted files.  It 
allows you to copy the names of the selected files to the command line.  This can be very useful 
when you want to perform a command only on certain files in a directory, but don't know their 
names or you don't want to type them in.  Future version of the Windows Shell might include the 
option to sort the files in the File List Window by size, date, or extension.

I.F. EXTERNAL COMMANDS
Most shells provide shell commands which are built into the shell itself.  The Windows Shell 
provides only the most basic shell commands, including: change directory (cd), make directory 
(md), and remove directory (rd).  The rest of the usual shell commands are implemented as 
"external commands".
Each external command is a Windows 3.0 Dynamic Link Library (DLL).  The Windows Shell 
uses a Windows 3.0 DLL loading function to load and run external commands.  Each external 
command must provide a set of functions to execute the command, show an about box, and 
show an options box.
The windows shell provides the "external commands window" to view and configure external 
commands (see figure 1-6).

 
figure 1-6

The options box allows the user to set "permanent" options on a command that will be invoked 
each time the command is run.  The about box allows the user to view a window which should 
contain useful information on what the command does and how to use it.
"External commands" are implemented as DLL's to allow new commands to be written without 
modification to the shell.  The format of a DLL is such that a normal DOS shell program can 
easily be ported to run under the shell.

I.G. SHELL COMMANDS
The user accessible commands contained in Winshell, or Shell Commands, are as follows:
cd <dirname> 	: Changes current directory to directory specified in dirname.
md <dirname> 	: Creates a directory as specified in dirname.
rd <dirname> 	: Deletes a directory as specified in dirname.
<DRIVE> :	: Changes current disk specified to drive specified in DRIVE.
ps	: Lists currently running processes.
min <task_name>: Minimizes program with caption matching task_name.
max <task_name>: Maximizes program with caption matching task_name.
kill <task_name>: Closes program with caption matching task_name.
exit	: Exits current Windows Shell.
exitwin	: Exits Windows.



II. DESIGN OF WINDOWS SHELL
The design of Windows Shell has been broken down into the many separate modules, both 
graphical and logical.  To simplify the explanation of the design, this section is divided into two 
main parts.  The first part will discuss the graphical objects of the Windows Shell.  This includes 
how the individual windows and buttons are designed, how they function, and they the 
communicate with one another.  The second part of this section will discuss the modules used 
in command interpretation.  This section will involve a detailed trace of the flow of control for the 
interpretation of a command.

II.A. GRAPHICAL OBJECTS OF THE WINDOWS SHELL
The windows shell has been divided into three main graphical objects, as seen in figure 2-1.  
Each of the objects is implemented in a separate C source file, and communicate with each 
other via Windows messages.  Although the "Main" window as seen in figure 2-1 is at the top of 
the hierarchy, controlling the other two windows, this explanation will be more clear of it starts 
from the bottom.

 
figure 2-1

II.A.1 The WSTDIO Window
By far the most important window in the shell is the WStdio window.  It is responsible for 
supplying the primitives such as reading and writing characters to a standard I/O type device.  
To do this in a windowing environment, is requires creating a "virtual" standard I/O display.  
This display is represented by a data structure, who's main element is an array of characters 
which represent the characters displayed on the screen.  When characters are written to the 
WStdio window, they a first copied into this character array, and then are actually displayed on 
the screen.
II.A.1.a Pertinent Data
To better understand the implementation of the WStdio window, let's look at the elements of 
the Display data structure as defined by the WStdio window.  The first feature is the array of 
characters representing the display (This is referred to as the "LineBuf".)  Second, are a set of 
elements used to track the state of the display:

int  iTopLine;			// Index of the current top line in the LineBuf
int  iBottomLine;			// Index of the current bottom line in the
					// LineBuf
int  TotalLineCount;		// the current number of line in the LineBuf
int  CurCharOffset;		// offset into LineBuff of current position

These first four elements are what control current state of LineBuff itself.  LineBuff is an array of 
characters which is logically divided into fixed length lines.  The actual number of lines 
available in LineBuff is a constant at compile time, but is typically much larger than the number 
of lines that will currently fit in the window on screen.  (This surpluss of lines in memory is used 
as a scrollback buffer, as will be discussed later.)  The indices to the top and bottom lines are 
used because LineBuff is a circular buffer.  These indices always point to the portion of the 
LineBuff that is currently displayed on the screen.  The TotalLineCount variable is the absolute 
number of lines in LineBuff.  CurCharOffset is the absolute position in LineBuff at which the next 
character to be displayed will be written.
The next set of elements is used when actually outputting lines to the screen.  Their uses 
and intentions are explained in the comments.

int  nLinesOnScreen;      	// the number of lines fitting on the window
					// in it's current size
int  nCurLineOnScreen;		// the current line the cursor is on in window
                       			// starting from 1 (NOT 0!)
int  yChar,               		// height in pixels of a line
int  xCaretPos;          		// distance (in pixels) from the left hand
                       			// side of the screen that the caret is at
When the user activates the scrollback feature by using the vertical scrollbar or the PAGE 
UP/PAGE DOWN keys, these variables are initialized and used to track the positioning of the 
scrollback:
 
BOOL 	isScrolling;		// True is window is in a scrolling back state
int  	TopScrollLineNum,	// index of the top line in the LineBuff  
					// during a scrollback
Another noteworthy element in the Display data structure is used to expedite the actual 
outputting of lines on the screen.

int  nUnpurgedLines,      		// # of line waiting to be written to
						// the screen
The WStdio window does not display a line of text immediately when it is received.  If 
possible, the window will wait until a predefined constant number of lines come in before it 
actually displays the lines.  This can dramatically increase the rate at which lines are displayed 
on the screen.  The nUnpurgedLines variable counts the number of lines waiting to be 
displayed.  In the current implementation (vers 1.3), this can lead to lines of text not being 
displayed while the task performs some lengthy operation.  This should be corrected in later 
versions by having a timer periodically purged any unpurged lines.
Finally, there are elements used to track how the user has highlighted any text in the WStdio 
window:

WORD wSelectState;
RECT rectInversion;
The wSelectState variable can be in three states: one indicating there is no highlighted 
rectangle, when all bits are turned off.  The second, SS_SELECTING,  indicates the user is 
currently marking a rectangle. The third, SS_RECTSELECTED, indicates that a rectangle is 
currently highlighted.  When in third state, the rectInversion variable will hold the coordinates of 
the highlighted rectangle.
II.A.1.b Painting The Display
Windows dictates that all screen I/O should be done in response to a WM_PAINT message. This 
message informs a window that it needs to repaint a portion of it's client area, and supplies the 
window with the coordinates of a rectangle it needs to repaint.  Thus upon receiving this 
message, the WStdio window calculates what lines need to be painted, and paints them.  When 
a client module requests the WStdio window to display a line (via the DM_PUTS message), the 
WStdio window only has to copy the line into it's internal Linebuff, and then invalidate the 
portion of the window that will be effected by the new line.  By invalidating a portion of the 
window, Windows will generate a WM_PAINT message, and the proper area of the window will 
be repainted, reflecting the new line to be displayed.  This scheme mandates that all screen I/O 
be done in response to the WM_PAINT message, which keeps all screen I/O consistent and in a 
fixed area in the program.
II.A.1.c Obtaining Standard I/O Input
Perhaps the most interesting feature in the implementation of the WStdio window is how it 
obtains input from the user.  To provide a function like getstr(), which does not return a value 
until the user presses the ENTER key, the Windows message loop had to be placed inside the 
getstr() function.  This allows other processes to run and respond to their own inputs while the 
WStdio window is waiting for input.
When a client module sends a DM_GETS message to get a string from the WStdio window, 
the WStdio window calls it's own DisplayGetStr() function.  This function first positions the caret 
at the appropriate position, and then falls into a message loop.  Inside this message loop, the 
function monitors the incoming messages looking for the ENTER key to be pressed, in which 
case it will fall out of the loop and return the text that was entered.  The function also monitors 
the incoming messages for keys like the arrow keys, in which case it will invoke the command 
history, and for WM_CLOSE message.  If a WM_CLOSE message comes in, the DisplayGetStr 
function exits the message loop and returns a value indicating that the function failed.
With this method of implementing the message loop in the input function, the client modules 
are simplified since they need not implement a separate message loop.  The main module of 
the Windows Shell, WINSHELL.C, in fact does not use a message loop.  Instead, it falls into a 
loop that might be expected out of a UNIX type command, in which it displays a command 
prompt, gets an input string, interprets it, and executes the appropriate action.  It does not use a 
message loop at all, like most other Windows WinMain functions have to do.
In order to obtain input from the user, the WStdio window uses a Windows edit control.  
When the user sees a prompt at which he or she can type, that prompt is actually inside a 
separate edit control, and not in the WStdio window itself.  The edit control is always positioned 
at the end of the last character entered, much as a caret would be.  This way, however, leaves 
much of the work of obtaining key-presses and displaying characters to the edit control.  It also 
helps provide the standard controls a user might expect from an input prompt,  such as marking 
text and replacing text.  The user will see an interface consistent with other programs which use 
edit controls. If future versions of Windows change the behavior of these controls, the Windows 
Shell will adapt automatically.
II.A.1.d Marking Text With The Mouse
The job of marking text on the display is quite simple.  The WStdio window responds to a 
WM_LBUTTONDOWN message (indicating the left mouse button is being pressed,) by obtaining 
a mouse capture.  This forces Windows to send all subsequent mouse messages to the window 
obtaining the capture.  While in this state, the WStdio window then responds to all 
WM_MOUSEMOVE messages by inverting a rectangle between the position where the mouse 
was originally pressed and the current position.  When the left mouse button is released, the 
capture is also released, and the rectangle is left highlighted.
The portion of highlighted text can now be accessed by both the WStdio window itself, and 
by client windows via the DM_GETMARKEDTEXT message, which is supplied by the wstdio.c 
module.  The function GetMarkedText(), in the wstdio.c module,  is called in response to this 
message.  It is responsible for determining what characters are actually marked and copying 
them to a buffer.  This is no simple task when proportionally spaced fonts are in use.  The 
function must navigate LineBuff and determine the actual length in pixels of each character in 
the buffer.  It then compares this to coordinates that are marked in the screen, and can 
determine what characters are actually marked.
II.A.1.e Command History
The WStdio is also responsible for providing a command history.  Whenever the user enters 
a command at the command prompt, the WStdio window records the command entered with the 
CommandHistory() function.  This function manages a simple queue of a constant size.  When a 
user enters a command, it is added at the end of the queue, and the first item in the queue is 
discarded if there are more than the constant limit of items in the queue.  When the user 
presses the up and down arrow keys, the WStdio window responds by displaying items from 
this queue on the command line.
II.A.1.f Wstdio Message Directory
The following is a list of messages that the WStdio window provides for client modules.  The 
messages are defined and processed explicity by the WStdio window. The client can invoke 
these by using the Windows SendMessage() function to send the desired message.

DM_PUTS	
Writes a string to the display.

DM_GETS  	
Gets a string from the display.

DM_CLEAR 	
Clears the Wstdio window.


DM_SETFONT	
Sets the font the Wstdio window will use.

DM_GETNUMCOLUMNS 
Returns the approximate number of columns on the display. A column is space 
enough for about 12 of the widest characters in the current font, and a trailing tab.  
This feature essentially indicates the number of file names that can be displayed 
on one line.

DM_GETMARKEDTEXT 
Returns a global handle to memory block containing marked text.  This memory 
must be freed by the user.

DM_SETMORE 
Turns the more feature on and off.    When this feature is turned on, the WStdio 
will automatically display a ----more---- at the bottom of the screen after the last 
number of lines displayed has filled up the screen.  The more feature is 
automatically turned off when after DM_GETS message is sent.

II.A.2 The ACTNBAR Window
The actnbar window provides the column of user-configurable push buttons along the left 
hand side of the Windows Shell.  Each push button provides a shortcut way for the user to 
execute a command.  The ACTNBAR window is actually a rectangular window surrounding the 
set of push buttons.  Associated with each push button is a caption and a command.  The 
caption is the text that is displayed in the button on the screen;  the command is the command 
string which will be invoked when the button is pressed.
When the ACTNBAR window is created, it creates it's push button children and initializes 
them to defaults saved in the WINSHELL.INI configuration file.  It's job thereafter is to report to 
it's parent window whenever one of it's buttons has been pushed, passing the parent window 
the command string to be executed.  
This is accomplished using the standard Windows WM_COMMAND message.  This 
message is sent to the ACTNBAR window whenever one of it's children push buttons is pressed.  
The ACTNBAR processes this message by first setting it's own caption (the string of text 
appearing in the caption bar of a window, which is not visible in the ACTNBAR window) to the 
command string of the child being pressed.  The ACTNBAR window then relays the same 
WM_COMMAND message to the parent (or client) window.  When the parent receives the 
WM_COMMAND from the ACTNBAR window, it reads caption text of the ACTNBAR window, and 
executes the command string contained therein.
Note that this logical command path is different from that of the other command interpretation 
path.  A command executed in response to the ACTNBAR being pressed is interpreted and 
executed in response to the WM_COMMAND message, and is not obtained via the command 
interpretation loop in the WinMain function.  This is discussed more in section II.B.2.
Also contained inside the ACTNBAR.C module is action button configuration dialog box.  This 
allows users to configure both the caption and command of each action button.

II.A.3 The WINSHELL Window
This window is the main window of the application, and controls the other windows as seen 
in figure 2-1.  The graphical duties of this window are quite simple.  The WINSHELL window 
creates and manages two children windows, the WSTDIO window and the ACTNBAR window.  
Both children are sized so that together they fill up the client area of the WINSHELL window.  
Thus the WINSHELL window reacts to changes in it's own size by repositioning and re-sizing 
the children so they always fill it's client area.
WINSHELL also provides the menu bar as seen at the top of the window.  It must respond to 
menu messages and execute the appropriate functions.  These functions include changing the 
font in the WSTDIO window, changing the colors of the Windows Shell, and popping up the 
various configuration dialog boxes.  These duties mostly involve sending a single message to 
the appropriate window to perform the task.  In this way, the WINSHELL window serves more as 
a message router for it's children than anything else.
If this seems too simple, it's because the graphically oriented tasks are only part of the 
tasks the WINSHELL window must perform.  It's main task, that of command interpretation, is 
discussed in the next section.
II.B LOGICAL MODULES FOR COMMAND INTERPRETATION
This section discusses the modules involved in command interpretation.  Now that the 
relationship of the 3 main windows has been defined, the matter of understanding command 
interpretation will be much easier.  First let's look at the design of the command interpreter, as 
seen in figure 2-2.

 
figure 2-2

The flow of control in figure 2-2 moves left to right.  The diamond shaped modules indicate 
modules which are returning user input.  The circular modules perform some logical operation 
on the input data, and the square boxes will be the end result of the command.
There exist two paths in which a command can be executed by the shell.  The first is by the 
user entering a command at the command prompt.  This is accomplished by looping for user 
input, interpreting it, and executing it.  The second path is invoked via the user pressing an 
Action Button; the command is executed immediately in response to the ACTNBAR's message.
II.B.1 The Command Prompt Path
Command interpretation begins in the WINSHELL.C module.  This module contains the 
WinMain function, which is the entry point of a Windows application.  After performing it's 
initializations and creating it's child windows, the WINSHELL.C module falls into the command 
interpretation loop as follows:
do
{
   DisplayPrompt (hwndDisplay); 

   // exit if display says to
   if (dgets (hwndDisplay, szCmdLine, MAX_COMMAND_LENGTH)== -1)
      break;  

   ExpandAliasString (szCmdLine, MAX_COMMAND_LENGTH);

   iInterp = InterpretCommand (hwndWinShell, hwndDisplay, szCmdLine);
} while (bContinue && iInterp != -1);
The first function in the loop displays the command prompt on the WStdio window.  The next 
job is to obtain a line of text from the user, which is accomplished by the dgets() macro.  Dgets() 
is a macro supplied by the WStdio module which sends the DM_PUTS message to a WStdio 
window.  Note that if dgets() returns -1, it means the user has closed the window, and the loop 
must be exited.  After the user input has been obtained, the input is passed to the 
ExpandAliasString() function defined in the ALIAS.C module, which will expand any aliases found 
in the string.  Finally, the string is passed to the InterpretCommand function in the INTERP.C 
module.  It is in this module that the string is parsed and executed.
Note that commands retrieved from the command line are not given a chance to expand the 
marked text symbol by using the WSTDIO.C module.  The marked text symbol is provided so 
that the symbol in the command string is replaced by the text marked in the WStdio window.  
Although this would be a desirable feature, a minor design flaw stopped me from implementing it 
(see section 3).
II.B.2 The Action Button Command Path
 The ACTNBAR.C module can instigate a command by sending a message to the WINSHELL 
window.  The WINSHELL responds by executing the command using the flow of control as seen 
in figure 2-2.  The following code is executed in response to such a message:
GetWindowText (LOWORD (lParam), szCmdLine, MAX_COMMAND_LENGTH);
ExpandAliasString (szCmdLine, MAX_COMMAND_LENGTH);
ExpandMarkedText  (szCmdLine, MAX_COMMAND_LENGTH);
InterpretCommand  (hwndWinShell, NULL, szCmdLine);
As you can see, the code is very similar to that used in the command interpretation loop in 
the previous section.  The only difference is that commands executed in response to the 
ACTNBAR module get to use the ExapandMarkedText() function, which expands the marked text 
symbol into the text currently marked on the WStdio window.  Also, the command executed in 
response to the ACTNBAR module are passed a WStdio window handle of NULL, prohibiting 
them from outputing any data to the WStdio window.  This is to safeguard the current text in the 
Wstdio window, which might otherwise be overwritten by the command executed by the button. 
II.B.3 The ALIAS.C Module
The ALIAS.C module provides alias expansion for command strings.  It is implemented as a 
Windows DLL, which provides the following advantages.  For all instances of the Windows Shell 
running, they all share a common ALIAS module.  This means that if an alias changed in one 
shell, it is changed for all shells, keeping all aliases consistent.  This methods also expedites 
the loading process of Windows Shell, because the default aliases only have to be read from 
disk once, for the first module.
The implementation of the ALIAS module is quite simple.  It maintains a dynamically 
resizable array of elements.  Each element contains an alias name and an alias value.  The 
module provides a dialog box for adding and deleting aliases, and the ExpandAliasString() 
function, which takes a string and expands any aliases within it.

II.B.4 The INTERP.C Module
The third and perhaps most important module used in command interpretation is the 
INTERP.C module.  This module is responsible for parsing a command line, determining what 
type of command it is, and executing the command accordingly.  There are three types of 
commands among which the module must discriminate.
The first type of command the INTERP module looks for are shell commands.  These are 
commands who's code is kept inside the Window Shell.  This is accomplished by a large switch 
statement that checks if the requested command is amongst those known to be external 
commands.  If INTERP determines that command is a shell command, it merely calls the 
function associated with the shell command.  All shell commands are contained in the 
COMMANDS.C module.  These commands are so trivial they will not be discussed.
The second type of command the INTERP module looks for are external commands.  These 
commands are implemented as Windows DLLs.  The INTERP function searches the default 
directory for files who's names match the specified command name and ending with the .WS 
extension.  If a corresponding external command file is found, the DLL is loaded and control is 
passed to it.  The specifications for an external command are outline in appendix A.
The third type of command the INTERP module looks for are executable files.  Windows 
provides the WinExec() function which performs this function.  However, the WinExec function 
only searches for executable files with and extension of .EXE.   DOS on the other hand, allows a 
different type of executable file to end with the .COM extension.  Also, Windows provides a DOS 
shell configuration file which can also be executed, who's extension is .PIF.  In order all these 
types of files to be executed, the INTERP module first gives the WinExec function a crack at 
executing it.  If this fails, INTERP then searches the PATH for a file who's name matches the 
command name and ends in either a .COM or a .PIF.  If either of these are found, an explicit file 
name and path is created and passed to the WinExec function, which will then execute the 
appropriate files.
If none of the above types of commands are found to match the specified command, an 
"unknown command" message is displayed in the WStdio window.

III. DEVELOPMENT PROCESS
This section discusses some of the problems and considerations that I ran into while 
designing and implementing the Windows Shell.   On a general note, it seems that many of the 
major design issues I originally set out to implement worked quite well.  From the onset, I 
intended to create a Windows application that did not have a message loop in WinMain function.  
I wanted the main module worry more about the matters of command interpretation than 
windowing.   The message loop was to be hidden in the screen I/O functions, which is how it is 
now implemented.   Also, the idea of having external commands implemented as DLLs worked 
out great.  I really had no idea if either of these ideas were feasible when I started.
Problems Encountered
The remainder of this section will be organized in a problem-solution format.  I will first 
present a problem or consideration, and then discuss how it was solved or overlooked.

P -  As mentioned in section II.B.1, commands entered at the command line aren't given a 
chance to expand the marked text symbol into text that is actually marked on the WStdio 
window.  I had originally intended to provide this feature, but the implementation in the WStdio 
window prevented it.  The problem lies in the fact that a command entered by the user is 
executed only after the user finishes typing the command and presses the ENTER key, which 
immediately generates a newline character.  When a newline is output to the WStdio window, 
the marked text is automatically un-marked.  Thus by the time the command is being interpreted, 
any marked text is no longer valid.  The Action Bar does not have this problem because it does 
not generate a newline character when pressed.
S - The solution for this problem was to disallow marked text expansion on the command line.  
While this is more or less avoiding the problem, I have not found an acceptable way to rectify it.

P - The Microsoft C functions for manipulating ENVIRONMENT variables do not work in a 
Windows program.  I don't know why.
S - The solution was to get a pointer to the environment area, and do all ENVIRONMENT 
manipulation functions by hand.  This was a messy job, but the only way I found to get it to 
work.

P - In Windows, the ENVIRONMENT of the parent is not inherited by the programs is spawns.  
This has made the ENVIRONMENT editor almost useless.
S - There is nothing that can be done for this, except pray for future releases of Windows to 
change this.

P - The speed of I/O to the display was too slow, running on a 16MHz VGA system.  For 
example, as lines were output from an LS command, the rate at which lines were displayed was 
annoyingly slow.  This is of course do to the graphical nature of displaying and scrolling text.
S - The solution was to buffer the lines as they came in, and to output them in bursts.  This made 
the code considerably more difficult to understand, but the end result was highly desirable.  I 
found that by just buffering every other line, screen I/O was greatly increased.

P - Use of "strtok" C library function is dangerous.  Because I am lexically analyzing a 
command line to determine what to execute, what flags to set, etc, I intended to use strtok.  
However, the C library version is not compatible with Windows, because it allocates memory in 
an incompatible way.  So I decided I would write my own. However, I realized that the way strtok 
is used will not work in a multi tasking environment.  Strtok "remembers" the last parameter you 
gave it, which allows you to call it successively to get the next tokens.  But with different 
programs using strtok simultaneously, it will get garbled.  
S - I considered two possible solutions for this problem.  The first was to redesign my strtok 
function to always require the string to be parsed as a parameter.  The calling routine would 
have to supply two buffers, one holding the source string, the second holding a buffer in which 
strtok could do it's work.  This however, would be quite cumbersome for the client using strtok.  
The second solution is to carefully organize the use of strtok so that it is used by all modules in 
a linear fashion, instead of allowing any one module use it any time it likes.  That means the 
module must know exactly what state the function is in before using strtok.  While the former is 
a more foolproof solution I chose to go with the latter, since it seems to work and required the 
least amount of change.



APPENDIX A. THE EXTERNAL COMMANDS DLL INTERFACE


OVERVIEW
	Each "External Command" is a DLL that contains the code for that command.  The 
'GENERIC.C' and associated files in the GENERIC directory provide a template for creating a 
new External Command.  
	An important consideration in implementing a new command is where to store your data.  
In order for your DLL to be completely reentrant, no variable can be stored in the data segment.  
That is, one must not declare variables outside of a function, or declare variables inside a 
function.  The reason for this is that each invocation of a DLL function uses that same data 
segment.  If a DLL function was called reentrantly,  static variables would be overwritten.  If a 
DLL requires more data than will fit on the stack, on must use dynamic allocation.  Future 
version may get rid of this requirement.

REQUIREMENTS

Each DLL must provide the following 3 functions for use by Windows Shell:

int FAR PASCAL ModuleProc (HWND hwndDisplay, int argc, LPSTR argv[]);
@ ORDINAL 3
hwndDisplay	- Window handle of STDIO Display to use for I/O.
argc	- Number of command line arguments.
argv	- Array of pointers to command line arguments.  The first pointer always points to 
the name of the DLL.
This function is called to let the DLL do the function which it is providing.  For example, if this 
were a DLL providing a file deletion function, the DLL would perform the deletion at this time.

int FAR PASCAL ShowOptions (HWND hwndParent);
@ ORDINAL 4
hwndDisplay	- Window handle of STDIO Display to use for I/O or as parent.
This function is called to tell the DLL to show it's options box.  The DLL should display a window 
which allows the user to set options in the DLL.

int FAR PASCAL ShowAbout (HWND hwndParent);
@ ORDINAL 5
hwndDisplay	- Window handle of STDIO Display to use for I/O or as parent.
This function is called to tell the DLL to show it's about box.  The DLL should display an about 
window at this time.

NOTE - It is essential that the DLL export these functions at the specified ordinal value in it's 
.DEF file.  Otherwise, The Windows Shell will not properly access the DLL.


USING THE DISPLAY
The header file 'wstdio.h' has been provided for outputing lines and other function to the 
display.  The most common of these is dputs(), which you can use to output a line to the display.  
See the header file for the description of the rest of the functions.

UTILITY FUNCTIONS
The 'wslib.dll' provides several useful functions for parsing command lines, and yielding to 
other applications.  It is extremely important that you use the YieldToOthers() function your code 
sits in a tight loop for an extended length of time.  See the header file 'wslib.h' for a list of useful 
functions.


APPENDIX B. FUTURE ENHANCEMENTS

Possible Future Enhancements
- User loadable alias files, supporting multiple loads of different files
- Allow more variables to be user configurable, such as the scrollback buffer size.
- Add a timer to the WStdio module to periodically purge all unpurged lines.
- Allow marked text to remain marked as the WStdio window is scrolled.  This would allow the 
marked text symbol to be expanded into the marked text for commands issued from the 
command line.
- Spawn a separate task for each Internal Command as it is run.  This would allow the DLL's to 
use static data, because each time a DLL is called, it would be from a different task.
Page: 2
 
TABLE OF CONTENTS


ABSTRACT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .	iii

HOW THIS DOCUMENT IS ORGANIZED . . . . . . . . . .. . . . .	iv

LIST OF FIGURES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 	v

Section

	I.	Features of Windows Shell . . . . . . . . . . . . . . . . . . . . . . . . 	1

		Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .	2

		Aliasing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .	3

		Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 	3

		Action Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .	3

		External Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 	4

		Shell Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 	5

	II.	Design of Windows Shell . . . . . . . . . . . . . . . . . . . . . . . . . 	7

		Graphical Objects in the Windows Shell . . . . . . . . . . . . . 	7

		 	The WSTDIO Window . . . . .  . . . . . . . . . . . . . . . 	8
				
				Pertinent Data . . . . . . . . . . . . . . . . . . . . . .	8

				Painting The Display . . . . . . . . . . . . . . . . .	10

				Obtaining Standard I/O input . . . . . . . . . .	11

				Marking Text  . . . . . . . . . . . . . . . . . . . .	12

				Command History . . . . . . . . . . . . . . . . . .	13

				Message Directory . . . . . . . . . . . . . . . . .	13

			The ACTNBAR Window . . . . . . . . . . . . . . . . . .	14

			The WINSHELL Window . . . . . . . . . . . . . . . . .	15

		Logical Modules For Command Interpretation. . . . . . . .	16

			The Command Prompt Path . . . . . . . . . . . . . . . .	17

			The Action Button Path . . . . . . . . . . . . . . . . . . . 	18

			The ALIAS.C Module . . . . . . . . . . . . . . . . . . . .	19

			The INTERP.C Module . . . . . . . . . . . . . . . . . . .	19

	III. 	The Development Process . . .  . . . . . . . . . . . . . . . . . .	21

Appendix

	A. Appendix A: External Commands DLL Interface . . . . . . . . . 	23


iv

20