




    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.
































