The Design and Implementation of VIOWIN - Part 1

From EDM2
Jump to: navigation, search
The Design and Implementation of VIOWIN
Part: 1 2 3 4 5 6 7 8

The Fullscreen PM Subset

Written by Larry Salomon Jr.

Introduction

For my job, I once had to write an application that ran only when OS/2 booted from the floppy diskettes. Because I had no access to the functionality PM provides, I resorted to a line-oriented interface, where messages were displayed on the screen and scrolled up when necessary. It was a good interface, I thought; it was fully NLS enabled and had intelligent defaults so the user basically only had to type in the name of the application. Unfortunately, the Quality Assurance team didn't concur with my opinion. "We want a nice interface!" one exclaimed. "Yeah, one with different windows and such!" another shouted.

I was backed into a corner that I could only get out of one way.

This series will describe the design and implementation of VIOWIN, a library that implements a subset of the Win APIs provided by PM for fullscreen sessions. The reasoning behind writing this series is that it provided me and will hopefully provide you with some unique insights into how a windowing system is developed; and since it is based on PM, your familiarity with the already defined interface will increase your capability to fully understand what is being described.

Obviously, this series assumes you have PM application development experience, but it isn't required.

Forethought

Before I could begin coding, I had to decide where to draw the line. I couldn't reasonably expect to implement the entire API set, but I didn't want to limit the capabilities of the library unnecessarily. I must apologize because I did not take any notes when developing this, so the "list" of limitations is probably incomplete. Most of the limitations were chosen to save time coding the library; after all, I did have an application to write using this library and only two weeks total to complete all of it!

The design points are listed below. First are the "have not's":

  1. No multiprocess or multithread application support.
  2. No overlapping window support.
  3. No movable window support.
  4. No mouse support.
  5. No profile support.
  6. No class styles.

...followed by the "have's":

  1. At least 3 implemented window classes - buttons, entryfields, and statics.
  2. Input focus support.
  3. Timer support.
  4. Cursor support.
  5. Limited resource support.
  6. Window styles.

For the window classes, not all styles were implemented (e.g. text fields and group boxes were written, but not rectangles or bitmaps), nor were all messages in each class implemented.

Cursor support is limited, due to the nature of the system. Since we are running in a character-mode fullscreen session, we cannot have dotted boxes around the text of a button, for example.

The only resource support that made it into the current version is for the STRINGTABLE. I would have liked to have added ACCELTABLE and DIALOGTEMPLATE support, but didn't have the time to do it.

Additionally, I wanted to have as much similarity to the Win APIs as I could possibly design and code. Thus, there is an anchor block and message queue (although they are hidden), message loops, window procedures, etc. The advantages here are that
1) I didn't have to spend additional time designing the paradigm on which my design would be based and
2) users of the library would already be familiar with the ideas, providing they had PM application development experience.

There are also some things not mentioned above that were included. I avoided the issue of output completely by choosing to leave out the Gpi APIs (for obvious reasons), but the static control, for example, had to be able to write its text out. Thus, the vwDrawText() function was added. Also, for the limited clipping provided in functions such as vwDrawText(), rectangle support was added. Also, certain system values were added, as well as the vwQuerySysValue() and vwSetSysValue() functions, and vwAlarm() was needed for audible feedback.

The base library consists of the files listed below, followed by a list of the files comprising the window classes, which were kept separate to encourage good programming.

VIOWIN.C Main module, containing miscellaneous functions
VWCLASS.C Window class support
VWCURS.C Cursor support
VWDRAW.C Drawing support
VWMSG.C Message support
VWRECT.C Rectangle support
VWRES.C Resource support
VWTIMER.C Timer support
VWUTIL.C Utility functions needed by the library
VWWND.C Window functions
CLASSES.C Main module, which registers the window classes
CLBT.C Button class
CLEF.C Entryfield class
CLLB.C Listbox class, never implemented
CLSB.C Scrollbar class, never implemented
CLST.C Static class

It should be noted here that exploitation of the Common/2 library was used whenever possible (especially for the linked-list routines). If you are not familiar with this library, it is recommended that you get the latest version (currently 1.6.0) from ftp.cdrom.com.

Throughout this series, I will describe each module in depth along with any notes that pop into my head. I realize that this will detract from the readability of the articles, but - again - I did not originally intend for this series to even exist or for the library to grow to what it has become.

Data Structures

This month, we will only look at the four predominant data structures involved. Additional data structures will be discussed as the code involving them is described. Next month, we will delve into the code proper, and the code will be provided with the next article so that you can do your own "armchair detecting." (This also gives me more time to insure that the code is well-commented, etc.)

Note!
You will notice that vw is the prevailing prefix used throughout the code. This applies to function names, data types, constants, etc. A side effect of this is that, since there is HVWWND instead of HWND (et al.), many structures had to be redefined to specify the new data type instead of the original version. This is tedious at best, and is avoided whenever possible.

The Anchor Block Structure

typedef struct _VWAB {
   ULONG ulSzStruct;
   ULONG ulStatus;
   HCMMEM hcmWork;
   HCLLIST hclClasses;
   HCLLIST hclWindows;
   HCLLIST hclTimers;
   HMODULE hmClasses;
   BOOL bIsSendMsg;
   struct _VWWND *hwndFocus;
   struct _VWCURSORINFO *pciCursor;
   USHORT usCursorState;
   LONG alSysValues[VWSV_CSYSVALUES];
} VWAB, *HVWAB;

The anchor block data structure, shown above, is used to maintain general housekeeping data on the state of the process as a whole (vs per thread in PM). The fields are described below:

ulSzStruct (ULONG) size of the structure, because I am afraid that there is still some thunking going on in the kernel.
ulStatus (ULONG) status of the library (VW_HABST_* constant).
hcmWork (HCMMEM) heap manager instance for general purpose consumption.
hclClasses (HCLLIST) linked-list of VWCLASSINFO structures defining each registered window class.
hclWindows (HCLLIST) linked-list of VWWND structures defining the existing windows.
hclTimers (HCLLIST) linked-list of VWTIMERINFO structures defining the timers in use.
hmClasses (HMODULE) handle of the DLL containing the predefined classes.
bIsSendMsg (BOOL) flag set when vwSendMsg() is called.
hwndFocus (HVWWND) handle of the window with the input focus.
pciCursor (HVWCURSORINFO) describes the cursor information. I cannot remember exactly why this is a pointer and not the structure itself.
usCursorState (USHORT) a VWCS_* constant, used internally.
alSysValues (LONG) an array of the system values.

The Class Information Structure

typedef struct _VWCLASSINFO {
   CHAR achName[256];
   PFNVWWP pfnWndProc;
} VWCLASSINFO, *PVWCLASSINFO;

achName is the name of the class as registered and pfnWndProc is a pointer to the associated window procedure.

The Window Structure

typedef struct _VWWND {
   ULONG ulSzStruct;
   struct _VWCLASSINFO *pciClass;
   USHORT usId;
   ULONG ulStyle;
   VWSWP swpSwp;
   LONG lForeClr;
   LONG lBackClr;
   PCHAR pchText;
   PVOID pvData[2];
} VWWND, *HVWWND;
ulSzStruct (ULONG) again, because I am paranoid.
pciClass (PVWCLASSINFO) pointer to the VWCLASSINFO structure so to optimize the vwSendMsg() function.
usId (USHORT) identifier of the window. Like PM, an id of -1 means that you don't care about the identifier and a "duplicate id" check is not made.
ulStyle (ULONG) window style.
swpSwp (VWSWP) size and position of the window.
lForeClr (LONG) foreground color. See below.
lBackClr (LONG) background color. See below.
pchText (PCHAR) window text.
pvData (PVOID) array (yes, I too just noticed the incorrect field name according to Hungarian notation) of window data. The window classes use index 1 and the application can use 0.
Note!
The colors are a necessary deviation from PM since there is no Gpi support. Instead of having each window class allocate and manage window words, I decided to do it instead, since it would be a frequently used piece of information.

Message Queue Structure

typedef struct _VWMQ {
   ULONG ulSzStruct;
   VWQMSG aqmMsgs[VW_SIZEQUEUE];
   ULONG ulHead;
   ULONG ulTail;
} VWMQ, *HVWMQ;
ulSzStruct (ULONG) again, because I am paranoid.
aqmMsgs (VWQMSG) array of VWQMSG structures containing the contents of the queue.
ulHead (ULONG) index of the front of the queue.
ulTail (ULONG) index of the rear of the queue.
Note!
This is a circular queue.

Next Month

That's it for this month. I hope I have whet your appetite with this installment. Next month, we will begin looking at the primary modules in the library, which will be followed in subsequent month's by the other, not-as-important modules, and finally by the window classes.

Any comments are most definitely welcome to my email address. See you next month!

The Design and Implementation of VIOWIN
Part: 1 2 3 4 5 6 7 8