Category : Windows 3.X Files
Archive   : WPJ1-1.ZIP
Filename : WPJV1N1.TXT

 
Output of file : WPJV1N1.TXT contained in archive : WPJ1-1.ZIP





WW WW WW PPPPPPPP JJ
WW WW WW PP PP JJ
WW WWWW WW PP PP JJ
WW WW WW WW PPPPPPPP JJ
WW WW WW WW PP JJ JJ
WWWW WWWW PP JJ JJ
WW WW PP JJJJJ

----------------------------------------------------------------
The Windows Programmer's Journal Volume 01
Copyright 1992 by Peter J. Davis Number 01
and Mike Wallace Jan 93
----------------------------------------------------------------
A monthly forum for novice-advanced programmers to share ideas and concepts
about programming in the Windows (tm) environment.

You can get in touch with the editor via Internet or Bitnet at:

HJ647C at GWUVM.BITNET or HJ647C at GWUVM.GWU.EDU

CompuServe: 71141,2071

or you can send paper mail to:

Windows Programmer's Journal
9436 Mirror Pond Dr.
Fairfax, Va. 22032

The two GWUVM IDs are Pete's and CompuServe is Mike's.

We can also be reached by phone at: (703) 503-3165.

Microsoft, MS-DOS, Microsoft Windows, Windows NT, Windows for Workgroups,
Windows for Pen Computing, Win32, and Win32S are registered trademarks of
Microsoft Corporation.

Turbo Pascal for Windows, Turbo C++ for Windows, and Borland C++ for
Windows are registered trademarks of Borland International.

WordPerfect is a registered trademark of WordPerfect Corporation.

The Windows Programmer's Journal takes no responsibility for the content of
the text within this document. All text is the property and responsibility
of the individual authors. The Windows Programmer's Journal is solely a
vehicle for allowing articles to be collected and distributed in a common
and easy to share form. No part of the Windows Programmer's Journal may be
re-published or duplicated in part or whole, except in the complete and
unmodified form of the Windows Programmer's Journal, without the express
written permission of each individual author. The Windows Programmer's
Journal may not be sold for profit without the express written permission
of the Editor, Peter J. Davis, and only then after he has obtained
permission from the individual authors.














Table of Contents

Subject Page Author(s)
-----------------------------------------------------------------
WPJ.INI ...................................... 3 Pete Davis

Off Topic .................................... 6 Pete & Mike

Beginner's Corner (C) ........................ 8 Pete Davis
& Mike Wallace

A Drag and Drop Trashcan (TPW) ............... 16 Andreas Furrer

Using DDE to Communicate With Program Manager. 18 Pete Davis

Implementing a Linked List in the Global Heap. 22 Mike Wallace

Book Review .................................. 26 Pete Davis

Last Page .................................... 28 Mike Wallace

Getting in Touch with Us ..................... 29 Pete & Mike




Windows Programmer's Journal Staff:

Publishers ......................... Pete Davis and Mike Wallace
Editor-in-Chief .................... Pete Davis
Managing Editor .................... Mike Wallace
Contributing Writer ................ Andreas Furrer




































WPJ.INI


First of all, I'd like to introduce myself. My name is Pete Davis and
I was the editor of the Pascal NewsLetter, a journal similar to this one
which lasted 1 year for 6 issues. I unfortunately had an accident which
left me unable to continue the newsletter for some time. By the time I was
back in shape and ready to go, someone had picked up the newsletter and
re-started it. It was nice to see that there was enough interest that it
could continue without me. In the past year I have developed an interest in
Windows programming using C, so I guess at this point, I'm more suited to
Windows programming anyway.

Well, it sure is nice to have a "magazine" again. I guess I have the
same problem now that I had with the Pascal NewsLetter: What is it? A
magazine? A Journal? A NewsLetter? Well, I never quite got it figured out.
The Pascal NewsLetter was originally intended to be just that, a
newsletter, but in its prime it was over 30 pages single-spaced, so it
wasn't exactly a newsletter.

What, you may ask, is the purpose of this thing anyway? Well, I love
to program. I know a lot of other people out there, techno-geeks like
myself, love it also. As with Pascal, I'm finding there aren't a whole lot
of magazines which cover Windows programming. That's fine, it just leaves
more readers for us, I suppose. Not to mention, this is free. There aren't
any free ones for Windows programming (or if there are, I haven't heard of
them). I like to teach people how to program and I can't think of an easier
way to get such a large audience and have it all be free.

In this magazine, you won't just be hearing Mike and I ramble on, but
you'll be hearing from a lot of people. Not professors, not industry
experts, but people like you and me, regular programmers who like what they
do and want to share their ideas and experiences with us. No one gets paid
and no one has to pay. That's the idea.

If the initial response we got, when we first started asking people
about doing this, is any indication, there are going to be a LOT of
readers. That means we should also have a lot of writers. You'll find a
file in this .ZIP file with the name SUBMIT.TXT. It is simple instructions
on how to submit an article. There aren't any solid rules and it's easier
than you'd probably expect, so please consider sending in an article.

Right now, things are real open to regular columnists. I had several
with the Pascal NewsLetter and their columns were very well received.
Since we don't have a regular columnist for a beginners column yet, Mike
and I are going to start it up ourselves, but I hope someone will try to
pitch in and give us a hand with it. When I did the Pascal NewsLetter, I
had a regular writer for a beginners column and it was the most popular
column in the magazine. There's a reason for that. There are a lot of
people trying to get started and just can't seem to get the hang of the
basics. Programming Windows is a lot different than programming in DOS and
it's not as easy to pick up, but with a little persistence, anyone can do
it.

Other columns that we'd like to see are ones that address things like
C++ for Windows and Turbo Pascal for Windows. We'd like to hear from you if
you want to tackle any of these. It's not a lot of work and only requires a
few hours each month. Most of us can make at least that much time.

The Pascal NewsLetter came out irregularly, but we'd really like to do








this on a monthly basis if possible. If we don't get enough submissions, we
might have to make it every two months. We should be able to let you know
by the second or third issue.

As far as things we'd like to see in the newsletter:

* Software and book reviews, maybe even reviews of Windows related
hardware. I'd like to see reviews every month.

* As I mentioned before, I want a beginners column for plain C for
Windows as well as one for Turbo Pascal for Windows and C++ for
Windows.

* As far as one-time articles, perhaps one on programming DLLs and
special considerations that need to be made for writing them.

* Articles on DDE and OLE programming.

* Articles on network programming in Windows for Workgroups and
Windows NT.

* Printing text and graphics in Windows

* Memory management

* Using different memory models and how to handle multiple code or
data segments.

* Programming TCP/IP and Sockets under Windows NT

* Maybe reviews of Windows NT while it's still in the pre-release
stage to let people who don't have it know what it's like and how
Microsoft is progressing with it.


That should be enough to start with. Please take the time and try to
contribute. You don't have to be an expert. In the Pascal NewsLetter, the
beginner's column was written by a guy who was just learning Pascal. He did
a fantastic job, and as I said earlier, it was the most popular column. I
had an article submitted to me by someone who didn't speak English very
well, so he wrote it in his native tongue, German, and I had it translated.
I had a 16 year-old high school student who submitted a terrific article,
so anyone can do it. You just need to take the time. The writing in this
magazine is pretty informal. People seemed to like that about the Pascal
NewsLetter. They said it was easier to relate to than regular magazines,
so I'm going to stick with that format.

As for the format, I'm going to try to keep it like I did with the
Pascal NewsLetter, in that it's just a plain text file with Form Feed
characters at page breaks. If there's a big push to go with something like
the Windows Write format, that can be done too. Personally, I prefer using
WordPerfect (just what I'm used to) and it makes it pretty easy for
handling formatting and getting articles from different people in different
formats.

In fact, as far as anything about the magazine, if you have
suggestions, we'd love to hear them. If you think we should change the way
we're doing something, then you might not be the only one. If we get enough
suggestions for things, or if it's just something we should obviously be
doing then we'll make the change.








Well, that's enough of my rambling on for now. Hope you guys (and
gals) like the magazine. I'm open to suggestions and I love to get
feedback, good and bad, about the magazine, so feel free to get in touch
with me or Mike at the address on the cover page.
































































Off Topic
By Pete and Mike

This is exactly what the title says, off topic. Mike and I have two
computers that we want to sell, so we figured we may as well throw those in
here. Both machines are identical. They are:

IBM PS/2 Model 70-486 (8570-B61)

Both machines have 2MB RAM and 60 MB hard drives. They come with 8512
Color VGA monitors and the IBM Enhanced Keyboards. The machines are less
than 4 months old and barely used.

The cost is $1,500.00 and includes shipping anywhere in the
continental United States. Shipping outside of the United States is covered
by the buyer.

These machines are really in excellent condition. We've checked them
out thoroughly and there aren't any problems with them. We'll throw in a
guarantee that if there are problems with them sometime within the first
month, you can return the computer for a full refund. Of course this
doesn't include any damage applied after the purchase.

Well, that's our little pitch for our computers. We don't normally
sell computers, so hopefully this will be the only ad we throw in here for
computers.

Our next off-topic thing is something Mike and I discussed and both of
us agreed that it wasn't something we wanted to do but felt that for the
magazine's best interest, we would. We are asking for donations. Neither of
us is looking to make a fortune in contributions (And I'd be willing to put
money down that we don't). The idea behind it is this. We want to be able
to support Windows programming with different compilers, Windows NT,
Windows for Workgroups, etc. The donations would be used specifically to
get the software so we could either work with these environments for our
own articles or use them to test programs and articles sent in by others.
Our address is at the end of the article. Send in what you believe this
magazine is worth. We want to put together the best Windows magazine out
there, but we're not rich, so we'll do what we can with what we have. If
you do want to send a donation, see the last page for our address. Make the
check payable to Pete Davis.



























Beginner's Corner
By Pete Davis and
Mike Wallace


Well, since this is the first issue and we don't have a writer for the
beginner's column yet, Mike and I are going to split it between the two of
us. I'm a strong believer in the beginner's column because once you make
the first few steps, you get hooked. Unfortunately, few books really
address the beginner so someone has to help them get started. We must
assume that the reader is familiar with the C language. Covering both a
beginners column for C and for Windows would be far too great a task. There
are several good books out for C programming and there's also the C News,
which, like this magazine is a file which is available on many BBSes and
the Internet. It's a great place to start learning C and I highly recommend
it. Also, although formally, all C routines are called functions, we use
the words procedure, function, and routine fairly interchangeably. A
function tends to imply that some result is returned to the calling routine
so I tend to use it in that manner.

In almost every beginners book on programming, the first program
written is the infamous "HELLO WORLD" program. We're going to do that here,
but in a sort of round-about way. We're not just going to show you the one
simple program, but we're going to go to great lengths in explaining the
different parts of a Windows program first. For example, I'm going to
specifically cover how Windows works and then the .DEF file which is used
to tell the compiler how your code and data is supposed to be configured
when it's linked. Then Mike and I are going to go in-depth into the .RC or
Resource source file. The .RC file has the definitions of all the resources
of your program. It has your dialog boxes, menus, icons, bitmaps, etc. We
won't actually get to the "HELLO WORLD" program itself until the second
issue.

To a beginner, it may seem a bit overwhelming that we're going to have
to cover so much just to do a "HELLO WORLD" program, but the truth is, we
don't HAVE to cover all of it. When you actually see the program, you'll
see how simple it really is. We'd just like to give you an overview of the
parts of a Windows program first and then show you a specific example. We'd
also like this article to be a sort of reference on how to create more than
just the simple resources and definitions (.RC and .DEF files) for a "HELLO
WORLD" program.

How Windows Works

Too some of you who are beyond the very basics, some of this you may
already know, but it may be a good idea to read anyway. Some of this is a
simplified explanation, but the point is to get the concept easy to
understand. Later we can be a little more specific.

Windows is what is called a non-preemptive multi-tasking environment.
A preemptive multi-tasking environment is one where the operating system
allocates a certain amount of time to each task. It then runs one task
until it has used its share of time and then runs another task until its
time has run out and so on until it gets back to the first task. Windows,
on the other hand, will run a procedure from your program until the
procedure is completed and then it will run a procedure from another
program until it is completed. What this means is that a Windows program
can take over the CPU entirely, if it wants, but that defeats the purpose
of programming for a multi-tasking environment. (There is one exception,
and that is DOS sessions running under Windows, which are handled in a








preemptive manner, but this is not our topic and won't be discussed in this
column.)

In a Windows program, the initialization of the program first
'registers' itself with Windows. It does this by telling Windows a few
parameters that it needs to know about the program and to set-up the main
message-loop, then telling Windows where the main window procedure is. A
message-loop procedure is one that accepts messages from Windows that are
sent to your program.

Messages in Windows are a way of telling your program what the user
is doing, or a way for your program to tell Windows or some other program
what to do. Windows messages usually come in the form of WM_something,
where the WM_ stands for Windows Message. For example, when you first
create your Main Window, one of the first messages passed to your procedure
is WM_CREATE. When you receive the WM_CREATE message, you know Windows is
about to create your window and if you want to initialize certain variables
to be handled by that procedure, you want to do it now. Or, if you receive
the WM_CLOSE message, you know that Windows is about to close your window
and end your program. You may want to, at this point, ask the user if he
wants to save his files or ask if he really wants to quit.

Messages are the heart of the Windows multi-tasking environment and
when we create our "HELLO WORLD" program, you'll see a little more clearly
how this works.

In your programs, you will create windows and dialog boxes. When you
do that, you need to tell Windows the name and location of a procedure
which is going to handle the messages used by the window or dialog box. The
procedure then gets all messages pertaining to that specific window or
dialog box. Each of these procedures is a lot like the main window
procedure to Windows. This is unlike a regular DOS C program in which the
program always controls which procedure is called next and is responsible
for making its own calls. In a Windows program, you tell Windows where your
procedures are and it will run them in response to certain commands and
user actions.

This may seem a little unclear, but all I can say is stick around
until the end of the second part of the article and it may make more sense
in terms of a real program. This is, essentially, how Windows works. If you
have questions, please feel free to contact us in one of the ways mentioned
on the first page and we will try to be more clear in the areas readers
seem confused about in the second part of this article.

The .DEF File
(Also known as the Module Definition File)

The .DEF file is what the compiler uses to find out how to handle your
program as a whole and how to handle individual routines in your program.
We're going to go fairly in-depth into the different things you can do in a
.DEF file, but in the second part of the article, you'll see a very simple
application .DEF file and see exactly what parts are basic. I will try to
distinguish between the things that you always must have and then parts
that are optional or rarely used.

I will show each parameter, a summary of its purpose and options,
followed by how it would appear in the .DEF file. The .DEF file is simply
an ASCII text file that you type in with your program editor.

The first parameter is the NAME. In general, this should be the same








as the name of the executable. Also, in the cases of Dynamic Link Libraries
(DLLs), this is replaced by the LIBRARY parameter.

NAME myprog (for a regular Windows program)
or
LIBRARY mydll (for a DLL)

The next parameter is the DESCRIPTION. This is inserted into the
header of your executable, but serves no real purpose other than perhaps
allowing you to keep track of version and/or copyright information.

DESCRIPTION 'My first Windows Program'

The EXETYPE parameter tells the compiler which environment the program
will be run under. For Windows, it is simply:

EXETYPE WINDOWS

The next parameter is the WINSTUB program. The WINSTUB is simply the
name of a program that is run in the event that someone tried to execute a
Windows program under DOS. This may be familiar to you. The most common
WINSTUB is the one that says, 'This program requires Microsoft Windows.' In
theory this program can be almost anything you want. A programmer could,
for example, have both a DOS and Windows version of his/her program with
the DOS version simply being a WINSTUB in the Windows version. In a later
article, I'll provide source code for a WINSTUB that will allow a user to
run your Window program from DOS. This is done by running Windows with the
name of the program as the parameter (i.e., the user types 'TESTPROG' and
the stub from TESTPROG executes the command:
'WIN TESTPROG'). The possibilities are enormous and it would be nice at
some point to see some more creative uses of the WINSTUB besides 'This
program requires Microsoft Windows.' Anyway, the standard WINSTUB is a
program called WINSTUB.EXE which comes with most Windows compilers. The
syntax is as follows:

WINSTUB 'WINSTUB.EXE'

The next section covers the code and data segments. Windows has the
Small, Medium, Compact and Large memory models. The memory model determines
whether or not there are multiple code and/or data segments. See the
following table:

Model # Data Segments # Code Segments
----------------------------------------------------------
Small Single Single
Compact Multiple Single
Medium Single Multiple
Large Multiple Multiple

For now, we'll stick mostly with Small or Medium models, as they're
the easiest to use. We will go into the different models in later articles
to discuss the advantages and disadvantages of each and how to program for
them.

Each code and data segment can have different options telling Windows
how to handle them. Most segments, you want to give the option MOVEABLE
which means that the Windows memory manager can move the segment around in
memory to make room for other things if needed. There may be occasions when
you would want a segment set to FIXED. For example, if you were writing a
program that was working with DOS on a fairly low level, it is useful to








have things set for FIXED so DOS will always know where they are. This is,
however, in the advanced arena, so we'll be avoiding it.

The PRELOAD option tells Windows to automatically load the segment
into memory before the program is actually executed. The LOADONCALL option
tells Windows only to load the segment when it is needed. This helps keep
memory available for other processes. In general, you want your main CODE
and DATA segments set for PRELOAD.

The DISCARDABLE option tells the Windows memory manager that it can
remove that segment from memory all together when it needs more memory. The
memory manager will then re-load the segment the next time it is needed.
This is fine for most CODE segments where the contents of the code does not
change. In DATA segments, the contents of the data will change as the
program is run and because of this, you do not want it to be discardable.
The discardable segments are not saved before they are discarded, so any
changes made to them are lost. Making a DATA segment discardable would give
unknown results.

The SINGLE option tells windows tells Windows that although there may
be multiple copies of the program running at once, that this segment may be
shared. This is useful for a CODE segment where several copies of the same
program can use the same copy of the code, thus saving memory. The DATA
segment, however, would be different from one running program to the next,
so the SINGLE option wouldn't really be appropriate. (Because of the way
Windows handles DLLs, they data segments MUST be SINGLE. This requires
special handling on the part of the programmer to handle multiple programs
using the same DLL. We'll discuss this another day.)

The MULTIPLE option tells Windows to create a separate copy of the
segment for each copy (instance) of the program that is being executed.
This is useful for DATA segments. If your CODE segment is single and your
DATA segment is multiple, you can share the CODE segment and save memory,
but each copy (instance) of the program will have its own data.

The following is an example for a Small model program. It has one code
segment and one data segment.
CODE PRELOAD MOVEABLE
DATA PRELOAD MOVEABLE MULTIPLE

The next parameters are Heapsize and Stacksize. Heapsize refers to how
much space is available for local dynamic memory allocation. If you are
familiar with dynamic memory allocation in regular C programming, then this
is nothing really new to you. The only real difference is in Windows you
have Global and Local heaps. For now, let's just keep the Heapsize at about
4096. This is a nice safe size for the types of programs we're going to be
doing for a while.

The stacksize tells Windows how much space to make available for the
stack. The stack is where Windows keeps a lot of it's variable
declarations. It also keeps information when you call procedures and
functions here. As with Heapsize, 4096 should do fine for the time being.
The syntax is as follows:

HEAPSIZE 4096
STACKSIZE 4096

The next section is the EXPORTS and IMPORTS sections. The exports are
procedures that will be called by something other than your own program.
For example, your main window procedure that receives all the messages








regarding your main window is an exported procedure. Any procedure that
accepts messages, for that matter, are Exported. These procedures receive
their messages from Windows and are called by Windows. Each procedure
exported should be followed by an @n where n is an integer number. The
number is an unique index number that Windows uses to help it keep your
program organized. It's not required, but it does help speed things up for
Windows and I suggest you use it all the time.

Imports are functions that you want to use from external sources, like
a DLL, or some other source. To use those, you simply need to list them. If
they come from a DLL, you need to do the name in the form of:
DLLNAME.FUNCTIONNAME.

EXPORTS MainWndProc @1
ADlgProc @2

IMPORTS SHELL.DRAGQUERYFILE


Well, that about covers the .DEF file. As we start to use it more
regularly, you'll see how the different sections affect the program. So,
we'll end this section with a sample .DEF file.


NAME MYPROG
DESCRIPTION "My first Windows program"
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096
STACKSIZE 4096
EXPORTS MainWndProc @1




The .RC File

The .RC file is used to define the resources for a Windows
application. Resources include icons, cursors, menus, dialog boxes,
bitmaps, fonts, string tables, accelerators, custom resources and version
information; in other words, the gist of a Windows program. The .RC file
can contain either definitions for one or more of each of these resource
types or tell Windows where to find the definition(s). I'll start with the
dialog box format this issue.

A dialog box is a type of window allowing the user to, for example,
select an item from a list box, pick a printer, select a drive for a file
directory, etc. In other words, whenever you want to display information
to the user or get input, use a dialog box. The "About" box is a dialog
box. The difference between a dialog box and a window is that a window is
normally used for drawing graphics and a dialog box displays text
("dialog"). You define a dialog box with the DIALOG statement, which has
the following format:

name DIALOG [load option] [memory option] col, row, width, height
[option statements]
BEGIN
[dialog box items]








END

Description of parameters:

name - unique (to your program) name for the dialog box

load option - determines when the dialog box is loaded into memory;
if specified, must be either PRELOAD or LOADONCALL. PRELOAD tells Windows
to load the dialog box when the application starts. This makes the box
appear quicker, but takes up memory since it must stay in memory throughout
execution of your program, even if your program never loads it (based on
user input, for example). The default, LOADONCALL, tells Windows to load
it when necessary.

memory option - combination of FIXED, MOVEABLE and DISCARDABLE. This
should normally be "MOVEABLE DISCARDABLE" (notice there's no comma). See
the article "Implementing a Linked List in the Global Heap" elsewhere in
this issue for a discussion of these attributes.

row,col,width,height - position and size of the dialog box; col
(column) and row specify the location of the upper left corner of the
dialog box relative to the upper left corner of the window which called it.
All dimensions are in dialog base units.

option stmts - describe the dialog box; can include the STYLE,
CAPTION, MENU, CLASS and FONT. These are described below.

STYLE - Format "STYLE style". Valid values for style are a
subset of the styles for windows. Any window style starting with WS_
or DS_ can be used (except for WS_MINIMIZEBOX and WS_MAXIMIZEBOX), and
combined with "|". These are listed below:

DS_LOCALEDIT - Forces memory used by dialog boxes into the application's
data segment.

DS_MODALFRAME - Creates a dialog box with a modal frame.

DS_NOIDLEMSG - No WM_ENTERIDLE messages are sent from the dialog box if
created with this style. WM_ENTERIDLE messages are normally used to alert
the application that the dialog box is displayed but no user activity has
happened yet.

DS_SYSMODAL - System modal dialog box. This means no other window can gain
the input focus until this dialog box is closed.

WS_BORDER - Border on the dialog box.

WS_CAPTION - Caption on the dialog box; can't be used with WS_DLGFRAME

WS_CHILD - Create a child dialog box; can't be used with WS_POPUP.

WS_CHILDWINDOW - Same as WS_CHILD.

WS_CLIPCHILDREN - When creating a parent dialog box, specifies that child
dialog boxes will be clipped at the boundary of the parent.

WS_CLIPSIBLINGS - Used with WS_CHILD; keeps "sibling" dialog boxes from
overlapping.

WS_DISABLED - the dialog box is initially disabled (cannot receive the








input focus).

WS_DLGFRAME - Double border.

WS_GROUP - The control can be reached via the direction keys (arrows).

WS_HSCROLL - Horizontal scroll bar.

WS_ICONIC - Initially iconic; used with WS_OVERLAPPED.

WS_MAXIMIZE - Initially maximized.

WS_MAXIMIZEBOX - Maximize box in the upper right corner.

WS_MINIMIZE - same as WS_ICONIC.

WS_MINIMIZEBOX - Minimize box in the upper right corner.

WS_OVERLAPPED - Caption and border.

WS_OVERLAPPEDWINDOW - Combination of WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU
and WS_THICKFRAME (standard parent window style).

WS_POPUP - Popup dialog box (can't be used with WS_CHILD).

WS_POPUPWINDOW - Combination of WS_POPUP, WS_BORDER and WS_SYSMENU
(standard popup window style)

WS_SYSMENU - System menu.

WS_TABSTOP - Specifies at which control the tab key stops.

WS_THICKFRAME - Thick frame (used to size the dialog box).

WS_VISIBLE - Initially visible.

WS_VSCROLL - Vertical scroll bar.

Example : STYLE DLGFRAME | WS_VISIBLE


CAPTION - Format "CAPTION text". Gives a caption of "text" to
dialog boxes defined with the WS_CAPTION style.

MENU - Format "MENU menuname". Assigns menu "menuname" to the
dialog box. The menu is normally defined in the .RC file.

CLASS - Format "CLASS classname". Causes a class other than the
class of the parent window to be used for the dialog box.

FONT - Format "FONT pointsize, typeface". Determines the font
size used for the dialog box, which in turn determines the sizing of
every control and the dialog box itself. Example : FONT 10, "Helv"




Defining Dialog Box Items:

Defining the objects in a dialog box (e.g., a check box) occurs
between the "BEGIN" and "END" statements. A lot of these control








statements have as part of their parameter list "col, row, width, height".
These give the size and location of the object, and must be integers. Some
objects have a "text" field, which can be any string enclosed in quotes
(e.g., "Cancel"). Most of the time, the optional "style" parameter can be
either WS_TABSTOP or WS_GROUP or the two combined using "|". The "id"
parameter is a unique identifier assigned by the programmer, with the
exception of static text controls, which are usually given an ID value of -
1 since they are never selected. The control statements are described
below:

CHECKBOX - Format "CHECKBOX text, id, col, row, width, height [, style]".
Defines a check box control.

COMBOBOX - Format "COMBOBOX id, col, row, width, height [,style]". Defines
a combo box control. This is a combination of an edit control and a drop-
down list box. The optional style parameter can include any combination of
WS_TABSTOP, WS_GROUP, WS_DISABLED and WS_VSCROLL.

CONTROL - Format "CONTROL text, id, class, style, col, row, width, height".
Specifies all forms of child window controls within a dialog box. The
"class" parameter can be either "button", "combobox", "edit", "listbox",
"scrollbar" or "static". The "style" parameter can be any of the allowed
values for CreateWindow().

CTEXT - Format "CTEXT text, id, col, row, width, height [, style]".
Defines a centered static text control.

DEFPUSHBUTTON - Format "DEFPUSHBUTTON text, id, col, row, width, height [,
style]". Defines the default pushbutton for a dialog box.

EDITTEXT - Format "EDITTEXT id, col, row, width, height [, style]".
Defines an editable text control in a dialog box. The style parameter can
be any combination of WS_TABSTOP, WS_GROUP, WS_VSCROLL, WS_HSCROLL,

WS_BORDER and WS_DISABLED. Text is aligned based on ES_LEFT, ES_CENTER or
ES_RIGHT.

GROUPBOX - Format "GROUPBOX text, id, col, row, width, height [, style]".
Draws a rectangle with a title at the top left around a group of other
controls.

ICON - Format "ICON text, id, col, row [, style]". Places an icon in the
dialog box. The "text" parameter is the name of the icon as defined
elsewhere in the .RC file with an ICON statement. The only allowed style
is SS_ICON.

LISTBOX - Format "LISTBOX id, col, row, width, height [, style]". Places a
list box in the dialog box. An example of a list box is, if you run a
Windows application and select "File Open..." from the menu bar, the box
that appears with a list of the filenames available for opening. Possible
values for "style" are any styles allowed in CreateWindow().

LTEXT - Format "LTEXT text, id, col, row, width, height [,style]". Defines
a left-justified static text control.

PUSHBUTTON - Format "PUSHBUTTON text, id, col, row, width, height [,
style]". Defines a pushbutton for a dialog box. The allowed styles are
WS_TABSTOP, WS_DISABLED and WS_GROUP.

RADIOBUTTON - Format "RADIOBUTTON text, id, col, row, width, height [,
style]". Defines a radio button in a dialog box.








RTEXT - Format "RTEXT text, id, col, row, width, height [,style]". Defines
a right-justified static text control.

SCROLLBAR - Format "SCROLLBAR id, col, row, width, height [, style]".
Defines a scroll bar within a dialog box.


Here is an example of the DIALOG statement that could be used for
showing a list of printers and letting the user select one. It includes a
list box to hold the printer names and three buttons: OK, RESET and CANCEL.


IDL_PRINT DIALOG LOADONCALL MOVEABLE DISCARDABLE 78, 40, 124, 58
CAPTION "Select a Printer"
STYLE WS_OVERLAPPED | WS_DLGFRAME | WS_CAPTION | WS_POPUP
BEGIN
LISTBOX IDL_LIST, 32, 6, 60, 27, LBS_STANDARD |WS_HSCROLL |WS_BORDER
DEFPUSHBUTTON "OK", IDL_OK, 4, 40, 37, 14, WS_GROUP
PUSHBUTTON "Reset", IDL_RESET, 44, 40, 37, 14, WS_GROUP
PUSHBUTTON "Cancel", IDL_CANCEL, 84, 40, 37, 14, WS_GROUP
END


That's all for now about dialog boxes. We'll continue next month with
more resource types. If you don't like the format and have an idea for a
better one, drop us a note.










































Programming Drag&Drop with Windows 3.1
by Andreas Furrer


This article describes writing applications that uses Drag&Drop. At
the end of this article is an example of an application that makes the use
of Drag&Drop. The program is written in Turbo Pascal for Windows (1.0), but
many of the things you'll learn in this article will port to other
languages.

A nice new feature of Windows 3.1 is Drag&Drop (D&D). With D&D you can
use the File Manager to select files and drop them onto an application to
perform some action on the files (e.g., print them).

In Windows 3.1 there are a lot of applications that make use of D&D.
For example, if you want to read a text file you can simply pick it up in
File Manager and drop it onto the window or the icon for Notepad or you can
print files by dropping them onto your Print Manager.

You can also use D&D for your own applications.

D&D is supported by the new SHELL.DLL. There are four procedures and
one new message. The declarations in Pascal are:


const wm_DropFiles = $0233;

procedure DragAcceptFiles(Wnd: HWnd; Accept: Bool);
external 'SHELL' index 9;

function DragQueryFile(Drop: THandle; FileIndex: Word;
FileName: PChar;MaxChars: Word): Word;
external 'SHELL' index 11;

function DragQueryPoint(Drop: THandle; var Pt: TPoint): Bool;
external 'SHELL' index 13;

procedure DragFinish(Drop: THandle);
external 'SHELL' index 12;

To use D&D with your application, you first have to register at least
one Window of your application to accept dropped files.
This will be done by:

DragAcceptFiles(HWindow,true);

Now this HWindow will receive wm_DropFiles message if some files are
dropped onto it. If you want to undo the registration just pass false as
the second parameter to the function above. This should always be done when
your window is destroyed.

If someone drags some files onto your window you will receive a
wm_DropFiles message. The word parameter (wparam) of this message is a
handle to a global data structure. This structure contains information
about the dropped files and you have to use this handle for all Drag&Drop
procedures. LParam is not used with this message.

Now you can get information about the dragged files. You have to use
the following two functions:









DragQueryFile:

function DragQueryFile(Drop: THandle; FileIndex: Word;
FileName: PChar;MaxChars: Word): Word;
external 'SHELL' index 11;

With this function you will get the filename of one of the dragged
files. You have to pass the handle of the D&D structure (received by
wm_DropFiles), the index of the file (0 is the first), a buffer for the
filename and the size of the buffer to this function. The function will
copy the filename into the buffer and return the number of copied chars. To
get the number of dropped files you can use $ffff as index.

DragQueryPoint:

function DragQueryPoint(Drop: THandle; var Pt: TPoint): Bool;
external 'SHELL' index 13;

With this function you can get the position of the cursor at the
moment when the files were dropped. You have to pass the handle for the D&D
structure (received by wm_DropFiles), and a variable of type TPoint to this
function. The return value is true, if the files were dropped in the client
area of the window, otherwise (for the non-client area) it is false.

At the end of your D&D procedure you have to tell Windows to release
the memory of the D&D data structure. This will be done with the DragFinish
function. Again you have to pass the handle of the D&D structure to this
function.

A simple application for demonstrating D&D is a Trashcan. The
accompanying code will implement a Trashcan which will delete all files and
directories you dropped into its icon. See the TRASH.PAS file.

After starting Trashcan, you can easily delete files and directories.
Just select the files or directories in File Manager and drag them onto the
icon of trashcan. If you have selected a hidden, read-only or a system
file, you will be asked if you really want to delete it.

To build Trashcan, you first have to open TRASH.RC with the resource
workshop and save it as TRASH.RES in the .RES format. Now you can compile
TRASH.PAS and you will get TRASH.EXE.



























A Custom Install Program: Part I
Using DDE to Communicate with Program Manager
By Pete Davis

This is going to be a four part article on writing an Install program
for Windows applications. I haven't completed the program yet so I don't
even know exactly how it's going to turn out. My main problem at this point
is that I really want to have a file compression algorithm for the files to
be installed. The main problem is my laziness. I'm not really in the mood
to write a unzip program, but since I'm having trouble coming up with
alternatives, that may be my only possibility.

This program is going to be loosely based on one I wrote in the past.
I can't use any of that code because it is now the property of someone
else, so I have to start from scratch. There are essentially three main
sections which I will discuss separately. There's the part that runs last
(which I'll be discussing first) which involves telling Program Manager to
create our program group(s) and application icon(s). The second part reads
and interprets a SETUP.INF file to get parameters of the installation, such
as what files are to be installed, what disk they're on, whether or not
they're executables, what is the default directory, etc. The third part is
the previously mentioned decompression routines. (If anyone has a
decompression algorithm they'd like to donate, that would be terrific.) The
last article will tie all these parts together and make them all work
together.

One thing of extra interest will be that the decompression routines
will be in a DLL. When I originally wrote my first install program, the
UNZIP algorithm I used required a lot of memory and it was either make it a
DLL or give it it's own data segment. I still haven't spent enough time
with multiple data segment programs, so I stuck with the easy (or so I
thought) method, the DLL.

The first part I want to discuss is using DDE to communicate with
Program Manager. This was the most challenging part for me the last time I
wrote an Install program, so it seems to me that it would be the part that
would be most interesting for a lot of people.

My first few attempt at creating program groups were pathetic cludges.
My main aim at the time was just to create the program group files myself
and make the appropriate modifications to the PROGMAN.INI file. This turned
out to be a little more difficult than I expected and I soon abandoned it.
The next thought was to just create my own program group files and install
them as part of the installation process. This was a workable solution but
would not allow for installing the code in anything but the default
directory.

About the time I was mulling over the good and bad points of the last
option, I came across a little snippet about using DDE to communicate with
Program Manager. After a lot of reading and looking at source code from
different sources I finally got a handle one it. This, incidentally, was my
first attempt with DDE so it was doubly challenging.

My first attempt at the DDE was itself a bit of a cludge. Instead of
trying to follow all of the normal DDE protocols, I just tried to force my
commands on Program Manager without the proper acknowledgements. (Ok, so
I'm a little lazy.) This was only partially successful and I soon broke
down and went the whole nine yards. From my experience with it, I have only
this to say: Follow the protocol. Don't try to force DDE down some
applications neck, 'cause it's gonna puke.








Since this article doesn't discuss DDE in general, I'm not going to go
in depth about variations in DDE. That will be discussed in a later article
by me or someone else (hopefully!). The way DDE with Program Manager works
is something like this. You put together a string of commands and place
them in a globally allocated space. A typical Program Manager command is:
[CreateGroup(My Group)] You then send a WM_DDE_EXECUTE command to Program
Manager and pass it the handle of your globally allocated string. That's
about all there is, in theory. In practice, there's a lot that needs to be
done.

The segment of DDE code provided with this issue is called PMDDE.C.
This contains routines which will be called by the main program, so it
isn't a runable module in itself. It can be included with your own
programs, however. Additionally, since I haven't finished the entire
program yet, there's no way to be sure that it all works. Well, that's just
a little splash of real life. If it doesn't work when I'm done, then I'll
just have to fix it and provide any fixes required. I debated whether to do
this article now or wait until I had the whole program together, but I
decided that even if there are mistakes, the algorithm itself is still
valid, and the final product will work.

The best way to handle a DDE conversation is to create a window that's
sole purpose is to handle your DDE conversation. In our case, and in most,
the window that handles the DDE conversation is not the main window and it
is usually not a window in the sense that it's visible. It is simply the
procedure which handles the DDE messages that we want. In our case we'll
call this procedure the DDEWndProc. The creation of this window is handled
in the main program, but I'll give you an idea of what the code looks like.

/* This code is executed when the main windows procedure
receives the WM_CREATE message
wc is a WNDCLASS variable.
hDDEProc is a static HWND */

wc.style = 0;
wc.lpfnWndProc = DDEWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "DDEWndProc";

RegisterClass(&wc);
hDDEProc = CreateWindow("DDEWndProc", NULL, WS_CHILD,
0, 0, 0, 0 hWnd, NULL, hInstance, NULL);

if (!hDDEProc)
MessageBox(hWnd, "DDE Window won't come up.", "ERROR",
MB_OK);
That's all there is to creating this blank little window. The next
thing on our list is to handle the actual DDE conversation.

Under the WM_CREATE of our DDEWndProc procedure, we need to add two
global atoms. These are the Application and Topic names that our
conversation is supposed to deal with. When you start a DDE conversation
and you want to contact a DDE server application (Program Manager in this
case) so you need to use the Application and Topic. Essentially what you do








is send a WM_DDE_INITIATE message with the application and topic as a
parameter. (These are actually one parameter by passing the
MAKELONG(Application, Topic) as a long in the message parameter. You also
need to pass the handle for your DDEWndProc in this message so that Program
Manager will know how to get back in touch with us. Notice that the
SendMessage has a -1 for the first parameter. This tells Windows to
essentially broadcast the message to all programs that are running.

The DDEWndProc will handle several other messages. One of them is the
WM_DDE_ACK message. This message is used to acknowledge responses from the
DDE server (Program manager.) This part is not quite so intuitive as I
learned. First of all, this part has to be broken up. If you're
acknowledging the WM_DDE_INITIATE (which we sent first thing. Don't tell me
you already forgot what I wrote in the last paragraph!) Ok, so here we are
sitting around with nothing to do and BOOM, we get an acknowledgement from
our WM_DDE_INITIATE. Well, it's about time. So the first thing we want to
do is make sure we grab the handle of Program Manager. This is passed as
the wParam of the WM_DDE_ACK message sent by Program Manager in reply to
our WM_DDE_INITIATE message. With all of the other messages we send to
Program Manager, we will now know exactly who to send them to and not have
to broadcast all of our messages.

At this point I'd like to mention one thing about DDE. There are two
ways to send Windows messages. You can use the SendMessage or the
PostMessage procedures. Both functions do the same thing except with
SendMessage, the message is sent and execution stops until the receiver of
the message has finished processing the message. With PostMessage, control
returns to the calling program immediately. With DDE you use the
SendMessage only for the WM_DDE_INITIATE message. For all other messages
you use the PostMessage procedure.

In our DDEWndProc we need to handle the WM_DDE_ACK message. This is
sent by Program Manager in response to all of our messages. We're actually
going to break that process into two parts, though. The first WM_DDE_ACK
that we get is in response to our WM_DDE_INITIATE. When we get the
acknowledgement we then have to make sure that Program Manager will handle
our conversation. We also need to grab Program Manager's handle.
Additionally, the lParam of each WM_DDE_ACK is probably going to have some
data that it points to that we need to delete. In the WM_DDE_INITIATE
response the handles for two atoms are sent back to us. In this case, they
happen to be the same two atoms we sent, so we just delete them. In
response to our WM_DDE_EXECUTE messages, we get a Global Memory handle that
is also the same one we sent to Program Manager (you'll see this later) so
we have to free it.

That basically handles all the rough stuff. To send commands to
Program Manager we need to use the GlobalAlloc command with the
GMEM_DDESHARE option so that we can share the data with Program Manager.
The data is actually just text strings that we pass to Program Manager to
execute as commands. These are commands like CreateGroup, AddItem, etc..
The commands we'll use are:

* CreateGroup(Group Name[, Group Path])

Where Group Name is the name of the Program Group you want to add to
Program Manager. Group Path is optional and specifies the path of the group
file. In our case, we'll let program manager decide where to put that.

* AddItem(Program [, Program Name, IconPath, IconNum, X, Y, DefDir, HotKey,
Minimize]








Just adds an Program item to the group you've created. The Program is
that Path and the Filename of the executable. Program Name is the name you
want to give it under Program Manager. Those are the only two we're going
to cover for now.

The other messages we're going to handle is the WM_CREATE_PMGRP and
WM_ADD_ITEM. These are custom messages that we're going to define in our .h
file. The first is used to create the program group under Program Manager
and the second is going to be create any items we're putting in the program
group. The lParam of these messages is going to be a handle for Atoms that
are going to have the names of the program group and the file names.

We'll then create the entire string that we want like:
"[CreateGroup(New Group)][ShowGroup(New Group)]"
and pass this off to Program Manager with a WM_DDE_EXECUTE message. Notice
that all commands are in brackets. Don't know why but just use 'em.

That about covers the PMDDE.C. I might modify it before the fourth
article in this series, but if I do I'll pass it along.

















































Implementing a Linked List in the Global Heap
By Mike Wallace

The ability to implement a linked list is almost a requirement if a
platform wants to get taken seriously. If you don't know what a linked
list is, let me explain. Using an array to store data internally is fine
if you have a good idea of how many items you'll need to store, which will
determine the size of the array (which must be stated explicitly in your
code prior to compiling). However, if you don't have a reasonable upper
bound, you have two solutions: either make the array as large as possible
and hope it always works, or allocate memory dynamically. The first
solution isn't good enough. It usually means a lot of wasted memory, and
in Windows, that's memory you can't afford to lose. The second solution is
a bit more difficult to implement, but is the only way to go. By
allocating memory dynamically (that is, at run-time), you only allocate
exactly enough memory needed to hold your data. This is the method that
produces a linked list, so called because the data is stored in a "list" of
memory blocks (nodes), where each block holds an item of data plus another
field giving the memory location of the next node in the "list", thus
"linking" the data.

I recently had to implement a linked list for a Windows program but
could not find any good examples of how to do this, so I had to reason the
problem out. It turned out to not be as difficult as I expected, but there
are some things you need to keep in mind when implementing a linked list.
Microsoft advises that when allocating a memory block, make it moveable and
discardable. Why? Windows is more efficient if it can move your memory
block around while the program is running in order to make the most of the
available memory. However, a consequence of this is that you cannot use a
pointer when linking two consecutive nodes in the list because Windows can
(and will) move each node around in memory as it sees fit. So, I had to
use a handle since that would guarantee the address stored in it (for the
next node) would always be valid. The tricky part was that Windows
requires a memory block to be locked when accessing a node by handle
because that ensures the node won't be moved until you unlock the block.

At the end of this article I've included the source code for a routine
which allocates ten nodes in the global heap, stores in each node a number
between 1 and 10 (the numbers are stored consecutively), then traverses the
list and prints (to a file) the value stored in each node, and finally,
retraverses the list and frees each node one at a time. Included with the
Windows Programmer's Journal package is all the code and files needed to
run the program. All of the files have a filename of "linklist", except
the batch file which is run to compile the program, which is called
"makelist.bat".

The beginning of the function contains declarations for the variables
needed to implement the linked list. The _listmarker structure is the
structure of each node in the list. The LISTMARKER variable has to be a
FAR pointer to the structure since the function uses the global heap. The
LISTMARKER variables (tailPos, tempPos and headPos) are used to traverse
the list. Finally, "fp" is a file pointer to the output file.

After the function opens the output file for writing, it does a
GlobalAlloc to allocate a block on the global heap for the first node. If
"NULL" is returned, it means there was not enough room for the node of a
size of FileMarker, so the function displays a message to that effect and
returns to the calling routine. Otherwise, the allocated block is locked
(so the block doesn't move while its fields are getting assigned), gets
initialized and then gets unlocked. The "hMem" handle points to the first








node for the duration of the function. This algorithm is repeated for each
successive node, using tailPos to point to the current end of the list.

The function then traverses the linked list, printing out the value of
the "value" field to the output file. This is done by locking each node,
performing a "fprintf" on the "value" field and then unlocking the node.
The output file is then closed.

Finally, the function traverses the list, freeing each node one at a
time. This is done by locking each node, saving its handle to the next
node, unlocking the current node and then freeing it. This algorithm is
repeated until the list has been traversed.

That is the entire algorithm. This is the first time I have written a
linked list in Windows, so there may be more efficient methods of attaining
the same ends. If you can find any, please send in your suggestions and
we'll print them.


void FAR PASCAL MakeList (HWND hWnd)
{
/* local variables */
short i;
static HANDLE hMem, hMem2, hMem3;

/* structure of each node in linked list */
typedef struct _listmarker {

short value;
HANDLE next;

} ListMarker;

/* declare a far pointer to the above structure */
typedef ListMarker FAR *LISTMARKER;

LISTMARKER tailPos, tempPos, headPos;

/* pointer to output file */
FILE *fp;

/* Open output file for writing */
fp= fopen("data.out", "w");

/* Build initial linked list of the numbers 1 to 10 */
if((hMem= GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
sizeof(ListMarker))) == NULL) {

/* Not enough memory, so beep, show a message and return */
MessageBeep(0);
MessageBox(hWnd, "Out of allocation memory!", "ERROR", MB_OK);

return;

}

/* Lock the first node, save a value, set next to NULL and unlock */
tailPos= headPos= (LISTMARKER) GlobalLock(hMem);
headPos->value= 1;
headPos->next= NULL;








GlobalUnlock(hMem);

/* Allocate a node for each of the numbers between 2 and 10 and link */
for (i=2; i < 11; i++) {

/* setup index lookup lists */
if((tailPos->next= GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE,
sizeof(ListMarker))) == NULL) {

MessageBeep(0);
MessageBox(hWnd, "Out of allocation memory!", "ERROR",
MB_OK);

return;

} /* If - End */

/* Lock the next node, save the value, and set its next to NULL
*/
hMem2= tailPos->next;
tempPos= (LISTMARKER) GlobalLock(hMem2);
tailPos= tempPos;
tailPos->value= i;
tailPos->next= NULL;

GlobalUnlock(hMem2);

} /* While - End */

/* Lock the 1st node and write out its "value" field */
tailPos= headPos= (LISTMARKER) GlobalLock(hMem);
fprintf(fp, "%d\n", tailPos->value);

/* Save the handle to the next node */
hMem2= tailPos->next;

/* Unlock the 1st node */
GlobalUnlock(hMem);

/* Go through list and print out "value" until no more nodes */
while (hMem2 != NULL) {

/* Lock the next node and save to tailPos */
tempPos= (LISTMARKER) GlobalLock(hMem2);
tailPos= tempPos;

fprintf(fp, "%d\n", tailPos->value);

/* Get the handle to the next node and then unlock the current one */
hMem2= tailPos->next;
GlobalUnlock(hMem2);

} /* While - End */

/* Close the output file */
fclose(fp);

/* free nodes in the list */
tempPos= (LISTMARKER) GlobalLock(hMem);
hMem2= tempPos->next;








tempPos= (LISTMARKER) GlobalLock(tempPos->next);
GlobalUnlock(hMem);
GlobalFree(hMem);

while(tempPos->next != NULL) {

hMem3= tempPos->next;
tempPos= (LISTMARKER) GlobalLock(tempPos->next);
GlobalUnlock(hMem2);
GlobalFree(hMem2);
hMem2=hMem3;

}

GlobalUnlock(hMem2);
GlobalFree(hMem2);

return;

} /* MakeList */
















































Book Reviews
By Pete Davis


Undocumented Windows: A Programmer's Guide to Reserved Microsoft Windows
API Functions

by Andrew Schulman, David Maxey, and Matt Peitrek
Addison-Wesley Publishing Company
ISBN 0-201-60834-0


Well, away with the formality and on to the book review. If you're
comfortable with programming Windows, then I have only two words to you
regarding this book: BUY IT! This is the one of the best references, not
only for finding functions that Microsoft 'forgot' to tell us about, but it
also gives an incredible amount of insight into how the internals of
Windows operates. Not to take away from Maxey and Peitrek, but Schulman's
fingerprints are all over this book.

This book is very well organized. Each chapter is divided in a way
that's easy to understand and covers specific topics. It's hard to know
where to start with this book, it has it all. It has chapters on KERNEL,
USER, GDI, and SYSTEM calls. It has a chapter on undocumented Windows
messages. There are great chapters on how to disassemble and examine
Windows executables. This is particularly useful for the true Windows
hacker.

The book also comes with a load of utilities for examining Windows
executables. I have actually found several of these utilities useful simply
for debugging my own code. Some of the utilities will tell you what
undocumented calls a program is making. This is a neat little way to find
out who's got an inside track at Microsoft. Of course, with the release of
Undocumented Windows, many of these calls are going to be used more
frequently.

Microsoft's humor in naming some of these calls (e.g. BozosLiveHere
and TabTheTextOutForWimps) are accented with the authors' humor. When
discussing how a certain utility sometimes "decides that a function is
undocumented when in fact it's documented. (It's sort of like one's
coworker who every week thinks he's found a bug in the compiler)." The book
is a joy to read just for the humor alone.

Although there are a lot of functions listed (well over a hundred, I'd
guesstimate), the true value of this book lies in its discussion of Windows
and how Windows operates. There is more in this book on the internal
operations of Windows than any ten books I've seen. He also discusses at
length the politics at Microsoft regarding the undocumented functions.

Well, I've talked about all the reasons that I like the book, but
let's discuss it's usefulness. Is it useful? Well, for its in-depth
discussion of Windows internals, yes. The functions themselves are
scattered in a lot of different areas of programming. Some would be useful
to some people while others would be useful to others. For example, someone
working on a Windows debugger would be very interested in task queues and
the like whereas a programmer of a painting package might be more
interested in the GDI function calls. There are tons of functions and the
documentation of each one is more complete than the documentation Microsoft
provides for most of it's 'documented' functions.









Schulman and Co. have done a fantastic job on this book and I don't
think I could give it a higher recommendation. I look forward to his
Undocumented NT (maybe? perhaps?).

































































Last Page
By Mike Wallace

Well, it's happened.
The first issue of Window's Programmer's Journal (official motto:
Apply directly to infected areas) is done, and I feel good about it. Why?
Because it's the first magazine I've seen that is fully devoted to Windows
programming and it's more than just product reviews. Pete and I were
hungry for something like WPJ but couldn't find anything that was really
helpful, so we thought, "Let's do one ourselves." It's been fun so far,
and hopefully we'll get lots of articles from ya'll so we can fill each
issue with solutions to your Windows programming problems. If you think
you have an idea for an article, send it in! If you just want to submit an
outline for an article to see if we'd be interested before you write a full
article, do it! The magazine can't last long without help from you people,
and if you've done something cool in Windows, we want to hear about it! If
you have any questions about Windows, ask! We're going to start a letters
column as soon as we have enough letters to fill one, and if we can't
answer your questions, we'll submit them to the rest of our readers to get
an answer. We're not just doing this as part of our work-release program,
we want to learn everything we can about programming in Windows, and I
haven't seen any magazines that are as devoted to it as I'd like, and we're
not looking for articles written by people with Ph.D.s - we'll take an
article from anybody. Future issues will depend on it.

Speaking of future issues, we have a few ideas about what you'll see
soon. Pete's going to write an article about how to print under Windows
3.0 & 3.1, we'll continue our beginner's column, start a column on how to
program C++ (written by me - since I don't know anything about C++, I
seemed overly qualified to write a beginner's column on it), some product
reviews of books and software, and just yesterday I bought a Windows NT
workstation and Pete has the pre-release of NT, so we're going to tell you
all about that and try to write some programs for it.

Coming Soon! The WPJ BBS! By Jan. 1st (if we're lucky, and by the
5th if we're not quite so lucky), you can send your articles and letters
directly to us. We also plan on putting the SIMTEL20 CD-ROM on it so you
can download anything you want. It's a great CD full of stuff you never
knew you needed but can't live without once you get it. We'll also be
getting the CICA CD-ROM of Windows shareware and public domain software
soon. See the "How to get in contact with us" section elsewhere in this
issue for more info.

If you're wondering about the point of this column, this is where I
get to rant and rave about anything I'd like. If you don't want to read
it, don't. You won't miss anything of earth-shattering importance. I'll
try to make it interesting, but there's no telling what will happen here -
you'll have to wait and see. If there's anything on your mind you want to
talk about it, send me a note and if it sounds like it would be of interest
to other readers, I'll write what I can about it. This is your forum as
much as mine. One of my minors in school (Va. Tech, by the way - I

graduated in '89 with a BS in Computer Science) was philosophy (the other
was math - I knew you were wondering about that!), so just because I don't
know anything about a subject won't stop me from writing about it. If
there's anything you want to get off your chest, tell me about it. I'm
always looking for a good discussion about anything.

That's the first issue. Hope you liked it; hope we're around for
awhile. This could be a lot of fun, and we want you to join us. Until
next month, may you look like the late Totie Fields!








Getting in touch with us:


Right now there are only four ways to get in touch with us. If you
have access to the Internet or BITNET, you can get in touch with us at:

HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (both Pete)

CompuServe: 71141,2071 (Mike)

WPJ BBS (703) 503-3021

You can also send paper mail to:

Windows Programmer's Journal
9436 Mirror Pond Drive
Fairfax, VA 22032
U.S.A.


Also, around January 1st, we'll be setting up a BBS specifically to
support the WPJ, but we'll also be offering the SIMTEL20 CD-ROM for
downloads. The SIMTEL20 system is one of the largest sources of public
domain and shareware software. We'll also be adding more CDs later as we
can afford it.

Anyway, the Windows Programmer's Journal BBS can be reached at: (703)
503-3021. You can get in touch with either Mike or Pete at this number. The
BBS is going to be relatively new, so don't be surprised if it's a little
buggy in the beginning. Right now it's only 2400 baud as my 9600 baud modem
died on me, but in the first month or two you can expect it to go up to
14,400. You can also expect to see a Fido-net node address by the second
issue.


































  3 Responses to “Category : Windows 3.X Files
Archive   : WPJ1-1.ZIP
Filename : WPJV1N1.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/