home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 32 Periodic
/
32-Periodic.zip
/
edmi3-5.zip
/
EDMI3-5.INF
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1995-05-08
|
244KB
|
3,506 lines
ΓòÉΓòÉΓòÉ 1. May 1995 Title Page ΓòÉΓòÉΓòÉ
The Electronic Developer's Magazine for OS/2
Portions copyright (c) by IQPac Inc.
Volume 3, issue 5
Administrivia
The last month has zoomed by and it's time for another issue of the magazine.
This issue seems to be a bit on the slim side but that is because of finals, no
doubt about it. You will finally see the end of the VIOWIN series, as well as
another fantastic installment about RMX-OS/2.
On the Net
One of the advantages of working in the "network systems development" group of
a large company is that one undoubtedly gets a connection to the Internet. I
still have no answer for why that is; maybe it's because the two names have the
word "net" in them. <grin>
Anyway, I now have a T1 link to the Internet, via an ethernet connection, from
my machine at work. I will try, from time-to-time, to place some interesting
demos of things- to-come in EDM/2 there, retrievable via anonymous FTP. The
machine name is os2man.sysdev.telerate.com and there is currently a demo of a
Stock Graphing program. The demo utilizes a set of graphing classes that I
wrote in C++ using Watcom's compiler. The set of classes has some work to be
done, as you will see if you get the demo, but they are already quite usable.
I plan to finish the classes and will rewrite them on my home machine ("clean
room") so that I can present a series in EDM/2 on their design and
implementation.
Regarding the Future of the Magazine
It needs to be stated again that the magazine will not be charging for
subscriptions. Enough said.
We are behind schedule in our preparation for this change, however; originally,
it was intended that the first issue should be in July (volume 3, issue 7).
This deadline can still be made, but we are far from completion of the steps
necessary to enact the change. Just thought you'd like to know.
Letters and Announcements
We have been getting scarce feedback, although better than nothing, about the
new Letters and Announcements sections. We are glad that you enjoy them. I
will reiterate the need for new columnists, however. Please send mail to me -
os2man@panix.com - if you're interested. Also, authors are always welcome;
please get the latest Article Submission Guidelines if you plan to write an
article for the magazine.
ΓòÉΓòÉΓòÉ 2. Copyright Notice ΓòÉΓòÉΓòÉ
Copyright Notice
EDM/2 is published by IQPac Inc. IQPac Inc. can be reached via U.S. Mail at
the following address:
IQPac Inc.
7 East Broadway, Box 804
New York, NY 10038
U.S.A.
Editor-in-chief Larry Salomon Jr.
Associate editor Carsten Whimster
Contributing editor Gordon Zeglinski
CEO/President Larry Salomon Jr.
All material is copyrighted by its original author. No part of this magazine
may be reproduced without permission from the original author.
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.
Neither IQPac Inc. nor this publication 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.
The OS/2 Accredited Logo is a trademark of International Business Machines
Corporation and is used by IQPac Inc. under license. This On-line Publication
is independently produced by IQPac Inc. and IBM is not responsible in any way
for its contents.
IQPac Inc. is an accredited member of the IBM Independent Vendor League.
Copyright Notice - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 3. Letters ΓòÉΓòÉΓòÉ
Letters
To write to EDM/2, send your email to os2man@panix.com and use the Subject:
line "Letters".
HTML Revisited
Ernest T Christley (ernestc@mercury.interpath.net) writes:
"I took interest in the fact that with issue 4 many of your readers are
requesting EDM/2 in HTML format. You should seriously consider adopting Howard
Gilbert's 'Sphydir'. It will generate HTML and IPF code simultaneously, and
makes HTML production a no-brainer, drag-and-drop, WPS enabled walk in the
park."
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Scratch Patch Resurrected
scratch01@aol.com writes:
"If you still answer these in EDM/2, I have a question that shouldn't be too
difficult...(why do I feel like I've missed something really obvious?)
I've noticed in several of the IBM apps (ex. VIEW.EXE) which use an MDI, the
main window's system menu is the standard system menu. However the system menu
on any child windows is different in that it uses CTRL key combinations instead
of ALT key combinations. I've noticed this behavior in several MDI type
Windows applications. Is there a simple way to do this for child windows, or
would I have to 'manually' change each system menu entry at window creation
time?"
Larry Salomon Jr. responds:
What needs to be done is to create your own accelerator table in your resource
file, load it using WinLoadAccelTable, and then set it as the child frame using
WinSetAccelTable. On the WinSetAccelTable call, make sure that the last
parameter is not NULLHANDLE, or you'll replace the accelerator table for the
entire application.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Sprites and the Magical Color Black
Jonathan Abbey (jonabbey@eden.com) writes:
"Hi Larry. I'm trying to make use of some of the ideas that you put together
in the sprite library you presented in EDM/2. I'm trying to do this on a cross
platform basis (we are developing class libraries for a game we're doing and we
want the class interface to be portable across OS/2 PM, X, and Windows, if not
Mac as well), and I'm wondering whether the techniques you presented would be
able to work if the transparent color was not black.
That is, is there something magical about black? Is it guaranteed to map into
all 0 bits on the display or something?
I guess if I can't figure out some way to be able to use an arbitrary
transparency index, I could remap things, so that all black turns into 0,0,1 or
some such, and the transparency index is converted to black.
I guess the only other ways of doing it would be by using GpiSetPel and/or by
cutting chunks out of large sprites, convert them to icons, and blit them bit
by bit to an off screen buffer, then swap it onto screen.
Yuck. I can't believe the GPI doesn't provide for 3 blit operands.
Anyway, thanks for any clarification you might be able to provide."
Larry Salomon Jr. responds:
The color black was chosen in conjunction with the ROP operation specified in
creating the monochrome bitmask. Think of how the process works conceptually
and then consider how you would create the mask. You might be able to try the
mapping method that you hinted at, but I do not know if it would work.
Converting the sprites to icons will not work because the algorithm presented
in the series is identical in concept to that which the system uses, except
that the application is responsible for creating the masks and not the system.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Custom Controls Needs a Custom Fix
Mark Mathews (mark.mathews@channel1.com) writes:
"The article 'Building Custom Controls' was great! We are porting DEU (for
DOOM) to OS/2 and we have been stuck on how to make a status bar for about 1
month. Thank you!!!!!
In the EDITOR1 example one should use the height from MINMAX instead of the
MENU. The reason is when changing the window size the height of the menu may
change, where MINMAX will not change.
Did anyone try to compile the source code with C Set++ 2.1? I tried to compile
EDITOR1.RC and I keep getting errors on MIS_BITMAP. I'm not sure yet. I'll
investigate.
I'm sending you EDITOR2.ZIP. I modified EDITOR to only have a status bar and
vertical and horizontal scrollbars ONLY. It works fine. My question is, what
is the the square windows on the lower right side of the window where the
horizontal and vertical scrollbars meet? For some reason that section has
become transparent. Can you help me?
I also want to say excellent work on the article 'Making Executable Smaller.'
Could the author expand on the subject of optimizing C code. Over the years
there are little tricks you can use to make the code faster and smaller. For
example, junk =3; if (temp==45) junk = 5; is faster and smaller than:
junk = temp==45 ? 5 : 3
BTW, if EDM/2 goes public please don't write articles like the other
programmers' magazines. Continue just what your doing. If you do that I will
be first in line to buy an EDM/2 subscription."
Eric Slaats responds:
Your suggestion to use the min/max control to set the statusbar height is
really elegant. If the menu height changes, the statusbar height will also
change. This solution prevents it, excellent. I'm afraid I can't help you
with your C-Set 2.1 problem. I don't own C-Set, and I don't know anyone who
does (or anyone who builds programs under OS/2 for that matter). Maybe someone
else can address this matter. The problem you've got with the scrollbars
really baffles me. When I executed your .EXE file, it clearly showed the
transparent area. After recompilation however, it was gone! I wasn't able to
invoke the error again. However I've noticed that a PM program can be
extremely sensitive to compiler settings. When using the MLE control I
couldn't get the find message to work properly. I've tried recompiling
examples that worked properly, but it would not work. After toying with the
compiler settings after reading about smaller .EXE files, I noticed that these
messages worked! Maybe there's a solution here (keep me posted). I've added a
the new EDITOR.CPP code (in CUSTOM.ZIP). This new code uses your min/max trick
and it is modified so that the ALT key combinations will work.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
scratch01@aol.com writes:
"Your article in the April '95 edition of EDM/2 ['Building Custom Controls']
has been very helpful. I have one question about the toolbar. In the article
you said something to the effect of '...the last menu loaded is the one
attached to the frame...' (the same thing is mentioned in a similar example
from IBM on Hobbes called FRMSUB.ZIP). However I have run into a difficulty
with this. When I press the ALT key (or the combination of ALT-anything) the
only menus that respond are the system menu and the toolbar (respond, as in
becoming selected or 'indented'). There is no response from the main (text)
menu. In fact, the only way to get a response is to use the mouse. If you are
aware of this, do you have a solution?
BTW, I tried reversing the loading order of the WinLoadMenu statements, and the
program trapped."
Eric Slaats responds:
The ALT thing you've noticed is a bug. I personally never use this feature but
(as your messages states) others do. It was rather sloppy to overlook this
problem. So I've come up with a solution. (The code is included in
CUSTOM1.ZIP). Simply reversing the loading order of the WinLoadMenu statements
isn't a solution. The program will trap because the last loaded menu (toolbar)
in this case will be handled twice and the menu won't be handled. So how does
this new code work?
The first thing we do is (indeed) swapping the WinLoadMenu statements so the
Toolbar will be loaded last. This way the toolbar will be loaded last and it
will be treated like a regular menu. Next we change the subclass window
procedure for the frame window. It must size and place the normal menu window.
So where at first the toolbar was handled we will now handle the menu. It is
still desirable that the toolbar is placed under the menubar. The toolbar is
now placed on top of the client window. So we have to put the menubar on top
and replace the toolbar directly underneath it. This is done by the following
lines:
pSWP[usMenu].x = pSWP[usToolbar].x;
pSWP[usMenu].y = pSWP[usToolbar].y +
pSWP[usToolbar].cy -
pSWP[usMenu].cy;
pSWP[usToolbar].y = pSWP[usMenu].y - pSWP[usToolbar].cy;
The menubar is placed on top by using the position and cy of the toolbar.
(Remember the toolbar has a larger height than the menubar). The last line
replaces the toolbar just under the menubar. So now every control has its
desired place and the ALT keys will work properly because the PM will attach
them to the menubar (highest menu loaded)
The code changes are marked with CODE CHANGE !!!!!!!!!
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Kudos and Stuff
Graham TerMarsch (cs27524@vcc8.langara.bc.ca) writes:
Well, just finished reading EDM/2 volume 3, issue 3, and decided that I've just
got to write and tell you a few things...
Firstly, thank you so much for releasing EDM/2. I've searched for, hoarded,
handed out, and read every single issue since its beginning and have loved
every issue; they were all helpful for something I've been working on.
If you're still accepting snippets, I'm sure I've got a few lying around that
I'd send along. I know it might be too little too late and have no excuse for
it, but if you'd like some I'd be happy to send them along.
As for what I'd like to see in an upcoming issue, I'll put my vote in with the
gentleman who suggested some info on making toolbars and button bars for an
application. I've spoken to several developers who all do it different, from
creating it as another menu option on the frame to creating a completely new
frame control from scratch. In a more broad sense, subclassing of windows
would be a really good topic; most everything I'm hung up on right now reflects
not knowing how to take proper advantage of window subclasing (especially the
frame window). Ok, maybe I'm a bit selfish on this but I'm allowed, it's my
suggestion. <grin>
I won't babble forever, but will instead thank you and all of the contributors
to EDM/2 once again for the service that you've done to all OS/2 developers. I
can say that if it wasn't for EDM/2, I probably would've given up on trying to
further my PM programming skills and would've just bought a quick and dirty
package instead.
Letters - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 4. Announcements ΓòÉΓòÉΓòÉ
Announcements
New Book Explains OS/2 Graphics Interface
A new book from John Wiley & Sons addresses the Graphics Programming Interface
(GPI) for OS/2 Warp, providing step-by- step instructions and accompanying
coding examples. The book, written by Stephen Knight and Jeffrey Ryan, covers
the full range of OS/2 GPI functions, including the latest additions to OS/2
Warp Version 3.
Programming the OS/2 Warp Version 3 GPI includes:
Drawing primitives
Working in coordinate spaces
Character fonts, metrics, sizing and positioning
Metafiles
Transformations
Over 60 screen shots, drawings and tables
Accompanying disk includes:
Graphics editor application
Text browser file
Query printer information
Other utilities
The book (416 pages, $39.95 U.S.) can be ordered as ISBN 0- 471-10718-2 or
through IBM as SR28-5681. Publisher's order line: (800) CALL-WILEY
(800-225-5945). Fax: (908) 203- 3200. For more information, e-mail:
CompBks@JWiley.Com.
John Wiley & Sons, a leading supplier of books about OS/2 and related
products, is a member of IBM's Independent Vendor League (IVL). The IVL
supports individuals and companies who develop and market books, newsletters,
magazines, training videos, courseware and consulting services for OS/2 and
other IBM personal software products.
This news release is from the IBM IVL News Service and may be freely copied
and distributed. For information about the IVL, call (203) 452-7704, fax
(203) 268-1075 or e-mail gailo@vnet.ibm.com. Send news and distribution
changes to ivlinfo@vnet.ibm.com. (OS/2 is a registered trademark of IBM
Corporation.)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
OS/2 Utilities CD-ROM Is Now Shipping
EMS Professional Shareware is now shipping the 15th (Apr'95) edition of its
OS/2 Utilities CD-ROM, with 774 carefully selected PD/Shareware ZIP files and
a database and search program so you can quickly find/view/copy/etc. $25
special "Net" price includes 3 CD-ROMs with a free copy of the 211,000 record
PC products database.
EMS Professional Shareware
4505 Buckhurst Ct.
Olney MD 20832-1830
Voice: 301-924-3594
Fax: 301-963-2708 ems@wdn.com
http://www.xmission.com/~wwwads/ems
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Perl 4 With Sockets
Located at hobbes.nmsu.edu /os2/unix/sockperl.zip
Perl for OS/2 with sockets. (This build also has use of crypt(), fork() and
-D debug options.) Built using EMX 09a with fix03 applied. This build passes
all the regression tests as the distribution version of perl.exe. Of course
this version won't run under dos at all, presumably the sock_ini call is
protect-mode only.
While perl5 with sockets is available also, some sites / systems may not be
able to support this larger .EXE, .DLL.
No changes were made to Kai's sources for Perl / OS/2.
I've run the entire test battery (using a csh script, as I don't have MAKE).
Aside from pure Unix-isms and problems in comparing strings with '<cr><lf>' on
OS/2, the only unexplained error I found was in op/magic.t, where SIG action
"DEFAULT" is supported? The only other anomaly is that this perl stops
creating new sockets after the 257th. Perhaps this is an OS/2 or OS/2 TCP/IP
limitation.
I have taken reasonable care in testing the resultant binary, but of course
there is NO WARRANTY. I have tested only a small subset of the Perl or EMX
support for Berkeley sockets.
Thanks as always to Larry for Perl, Kai for the OS/2 version, and Eberhard
Mattes for the excellent EMX environment.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Adams-Blake Publishing Announces Book on How To Be A Consultant
People who are proficient in OS2 programming have a unique opportunity to work
independently as a contract consultant. While not for everyone, for most,
doing contract work will result in a significant increase in income. Others,
especially those with children or other responsibilities, prefer the more
flexible work schedule. There are also those who seek to work out of their
home. However, it is not get-rich-quick by any stretch of the imagination.
Starting an independent consulting business is not the easiest thing in the
world but it's absolutely doable by most technically skilled people. Finding
clients and knowing how to conduct oneself in face-to-face sales situations
are the two most difficult tasks for most people. Those who want to work
through brokers or agents can do so, but they have to know how to negotiate so
the agent doesn't end up with all the money.
Technical people have the most difficulty with sales and marketing. Marketing
is not sales. Marketing is finding someone to sell to. Sales is the
face-to-face meeting. With respect to face-to-face sales, it is not like a
job interview. You must be in control and direct each "scene" of the play.
You're equal, not subservient to the client. There is no one strategy but
there are many different ways the technical sale can be (or should be) closed.
There are a multitude of agents who act as third party matchmakers. This can
be a good way to start out, however you will give up a good part of your
billing income. With agents, there are many contract pitfalls, such as the
"you're not paid until we're paid" clause you must be aware of and be able to
negotiate around.
And of course, you have to be qualified. Yet, it's not technical knowledge
that is the most necessary ingredient to success. You must have a take-a-risk
personality. You have to want an "adventure." You have to be motivated by
money because no one is going to stroke your ego while on the job.
Our publishing company has a 320 page title on the subject of technical
consulting.
With respect to the non-commercial nature of this group, we do not mention
title, price or availability. This announcement is neither an offer to sell,
nor a solicitation of an offer to buy. The offer is made only by the
prospectus.
If you have an interest and would like information, contact us by e-mail.
Jennifer Church
Adams-Blake Publishing
abpub@aol.com
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Designing Object-Oriented User Interfaces
IS International's four-day course on designing user interfaces has been
updated to include designing interfaces for OS/2 Warp. The course
incorporates presentations, demonstrations, workshops, and a sample
application scenario to teach the complete object-oriented interface design
process.
Topics include:
GUI / OOUI history, concepts and philosophy
User interface design principles and benefits
Design process
Task analysis
Components and interaction
Designing, building and testing low fidelity prototypes
Developing prototypes with IBM's VisualAge
The course is offered in both public and on-site venues. It is also available
through IBM's Object Technology University and IBM Education and Training as
the Designing Object- Oriented Interfaces Workshop, course N5010. Sessions are
taught by Ian Stopps and Harris Kravatz, both experienced in the design,
teaching and documentation of user interfaces, including IBM's Common User
Access (CUA) standard.
For more information, contact IS International at (800) 276- 1075, fax (407)
994-4373, e-mail info@isii.com, or http://www.isii.com.
IS International, an advanced education and consulting company specializing in
object-oriented design and development, is a member of IBM's Independent
Vendor League (IVL). The IVL supports individuals and companies who develop
and market books, newsletters, magazines, training videos, courseware and
consulting services for OS/2 and other IBM personal software products.
This news release is from the IBM IVL News Service and may be freely copied
and distributed. For information about the IVL, call (203) 452-7704, fax
(203) 268-1075 or e-mail gailo@vnet.ibm.com. Send news and distribution
changes to ivlinfo@vnet.ibm.com. (OS/2 is a registered trademark of IBM
Corporation.)
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
GNU Fortran (G77) Has Been Ported To EMX.
It's available for anonymous ftp on ftp.uni-stuttgart.de. Look for g77bin.zip
(binaries) and g77src.zip (source) in directory
/pub/systems/os2/emx0.9a/contrib.
It's also available for anonymous ftp on ftp.leo.org. Look for g77bin.zip
(binaries) and g77src.zip (source) in directory
/pub/comp/os/os2/gnu/emx+gcc/contrib.
Please note that this is a quite early release of g77 and has several bugs.
Please send bug reports for g77 to the address given in
/emx/gnu/gcc-2.6/f/INSTALL, except for bugs introduced by the port, which
should be reported to me.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
FREE DEMO - ZGRAF C++ Graph Toolkit
The ZGRAF C++ Graph Toolkit is a library of routines for making tech/business
graphs in several environments, including OS/2 Presentation Manager and
Windows/Windows NT.
Graph styles include X/Y, Bar, Pie, Area, Ribbon, Scatter, Polar, Log, 2-D
Function, 3-D Surface Graphs, Smith Chart, and more! The toolkit sells for
$30 (Personal Version) or $45 ( Commercial Developer Version) and includes
full C++ library source code. There are no royalties.
You can download a free demo from our BBS (see phone number below). For a
demo disk, just send e-mail with your name/address/company information
(Serious inquiries only, please. Allow 2-4 weeks for delivery).
Thanks for your interest in our products.
ZGRAF Software Products
1831 Old Hickory Ct.
New Albany, IN 47150
Phone: (812) 949-9524
BBS: (812) 949-0416, 14.4K/9600 BPS, 8/1/None
Compuserve: 70742,1356
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
REXX Cookbook by Merrill Callaway
The REXX Cookbook by Merrill Callaway is now available from WHITESTONE. The
319-page book is a tutorial written for both beginners and more experienced
programmers. Extensive use of REXX programming examples helps illustrate
topics in a real-life context. In addition to basic concepts, The REXX
Cookbook shows how to write programs that work with everyday OS/2 applications
and files, including PostScript, Structured Query Language (SQL), DB2/2,
AmiPro, and others.
The REXX Cookbook, ISBN # 0-9632773-4-0, sells in the U.S. for $27.95. A
companion disk, THE REXX FILES, ISBN # 0- 9632773-5-9, is priced at $14.95
U.S.
For more information, contact WHITESTONE at e-mail 5979987@MCIMAIL.COM or
Voice (505) 268-0678.
WHITESTONE, a publisher of books about OS/2 and related products, is a member
of IBM's Independent Vendor League (IVL). The IVL supports individuals and
companies who develop and market books, newsletters, magazines, training
videos, courseware and consulting services for OS/2 and other IBM personal
software products.
This news release is from the IBM IVL News Service and may be freely copied
and distributed. For information about the IVL, call (203) 452-7704, fax
(203) 268-1075 or e-mail gailo@vnet.ibm.com. Send news and distribution
changes to ivlinfo@vnet.ibm.com.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
JYACC Announces JAM For OS/2 At DB-Expo
DB-EXPO, San Francisco, CA - May 2, 1995 - Today, JYACC, Inc., announced the
OS/2 version of JAM (JYACC Application Manager), the leading cross-platform
tool for building client/server and distributed applications. JYACC will show
the new release for the first time at DB-Expo Booth 1162 in San Francisco's
Moscone Center.
JAM for OS/2 allows developers to build 32 bit GUI applications that fully
exploit the stability and preemptive multi-tasking features of the OS/2
platform, said Darryl Zack, JYACC Vice President of Sales and Marketing. The
ability to build OS/2 applications with JAM and re-deploy them on over 100
platforms and operating environments is an essential component in our
customers enterprise computing strategy.
With the release of JAM for OS/2 Warp, customers will be able to build and
deploy business-critical applications that are portable enough to span the
enterprise, said Jim Grant, Vice President, IBM Solution Developer Operations.
This new product from JYACC continues their tradition of support for IBM
client/server solutions, including AIX on the RS/6000, and DB2/2 and
represents another important vendor who has committed support for OS/2, the
industry's leading 32-bit operating system.
Applications developed with JAM for OS/2 can be deployed on OS/2 versions 2.x
and Warp, as well as 100 other platforms and operating environments, including
MS-Windows, DOS, Motif, VAX/VMS, Macintosh, and virtually every implementation
of UNIX. JAM also integrates seamlessly with more than twenty of the most
popular RDBMS products, and provides transparent access to legacy systems via
DRDA and Microsofts ODBC.
The $2,000 JAM for OS/2 package includes:
The complete JAM development environment.
A database driver for JYACCs built-in prototyping database (JDB).
A second, customer-selected database driver. (Users can purchase
additional database drivers if they wish. Drivers are currently
available for Oracle, Sybase, Informix, and DB2. Drivers for other RDMS
products will be offered later this year.)
Complete documentation.
JAM for OS/2 continues the JYACC tradition of never charging runtime fees.
Contact: Eric Block (212) 267-7722 or royalties for JAM-built applications.
About JAM and JYACC
JAM combines four significant advanced technologies -- visual programming,
repository-driven development, object- orientation, and high performance
transaction management. In addition to offering a fully graphical development
environment, JAM is the industry's most advanced application development tool
in delivering codeless programming and productivity. JAM is the centerpiece
of a fully integrated family of application development products that includes
a report writing tool, and interfaces to more than 20 database engines, the
leading transaction monitors (including Novell's TUXEDO and Transarc's
Encina), and CASE tools (including Cadre's Teamwork and Innovator SERM from
MID, GmbH of Germany).
JYACC offers products and services that enable developers to build high
performance client/server applications quickly and cost-effectively, integrate
them into their business environment, and maximize each application's value.
Founded in 1978 as a software consulting firm, JYACC first shipped JAM in
1985. With ten years as an industry leader and tens of thousands of JAM
development licenses sold worldwide, JYACC has impeccable credentials in the
open systems marketplace. Thanks to its power and field-proven performance,
JAM has been selected by IS organizations throughout the Fortune 1000 to build
the most demanding, mission critical applications. JYACC is based in New York
City with offices in Boston, Massachusetts; Parsippany, New Jersey; San
Francisco, California; Chicago, Illinois; Atlanta, Georgia; and Orlando,
Florida. JYACC also has offices in London (UK) and Paris, France. JYACC
Headquarters is located at 116 John Street, New York, New York 10038.
JAM and Jterm are registered trademarks of JYACC, Inc. JAM/TPi, JAM/CASE
interface, and JAM/ReportWriter are trademarks of JYACC. OS/2 and Warp are
registered trademarks of IBM, Corporation. Other brands and product names
appearing in this document may be trademarks or registered trademarks of their
respective companies.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Prominare Launches Prominare Designer
Prominare Designer, an OS/2 PM programmer's Rapid Application Development tool
for creating fully featured GUIs for OS/2, has been launched by Prominare
Inc., of Canada.
Prominare Designer allows the developer to create visual interfaces for an
application in a matter of minutes without having to write any source code.
This productivity gain remains high throughout the development of the
application, even as new visual interface elements are added.
Prominare Designer generates code for multiple class libraries and multiple
compilers, and offers the capability to generate code across platforms, e.g.
OS/2, Windows 3.1, and Windows NT, all from one tool. This feature makes the
process of developing for multiple platforms easy.
Acting as an extended resource editor, Prominare supports all versions of
OS/2, including Warp. Its inherent flexibility enables the power of C and C++
to be fully exploited, with the added benefits of intelligent code generation.
Programmers can construct compact, efficient code without unnecessary
overheads or proprietary modules.
Programmers can use one interface to create both the resources and source code
for PM applications. The resource editing capabilities of Prominare are
backwardly compatible with all versions of OS/2. This offers unique
facilities in the areas of custom controls and PM Control Extensions (PMCX),
facilities which are lacking in other tools.
Prominare supports all OS/2 PM controls including multimedia (MMPM/2) and Pen
for OS/2.
Another impressive ability is that of Prominare-created applications to easily
conform to individual companies' programming standards, coding conventions and
selected level of CUA compliance. This ability to allow programmers to modify
Prominare's source code generation rules ensures that the source code
generated conforms with company naming conventions and coding standards.
This capability is essential for speeding up programming in major companies
which are developing large applications, as the code is in a form that their
programmers already understand.
Matt Smith, Prominare Designer architect, said, "Prominare speeds the process
by removing unnecessary generation phases. When the visual design for the
application is modified, Prominare adds source code for only the parts that
have been modified since the last generation operation was carried out.
"Prominare's inherent intelligence enables the application developer to change
the look and feel of the interface without having to reprogram the actions of
individual controls. The application developer can add his or her own source
code to that generated and Prominare ensures that the application developer's
source code remains untouched the next time a change is made to the visual
design, even when new source code based on the changes is added.
Prominare Designer has a suggested retail price of $699 (US) and can be
ordered through Indelible Blue, Programmer's Paradise, Egghead Software, OS/2
Express, ImageSoft in the US. In the UK, it can be order through
Microtransfer and OneStop OS/2. A complete list of qualified resellers can
found through Prominare's WWW server at http://www.prominare.com/prominare.
Further detail on Prominare Designer can be found through Prominare's WWW
server or by sending email to designer@prominare.com.
Prominare is the Latin word which means "to drive forward," and Prominare
Designer allows developers to do just that.
Announcements - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 5. The Design and Implementation of VIOWIN (Part 8) ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 5.1. Introduction ΓòÉΓòÉΓòÉ
The Design and Implementation of VIOWIN (Part 8)
Written by Larry Salomon, Jr.
Introduction
For my job, I once had to write an application that ran only when OS/2 booted
from the floppy diskettes. Because I had no access to the functionality PM
provides, I resorted to a line-oriented interface, where messages were
displayed on the screen and scrolled up when necessary. It was a good
interface, I thought; it was fully NLS enabled and had intelligent defaults so
the user basically only had to type in the name of the application.
Unfortunately, the Quality Assurance team didn't concur with my opinion. "We
want a nice interface!" one exclaimed. "Yeah, one with different windows and
such!" another shouted.
I was backed into a corner that I could only get out of one way.
This series describes the design and implementation of VIOWIN, a library that
implements a subset of the Win APIs provided by PM for fullscreen sessions.
The reasoning behind writing this series is that it provided me and will
hopefully provide you with some unique insights into how a windowing system is
developed; and since it is based on PM, your familiarity with the already
defined interface will increase your capability to fully understand what is
being described.
Obviously, this series assumes you have PM application development experience,
but it isn't required.
This Month
This month, we will (finally) wrap up the series with the VWWC_BUTTON class.
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.2. Button Controls ΓòÉΓòÉΓòÉ
Button Controls
VIOWIN implements three types of button controls: pushbuttons, checkboxes, and
radiobuttons. Checkboxes and radiobuttons are assumed to be the "auto" type,
meaning that they process the painting themselves. Ownerdrawn buttons are not
supported. I need not describe the functionality of each, but it should be
noted that even though all three types belong to the same window class, they
are different enough that they can "logically" be considered of distinct
classes.
There are four helper functions used by the static control (the term "subclass"
is used below to refer to the different types of button classes):
pushButtonProc() - processes the messages for the push button "subclass."
checkBoxProc() - processes the messages for the check box "subclass."
radioButtonProc() - processes the messages for the radio button "subclass."
findGroupButton() - finds a specified radio button within a group (first, last,
previous, or next).
The first three simply process the WM_PAINT, WM_CHAR, and BM_ messages.
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.3. The Instance Data and Other Things ΓòÉΓòÉΓòÉ
The Instance Data and Other Things
The instance data is shown in the code below. The definitions of the fields
are listed afterwards.
#define RB_SELECTED 'o'
#define CB_SELECTED 'x'
typedef struct _INSTDATA {
ULONG ulSzStruct;
ULONG ulStyle;
BOOL bChecked;
} INSTDATA, *PINSTDATA;
Field Definition
ulSzStruct Size of the structure in bytes
ulStyle Style of the window
bChecked TRUE if this is a checkbox and it is checked. FALSE
otherwise.
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume
3, Issue 5
ΓòÉΓòÉΓòÉ 5.4. The pushButtonProc() Function ΓòÉΓòÉΓòÉ
The pushButtonProc() Function
The appearance of the button is simply a rectangle with the text centered
within. If the button has the focus, the text colors (foreground and
background) are inverted. While it would have been nice to draw a border
around the button, it was determined that the 200% increase in height (since
extra two rows are necessary but the button only has one row of text) wasn't
worth it.
MRESULT EXPENTRY pushButtonProc(HVWWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2)
//-------------------------------------------------------------------------
// This "sub-window procedure" handles the push button-specific messages
//-------------------------------------------------------------------------
{
PINSTDATA pidData;
pidData=vwQueryWindowPtr(hwndWnd,1);
switch (ulMsg) {
case WM_PAINT:
{
RECTL rclWnd;
CHAR achText[256];
ULONG ulFore;
ULONG ulBack;
vwQueryWindowRect(hwndWnd,&rclWnd);
rclWnd.xRight--;
rclWnd.yTop--;
vwQueryWindowText(hwndWnd,sizeof(achText),achText);
ulFore=vwQueryForeColor(hwndWnd);
ulBack=vwQueryBackColor(hwndWnd);
//----------------------------------------------------------------
// Fill ourselves with the background color.
//----------------------------------------------------------------
vwFillRect(hwndWnd,&rclWnd,ulBack);
//----------------------------------------------------------------
// If we have the focus, invert the colors to indicate this
//----------------------------------------------------------------
if (vwQueryFocus()==hwndWnd) {
ulFore^=0x000000FF;
ulBack^=0x000000FF;
} /* endif */
//----------------------------------------------------------------
// Draw the button text
//----------------------------------------------------------------
vwDrawText(hwndWnd,
-1,
achText,
&rclWnd,
ulFore,
ulBack,
DT_CENTER|DT_VCENTER);
}
break;
case WM_CHAR:
{
USHORT usFlags;
USHORT usMods;
//----------------------------------------------------------------
// Code like this is what makes me appreciate the similarities
// of the library to the corresponding PM code. Here, we
// check to see if we've been selected using the <SPACE> or
// <ENTER> keys (either one).
//----------------------------------------------------------------
usFlags=KC_VIRTUALKEY | KC_KEYUP;
usMods=KC_ALT | KC_CTRL | KC_SHIFT;
if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
switch (CHARMSG(&ulMsg)->vkey) {
case VK_SPACE:
case VK_ENTER:
case VK_NEWLINE:
vwPostMsg(hwndWnd,BM_CLICK,0,0);
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
}
break;
case WM_QUERYDLGCODE:
return MRFROMLONG(DLGC_BUTTON);
case BM_CLICK:
vwPostMsg(VWHWND_DESKTOP,
WM_COMMAND,
MPFROMSHORT(vwQueryWindowUShort(hwndWnd,QWS_ID)),
0);
break;
case BM_QUERYCHECKINDEX:
return MRFROMSHORT(-1);
case BM_QUERYHILITE:
break;
case BM_SETHILITE:
break;
case BM_QUERYCHECK:
return MRFROMSHORT(FALSE);
case BM_SETCHECK:
return MRFROMSHORT(FALSE);
case BM_SETDEFAULT:
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
return MRFROMLONG(FALSE);
}
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.5. The checkBoxProc() Function ΓòÉΓòÉΓòÉ
The checkBoxProc() Function
Note the choice (in the "Instance Data and Other Things" section) of character
for the checked state of the button ("x"). While "√" is probably a better
choice, this character might not exist in other codepages, so we'll stick to
one that is more likely to exist.
MRESULT EXPENTRY checkBoxProc(HVWWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2)
//-------------------------------------------------------------------------
// This "sub-window procedure" handles the check box-specific messages
//-------------------------------------------------------------------------
{
PINSTDATA pidData;
pidData=vwQueryWindowPtr(hwndWnd,1);
switch (ulMsg) {
case WM_PAINT:
{
CHAR achFmt[256];
CHAR chCheck;
CHAR achText[256];
ULONG ulFore;
ULONG ulBack;
vwQueryWindowText(hwndWnd,sizeof(achFmt),achFmt);
//----------------------------------------------------------------
// See if we're checked and, if so, display the appropriate
// character in the brackets.
//----------------------------------------------------------------
chCheck=pidData->bChecked?CB_SELECTED:' ';
sprintf(achText,"[%c] %s",chCheck,achFmt);
ulFore=vwQueryForeColor(hwndWnd);
ulBack=vwQueryBackColor(hwndWnd);
//----------------------------------------------------------------
// If we have the focus, invert the colors to indicate this
//----------------------------------------------------------------
if (vwQueryFocus()==hwndWnd) {
ulFore^=0x000000FF;
ulBack^=0x000000FF;
} /* endif */
//----------------------------------------------------------------
// Draw the button text as we have built it above
//----------------------------------------------------------------
vwDrawText(hwndWnd,
-1,
achText,
NULL,
ulFore,
ulBack,
DT_LEFT|DT_VCENTER|DT_ERASERECT);
}
break;
case WM_CHAR:
{
USHORT usFlags;
USHORT usMods;
usFlags=KC_VIRTUALKEY | KC_KEYUP;
usMods=KC_ALT | KC_CTRL | KC_SHIFT;
if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
//----------------------------------------------------------------
// If the user pressed the spacebar, toggle the checked state
// by sending ourselves a BM_CLICK message
//----------------------------------------------------------------
switch (CHARMSG(&ulMsg)->vkey) {
case VK_SPACE:
vwPostMsg(hwndWnd,BM_CLICK,0,0);
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
}
break;
case WM_QUERYDLGCODE:
return MRFROMLONG(DLGC_BUTTON);
case BM_CLICK:
//-------------------------------------------------------------------
// Toggle the check state, repaint ourselves, and send the
// notification to our owner, which is always the desktop.
//-------------------------------------------------------------------
pidData->bChecked=!pidData->bChecked;
vwSendMsg(hwndWnd,WM_PAINT,0,0);
vwSendMsg(VWHWND_DESKTOP,
WM_CONTROL,
MPFROM2SHORT(vwQueryWindowUShort(hwndWnd,QWS_ID),
BN_CLICKED),
MPFROMHWND(hwndWnd));
break;
case BM_QUERYCHECKINDEX:
return MRFROMSHORT(-1);
case BM_QUERYHILITE:
break;
case BM_SETHILITE:
break;
case BM_QUERYCHECK:
return MRFROMSHORT(pidData->bChecked);
case BM_SETCHECK:
pidData->bChecked=SHORT1FROMMP(mpParm1);
vwSendMsg(hwndWnd,WM_PAINT,0,0);
break;
case BM_SETDEFAULT:
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
return MRFROMLONG(FALSE);
}
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.6. The radioButtonProc() Function ΓòÉΓòÉΓòÉ
The radioButtonProc() Function
This one was the most tricky to handle because of the processing of the arrow
keys. In PM, pressing the up or left arrow moves the focus to the previous
button in the group and the down and right arrow moves the focus to the next
button in the group. After spending a couple of days on this and still not
successfully accomplishing the desired behavior, I removed the code to the
findGroupButton() function which greatly simplified this window procedure.
MRESULT EXPENTRY radioButtonProc(HVWWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2)
//-------------------------------------------------------------------------
// This "sub-window procedure" handles the radio button-specific messages
//-------------------------------------------------------------------------
{
PINSTDATA pidData;
pidData=vwQueryWindowPtr(hwndWnd,1);
switch (ulMsg) {
case WM_PAINT:
{
CHAR achFmt[256];
CHAR chCheck;
CHAR achText[256];
ULONG ulFore;
ULONG ulBack;
vwQueryWindowText(hwndWnd,sizeof(achFmt),achFmt);
//----------------------------------------------------------------
// See if we're checked and, if so, display the appropriate
// character in the brackets.
//----------------------------------------------------------------
chCheck=pidData->bChecked?RB_SELECTED:' ';
sprintf(achText,"(%c) %s",chCheck,achFmt);
ulFore=vwQueryForeColor(hwndWnd);
ulBack=vwQueryBackColor(hwndWnd);
//----------------------------------------------------------------
// If we have the focus, invert the colors to indicate this
//----------------------------------------------------------------
if (vwQueryFocus()==hwndWnd) {
ulFore^=0x000000FF;
ulBack^=0x000000FF;
} /* endif */
//----------------------------------------------------------------
// Draw the button text as we have built it above
//----------------------------------------------------------------
vwDrawText(hwndWnd,
-1,
achText,
NULL,
ulFore,
ulBack,
DT_LEFT|DT_VCENTER|DT_ERASERECT);
}
break;
case WM_CHAR:
{
USHORT usFlags;
USHORT usMods;
usFlags=KC_VIRTUALKEY | KC_KEYUP;
usMods=KC_ALT | KC_CTRL | KC_SHIFT;
if ((CHARMSG(&ulMsg)->fs & usFlags)!=usFlags) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
if ((CHARMSG(&ulMsg)->fs & usMods)!=0) {
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
//----------------------------------------------------------------
// If the user pressed <SPACE> or either <ENTER> key, select
// ourselves. If they pressed the <UP> or <LEFT> keys, click the
// previous button in the group. If they pressed the <DOWN> or
// <RIGHT> keys, click the next button in the group.
//----------------------------------------------------------------
switch (CHARMSG(&ulMsg)->vkey) {
case VK_SPACE:
case VK_ENTER:
case VK_NEWLINE:
vwPostMsg(hwndWnd,BM_CLICK,0,0);
break;
case VK_UP:
case VK_LEFT:
{
HVWWND hwndPrev;
hwndPrev=findGroupButton(hwndWnd,QW_PREV);
if (hwndPrev==NULLHANDLE) {
hwndPrev=findGroupButton(hwndWnd,QW_BOTTOM);
} /* endif */
vwSendMsg(hwndPrev,BM_CLICK,MPFROMSHORT(TRUE),0);
}
break;
case VK_DOWN:
case VK_RIGHT:
{
HVWWND hwndNext;
hwndNext=findGroupButton(hwndWnd,QW_NEXT);
if (hwndNext==NULLHANDLE) {
hwndNext=findGroupButton(hwndWnd,QW_TOP);
} /* endif */
vwSendMsg(hwndNext,BM_CLICK,MPFROMSHORT(TRUE),0);
}
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
}
break;
case WM_QUERYDLGCODE:
return MRFROMLONG(DLGC_BUTTON);
case BM_CLICK:
{
SHORT sIndex;
HVWWND hwndCheck;
//----------------------------------------------------------------
// If we've been clicked, we need to find the button _within our
// group_ that is currently selected, unselect it, and then
// select ourselves. This is not as trivial as it sounds, but
// the code below doesn't indicate this. See findGroupButton().
// - - - - - - - - - - - - - -
// Send ourselves a BM_QUERYCHECKINDEX to see who currently is
// selected in the group.
//----------------------------------------------------------------
sIndex=SHORT1FROMMR(vwSendMsg(hwndWnd,BM_QUERYCHECKINDEX,0,0));
//----------------------------------------------------------------
// If sIndex is not -1, find the button and uncheck it.
//----------------------------------------------------------------
if (sIndex!=-1) {
hwndCheck=findGroupButton(hwndWnd,QW_TOP);
while (sIndex>0) {
hwndCheck=findGroupButton(hwndCheck,QW_NEXT);
sIndex--;
} /* endwhile */
} else {
hwndCheck=NULLHANDLE;
} /* endif */
if (hwndCheck!=NULLHANDLE) {
vwSendMsg(hwndCheck,BM_SETCHECK,MPFROMSHORT(FALSE),0);
} /* endif */
//----------------------------------------------------------------
// Check ourselves, set the focus to us, and send the notification
// to our owner (the desktop).
//----------------------------------------------------------------
vwSendMsg(hwndWnd,BM_SETCHECK,MPFROMSHORT(TRUE),0);
vwSetFocus(hwndWnd);
vwSendMsg(VWHWND_DESKTOP,
WM_CONTROL,
MPFROM2SHORT(vwQueryWindowUShort(hwndWnd,QWS_ID),
BN_CLICKED),
MPFROMHWND(hwndWnd));
}
break;
case BM_QUERYCHECKINDEX:
{
HWND hwndGroup;
SHORT sIndex;
//----------------------------------------------------------------
// Moving the findGroupButton() code to a separate function
// made this a lot easier. Amen to code-readability!
// - - - - - - - - - - - - - -
// Start from the top and enumerate all of the buttons in the
// group until we find one that is checked.
//----------------------------------------------------------------
hwndGroup=findGroupButton(hwndWnd,QW_TOP);
if (hwndGroup==NULLHANDLE) {
return MRFROMSHORT(-1);
} /* endif */
sIndex=0;
if (SHORT1FROMMR(vwSendMsg(hwndGroup,BM_QUERYCHECK,0,0))==TRUE) {
return MRFROMSHORT(sIndex);
} /* endif */
hwndGroup=findGroupButton(hwndGroup,QW_NEXT);
while (hwndGroup!=NULLHANDLE) {
sIndex++;
if (SHORT1FROMMR(vwSendMsg(hwndGroup,BM_QUERYCHECK,0,0))==TRUE) {
return MRFROMSHORT(sIndex);
} /* endif */
hwndGroup=findGroupButton(hwndGroup,QW_NEXT);
} /* endwhile */
return MRFROMSHORT(-1);
}
case BM_QUERYHILITE:
break;
case BM_SETHILITE:
break;
case BM_QUERYCHECK:
return MRFROMSHORT(pidData->bChecked);
case BM_SETCHECK:
pidData->bChecked=SHORT1FROMMP(mpParm1);
vwSendMsg(hwndWnd,WM_PAINT,0,0);
break;
case BM_SETDEFAULT:
break;
default:
return vwDefWindowProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endswitch */
return MRFROMLONG(FALSE);
}
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.7. The findGroupButton() Function ΓòÉΓòÉΓòÉ
The findGroupButton() Function
This does the hard work for the radio buttons. Note the following behavioral
characteristics:
The previous button of the top button in the group does not exist.
The next button of the bottom button in the group does not exist.
The previous or next button in the group must be a radio button, but
having a checkbox in the middle of the group does not delineate the
group.
HVWWND findGroupButton(HVWWND hwndWnd,LONG lCmd)
//-------------------------------------------------------------------------
// This function finds the group button in the appropriate position given
// a button handle in the same group.
//
// Input: hwndWnd - button handle in the group to check
// lCmd - a QW_ constant (from the vwQueryWindow() function)
// Returns: specified button handle if successful, NULLHANDLE otherwise
//-------------------------------------------------------------------------
{
HVWWND hwndTop;
HVWWND hwndBottom;
HVWWND hwndReturn;
ULONG ulStyle;
CHAR achClass[256];
BOOL bIsRadioButton;
HVWWND hwndLast;
//----------------------------------------------------------------------
// Of the four QW_ constants, QW_PREV and QW_NEXT make recursive calls
// specifying QW_TOP and QW_BOTTOM respectively. Thus, the latter two
// must be entirely self-contained in order to avoid an endless
// recursive loop. Additionally, QW_PREV cannot call QW_NEXT, nor can
// QW_NEXT call QW_PREV.
//----------------------------------------------------------------------
switch (lCmd) {
case QW_PREV:
//-------------------------------------------------------------------
// Query the top of the group and check for equality with the
// specified window. If they match, return NULLHANDLE.
//-------------------------------------------------------------------
hwndTop=findGroupButton(hwndWnd,QW_TOP);
if (hwndWnd==hwndTop) {
return NULLHANDLE;
} /* endif */
hwndReturn=hwndWnd;
//-------------------------------------------------------------------
// Work our way backwards in the window chain until we find the
// first radio button.
//-------------------------------------------------------------------
do {
hwndReturn=vwQueryWindow(hwndReturn,QW_PREV);
if (hwndReturn==NULLHANDLE) {
return NULLHANDLE;
} /* endif */
ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
(((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
((ulStyle & BS_RADIOBUTTON)!=0)));
} while (!bIsRadioButton); /* enddo */
return hwndReturn;
case QW_NEXT:
//-------------------------------------------------------------------
// Query the bottom of the group and check for equality with the
// specified window. If they match, return NULLHANDLE.
//-------------------------------------------------------------------
hwndBottom=findGroupButton(hwndWnd,QW_BOTTOM);
if (hwndWnd==hwndBottom) {
return NULLHANDLE;
} /* endif */
hwndReturn=hwndWnd;
//-------------------------------------------------------------------
// Work our way forewards in the window chain until we find the
// first radio button.
//-------------------------------------------------------------------
do {
hwndReturn=vwQueryWindow(hwndReturn,QW_NEXT);
if (hwndReturn==NULLHANDLE) {
return NULLHANDLE;
} /* endif */
ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
(((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
((ulStyle & BS_RADIOBUTTON)!=0)));
} while (!bIsRadioButton); /* enddo */
return hwndReturn;
case QW_TOP:
//-------------------------------------------------------------------
// Start with the window specified and work our way backwards until
// we either reach the beginning
//-------------------------------------------------------------------
hwndReturn=hwndWnd;
hwndLast=hwndReturn;
ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
while ((ulStyle & WS_GROUP)==0) {
hwndReturn=vwQueryWindow(hwndReturn,QW_PREV);
//----------------------------------------------------------------
// If we've reached the beginning of the window chain return the
// last valid one that we saw
//----------------------------------------------------------------
if (hwndReturn==NULLHANDLE) {
return hwndLast;
} /* endif */
ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
(((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
((ulStyle & BS_RADIOBUTTON)!=0)));
//----------------------------------------------------------------
// If the current window (hwndReturn) is of the class VWWC_BUTTON
// and the style indicates it's a radio button, remember this
// window handle
//----------------------------------------------------------------
if (bIsRadioButton) {
hwndLast=hwndReturn;
} /* endif */
} /* endwhile */
return hwndReturn;
case QW_BOTTOM:
hwndReturn=hwndWnd;
hwndLast=hwndReturn;
//-------------------------------------------------------------------
// Start here and search forward until we find either the end of
// the window chain or the beginning of the next group. Note that
// we can't set ulStyle to the window style because, if this is
// the first button in the group, we will return it instead of the
// proper value.
//-------------------------------------------------------------------
ulStyle=0;
while ((ulStyle & WS_GROUP)==0) {
hwndReturn=vwQueryWindow(hwndReturn,QW_NEXT);
//----------------------------------------------------------------
// If we've reached the end of the window chain return the
// last valid one that we saw
//----------------------------------------------------------------
if (hwndReturn==NULLHANDLE) {
return hwndLast;
} /* endif */
ulStyle=vwQueryWindowULong(hwndReturn,QWL_STYLE);
vwQueryClassName(hwndReturn,sizeof(achClass),achClass);
bIsRadioButton=((strcmp(achClass,VWWC_BUTTON)==0) &&
(((ulStyle & BS_AUTORADIOBUTTON)!=0) ||
((ulStyle & BS_RADIOBUTTON)!=0)));
//----------------------------------------------------------------
// If the current window (hwndReturn) is of the class VWWC_BUTTON
// and the style indicates it's a radio button, remember this
// window handle
//----------------------------------------------------------------
if ((bIsRadioButton) && ((ulStyle & WS_GROUP)==0)) {
hwndLast=hwndReturn;
} /* endif */
} /* endwhile */
return hwndLast;
default:
return NULLHANDLE;
} /* endswitch */
}
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume
3, Issue 5
ΓòÉΓòÉΓòÉ 5.8. The Window Procedure ΓòÉΓòÉΓòÉ
The Window Procedure
The actual window procedure simply handles the WM_CREATE and WM_DESTROY
messages, to allocate and destroy the instance data. Other messages are passed
to the appropriate "sub window procedure" based on the window style.
MRESULT EXPENTRY VwButtonClassProc(HVWWND hwndWnd,
ULONG ulMsg,
MPARAM mpParm1,
MPARAM mpParm2)
//-------------------------------------------------------------------------
// This window procedure simply processes the WM_CREATE and WM_DESTROY
// messages and otherwise calls the appropriate "sub window procedure"
// to handle the other messages. This must be done this way since all
// button types are of the same class.
//-------------------------------------------------------------------------
{
PINSTDATA pidData;
pidData=vwQueryWindowPtr(hwndWnd,1);
switch (ulMsg) {
case WM_CREATE:
pidData=calloc(1,sizeof(INSTDATA));
if (pidData==NULL) {
return MRFROMSHORT(TRUE);
} /* endif */
vwSetWindowPtr(hwndWnd,1,pidData);
pidData->ulSzStruct=sizeof(INSTDATA);
pidData->ulStyle=vwQueryWindowULong(hwndWnd,QWL_STYLE);
pidData->bChecked=FALSE;
return MRFROMSHORT(FALSE);
case WM_DESTROY:
vwSetWindowPtr(hwndWnd,1,NULL);
free(pidData);
return MRFROMSHORT(FALSE);
default:
if ((pidData->ulStyle & BS_AUTOCHECKBOX)!=0) {
return checkBoxProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} else
if ((pidData->ulStyle & BS_CHECKBOX)!=0) {
return checkBoxProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} else
if ((pidData->ulStyle & BS_AUTORADIOBUTTON)!=0) {
return radioButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} else
if ((pidData->ulStyle & BS_RADIOBUTTON)!=0) {
return radioButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} else {
//----------------------------------------------------------------
// Assume it is a pushbutton.
//----------------------------------------------------------------
return pushButtonProc(hwndWnd,ulMsg,mpParm1,mpParm2);
} /* endif */
} /* endswitch */
}
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 5.9. Conclusion ΓòÉΓòÉΓòÉ
Conclusion
This concludes the VIOWIN implementation. It has been demonstrated that a
subset of PM can be defined for character mode applications, if the proper
subset is defined by the designer. By implementing a subset of PM instead of
developing a new user interface, we allow the programmer to leverage their PM
experience when developing character-mode interfaces. This results in a much
higher productivity, since they can "just do it" instead of having to concern
themselves with learning how to program a new user interface (which includes
the pitfalls and idiosyncrasies also).
Where can we go from here? To be honest, I have thought of reimplementing
VIOWIN many times to include overlapping windows, a hierarchical parent-child
and owner-ownee set of relationships, more window classes (especially listboxes
and menus), and then more resource types (especially dialog boxes). After this
is done, it could be investigated whether or not a subset of the ICLUI ("IBM
Class Libraries for User Interface," I believe) could be implemented on top of
the new VIOWIN to allow C++ programmers to also gain the advantages of a
familiar programming paradigm.
The Design and Implementation of VIOWIN (Part 8) - EDM/2 - May 1995 - Volume 3,
Issue 5
ΓòÉΓòÉΓòÉ 6. RMX-OS2: An In-Depth View (Part 4) ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 6.1. Introduction ΓòÉΓòÉΓòÉ
RMX-OS2: An In-Depth View (Part 4)
Written by Johan Wikman
Introduction
This is the fourth article in a series where I am describing RMX. RMX is a
system that allows OS/2 PM applications to run remotely, that is, to run on one
computer and be used on another. Now, supposing you have an application that
you want to run remotely, how do you start it on the remote computer? In this
article I will describe how that can be done.
I assume you have read the previous articles, especially the one dealing with
the mechanism RMX uses for the communication between different processes.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.2. The Problem ΓòÉΓòÉΓòÉ
The Problem
In the normal case, when applications are run locally, starting an application
is not a problem. If the application has an program-object it is enough to
double-click on that, or you can simply start it from the command line.
Starting an application from within another application is almost as trivial.
Using one of the spawn() functions from the C-library or DosExecPgm() directly
it is easy to start other applications.
The documentation of DosExecPgm() states that it cannot be used for starting an
application that is of different type (fullscreen, windowed, PM application)
than the starting application, but DosStartSession() must be used instead. I
don't know what the situation actually is, because I have at least not
experienced any problems when starting PM applications (using DosExecPgm())
from non-PM applications.
Anyway, when running remote applications the situation is quite different.
Obviously DosExecPgm() is not capable of starting an application on another
computer. The conclusion is that we need some mechanism on the other computer
that starts the application that is to appear on the local computer. So, what
is this mechanism? Well, the mechanism is another remote application that is
prepared to accept commands from the local computer and start other remote
applications.
This is almost a CATCH-22 situation<grin>. To run remote applications we need
another remote application (actually mechanism as it need not be a single
application) that starts them for us.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.3. Standard Solutions ΓòÉΓòÉΓòÉ
Standard Solutions
Depending on what network is being used, there are certain standard solutions
for running applications remotely.
TCP/IP
Apart from being a protocol, the TCP/IP concept includes a lot of different
applications. Provided the right daemons are running (I won't go into that
now) it is possible to use TELNET for logging into a computer and running
programs remotely. Currently I have two computers at home, the hostname of one
of them is odin, and the hostname of the other is loke. While sitting at odin,
I can log into loke the following way:
[C:\]telnet loke
After having entered my password, I get an almost ordinary command-line prompt.
[<loke>-C:\]
Although I sit at odin, whatever I do is executed in the context of loke.
Typing dir shows me the context of the C-drive of loke. If I run command-line
programs they also run on loke, but I can interract with them on odin I am
sitting at. However, If I start a PM application then it will appear on loke,
and not on odin. That is, TELNET as such does not allow PM application to be
used remotely. If you remember from previous articels, all that is required in
order to run an RMX application is that the environment variable RMXDISPLAY has
been set. So, if I want to run a PM application on loke, yet be able to use it
on odin I would:
[<loke>-C:\]set RMXDISPLAY=odin[<loke>-C:\]start
pulse.exe
This works, provided PULSE.EXE has been patched the way I described in a
previous article.
Named Pipes
LAN Server (perhaps some other products as well) provides the possibility of
running programs on another computer using the command NETRUN. I have never
tried it out, but supposedly it would be possible to set the RMXDISPLAY
variable and start an application (patched for RMX) using it.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.4. Custom Solutions ΓòÉΓòÉΓòÉ
Custom Solutions
Even if the TELNET option works and even if TELNET as such is very useful, the
option is rather limited. In practice it would be, I can imagine, quite
difficult to create a program object that automatically would start a remote
application. Also, the TELNET option is present only on TCP/IP networks. For
these reasons, but also because it was a nice problem<grin>, I developed a
custom solution that is independent from any applications provided by the
network software. The solution consists of three programs: RMXSTRTR.EXE,
RMXSTART.EXE and RMXSTOP.EXE.
RMXSTRTR.EXE and RMXSTART.EXE runs on different computers. RMXSTRTR.EXE is a
daemon application that usually is started when the computer is booted. It
sits there idle, waiting for start requests from RMXSTART.EXE that is run on
some other computer. RMXSTOP.EXE provides a graceful way of stopping a
(possibly) detached RMXSTRTR.EXE.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.5. RMXSTRTR.EXE ΓòÉΓòÉΓòÉ
RMXSTRTR.EXE
The overall structure of RMXSTRTR.EXE is illustrated in the following figure.
So, what is going on?
When RMXSTRTR.EXE is started, it initializes itself, which among other things
involves the creation of two semaphores.
1. If it succeeds in the initializing, it spawns a second thread.
2. The startup thread then blocks on one of the semaphores.
3. The started thread creates a connection, which it subsequently blocks on.
4. When some instance of RMXSTART.EXE somewhere on the network opens the
connection, the thread
5. immediately spawns a new thread and passes the connection handle along.
The current thread (thread 2) then loops back to step 4.
6. The new thread reads the start request from RMXSTART,
7. starts the requested application, and
8. sends a response telling whether the starting succeeded. Finally it just
dies.
Having a separate thread for each client ensures that the likelihood that
RMXSTRTR would be busy when an instance of RMXSTART attempts to open a
connection is quite small. Nevertheless, under heavy load the task of
spawning a new thread might take a while, so a better approach would perhaps
be to have a number of threads ready for immediate dispatch.
Main function of RMXSTRTR
Let's look then at the main function of RMXSTRTR in greater detail (the actual
code is available in a zip-file you should have got along with this issue).
set_new_handler(OutOfMem);
ios::sync_with_stdio();
The first call establishes a function that is called when the C++ operator new
fails to allocate memory. It is unlikely that an out-of-memory situation ever
occurs, but it doesn't hurt. The function specified simply writes a message
and terminates the application. The following call synchronizes the C++
output mechanism (cout) with the C output mechanism (printf). This is
necessary because both are being used within RMXSTRTR.
ULONG ulFunctionOrder = MAKEUSHORT(EXLST_ADD, 0xFF);
DosExitList(ulFunctionOrder, CleanUp);
Then we register a cleanup-function. The function registered - CleanUp() -
will be called by the system regardless of how RMXSTRTR is terminated. The
first argument of DosExitList() specifies what we want to do. The high-order
word should be 0, and the low-order word contains the actual information as
two one-byte fields. The lower of the bytes specifies the action: EXLST_ADD
indicates that we are adding a function to the cleanup-functions, EXLST_REMOVE
indicates that we want to remove an existing function, and EXLST_EXIT
indicates that we have done our processing and the system should call the next
function. EXLST_EXIT is used only from within the actual cleanup-function.
The higher of the bytes specifies where the registered function should be
placed in the list of cleanup- functions. Functions with an order code of 0x0
are invoked first, and functions with an order code of 0xFF are invoked last.
hev = CreateEventSemaphore();
hmtx = CreateMutexSemaphore();
Two semaphores - one of them an event-semaphore and the other a
mutex-semaphore - are created. The main thread blocks on the event-semaphore
when it has initialized everything and has started the thread that does the
actual job. As I will show later, the name used for the semaphore is
constructed from the value of the environment variable RMXCOMMS. Doing this
gives us two benefits:
It effectively means that there can only be one RMXSTRTR running using a
specific RMXCOMMS DLL. This is what we want, as it does not make sense
to have several instances of RMXSTRTR that uses the same communications
DLL. On the other hand it allows several instances of RMXSTRTR to run,
provided they use a different DLL.
As the name of the semaphore is constructed from the value of RMXCOMMS it
means that we later can open the semaphore and post it, thus causing the
(possibly detached) RMXSTRTR to exit.
It is here that RMXSTRTR exits after having printed an error message if the
creation of the event semaphore fails, as that indicates that an RMXSTRTR
using the same RMXCOMMS DLL already is running. The mutex semaphore is used
for synchronizing the output of different threads.
PSZ pszName = GetStarterName();
The next this to do is to obtain the name RMXSTRTR should listen on.
GetStarterName() is implemented on top of the RMXCOMMS function
RmxGetServiceName(). That means that the contents of the buffer that is
returned varies depending on which actual communications DLL is being used.
That doesn't matter, however, as we do not care what it contains.
void (*firstThread)(void*) = (void (*)(void*)) StarterLoop;
int tid = _beginthread(firstThread, SIZE_STACK, pszName);
Once the semaphores have been created and the name RMXSTRTR should be
listening on has been obtained, the thread that does the actual work can be
started. The function _beginthread() is the C RTL function for creating
threads. The first argument is a pointer to a function that takes a void* as
argument and returns nothing, the second argument is the size of the stack,
and the third argument is an argument that should be provided to the thread
function (the one given as first argument). This is the Borland format, the
prototype is slightly different in IBM and other compilers. The function we
want to use as thread function - StarterLoop() - is otherwise ok, except that
it takes a PSZ as argument and not a void*. The funny looking variable
declaration above the call to _beginthread() is simply there for making
StarterLoop() acceptable as argument. This is perfectly safe as PSZ and void*
are fully compatible in this context.
DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
Once the new thread has been started, the main thread simply blocks on the
created semaphore. There it stays forever if need be.
Starter Loop
Essentially the starter loop - as shown in the figure earlier - is very
simple. It is a tight loop where a connection is created, a connecting
instance of RMXSTART is waited for, and a handler thread that does the job is
spawned.
while (TRUE) {
create connection
wait for RMXSTART
spawn handler thread
}
The connection is created the following way.
HCONNECTION hConn;
ULONG rc;
rc = RmxCreate(pcszName, &hConn);
The name of the connection - pcszName - was obtained as an argument to the
function. It is the same name as was used in the call to _beginthread() in
the main thread. If the call is successful, hConn contains the connection
handle.
RmxConnect(hConn);
This call blocks until somebody opens the connection. The task of actually
starting an application is a rather heavy operation, so a separate thread is
dedicated for it.
_beginthread(HandlerThread, SIZE_STACK, (VOID*) hConn);
The connection handle is provided as thread argument. Immediately when the
thread has been started a new connection is created and RMXSTRTR is ready for
another client.
Handling the Client
The client wants RMXSTRTR to start an application. Exactly which one, the
client (RMXSTART) has to tell RMXSTRTR. The first thing to do then, is to
read the entire request the client sent. For that purpose a small structure
has been defined.
struct Request{
PBYTE pbRequest;
ULONG ulSize;
};
So first the entire request is read.
Request request;
ReadRequest(hConn, &request);
The hConn was received by the thread when it was started. ReadRequest() (which
I won't look at in detail) simply reads everything the client has sent and
allocates a sufficiently large buffer on behalf of the caller where it stores
the data. ulSize is updated to the actual size of the data sent by the
client. We need to know the exact size of the request as we cannot trust the
client to provide us with data of proper format.
Once the request has been read, we must parse it. A proper request is of one
of the following formats,
DISPLAY0APPLICATION00
DISPLAY0APPLICATION0ATTRIBUTES00
where DISPLAY, APPLICATION and ATTRIBUTES denotes strings (without ending
NULL). That is, two or three catenated ASCIIZ strings followed by an
additional NULL.
PSZ pszDisplay, pszApplication, pszArguments;
ParseRequest(&request, &pszDisplay, &pszApplication,
&pszArguments);
ParseRequest() takes a request and sets the three provided PSZ pointers to
point at the correct place in the request buffer. Once the request has
successfully been parsed, we can call the function that actually starts the
application.
StartApp(pszDisplay, pszApplication, pszArguments);
When the application has been started a return code is sent back to the
client. What the return code - rc - actually is depends on whether everything
done so far has succeeded.
SendResponse(hConn, rc);
Finally when everything is ready, the connection can be disconnected and
closed.
RmxDisConnect(hConn);RmxClose(hConn);
Starting the Application
Ok, now we have got so far that the request sent by the client (RMXSTART.EXE)
has been read and parsed. Now it's time to start the application. But, we
don't yet know for sure that the application the client specified actually
exists. The first this to do is to find out if the application path specified
by the client can be used directly.
ULONG rc = NO_ERROR;CHAR achPath[CCHMAXPATH];if
(access(pcszApplication, 0)){
Access() returns zero if the string provided as first argument denotes an
application. That is, we end up in the if-branch if the application is not
found. The next thing is to look for the application on the path.
rc = DosSearchPath(SEARCH_IGNORENETERRS |
SEARCH_ENVIRONMENT |
SEARCH_CUR_DIRECTORY,
"PATH",
pcszApplication,
achPath,
CCHMAXPATH);
if (rc == NO_ERROR)
pcszApplication = achPath;
If DosSearchPath() returns NO_ERROR then the application was found. In that
case the fully qualified name of the application is copied to achPath. Also
if the function succeeds we set pcszApplication to point to achPath. That
way, in the code to follow, we need not worry where the final application name
is to be found, but can simply use pcszApplication. Now that we know the
applications exists, we can finally launch it.
if (rc == NO_ERROR)
LaunchApp(pcszDisplay, pcszApplication,
pcszArguments);
If you look at the code I've provided, you'll see that I've commented out some
code that would be executed before LaunchApp(). As I wrote RMXSTRTR to be
used for starting remote application it must first be verified that the
application to be started can be run remotely. After all, the application to
be started is supposed to turn up on another computer somewhere and if that
simply is not possible it doesn't make much sense starting it in the first
place.
Launching the Application
The first thing that is done when the application is to be launched is that
the environment is cloned.
PSZ pszEnv = CloneEnvironment(pcszDisplay), pszArg = 0;
Why is that done? Well, if you have read the previous articles about RMX you
know that the value of the environment variable RMXDISPLAY specifies the
computer where the remote application will turn up. So, the value of that
variable must be set to the value given by the client. Why not simply set
RMXDISPLAY to the value desired and then start the application as it is easy
to start a child process so that it inherits the environment. That could be
done, provided RMXSTRTR would be single-threaded. Now that RMXSTRTR is
multi-threaded that cannot be done, as several threads could simultaneously
modify the variable. Synchronizing the launching of applications using
semaphores would be a viable alternative, but launching the application is the
most heavily-used operation in RMXSTRTR and it would be a pity not to use
threads there. So, CloneEnvironment() clones the current environment and
sets/replaces the value of RMXDISPLAY with the value specified by the client.
Finally it returns the copy.
If the application has arguments we must build a proper argument string.
if (pcszArguments){
ULONG ulApplication = strlen(pcszApplication) + 1,
ulArguments = strlen(pcszArguments) + 1,
ulSize = ulApplication + ulArguments + 1;
pszArg = new CHAR [ulSize];
strcpy(pszArg, pcszApplication);
strcpy(&pszArg[ulApplication], pcszArguments);
pszArg[ulSize - 1] = 0;
}
According to the documentation of DosExecPgm(), the argument string should
consist of the application name and a NULL, followed by all arguments and a
double NULL.
RESULTCODES resultCodes;
ULONG rc = DosExecPgm(0, 0, EXEC_BACKGROUND,
pszArg, pszEnv, &resultCodes,
pcszApplication);
Then finally the application is started.
Logging
Throughout RMXSTRTR a function named Print() is used for printing information.
It is essentially a thread-safe version of printf(). RMXSTRTR is linked using
the MT RTL, but even so I noticed that the printout of different threads
occasionally got interleaved.
static VOID Print(PCSZ pszFormat, ...)
{
if (DosRequestMutexSem(hmtx, SEM_INDEFINITE_WAIT))
return;
printf("[%d, %d]: ", pid, CurrentTid());
va_list arguments;
va_start(arguments, pszFormat);
vprintf(pszFormat, arguments);
va_end(arguments);
DosReleaseMutexSem(hmtx);
}
The mutex semaphore that was created in main() is used for synchronizing
different threads. First the current pid and tid is printed out. Then using
the va_start, va_list and va_end macros the string with possible additional
arguments is printed.
Creating the Event Semaphore
The event semaphore name is created from the name of the used communications
DLL. The name of the DLL has to specified in the variable RMXCOMMS. So,
first we obtain that name.
PCSZ pcszRmxComms = getenv("RMXCOMMS");
Then the name is catenated to a common prefix.
CHAR achSemName[CCHMAXPATH];
strcpy(achSemName, "\\SEM32\\RMX\\STARTER\\");
strcat(achSemName, pcszRmxComms);
And then the semaphore is created.
HEV hev = 0;
if (DosCreateEventSem(achSemName,
&hev,
DC_SEM_SHARED,
FALSE) != NO_ERROR) hev = 0;
return hev;
If this functions fails it is an indication that another instance of RMXSTRTR
that uses the same communications DLL is running.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.6. RMXSTART.EXE ΓòÉΓòÉΓòÉ
RMXSTART.EXE
RMXSTART is a great deal simpler than RMXSTRTR. It basically makes a request
out of the arguments, opens a connection to RMXSTRTR, sends the request, waits
for a reply and finally closes the connection. If RMXSTART is started without
arguments it prints out:
usage: rmxstart display cpu application [arguments]
DISPLAY refers to the local computer, that is, the one where the application
will appear. CPU refers to the computer where the application will run, that
is, in practice a computer where RMXSTRTR is running. Nothing prevents the
DISPLAY and CPU from being the same. APPLICATION is, of course, the
application to be started, and ARGUMENTS is the arguments that should be
provided to the application. If more than one argument is to be provided to
the application then they must all be enclosed in quotes.
The main function
When RMXSTART is started we set the arguments to a few variables for easier
access.
int main(int argc, char* argv[])
{
PCSZ pcszDisplay = argv[1],
pcszHost = argv[2],
pcszApplication = argv[3],
pcszArguments = 0;
if (argc == 5)
pcszArguments = argv[4];
The name of the starter is, the same way as in RMXSTRTR, obtained from:
PSZ pszName = GetStarterName();
Now that we know the host (the computer where the application is to be run) and
the name of the starter we open a connection to the starter.
HCONNECTION hConn = OpenConnection(pcszHost, pszName);
Once the connection has been opened, the request can be sent. If it is
successfully sent we wait for the reply.
if (SendRequest(hConn, pcszDisplay, pcszApplication, pcszArguments))
ReadReply(hConn);
Finally the connection is closed.
RmxClose(hConn);
Opening the Connection
When the connection is opened we must take precautions for the event that
RMXSTRTR is busy.
HCONNECTION hConn = 0;
ULONG ulAttempts = 1, rc;
do{
rc = RmxOpen(pcszHost, pcszPort, &hConn);
if (rc == ERROR_PIPE_BUSY)
DosSleep(ulAttempts * 200);
} while ((rc == ERROR_PIPE_BUSY) &&
(ulAttempts++ < MAX_ATTEMPTS));
Using RmxOpen() we attempt to open the connection. If it fails because
RMXSTRTR is busy, then we sleep for a while and try again. Each time the
function fails, we sleep a little longer. But not forever; after a specified
number of max attempts we just give up.
Sending the Request
In order to start a remote application we must send the name of our local
computer, the name of the application and possible arguments. It is simply a
question of concatenating the two (possibly three) strings and adding an extra
NULL. First we must find out how much memory the entire request needs.
ULONG lenDisplay = strlen(pcszDisplay) + 1,
lenApplication = strlen(pcszApplication) + 1,
lenArguments = pcszArguments ? strlen(pcszArguments) + 1 : 0,
lenRequest = lenDisplay + lenApplication +
lenArguments + 1;
One is added to each sublength as otherwise we wouldn't reserve enough memory
for each NULL. Finally an additional byte is added to the length of the entire
request. When the length is known, the memory can be allocated.
PSZ pszRequest = new CHAR[lenRequest],
p = pszRequest;
Then each string is copied to the request buffer.
strcpy(p, pcszDisplay);
p += lenDisplay;
strcpy(p, pcszApplication);
p += lenApplication;
if (pcszArguments){
strcpy(p, pcszArguments);
p += lenArguments;
}
Finally the double NULL is added.
*p = 0;
Now the request can be sent to RMXSTRTR.
ULONG rc = RmxWrite(hConn, pszRequest, lenRequest);
Reading the Reply
Even if it is unlikely that RMXSTRTR would ever return anything but a status
code, it is better to make sure that any kind of reply can be handled. We need
a few variables for that.
ULONG ulBytesRead, ulSize = SIZE_BUFFER;
BYTE *pbReply = 0;
ULONG rc;
Then we can enter the loop for reading the reply.
do{
pbReply = new BYTE [ulSize];
rc = RmxRead(hConn, pbReply, ulSize, &ulBytesRead);
if (rc == RMXERR_ENLARGE_BUFFER)
{
delete [] pbReply;
ulSize = ulBytesRead;
}
} while (rc == RMXERR_ENLARGE_BUFFER);
We spin in the loop until we have a buffer sufficiently large (shouldn't ever
need more than two attempts). The loop is safe as, even if I didn't mention
it, a handler for the out-of-memory situation has been set in main().
if (rc || (ulBytesRead != sizeof(ULONG)))
{
delete [] pbReply;
cerr << "rmxstart: Failed to read reply from starter." << endl;
return;
}
If RmxRead() returns an error, or if the size of the returned reply is
something other than 4 bytes, we give up. The rest of the function is simply a
switch on the returned status code along with appropriate messages to the user.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.7. RMXSTOP.EXE ΓòÉΓòÉΓòÉ
RMXSTOP.EXE
RMXSTOP is the simplest of the three applications. Its task is to gracefully
stop a running RMXSTRTR. The RMXSTRTR to stop is either specified by
explicitly giving the name of the communications DLL the RMXSTRTR is using, or
by allowing RMXSTOP to use the current value of RMXCOMMS. If no arguments has
been given RMXSTOP uses the value of RMXCOMMS.
PCSZ pcszRmxComms = 0;
if (argc == 1)
{
pcszRmxComms = getenv(RMXCOMMS);
if (pcszRmxComms == 0)
return EXIT_INIT;
}
If no arguments have been given and the environment variable RMXCOMMS has not
been specified, there is nothing we can do. If arguments have been given we
verify that they are of proper format.
else
{
if (strcmp(argv[1], "-c"))
return EXIT_INIT;
pcszRmxComms = argv[2];
}
If the flag is "-c" we use argument following it as the DLL name. From the DLL
name we build the semaphore name.
CHAR achSemName[CCHMAXPATH];
strcpy(achSemName, RMXSEMPREFIX);
strcat(achSemName, pcszRmxComms);
RMXSEMPREFIX is a common prefix (actually "\\SEM32\\RMX\\STARTER\\") that is
also used by RMXSTRTR when it creates the event semaphore. Once the complete
name is available we can open the semaphore.
HEV hev = 0;
if (DosOpenEventSem(achSemName, &hev) == NO_ERROR)
{
DosPostEventSem(hev);
DosCloseEventSem(hev);
}
If it succeeds we know that the main thread of some RMXSTRTR is blocked on that
semaphore. Hence, if we post the semaphore the RMXSTRTR process will
terminate. If the opening fails, we know no RMXSTRTR is running using the
specified communications DLL.
else
{
cerr << "rmxstop: No rmxstrtr using " << pcszRmxComms
<< " seems to be running." << endl;
}
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.8. Building the Applications ΓòÉΓòÉΓòÉ
Building the Applications
Along with the article you should get a zip-file, RMXSTART.ZIP, that contains
all source and ready-made applications and DLLs. The makefiles are made for
NMAKE.EXE (the make provided with IBM's compiler) and the Borland compiler.
Pretty heavy editing is probably needed if you use something else. Before
starting the build, you have to set the environment variable RMXROOT to point
to the directory where you unzipped the zip-file. E.g.
[C:\]set RMXROOT=C:\RMX
Then you simply:
[C:\]cd RMX
[C:\RMX]nmake
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.9. Running the Applications ΓòÉΓòÉΓòÉ
Running the Applications
The first thing you should do is to either include the directory RMX\DLL in
your LIBPATH, or move the DLLs to some directory already in your LIBPATH.
Remember that RMXPIPE.DLL requires the file RMXPIPE.DAT to be in the same
directory where it is and that RMXTCPIP.DLL requires that the file
RMX\RMXCOMMS\RMXTCPIP\services is appended to your TCPIP\ETC\services file. To
start RMXSTRTR, e.g.:
[C:\RMX\BIN]set RMXCOMMS=RMXTCPIP
[C:\RMX\BIN]rmxstrtr
Supposing the name of your computer is odin and the name of the computer where
RMXSTRTR is running is loke, you could start pulse.exe on that computer with
the following commands.
[C:\RMX\BIN]set RMXCOMMS=RMXTCPIP
[C:\RMX\BIN]rmxstart odin loke c:\os2\apps\pulse.exe
If you are using named pipes, the commands would be something like:
[C:\RMX\BIN]set RMXCOMMS=RMXPIPE
[C:\RMX\BIN]rmxstart \\odin \\loke c:\os2\apps\pulse.exe
Remember, these programs only provide a means for starting an application on
another computer. They do not, in themselves, redirect any output anywhere.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 6.10. Conclusion ΓòÉΓòÉΓòÉ
Conclusion
In this article I described the programs that can be used for starting
applications on other computers. The programs are slightly modified, compared
with the "official" RMX versions, in that they also start applications that
have not been patched for RMX. That is, it is possible to start remote
applications that you subsequently cannot interact with.
I have uploaded a complete version of RMX to hobbes and the zip resides in the
directory network\other. If you install that package, then you actually could
start a PM application on a remote computer and use it on your local. But
please, keep in mind that the version is early beta. Don't try it out if you
expect a finished product<grin>.
If you have any problems with RMX, feel free to send me mail.
RMX-OS2: An In-Depth View (Part 4) - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7. /dev/EDM/BookReview ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 7.1. Introduction ΓòÉΓòÉΓòÉ
/dev/EDM2/BookReview
Written by Carsten Whimster
Introduction
In /dev/EDM2/BookReview, I focus on development books and materials. The
column is written from the point of view of an intermediate PM C programmer and
intermediate REXX programmer. Pick up whichever book strikes your fancy, and
join the growing group of people following our PM programming columns. I have
already reviewed a number of beginner's books, and will try to concentrate a
bit more on intermediate techniques and special topics from now on.
Please send me your comments and thoughts so that I can make this column as
good as possible. I read and respond to all mail.
OS/2 Warp Unleashed, Moskowitz, Kerr, et al is a book I have wanted to review
for a while (well, this version is actually brand-new, but you know what I
mean). I have just received a copy of the new edition, hot off the press, and
the book, while good for novices too, really comes into its own in the hands of
power users. Many programmers are power users, so many of these tips should be
useful in setting up your development machine.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.2. Errata ΓòÉΓòÉΓòÉ
Errata
My WWW home page grows and grows. It is getting a little more stable and
up-to-date now, but as with everyone I know who has one, it is always being
changed. In the coming few months I may try to create an EDM/2 "homepage" and
have a lot of information about EDM/2 and OS/2 programming on it. We'll see
how much time I get for this project.
My school (University of Waterloo), like many schools, has a large Microsoft
presence, and many decisions are based on not stepping on Microsoft's toes,
since they donate large amounts of software to the school. If anyone out there
has any experience with changing the attitudes of the powers that be, please
e-mail me. I would like to increase the OS/2 awareness and enthusiasm on
campus, but it is hard. There is at the moment a small hard-core OS/2
following, and I would like to increase that to a large hardcore presence
<grin>.
Van Nostrand Reinhold and John Wiley & Sons (I think I got that right) have
apparently announced the sale of all of VNR's OS/2 titles to John Wiley & Sons.
Personally, I think that VNR jumped ship at the worst possible time, with
Warp's growing sales, but there is obviously a lot I don't know about the
situation. This probably means that getting books from VNR or John Wiley &
Sons is going to be difficult for the next little while. I am therefore
looking for ideas for the next couple of review columns. E-mail me at
bcrwhims@undergrad.math.uwaterloo.ca if you have any ideas of good
programming/power user books for me to review.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.3. OS/2 Warp Unleashed - Deluxe Edition ΓòÉΓòÉΓòÉ
OS/2 Warp Unleashed - Deluxe Edition
This book is just full of both common and obscure hints and tricks; it has
chapters on the applets, the Internet, and just about anything else you can
imagine. Here is a list of the chapters:
1. Installation
2. System Configuration
3. Reconfiguration
4. Workplace Shell
5. Workplace Shell Objects
6. Configuring the Workplace Shell
7. Command-line Interface
8. REXX Programming
9. Virtual DOS Machines
10. WIN-OS/2 - Windows in OS/2
11. The Video Subsystem
12. Fonts
13. Printing
14. File Systems
15. Multimedia
16. Productivity Applets
17. Networking
18. Troubleshooting
19. OS/2 and the Internet
20. Portable Computing with OS/2
Appendix A. The OS/2 Unleashed CD-ROM
Appendix B. Resources
Appendix C. OS/2 System Messages
This book is huge! Over 1200 pages, to be exact. Hence, I don't think that I
can read everything in one month, and also have a semblance of a life. I will
read whatever I am interested in, and base my review on these chapters. In the
process, I will probably (hopefully) cover the items of interest for most of
the column's readers.
I skipped certain chapters, since my machine is already set up, installed, and
pretty well configured the way I want it, but there were still a large number
of chapters of interest to me. Having skipped chapter 1, I started reading in
chapter 2. Many of the tips in this chapter (and the other chapters) can be
found on the Internet in one of the various newsgroups, or in a file on an ftp
site, but I have never seen anyone explain this stuff in such elaborate
detail, and with such accuracy and confidence as the authors of this book (et
al covers about a dozen other authors), many of which actually develop or
assist in developing OS/2 itself. The usual foundations are well explained in
this book, although the authors are careful not to explain anything that they
feel IBM already explained well either in the documentation that came with
OS/2, or in the on-line help files. Unfortunately, there is a large amount of
information which doesn't fall into the latter category, so the authors have
the opportunity to improve on what you have seen before.
Chapter 2 has a number of interesting tidbits of information about the
config.sys, and the file system. Many of the usual tips are here, but there
are many extra tips as well. David Moskowitz, who wrote this chapter, shows
you how to set up OS/2 for a minimum system, a "better" system, and a power
user system. These types of tips abound, but the descriptions given here are
better than usual, complete with rationale. Explanations are given for most,
if not all, of the unusual and obscure config.sys parameters.
Chapter 3 shows you how to move things around, which parts of OS/2 can be
deleted under what circumstances, and gives more configuration tips. The
first item is how to remove OS/2 Warp! If this is all you wanted to do, you
would probably just scan the book at the bookstore, and you certainly wouldn't
be reading this column. Unless you were running a 100 OS/2 machine site,
perhaps. There is a really neat section on how to use the Recovery Choices
screen available on booting with the Alt-F1 keystroke to set up custom
config.sys'es. The end result is similar to what DOS 6.x offers with both
config.sys and autoexec.bat, but more integrated. It outlines what to do if
you want to use your desktop like you used to use the Windows desktop, before
you switched. Also explained is how to recover from INI file corruption, and
how to set up multiple desktop configurations. There is a section with MSHELL
and TSHELL, and how to use these correctly, as well as how to use these
concepts to use any other program as your desktop. Once you have your desktop
set up, you probably won't want to change it too much, but there is a lot of
interesting information here. If you develop on a small system, perhaps you
may consider going to an MSHELL desktop to conserve RAM, and regain a little
memory, and hence performance.
Chapters 4, 5, and 6 all discuss the Workplace Shell. Chapter 4 is a slightly
more in-depth tutorial than IBM gave us with OS/2. Many obscure features are
noted, such as the fact that the objects listed after a Find has been
performed are the real thing! Do not delete these objects. Also, if you have
your desktop set to need a password on bootup, and then forget that password,
there are directions on how to get yourself out of that mess.
Chapter 5 discusses the objects on the desktop in elaborate detail. The whole
WPS internal class hierarchy is given, and the most important ones are
explained. A neat tip is given in this chapter: how to move templates. This
is not obvious at all, but once you realize that all objects have a default
drag-and-drop action that sometimes can be over-ridden, that the default
action of the templates are a version of copy, and that the move augmentation
key is shift, then it all comes together. This level of detail is standard
throughout the book, and is immensely helpful for those of us that say "Yeah,
ok, but why?" all the time. Another neat feature of the book is that little
REXX scripts are given all the way to accomplish helpful tasks. These are all
on the included CD-ROM, so that they don't have to be typed in. The obscure
pages in the object settings notebooks finally seem more purposeful to me,
even if I don't personally use them all. One of the strong points of the book
is that all the way through it, there are little short-cuts for commonly
performed actions.
Chapter 6 explains how to customize the Workplace Shell. This includes
explaining the PROTSHELL and RUNWORKPLACE statements in the config.sys. It
also goes through the AUTOSTART and RESTARTOBJECT parameters. These
parameters are fairly misunderstood by many people, both novices and
self-proclaimed "experts", with which the Net abounds, but the record is set
straight here. A neat little tip follows: try putting the line SET
MENUSTYLE=SHORT in your config.sys. You can probably guess what it does, but
what a relief from information overload on every pop-up menu the system
presents you with. Many of the tips presented in earlier chapters are
elaborated on here as well. There are a number of tips here on how to develop
WPS objects under Warp. Some of the old tips are no longer relevant, since
Warp now uses DSOM by default, which means that your objects will run
separately from the WPS, and will no longer bring the system down, if they are
buggy.
Chapter 7 discusses command-line windows, but since I have done a lot of work
with these, I will skip this chapter. The author likes 4OS2, but personally I
prefer YAOS. It also has aliases, history, and so on, but is much more like
the tcsh that I use at school. Chapter 8 is about REXX programming, and
again, I will move over this, having already read a number of introductory
REXX books. Virtual DOS machines in chapter 9, and Win-OS/2 in chapter 10 are
not terribly interesting to me either. I firmly believe in supporting the
OS/2 developer community, and I am not one of the people who runs NetScape for
Windows, WordPerfect 5.1 for DOS or Word for Windows regularly. The current
batch of OS/2 programs that do the same thing are close in functionality, and
this is good enough for right now.
Chapter 11 covers the video subsystem, and is written by Bill Bodin, the OS/2
Warp Video Team Lead and Video Architect for the WPS. His involvement with
OS/2 video really shows in the coverage he gives to this topic. Like so many
of the chapters, this chapter is in-depth, covers pretty well everything, and
has a unique insight into the inner workings of OS/2. The pros and cons of
8514/A, SVGA, VGA, and so on are all given. For example, did you know that
the mode command now supports column widths of 1 to 255 inclusive? Maybe 1
isn't terribly useful, but it is nice to know that you impose your own
restrictions, as opposed to following theirs. Some alternative ways of
installing video drivers are given for those of you who are not able to use
the display driver installation utility.
Chapter 12 speaks of fonts. I have never quite understood why screen fonts
seem so crude in OS/2, but I am sure that this chapter has that information
buried somewhere, although I was unable to find it. Everything I have ever
printed from OS/2 has come out beautifully, but the fonts used on my screen
are frequently poorly spaced, and choppy. I have seen a lot of other people
complain about this phenomenon on Usenet newsgroups, but no-one has ever
satisfactorily explained it. Installation and usage of both Adobe Type 1 and
True Type fonts is explained.
Printing is the topic of the next chapter. Again, I skimmed this quickly. I
use the HP LaserJet 4 at school, so I just print to file, and am done. For
this reason, there is nothing in particular I needed to know from this
chapter. Chapter 14, on the other hand, discusses file systems. Having
recently written a small file system, this topic was of particular interest to
me. FAT is built into Warp, whereas HPFS in an installable file system. That
much I knew. On the other hand, Warp still has to know something about HPFS
in order to be able to boot from an HPFS drive, with no FAT around. I hadn't
really thought about that before, but it does make sense. But, then how do
other people write IFSs for Warp? It is not possible for someone to port JFS,
for example, and then put a little code into Warp so that it can boot from a
JFS disk. Yet another chicken and egg argument... All aspects of both file
systems are explained, such as caches, long/short file names, EAs, and so on.
The relevant parameters from config.sys are pointed out and explained. The
various disk utilities that come with Warp are also outlined. A couple of
neat ways of using EAs are given, such as how to store comments with a file,
without changing the file.
Multimedia is covered in chapter 15. The rationale behind developing it in
the first place is given, and then everything from DIVE to TV is discussed.
Several REXX scripts are given that demonstrate how to program for multimedia
with REXX. In addition to this, the applets that come with MMOS2 are covered.
The most popular audio cards are talked about, as well as some special
applications, such as Video IN. There is even some discussion of the
suitability and features of the various sound cards on the market today.
Finally, a brief guide to video recording, multimedia and the Internet, CD-ROM
drives, Pen for OS/2, speech technology, and error messages are discussed.
Chapter 16 is an introduction to the Icon Editor, EPM, and the other applets.
There is a thick chapter 17 on networking, and another on trouble shooting.
The latter chapter includes sections on installation, problem prevention,
failure recovery, and error logging.
Chapter 19 covers the Internet. Unfortunately, this area has been moving so
fast that some of the information is already out of date, although the book
was only just published. Such is life. For example, The Web Explorer covered
is version 0.91, whereas we now have 1.01, and the 950331 beta. Nonetheless,
there is some good information in here, including a section on the
much-maligned Ultimail Lite. PPP is also left out, since it was only released
in December/January. The next update of this book will surely have a nice
section on connecting to other providers, complete with scripts and
information for both SLIP and PPP.
Finally, another chapter for which I don't have much use, but one that is
probably a god-send for many: Portable computing with OS/2. There is also an
appendix about the CD-ROM that comes with the book. Unfortunately, the CD-ROM
itself is a bit messy, but the coverage of the CD in the book is excellent
paradoxically.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.4. Summary ΓòÉΓòÉΓòÉ
Summary
There is a plethora of insight and inside knowledge in this book which simply
can not be found anywhere else. This is one of the best books I have ever read
about OS/2, and I have no qualms about giving it my mark of excellence, an A+.
This is just one of those books that everyone who owns OS/2 should own. If IBM
licensed it, and included it with every copy of OS/2 sold, they would probably
save a bundle in support costs. Unfortunately, that is probably just a
pipedream. The only possible drawback to this book is the relatively high
price of 39.99US$/53.99CAN$, but rest assured that once you have paid for it,
you will not regret. A "must buy" book.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.5. Books Reviewed ΓòÉΓòÉΓòÉ
Books Reviewed
This list is getting rather long, so I will just add list the book reviewed
from now on, and instead keep an index of books reviewed, and issues they are
reviewed in. Here is this month's entry:
OS/2 Warp Unleashed, Moskowitz, Kerr, et al.
- Sams Publishing. ISBN 0-672-30545-3. US$39.99, CAN$53.99
- OS/2 Users and Power Users
- A+
This book has a wealth of hard-to-come-by information regarding just
about every imaginable topic on OS/2. This book belongs in the OS/2
library of everyone.
NOTES
This list contains all books I have reviewed, so that you can find what you
are looking for at a glance. I will be careful to rate books fairly. 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.
LEGEND
BOOK: The name of the book, and the author(s).
PUBLISHING INFORMATION: 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. Many books try to
cover too much, and get a lower mark as a result.
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 some updating.
C Mediocre book with some good sections, but badly in need of fixing.
C- Mediocre book, little good material, desperately in need of an
overhaul.
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 very brief summary of the review proper.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.6. Index ΓòÉΓòÉΓòÉ
Index
This Content Index is designed to let you find the book that covers the topics
you need to learn about. It will eventually have a lot of categories, with
each book being rated along each row. These tables will be quite large, and
will continually grow, so please give me your feedback regarding what
categories you would like to see, and which you don't. It may take me a while
to flesh them out, so have a little patience.
BOOK LEGEND
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéCode ΓöéIssue ΓöéTitle Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéRWP Γöé2-3 ΓöéReal World Programming for OS/2 2.1 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéLPE Γöé2-4 ΓöéLearning to Program OS/2 2.0 Presentation Manager by Example Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéODD Γöé2-5 ΓöéWriting OS/2 2.1 Device Drivers in C Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéGPI Γöé2-6 ΓöéOS/2 Presentation Manager GPI Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéTAO Γöé2-7 ΓöéThe Art of OS/2 2.1 C Programming Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéMOR Γöé2-8 ΓöéMastering OS/2 REXX Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéRSH Γöé2-9 ΓöéREXX Reference Summary Handbook Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéADO Γöé2-10 ΓöéApplication Development Using OS/2 REXX Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéPMP Γöé2-11 ΓöéOS/2 Presentation Manager Programming Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéDOA Γöé3-1 ΓöéDesigning OS/2 Applications Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOSP Γöé3-2 ΓöéOS/2 Programming Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéTGO Γöé3-4 ΓöéThe GUI-OOUI War Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOU Γöé3-5 ΓöéOS/2 Warp Unleashed, Deluxe Edition Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
NOTE: books which cover the same material can look similar in this table, but
be different in real life. The style of a book, for example, can not be seen
from a quick table, so make sure that you follow up by reading the reviews of
the books you find here. Finally, be sure that the books you are comparing are
aimed at the same audiences.
PM C BOOKS
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéBOOK ΓöéMARK ΓöéKernel ΓöéDevice ΓöéVIO andΓöéPM ΓöéGPI ΓöéFonts ΓöéPrint Γöé
Γöé Γöé ΓöéBasics ΓöéDriver ΓöéAVIO ΓöéIntro Γöé Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéRWP ΓöéB+ Γöé2 Γöé0 Γöé0 Γöé4 Γöé4 Γöé4 Γöé3 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéPME ΓöéB- Γöé1 Γöé0 Γöé0 Γöé2 Γöé2 Γöé2 Γöé0 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéODD ΓöéA Γöé0 Γöé5 Γöé0 Γöé0 Γöé1 Γöé0 Γöé1 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéGPI ΓöéC+ Γöé0 Γöé0 Γöé0 Γöé0 Γöé5 Γöé2 Γöé3 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéTAO ΓöéB+ Γöé3 Γöé2 Γöé1 Γöé4 Γöé1 Γöé2 Γöé0 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéPMP ΓöéA- Γöé1 Γöé0 Γöé1 Γöé5 Γöé3 Γöé4 Γöé2 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOSP ΓöéB+ Γöé2 Γöé0 Γöé0 Γöé3 Γöé2 Γöé1 Γöé0 Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
REXX BOOKS:
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéBOOK ΓöéMARK ΓöéREXX ΓöéWPS ΓöéReferenceΓöé
Γöé Γöé ΓöéIntro Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéMOR ΓöéB Γöé4 Γöé0 Γöé2 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéRSH ΓöéA Γöé1 Γöé2 Γöé5 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéADO ΓöéA- Γöé3 Γöé2 Γöé4 Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
SYSTEM AND NON-PROGRAMMING BOOKS:
ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
ΓöéBOOK ΓöéMARK ΓöéKernel ΓöéDevice ΓöéVIO andΓöéPM ΓöéThread ΓöéGPI ΓöéFonts ΓöéPrint ΓöéWPS Γöé
Γöé Γöé ΓöéBasics ΓöéDriver ΓöéAVIO Γöé Γöé Γöé Γöé Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéDOA ΓöéA Γöé4 Γöé4 Γöé2 Γöé4 Γöé5 Γöé3 Γöé2 Γöé3 Γöé0 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéTGO ΓöéB Γöé0 Γöé0 Γöé0 Γöé2 Γöé1 Γöé0 Γöé2 Γöé1 Γöé5 Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
ΓöéOU ΓöéA+ Γöé1 Γöé4 Γöé4 Γöé5 Γöé2 Γöé5 Γöé5 Γöé5 Γöé5 Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
RATINGS LEGEND:
ΓöîΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé0ΓöéNo coverage Γöé
Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé1ΓöéVery light coverage Γöé
Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé2ΓöéIntroductory coverage Γöé
Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé3ΓöéGood Coverage Γöé
Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé4ΓöéIn-depth coverage Γöé
Γö£ΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
Γöé5ΓöéAuthoritative Γöé
ΓööΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 7.7. Coming Up ΓòÉΓòÉΓòÉ
Coming Up
I haven't yet picked out a book for next month, but I am going to look for an
intermediate PM book. The following are some other books I intend to review,
in no particular order:
OS/2 Presentation Manager GPI, 2nd edition, Winn
The Design of OS/2, 2nd Edition, Kogan and Deitel
Designing High Powered OS/2 Applications, Reich (tentative title)
I am considering reviewing the IBM OS/2 Redbooks, since they are readily and
cheaply available, and look like good reference.
If anyone has a book they want to see reviewed, I will be happy to oblige.
Just mail me and tell me. Publishers can send me books at the address on my
personal page at the end of the magazine, and I will review all OS/2
development- related and advanced user books I receive.
/dev/EDM2/BookReview - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 8. OOPS Avenue ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 8.1. Introduction ΓòÉΓòÉΓòÉ
OOPS Avenue
Written by Gordon Zeglinski
Using C++ In Dynamic Link Libraries
Just when things start moving along, a new set of setbacks arise. If they
weren't happening to me, they'd be quite comical. At any rate, we'll take a
break from SOM/DSOM in this issue, and look at using C++ code from Dynamic Link
Libraries (DLLs). Before looking at C++ specific issues, we start by looking
at some DLL basics.
OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 8.2. DLL Basics ΓòÉΓòÉΓòÉ
DLL Basics
A DLL is a library of code and or resources that can be loaded and unloaded
dynamically and shared between processes. Dynamic loading means that the
library is loaded at run time rather than being statically bound to the
application. When a DLL is loaded or unloaded, the operating system calls the
function _DLL_InitTerm(). The following snippet is a skeleton _DLL_InitTerm()
function:
unsigned long _System _DLL_InitTerm(unsigned long hModule, unsigned long ulFlag){
switch (ulFlag) {
case 0 :
// do load initialization here
break;
case 1 :
// do unload termination here
break;
}
return 1UL; //return 0 if we want to indicate that the initialization code has failed
}
The above function (in its current form) is only useful for a resource DLL or a
DLL that contains only assembly language functions. High level languages will
require initialization and termination routines to be called. If we use
C-Set++ as an example, the minimal _DLL_InitTerm() function would be as
follows:
unsigned long _System _DLL_InitTerm(unsigned long hModule, unsigned long ulFlag){
switch (ulFlag) {
case 0:
//initialize the C Run Time library
if (_CRT_init() == -1)
return 0UL;
//for C++ code we call __ctordtorInit to create the global/static intances
__ctordtorInit();
// do user load initialization here
break;
case 1:
// do user unload termination here
//for C++ code we call __ctordtorTerm to destroy static/global instances
__ctordtorTerm();
//if the C Run Time library is STATICALLY linked, we call _CRT_term to free up the
//resources used by the CRTL
_CRT_term();
break;
}
return 1UL; //return 0 if we want to indicate that the initialization code has failed
}
Note: for compilers other than C-Set++, different run time library
initialization/termination calls have to be made.
Functions are exported from a DLL by either name or numerical offset. The
standard way of exporting a function is to specify its name in the "EXPORTS"
section of the definition file for the DLL. Most compilers also allow a short
cut method of exporting functions. This is to declare them with a special
keyword that causes the compiler to generate code that the linker will
automatically export for you. In C-Set++ one uses the "_Export" keyword.
This seems simple enough. However, there are numerous pitfalls as we shall
soon see.
OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 8.3. DLLs and C++ ΓòÉΓòÉΓòÉ
DLLs and C++
C++ mangles function names. This can increase the difficulty in exporting C++
functions. C-Set++ provides a utility called CPPFILT to extract mangled names
so that they may be placed in the .DEF file. Alternatively, one can use the
_Export keyword to have the compiler and linker work together to export the
function. Let's define the class Foo so that it's member functions will be
exported. The code to do this is presented below:
struct FooBar{
int Y;
}
class _Export Foo{
public:
Foo();
~Foo();
int GetVar(){return FooVar;}
void SetVar(int);
FooBar* CreateFooBar();
protected:
int FooVar;
};
Note: Borland C++ allows one to use the _export keyword in a similar manner as
one uses _Export in C-Set++.
By placing the keyword _Export after the keyword class, the compiler
automatically exports all non-inline functions. In this example Foo::Foo(),
Foo::~Foo(), Foo::SetVar(int), and Foo::CreateFooBar() will all be exported.
Foo::GetVar() will not be exported because it is implicitly defined as inline.
Let's say that we have coded Foo's member functions so they can be exported.
We compiled the code and linked it statically to the C run time library to form
a DLL. We then link the resulting DLL to the following code snippet to produce
an executable file.
void main(){
Foo FooInst;
FooBar *Bar;
Bar=FooInst->CreateFooBar();
delete Bar;
}
Let's assume that Foo::CreateFooBar() is contained in the Foo DLL and is
defined as follows:
FooBar* Foo::CreateFooBar(){
return new FooBar;
}
We've now compiled and linked our code. Everything should be fine until we
actually try running the code. In this scenario, we have 2 active C run time
libraries. The first is bound to the Foo DLL and the second is bound to the
executable. When the delete operator is evoked, the memory is freed from the
local C RTL. This is where the problem will occur. The memory was allocated
in the DLL's C RTL and an attempt to free it was made in the executable's CRTL.
There are two ways of solving this problem. First, one can use another DLL
that holds the C RTL and dynamically link this DLL to FOO DLL and the
executable. Alternatively, one can create and export a new function in FOO DLL
that is used to delete instances of FooBar.
Creating a separate DLL for the C RTL is not without its pitfalls. The biggest
pitfall is that OS/2 doesn't unload DLLs in reverse order. In fact, the order
in which they are unloaded is somewhat unpredictable. This is a serious
problem. What if the C RTL DLL is unloaded first? If this happens, it's most
likely that when subsequent DLLs are unloaded they will trap or hang the
process if they have any static or global object instances in them. One way
around this is to use exit handlers at different priorities. These exit
handlers call the __ctordtorTerm() function and keep track of the DLL's
initialization state. Another method could be to use a counter variable in the
C RTL DLL that keeps track of how many other DLLs are using it. This method
would require the C RTL DLL to export a function for incrementing and
decrementing this counter. These functions would have to be called each time a
dependent DLL is loaded and unloaded. When the counter reaches 0, the C RTL is
shutdown by calling _CRT_term. Both the counter method and the exit handler
method require each DLL to use a custom _DLL_InitTerm function.
OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 8.4. Using C++ DLLs Across Different Languages or Compilers ΓòÉΓòÉΓòÉ
Using C++ DLLs Across Different Languages or Compilers
Because the name mangling scheme is not standardized, nor is the calling
convention for that matter, it is impossible to use C++ functions "raw" across
different compilers. To do this, one has to define C to C++ wrapper functions.
The following snippet shows how to wrap the Foo class in C- Set++.
extern "C"{
void* _System CreateFoo();
void _System DestroyFoo(void *_Foo);
int _System FooGetVar(void *_Foo);
void _System FooSetVar(void *_Foo, int V);
void* _System FooCreateFooBar(void *_Foo);
void _System DestroyFooBar(void *_FooBar);
};
void* _System CreateFoo(){
return new Foo;
}
void _System DestroyFoo(void *_Foo){
delete ((Foo*)_Foo);
}
int _System FooGetVar(void *_Foo){
return ((Foo*)_Foo)->GetVar();
}
void _System FooSetVar(void *_Foo, int V){
((Foo*)_Foo)->SetVar(V);
}
void* _System FooCreateFooBar(void *_Foo){
return ((Foo*)_Foo)->CreateFooBar();
}
void _System DestroyFooBar(void *_FooBar){
delete ((FooBar*)_FooBar);
}
The function names CreateFoo(), DestroyFoo(), etc. can be exported by placing
them in the EXPORTS section of the DLLS module definition file. The following
snippet illustrates how these wrapper functions can be used.
void main(){
void *FooInst=CreateFoo();
FooSetVar(FooInst, 10);
DestroyFoo(FooInst);
}
The above snippet can be the main routine for either a C or a C++ program. The
problem of multiple C run time libraries is avoided in this case because all
memory allocation and deallocation is handled in the DLL's wrapper functions.
OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 8.5. Wrapping Things Up ΓòÉΓòÉΓòÉ
Wrapping Things Up
That's it for another issue. We have seen several ways of using C++ code
contained in a DLL. The problem of having multiple C runtime libraries within
a single process along with the problem of DLL unloading has been examined.
Several solutions to each of these problems have been presented here.
OOPS Avenue - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 9. Introduction to PM Programming ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 9.1. Introduction ΓòÉΓòÉΓòÉ
Introduction to PM Programming
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 curiosity, 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. <grin>
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 me via email and I will do my best to answer them
in a timely fashion.
Last Month
Last month we began looking at the menu control, which we will continue with
this month.
Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 9.2. Basic Knowledge Required ΓòÉΓòÉΓòÉ
Basic Knowledge Required
Before we may continue, we should take a brief look at the typical use of a
menu control, from the programmer's perspective. This involves the definitions
of the manifest constants, the menu template definition, the "loading" of the
menu (you'll see why "loading" is in quotes in a minute), and the processing of
the user's actions. We're taking this different approach to looking at the
window class because - as we stated last month - the menu provides the most
widely used functionality of any of the window classes; as such, you'll need to
know how to use it because you'll be writing this code more times than any
other.
Manifest Constants
Manifest constants - a.k.a. #define's - are a convenient language element
which allow us to use a "name" in place of something else. For menus, the
"something else" is a number which represents an identifier unique to that menu
template. You'll find that in larger applications that the file containing
these constants can grow quite large, so it would be helpful if, at a glance,
you could determine the use of the constant from looking at its name. To
accomplish this, I defined a naming convention. You can use this one or your
own - it doesn't matter. What does matter is that you spend less time trying
to find out how a constant is used and more time on actually using the
constant. For menus, I use the following:
Constant form What it represents
M_id Menu or submenu identifier
MI_id Menuitem identifier
The constants that are used for resource definitions I keep in a separate file
to allow me to make the file a dependancy of all files that use resources.
This is simply a suggestion.
Template Definition
Under Windows, there is App Studio which allows you to define and maintain all
of your resources. How come there isn't something like this for OS/2?
Regardless, you have to design your menus "blind," meaning that you can't see
the result until you actually use the menu you've built.
As it is with writing applications, designing your menu layout should be the
most important action; a confusing or deep (i.e. many pullrights) menu
structure will often confuse the user and turn them away from using your
application. Group the items in submenus in a logical fashion so that the
user can "take a guess" at where to look when trying to execute a particular
action.
IBM's "Common User Access" (CUA) guidelines define a number of pulldown menus
and a (non-inclusive) list of what they should contain. I've included a brief
list of these (since I cannot find my CUA book <pout>) below:
Pulldown name Menu items contained therein
File New, Open, Close, Save, Save as, etc.
Edit Undo, Copy, Cut, Paste, etc.
Help Help index, General help, Using help, Keys help
Another important CUA note is the use of the ellipsis and bang punctuation
marks on text. An ellipsis should be appended to menu item text when
selecting the menu item results in a dialog being displayed. A bang should be
appended to text belonging to items on the action bar (note that this
therefore excludes pullrights and any popup menu items) when selecting them
does not display a pulldown menu (i.e. when it is a leaf-node). These are
used as feedback indicators to the user to alert them about the behavior of
the application without having them find out "the hard way."
Loading a Menu
Loading a menu usually involves the setting of a flag only. No explicit
loading is usually performed by the application code. (Popup menus are the
exception to this rule, since the current CUA specification eliminates action
bars.) In the call to WinCreateStdWindow(), simply include FCF_MENU on the
set of flags passed (by reference) as the third parameter.
#define RES_CLIENT 256
HWND hwndFrame;
HWND hwndClient;
ULONG ulCreate=FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX |
FCF_MENU | FCF_SHELLPOSITION | FCF_TASKLIST;
hwndFrame=WinCreateStdWindow(HWND_DESKTOP,
WS_VISIBLE,
&ulCreate,
CLS_CLIENT,
"Test application"
0,
NULLHANDLE,
RES_CLIENT,
&hwndClient);
It has been stated before in this column (I hope) that, when using FCF_MENU,
FCF_ICON, or FCF_ACCELTABLE that the eighth parameter must specify the
resource identifier of the resources corresponding to these flags. Since we
specified FCF_MENU, we should have a menu template defined that begins with:
MENU RES_CLIENT
:
If we do not have this defined, the WinCreateStdWindow() function will fail.
A useful note here is that, as each component of the window specified in
ulCreate is successfully created, the corresponding bit in ulCreate is set to
0. So, the components that were not created successfully can be determined by
examining ulCreate after the function fails.
Processing the User's Requests
Now we learn how to utilize the menu in our application code. There are
usually two messages that we will be interested in when coding our
application: WM_INITMENU and WM_COMMAND. Note that, if any MENUITEMs have
the MIS_SYSCOMMAND or MIS_HELP style, we will need to add the WM_SYSCOMMAND
and WM_HELP messages to this list, but for the moment we'll assume that we
have none with these menu item styles.
WM_INITMENU is sent to the client window whenever a menu or submenu is about
to be used by the user, e.g. when the user presses F10 to get to the action
bar, when the user clicks on a pulldown menu to display the pulldown, etc.
Intercepting this message allows us to dynamically enable or disable menu
items according to the state of our application. For example, if the user
selects the "Print" menuitem, you might want to disable the "Exit" menuitem
until printing is completed. We will see later how to change menuitem
attributes.
SHORT1FROMMP(mpParm1) specifies the identifier of the menu. If the actionbar
is the cause of the message, this will be FID_MENU; otherwise, it will be the
identifier you specified on the SUBMENU statement in the menu template.
HWNDFROMMP(mpParm2) is the handle of the window corresponding to the
identifier. You should know that pulldown and pullright menus are actually
separate windows which belong to something called an "object" window when not
in use. When you click on a pulldown, the appropriate window is retrieved
from the object window and displayed on the desktop. This window handle is
needed to send messages to the menu.
WM_COMMAND, WM_SYSCOMMAND, and WM_HELP are all sent whenever the user selects
a menuitem with the corresponding style. This is your indicator that the user
wants something done and that you are to process this request.
SHORT1FROMMP(mpParm1) specifies the identifier of the menuitem selected.
SHORT1FROMMP(mpParm2) specifies the source of the message and will always be
CMDSRC_MENU when this message is sent via a menu control.
SHORT2FROMMP(mpParm2) is TRUE if this message was sent as the result of a
mouse action or FALSE if sent as the result of a keyboard action.
Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 9.3. Next Month ΓòÉΓòÉΓòÉ
Next Month
Next month we'll start to look at a sample application that uses the menu
control, and we'll begin to look at the MM_ message family which allows you to
interact with the menu control. As always, feedback will be enjoyed immensely;
send any comments, suggestions, etc. to os2man@panix.com.
Introduction to PM Programming - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10. 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 hobbes.nmsu.edu in the /os2/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:
Larry Salomon - os2man@panix.com (Internet).
Carsten Whimster - bcrwhims@undergrad.math.uwaterloo.ca (Internet).
The following people contributed to this issue in one form or another (in
alphabetical order):
Larry Salomon, Jr.
Carsten Whimster
Johan Wikman
Gordon Zeglinski
Network distributors
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10.1. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
Larry Salomon Jr.
Larry Salomon Jr. has been developing OS/2 applications since version 1.1 in
1989. He has written numerous applications, including the Scramble applet that
was included in OS/2 versions 2.0-2.11, and the I-Brow, Magnify, and Screen
Capture trio that has been distributed on numerous CD-ROMs.
Larry is also the coauthor of the successful book, The Art of OS/2 2.1 C
Programming (Wiley-QED). Finally, he is the CEO/President of IQPac Inc. which
is responsible for the publication of EDM/2 and he is a frequent contributor to
the publication.
Larry can be reached electronically via the Internet at os2man@panix.com.
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10.2. Carsten Whimster ΓòÉΓòÉΓòÉ
Carsten Whimster
Carsten is an undergraduate Computer Science student at the University of
Waterloo. He is currently in fourth year, and enjoying it immensely. He uses
Watcom C/C++ 10.0a and Watcom VX-REXX 2.0b. Carsten is the author of some
commandline utilities, POV-Panel/2, and soon to come POVEd. He is also a
TEAM-OS/2 member, and has adopted a little computer store called The Data Store
in Waterloo, Ontario.
You may reach Carsten...
...via email:
bcrwhims@undergrad.math.uwaterloo.ca - Internet
...World Wide Web homepage (incomplete; aren't they all):
http://www.undergrad.math.uwaterloo.ca/~bcrwhims - WWW
...via snail mail:
Carsten Whimster
318A Spruce Street
Waterloo, Ontario
Canada
N2L 3M7
...via phone
(519) 886-2439
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10.3. Johan Wikman ΓòÉΓòÉΓòÉ
Johan Wikman
Johan Wikman received his Master's degree in Computer Science with a thesis
"Adding remote execution capability to operating systems". He has been
programming for OS/2, using C++, ever since 1990.
Currently he works for Nokia Telecommunications where he takes part in a
project that developes network management software in a Unix environment. In
his spare time, he continues working on RMX-OS2, a system that provides remote
execution for OS/2.
Johan can be reached electronically via the Internet at
johan.wikman@ntc.nokia.com, or via ordinary mail:
Johan Wikman
Smedjeviksvagen 23 B 22
FI-00200 Helsinki
FINLAND
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10.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.
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 10.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!
Paul Hethmon (phethmon@utk.edu) - Compuserve
Gess Shankar (gess@knex.mind.org) - Internet
Jason B. Tiller (PeerGynt@aol.com) - America On-line
David Singer (singer@almaden.ibm.com) - IBM Internal
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!
Contributors - EDM/2 - May 1995 - Volume 3, Issue 5
ΓòÉΓòÉΓòÉ 11. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
How Do I Get EDM/2?
EDM/2 can be obtained in any of the following ways:
On the Internet
All back issues are available via anonymous FTP from the following sites:
- hobbes.nmsu.edu in the /os2/newsltr directory.
- ftp.luth.se in the /pub/os2/programming/newsletter directory.
- generalhq.pc.cc.cmu.edu in the /pub/newsletters/edm2 directory.
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.
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
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".
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.
How do I Get EDM/2? - EDM/2 - May 1995 - Volume 3, Issue 5