home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 32 Periodic
/
32-Periodic.zip
/
edmi2-5.zip
/
EDMI2-5.INF
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1994-05-09
|
204KB
|
2,219 lines
ΓòÉΓòÉΓòÉ 1. May 1994 Title Page ΓòÉΓòÉΓòÉ
Welcome to EDM/2 - The Electronic OS/2 Developer's Magazine!
Portions copyright (c) by Larry Salomon Jr.
Volume 2, issue 5
Copyright Notice and Other Stuff
The Editor-in-Chief of this electronic magazine is Larry Salomon, Jr.
Portions of EDM/2 are copyrighted by the editors. This publication may be
freely distributed in electronic form provided that all parts are present in
their original unmodified form. A reasonable fee may be charged for the
physical act of distribution; no fee may be charged for the publication itself.
All articles are copyrighted by their authors. No part of any article may be
reproduced without permission from the original author.
Neither this publication nor the editors are affiliated with International
Business Machines Corporation.
OS/2 is a registered trademark of International Business Machines Corporation.
Other trademarks are property of their respective owners. Any mention of a
product in this publication does not constitute an endorsement or affiliation
unless specifically stated in the text.
Administrivia
Ah! I've been running around like a madman the past two weeks. So much has
happened that needs to be told that I doubt I will remember to tell it all.
First, the IBM PSP Technical Interchange in San Francisco (yes, I finally
spelled it correctly) was amazing. I was fortunate enough to meet so many
people, and many of the people I met told me they knew of, if not read
themselves, EDM/2. Of the many I met, I have to say that the best meets were
with Kathleen Panov (just because I coauthored a book with her doesn't mean
I've met her!), Tim Sipples, and Dave Whittle.
The sessions themselves were chocked full of useful information. Myself, I got
the most from Sheila Harnett's WPS Programming, and I hope to apply that to my
current work projects (and eventually write an article for EDM/2). There was a
Meet the Editors session where the editors of OS/2 Developer, OS/2 Magazine,
and OS/2 Professional talked a lot and answered questions; of course, yours
truly jumped in the conversation whenever possible to plug the magazine.
Throughout the week, I managed to distribute close to 100 flyers to people who
asked for one about the magazine, so if any of you are out there, welcome
aboard!
New Conquest Achieved
Also, I had the pleasure of meeting Janet Gobielle who graciously volunteered
to distribute EDM/2 on FidoNet. Onward to plunder and burn! <grin>
Things Desired
Recently in the comp.os.os2.programmer.misc newsgroup, a few people griped
about the need for sprite support. So, starting with this issue, there will be
a multi-part series on a completely modular, multithread-enabled library that
supports sprite of up to 128x128 pels in size. The library is already written
and even incorporated into a new version of Common/2 - soon to be released on
hobbes - so don't worry about this becoming an undoable project. <grin>
Credit Deserved
Since Carsten has been proofing the magazine since volume 2, issue 3 (although
I lost his changes for the last issue), I've decided it's time to start giving
him credit for his extra work beyond the call of duty; so, Carsten is now
officially the/an Associate Editor of the magazine. Congratulations on a job
well done!
More From the Credit Department
David Charlap, in his endless pursuit to open problem reports against OS/2
<grin> has notified me that APAR number PJ13781 has been created for the
problem of the Palette Manager samples (in volume 1, issue 1 of EDM/2) causing
PM to become unstable. Thanks, David!
ΓòÉΓòÉΓòÉ 2. Features for May 1994 ΓòÉΓòÉΓòÉ
The following articles constitute this issue's features:
o Sprites and Animation - Part 1
o Using SYSLEVEL Files in Your Applications
ΓòÉΓòÉΓòÉ 2.1. Sprites and Animation - Part 1 ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 2.1.1. Introduction ΓòÉΓòÉΓòÉ
Written by Larry Salomon, Jr.
Introduction
Some time ago, I posted an article to comp.os.os2.programmer.misc describing
how a friend and I wrote an animated demo application using home-grown sprite
routines. As I stated then, the routines were very tightly integrated into the
application; thus, they were not suitable for general availability. I received
a few requests to "clean them up" and since animation had been in the Want Ads
for some time, I decided to design and implement a sprite library. The result
is presented in i495.zip. This is a demonstration program that uses the sprite
library to simulate the Long Island Expressway on my trip to and from work. :)
This multipart series will go through the design and implementation of the
sprite library; additionally, its uses for animation will be briefly touched
upon. The reader is expected to be competent in PM application development as
well as have at least introductory knowledge to the Gpi subsystem. Any
background knowledge on animation techniques will be very helpful also.
A caveat: I intentionally left out the source code for the sprite library from
part 1 so that no one who doesn't already know this stuff will make any
incorrect assumptions about how the code works; the source will be included in
later parts of this series. In the meantime, you can enjoy using the SPRITE.H
and SPRITE.LIB files. :) The library was compiled using IBM C-Set++, so it is
a 32-bit library. It was not compiled for multithreaded applications, nor was
z-ordering implemented. By next month, I will have released a new version of
Common/2 (available at your nearest hobbes shadow) containing the sprite
subsystem and corresponding programming reference; unlike the remainder of the
library, however, I will make the source for this component available so do not
think that the usefulness of the series will be diminished.
Another caveat: the library was developed on my SVGA system at work; when
showing it to some fellow colleagues at the IBM PSP Technical Interchange on an
XGA system, the transparancy was - shall we say - overdone. A quick chat with
Kelvin Lawrence yielded nothing other than the SVGA drivers do not work
properly all of the time. I guess I broke the library so that it would work on
my SVGA screen. :)
ΓòÉΓòÉΓòÉ 2.1.2. Background ΓòÉΓòÉΓòÉ
Background
What is a sprite? The term dates at least as far back as the VIC-20 and refers
to a graphical object that is animated in some form or another; for performance
reasons, these sprites were typically bitmapped graphics. Since animation
often depicts everyday objects, and these objects have arbitrary (i.e.
non-rectangular) shapes, bitmaps - in the Gpi sense - cannot be used alone to
represent a sprite because they overpaint what is underneath. This wouldn't be
a problem normally except that bitmaps must be rectangular in shape.
Presentation Manager defines a resource called a pointer (for this discussion,
we will lump icons in this category since the only difference between the two
is the first two bytes in the file defining the pointer or icon), which has an
color which is transparent, i.e. the areas painted by this "color" show what
was underneath instead. Unfortunately for us, the size of the pointer is fixed
(its size can be determined using the WinQuerySysValue() function), making it
unsuitable for most animation (assuming we stick to documented functions for
drawing the pointer). If we were able to create a transparent "color" for our
bitmaps, we could have irregular shapes surrounded by transparency to make the
shape "rectangular". This is, then, our immediate goal; there are other
functions which will also be needed, but without the ability to draw a sprite
the remainder of the library is rather useless.
Let us begin by looking at the design of the library as well as the decisions
that were made and how they affect the implementation. My original intent for
the library was to have four functions:
o Create a sprite from a bitmap
o Destroy a sprite
o Draw a sprite
o Move a sprite
We must first explain the third for - speaking in hindsight - the
implementation of the drawing will affect the method of creation.
ΓòÉΓòÉΓòÉ 2.1.3. Blast From the Past ΓòÉΓòÉΓòÉ
Blast From the Past
I must confess that I learned the technique for drawing a sprite from Charles
Petzold's article series in the Microsoft Systems Journal where he developed a
game of checkers for OS/2. The checker pieces are irregular so he described
how to draw them and keep the underlying image intact where the piece was not
drawn. How is it done? Well, if you'll think back to the days of boolean
logic, you'll remember that the AND and OR functions have the following
properties:
x AND 1 = x
x OR 0 = x
If we require that all regions in the original bitmap that are to be
transparent must have the color black, we can use the OR function with the
target being x to implement the transparent portions. If we only do this,
however, the non-transparent portions of the bitmap will get OR'd with whatever
was underneath. Somehow, we need to insure that all portions on the target
where the original bitmap is not transparent are turned to black, so the OR
function will not alter the bitmap in any way.
Phantom of the Opera
To accomplish this, we need a second bitmap. Called a mask, it is a monochrome
bitmap which we combine with the target to change the portions of the target to
black as stated in the last paragraph. This is accomplished by making the
portions of the mask corresponding to the transparent areas white, and the
non-transparent areas black, and then AND'ing this mask with the target.
I realize this is quite confusing, so let's present an example of what is being
said. To the left is the original bitmap; to the right is the mask. Both are
surrounded by a light gray rectangle only for illustrative purposes.
We will paint the original bitmap on the following background, using black as
the transparency color, as described above.
First, we need to mask out the areas of the target where the image will be
painted. This is done using GpiBitBlt() with the ROP_SRCAND operation, and it
yields the following:
Finally, we paint the original bitmap on top of this using the ROP_SRCPAINT
operation (the equivalent of the OR function), yielding the following:
ΓòÉΓòÉΓòÉ 2.1.4. The Four Revisited ΓòÉΓòÉΓòÉ
The Four Revisited
To implement the create sprite from bitmap function, we need to also create a
mask which is associated with the bitmap. The application programmer should
not have to manage this and insure the proper mask is used with the
corresponding bitmap, etc., so the sprite data structure should keep track of
both.
When you look at the code, you'll think that it is rather trivial. However,
actually developing the code to its present state was a bit of work. Of course,
we have to have a memory device context and associated presentation space.
And, since we stated that the mask is a monochrome bitmap, we can call
GpiQueryBitmapInfoHeader() to get information about the original image, set
cPlanes and cBitCount to 1 and call GpiCreateBitmap() to create the bitmap.
This is then set into the presentation space.
Now comes the tricky part. How do you tell the GpiBitBlt() function to make
all black portions white and all non-black portions black? To quote an
extremely old piece of IBM documentation, the Programming Guide (page 24-7)
from the OS/2 1.2 Programmer's Toolkit:
o If you are copying a color bit map to a monochrome bit map or device, those
pels that have the same color as the current image-background color in the
source presentation space adopt the image background color of the target
presentation space. So, for example, if your current image background color
in the source presentation space is blue, all blue pels in the bit map take
on the color of the current image background in the target presentation
space.
All other pels in the color bit map adopt the current image-foreground color
of the target presentation space.
Unfortunately, I decided to use GpiWCBitBlt() instead of GpiBitBlt() for the
mask creation. Since there is no source presentation space it is difficult to
determine what will happen given the above text. I could not determine what
the rule is for GpiWCBitBlt() (since what I observed makes no sense), so either
the text is wrong, I am just being stupid, or we are seeing the broken SVGA
drivers in action. :) By trial-and-error I figured out that, in order to
create the mask, we call GpiSetColor(CLR_WHITE) and GpiSetBackColor(CLR_BLACK)
and then call GpiWCBitBlt() to actually initialize the mask bitmap.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Sprite destruction should be fairly trivial, and we have already discussed how
the sprites are drawn, so let's look at how they are moved.
The Quest to Avoid Flicker
When a sprite is moved, there are two scenarios to consider:
1. The bounding rectangle of the sprite at the old and new positions do not
overlap
2. The bounding rectangle of the sprite at the old and new positions overlap
The first case is trivial to implement - you paint the background over the old
position, and redraw in the new position. The second case, however, is not so
simple; if we treated the second case as the first, there is a noticeable
flicker in the regions that overlap. To avoid this, we need to insure that we
call GpiBitBlt() only once. This is accomplished using a work-area which is
another bitmap set in a presentation space associated with a memory device
context. The strategy is thus:
1. Determine the rectangle that bounds the bounding rectangles of the sprite
at the old and new positions.
2. Copy the background from the rectangle calculated in step 1 into the work
area.
3. Draw the sprite at the new position, relative to the old position.
4. Copy the contents of the work area to the screen presentation space.
Step 4 has the visible effect of both erasing the sprite at the old position
and redrawing it in the new position. This is a hybrid form of
double-buffering, which is defined to be the procedure by which the next
"frame" in a sequence is prepared off-screen while the first screen is being
displayed. The prepared screen is then displayed while the next frame is
prepared, and so on. The effect produced is much smoother than if the frames
were prepared on-screen, as you can imagine.
Note that the algorithm we used is only good when the overlapping is present.
Attempting to use this when there is no overlap could result is severely
degraded performance when you consider that the distance between the old and
new position could be quite a lot, making the area blit'd to the screen quite
large and CPU intensive in execution.
ΓòÉΓòÉΓòÉ 2.1.5. Summary ΓòÉΓòÉΓòÉ
Summary
In the last section, you probably noticed a few loose ends, namely the concept
of a background and the management of the work area used when moving the sprite
from one position to another. Next month, we'll tie up these loose ends with
the introduction of the playground; we will also start to look at the
implementation of i495.exe followed by the code for the library itself.
ΓòÉΓòÉΓòÉ 2.2. Using SYSLEVEL Files in Your Applications ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 2.2.1. Introduction ΓòÉΓòÉΓòÉ
Written by Martin Lafaix
Introduction
What's that?
Determining a computer software configuration has always been a tricky process.
It would be great to have a standard way for registering applications, so that
we could easily query the system configuration. But wait a minute! OS/2
provides the SYSLEVEL command, which does just that (it even tells us the
various component versions)! If only we could use it for our own purposes...
Why?
This registering ability proves its usefulness when writing (relatively) large
projects or components. For example, if you write a public toolkit or tools
other programs may use, it would be a good idea to register them. (OS/2 already
uses it this way: on my home system, the syslevel command tells me that MMPM/2
and the Developer's toolkit are present - the same thing occurs if you have
Communication Manager, etc.) When distributing such a tool, tell your users
your component name and ID; it would then be easy for them to write an
installation procedure which checks your component presence.
Another interest is that it helps component writers in creating CSD or
component updates. As each SYSLEVEL file maintains a current CSD level as well
as a previous CSD level field, it's easy to check what to update, and what to
leave alone.
It's also useful while maintaining a computer network. It would provide the
maintainer an up-to-date information database.
Contents
This article contains two parts. The first one describes the SYSLEVEL file
format. The second part describes the two proposed APIs (one for C, and one
for Rexx).
ΓòÉΓòÉΓòÉ 2.2.2. A Voyage to Syslevel ΓòÉΓòÉΓòÉ
A Voyage to Syslevel
When you start SYSLEVEL.EXE, it scans all your drives for SYSLEVEL files.
These files are named SYSLEVEL.xxx (where xxx is any three-letters extension),
and have a specific header. When one such file is found, it is displayed, as
shown in figure 1. So, to be able to use SYSLEVEL for our own purpose, we'll
have to decrypt SYSLEVELs' file headers, and find out how (and where) to store
our own data.
C:\MMOS2\INSTALL\SYSLEVEL.MPM
Multimedia Presentation Manager 2
Extensions systКme 1.10 ID de composant 562137400
Type MMPM\2
Niveau de modifications en cours : UN00000
Niveau de modifications antВrieur : UN00000
Figure 1. Syslevel output sample (French version, sorry :-) )
On the File Header
A SYSLEVEL file header looks like the following:
typedef struct _SYSLEVELHEADER {
unsigned char h_magic[2];
unsigned char h_name[9];
unsigned char h_reserved1[4];
unsigned char h_updated;
unsigned char h_reserved2[17];
ULONG h_data;
} SYSLEVELHEADER;
Figure 2. The SYSLEVELHEADER structure.
h_magic is the magic cookie. Its value is 0xFFFF.
h_name is the string "SYSLEVEL", in uppercase and null-terminated.
h_reserved1 meaning unknown. Set to zero.
h_updated was 1 for OS2, GRE and MPM, and 0 for TLK. My guess: set
it to zero.
h_reserved2 meaning unknown. Set to zero.
h_data points to the beginning of the file's data structure
(offset from the beginning of the file), which is described
below.
While I realize there's still many holes in there, it appears to fulfill our
needs; namely, we are now able to create files recognized by SYSLEVEL.EXE.
Isn't that great?
But it's time to learn more...
The SYSLEVEL Data Structure
In the previous section, we have seen that the file's data structure starts at
offset h_data. This structure (aka. the SYSLEVEL data structure) looks like
the following:
typedef struct _SYSLEVELDATA {
unsigned char d_reserved1[2];
unsigned char d_kind;
unsigned char d_version[2];
unsigned char d_reserved2[2];
unsigned char d_clevel[7];
unsigned char d_reserved3;
unsigned char d_plevel[7];
unsigned char d_reserved4;
unsigned char d_title[80];
unsigned char d_cid[9];
unsigned char d_revision;
unsigned char d_type[1];
} SYSLEVELDATA;
Figure 3. The SYSLEVELDATA structure.
d_reserved1 set to zero...
d_kind specifies the component "kind". It can be any of the
following:
SLK_BASE (0) "Base version"
SLK_EXTENSION (2) "System extension"
SLK_STANDARD (15) Neither "Base version" nor "System extension"...
:-)
Any other value is equivalent to SLK_STANDARD (except 1, which is equivalent
to SLK_EXTENSION).
d_version specifies the component version. Its format is a bit
strange: the four high-order bits of d_version[0] contains
the major version number, the four low-order bits contains
the first minor version digit, and d_version[1] contains
the second minor version digit.
For example, if d_version[0] is 0x21 and d_version[1] is
0x02, you will get "2.12".
[You can have a revision level, as in "2.12.a". See
d_revision below.]
d_reserved2 oh no, not again. Set to zero.
d_clevel specifies the current CSD level. It's a seven-byte string,
usually in the form "AAC####", where AA is a two-byte
string, C a country-dependent code, and #### a number. For
example, on my home computer, I get "XRF2010" for the base
operating system (It's the French version), and "XR02100"
for the developer's toolkit (US version, this time).
It's just a suggested usage and is not enforced in any way.
As long as you use seven printable characters, it should
work.
d_reserved3 guess what? You lose! Set to 0x5F this time.
d_plevel specifies the previous CSD level. If there was no previous
level; set it equal to the current level, d_clevel.
d_reserved4 is just like d_reserved3; set to 0x5F
d_title specifies the component name. It's a null-terminated
string.
d_cid specifies the component ID. It's not null-terminated.
d_revision specifies the component revision. It does not appear in
the version field if sets to zero. If it's not null, it
will be concatenated with major and minor version number,
as in "1.2.3" (where 1 is the major version, 2 the minor
and 3 the revision). If you prefer a letter in place of a
digit, just increment the revision number by 0x10 for an
upper-case letter, or by 0x30 for a lower-case. That is,
if d_revision is 0x11, you will get an "A", and so on.
d_type specifies the component type. It's an optional,
null-terminated string. This field allows you to store
additional informations for your component. For example,
this field is used to differentiate the blue and salmon
distribution of OS/2 (a type of '0-2' indicates the
'salmon' one).
Well, enough said on this exploration. It's time to go back to much safer
places...
ΓòÉΓòÉΓòÉ 2.2.3. Home, Sweet Home ΓòÉΓòÉΓòÉ
Home, Sweet Home
This walk was fun, but all good things must come to an end. So we are back.
And it's time to write some functions to comfort our precious new knowledge,
isn't it?
Two APIs are available, a C one and a REXX one.
The SYSLEVEL C API
This section describes the API which provides access to the syslevel files. The
corresponding code is in CLEVEL.ZIP. It's just an include file, level.h and a
small C file, level.c which can be included, say, in your favorite library. It
has been tested with GCC/2, but it should work with any other C compiler...
APIRET LvlOpenLevelFile(PSZ pszName, PHFILE phFile, ULONG ulOpenMode, PSZ
pszCID)
APIRET LvlCloseLevelFile(HFILE hFile)
APIRET LvlQueryLevelFile (PSZ pszName, PSZ pszCID, PVOID pBuffer, ULONG
ulBufSize)
APIRET LvlQueryLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG
ulBufSize, PULONG pulSize)
APIRET LvlWriteLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG
ulBufSize, PULONG pulSize)
Design considerations
This API has been modeled upon the profile (Prf) functions.
Examples
The following two figures show how to check for the existence of a component,
and if a component needs updating, respectively.
:
#include <level.h>
:
int main()
{
HFILE hFile;
:
if(hFile = LvlOpenLevelFile("DBM",
OLF_SCANDISKS | OLF_CHECKID,
"123456789"))
/* present */
:
else
/* not present */
:
:
LvlCloseLevelFile(hFile);
:
}
Figure 4. Syslevel API usage sample - Checking for the existence of a
component
:
#include <level.h>
:
BOOL _needUpdate(HFILE hFile)
{
CHAR achCSD[7];
ULONG ulCount;
if(LvlQueryLevelData(hFile, QLD_CURRENTCSD, achCSD, 7, &ulCount))
/* shall we update it? */
return strncmp(achCSD, "DBF0099",7) <= 0; /* for example */
else
/* an error occurred */
:
}
:
Figure 5. Syslevel API usage sample - Shall we update component?
The SYSLEVEL REXX API
Well, it's not really an API, it's in fact a single function. The
corresponding code is in RLEVEL.ZIP. It's just a REXX file, named REXXLVL.CMD.
Put it somewhere along your PATH. The zip file also contains MAKESYSL.CMD,
which can be used to create SYSLEVEL files.
This function has been modeled upon the STREAM function.
RexxLvl()
Example
The following example is a REXX script. It allows you to easily create
syslevel files.
/* makesysl.cmd 940327 */
say 'Component name:'; parse pull name
say 'Component ID:'; parse pull ID
say 'Component type (optional):'; parse pull type
say 'Component version (as x.y[.z]):'; parse pull version
say 'Current CSD Level:'; parse pull CSD
say 'Component extension:'; parse pull ext
file = RexxLvl("n", ext, ID)
call RexxLvl "s", file, "n", name
call RexxLvl "s", file, "c", csd
call RexxLvl "s", file, "v", version
call RexxLvl "s", file, "t", type
rc = RexxLvl("c", file)
if rc = 0 then say 'SYSLEVEL.'ext' created.'
Figure 6. Creating a syslevel file in REXX.
ΓòÉΓòÉΓòÉ 2.2.4. Summary ΓòÉΓòÉΓòÉ
Summary
Now you have enough information to use the SYSLEVEL files well. However, the
advertised advantages would become a reality only if we use SYSLEVEL files
extensively. So, if you like these perspectives, use them, ask them, require
them, again and again, until you get satisfaction. :-)
As a sidenote, the information exposed in the first part of this article is the
result of my own exploration. If you find any inaccuracy or if you have more
information, please, let me know.
ΓòÉΓòÉΓòÉ <hidden> kind ΓòÉΓòÉΓòÉ
SLK_BASE denotes a "base" component.
SLK_EXTENSION denotes a system extension.
SLK_STANDARD denotes a "standard" component. It's the suggested
component kind value.
ΓòÉΓòÉΓòÉ <hidden> ulOpenMode - input ΓòÉΓòÉΓòÉ
ULONG field that describes the mode of the open function.
OLF_OPEN open the specified file. The default behavior is to
scan the current disk, starting from the current
directory. It returns the first SYSLEVEL file whose
extension matches pszName You can override this by
combining OLF_OPEN with OLF_SCANDISK or OLF_CHECKID.
OLF_SCANDISKS scans all disks (starting from C:). Use this flag to
modify the default OLF_OPEN behavior.
OLF_CHECKID finds file(s) whose ID matches the specified one. Use
this flag to override the default OLF_OPEN behavior.
OLF_CREATE creates the specified file in the current directory.
A valid pszName and ID should be provided.
ΓòÉΓòÉΓòÉ <hidden> ulWhat - input ΓòÉΓòÉΓòÉ
The following flags can be used when querying (or writing) a SYSLEVEL file.
QLD_MAJORVERSION Query (or update) the major version field. It's a
one-character field. It should be in the range
'0'-'9'. The value is placed in (or taken from) the
first character of pBuffer. (Buffer size should be at
least 1.)
QLD_MINORVERSION Query (or update) the minor version field. It's a
two-character field. It should be in range '00'-'99'.
The value is placed in (or taken from) the first two
chars of pBuffer. (Buffer size should be at least 2.)
QLD_REVISION Query (or update) the revision field. It's should fit
in a character. If it's '0', there's no revision
available. It can be a letter as well as a digit.
The value is placed in (or taken from) the first
character of pBuffer. (Buffer size should be at least
1.)
QLD_KIND Query (or update) the kind field. The value is placed
in (or taken from) the first character of *pBuffer.
(Buffer size should be at least 1.)
QLD_CURRENTCSD Query (or update) the current CSD level (when you
update this field, its old value is copied to the old
CSD level field). It's a seven-character field, and
it does not have to be null-terminated. The value is
placed in (or taken from) the first seven characters
of pBuffer. (Buffer size should be at least 7.)
QLD_PREVIOUSCSD Query the previous CSD level. You can't update this
field. The value is placed in the first seven chars
of pBuffer. (Buffer size should be at least 7.)
Note: CSD levels are not null-terminated. Be careful
when using such a returned value.
QLD_TITLE Query (or update) the component title field. It's an
eighty-character string (required ending null
included). The value is placed in (or taken from) the
first eighty characters of pBuffer. On input, the
buffer size should be at least 80. On output, the
buffer size can exceed 80, but the written string is
truncated (and null-terminated) to eighty characters.
QLD_ID Query (or update) the component ID field. It's a
nine-character field. It does not have to be
null-terminated. The value is placed in (or taken
from) the first nine characters of pBuffer. (Buffer
size should be at least 9.)
Note: IDs are not null-terminated. Be careful when
using such a returned value.
QLD_TYPE Query (or update) the component type field.
ΓòÉΓòÉΓòÉ <hidden> LvlOpenLevelFile ΓòÉΓòÉΓòÉ
APIRET LvlOpenLevelFile(PSZ pszName, PHFILE phFile, ULONG ulOpenMode, PSZ
pszCID)
Use this to find, open or create a SYSLEVEL file.
It returns the following values:
0 NO_ERROR
2 ERROR_FILE_NOT_FOUND
3 ERROR_PATH_NOT_FOUND
4 ERROR_TOO_MANY_OPEN_FILES
5 ERROR_ACCESS_DENIED
12 ERROR_INVALID_ACCESS
26 ERROR_NOT_DOS_DISK
32 ERROR_SHARING_VIOLATION
36 ERROR_SHARING_BUFFER_EXCEEDED
82 ERROR_CANNOT_MAKE
87 ERROR_INVALID_PARAMETER
99 ERROR_DEVICE_IN_USE
108 ERROR_DRIVE_LOCKED
110 ERROR_OPEN_FAILED
112 ERROR_DISK_FULL
206 ERROR_FILENAME_EXCEED_RANGE
231 ERROR_PIPE_BUSY
ΓòÉΓòÉΓòÉ <hidden> pszName - input ΓòÉΓòÉΓòÉ
The syslevel file extension. It's a three-letter, null-terminated string. That
is, LvlOpenLevelFile deals with syslevel files named syslevel.xxx, where xxx
is pszName's value.
ΓòÉΓòÉΓòÉ <hidden> LvlCloseLevelFile ΓòÉΓòÉΓòÉ
APIRET LvlCloseLevelFile(HFILE hFile)
Use this to close a SYSLEVEL file. It's just a DosClose alias, for API
consistence.
It returns the following values:
0 NO_ERROR
2 ERROR_FILE_NOT_FOUND
5 ERROR_ACCESS_DENIED
6 ERROR_INVALID_HANDLE
ΓòÉΓòÉΓòÉ <hidden> LvlQueryLevelData ΓòÉΓòÉΓòÉ
APIRET LvlQueryLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG
ulBufSize, PULONG pulSize)
Use this to query an already opened SYSLEVEL file.
It returns the following values:
0 NO_ERROR
6 ERROR_INVALID_HANDLE
87 ERROR_INVALID_PARAMETER
122 ERROR_INSUFFICIENT_BUFFER
When it returns ERROR_INSUFFICIENT_BUFFER, *pulSize contains the minimum
requested size.
ΓòÉΓòÉΓòÉ <hidden> pBuffer - input/output ΓòÉΓòÉΓòÉ
Address of the buffer that contains the data to write/read.
ΓòÉΓòÉΓòÉ <hidden> pulSize - output ΓòÉΓòÉΓòÉ
Address of the variable to receive the number of bytes actually read or
written.
ΓòÉΓòÉΓòÉ <hidden> LvlWriteLevelData ΓòÉΓòÉΓòÉ
APIRET LvlWriteLevelData(HFILE hFile, ULONG ulWhat, PVOID pBuffer, ULONG
ulBufSize, PULONG pulSize)
Use this to update an already opened SYSLEVEL file.
It returns the following values:
0 NO_ERROR
6 ERROR_INVALID_HANDLE
19 ERROR_WRITE_PROTECT
29 ERROR_WRITE_FAULT
87 ERROR_INVALID_PARAMETER
122 ERROR_INSUFFICIENT_BUFFER
When it returns ERROR_INSUFFICIENT_BUFFER, *pulSize contains the minimum
requested size.
ΓòÉΓòÉΓòÉ <hidden> ulBufSize - input ΓòÉΓòÉΓòÉ
The length, in bytes, of pBuffer. This is the number of bytes to be read or
write.
ΓòÉΓòÉΓòÉ <hidden> phFile - output ΓòÉΓòÉΓòÉ
Address of the handle for the file.
ΓòÉΓòÉΓòÉ <hidden> pszCID - input ΓòÉΓòÉΓòÉ
It's the component ID string. It's required when you specify the OLF_CHECKID
flag when opening a syslevel flag. It's a nine-digit string, not
null-terminated, which uniquely identifies the component in conjunction with
pszName. That is, you can have multiple SYSLEVEL files with the same name, but
you can't have multiple syslevel files with the same name and ID.
If you are not using the OLF_CHECKID flag, set pszCID to NULL.
ΓòÉΓòÉΓòÉ <hidden> RexxLvl() ΓòÉΓòÉΓòÉ
ΓöÇΓöÇΓöÇRexxLvl(ΓöÇΓö¼ΓöÇC,ΓöÇΓöÇfileΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇ)ΓöÇΓöÇΓöÇ
Γö£ΓöÇEΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé Γö£ΓöÇ,ΓöÇΓöÇextensionΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé Γöé ΓööΓöÇ,ΓöÇidΓöÇΓöñ
Γöé ΓööΓöÇ,,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γö£ΓöÇN,ΓöÇΓöÇextension,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γö£ΓöÇO,ΓöÇΓöÇextension,ΓöÇΓöÇidΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γö£ΓöÇQ,ΓöÇΓöÇfile,ΓöÇΓöÇfieldΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓööΓöÇS,ΓöÇΓöÇfile,ΓöÇΓöÇfield,ΓöÇΓöÇvalueΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
RexxLvl returns a string describing the state of, or the result of an operation
upon, a SYSLEVEL file. This function is used to request information on the
state of a SYSLEVEL file, or to carry out some specific operation on the
SYSLEVEL file.
The first argument can be one of the following strings (of which only the first
letter is needed) which describes the action to be carried out:
"c[lose]" closes the specified syslevel file. File is a filename returned
by a previous RexxLvl OPEN or NEW call.
"e[num]" enumerates the matching SYSLEVEL files. Extension is (an
optional) SYSLEVEL file extension. Id is (an optional)
component ID. It returns the number of matching files, or
'ERROR'. The corresponding filenames are pushed on the current
queue. Use PULL or PARSE PULL to get them back.
"n[ew]" creates a new SYSLEVEL file, in the current directory. Extension
is the SYSLEVEL file extension, and id is the component ID. It
returns a file name to be used by subsequent RexxLvl calls.
"o[pen]" opens the specified SYSLEVEL file. Extension is the SYSLEVEL
file extension, and id is the component ID. It returns a file
name to be used by subsequent RexxLvl calls, 'NOTFOUND' if the
required file was not found or 'ERROR' if an error occurred
while searching.
Note: It returns the first matching SYSLEVEL file.
"q[uery]" queries a SYSLEVEL file field. File is a filename returned by a
previous RexxLvl OPEN or NEW call. Field is the field to be
queried. It can be any of the following (of which only the
first letter is needed):
"n[ame]" component name. Its length cannot exceed 79 characters.
"i[d]" component ID. It's a nine-digit string.
"k[ind]" component kind. It can be 0 (if the component is a base
one), 1 or 2 (if the component is a system extension) or 15
otherwise.
"v[ersion]" component version. It should follows the 'x.yy[.z]' format.
"t[ype]" component type. It's a string.
"c[csd]" current CSD level. It's a seven-byte string.
"p[csd]" previous CSD level. It's a seven-byte string.
It returns the field value or 'ERROR'.
"s[et]" sets the specified SYSLEVEL file field. File is a filename
returned by a previous RexxLvl OPEN or NEW call. Field is the
field to be set. It can be any of the values taken by the field
parameter of the RexxLvl "query" call, except "p[csd]" (you
can't set the "p[csd]" field's value -- it is automatically sets
when you update the c[csd] field). Value is the field's new
value. It returns an empty string, or 'ERROR'.
ΓòÉΓòÉΓòÉ <hidden> LvlQueryLevelFile ΓòÉΓòÉΓòÉ
APIRET LvlQueryLevelFile(PSZ pszName, PSZ pszCID, PVOID pBuffer, ULONG
ulBufSize)
Use this to query/find existing SYSLEVEL files. This function enumerates all
the SYSLEVEL files present in the system and returns the names as a list in the
pBuffer parameter. Each SYSLEVEL file name is terminated with a NULL character
and the last name is terminated with two successive NULL characters.
Specifying pszName or pszCID (or both) restricts the enumeration to the
corresponding SYSLEVEL files.
It returns the following values:
0 NO_ERROR
87 ERROR_INVALID_PARAMETER
122 ERROR_INSUFFICIENT_BUFFER
When it returns ERROR_INSUFFICIENT_BUFFER, the first ulBufSize bytes of pBuffer
are correctly filled.
ΓòÉΓòÉΓòÉ 3. Columns ΓòÉΓòÉΓòÉ
The following columns can be found in this issue:
o /dev/EDM/BookReview
o C++ Corner
o Introduction to PM Programming
o Scratch Patch
ΓòÉΓòÉΓòÉ 3.1. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 3.1.1. Introduction ΓòÉΓòÉΓòÉ
/dev/EDM2/BookReview
/dev/EDM2/BookReview is a monthly column which focuses on development oriented
books and materials. This will mostly consist of programming books, such as
this month's Writing OS/2 2.1 Device Drivers in C, but could also be books like
The Design of OS/2. The column is from a beginning PM programmer's eyes
(because that's what I am), and hopefully that is most useful to the community
in general. As I get on with the column, however, I expect to get better, and
so within a year or so, I will presumably :) qualify as an intermediate
programmer, or perhaps even somewhat of an expert. Hopefully you, the readers,
will move with me in that respect. When reading this column, try to pick up
whichever book strikes your fancy, and join the growing group of people
following our introductory PM programming columns. I will try to review books
aimed at beginners to start with, and then move on from there.
The column will largely be demand-oriented (after I get my own books out of the
way early on), so if you have a book you would like reviewed, send me e-mail
and tell me about it, or even better, send me the book. (no-one has sent me
any requests yet, and my personal library is nearly covered! If no-one writes,
I will choose some myself). Finally, please send me your comments and thoughts
so that I can make this column as effective as possible. After all, this is our
magazine, and it will be most effective with lots of reader feedback.
I decided to review this book for two reasons. First of all, OS/2 needs more
device drivers, as we all know, and I figured that reviewing this might prompt
some would-be device-driver writers to buy it and get going. Secondly, I have
heard many good things about this book, and so was naturally curious about it.
ΓòÉΓòÉΓòÉ 3.1.2. Errata ΓòÉΓòÉΓòÉ
Errata
I have just picked up Watcom C/C++ 9.5, so things have changed a bit since last
month. The makefile that comes with Real World Programming for OS/2 2.1 works
fine, with a couple of modifications:
1. Add a section for C++, if you plan on using the makefile for C++
programming. You can just copy the C section, and modify it as follows:
.cpp.obj:
@echo ╨╛╨╛╨╛ Compiling $*.cpp using WATCOM C/C++ options ╨┐╨┐╨┐
wpp386 -d1 -zq -W2 -D__WATCOM__ $(WCL386OPTS) $*.cpp
and add .cpp to the .EXTENSIONS directive after .c.
2. In each .DEP file, add .SYMBOLIC to the end of the ALL: line. This
eliminates some error messages that otherwise occur.
ΓòÉΓòÉΓòÉ 3.1.3. Writing OS/2 2.1 Device Drivers in C, 2nd Edition ΓòÉΓòÉΓòÉ
Writing OS/2 2.1 Device Drivers in C, 2nd Edition
This book is a must for device driver programmers! It has extensive reference
material all the way through, and brief examples of how to use many of the
functions. Skeleton code is presented throughout, to guide the novice and
intermediate OS/2 device driver programmer. Strategies are explained and much
of the inside workings of OS/2 and hardware are explained.
Here are the chapter headings:
1. The Evolution of PC Device Drivers
2. Understanding Device Drivers
3. The PC Hardware Architecture
4. An Overview of the OS/2 Operating System
5. The Anatomy of an OS/2 Device Driver
6. Device Driver Strategy Commands
7. A Simple OS/2 Physical Device Driver
8. The Micro Channel Bus
9. OS/2 2.1 Virtual Device Drivers
10. Memory Mapped Adapters and IOPL
11. Direct Memory Access (DMA)
12. Extended Device Driver Interface
13. Debugging OS/2 2.1 Device Drivers
14. An Introduction to Presentation Drivers
15. Working with Pointers
16. PCMCIA Device Drivers
17. Tips and Techniques
18. Device Helper Reference
19. Reference Publications
20. Listings
21. OEMHLP and TESTCFG
The first four chapters serve to introduce the area of device driver
programming by way of explaining where we came from, and where OS/2 is headed.
First, we are treated to a brief history of the micro-computer, starting with
the Altair 8800, and covering the very early ways of programming directly for
the hardware. This stuff is even worse than DOS, believe it or not. The very
early programs each had their own built-in operating system!! The origins of
micro-computer operating systems are outlined along with explanations of BIOS
and some architecture basics, like the bus.
In chapter three, the PC hardware architecture is explained, starting with the
8088, and going through the 80286, the AT bus, the PS/2, the Micro Channel bus,
EISA, real mode, protect mode, addressing and the ring architecture of the
80386 and 80486. In chapter four we are then walked through the early versions
of OS/2, disadvantages and all, to the OS we all know and love, OS/2 2.x.
The book really starts in chapter five. The early chapters were very brief,
and could be read comfortably in one sitting. This chapter gets more
complicated, and has some spine chilling warnings like "It may be difficult or
impossible to find a device driver problem using normal debugging techniques."
Luckily, we have the OS/2 kernel debugger, KDB. Installation of the kernel
debugger is explained, and then the basic OS/2 device driver design is
explained step by step. The various components of the device driver are
outlined, and code for a start-up routine given. Unfortunately, the start-up
routine is in assembly code, and Watcom C/C++, my compiler, does not come with
an assembler, so I could not follow this on my computer.
Device drivers have a strategy section, which is basically a switch for the
message type the OS calls the driver with. Depending on what the OS needs, a
separate section of the device driver is entered, and the need fulfilled.
Device drivers can either fulfil the request immediately, or it can acknowledge
the receipt of the request, and fulfil it as time permits. There are quite a
few different strategy commands that the OS can use, depending on what type of
driver you are writing.
Chapter seven explains a sample device driver for an 8-bit parallel port. You
can enhance this code to suit your needs, if you have to program such a port.
This is the only fairly complete device driver code that the book contains, but
of course most people attempting to program a device driver have the
specifications for the particular device they are interested in, and so the
skeleton code suffices.
The remainder of the chapters discuss various other types of device drivers,
such as memory mapped drivers, presentation device drivers, and so on. These
chapters are fairly introductory in nature, and no-one is going to get a free
ride here. This book has to be supplemented with device specific reference
material! On the other hand, I shudder to think how anyone would program a
device driver for OS/2 without this book, or something similar. There are many
efficiency considerations to take into account, and trying to program for OS/2
with only DOS device driver knowledge would be like trying to climb Mont Blanc
after walking up the local Devil's Hill. You are bound to do things wrong
without some guidelines.
Programming device drivers for OS/2 is not for the faint of heart, but neither
is it impossible. It requires the right tools, the right attitude, the right
information, the patience, and this book (or another similar book, but I have
never heard of any other book like this). Like any difficult programming
problem, successfully writing a device driver for OS/2 is tricky, but
potentially very rewarding. Just take a look at the popularity of the SIO
drivers, which are considered to be better than OS/2's own by most people. Good
luck!
ΓòÉΓòÉΓòÉ 3.1.4. Summary and Ratings ΓòÉΓòÉΓòÉ
Summary and Ratings
This is a very authoritative book, almost more of a reference book than a
tutorial. It has a lot of tables of flag bits, device helper functions, PCMCIA
card services, KDB keywords, ad infinitum. Although it is a large book (at 547
pages), it still has a very terse feel to it, and is definitely aimed at
advanced programmers. Anyone considering writing device drivers should
definitely be comfortable with C, and familiar with computer architecture and
the specific hardware they want to program for. This is a "bible" type of
book, and as such is probably required reading for OS/2 device driver
programmers in much the same way that the ARM is required for C++ programmers.
The only downside is what is not there. IFS drivers are not covered, and
neither are SCSI or ADD drivers. This is mentioned in the introduction,
however, and is promised for the next printing. I did feel a little surprised
by the fact that the DevHlp library used in the book has to be purchased
separately, but I suppose it would be a little much to ask for it to be
included with such a reasonably priced book.
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéBOOK ΓöéAUDIENCE ΓöéMARKΓöéCOMMENTS Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéReal World Programming for OS/2 2.1,ΓöéIntermediateΓöéB+ ΓöéLots of good code examples, but sometimes it is Γöé
ΓöéBlain, Delimon, and English, SAMS Γöéto Advanced Γöé Γöétoo complex for novices. Accurate. Well Γöé
ΓöéPublishing. ISBN 0-672-30300-0. ΓöéPM C Γöé Γöéorganized. The index needs a little beefing up. Γöé
ΓöéUS$40, CAN$50. Γöéprogrammers Γöé ΓöéGood, but not entirely complete how-to reference. Γöé
Γöé Γöé Γöé ΓöéGood purchase. Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéLearning to Program OS/2 2.0 ΓöéBeginning PMΓöéB- ΓöéThis book can be both frustrating and very Γöé
ΓöéPresentation Manager by Example, ΓöéC Γöé Γöérewarding. It is not very large, and a bit Γöé
ΓöéKnight, Van Nostrand Reinhold. ISBN ΓöéProgrammers Γöé Γöépricey, but has some excellent chapters on Γöé
Γöé0-442-01292-6. US$40, CAN$50. Γöé Γöé Γöébeginning topics, such as messages, resources, Γöé
Γöé Γöé Γöé ΓöéIPF, and dialog boxes. Strictly for beginners. Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéWriting OS/2 2.1 Device Drivers in ΓöéAdvanced C ΓöéA- ΓöéThe only thing a device driver programmer would Γöé
ΓöéC, 2nd Edition, Mastrianni, Van ΓöéProgrammers,Γöé Γöénot find in here is how to write SCSI, ADD, and Γöé
ΓöéNostrand Reinhold. ISBN Γöéfamiliar Γöé ΓöéIFS drivers. Most everything else is in here, Γöé
Γöé0-442-01729-4. US$35, CAN$45. Γöéwith Γöé Γöéalong with skeleton examples. An optional DevHlp Γöé
Γöé Γöéhardware Γöé Γöélibrary of C-callable functions can be purchased Γöé
Γöé Γöéprogramming Γöé Γöéby those who don't have time to write their own. Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
This table contains all books I have reviewed, so that you can find what you
are looking for at a glance. I will be very careful to rate books fairly
relative to each other. If I feel a need to adjust ratings, I will adjust all
of them at the same time, and write a note explaining why I felt this
necessary. Please note that books aimed at different audiences should only be
compared with great care, if at all. I intend to concentrate on the strong
points of the books I review, but I will point out any weaknesses in a
constructive manner. Read the reviews carefully for what you are looking for.
BOOK: The name of the book, author(s), publishing company, ISBN, and
approximate price.
AUDIENCE: This is a description of the audience I think the book targets best.
This is not intended as gospel, just a guideline for people not familiar with
the book.
MARK: My opinion of the success of the book's presentation, and how well it
targets its audience. Technical content, accuracy, organization, readability,
and quality of index all weigh heavily here, but the single most important item
is how well the book covers what it says it covers. I don't expect to see any
book score less than C, but the scale is there if necessary.
ΓöîΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéA+ ΓöéGround-breaking, all-around outstanding book Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéA ΓöéExcellent book. This is what I want to see happen a lot Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéA- ΓöéExcellent book with minor flaws Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéB+ ΓöéVery good book with minor flaws or omissions Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéB ΓöéGood book with some flaws and omissions Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéB- ΓöéGood book, but in need of improvement Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéC ΓöéMediocre book with some potential, but in need of repairing Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéD ΓöéDon't buy this book unless you need it, and nothing else exists Γöé
Γö£ΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéF ΓöéDon't buy this book. Period Γöé
ΓööΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
COMMENTS: This is a summary of the review proper, although in a very brief
format.
ΓòÉΓòÉΓòÉ 3.1.5. Coming Up ΓòÉΓòÉΓòÉ
Coming Up
Next month I will be looking at The Art of OS/2 C Programming, Panov, Salomon
and Panov, if it gets here in time (sounds familiar :). Otherwise I will review
OS/2 Presentation Manager GPI, Winn, or a REXX book. The books I intend to
review are (not necessarily in this order):
o The Art of OS/2 C Programming, Panov, Salomon and Panov
o OS/2 Presentation Manager GPI, Winn
o OS/2 Presentation Manager Programming, Petzold - 1994 - not yet published :(
o The Design of OS/2, 2nd Edititon, Kogan and Deitel - 1994 - not published
yet? I will review the old version if someone sends me one, but if I have to
buy it I will wait for the new edition.
This list is not set in stone, but they are books I am interested in. I am
considering reviewing the IBM OS/2 Redbooks, since they are readily and cheaply
available, and look like good introductory reference. I am also considering
reviewing OS/2 Unleashed, but it is not strictly speaking a development book,
so I'm going to wait until the list of real development books has diminished a
bit. By the way, does anyone know why the special edition of OS/2 Unleashed
has completely different authors? And what is different about the Special
Edition?
I would like to review a REXX book as I have VX-REXX 2.0, but I don't really
know what books are supposed to be good, so if anyone has ideas here, please
write. Finally, if anyone has a book they want to see reviewed, I will be
happy to oblige as long as I can afford it. Of course, the request could be
satisfied a lot quicker if accompanied by a book. :)
ΓòÉΓòÉΓòÉ 3.2. C++ Corner ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 3.2.1. Introduction ΓòÉΓòÉΓòÉ
Written by Gordon Zeglinski
Introduction
As my project enters its final stages, the work load associated with it has
gone through the roof. Therefore, the column will be a tad shorter than usual.
Drag and drop is one of OS/2's nicest features, but probably one of the most
feared by new programmers. It's particularly painful, because you can't set
breakpoints inside the processing of the DM_DRAG, DM_DRAGOVER, etc. messages.
But since this is a C++ column, and drag and drop is a bit complex for a single
"tad smaller than usual" article, we'll look at the drop half of drag and drop
using the IBM PM class libraries. These class libraries do a lot more than just
encapsulate the PM infrastructure; they abstract PM to such an extent, that
they could be developed into a cross platform toolkit.
ΓòÉΓòÉΓòÉ 3.2.2. Processing Drop ΓòÉΓòÉΓòÉ
Processing Drop
Drop Basics
Before moving on to looking at the code which processes the drop actions, we
will briefly look at the stages involved in processing a drop:
1. The application is notified of a drag occurring. The application checks
what is being dragged over it. It then sets the return value to indicate
to the OS, whether the dragged object(s) can be dropped.
2. When the user drops the dragged objects, the application is notified of the
drop. It then performs the actions associated with the drag.
Both the initiator and recipient of the drag and drop operation must agree upon
the information being exchanged; this is done by using a rendering mechanism
and format specifier, both of which are text strings. The OS/2 PM programming
reference defines a set of standard rendering and format strings. In addition
to these, the programmer can define application-specific rendering and format
strings.
Drop in the ICLUI
The ICLUI uses several objects to encapsulate drag and drop. We will look at
those classes which we will use in the sample program.
Instances of the IDMItem or it's ancestors represent the objects being dragged.
By subclassing IDMItem, we can create specialized drag items if we choose to
implement our own rendering mechanisms. For this example, we create a new class
called AFileItem but give it no "special" properties.
class AFileItem : public IDMItem {
public:
AFileItem ( const IDMItem::Handle &item );
virtual Boolean
targetDrop ( IDMTargetDropEvent & );
};
The method targetDrop is called when the dragged objects are dropped. We
override this function to handle our application specific processing of the
drop event.
The template class IDMItemProviderFor is derived from the class
IDMItemProvider. We subclass IDMItemProviderFor to control various aspects of
the drag and drop process. IDMItemProvider implies that this object creates
IDMItem objects. However, it can do a lot more than just that. Below, we
subclass the template class IDMItemProviderFor to provide support for drag over
type events.
class AFileProvider : public IDMItemProviderFor< AFileItem > {
public:
virtual Boolean
provideEnterSupport ( IDMTargetEnterEvent &event );
};
We override the method provideEnterSupport so that when objects are dragged
over our main window, we can test them to see if they can be dropped. Both the
ICLUI classes we have looked at provide many more member functions that we can
override to provide other drag and drop features, but we will not look at these
here.
ΓòÉΓòÉΓòÉ 3.2.3. Building a Simple Test Application ΓòÉΓòÉΓòÉ
Building a Simple Test Application
Our simple test application will consist of a frame window and a multi-line
edit control. The frame window class will be subclassed by MyFrame. The MLE
control will be a member of MyFrame. When a file is dropped on the MLE, the
contents of the MLE are discarded and the file is loaded into the control. The
following section of code checks the objects being dragged over the MLE.
Boolean AFileProvider::provideEnterSupport( IDMTargetEnterEvent &event ){
// Get handle to the drag target operation
IDMTargetOperation::Handle targetOp = IDMTargetOperation::targetOperation();
// only want to accept 1 file
if(targetOp->numberOfItems()!=1){
event.setDropIndicator(IDM::neverOk);
return(true);
}
// Get the types for the drag item.
IString strTypes = targetOp->item(1)->types();
// See if it's marked as a "plain text" file
if ((strTypes.indexOf(IDM::plainText))){
event.setDropIndicator(IDM::ok);
return(true);
}
// Type is not recognized - set the drop indicator to prevent a drop!
event.setDropIndicator(IDM::neverOk);
return(true);
}
If there is more than one object being dropped over, or the object isn't
identified as "plain text", the application sets the drop indicator to neverOk.
This will then prevent the drop from occurring, and change the pointer to
indicate that a drop is not permitted. The following code snippet, loads the
MLE with the dropped file.
Boolean AFileItem::targetDrop( IDMTargetDropEvent & Event){
IMultiLineEdit *DropWin=(IMultiLineEdit *)this->targetOperation()->targetWindow();
IString
fname = this->containerName() + this->sourceName();
//erase the edit window
DropWin->removeAll();
//load the file into the edit window
DropWin->importFromFile(fname);
return true;
}
The constructor for the class MyFrame follows. The constructor enables drag
and drop for the MLE and attaches an instance of our FileProvider to the MLE.
MyFrame::MyFrame(const char *Title):
IFrameWindow(Title,IResourceId(1), //-------------------
IFrameWindow::titleBar| //
IFrameWindow::sizingBorder| //
IFrameWindow::minimizeButton| // Create the Frame
IFrameWindow::systemMenu| // Window
IFrameWindow::shellPosition| //
IFrameWindow::minimizeButton| //
IFrameWindow::windowList| //
IFrameWindow::maximizeButton), //--------------------
EditWin(10,this,this){ // Create the Edit Window
// ID=10, use this frame
// window as the parent and
//owner
//---------------------
setIcon(IResourceId(1));
setClient(&EditWin);
//enable default drag and drop handler
IDMHandler::enableDragDropFor(&EditWin);
//attach the provider
EditWin.setItemProvider(&FileProvider);
show();
}
The file CPPDD.CPP contains the complete source code for the simple app. To
compile the code simply execute the Rexx program GO.CMD.
ΓòÉΓòÉΓòÉ 3.2.4. Summary ΓòÉΓòÉΓòÉ
Summary
Drag and drop is one of OS/2's most intuitive user interface features and the
ICLUI completely encapsulates the direct manipulation API. However, as with
other parts of the ICLUI its encapsulation strategy is not clearly documented.
In this article, we have explored how to enable our ICLUI applications to
accept dropped files.
Yet, we still have only barely touched this topic's surface.
ΓòÉΓòÉΓòÉ 3.3. Introduction to PM Programming ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 3.3.1. Introduction ΓòÉΓòÉΓòÉ
Written by Larry Salomon, Jr.
Introduction
The purpose of this column is to provide the readers out there who are not
familiar with PM application development the information necessary to satisfy
their curiousity, educate themselves, and give them an advantage over the
documentation supplied by IBM. Of course, much of this stuff could probably be
found in one of the many books out there, but the problem with books in general
is that they don't answer the questions you have after you read the book the
first time through.
I will gladly entertain feedback from the readers about what was "glossed over"
or what was detailed well, what tangential topics need to be covered and what
superfluous crap should have been removed. This feedback is essential in
guaranteeing that you get what you pay for. :)
It should be said that you must not depend solely on this column to teach you
how to develop PM applications; instead, this should be viewed as a supplement
to your other information storehouses (books, the network conferences, etc.).
Because this column must take a general approach, there will be some topics
that you would like to see discussed that really do not belong here. Specific
questions can be directed to the Scratch Patch, where an attempt to answer them
will be made.
ΓòÉΓòÉΓòÉ 3.3.2. Last Month ΓòÉΓòÉΓòÉ
Last Month
Last month, we introduced the WM_COMMAND and WM_CONTROL messages, which are -
as you will see - very important in the development of many PM applications.
We also looked at the HELLO dialog procedure in a little detail, and were
introduced to three new APIs.
This month, we will introduce some more APIs, will continue dissecting the
dialog procedure, and will begin looking at our first window class in detail.
ΓòÉΓòÉΓòÉ 3.3.3. New APIs ΓòÉΓòÉΓòÉ
New APIs
PM has a few specific APIs which are more "helper APIs" than anything else,
because they replace two APIs, the first of which is always WinWindowFromID().
HWND WinWindowFromID(HWND hwndParent,ULONG ulId);
WinWindowFromID searches the children of hwndParent to find a window whose
identifier (remember these from the first column in this series?) matches ulId.
It returns the window handle if found, or NULLHANDLE otherwise.
These new functions are listed below:
BOOL WinSetDlgItemText(HWND hwndDlg,ULONG ulId,PSZ pszText);
ULONG WinQueryDlgItemText(HWND hwndDlg,
ULONG ulId,
LONG ulSzBuffer,
PCHAR pchBuffer);
LONG WinQueryDlgItemTextLength(HWND hwndDlg,ULONG ulId);
These three functions provide the equivalent of the WinSetWindowText(),
WinQueryWindowText(), and WinQueryWindowTextLength() functions that we looked
at last month. The only difference is that the above three functions call
WinWindowFromID() first to determine the handle of the window you are
interested in.
Letter carriers and Bulletin Boards
While thinking about the topics that I should cover this month, I realized
that, although the terms sending and posting messages have been used liberally
over the lifespan of this column, the functions to perform these two actions
have never been discussed, nor has the difference between the two been
discussed.
MRESULT WinPostMsg(HWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2);
MRESULT WinSendMsg(HWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2);
Both WinSendMsg and WinPostMsg take the same parameter set:
hwndWnd the window to receive the message to be posted or sent
ulMsg the message identifier
mpParm1, mpParm2 message-specific parameters. See the Programming Reference
for detailed information about the parameters required for
each message.
The difference between posting and sending is that the former simply puts the
message in the message queue of the recipient, while the latter is (logically
speaking) a direct call to the window procedure of the recipient's window
procedure. The significance of the last statement is that your window
procedure will be blocked until the WinSendMsg() call returns, and that will
not happen until the recipient finishes processing the message.
Why is one used over the other? For one thing, since WinSendMsg() is a
synchronous call, pointers that are specified are guaranteed to point to valid
areas of memory (this is important if they point to local variables on the
stack). Note the word valid instead of accessible; if you send a message to
another process with a pointer, accessability to the pointer must be
established either via shared memory or giveable/gettable memory. WinSendMsg()
does have one disadvantage, however; it requires that the sender have a message
queue. WinPostMsg(), on the other hand, can be sent from anywhere, regardless
of whether or not WinCreateMsgQueue() was called previously (this is handy for
secondary threads).
Given this information, let us look at one more "dialogish" API -
WinSendDlgItemMsg().
MRESULT WinSendDlgItemMsg(HWND hwndDlg,
ULONG ulId,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2);
This function, as you can imagine, behaves the same as WinSendMsg(), except
that - as with the first three APIs discussed in this section - it calls
WinWindowFromID() to get the handle of the window to whom the message should be
sent. It should be noted that there is no function WinPostDlgItemMsg(). I
have never been able to get a straight answer for why this is so,
unfortunately.
One last API to look at - WinDefDlgProc().
MRESULT WinDefDlgProc(HWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2);
In volume 2, issue 1, we briefly noted how WinDefWindowProc() was used to
handle all messages that we did not want to process in our window class
procedure. WinDefDlgProc() has the same purpose except that it is used within
dialog procedures. Please be aware that, using one when you should be using
the other will result in very strange behavior, so be careful!
ΓòÉΓòÉΓòÉ 3.3.4. nameDlgProc() Revisited ΓòÉΓòÉΓòÉ
nameDlgProc() Revisited
Let's look at nameDlgProc() one more time, this time in its entirety.
Following that is the resource file definition for the dialog.
MRESULT EXPENTRY nameDlgProc(HWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2)
{
PNAMEDLGINFO pndiInfo;
pndiInfo=(PNAMEDLGINFO)WinQueryWindowPtr(hwndWnd,0); // @1
switch (ulMsg) {
case WM_INITDLG: // @2
{
HAB habAnchor;
HWND hwndLb;
CHAR achText[64];
pndiInfo=(PNAMEDLGINFO)PVOIDFROMMP(mpParm2); // @3
WinSetWindowPtr(hwndWnd,0,(PVOID)pndiInfo); // @4
WinSendDlgItemMsg(hwndWnd, // @5
DNAME_EF_NAME,
EM_SETTEXTLIMIT,
MPFROMSHORT(sizeof(pndiInfo->achName)),
0);
habAnchor=WinQueryAnchorBlock(hwndWnd);
hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);
WinLoadString(habAnchor, // @6
NULLHANDLE,
STR_TOM,
sizeof(achText),
achText);
WinInsertLboxItem(hwndLb,LIT_END,achText); // @7
WinLoadString(habAnchor,
NULLHANDLE,
STR_DICK,
sizeof(achText),
achText);
WinInsertLboxItem(hwndLb,LIT_END,achText);
WinLoadString(habAnchor,
NULLHANDLE,
STR_HARRY,
sizeof(achText),
achText);
WinInsertLboxItem(hwndLb,LIT_END,achText);
}
break;
case WM_CONTROL: // @8
switch (SHORT1FROMMP(mpParm1)) {
case DNAME_LB_NAMELIST:
switch (SHORT2FROMMP(mpParm1)) {
case LN_SELECT: // @9
{
HWND hwndLb;
SHORT sIndex;
hwndLb=WinWindowFromID(hwndWnd,DNAME_LB_NAMELIST);
sIndex=WinQueryLboxSelectedItem(hwndLb);
WinQueryLboxItemText(hwndLb,
sIndex,
pndiInfo->achName,
sizeof(pndiInfo->achName));
WinSetDlgItemText(hwndWnd,
DNAME_EF_NAME,
pndiInfo->achName);
}
break;
case LN_ENTER: // @10
WinPostMsg(hwndWnd,WM_COMMAND,MPFROMSHORT(DID_OK),0);
break;
default:
return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2); // @11
} /* endswitch */
break;
default:
return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
break;
case WM_COMMAND:
switch (SHORT1FROMMP(mpParm1)) {
case DID_OK: // @12
WinDismissDlg(hwndWnd,TRUE);
break;
case DID_CANCEL: // @13
WinDismissDlg(hwndWnd,FALSE);
break;
default:
return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
break;
default:
return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
return MRFROMSHORT(FALSE);
}
------------------------------------------
DLGTEMPLATE DLG_NAME LOADONCALL MOVEABLE DISCARDABLE
{
DIALOG "Input Required", DLG_NAME, 112, 59, 150, 100,
WS_VISIBLE,
FCF_SYSMENU | FCF_TITLEBAR
{
LTEXT "Select a name, or enter it below, and select ""Ok""" ".", -1, 10, 80, 130, 16, DT_WORDBREAK
LISTBOX DNAME_LB_NAMELIST, 10, 45, 130, 35, LS_HORZSCROLL
ENTRYFIELD "", DNAME_EF_NAME, 12, 30, 127, 8, ES_MARGIN
DEFPUSHBUTTON "Ok", DID_OK, 10, 10, 40, 13
PUSHBUTTON "Cancel", DID_CANCEL, 55, 10, 40, 13
}
}
From the dialog template, we see that the dialog consists of five controls: a
text control (LTEXT) whose identifier is -1 (see below), a listbox control
(LISTBOX) whose identifier is DNAME_LB_NAMELIST, an entryfield control
(ENTRYFIELD) whose identifier is DNAME_EF_NAME, and two pushbuttons (the first
is DEFPUSHBUTTON meaning it's the default pushbutton and the second which is
simply PUSHBUTTON) whose identifiers are DID_OK and DID_CANCEL, respectively.
It is important to remember that, while the symbolic constants
DNAME_LB_NAMELIST and DNAME_EF_NAME are defined in HELLORC.H, DID_OK and
DID_CANCEL are defined in <pmwin.h> which is #include-d by <os2.h>.
Looking at the easiest message first, at numbers @12 and @13 we see the
processing of the WM_COMMAND message, which (if you'll remember from last
month) is sent by a pushbutton whenever it is pressed ("selected" is the term
typically used). You should remember that the identifier of the button is in
SHORT1FROMMP(mpParm1), which we "switch" on to determine the appropriate action
to take. Here, we simply dismiss the dialog with either TRUE or FALSE returned
depending on whether the user completed the dialog or changed their mind and
decided to select Cancel.
At number @8 we see the WM_CONTROL message. Again, last month we looked at
this message and you should remember that the identifier of the window sending
the message is in SHORT1FROMMP(mpParm1), which we "switch" on to determine how
to interpret the notification code. Since we're interested in the listbox
only, we process "case DNAME_LB_NAMELIST" and let WinDefDlgProc() handle
everything else (at number @11). At number @9 is the LN_SELECT notification,
which is sent whenever a listbox item is selected. Number @10 is the LN_ENTER
notification, which is sent whenever ENTER is pressed while the listbox has the
input focus or any listbox item is double-clicked. Since we will not be
looking at the listbox in any great detail until a future issue, I will not
elaborate on these two notifications until that time.
At number @2 is the dialog initialization code, which I will not discuss at
this time due to its complexity relative to what has been covered by this
column up to this point in time.
ΓòÉΓòÉΓòÉ 3.3.5. The WC_ENTRYFIELD Window Class ΓòÉΓòÉΓòÉ
The WC_ENTRYFIELD Window Class
Entryfields belong to the class WC_ENTRYFIELD and are probably the easiest of
the window classes to use, since there isn't a lot of variation involved in the
control's design. An entryfield is used to get a single line of text from the
user and has clipboard support built-in (the clipboard will be discussed in a
later issue). In an entryfield, text can be selected with the mouse or the
keyboard. A selection consists of an anchor point and a cursor point. The
anchor point is the point at which the selection began, and the cursor point is
the point where the selection ends, and may move depending on whether the
selection is still in progress.
An entryfield can have the following styles:
ES_ANY relates to DBCS ("double byte character set") support and
will not be discussed here.
ES_AUTOSCROLL specifies that, when the user moves the cursor outside of
the visible area, the entryfield should automatically
scroll so that the cursor is in a visible area.
ES_AUTOSIZE specifies that the entryfield should automatically size
itself to insure that its contents are completely visible.
ES_AUTOTAB specifies that, when the user enters the number of
characters equal to the current text limit (see
EM_SETTEXTLIMIT), the entryfield should automatically give
the input focus to the next control on the dialog.
ES_CENTER specifies that the text should be displayed centered.
ES_COMMAND relates to online help and will not be discussed here.
ES_DBCS relates to DBCS ("double byte character set") support and
will not be discussed here.
ES_LEFT specifies that the text should be displayed flush-left.
ES_MARGIN
ES_MIXED relates to DBCS ("double byte character set") support and
will not be discussed here.
ES_READONLY specifies that the user should not be able to change the
contents.
ES_RIGHT specifies that the text should be displayed flush-right.
ES_SBCS relates to DBCS ("double byte character set") support and
will not be discussed here.
ES_UNREADABLE specifies that each character in the entryfield should be
displayed as an asterisk ('*').
The entryfield has a number of messages that it understands, and they are
listed below. We will discuss some of them here, and will continue in the next
issue.
o EM_CLEAR
o EM_COPY
o EM_CUT
o EM_PASTE
o EM_QUERYCHANGED
o EM_QUERYFIRSTCHAR
o EM_QUERYREADONLY
o EM_QUERYSEL
o EM_SETFIRSTCHAR
o EM_SETINSERTMODE
o EM_SETREADONLY
o EM_SETSEL
o EM_SETTEXTLIMIT
You've probably noticed that there are no messages for setting and retrieving
the contents of an entryfield. This is done using the WinSetWindowText() and
WinQueryWindowText() (and through the "dialogish" APIs discussed earlier this
issue).
Let's look at our first four messages - EM_QUERYCHANGED, EM_QUERYFIRSTCHAR,
EM_QUERYREADONLY, and EM_QUERYSEL.
EM_QUERYCHANGED
This message is sent to determine if the text has changed since this message
was last sent (or since the control was created).
Parameters
param1
ulReserved (ULONG)
Reserved, 0.
param2
ulReserved (ULONG)
Reserved, 0.
Returns
reply
bChanged (BOOL)
changed indicator
TRUE the contents have changed since the last time this message
was sent.
FALSE the contents have not changed since the last time this
message was sent.
EM_QUERYFIRSTCHAR
This message is sent to determine the zero-based index of the first character
visible in the entryfield.
Parameters
param1
ulReserved (ULONG)
Reserved, 0.
param2
ulReserved (ULONG)
Reserved, 0.
Returns
reply
sIndex (SHORT)
the zero-based index of the first visible character.
EM_QUERYREADONLY
This message is sent to determine if the entryfield is read-only or not.
Parameters
param1
ulReserved (ULONG)
Reserved, 0.
param2
ulReserved (ULONG)
Reserved, 0.
Returns
reply
bReadOnly (BOOL)
the read-only state of the entryfield.
TRUE the entryfield is read-only.
FALSE the entryfield is not read-only.
EM_QUERYSEL
This message is sent to determine the current selection, if any exists.
Parameters
param1
ulReserved (ULONG)
Reserved, 0.
param2
ulReserved (ULONG)
Reserved, 0.
Returns
reply
sFirst (SHORT)
the zero-based index of the anchor point.
sLast (SHORT)
the zero-based index of the cursor point.
ΓòÉΓòÉΓòÉ 3.3.6. Summary ΓòÉΓòÉΓòÉ
Summary
This month we learned a lot of new things:
o We looked at a slew of new APIs, many of which are attuned to dialogs
o We looked at nameDlgProc() is more detail
o We began looking at the WC_ENTRYFIELD class in detail
Next month, we will continue with the WC_ENTRYFIELD discussion, but will hold
off from discussing nameDlgProc() until we look at the WC_LISTBOX window class.
ΓòÉΓòÉΓòÉ 3.4. Scratch Patch ΓòÉΓòÉΓòÉ
Written by Larry Salomon, Jr.
Welcome to this month's "Scratch Patch"! Each month, I collect various items
that fit into this column sent to me via email. The ones that I feel contribute
the most to developers, whether in terms of information or as a nifty trick to
tuck into your cap, get published in this column.
To submit an item, send it via email to my address - os2man@panix.com - and be
sure to grant permission to publish it (those that forget will not be
considered for publication).
ΓòÉΓòÉΓòÉ 3.4.1. Gotcha Notes! ΓòÉΓòÉΓòÉ
Gotcha Notes!
Last week I was developing a multithreaded application that needed two-way
communication between the main and secondary threads. The easiest solution, as
you may well know, was to use an object window in the second thread with its
own message loop. The purpose of the second thread was to perform some lengthy
processing, but needed to be interruptable, i.e. if the user pressed the Abort
button, the dialog would send the object window the appropriate message. After
the thread terminated its processing, it would send a response back.
A problem was created, though, that resulted in deadlock. Although it didn't
take long to deduce because the code was still quite skeletal (making the
process of elimination quite easy), I still do not know why the deadlock
occurred. In any case, it is necessary to relate the situation to the readers
so that they may avoid it in their own applications.
The code looked something like the following:
objectWndProc(...)
{
POBJECTINSTDATA poidData;
:
case MYM_ABORT:
: /* Abort processing */
WinSendMsg(poidData->hwndDlg,MYM_PROCESSINGABORTED,0,0);
break;
:
}
processDlgProc(...)
{
POBJECTINSTDATA poidData;
:
case WM_COMMAND:
switch (SHORT1FROMMP(mpParm1)) {
case DLG_PB_ABORT:
WinPostMsg(poidData->hwndObj,MYM_ABORT,0,0);
default:
return WinDefDlgProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
case MYM_PROCESSINGABORTED:
WinDismissDlg(hwndWnd,DID_CANCEL);
break;
:
}
INT main(VOID)
{
SHORT sRc;
:
sRc=WinDlgBox(HWND_DESKTOP,
HWND_DESKTOP,
processDlgProc,
NULLHANDLE,
DLG_PROCESS,
NULL);
if (sRc!=DID_CANCEL) {
:
} /* endif */
:
}
A lot was removed for clarity, but the pertinent parts are shown above. What
would happen was that, while testing the communication mechanisms, whenever I
would press the Abort button, the dialog would go away, but the application
would not terminate; looking at the above, you can probably figure out what the
problem was. The problem, in case you can't figure it out, is the
WinSendMsg(...,MYM_PROCESSINGABORTED,...) call to the dialog. For some reason,
if a message is sent intraprocess from the object window to the dialog and the
dialog dismisses itself, the process will deadlock. Changing the WinSendMsg()
to WinPostMsg() eliminated the problem.
I suspect the answer to why lies in the existence of a message loop in the
object window thread, but I cannot be sure. If anyone can give a definitive
answer, I would be happy to publish it.
ΓòÉΓòÉΓòÉ 3.4.2. Snippet(s) of the Month ΓòÉΓòÉΓòÉ
Snippet(s) of the Month
David Charlap (david@porsche.visix.com) sent us the following:
You can include this snippet. SWEEP.CMD is a REXX program that allows you to
apply any command-line to a recursive set of directories.
Syntax is:
SWEEP <command-line>
The program will visit every subdirectory of the current directory (and all
descendants thereof) and execute your command line in each one. For example,
to delete every backup file on your drive, just "cd" to the root directory of
the drive and type
SWEEP DEL *.BAK
If the command you want to execute is a CMD file, be sure to use the "CALL"
command, or Rexx will complain:
SWEEP CALL MyCmdFile.CMD myArgs...
ΓòÉΓòÉΓòÉ 3.4.3. Want Ads ΓòÉΓòÉΓòÉ
Want Ads
Below are the hot topics as of this issue's writing. Feel free to write on any
of these.
Workplace Shell Programming (hot) - this is still quite the "black magic"
topic, about which we have seen only one article. There are many out there who
do WPS programming for a living, but they have not been sufficiently
enlightened about our need. :)
Client/Server (hot) - using either named pipes (with or without a network) or
sockets, client/server programming is all the rage these days. On a related
note, some people have also expressed an interest in learning about interfacing
with the various protocol drivers (e.g. NDIS, IPX/SPX, etc.). Any articles in
this area are most welcome.
Multimedia (warm) - we recently had two articles on this topic. However, they
both dealt with sound, which we all know is not the only alternative media
type. Articles on anything else - MIDI, video, etc. - are needed.
ΓòÉΓòÉΓòÉ 4. How do I get EDM/2? ΓòÉΓòÉΓòÉ
EDM/2 can be obtained in any of the following ways:
On the Internet
o All back issues are available via anonymous FTP from ftp.cdrom.com in the
/pub/os2/2_x/program/newsltr directory.
o The EDM/2 mailing list. Send an empty message to edm2-info@knex.mind.org to
receive a file containing (among other things) instructions for subscribing
to EDM/2. This is a UUCP connection, so be patient please.
o IBM's external gopher/WWW server in Almaden. The address is
index.almaden.ibm.com and it is in the "Non-IBM-Originated" submenu of the
"OS/2 Information" menu; the URL is
"gopher://index.almaden.ibm.com/1nonibm/os2nonib.70".
On Compuserve
All back issues are available in the OS/2 Developers Forum 2.
IBM Internal
o IBM's internal gopher/WWW server in Almaden. The address is
n6tfx.almaden.ibm.com and it is in the "Non-IBM-Originated Files" menu; the
URL is "gopher://n6tfx.almaden.ibm.com/1!!nonibm/nonibm.70".
o IBM's REQUEST command on all internal VM systems. Enter the VM command
REQUEST LIST FROM ASSELIN AT RALVM12 and a list of the requestable packages
will be sent to you; in this list are the names of the packages containing
the EDM/2 issues.
ΓòÉΓòÉΓòÉ 5. Contributors to this Issue ΓòÉΓòÉΓòÉ
Are You a Potential Author?
We are always looking for (new) authors. If you have a topic about which you
would like to write, send a brief description of the topic electronically to
any of the editors, whose addresses are listed below, by the 15th of the month
before the month in which your article will appear. This alerts us that you
will be sending an article so that we can plan the issue layout accordingly.
After you have done this, get the latest copy of the Article Submission
Guidelines from ftp.cdrom.com in the /pub/os2/2_x/program/newsltr directory.
(the file is artsub.zip) The completed text of your article should be sent to
us no later than five days prior to the last day of the month; any articles
received after that time may be pushed to the next issue.
The editors can be reached at the following email addresses:
o Larry Salomon - os2man@panix.com (Internet).
o Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet).
The following people contributed to this issue in one form or another (in
alphabetical order):
o Martin Lafaix
o Larry Salomon, Jr.
o Carsten Whimster
o Gordon Zeglinski
o Network distributors
ΓòÉΓòÉΓòÉ 5.1. Martin Lafaix ΓòÉΓòÉΓòÉ
Martin Lafaix
Martin Lafaix is a computer science student at the UniversitВ de Nice-Sophia
Antipolis. He currently works on his PhD thesis (key areas: functional
language, type as value, programming at large, ...).
He can be reached at the following address: lafaix@sophia.inria.fr
ΓòÉΓòÉΓòÉ 5.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
Larry Salomon, Jr.
Larry Salomon, Jr. wrote his first Presentation Manager application for OS/2
version 1.1 in 1989. Since that time, he has written numerous VIO and PM
applications, including the Scramble applet included with OS/2 and the
I-Brow/Magnify/Screen Capture trio being distributed by IBM with the
Professional Developers Kit CD-ROM. Currently, he works for Cheyenne Software
in Roslyn, New York and resides in Bellerose, New York with his wife Lisa.
Larry can be reached electronically via the Internet at os2man@panix.com.
ΓòÉΓòÉΓòÉ 5.3. Carsten Whimster ΓòÉΓòÉΓòÉ
Carsten Whimster
I am an undergraduate Computer Science student at the University of Waterloo,
and an OS/2 enthusiast as of OS/2 2.0. I am currently in my third year, taking
mainly operating system, language, and compiler courses as much as possible.
This is not too difficult obviously, since this covers most of what they try to
teach us in any case :). This summer I will be working at the University as a
tutor in CS241, an introductory course to compilers.
I am a beginning OS/2 PM programmer with a few projects on the go, and many
more in my head. I am now using Watcom C/C++ 9.5, and Watcom VX-REXX 2.0, with
Watcom C/C++ 10.0 becoming my mainstay, as soon as it comes out. I try to buy
as many books as I can afford on OS/2 programming, but I don't have much money.
If anyone sends me books, I will review them as time permits, provided they are
topical. Finally, I am a TEAM-OS/2 member, and stay busy trying to keep up
with several OS/2 groups on the Internet. My Mosaic homepage should get a lot
more interesting over the summer as I get more time to spend on these things.
You may reach me...
...via email:
bcrwhims@undergrad.math.uwaterloo.ca - Internet
gopher://descartes.math.uwaterloo.ca:70/h0/mathSOC/.csc/.www/.bcrwhimster/homepage.html
- Mosaic homepage
...via snail mail:
Carsten Whimster
319 Erb Street West, 3rd floor
Waterloo, Ontario
Canada
N2L 1W4
ΓòÉΓòÉΓòÉ 5.4. Gordon Zeglinski ΓòÉΓòÉΓòÉ
Gordon Zeglinski
Gordon Zeglinski is a freelance programmer/consultant who received his Master's
degree in Mechanical Engineering with a thesis on C++ sparse matrix objects.
He has been programming in C++ for 6 years and also has a strong background in
FORTRAN. He started developing OS/2 applications with version 2.0 .
His current projects include a client/server communications program that
utilitizes OS/2's features which has entered beta testing. Additionally, he is
involved in the development of a "real-time" automated vehicle based on OS/2
and using C++ in which he does device driver development and designs the
applications that comprise the control logic and user interface.
He can be reached via the Internet at zeglins@cc.umanitoba.ca.
ΓòÉΓòÉΓòÉ 5.5. Network distributors ΓòÉΓòÉΓòÉ
Network Distributors
These people are part of our distribution system to provide EDM/2 on networks
other than the Internet. Their help to provide access to this magazine for
others is voluntary and we appreciate them a lot!
o Paul Hethman (hethmon@apac.ag.utk.edu) - Compuserve
o Gess Shankar (gess@knex.mind.org) - Internet
o David Singer (singer@almaden.ibm.com) - IBM Internal
o Andre Asselin (ASSELIN AT RALVM12) - IBM Internal
If you would like to become a "network distributor", be sure to contact the
editors so that we can give you the credit you deserve!