Contents of the README.TXT file
OS/2 Work Place Shell Sample Program - Address Book
Copyright (C) 1993 IBM Corporation
DISCLAIMER OF WARRANTIES. The following [enclosed] code is
sample code created by IBM Corporation. This sample code is
not part of any standard or IBM product and is provided to you
solely for the purpose of assisting you in the development of
your applications. The code is provided "AS IS". ALL
WARRANTIES ARE EXPRESSLY DISCLAIMED, INCLUDING THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. IBM shall not be liable for any damages arising out
of your use of the sample code, even if IBM has been advised of
the possibility of such damages.
Specials thanks to Diana Mack for the careful review of the
code and dokumentation .
This example implements a simple address book. An address book
contains "people" who have names, addresses, phone numbers, etc.
The address book is implemented as a subclass of the WPS folder
class, WPFolder. Subclassing WPFolder has the advantage of
inheriting standard folder behavior, especially the Icon,
Settings, and Details view. The address book adds an additional
view, "Indexed View", which is an alphabetically-tabbed view of
the persons within the address book.
The person object contained within the address book is
implemented as a subclass of WPAbstract. Subclassing WPAbstract
has the advantage of inheriting base WPS object behavior like
drag/drop, pop-up menu, and the Settings view. The person
class adds an additional "Info" page to the Settings view where
the user can change an address, phone number, etc.
Alternatively, the person class could have been a subclass of
WPDataFile. This allows the person object to be copied to a
diskette (WPAbstract's cannot be copied to diskette because
their instance data is stored in the OS2.INI file). However,
WPAbstract instances are more quickly created for objects whose
data storage requirements are small. Indeed, FAT file system
drives waste considerable space for small files because they
allocate an entire sector (usually about 2-4K) for each data
This example also has other "support" classes. The ShrList
class is a simple ordered list. And the ShrNotifier is a
mechanism used by the ShrAddressBook and ShrPerson classes to
simplify the synchronization of the display of their instance
data with the views seen by the user.
Installation of the Address Book
Copy SHARE.DLL to one of your fixed disks, then execute
SHRINST.EXE. It will prompt you for the path where you copied
SHARE.DLL, select Install. SHRINST.EXE will register all the
classes needed by this example, namely, ShrFolder,
ShrAddressBook, ShrPerson, ShrList, and ShrNotifier.
An "Address Book" object will be created on your desktop.
Open it and select "Create person".
Note: Some users reported having to reboot after the installation
to get the correct icon for the address book. If the address
book icon looks like a folder after installing, try rebooting.
All known problems are documented in detail in WPS-PGM.TXT.
This example was tested on OS/2 2.0 GA and several problems with
person's not showing in the Icon view of the address book were
found; these problems did not occur in later testing on the
March beta of OS/2 2.1.
There was also a rather serious problem with the SHARE.DLL
being wrongly unloaded by the WPS (see "Problem 16" in WPS-PGM.TXT).
This can be avoided by keeping an address book "Indexed View" open
The SOM compiler generates a number of files based on the
contents of the class definition file (*.CSC):
*.IH - implementation header.
*.PH - private header.
*.SC - compiled SOM class definition
*.PSC - private portion of compiled SOM class definition.
*.H - SOM method macro definition (eg, ADDRBK.H).
Do not create an include file (*.H) with the same name as your
class definition file (*.CSC). It will be overwritten by the
*.H file generated by the SOM compiler. You can include
constants, macros, typedefs, etc, in the "passthru" section of
your class definition file, or if you prefer, create an include
file but use a different suffix, eg, *.PTH.
SHARE.C - common functions, DLL initialization, etc.
SHARE.H - MRI constants, macros, typedef's, etc.
SHARE.DEF - exports for SHARE.DLL
SHARE.MAK - make file for SHARE.DLL and SHRINST.EXE.
SHRFOLDR.H - header file.
SHRFOLDR.SC - compiled CSC file.
SHRFOLDR.OBJ - object code file.
SHRFOLDR.CSC is NOT included in this package.
SHRFOLDR.C is NOT included in this package.
NOTE: ShrFolder is a subclass of WPFolder created to add the
methods shrAddedToContent and shrRemovedFromContent. The
source code for this module IS NOT INCLUDED because it uses
undocumented methods. This problem has been reported to Boca.
See WPS-PGM.TXT for other known problems and workarounds.
ADDRBK.CSC - class definition.
ADDRBK.C - model code.
ADDRBKV.C - view code.
ADDRBK.ICO - address book icon.
ShrAddressBook is a subclass of ShrFolder that adds an
additional view, the "Indexed View", which looks similar to a
tabbed address book. ShrAddressBook's Indexed View displays
instances of ShrPerson in separate pages, eg, page "A - C"
might hold an instance of ShrPerson titled "Adams, John".
PERSON.CSC - class definition.
PERSON.C - model code.
PERSONV.C - view code.
PERSON.ICO - person icon.
ShrPerson is a subclass of WPAbstract that hold information
about a person, eg, name, address, etc. ShrPerson adds an
"Info" page to the Settings notebook to allow the user to
change the person data.
NOTIFY.CSC - class definition.
NOTIFY.C - model code.
ShrNotifier is a subclass of SOMObject that provides a simple
notification mechanism used to keep models (like
ShrAddressBook and ShrPerson, in ADDRBK.C and PERSON.C,
respectively) synchronized with their views (ADDRBKV.C and
SOMLIST.CSC - class definition.
SOMLIST.C - model code.
LIST.C - basic list functions.
LIST.H - basic list functions header.
ShrList is a subclass of SOMOBJECT that implements an ordered
list. It is used by ShrNotifier to keep track of the
models interested views (windows).
SHARE.RC - menus, strings, pointers.
SHARE.DLG - dialogs.
SHRINST.C - source code.
SHRINST.DLG - dialog.
SHRINST.H - MRI constants.
ADDRESS BOOK EXAMPLE - HINTS AND TIPS
This section contains information that may be of interest to the
SOM/WPS programmer. Much of it is gleaned from the comments
within the source code.
What is SOM?
Let's break the question down a bit first...
What is an Object?
The short answer -- an object is data and behavior. Objects
communicate using a messaging technique. These messages can be
used to query an object's data or ask it to perform some
What is an Object Model?
A representation of an object. In rough terms, the object model
of C++ is a structure with a list of associated functions that
act on that structure. In Smalltalk, the object model is either
byte data or pointers to other objects with a collection of
methods that act on the byte data or object pointers.
So, What is a System Object Model?
A common representation of an object. The goal is to allow for
communication between objects and sharing of object class
implementations independent of the underlying implementation
SOM provides a basic class definition compiler that generates
bindings that are acceptable to the various compilers (C Set/2
How are SOM and WPS Related?
The Workplace Shell uses SOM as the basis for its object model.
All the objects created by WPS are subclasses of the root
class provided by SOM, SOMObject.
SOM can be used independently of the WPS. For example, the
ShrList and ShrNotifier classes are implemented as a subclass of
SOMObject. The converse is not possible, that is, if you write
to the WPS, you must use a SOM-based solution (eg, C Set/2 and
SOM/WPS macros, or C++ and SOM/WPS C++ bindings).
WPS uses C Set/2 and the SOM C Set/2 bindings. There exists
SOM/WPS bindings for C++, but they have not been as throughly
tested as the SOM C Set/2 bindings for WPS.
Serial Access to Object Instance Data
If you're going to access instance data YOUR subclass has
defined from a second thread, use wpRequestObjectMutexSem and
The wpRequestObjectMutexSem method will prevent other threads
from modifying your object's instance data (of course, this
assumes new methods you add that query/set instance data use
wpRequestObjectMutexSem and wpReleaseObjectMutexSem, too).
WPS is extremely multithreaded. The wpRequestObjectMutexSem and
wpReleaseObjectMutexSem methods are very important. It is wise
to request/release the object mutex semaphore in each new
instance method your define that queries/sets object instance
data (eg, shrSetAddress, shrQueryAddress). In addition, the
method should include exception protection should the method
trap to make certain it releases the object's semaphore.
See ShrSetObjectString and ShrQueryObjectString in SHARE.C for
Handling exception conditions (eg, referencing an invalid
pointer) is very easy under OS/2 2.0. ShrExceptionHandler in
SHARE.C along with two macros, ShrStartTryBlock and
ShrEndTryBlock, make it very easy to code. See examples in
ADDRBKV.C and SHARE.C. BTW, the OS/2 2.1 toolkit example WPCAR
shows how to use the "#pragma handler" rather than the macros
this example uses.
NOTE! It is very important that exception handlers be coded in
routines that request mutex semaphores! The exception condition
should relinquish the semaphore if it was successfully
requested. Otherwise, later requestors of the semaphore could
wait indefinitely, typically resulting in a hang of one of the
WPS threads or the entire WPS.
Registering New WPS Views
When a view is registered with wpRegisterView, it is subclassed
by the WPS and its window procedure pointer saved in a reserved
window words. The WPS subclass window procedure handles all the
WM_CONTROL (CN_) notification messages for WPS object container
records inserted into a container, along with the system menu
code to display the context menu, and a few WM_COMMAND
messages (delete, copy, move, etc).
It is often desireable to re-subclass after calling
wpRegisterView so your frame window procedure gets called before
the WPS version. This is necessary because the WPS version does
not forward any WM_CONTROL messages to its superclass, and your
frame window procedure may need these notifications.
See ShrOpenAddressBook in ADDRBKV.C for an example.
Determining an Object's Protocol (Type)
One advantage SOM has over C++ is the choice of method
resolution. You can use one similar to C++ (offset into a
v-table), or dynamic lookup at runtime using the "name lookup"
on the method declaration.
This allows the definition of more polymorphic classes. For
Mammals Reptiles Birds Ghouls Ghosts Goblins
Assume LivingThings and UndeadThings respond to
"areYouFriendly", but Things do not. Using SOM and given a
pointer to a LivingThing or UndeadThing, I could ask
"areYouFriendly". In C++, LivingThings and UndeadThings would
have to have a common ancestor that responded to that message.
In SOM, LivingThings and UndeadThings would not have to have a
common ancestor if the "areYouFriendly" method was defined as
"name lookup", ie, it uses SOM's dynamic message resolution, not
offset method resolution technique. SOM also provides
somRespondsTo to help figure out cases where your are really not
certain the type of the receiver.
Despite this flexibility, many SOM programmers use _somIsA to
determine an objects type, instead of _somRespondsTo.
One drawback to _somIsA is its dependency on the class hierarchy
to infer an object's protocol. For example, a new-and-improved
version of LivingThings that is not a direct descendant of
Things would not be recognized as a "LivingThings" if client
classes used _somIsA, while they would if client classes had
But note there is a problem to be considered -- a class often
has methods that are not "name lookup" methods, ie, they use
SOM's offset message resolution much like that used by C++, so
creating a new class that is not a subclass of the class's
superclass would require considerable care since it would have
to be certain to have its version of this class has its methods
in the same order as the method table of this class.
The ShrPerson class implements the "shrUnderstandsProtocol"
method. Ideally this method would exist in the root class, so
OO programmers could determine the object's protocol and avoid
type checking, which leads to more flexibility and reuse.
See ADDRBK.C for an example.
ShrAddressBook is an example of "restrictive containment". It
will hold objects, but only those of a specific type. There are
other examples of restrictive containment in the OS/2 WPS. The
Printer object only allows print jobs within it; the Minimized
Window Viewer only allows minimized windows within it.
Restrictive containment can effectively be used to guide the
user to the purpose of a container. But be certain that such
restriction is considered reasonable to the user. It is often
tempting to use restrictions to solve programming problems and
not user interface problems.