home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
xwplascr.zip
/
XWPL0208.ZIP
/
progref.inf
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
2002-07-02
|
83KB
|
2,051 lines
ΓòÉΓòÉΓòÉ 1. XWorkplace Programmer's Guide and Reference ΓòÉΓòÉΓòÉ
Notices
Introduction -- start here
National Language Support
The XWorkplace source code
Source code details
Adding features to XWorkplace
Miscellaneous WPS programming notes
ΓòÉΓòÉΓòÉ 2. Notices and Legalese ΓòÉΓòÉΓòÉ
Please see the XWorkplace User Guide for the "Notices" section: the GNU General
Public Licence (GPL), the development team, credits, and thank you's.
ΓòÉΓòÉΓòÉ 3. Introduction -- Start Here ΓòÉΓòÉΓòÉ
Welcome to the XWorkplace source code!
This book has been written by XFolder's and XWorkplace's original author,
Ulrich MФller, to introduce you to the world of XWorkplace programming.
This book covers two different things:
1. Information about XWorkplace National Language Support (NLS). This is of
interest for people who would like to translate XWorkplace to a new
language. No knowledge of C programming is required for translations, but
knowing HTML helps.
See "National Language Support" for more information.
2. Information about the XWorkplace C source code. This is mainly of
interest for programmers who would like to contribute to XWorkplace, find
bugs, or who are just interested in learning how the thing is
functioning.
See "The XWorkplace Source Code" for a general introduction and how to
compile.
See "Source Code Details" for information about specific XWorkplace
features and their implementation. This is useful for contributors.
See "Adding Features to XWorkplace" for information about how to hook
your own code into XWorkplace.
If you have questions, please post a message to
xworkplace-dev@yahoogroups.com, which is the mailing list for XWorkplace
developers.
But if you want to start writing WPS classes, please don't start asking things
like "What is an IDL file?". If you have never created a WPS class, please
read the excellent courses at EDM/2 (www.edm2.com) first, which explain a lot
of things to get you started. As far as I know, XWorkplace is the most complex
WPS source code available, and it probably does not serve very well as a WPS
beginner's tutorial.
Thanks!
ΓòÉΓòÉΓòÉ 4. National Language Support (NLS) ΓòÉΓòÉΓòÉ
Overview
Requirements for translations
Preparations
The main NLS DLL (XFLDRxxx.DLL)
The INF and HLP files
The h2i utility
Images and screenshots
Other files
Testing your NLS files
ΓòÉΓòÉΓòÉ 4.1. Overview ΓòÉΓòÉΓòÉ
National Language Support (NLS) is done by separating everything that is
language-dependent from the actual program logic. The way XWorkplace does this
is that all the NLS stuff is packaged into files that are completely separate
from XFLDR.DLL so you can change XWorkplace's language without having to
recompile XWorkplace itself.
XWorkplace NLS packages identify themselves to the XWorkplace core via country
codes, as described on the "COUNTRY" page in the OS/2 Command Reference
(CMDREF.INF).
XWorkplace's language depends on exactly one setting in OS2.INI (application
"XWorkplace", key "LanguageCode"). If that setting is changed, XWorkplace
assumes a whole new set of language files to be present. The setting is only
checked once at WPS startup or later if you explicitly load a new language in
the XWorkplace Setup object. If no code is present, "001" for US English is
assumed.
The XWorkplace sources contain everything for creating the US English NLS
package, as it comes with the standard XWorkplace binary release. The language
code for US English is "001". Everything that is related to English NLS is
therefore in the 001\ directory tree.
The first step you'll have to take is finding out your country code. For
example, Italian would be 039.
Unfortunately, XWorkplace's National Language Support (NLS) is spread across
quite a number of files, which have different file formats.
Basically, XWorkplace's NLS can be separated into three parts:
1. Run-time NLS: this is all the language-dependent things that XWorkplace
will ever display to the user, such as menus, dialogs, messages, and
notebook pages.
Here we have:
The NLS DLL to be put into the XWorkplace bin subdirectory. This
file contains all language-dependent Presentation Manager (PM)
resources, mostly dialogs and menus. Also, a lot of strings are
stored here.
The NLS DLL is called xfldrXXX.dll, with "xxx" being your
three-digit language code. The files neccessary to translate this
DLL are in the 001\dll directory. All this goes into
bin\xfldr001.dll in the binary release.
See "The main NLS DLL" for details.
The XWorkplace message file, help\xfldrXXX.tmf. This file holds all
kinds of messages which are mostly displayed in XWorkplace's message
boxes and are too large to be put into the resources of the NLS DLL
(because PM string resources are limited to 256 characters,
unfortunately).
The file has a format similar to that of the source files for the
IBM MKMSGF.EXE utility, but using that utility is not necessary for
XWorkplace. There are several *.tmf files in the 001\misc directory
in the sources, which are combined to form help\xfldr001.tmf in the
binary release.
See "Other files" for details.
The WPS class descriptions which are displayed on the "WPS Classes"
settings page in the "Workplace Shell" object. This was introduced
with XFolder 0.80 also.
This file is called XFCLSxxx.TXT, with "xxx" being your three-digit
language code. It also resides in the 001\misc directory.
See "Other files" for details.
A number of REXX .CMD and text files for XWorkplace's installation.
The files to be translated are in the 001\misc subdirectory and go
into install\ in the binary release.
See "Other files" for details.
2. Documentation: the XWorkplace User Guide (INF file) and online help (HLP
file). This is not absolutely necessary and probably the larger part of
the translation work, since I have written so much text over time.
Here we have:
The XWorkplace Online Reference (INF) in the XWorkplace main
directory.
This file is called xfldrXXX.inf, with "xxx" being your three-digit
language code. The HTML source files neccessary to translate this
file are in the 001/inf.001 subdirectory.
See "The INF and HLP files" for details.
The XWorkplace HLP file in the HELP subdirectory. This file holds
all the help panels that are displayed when you press F1.
This file is called xfldrXXX.hlp, with "xxx" being your three-digit
language code. The files neccessary to translate this file are in
the 001/xwphelp2 subdirectory.
See "The INF and HLP files" for details.
(Yes, I know the directory naming conventions might seem strange,
but if you have ever tried to rename a directory with CVS, you will
understand.)
3. Installation: a number of files which are only used while XWorkplace is
being installed. These set up XWorkplace objects and INI keys in a
certain language. Please see the README in the MISC directory for
details.
4. The Warp 4 SmartGuide script which was present with XFolder and
XWorkplace before V0.9.7 is gone now.
ΓòÉΓòÉΓòÉ 4.2. Required Tools ΓòÉΓòÉΓòÉ
Even though all the source files in this package can be edited using any editor
(because they're all plain text files), you will need some extra utilities to
create the actual NLS files.
In any case, a C compiler is not required.
To be more precise:
I have written my own utility which converts the HTML sources for the INF
and HLP files to IPF format for IPFC (see below). This is in the
xwphelpers repository on Netlabs, so in addition to the XWorkplace
sources, you will need to check out xwphelpers as well. The utility is
called h2i.exe and gets called automatically by the makefiles.
The makefiles also convert the GIF files for the INF and HLP files to BMP
format automatically. For this to work, you will need the "Generalized
Bitmap Module" (GBM) package from Hobbes. The makefiles assume that
gbmsize.exe is on your PATH.
In order to create INF and HLP files, you need IBM's "Information
Presentation Facility Compiler" (IPFC.EXE). This thing is part of the
OS/2 Developer's Toolkit, which is finally included with eComStation and
the IBM Convenience Packs.
If you don't have the Toolkit, IPFC is contained in the Device Driver
Development Kit (DDK), which IBM has put online at
http://service.boulder.ibm.com/dl/ddk/priv/ddk-d. You will need to
register, but then downloads are free. Download combase.zip, which has
IPFC plus a number of other tools. (Note: I was reportes that apparently
this is now in tools.zip.) After unpacking, IPFC is in the DDK\base\tools
directory, which you should include in your PATH.
The makefiles in this package were written for IBM NMAKE, which comes
with all the IBM compilers (and also with the DDK mentioned above). I'm
not sure these will work with other MAKE utilities, such as DMAKE or GNU
make. I'd be grateful for feedback.
The makefiles are only for conveniently updating the target NLS files. If
you don't have NMAKE, you can still assemble the files manually. See the
following pages for details.
XWorkplace V0.9.0 and above can read the TMF message file directly, so
MKMSGF.EXE is no longer needed to compile message files.
ΓòÉΓòÉΓòÉ 4.3. Preparations ΓòÉΓòÉΓòÉ
XWorkplace strictly separates language-dependent resources from the rest of the
program. To make things easier, all language-dependent resources are in the
"001" subtree of the main XWorkplace directory, which holds all English NLS
files.
Here's a list of things you need to do before you can begin translations.
1. The first thing you need to do is find out your three-digit language
code. Open the OS/2 Command Reference, "Country" page, and find the code
for your country.
2. Make a copy of the entire 001 directory tree within the XWorkplace source
tree, renaming it to your country code. For example, if your language is
Italian, you should have a 039 tree next to the 001 tree.
3. Some files in the 001 directory carry a three-digit language code in
their respective names. For your language, you need to change all the
filenames with "001" in their names to your country code (e.g. 039 for
Italian). For example, rename dll\xfldr001.dlg to dll\xfldr039.dlg.
4. You will also have to change the dll\*.def file and dll\makefile, which
assume a country code of 001 at this point. Required changes are noted in
the files themselves.
5. Open dll\xfldrXXX.rc (with "xxx" being your country code) and find the
strings "ID_XSSI_DLLLANGUAGE" and "ID_XSSI_NLS_AUTHOR". Change those two
to match your language and name; this is the information that is
displayed to the user in the "Language" drop-down box in the "XWorkplace
Setup" settings object.
You should now be ready to recompile the NLS DLL for the first time.
If you have IBM VAC++, you can simply use MAKE.CMD to have the DLL recreated.
Open MAKE.CMD and check somewhere in the middle where the script checks for
the presence of the 049 directory, and change the variables to point to your
new directory instead. Running MAKE.CMD should then work fine, since all the
neccessary files are included.
Otherwise, things get a bit more complicated. Since the resource compiler
(RC.EXE) is already included with every OS/2 installation, you can try the
following:
1. Copy an existing XWorkplace resource DLL (e.g. xfldr001.dll) into your
new NLS directory; rename it so that it contains your language code (e.g.
xfldr039.dll).
2. Open a command line in that directory.
3. Type rc xfldr039.rc xfldr039.dll (replace "039" with your language code),
which should create a new .RES file and link it against the existing DLL.
After recompiling, you can test the DLL as described in "Testing the DLL".
ΓòÉΓòÉΓòÉ 4.4. The NLS DLL ΓòÉΓòÉΓòÉ
Files that need to be changed:
xfldr001.def: The module definition file. Required changes are noted in
the file itself.
makefile: Makefile for IBM NMAKE. Required changes are noted in the file
itself.
xfldr001.rc, xfldr001.dlg: These are the main resource files which need
lots of changes.
I've documented everything you need to change in the .RC file.
The .DLG file is included when the RC files is recompiled. It contains
all the XWorkplace dialogs (i.e. notebook pages and other dialog
windows). Sorry, there are no comments in there because I'm using
DLGEDIT.EXE to create the dialogs, which rewrites the DLG file at every
change, so all comments in there get lost.
Note: Because of this stupid limitation, I am currently trying to get rid
of all the dialog resources and eventually the .DLG file altogether.
Starting with V0.9.16, more and more dialog resources are converted so
that XWorkplace only loads the strings for the dialog elements from the
string tables in the .RC file any more and creates the dialog dynamically
at run time. This also saves you from realigning the controls if you
don't have enough space.
For the remaining dialogs, you can use DLGEDIT.EXE, the IBM dialog editor from
the Developer's Toolkit, to change the dialogs. (This will not affect the .RC
file.) For this, you will need to create the .RES file first. This is done by
MAKE.CMD; alternatively, you can start RC.EXE with the "-r" option, which
creates a .RES instead of linking the resources to an executable.
If you then open the .RES file with the dialog editor, you can choose
include/dlgids.h as an include file so that all the numerical ID's have a more
meaningful name.
When you then save the file, the .RES and .DLG files will be recreated by
DLGEDIT. The .RC file remains untouched though.
The dialog editor has a helpful "Translate mode" in its "Options" menu which
disables a lot of menu items so you don't accidentally change dlg ID's or
other important stuff.
I don't know if you can use the URE editor also, I have not tried that.
ΓòÉΓòÉΓòÉ 4.5. The INF and HLP Files ΓòÉΓòÉΓòÉ
The sources for the INF and HLP files are written using a slightly extended
HTML syntax. Creating INF and HLP files is therefore a two-step process:
1. The HTML sources are translated into an .IPF source file, using my the
h2i utility. I am no longer using html2ipf.cmd because it's so damn slow
and doesn't support string replacements.
2. Next, the .IPF source is fed into IBM's ipfc from the Developer's
Toolkit. See "Requirements" for where to get this utility.
Please use the make.cmd file on the top level of the XWorkplace source files
to have the doc files created.
I recommend translating all the .HTML files and keep using make.cmd to have
the HTML files converted into a single .IPF file (using my h2i utility), which
can then be fed into ipfc. This has the advantage that you'll only have to
change some panels in future versions, of which I will keep track. Also, I
always note changes to the INF and HLP files in the HTML source files in HTML
comments tags, so you can easily search for what's changed.
The "root" file in each of the two source directories is called xfldrXXX.html,
respectively, with "xxx" being your country code (which you should change in
this one filename because h2i will use this name for the target IPF file
also).
In any case, mind these important notes:
The (slightly awkward, I admit) structure of the files is the following,
in both directories:
xfldrXXX.html is the "root" file. All other files are somwhere below in
the INF/HLP table-of-contents hierarchy, depending on the SUBLINKS tags
in the HTML source files.
Do not change filenames! h2i sorts the IPF pages internally
alphabetically according to the filenames, that's why I've implemented
these strange naming conventions. I admit that since the structure has
developed over time, it may not seem very logical to you, but it works.
Changing things here will result in a lot of work, since all the links in
the HTML files would have to be adjusted also.
Within the HTML files, do not change anything within angle brackets
("<xxx>"). Translate only the text outside of these. Even though some
tags might not be good HTML style and the HTML files might not look
pretty when viewed with Netscape, certain tag combinations (especially
the <BR><LI> combinations) are neccessary to make the pages look good for
IPF.
Don't forget to translate the page titles (in between the <TITLE> tags).
This is what appears in the title of a panel window and in the "Table of
contents" tree. I've forgotten this many times...
I do not recommend translating everything for the INF book. For the old
XFolder, I did the German translation myself, and I think that the
"Revision history" section makes no sense translating, because it is
frequently updated and NLS versions didn't exist for the older versions
anyway. Also, the "XWorkplace Internals" pages apply to programmers,
which need to know English anyway, because otherwise they won't find
their way through the required Toolkit docs either. So I think you can
save yourself some work there.
ΓòÉΓòÉΓòÉ 4.6. The h2i Utility ΓòÉΓòÉΓòÉ
Older versions of XFolder and XWorkplace used the very valuable html2ipf.cmd
script by Andrew Pavel Zabolotny which has served me quite well over the years.
However, this has now been replaced with my own h2i.exe utility, which is both
faster and more flexible.
h2i is contained in the xwphelpers repository at netlabs (see "Requirements").
Start h2i to have its syntax explained. It works quite similar to html2ipf.cmd,
so you can also check HTML2IPF.INF for the general principle.
In addition, h2i supports the following:
The <HTML> tag has new attributes: XPOS= and YPOS= work just like IPF's
"x" and "y" tags; WIDTH= and HEIGHT= are the same as in IPF.
The <A> tag accepts a new AUTO= attribute, which works just like HREF=,
but automatically opens and closes the window (this is, for example, used
on the "Introduction" page of the XWorkplace Online Reference).
The <CITE> and </CITE> formatting tags are now set to use a
non-proportional font, which is used extensively.
Some formatting changes (<UL>, <BR>, <B> etc.).
As opposed to html2ipf, h2i supports the resid attribute to the <HTML>
tag to allow setting the resid explicitly, which is very helpful for
composing help panels that can actually get called by ID from XWorkplace.
In addition, h2i supports string replacements via entities. An entity
always has the form &entity; and whatever is between the "&" and and ";"
characters can be dynamically replaced. Since h2i can also parse C
include files for C preprocessor #define's, this allows for including the
same headers in XWorkplace and h2i to share definitions and resids.
Finally, h2i supports the new <IFDEF> and <IFNDEF> tags for conditional
compiles.
ΓòÉΓòÉΓòÉ 4.7. Images and Screenshots ΓòÉΓòÉΓòÉ
The images in both the INF and HELP directory are in GIF format. Unfortunately,
HTML does not support the OS/2 BMP format, and ipfc does not support GIF.
So the makefiles in INF and HELP automatically convert all GIF images to BMP
format, if required. This requires gbmsize.exe to be on your PATH (see
"Requirements")
If you do not want to use gbmsize, you can convert all the GIFs to BMPs
manually, e.g. using PMView. Be careful though: IPFC only supports uncompressed
OS/2 1.3 bitmaps. That is, neither compressed bitmaps nor Windows or OS/2 2.0
bitmaps work. This is annoying, because IPFC's own image compression is totally
outdated, but there's nothing we can do about this.
I'd be very grateful if you could create your own screenshots for the online
documentation to reflect your language.
I have used the following settings for the screenshots (just for your
information, you don't have to use these):
Fonts used:
Titlebars: Humanist 521, 13 points (available on the
CorelDraw 4 CD in Type 1 format)
All the other fonts are set to 9.WarpSans.
CandyBarZ installed, colors:
Active: top 191/0/0, bottom 52/0/0
Inactive: top 160/160/130, bottom 40/40/40
Oh yes, XWorkplace installed. ;-)
Now, if you create your own screenshots, save them as GIFs with the exact
filenames of the originals (e.g. trunc.gif); you must then DELETE the
respective BMP file, because HTML2IPF will only call the image converter for
BMP if no BMP file of the same name exists.
Tricks to reduce file sizes:
Keep in mind that HLP/INF files have their own compression scheme which works
best when much redundant data is in the bitmap files. For those who know what
that is: IPFC compresses using a modified Lempel-Ziv-Welch algorithm (similar
to the GIF format). In plain English, large areas which have the same color can
be compressed best.
This leads to the following recommendations:
Do not take screenshots of folders with background bitmaps. There will be
practically no compression on those.
Use as few colors as possible. You can use PMView to reduce the number of
colors to, say, 12 colors, which usually still looks alright.
When converting images, make sure you don't have "dithering" or "error
diffusion" enabled, because this will add lots of extra pixels which will
make compression less efficient.
Also, if you need to scale images to a smaller size, make sure not to
enable any "interpolation", i.e. introducing extra pixels to make colors
smoother. This adds lots more colors to the file, which cannot be
compressed well either.
ΓòÉΓòÉΓòÉ 4.8. Directory "MISC" ΓòÉΓòÉΓòÉ
The MISC directory contains files used by XWorkplace's installation script
(INSTALL.CMD) plus the SmartGuide Script used for the XWorkplace introduction.
INSTxxx.MSG (with "xxx" being your country code) was used for
installation messages before the WarpIN installer was used. Even though
the old INSTALL.CMD still works for XWorkplace, it really doesn't make
much sense to translate this message file any more.
The file was used by XHELP.CMD (in the XWorkplace package, taken from my
CommandPak), which is capable of extracting single text messages in
between the <TOPIC>; and </TOPIC> tags in this file. The text between
these tags is then displayed on the screen.
If you still wish to translate this file, what you need to do here is
simply translate all the text which follows a <TOPIC> tag. The text is
displayed "as is", and no formatting is performed; as a result, you must
take care that no more than 80 characters are contained in a line.
You also should take care of the line breaks: it makes a difference in
output whether a </TOPIC> end tag is found at the end of a line or at the
beginning of a new line, because in the latter case, the line break is
still printed to the screen.
Just one more note: Do not change the keys mentioned in this file ("X",
"Y", "N"), even if your language does not use "Y" for saying "Yes".
Unfortunately, INSTALL.CMD relies on these keys. :-(
INSTLxxx.CMD is a straightforward REXX script which creates the default
XWorkplace installation objects (the "XWorkplace" folder plus all the new
settings objects). Even if you don't know REXX, don't worry: you only
have to change the strings on top of the file, which contain all the
language-dependent things. Be careful with the quotes. Do not change
anything else, because XWorkplace relies on it.
Even though XWorkplace uses WarpIN for installation, this REXX script
gets called after the first WPS restart after installation.
Similarly, CROBJxxx.CMD creates the default XWorkplace Configuration
Folder.
This REXX script gets called by INSTLxxx.CMD. Also, this gets called
independently when the "Recreate config folder" button is pressed on the
"Objects" page in the "XWorkplace Setup" object.
SOUNDxxx.CMD is the REXX script which creates the neccessary INI entries
for having the new XWorkplace system sounds in your "Sound" object. Only
change the strings at the top of the file to your language.
This REXX script gets called from the "Features" page in the "XWorkplace
Setup" object when extended system sounds are enabled.
XFLDRxxx.SGS used to be a Warp 4 SmartGuide script to display the
"Welcome" window after XWorkplace has been installed and the WPS has been
restarted. This is no longer distributed starting XWorkplace V0.9.7,
since SmartGuide is no longer supported with OS/2. Do not translate it.
ΓòÉΓòÉΓòÉ 4.9. Testing Your NLS Files ΓòÉΓòÉΓòÉ
XWorkplace's NLS depends entirely on a single entry in OS2.INI
("XFolder"::"LanguageCode"). This entry defaults to a "001" string and can be
changed either at installation time (if the install script does it) or by using
the "Language" setting in the "XWorkplace Setup" object.
All NLS resources are loaded depending on this one setting. That is, if you
change the language, XWorkplace expects not only your NLS DLL to be present in
/BIN, but also the TMF, HLP, and WPS class description files in /HELP. So if
you have not translated these yet, you might want to create a copy of the
English ones with your language code in the filename.
To test a new version of your NLS files:
Make sure you do not currently have your new NLS DLL selected on the
"XWorkplace Internals" settings page, because if you do, the DLL is
locked by XWorkplace and cannot be replaced.
Select "US English" instead, which will unlock the previously used DLL,
which can then be deleted from the XWorkplace directory.
Then put your new DLL into the BIN subdirectory and open the settings
again; select your DLL and see if things work.
Additional caveat for INF/HLP files: Before compiling the .IPF to the
.HLP/.INF files, you should make sure that the target file is not
currently in use.
With INF files, that's easy: simply close it if it's open.
With HLP files, you have to keep in mind that the WPS keeps these files
locked even after you've closed a help panel window. However, the WPS
only ever keeps a single HLP file locked at a time, so in order to unlock
the XWorkplace HLP file, simply open a default WPS help panel, e.g. by
selecting "Extended Help" for the Desktop window.
You can then copy the new XWorkplace .HLP file to the XWorkplace HELP
directory. (MAKE.CMD will do this automatically.)
ΓòÉΓòÉΓòÉ 5. The XWorkplace Source Code ΓòÉΓòÉΓòÉ
Overview
Requirements for compiling
Build setup
Making (building) XWorkplace
The config.in file
XWorkplace makefiles
Troubleshooting
Creating the code documentation
The SRC\CLASSES\ directory
The SRC\HELPERS\ directory
XWorkplace function prefixes
Debugging XWorkplace
ΓòÉΓòÉΓòÉ 5.1. Overview ΓòÉΓòÉΓòÉ
Before going into the details of source code, which is complex enough to get
even the more experienced programmer confused, please read the chapters in the
"XWorkplace internals" chapter of the XWorkplace Online reference for a first
introduction to XWorkplace's basic inner workings.
This will give you a vague idea of what XWorkplace is doing where and deals
with the most important concepts only, so you don't get overwhelmed by all the
details which come in this file.
The different subdirectories contain the different parts of XWorkplace. The
layout of the subdirectories has been changed with XWorkplace V0.9.0 to allow
for easier addition of new features by people other than me. Also, since
XWorkplace will be on the Netlabs CVS server, many changes had to be made to
the makefiles and code layout.
The 001\ directory tree still contains all the National Language Support
(NLS) for English.
The BIN\ directory tree contains binary object files which are created
from the sources (below) by the various makefiles. If that directory
doesn't exist (it's not part of the CVS tree, for many reasons), it will
be created automatically by the makefiles.
The directory structure and the makefiles are designed to not depend on
the BIN directory tree. As a result, you can always delete the entire BIN
directory or any single files in there to enforce a complete or partial
recompilation by the makefiles.
The IDL\ directory contains SOM IDL source files for the various
XWorkplace classes. The .DEF files in this directory are created
automatically by the SOM compiler (SC.EXE), but not used in the build
process (see below).
When invoked by the makefile, the SOM compiler is told to update the C
sources in SRC\CLASSES and write the class header files (*.h, *.ih) to
INCLUDE\CLASSES.
In general, all SOM code should be in the CLASSES subdirectories. Since
several people might be working on the same classes, the code in CLASSES
should only call implementation code in other directories of SRC, which
should be prototyped in a corresponding subdirectory of INCLUDE.
The INCLUDE\ directory tree has all the headers for XWorkplace.
In that tree, INCLUDE\CLASSES\ has the headers which are generated by the
SOM compiler from the IDL files in the IDL directory (above). There is no
hand-written code in that directory.
INCLUDE\HELPERS\ has the headers for the files in SRC\HELPERS\ (see
below). Note: This is now in a separate CVS archive on Netlabs, which is
called "xwphelpers". You need to check out that archive to be able to
compile.
INCLUDE\FILESYS\ has the headers for the files in SRC\FILESYS\ (see
below).
INCLUDE\SHARED\ has headers for code which might be used by several parts
of XWorkplace, developed by several people, and corresponds to
SRC\SHARED. I guess you get the idea now.
The SRC\ directory tree contains the actual C/CPP source files for
XWorkplace.
In that tree, SRC\CLASSES\ has the SOM code for the WPS classes which
will be compiled into XFLDR.DLL. It is this DLL which loads the NLS DLL
(XFLDRxxx.DLL, with xxx being a language code) at Desktop startup or when
the language is changed using the "XWorkplace Internals" settings page.
See this page for more.
The SRC\HELPERS\ subdirectory contains a lot of C files with helper
functions which are independent of XWorkplace. That is, these can be used
with any OS/2 VIO and/or PM program. The functions are grouped into
categories. See this page for more. Note: This is now in a separate CVS
archive on Netlabs, which is called "xwphelpers". You need to check out
that archive to be able to compile.
The SRC\HELPERS\ dir also contains files from Dennis Bareis' PMPRINTF
package, which is available in full from his homepage. Refer to the
"Debugging XWorkplace" section for details.
The other subdirectories in SRC\ contain implementation code for
XFLDR.DLL (called by the SOM code in SRC\CLASSES) or external programs
which are part of XWorkplace, such as NetscapeDDE and Treesize.
TOOLS\ contains some tools used by the makefiles. See Making XWorkplace.
ΓòÉΓòÉΓòÉ 5.2. Required Tools ΓòÉΓòÉΓòÉ
1. Compiler. With V0.80, I have switched to IBM VisualAge C++ 3.0 to develop
XWorkplace. For VAC++ 3.0, fixpak 8 is strongly recommended, because the
original crashes frequently with the complex SOM header files.
Other compilers are presently not supported. Most notably, some people
have tried to compile using VAC 3.6.5 and ran into problems.
2. You need some OS/2 Developer's Toolkit for all the SOM header files and
the SOM compiler.
I am still using the Warp 3 toolkit, mostly because if XWP is built using
a newer toolkit, it will not start on Warp 3. Besides, it appears that
the SOM compiler and nmake from the Warp 4.5 toolkit have some problems,
according to some reports I got.
3. IBM NMAKE is our make utily. This comes with VAC, so no problem there.
As said above, newer nmake's appear to have problems with XWorkplace's
makefiles, mostly with invoking the SOM compiler. I am using nmake 3,
which comes with either the Warp 3 toolkit or VAC 3.
4. You need to check out the "xwphelpers" CVS archive from Netlabs also.
XWorkplace uses a lot of code which is shared between WarpIN and
XWorkplace, which has been separated into a new CVS archive. (Starting
with V0.9.6, the WarpIN sources are no longer needed.) There's no way to
compile without that code.
5. Only if you enable debugging code through XWP_DEBUG in config.in, you
will need the full PMPRINTF package by Dennis Bareis.
Check the "Debugging" section for details.
ΓòÉΓòÉΓòÉ 5.3. Build Setup ΓòÉΓòÉΓòÉ
With V0.9.12, the build process has been reworked to make building a bit
easier. External environment variables are no longer needed, and the makefiles
now reference the tools by their full path, so there's no need to put the files
from tools\ onto your PATH any longer.
Still, the following setup is recommended for XWorkplace to build successfully:
1. You will need to set your build environment in the config.in file before
building will work. This replaces the external environment variables
which were required before V0.9.12.
2. Because XFLDR.DLL is locked while the WPS is running, you should SET
RUNWORKPLACE=[bootdrv]:\OS2\CMD.EXE in CONFIG.SYS. This will cause an
OS/2 window to come up instead of the WPS after bootup (which is really
helpful if something is wrong in the XWorkplace code). Type pmshell then
to start the WPS.
3. Make sure you have at least 60 MB of free space in your TEMP directory.
This is needed for precompiled headers. I strongly recommend using
RAMFS.IFS for your TEMP directory. This dramatically speeds up things if
you have 128 MB RAM or more. See Troubleshooting for hints about RAMFS.
ΓòÉΓòÉΓòÉ 5.4. Making (Building) XWorkplace ΓòÉΓòÉΓòÉ
Starting the build process. Starting with V0.9.12, this is a two-step process.
After opening a command line in the main XWorkplace directory (the parent of
src and include), do this:
1. Run nmake dep. This examines all source files for dependencies (#include
statements) and writes a .depend file into each source directory which is
then used by the makefiles to rebuild things properly.
Note: You only need to run nmake dep before building for the first time,
or if source dependencies (#include statements) have changed. To be on
the safe side, re-run nmake dep once after you have checked out new
sources from the CVS server.
nmake dep uses the fantastic fastdep utility by Knut Stange Osmundsen,
which I have stolen from the Odin sources. This should be in the root
directory of your xwphelpers repository.
Note: If you have never built XWorkplace before, nmake dep will give you
lots of warnings that headers could not be found. This is normal because
the SOM headers for the XWorkplace classes will only be produced during
the first full build.
2. After that, run either nmake all or nmake really_all to build. This will
produce lots of object files in bin\ and the executables in bin\modules.
At the same time, those executables are copied to the proper locations in
your XWorkplace installation directory as specified in config.in.
After that, restart the WPS to have XFLDR.DLL reloaded.
nmake all (or just nmake) will only rebuild XFLDR.DLL, XWPDAEMN.EXE, and
XWPHOOK.DLL , while nmake really_all will produce the full set of
XWorkplace executables plus the NLS files.
Rebuilding the whole thing. To rebuild everything, you have three options:
Delete the entire bin\ tree. This is not part of the CVS repository at
Netlabs and recreated dynamically for all files that have been created.
Deleting it will cause all target object files to become outdated and
thus be recompiled, which will then also invoke the linker.
Use nmake -a on the main makefile. This will even re-invoke the SOM
compiler on all .IDL files.
Open and save (or touch) include/setup.h to make it newer than the target
files. This is #include'd in all XWorkplace C files, and the makefiles'
inference rules will then enforce recompilation of all C files.
ΓòÉΓòÉΓòÉ 5.5. The "config.in" File ΓòÉΓòÉΓòÉ
This section describes the build environment which is used by the makefiles.
Before V0.9.12, these variables had to be set externally before building. This
has been changed; the environment is now set exclusively through the config.in
file in the main XWorkplace directory.
If these values not set correctly, you'll get errors from the makefiles
(certain checks are built into those), or compilation or linking will fail.
1. CVS_WORK_ROOT must point to the root of your CVS working directories. The
XWorkplace makefiles now (V0.9.6) assume that all your projects (most
importantly, XWorkplace and XWPHelpers) are located in subdirectories of
a single directory. (This is useful for working with CVS in the first
place, so this shouldn't be much of a requirement.)
This variable must point to the parent directory of xworkplace and
xwphelpers. The makefiles will set a number of other environment
variables based on that variable to locate the XWorkplace and XWPhelpers
source tree bases.
Example: SET CVS_WORK_ROOT=K:\cvs
2. TKBASE and VACBASE are new with V0.9.12 and must point to the base
directories of your Toolkit and VisualAge C++ installations,
respectively. Specify the parent directories of h and include. This is
because the build process no longer relies on your INCLUDE environment
variable, but specifies everything on the compiler and linker command
lines.
3. XWPRUNNING must point to an existing XFolder/XWorkplace installation.
Since the makefiles first create all the files in bin\, this is not
suitable for testing your code, because XWorkplace expects a lot of files
at fixed locations relative to the directory where XFLDR.DLL resides.
Most makefiles will copy the target files to the directory pointed to by
this environment variable (after unlocking executables), so after
rebuilding, you can simply restart the WPS, and your new code will be
running in the WPS.
Do one of the following:
Install the latest XWorkplace binary WarpIN archive. Set XWPRUNNING
to the same directory which you specified as the target path to
WarpIN.
Alternatively, copy the entire "release" subtree to some new
location and specify that location with XWPRUNNING to start.
This must point to the parent directory of bin\, help\ etc. in the
XFolder/XWorkplace installation tree.
Example: SET XWPRUNNING=J:\Tools\XWorkplace
4. If XWP_DEBUG is defined (to anything), XWorkplace will be compiled and
linked with debug code enabled.
This will have quite a number of consequences since this will pass the
__DEBUG__ define to the compiler, to which many code parts react. For
example, only if that flag is defined, PmPrintf calls will be compiled.
See "Debugging XWorkplace" for details.
IMPORTANT NOTE: If you compile the debug version, you must have the
PMPRINTF DLLs somewhere on your LIBPATH, or otherwise you'll spend days
figuring out why XWorkplace is simply not working any more. (I had this
once after a reinstall of OS/2, after which the DLLs where gone.) That
is, XWorkplace classes will not load at Desktop startup, because the
PMPRINTF DLL imports cannot be resolved. Neither will registering
XWorkplace classes succeed. And don't expect to get an error message
other than FALSE.
By contrast, if XWP_DEBUG is not defined, release code is produced.
5. Replacing in-use files. You can rebuild XWorkplace even while the WPS is
up and XWorkplace is installed. The makefiles will automatically unlock
DLLs which are currently in use (DosReplaceModule). After the rebuild,
restart the WPS to make it use the newly built DLLs. To do this, simply
set XWP_UNLOCK_MODULES=YES.
Note: This environment variable has was with V0.9.3 because with Warp 4
FP13, unlocking WPS modules hung the WPS after the next Desktop restart.
This problem has been fixed with FP15, so there is really no reason to
not have this variable set to YES any more.
The exception to this are XWPDAEMN.EXE and XWPHOOK.DLL, which are never
unlocked. This is intentional. Unlocking an executable which has
registered a system hook (which becomes part of every PM process on the
system) will never release the hook DLL again, so you'd have to reboot to
use the new DLL.
Warning: If you don't restart the daemon before restarting the WPS, the
XWorkplace startup folder will get processed again after the Desktop
restart. To start XWPDAEMON.EXE explicitly, give it the "-D" option, or
it will tell only you to get lost.
So if you get an error during the build process which says "XWPDAEMN.EXE
is in use", kill XWPDAEMON.EXE using some process killer, which will
properly unload the hooks, and try building again.
ΓòÉΓòÉΓòÉ 5.6. XWorkplace Makefiles ΓòÉΓòÉΓòÉ
The XWorkplace makefiles are quite smart, but therefore quite complex. This
section is supposed to explain why I chose this approach and what the makefiles
do exactly.
I redesigned the entire XWP sources structure with V0.9.0 and made some more
changes with V0.9.12. The sources were supposed to be structured so that the
following was possible:
Several developers must be able to cooperatively work on the sources. As
a result, it must be possible for each developer to work on his own
directory to avoid conflicts.
Still, it should be possible to build the entire thing in one snap.
Building the entire thing should even take place if a makefile from one
of the subdirectories was called.
The makefiles should be easily adjustable in case someone wants to use a
different compiler.
Clean separation of files which reside on the Netlabs CVS server from
those which are created in the build process.
Since the helpers from the "xwphelpers" CVS archive are used, it must be
possible to call the makefile in that directory, but still write the .OBJ
files into the XWorkplace bin\ directory.
It should be possible to rebuild the executables (XFLDR.DLL and the .EXE
files) and just restart the WPS for the changes to take effect.
With V0.9.12, I was finally getting tired of always manually updating the
makefile dependencies if #include statements were changed in the sources.
So nmake dep support had to be introduced.
As a result, I came up with the following:
A single configuration file which sets up all compiler and linker
options. This is setup.in in the main directory, which is included from
all makefiles via the nmake !include directive.
System-dependent configuration (directories etc.) is done via another
file, config.in.
The makefiles create all output files (.OBJ, .DLL, .EXE) in the bin\
directory, which is created if it doesn't exist.
To rebuild the entire thing, one can simply delete the entire bin\ tree.
If the main makefile is started, it changes to the subdirectories and
calls nmake again with MAINMAKERUNNING=YES defined. This way the
sub-makefile knows that it's started from the main makefile. Otherwise
the sub-makefile calls the main makefile (which in turn calls the
sub-makefile) so that the entire thing always gets rebuilt.
The sub-makefiles compile only. Linking is done by the main makefile.
This way every executable can use shared code, such as the helpers.
nmake dep is supported through a new makefile in src\ which calls all
makefiles in the subdirectories of src\ with either the "all" or the
"dep" target. A "dep" target was then added to all the makefiles in src\
which invokes fastdep on all C files to produce the .depend file... which
is in turn included in the makefiles.
This invokes fastdep.exe from the XWP Helpers directory, which I stole
from the Odin sources. fastdep was written by Knut Stange Osmundsen and
creates a .depend file in each source directory with all the includes
which are retrieved directly from the C sources.
ΓòÉΓòÉΓòÉ 5.7. Troubleshooting ΓòÉΓòÉΓòÉ
1. If you get errors from the makefiles, make sure you have set up config.in
correctly.
2. Same thing if the compiler cannot find an include file, or the linker
cannot find libraries.
3. Make sure your TEMP, TMP, and TMPDIR directories are set correctly. Most
importantly, when using RAMFS.IFS, do not use a root directory because
apparently RC chokes on that. I have the following in CONFIG.SYS:
IFS=J:\common\ifs\RAMFS64.IFS
CALL=J:\common\ifs\RAMDISK.EXE Z:
RUN=I:\OS2\CMD.EXE /C md Z:\temp
SET TMP=Z:\temp
SET TEMP=Z:\temp
SET TMPDIR=Z:\temp
4. Also, you need to check out the "xwphelpers" CVS archive from Netlabs for
the helpers code. Make sure that this code is not outdated (I usually
update it together with the main XWorkplace code).
Same thing if you get unknown definitions or unresolved externals during
compiling/linking. This is most probably due to outdated helpers.
5. If the SOM compiler chokes on the .IDL files, you may have a problem with
the nmake version that is running. Several people have reported that the
nmake that comes with the Warp 4.5 Toolkit does not set SMINCLUDE
correctly from the makefiles. I am still running nmake 3, which comes
with the Warp 3 Toolkit and also with the IBM VAC 3 compiler.
Alternatively, look at idl\makefile and search for SMINCLUDE. Uncomment
the line that sets the environment variable and set the variable to the
proper values externally. Some people have gotten the thing to work like
that too.
The SOM compiler that comes with some versions of the Warp 4.5 Toolkit
appears to produce very strange errors also, according to some user
reports. I recommend using the Warp 3 Toolkit; see Required Tools.
6. If you get unresolved externals while linking the XCenter widgets, take a
look at src\shared\xwp.def, which exports the functions from XFLDR.DLL.
7. If you get something like "File XWPDAEMN.EXE/XWPHOOK.DLL is in use", use
WatchCat or some other process killer to kill XWPDAEMN.EXE, which will
automatically unload the hook DLL. Then, after the build, restart the
daemon by executing XWPDAEMN -D (to circumvent the error message box
which comes up otherwise).
See config.in for details.
8. If you get really strange compilation errors, VAC might have gotten
confused with precompiled headers. Delete all .PCH files in your TEMP
directory, or comment out the PRECH line in setup.in to disable
precompiled headers altogether. I have also found that killing
DDE4LOAD.EXE (the VAC background process) helps sometimes, for whatever
reason.
9. If you cannot install XWorkplace after the build, you have probably built
the debug version, but the PMPRINTF DLLs are not on your LIBPATH. Do not
build the debug version if you haven't downloaded PMPRINTF yet. See
"Debugging" for details.
ΓòÉΓòÉΓòÉ 5.8. Creating the Code Documentation ΓòÉΓòÉΓòÉ
Starting with V0.9.0, you can have HTML documentation created for the whole
XWorkplace code. This is done using my own xdoc utility, which can be found in
the root directory of the XWorkplace Helpers.
The sources for xdoc are still in the WarpIN source tree.
xdoc is capable of parsing C/CPP source code and header files to some extent.
When certain codes are found in a comment in the sources (e.g. @@), that
comment is assumed to document some function and will be considered for HTML
output.
Call createdoc.cmd in the main directory, which will create the HTML
documentation in a new subdirectory of the code tree HTML\. Open index.html
then to get an index of all XWorkplace source files.
ΓòÉΓòÉΓòÉ 5.9. The SRC\CLASSES\ directory ΓòÉΓòÉΓòÉ
SRC\CLASSES contains only C code which was originally generated by the SOM
compiler from the IDL files in the IDL\ directory. Of course, that code has
been extended so that the new classes do anything meaningful.
As opposed to versions before 0.9.0, this directory contains SOM code only. The
idea is that (except for fairly small method code) code in one of these class
files should call some implementation function in a directory other than
SRC\CLASSES. Only in doing so it is possible that several developers can
implement features within the same WPS class.
For example, src\classes\xfldr.c branches over to src\filesys\folder.c, which
is the "folder implementation" code and has most of the folder features.
The XWorkplace package contains many classes, but puts them all into a single
DLL. This is possible by specifying the same target DLL in the IDL files.
(XWorkplace's IDL files are now in the separate IDL\ directory.) One can put
several classes into one .IDL file (which happens in xtrash.idl for example) or
spread them across several IDL files too.
Note that the .DEF files in IDL\ are not used. These files are created
automatically by the SOM compiler, which cannot however create a single DEF
file if you use several IDL files for the same DLL. For finally linking the
whole main DLL, the makefiles instead use \src\shared\xwp.def, which I manually
created from all the DEF files which were created by the SOM compiler. This
file exports lots of mysterious SOM structures which allow the SOM kernel see
the classes in the DLL.
ΓòÉΓòÉΓòÉ 5.10. The SRC\HELPERS\ directory ΓòÉΓòÉΓòÉ
SRC\HELPERS contains lots of useful code which I have developed over time. This
code is independent of XWorkplace and could be used with any OS/2 program. Some
of the code is for PM programs, some can be used with text-mode programs also.
Consider this a general OS/2 programming library.
Note: XWorkplace's source code does not contain the helpers source code.
Instead, during the build process, the XWorkplace makefiles branch over to the
"xwphelpers" source tree, which is also on the Netlabs CVS server. You will
need to set the HELPERS_BASE environment variable to point to the "xwphelpers"
source tree for this to work.
In detail, we have:
animate.* contains some animation code.
cnrh.* Container helper functions (new with V0.9.0, partly moved from
winh.*).
comctl.* Various window procedures.
debug.* parses executables and SYM files for debugging information; used
by except.c (below). Introduced with V0.84, moved to SRC\HELPERS\ with
V0.9.0.
dosh.* Control Program helper functions.
eas.* contains helper functions to handle extended attributes.
except.* contains generic code for implementing powerful exception
handlers. This was introduced with V0.84 and has been moved to
SRC\HELPERS\ with V0.9.0. The code has been straightened out to be
independent of XWorkplace with the use of exception "plug-ins". See
"XWorkplace exception handling" for details.
gpih.* GPI (graphics) helper functions.
linklist.* contains helper functions to handle linked lists.
prfh.* is new with V0.82 and contains Profile (INI) helper functions.
procstat.* modified Kai Uwe Rommel's DosQProc() functions.
shapewin.* contains the ShapeWindows library. See the top of shapewin.c
for details (new with V0.85).
stringh.* contains helper functions to handle strings/texts
syssound.* has code for managing system sound data and sound schemes.
threads.* contains helper functions to synchronize threads.
tmsgfile.* has Christian Langanke's new .TMF (text message file) handling
to get rid of those ugly .MSG files.
winh.* Win (PM) helper functions.
wphandle.* Henk Kelder's WPS handles functions.
ΓòÉΓòÉΓòÉ 5.11. XWorkplace Function Prefixes ΓòÉΓòÉΓòÉ
XWorkplace uses function prefixes to indicate in which source file a certain
function resides. XWorkplace function prefixes are in lower case to distinguish
them from the OS/2 API function prefixes. So if you encounter some lower-case
function prefix, you can be pretty sure it's some function in MAIN or HELPERS
and has been prototyped in the corresponding header file.
If a function has no prefix, it's probably in the same source file and not
prototyped in the headers.
However, there are two general function prefixes which are used to indicate
certain function types:
fnwp* is my general prefix for window procedures (the MRESULT EXPENTRY...
type), which may or may not be exported.
fncb is my general prototype for callback functions. Most of these are
callbacks for the notebook helpers in shared\notebook.c, but there are
some for functions in HELPERS also. See the respective function header
then.
Here are the other function headers and the files where their code resides:
anm* helpers\animate.*
apm* startshut\apm.*
arc* startshut\archives.*
cfg* config\cfgsys.*
cls* config\classlst.*
cmn* shared\common.*
cnrh* helpers\cnrh.*
ctl* helpers\comctl.*
dtp* filesys\desktop.*
dosh* helpers\dosh.*
dsk* filesys\disk.*
ea* helpers\eas.*
exc* helpers\except.*
fdr* filesys\folder.* or filesys\fdrhoty.*
fops* filesys\fileops.*
fsys* filesys\filesys.*
ftyp* filesys\filetype.*
gpih* helpers\gpih.*
hif* config\hookintf.*
krn* shared\kernel.*
lst* helpers\linklist.*
mnu* filesys\menus.*
ntb* shared\notebook.*
obj* filesys\object.*
prfh* helpers\prfh.*
prc* helpers\procstat.*
shp* helpers\shapewin.*
snd* helpers\syssound.* or filesys\sound.*
stb* filesys\statbars.*
strh* helpers\stringh.*
thr* helpers\threads.*
tmf* helpers\tmsgfile.*
wph* helpers\wphandle.*
wpsh* shared\wpsh.*
xsd* startshut\shutdown.*
xthr* filesys\xthreads.*
xwp* newly introduced SOM instance methods in SRC\CLASSES
xwpcls* newly introduced SOM class methods in SRC\CLASSES
ΓòÉΓòÉΓòÉ 5.12. Debugging XWorkplace ΓòÉΓòÉΓòÉ
Debugging WPS applications can be really tiresome, because you have to restart
the WPS for every tiny change you made to the source codes to take effect. And,
as with any PM program, you can't just printf() stuff to the screen. Even
worse, it's hard to use the PM debugger, because you have to start the whole
WPS (PMSHELL.EXE) with it, since XFLDR.DLL is no standalone application.
So I had to look for something else.
To enable the debug build, set XWP_DEBUG in config.in. Again, mind the warnings
given there. Of course, you will then have to cause a complete rebuild by
deleting the bin\ directory.
Enabling the debug code has a large number of consequences:
1. Since in debug mode, the __DEBUG__ define is passed on the compiler
command line, many other parts of the code can react to that. For
example, you will find a few interesting new items in the Desktop's
context menu, such as "Crash WPS" to test the exception handlers.
2. Depending on whether __XWPMEMDEBUG__ is uncommented at the bottom of
include\setup.h, all memory management functions will be replaced by
debug versions which give you very detailed logs of all memory that was
ever allocated. See memdebug.c in the helpers for details. This will also
produce an additional Desktop context menu item which will open a PM
window with lots of information.
3. There are a large number of _Pmpf(("xxx")) calls in the code. These are
for the magnificent PMPRINTF package by Dennis Bareis.
Some files from the PMPRINTF package are included so that you can
compile. The PM interface which actually displays the messages plus the
required DLLs which must be on the LIBPATH are not however. Last time I
checked (March 13, 2001), this package was available at
http://www.labyrinth.net.au/~dbareis/zips_fw/pmf96179.zip.
These calls only display anything if the proper DEBUG_xxx #define's are
set in include\setup.h (changed with V0.9.0). You can conditionally
enable groups of debugging flags in there, but some of them haven't been
tested in a long while and might cause compilation errors.
For the release version of XWorkplace, all these flags have been
disabled, so no additional code is produced at all. You thus don't have
to remove the commands to speed up XWorkplace, because this wouldn't make
any difference.
_Pmpf(("xxx")) uses regular printf syntax, except for those strange
double brackets, which are needed because macros don't accept variable
parameter lists otherwise.
ΓòÉΓòÉΓòÉ 6. Source Code Details ΓòÉΓòÉΓòÉ
XWorkplace settings
Folder window subclassing
Menu manipulation
Extended sort functions
XWorkplace threads
Playing sounds
XShutdown
XWorkplace exception handling
ΓòÉΓòÉΓòÉ 6.1. XWorkplace Settings ΓòÉΓòÉΓòÉ
XWorkplace uses two kinds of settings: global and instance settings.
The global settings are set both in the "Workplace Shell" object and on the
"XDesktop" notebook page and are stored in the "XWorkplace" app in OS2.INI. All
the global notebook logic is in src\shared\notebook.c.
Note that the large structure called GLOBALSETTINGS that was used from XFolder
0.1 until XWorkplace 0.9.16 is gone now. Yes, it almost broke my heart, but I
got sick of it. Instead, global settings are implemented via cmnQuerySetting
and cmnSetSetting in src\shared\common.c now.
By contrast, the individual object settings are stored in instance data, which
is declared in the .IDL files. Most of these are stored and retrieved using the
normal WPS mechanism (wpSaveDeferred/wpRestoreData) and can have a certain
"transparent" value, which means that the global setting is to be used instead.
ΓòÉΓòÉΓòÉ 6.2. Subclassing Folder Windows ΓòÉΓòÉΓòÉ
XWorkplace subclasses all WPFolder frame windows to intercept a large number of
messages. This is needed for the majority of XWorkplace's features, which are
not directly SOM/WPS-related, but are rather straight PM programming.
For an introduction to how this works, see the top of src\folder\fdrsubclass.c.
ΓòÉΓòÉΓòÉ 6.3. Menu Manipulation ΓòÉΓòÉΓòÉ
This is perhaps the most complex part of XWorkplace. After all, this is what
I've started with, so some code parts may well be unchanged since December '97,
when I neither knew much about C nor about WPS programming.
With V0.81, all the logic for manipulating and evaluating context menus has
been moved to a new file, menus.c. All these functions have been given the mnu*
prefix to make this a bit clearer.
The XWorkplace classes override wpModifyPopupMenu and wpMenuItem[Help]Selected
for almost every replacement class. These overrides either handle the new
context menu items in that method code or, for XFolder and XFldDisk, call the
functions in menus.c, because these two classes share many common menu items,
so we can share most of the code also.
All newly inserted menu items use variable menu IDs. You can tell this from
their #define names, which have an _OFS_ in their name (check dlgids.h). To all
these values, XWorkplace adds the offset that is specified on the "Paranoia"
notebook page.
For an introduction to how the config folder menu items work, see the
"XWorkplace Internals" section in the XWorkplace User Guide. XWorkplace uses a
fairly obscure system of global variables to be able to relate menu items to
their intended functions. All the variable menu items are stored in a global
linked list when the context menu is opened for a folder. In each list item,
XWorkplace also stores what kind of object (template, program object, folder
content item etc.) the menu item represents. This list is then examined by
wpMenuItemSelected to perform the corresponding action (create a new object,
start program etc.). After that, the list is destroyed, so it only eats up
memory while the context menu is open. All this code is now (V0.81) in menus.c.
As opposed to the "regular" new menu items, the folder content menus are
initially only inserted as empty submenu stubs. They are only filled with items
when they're opened: XWorkplace intercepts WM_INITMENU in the subclassed folder
frame proc (fnwpSubclassedFolderFrame, src\filesys\folder.c) and then populates
the menu. These menu items are stored in the global list too and marked as
folder content menu items so that wpMenuItemSelected will then simply open the
corresponding Desktop object. The folder content code has now been moved to
menus.c also.
Painting the icons is then done using owner-draw menu items; the messages which
are necessary for this are also intercepted in fnwpSubclassedFolderFrame and
then call corresponding functions in menus.c.
The folder content menu windows are also subclassed to be able to intercept
right-mouse button clicks. The new window proc for this is called (suprise!)
fnwpFolderContentMenu.
The xfSelectingMenuItem method introduced in V0.80 has been removed again with
V0.81 due to the problems with SOM multiple inheritance.
ΓòÉΓòÉΓòÉ 6.4. Extended Sort Functions ΓòÉΓòÉΓòÉ
Folder sorting has been mostly rewritten with V0.9.12, and the documentation
for this can be found in src\filesys\fdrsort.c.
ΓòÉΓòÉΓòÉ 6.5. XWorkplace Threads ΓòÉΓòÉΓòÉ
XWorkplace is quite heavily multi-threaded and offloads most tasks which are
probable to take some time to several threads which are always running in the
background. Those threads create object windows and are thus normally blocked,
unless there's real work to do. XWorkplace uses mutex semaphores all over the
place to serialize access to global data structures.
With V0.9.0, all the thread code has been put into a new file, called
src\filesys\xthreads.c.
All threads are created in krnInitializeXWorkplace (src\shared\kernel.c), which
gets called from M_XFldObject::wpclsInitData, which is probably the first SOM
method called when the WPS is initializing at startup.
All threads have some fntXXXThread function, which is the main thread function
passed to the thr* functions in /helpers/threads.c when the thread is created.
These in turn create an object window using some fnwpXXXObject function as
their window procedure.
For each thread, we then have some krnPostXXXMsg function which posts a message
to the corresponding object window. All messages are defined and explained in
include\filesys\xthreads.h.
The following additional threads are available:
The Worker thread is running with idle priority and does mainly
maintenance which is not time-critical.
For example, the Worker thread maintains the global linked list of
currently awake Desktop objects. XFldObject::wpObjectReady post
WOM_ADDAWAKEOBJECT to the Worker thread, which then adds the object to
that list. (This list is needed by XShutdown to store all the awake
Desktop objects; see the XWorkplace User Guide for details).
The Worker thread runs at "Idle" priority, unless more than 300 messages
have piled up in its message queue. In this case, the priority is
temporarily raised to "Regular" and set back if the message count goes
below 10 again. This can happen when opening folders with a very large
number of objects.
The "Speedy" thread is running at a high "Regular" priority for things
which won't take long but should not block the main WPS (Workplace)
thread. This thread creates an object window also. For example, the new
system sounds are played here, and the Desktop start logo is shown.
The "File" thread is new with V0.9.0 and runs with regular priority, that
is, concurrently with the WPS user interface. This now does file
operations, such as moving objects to and emptying the trash can and
such. This thread will probably get more jobs in the future.
ΓòÉΓòÉΓòÉ 6.6. Playing Sounds ΓòÉΓòÉΓòÉ
The new system sounds are played in the "Speedy" thread with high regular
priority. Check fntSpeedyThread and fnwpSpeedyObject for details about how this
is implemented using MMOS/2.
Unfortunately, nowhere is documented how to access and modify the system sounds
that appear in the "Sound" object. I have accidently discovered that this is
actually fairly easy: these are stored in MMPM.INI in the MMOS/2 directory.
Each sound has an index in that file, which I have declared in common.h (those
MMSOUND_* #define's). These should be the same on every system. The INI data
then contains a "<soundfile>#<description>#<volume>" string.
Sound data manipulation has been moved into a separate file with V0.9.0: check
/helpers/syssound.c for details. This now also supports sound scheme
manipulation.
To make sure that the actual sound playing (which requires MMPM/2) also works
on systems where MMPM/2 is not installed, XWorkplace dynamically imports the
functions from the MMPM/2 DLLs. See src\media\* for details.
ΓòÉΓòÉΓòÉ 6.7. XShutdown ΓòÉΓòÉΓòÉ
XShutdown (i.e. the "eXtended Shutdown" and "Restart Desktop" features) resides
entirely in the src\startshut\shutdown.c file.
XShutdown starts two additional threads to close all the windows. This is
described in detail in the "XWorkplace Internals" section of the XWorkplace
User Guide. I have also tried to put plenty of comments into the sources.
ΓòÉΓòÉΓòÉ 6.8. XWorkplace Exception Handling ΓòÉΓòÉΓòÉ
XWorkplace registers additional exception handlers in certain parts where I
considered worth it.
With "worth it" I mean the following situations:
1. Certain code parts crashed on my system and these parts seemed
error-prone enough to me to outweigh the performance loss of registering
and deregistering exception handlers.
2. Exception handlers must be registered for all additional threads. If no
exception handling was registered there, crashes would take the whole WPS
down, because the default WPS exception handler only deals with the
default WPS threads.
3. Exception handlers must also be registered every time mutex semaphores
are used. If a code part crashes while a mutex semaphore has been
requested by a function, all other threads waiting for that semaphore to
be released will be blocked forever. And I mean forever, because even
DosKillProcess won't be able to terminate that thread. You'd have to
reboot to get out of this. So the exception handler must always check for
whether a mutex semaphore is currently owned by the thread and, if so,
release it.
XWorkplace does not use the VAC++ library funcs for all this, but installs its
own set of quite complex exception handlers (using DosSetExceptionHandler()).
The code for exception handlers has been made independent of XWorkplace and
moved to /helpers/except.c with V0.9.0.
Also, I have created a few handy macros which automatically register and
deregister the XWorkplace exception handlers. This avoids the frequent problem
that one forgets to deregister an exception handler, which leads to really
awkward problems which are almost impossible to debug. Those macros are called
TRY_xxx and CATCH to mimic at least some C++ syntax. See the top of
src\helpers\except.c for detailed instructions how to use these.
The XWorkplace exception handlers are the following:
excHandlerLoud is the one that makes the loud sounds and writes the
XFLDTRAP.LOG file which is well-known to many XWorkplace users (grin). It
uses a longjmp() to get back to the function, which might then react to
that exception by trying to restore some safe state of the thread. See
the func header for details about how this works.
This handler is used by all the additional XWorkplace threads and also by
the subclassed folder frame and folder content menu window procs. This
slows down the system a bit because the handler must be registered and
deregistered for each message that comes in, but there's no other way to
do this. (I think.)
With V0.84, I have added lots of debugging code which I found in the
EXCEPTQ.ZIP package at Hobbes. The exception handlers are now capable of
finding symbols either from debug code (if present) or from a SYM file in
order to write more meaningful trap logs. See the top of except.c for
details.
excHandlerQuiet is similar to excHandlerPlus in that it uses a longjmp()
also, but neither is this reported to the user nor is the logfile written
to (that's why it's "quiet").
This is used in places where exceptions have ben known to occur and
there's no way to get around them. I created this handler for V0.80
because I found out that somIsObj() is not a fail-safe routine to find
out if a SOM pointer is valid, even though IBM claims it is.
(These were the strange errors in the Worker thread which appeared in
V0.71 when folders with subfolders were deleted, because the Worker
thread then tried to access these objects when the folder was populated
right before deletion.)
So I created the wpshCheckObject func which can return FALSE, using this
handler, if access to the object fails.
ΓòÉΓòÉΓòÉ 7. Adding Features to XWorkplace ΓòÉΓòÉΓòÉ
Overview
Adding a new class
Extending existing XWorkplace classes
The "XWorkplace Setup" object
XWorkplace code you might find useful
Writing an XCenter widget plugin DLL
ΓòÉΓòÉΓòÉ 7.1. Overview ΓòÉΓòÉΓòÉ
This section describes how you can integrate your own code into XWorkplace.
Since XWorkplace is now a Netlabs project on the Netlabs CVS server, certain
rules must be followed so that the whole thing still works even though several
developers might be adding stuff.
With XWorkplace V0.9.0, I have restructured the whole directory and makefile
system to allow for extending XWorkplace. In any case, the idea is that all
XWorkplace classes will reside in one single DLL, XFLDR.DLL, but should be
capable of being registered independently.
Basically, there are two situations which you need to tell apart:
1. You can add a new class to XWorkplace. That is, you wish to hook your
code into the WPS, but XWorkplace doesn't have a class for this yet. This
situation applies both if you wish to replace a standard WPS class
(example: the spooler class, WPSpool) which XWorkplace doesn't replace
yet, or if you wish to create an all new class. (This only makes a
difference at install time, whether the install program will replace a
class.)
2. You may choose to extend an existing XWorkplace class (either an
XWorkplace replacement for a default WPS class, e.g. XFolder, or a newly
introduced XWorkplace class, e.g. XFldWPS -- the "Workplace Shell"
object). This is much simpler, because you can build on existing code.
ΓòÉΓòÉΓòÉ 7.2. Adding a New Class ΓòÉΓòÉΓòÉ
This section describes what to do if you want to write some all new SOM WPS
class, which should be integrated into the main XWorkplace DLL, and describe
which files need to be changed to have your stuff compiled into the whole
thing.
1. Most importantly, I suggest that you put all your code into a separate
source directory in the XWorkplace SRC\ and INCLUDE\ directory trees.
Please do not put your stuff into SRC\FILESYS, because this will make it
pretty difficult to maintain order. For the purpose of explanations here,
I will assume that your directory is called SRC\YOURDIR\ and your class
is called XWPYourClass.
So first of all, create your two subdirectories (YOURDIR) in INCLUDE and
SRC.
2. Create a new IDL file for your class. As a template, you can use
idl\__sample_dataf.idl, which is a sample for a WPDataFile subclass.
Put your new IDL file into the idl\ directory and modify the makefile in
there to recognize your IDL file. That is, add your header file to the
all: statement and add a corresponding line to the bottom. That's all.
And please, add a comment that you did so.
For the purpose of clarity, I suggest that with your IDL file, you take
one of the existing IDL files as a template. My IDL coding style has
evolved during the last two years, and I now consider the comments etc.
in there pretty lucid in order not to forget anything. Of course, if you
have something better, go ahead.
3. Run the main makefile once. The makefile in idl\ will realize that a new
.IDL file has been added and create headers in include\classes\, a .DEF
file in idl\, and stub C code in src\classes\.
4. Now that you have the stub C file in src\classes, modify the makefile in
src\classes to compile your stub file as well. Add your file to the OBJS
macro, and add dependency rules in the $(OUTPUTDIR)\xxx.obj: style to the
bottom. Again, add a comment that you did so.
5. In SRC\YOURDIR\, write your own makefile which compiles your sources. You
can take the makefile in SRC\FILESYS\ as a template. This makefile is
pretty smart because it automatically recognizes whether it is called
from the main makefile, and if not, it invokes the main makefile, which
in turn will call the sub-makefiles later. Also, that makefile uses the
general makefile include setup.in in the main directory for compiler
setup etc.
Make sure that your makefile writes all .OBJ files into the BIN
directory, which your makefile must create if it doesn't exist yet.
Again, see how the makefile in SRC\FILESYS does this.
Other than that, in SRC\YOURDIR, do whatever you want.
6. Coding. For your C code, make sure that you get the #include's right.
Take a look at any C file in SRC\FILESYS for examples (folder.c is a good
candidate, because it's fairly complex). If you use any headers from
include\shared\, there are certain rules that you must follow, because
these headers require other headers to be included already.
Also, I strongly recommend to always include include\setup.h, because
this will automatically make your code PMPRINTF-enabled.
I don't care about your coding style, but if you want your code to be
documented automatically, you should follow mine, because otherwise
xdoc.exe won't work. See Code documentation for details.
7. Note that the SOM compiler is unable to recognize that several classes
should be put into the same DLL and create a common .DEF file for this
purpose, so you have to do this manually.
So have the SOM compiler create a .DEF file for your class from your .IDL
source file. (The makefile in idl\ will do this automatically if you have
added your header to the all: target.)
Then take the block below the EXPORTS line from the .DEF file and add it
to the bottom of src\shared\xwp.def (which is the module definition file
used for linking the whole XWorkplace DLL). These structures make the SOM
kernel see your class in the DLL. If you don't do this, your class cannot
be registered.
8. Finally, take a look at \makefile. This is the "master makefile" which
links all .OBJ modules into the main XWorkplace DLL (XFLDR.DLL). In that
makefile, there is an OBJS macro which lists all the .OBJ files which are
to be linked together.
Add your .OBJ file(s) to the end of that variable (and please, add a
comment that you did so).
This should work. If you have any questions, feel free to contact me.
ΓòÉΓòÉΓòÉ 7.3. Extending Existing XWorkplace Classes ΓòÉΓòÉΓòÉ
This section describes what to do if the class that you need already exists in
XWorkplace. Of course, this requires less setup work, because much of the work
has already been done.
1. If you need a new WPS method which isn't overridden yet, modify the IDL
file in IDL\ to suit your needs.
If the method you need is already overridden by XWorkplace, go to 3.
2. If you then re-make XWorkplace, the SOM compiler will automatically get
invoked and modify the sources in SRC\CLASSES and the headers in
INCLUDE\CLASSES accordingly.
3. Again, as said on the previous page, add your own directory to INCLUDE
and SRC. Modify the SOM code of the class you need in SRC\CLASSES to call
your implementation in your SRC\YOURDIR directory.
4. You will need to add your header from INCLUDE\YOURDIR to the SOM class
code file that you modified. Please think of some useful function prefix
for your exported functions so that other programmers (including me) can
find your code more easily.
Don't forget to update src\classes\makefile so that the class code file
will be made dependent on your new header (which you have added to the
SRC\CLASSES code).
5. In SRC\YOURDIR\, write your own makefile which compiles your sources. You
can take the makefile in SRC\FILESYS\ as a template. This makefile is
pretty smart because it automatically recognizes whether it is called
from the main makefile, and if not, it invokes the main makefile, which
in turn will call the sub-makefiles later. Also, that makefile uses the
general makefile include setup.in in the main directory for compiler
setup etc.
Make sure that your makefile writes all .OBJ files into the BIN
directory, which your makefile must create if it doesn't exist yet.
Again, see how the makefile in SRC\FILESYS does this.
Other than that, in SRC\YOURDIR, do whatever you want.
6. Finally, take a look at \makefile. This is the "master makefile" which
links all .OBJ modules into the main XWorkplace DLL (XFLDR.DLL). In that
makefile, there is an OBJS macro which lists all the .OBJ files which are
to be linked together.
Add your .OBJ file(s) to the end of that variable (and please, add a
comment that you did so).
ΓòÉΓòÉΓòÉ 7.4. The "XWorkplace Setup" Object ΓòÉΓòÉΓòÉ
If you have added new code to XWorkplace, you might wonder how to integrate
your code into the "XWorkplace Setup" object, most notably, how to add stuff to
the "Features" container.
This is pretty easy. The "Features" page uses a subclassed container (the code
for those checkboxes is in helpers\comctl.c, but this you need not worry
about). All you have to do is take a look at src\shared\xsetup.c. The
setFeaturesInitPage function is responsible for initializing the container with
the features, while the setFeaturesItemChanged function reacts to selection
changes in the container.
To add something, perform the following steps:
1. Add a dialog item ID to include\dlgids.h, where all the other items of
this kind are (search for ID_XCSI_GENERALFEATURES to find them).
2. Add a string for your setting to the NLS strings (e.g. for English, to
001\xfldr001.rc), using that ID.
3. Add your ID to the FeatureItemsList array in src\shared\xsetup.c. Your
item will then automatically get inserted into the container by
setFeaturesInitPage.
4. Still, in setFeaturesInitPage, you need to add a line which checks the
container checkbox according to the setting (those
ctlSetRecordChecked(hwndFeaturesCnr ... lines).
5. In setFeaturesItemChanged, add a case/switch which reacts to user
changes.
ΓòÉΓòÉΓòÉ 7.5. XWorkplace Code You Might Find Useful ΓòÉΓòÉΓòÉ
This section should help you identify XWorkplace code sections which might also
be useful to you.
1. This applies mostly to the code in the HELPERS directory. All of that
code is not dependent on XWorkplace and could be used in any program.
There are lots of Control Program, Presentation Manager and GPI helper
functions which might solve problems that you are having.
To use the helper funcs, simply add #include "helpers\xxx.h" at the top
of your code. See the top of the respective header for additional
#include's which are required by the helper.
2. There are some functions in src\shared\common.c which might be useful to
you, most notably to query some XWorkplace settings and NLS stuff.
cmnQuerySetting will return a global setting, for example, or
cmnMessageBox will display one of the pretty XWorkplace message boxes.
3. To find out how to create a WPAbstract class from scratch, including a
completely new view defined by your class (like the "Class list view"),
you can take a look at xclslist.idl and xclslist.c, which do exactly
this. See the comments in that file for instructions.
4. To create a new settings object (which is not derived from WPSystem),
take a look at XWPSetup, a direct subclass of WPAbstract, which is
implemented this way.
5. For easier maintenance of notebook dialog procs, I have created
src\shared\notebook.c, which does just this using callbacks, so you don't
have to rewrite the same stupid window procedures for each notebook page.
This is used throughout XWorkplace's source code whenever settings pages
are inserted, and has proven to be extremely useful.
6. Finally, src\shared\kernel.c contains code which you can extend for
certain tricky situations. For one, you can extend
krnInitializeXWorkplace to have code executed upon Desktop startup;
secondly, you can add messages to krn_fnwpThread1Object if you need code
to absolutely always execute on thread 1 of PMSHELL.EXE, which cannot be
guaranteed with open views of any kind (especially folder views).
ΓòÉΓòÉΓòÉ 7.6. Writing an XCenter Widget Plugin DLL ΓòÉΓòÉΓòÉ
You can write independent plug-in DLLs for the XCenter to implement XCenter
widget classes. This saves you from dealing with all the WPS programming
details and even from having to compile the rest of XWorkplace.
Detailed documentation for writing plug-in DLLs has been added to the
XWorkplace User Guide with V0.9.9. Please see that documentation for details.
Still, since you have obviously downloaded the XWorkplace source code, if you
are interested, I strongly suggest that you create the XWorkplace code
documentation. Then, in the HTML files which are generated, look for the
documentation for src\shared\center.c documentation which gives you plenty of
introductory information.
Several standard XCenter widgets have been created as plugin DLLs to show you
how this can be done. Their sources are in the src\widgets directory. In that
directory, you will also find ____sample.c, which you can use as a template for
your own widgets.
ΓòÉΓòÉΓòÉ 8. Miscellaneous WPS Programming Hints ΓòÉΓòÉΓòÉ
Some SOM tricks
ΓòÉΓòÉΓòÉ 8.1. Some SOM Tricks ΓòÉΓòÉΓòÉ
In general, XWorkplace is pretty straightforward SOM/WPS code. It overrides a
lot of wp* and wpcls* methods.
In order to avoid too much confusion, the methods which XWorkplace adds do not
carry the usual wp* and wpcls* prefixes, but xwp* and xwpcls* instead. Only
"real" XWorkplace SOM methods have this prefix; "normal" functions have other
prefixes (see the previous page for a list).
As XWorkplace became more complex over time, I have delved quite deeply into
SOM. While I still don't fully understand what is going on in the SOM kernel
(from what I hear, I guess nobody does) and some bugs in there keep puzzling
me, I've found out some interesting stuff.
Note: The following is not required to write WPS classes. This is additional
information for those who have written WPS classes already and might be
interested in some SOM internals.
Most of this is related to the "WPS Classes" object (xclslist.c). The SOM logic
for this is in classlst.c in clsWPSClasses2Cnr, which can analyze the current
SOM runtime environment (which is that of the WPS), i.e. all the classes that
have been loaded and query their inheritance hierarchy at runtime.
This inserts the WPS class tree as recordcores into a given cnr control. This
works with any containers in tree views, so that some XWorkplace dialogs can
use this too. Check the sources, there's some interesting stuff.
Note that there are quite a number of functions in XWorkplace which take SOM
(WPS) objects as a parameter, even though they are not SOM methods. See
src\shared\wpsh.c for examples. The reason for this is that resolving SOM
methods takes quite a bit of time, and calling regular functions will work just
as well, but faster.
If you look into the .IH header files created by the SOM compiler, you see that
the C bindings for method calls are really all macros #define'd in the header
files which translate into more complex C code.
Here's an example: if you call _wpQueryStyle(somSelf) in xfldr.c, where this
method has not been overridden, the WPObject version of this method should get
called. Here's the #define in xfldr.ih for this:
#define XFolder_wpQueryStyle WPObject_wpQueryStyle
And WPObject_wpQueryStyle is #define'd in wpobject.h from the toolkit headers
as follows:
#define WPObject_wpQueryStyle(somSelf) \
(SOM_Resolve(somSelf, WPObject, wpQueryStyle) \
(somSelf))
Actually, there are more macros related to this, but this is the important one.
SOM_Resolve in turn is a macro #define'd in somcdev.h, which calls the SOM
kernel function somResolve. That function finally goes through the class method
tables to find the actual function address and call it.
As as result, not only does compiling of SOM code take ages (because of all the
nested macros), but also calling SOM methods does, because as opposed to
"static" OO languages such as C++, method resolution is occuring at run-time.
IBM says in the SOM docs that calling a SOM method takes at least three times
as long as calling a normal C function.
Since there is no real need to write functions as SOM methods, except when you
want to design a method which can be overriden in subclasses, I have only done
so in rare occasions to speed up processing.
Here are some other SOM tricks and functions which are not mentioned directly
in the WPS reference (but only in the chaotic SOM docs), but these are very
useful. Some of this is pretty basic, some might be new to WPS programmers, so
I'll list this here:
Since all the SOM stuff is declared in those huge header files, you need
to #include a header file if you need access to certain class-specific
features.
For example, if you write a subclass of WPDataFile and need some
program-object method call (e.g. _wpQueryProgDetails), you need to put
#include <wppgm.h> on top of your code, or the method binding will not be
found.
This is not neccessary if the method is defined for a superclass of your
class, because the SOM headers automatically #include all the parent
classes. That is, for example, you don't need to #include wpfsys.h (for
WPFileSystem) for your WPDataFile subclass.
The most important thing to keep in mind is that all SOM classes are
objects too. They are instances of their respective metaclasses. This
takes some getting used to, but it is this concept only which allows WPS
classes to be created at runtime and for class replacements in the first
place.
That is, for example, any Desktop object is an instance of WPObject
(really one of its subclasses). The WPObject class in turn is an instance
of its metaclass, M_WPObject.
In SOM, the default metaclass for a class is SOMClass. However, the WPS
overrides this behavior to create a unique metaclass for each WPS class,
which is prefixed with M_. Since the metaclass is a class as well, it has
methods too (the so-called "class methods", which operate on class
objects, as opposed to the "instance methods" of the class itself, which
operate on instances of the class -- the Desktop objects).
To access a class object, for any existing class you always have a
corresponding macro which is an underscore plus the class name. That is,
the class object of WPObject can always be obtained with _WPObject. This
is useful for calling class methods, which always need to be invoked on a
class object. So, to call a folder class method, you do something like
_wpclsQueryOpenFolders(_WPFolder).
Note: If a class has been replaced, the macro will not return the
original, but the replacement class. That is, if XWorkplace is installed,
the above example would actually return the XFldObject class object (see
notes below), and methods invoked on the WPObject class object would
actually be resolved for XFldObject. That's how class replacements work
in the first place. See the notes below for more.
BOOL _somIsA(pObject, pClassObject) checks for whether pObject is an
instance of the class specified by pClassObject or one of its subclasses.
This is extensively used in statbars.c to adjust status bar display
depending on the class of a single object which is currently selected.
Example: _somIsA(somSelf, _WPObject) should always be true within the WPS
context, since all WPS classes are subclasses of WPObject. By contrast,
_somIsA(somSelf, _WPFolder) would only return TRUE if somSelf is a WPS
folder. (This would work with _XFolder too, but this would require that
you have access to the XFolder header files and that XFolder replaces
WPFolder. _WPFolder always works, even if WPFolder is replaced, because
_WPFolder would be resolved to point to the replacement class object then
-- e.g. _XFolder.)
PSZ _somGetName(pClassObject) returns the class name specified by
pClassObject, as specified in the IDL file. (That is different from
wpclsQueryTitle.)
Example: _somGetName(_XFldObject) will return "XFldObject".
SOMClass* _somGetParent(pClassObject) returns a parent class.
Examples: _somGetParent(_WPProgram) returns the WPAbstract class object
(_WPAbstract). _somGetParent(_XFolder) should return _WPFolder, unless
there's some other WPFolder replacement class above XWorkplace in the
replacement list.
BOOL _somDescendedFrom(pClass, pClassParent) returns TRUE if pClass is
descended from pClassParent.
Examples: _somDescendedFrom(_WPFolder, _WPObject) should return TRUE.
_somDescendedFrom(_WPFolder, _WPProgram) would return FALSE.
somResolveByName(pClassObject, "method") gives you a function pointer as
implemented by the specified class. You should assign this to a function
pointer variable which matches the function prototype, or otherwise
you'll get crashes. This can be useful if you invoke a SOM method
frequently, for example in a loop on many objects, because then SOM
method resolution has to be done only once. If you used the macros,
resolution would take place for each iteration in the loop.
Class replacements. Nowhere is really documented how class replacements
actually work, except that replacement classes must be direct descendants
of the class which is to be replaced. I assume that class replacements
are a feature of the SOM class manager, of which the WPS class manager is
a descendant (WPClassManager is half documented in the WPS Reference.) At
least there is a documented SOMClassMgr method, somSubstituteClass, which
appears to be doing exactly this job.
From what I've seen, class replacements seem to work this way: Any time a
class object is queried, the class manager does not return the class
object of the specified class, but the object of the replacement class
instead. As a result, all the method calls are not resolved for the
original class, but for the replacement class instead.
Examples: If XFolder replaces WPFolder, wpModifyPopupMenu is not called
for WPFolder, but for XFolder instead, even though the WPS had originally
called it for a folder object. By contrast, for wpQueryIcon, which is not
overridden by XFolder, method resolution leads to the method as
implemented by the parent class, which should be WPFolder, unless some
other class replacements is present.
The class replacement mechanism is most obvious with the class object
macros described above: if you have a _WPFolder in your code, this
returns the class object of XFolder, i.e. _WPFolder == _XWorkplace. So if
you absolutely need the WPFolder class object (which is normally not
necessary, since this would circumvent XFolder's functionality), you use
_WPFolder (which returns the XFolder class object) and then climb up the
class object's inheritance tree using _somGetParent until _somGetName
returns "WPFolder".
To get the class object of any class without having access to its header
files, do the following:
somId somidThis = somIdFromString("WPObject");
SOMClass *pClassObject = _somFindClass(SOMClassMgrObject, somidThis, 0, 0);
Note again that _somFindClass will return replacement classes instead of
the originals. (That's how the class object macros work, BTW.)
__get_somRegisteredClasses(SOMClassMgrObject) returns a SOMClassSequence
of all currently registered class objects. This is used by the "WPS
classes" page in the "Workplace Shell" object. See classlst.c for
details.
ΓòÉΓòÉΓòÉ 9. Resources on the Internet ΓòÉΓòÉΓòÉ
This chapter contains all external links referenced in this book. Each link
contained herein is an Unified Resource Locator (URL) to a certain location on
the Internet. Simply double-click on one of them to launch Netscape with the
respective URL.
ΓòÉΓòÉΓòÉ 9.1. http://service.boulder.ibm.com/dl/ddk/priv/ddk-d ΓòÉΓòÉΓòÉ
Click below to launch Netscape with this URL:
http://service.boulder.ibm.com/dl/ddk/priv/ddk-d
ΓòÉΓòÉΓòÉ 9.2. http://www.edm2.com ΓòÉΓòÉΓòÉ
Click below to launch Netscape with this URL:
http://www.edm2.com
ΓòÉΓòÉΓòÉ 9.3. http://www.labyrinth.net.au/~dbareis/zips_fw/pmf96179.zip ΓòÉΓòÉΓòÉ
Click below to launch Netscape with this URL:
http://www.labyrinth.net.au/~dbareis/zips_fw/pmf96179.zip