





    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 1993 by Peter J. Davis                       Number 02
and Mike Wallace                                          Feb 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.

WPJ is available  from the WINSDK, WINADV and MSWIN32 forums on CompuServe,
and the  IBMPC, WINDOWS and  BORLAND forums  on GEnie.   On Internet,  it's
available on WSMR-SIMTEL20.ARMY.MIL and FTP.CICA.INDIANA.EDU.  We upload it
by  the 1st  of each  month and  is usually  available by  the 3rd  or 4th,
depending on when the sysops receive it.

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

Letters .......................................  5  Readers

Install Program Part II .......................  7  Pete Davis

Programming a Drag&Drop Server ................  9  Andreas Furrer

C++ Beginner's Column ......................... 12  Mike Wallace

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

Using LZExpand Library ........................ 18  Alex Fedorov

Implementing a Linked List - Revisited ........ 21  Mike Wallace

An Introductory Look at DLLs and Make Files ... 22  Rod Haxton

The Windows Help Magician ..................... 29  Jim Youngman

Last Page ....................................  30  Mike Wallace

Getting in Touch with Us .....................  31  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
Contributing Writer ................ Alex Federov
Contributing Writer ................ Rod Haxton
Contributing Writer ................ Jim Youngman



























                                  WPJ.INI
                               By Pete Davis

     Well, welcome to the second issue of the Windows Programmer's Journal.
I  don't really know  what to  say. We've  been totally  blown away  by the
response  we've been getting.  I'm writing this  on January 15th  and as of
today, on Compuserve and  GEnie (the only two places we  can really see how
many  issues are being downloaded) we've counted 873 downloads. That number
goes up  every day and it doesn't include all  of the other places that the
Windows  Programmer's Journal is available. We've gotten letters from a lot
of you  with good and  bad things to  say. (When I  say bad, I  really mean
critical.) Criticism is fine and  we're even going to publish some of it in
this issue.

     We've also  received a terrific  response from Andrew  Schulman, whose
book  we reviewed in  the last issue.  We'll show an  excerpt from that and
other letters in the letters column. 

     One  of the criticisms  that was  most discussed  was the  Linked List
article written  by Mike.  We  should be  receiving an  article from  Peter
Shroesbree for  the next issue, showing an alternate way of doing it. We'll
also have a  third article, showing yet  another way of doing this  in next
month's issue, done by Rod Haxton,  who's writing an article in this issue.
Since this has  become a  bit of a  hot topic,  we're going to  do a  short
article in next  month's issue  about the advantages  and disadvantages  of
each of these methods.

     We'd  also like to welcome David Campbell.   In March, he'll be taking
over the beginner's  column. David has a good bit  of experience in Windows
programming and is quite a hacker. He has shareware and commercial software
on the market, so his experience will be valuable to all of us.

     Speaking of experience, I suppose it's time to kind of spill the beans
about Mike and I.  So as not to confuse  anyone, neither Mike nor I  have a
lot  of experience  programming  Windows. We  are  not authorities  on  the
subject, but we don't think  that means we don't know a few  things that we
can share. We're both learning a lot all the time. The linked list  article
is an  example. All I'm  trying to say  is, don't  say, "Well, the  Windows
Programmer's Journal says this, so it must  be true."  Not that you  would,
but we all  can make mistakes and we're  not always going to be  right. The
good thing is that there are obviously  a lot of you out there reading this
and with your help, we can make corrections.

     We have another  article from Andreas Furrer this month. Last month he
wrote  an article about  programming a Drag  & Drop client  in Windows 3.1.
This month he's going  to talk about writing a Drag  & Drop server program.
We've also  got an article by Alex  Federov of Moscow, Russia  on using the
LZEXPAND.DLL. 

     Just got my  sample issue of Windows Tech Journal.  Ahem... How do you
spell cancel? Nah, it ain't  that bad, just not really my type of magazine,
I guess. Had an offer for Windows NT Developer.  12 issues for a mere $129.
No thanks, I'll buy the book.

     Sorry, I digress. Geez, let's see, I'm going to be  writing the second
part to the install program. I'm basically covering a lot of the stuff Alex
Federov is covering.  His sample, however, is  written in Turbo Pascal  for
Windows.  I was supposed to do an article on printing, this month, but I've
been really busy, so I'm going to have to put it off until the  next issue.
I'll share  a really  wonderful  experience with  you  about my  trials  in








learning to print also.

     Ah, and  I almost forgot. We're going to do  a reader poll next month.
Here's the question. What  format would you like  to see WPJ in? We've  had
suggestions for a lot of different  formats. Mike is leaning in the Windows
Write direction. That's ok,  but it doesn't quite have the power  of a real
word processor, which is a pain when putting the whole thing together. Dave
Campbell suggested Windows WINHELP format.  I've seen a sample, and I  have
to  say,  it's  pretty damn  impressive.  We've  also  had suggestions  for
Postscript and TeX. Now, the problem with Postscript,  as I see it, is it's
BIG. That means it'll take longer for you to download. If you're getting it
off Compuserve or  GEnie, or some other pay system, it costs you. As far as
TeX, I  don't know how  popular it  is. Personally I've  never used it  and
don't know  anyone who  has (though  I've heard good  things about  it), so
unless we get a huge outcry for the TeX format, I don't think we'll go that
way. That leaves  the regular text  format that you're  getting it in  now,
Write format, or  WinHelp format. Now, before you cast  your votes, we will
be distributing the March issue in all three of those formats. After March,
tell us what you think. I just wanted to give everyone a heads-up on that.

     One  final note: We mentioned our BBS in  the last issue. Well, we had
it up for  about 3 days and  before anyone had a  chance to call, the  hard
drive got wiped out. I've  been trying to get the thing  back together, but
the hard drive is really  getting unreliable. What it looks like  I'm going
to have to  do is get rid of it and replace it. I currently have two 65 meg
Seagates  which have  done their  time.  The main  one (C:  drive) is  just
getting a little too flakey,  so we're going to toss it and  probably throw
in a 600 meg hard drive that we saw a good deal on. (We have two  machines,
so we're  going to network  them so that  Mike can use  the 600 meg  on his
machine too.)  Anyway, we don't know if we'll have  it up this month. If we
don't, it'll be next month. Sorry for the problems there.

     I'd like to thank everyone who's  reading the magazine and sending  in
their comments and suggestions. It helps us to do a better job and it helps
you get a better magazine. We really appreciate your comments and we'd like
you to  keep them coming.  Also, as  always, please, please,  send us  your
articles. We want them!!!!

     By the way, it's now January 31  and the number of downloads on  GEnie
and Compuserve alone are about 1200, total. Sorry, just about  broke my arm
patting myself on the back there. 'Scuse me while I pump up our egos a bit.
We'll try not to do that too often.

     And remember, if you read it  in the Programmer's Journal, it might be
right!

                                                  _Pete Davis





















                                  Letters

Date:  04-Jan-93 13:48 EST
From:  Andrew Schulman [76320,302]
Subj:  Windows Programmer's Journal

     Thanks  very much  for sending the  magazine.   Of course,  I read the
review of UndocWin  very carefully, and read the rest  pretty carefully.  I
guess my main question  is, Why the heck are you guys doing this?  You both
write well.  The material is interesting and  entertaining.  So why are you
giving it away  for free?   Doesn't make  any sense  to me.   You could  be
making  money from  your  writing, though  not  necessarily with  your  own
magazine.   But clearly you  could write  for MSJ, WDDJ,  or Dr. Dobb's  (I
won't mention that other magazine that covers Windows programming...).  So,
like, why give the stuff away? 

     Thanks  for the kind review of UndocWin.   If you are looking for more
stuff on  how Windows operates,  I think  you'll be pleased  with the  book
"Windows Internals" that Matt Pietrek is just finishing up.  It will appear
in the series  of books I am editing for  Addison-Wesley, probably in March
or  April.   Most of the  book is  typeset already.   It  presents detailed
pseudocode for many  of the key Windows API functions.  For example, if you
want to know what CreateWindow or RegisterClass or GetMessage or ShowWindow
or GlobalAlloc actually does, in sometimes painful detail, this is it.

     UndocNT?  Well, that's an interesting question.  Microsoft has   asked
me that question too.   As you know, the  entire NT API (as opposed  to the
Win32 API) is right  now undocumented.  Helen Custer's book "Inside Windows
NT"  does a good job of showing in a conceptual-overview sort of way how NT
works, but as she  herself says in  the preface the book's  goal is to  how
"exactly how NT sort of  works"  Exactly sort  of!  A brief examination  of
the NT process viewer,  PVIEW.EXE, shows that there is  some dynamite stuff
at the NT API layer that currently  isn't available via Win32.  (Ray Duncan
was  who  put me  on  to  looking  at PVIEW;  I  looked  at it  first  with
Microsoft's COFF -DUMP,  and have  since been modifying  my Windows  Source
product to disassemble PE files.) 

     So there's a  lot of interesting stuff in NT.   And Microsoft actually
seems to look _favorably_ on an Undocumented NT book.  This way, they don't
have to document it!

     There's just  one problem:  to do a book  like UndocDOS or UndocWin or
UndocNT takes  a long time.   Basically, it's not  worth doing such  a book
unless you're going to sell a  lot of copies.  And  I do not think that  NT
anything is  going to sell  a lot of  copies for a few  years.  To  me, the
whole thing is reminiscent  of OS/2 in a lot of ways.   (In a lots of ways,
it's not  reminiscent of OS/2 of  course:  Microsoft has  clearly learned a
lot of lessons, but I think it's also repeating some of the same mistakes.)
Me, I'm putting my money on Win32s rather  than NT.  I told one of the guys
at Microsoft  that I would  start working on  it after they  sold a million
copies of NT.  I'm not holding my breath. 

     In looking over  this letter, I  realize that the phrases  "money" and
"sell" keep appearing.  This must say something about me.  :-)

Regards,
Andrew

[Thanks  for the  kind  review of  WPJ,  Andrew, and  the  tip on  "Windows
Internals" - I look forward to reading it. -Mike]








Date:  10-Jan-93 03:22 EST
From:  Alex Fedorov [72400,274]
Subj:  WPJ

Mike--

     Here is Alex Fedorov from Moscow,  Russia.  Yesterday I downloaded the
1st  issue of  WPJ. This is  great! I've  a whole  set of  Peter's previous
magazine - Pascal News Letter. I liked it. I'm working as an editor for our
"Computer Press" magazine - the most popular computer magazine here. Before
that I've worked  as tech support person for Borland Pascal  for one of its
distributors here.  Reading  WPJ.INI section,  I've realized  that you  are
looking for authors. I would like to offer a set  of articles, dedicated to
changes in  Windows 3.1 - new DLLs, concepts and APIs from Turbo Pascal for
Windows.   These articles  were prepared for  publication here  and can  be
translated in  a short time. The  articles cover new  kernel API functions,
TrueType  fonts,  OLE/DDEML,  COMMDLG,  Drag  and  Drop,  VER and  TOOLHELP
libraries.   Beside the  texts, there is  plenty of examples,  which can be
used like small utilities.

     Please  let me know  if this is  interesting for beginner/intermediate
section of WPJ. Also, I've plenty of hacks for advanced users. 

                                   Let me know if you need more
                                   information.
  
                                   Sincerely, Alex

[Glad you liked the 1st issue, Alex.  Hope the rest go over as well.  We've
included  your first  article in  this issue  and plan  to include  more in
future issues. -Mike] 





































                Install Program Part II: File Decompression
                               By Pete Davis

     Well, I don't know where my head's been, but I think I found  it. Last
time  I  was  discussing  how  much   I  was  dreading  coming  up  with  a
decompression  algorithm and it  occurred to me  that I don't  need to. The
LZEXPAND.DLL has all the routines we need for decompression. I was still in
the  Windows  3.0  mindset.  When  I  did  my  first  install  program  the
LZEXPAND.DLL  wasn't available  to me, so  I didn't  even consider  it last
month. Several of you mentioned this to me also. In retrospect, it seems so
obvious. Oh well.... You should also  read Alex Fedorov's article on  using
LZEXPAND under Turbo Pascal in this issue.

     Ok, so for those of you that don't know, LZEXPAND.DLL is a set of file
decompression  routines  supplied  with  Windows 3.1.  Because  I  want  to
maintain 3.0 compatibility (a bad  habit I pick up from work, I guess) I am
supplying the LZEXPAND.DLL file with this issue.

     This article isn't going to be too long  because, thanks to Microsoft,
the LZEXPAND.DLL takes all the work out of file decompression. They make it
as easy as opening, reading, and closing a file. 

     One feature we're going to  have in our program is two  of those nifty
little progress bars that shows us how far we are through our installation.
One is going  to show progress  for the entire  installation. The other  is
going to handle  progress for the current file. This is where we run into a
bit  of a problem.  In the past  I used the  .ZIP format and  that kept the
total uncompressed  file size  internally so  I could  figure out how  many
bytes the file was going to be uncompressed at run-time. I have been unable
to find a way  to do that with the LZEXPAND.DLL so we're going to have that
in our SETUP.INF file.

     Let me run off on a little tangent here and explain the SETUP.INF. The
SETUP.INF  is going  to be  the file  that makes  our installation  program
generic. The SETUP.INF  file is going to keep information  like the name of
the Application  group, the default destination  directory, whether certain
files will go  into sub-directories within  the application directory,  how
large each  file is un-compressed, what  the compressed filename  is on the
installation  diskette and so on and  so on. We're also  going to break the
rules a  bit. I mentioned earlier  the trouble that Mike got  into with his
article about doing Global linked lists. Well, we're going to use his 'bad'
example and in  this case, I  believe I can  justify it.  First of all,  an
install  program has, in this programmer's mind,  every right to hog up the
CPU.  (Just  try to  run  another  program while  the  floppy drive's  busy
anyway.) Second, it's going to be  playing around with Program Manager, and
when that's going  on, you don't want  the user clicking around  everywhere
and  screwing up the installation, so, we're going  to hog up the CPU. That
means that whatever  global memory is there is ours for the taking and gosh
darnit, we're going  to take what  we want! So, bear  with me on  our nasty
little global linked list. (That will be in next months issue).

     Well,  that little  side-track got  a little  longer than  I expected.
Anyway, back to  LZEXPAND. So, we know the uncompressed  file size from our
SETUP.INF.  What's left is to get our current progress. That's pretty easy.
The way it works is that when you read  from a compressed file, you have to
allocate the buffer. That means that if the buffer is, say, 20k, then every
time  20k of data  is decompressed, we  have to write  out the data  in the
buffer to our uncompressed file on the destination disk. So, all we have to
do  is  update  our  progress  bar  by 20k  and  whatever  percent  of  the
installation that is. The formulas are really simple. 








     The   commands  we're  going  to   be  concerned  about  are:  LZInit,
GetExpandedName, LZRead, and LZClose. 

     The LZInit function essentially allocates memory for the decompression
algorithm  and initializes some data that the algorithm uses. The prototype
is:

HFILE LZInit(HFILE SrcFile)

     SrcFile is the file  handle received from a regular  OpenFile function
call.  We use this handle  only for the  LZInit, but we keep  the file open
until the end of our  decompression. If the return value from LZInit is the
same  as SrcFile, then that means our  file isn't compressed. If the return
value  is greater  than  0,  then it  is  a  special  file handle  for  our
compressed file. If the return value is less than 0, then we have an error.

     After we  do the LZInit, we  have to do  a GetExpandedName to  get the
filename of our file as  it was prior to  being compressed. We'll use  this
filename when we open the output file to write the  uncompressed version of
the file. The prototype for the GetExpandedName is:

int GetExpandedName(LPCSTR lpszSource, LPSTR lpszBuffer);

     lpszSource  is a pointer  to the string  that has the  filename of the
compressed file.  lpszBuffer will have the  name of the file  prior to it's
compression. This  is the filename that  we will use when  writing the file
back. The return value is TRUE if successful.

     After that, of course, is the LZRead which, again (isn't this just the
most bizarre thing) is a lot like the _lread function. It's prototype:

int LZRead(HFILE hf, void FAR* lpvBuf, int cb);

     hf  is the  file handle  we returned  from the  LZInit. lpvBuf  is our
buffer to hold the  data we read. cb is  the number of bytes read  from the
file.  This is the  number we'll use  to write the  data out to  our output
file.

     Last, but not least, the LZClose. It's simply:

void LZClose(HFILE hf);

     where hf is the file handle to close. 

     That's  about all  we need.  It's pretty  simple. There  are other  LZ
commands  and maybe  at some  point I'll  have a  discussion of  the entire
library of  commands. At this  point, though, it's confession  time. I must
admit I have no  code to go with this article this month. Fear not, it will
be in next  months issue. I'm  hoping to wrap up  the entire thing  in next
months issue,  and with  several other  people helping  out in next  months
issue, that just  might be possible. Anyway, until then,  mer i beaucoup et
au r voir. (Just trying to be a little international there.)
















          Programming a Drag&Drop Server for Windows 3.1 with TPW
                             by Andreas Furrer

     Last issue I explained  how to implement  a client for Drag&Drop  with
File Manager. This was easy because it is well documented by Microsoft. But
now, what if we  want to be the server  for Drag&Drop (e.g. if you  want to
program your own file manager)?

     There  is no documentation from  Microsoft for this,  so the following
can change with the next version of Windows.

     The first we have to do is capturing the mouse. This is done by

  SetCapture(HWindow);

where HWindow is  the handle of  the window that  should receive the  mouse
messages. Now we will receive WM_MouseMove messages every time the mouse is
moved even if the mouse is not in your client window.

     If the mouse was  moved, we have to detect if the  window at the point
of the cursor is registered to accept dropped files.

So we have to process WM_MOUSEMOVE messages:
  1) You can get  the current position of the  cursor when the message  was
sent by:

       Point.X := LoWord(GetMessagePos);
       Point.Y := HiWord(GetMessagePos);

  2) Now we can get the window at this Point:

       DragWnd := WindowFromPoint(Point);

  3) To check if the DragWnd is registered to accept dropped  files we have
to check if  the window has the exStyle ws_Ex_AcceptFiles.  If the Style is
set, we  will set the cursor  to a cross, if  not we will  set the standard
cursor: 

       if GetWindowLong(DragWnd,gwl_ExStyle) and ws_Ex_AcceptFiles =
                  ws_Ex_AcceptFiles then
         SetCursor(LoadCursor(0,idc_Cross))
       else
         SetCursor(LoadCursor(0,idc_Arrow));

     ws_Ex_AcceptFiles has a value of $00000010;


     Now if the mouse button is released we have to release the capture and
set the default cursor with

  ReleaseCapture;
  SetCursor(LoadCursor(0,idc_Arrow));

     Get the DropWnd under the  cursor (see above) and if the  window under
the  mouse is  a D&D  window  (see above)  we have  to post  a wm_DropFiles
message to it. But in this message we have to set wParam to a handle with a
Drag&Drop structure and the format of this structure is not documented.

I found out that the structure looks like this:









  type PDragDropStruct =^TDragDropStruct;
       TDragDropStruct = record
         DataOffset      : word;
         DropPoint       : TPoint;
         DropInNonClient : bool;
         Data            : array[0..0] of char;
       end;

The meanings of the parts of this structure are:
  1) DataOffset :
       This is the offset where the filenames begin.
  2) DropPoint
       This is the point where the mouse was released.
       The coordinates are client coordinates.
  3) DropInNonClient
       This flag is set if the mouse was released in the non-client area
       of the window (e.g., title bar).
  4) Data
       Here is the beginning of the data. All filenames are separated by a
       chr(0) and the end of this list is terminated by another chr(0).

Now we have to do the following:
1) Allocate memory for the Drag&Drop structure
2) Lock the memory
3) Set the data
4) Unlock the memory
5) Use the Handle to the memory as wParam

For example we want to have 3 files in the Drag&Drop structure

const s : array[1..3,0..255] of char=('C:\autoexec.bat',
                                      'C:\config.sys',
                                      'C:\dos\command.com');

We have to compute the length of all the strings

  l := 0;
  for i := 1 to 3 do
    l := l+ StrLen(s[i]);

and have to allocate memory for the  whole structure. The memory must be of
the type gmem_DDEShare.

  DataHandle := GlobalAlloc(gmem_DDEShare,sizeof(TDragDropStruct)+l);

To set the data we lock the memory

  DataPtr := GlobalLock(DataHandle);

and fill the fields of the structure:

  with PDragDropStruct(DataPtr)^ do begin
    DataOffset:=Data-DataPtr;
    DropInNonClient:=(
      DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient);
    ScreenToClient(DropWnd,Point);
    DropPoint   :=Point;
  end;

where








  DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient

will test if the cursor is not in the client area of the window.

The last data  we have to set are the filenames.  We do this with a pointer
p. Initially we set p to the field data of the structure.

  p:=PDragDropStruct(DataPtr)^.Data;

Now  we copy each string to  p and set p at the  end of the string plus one
(StrLen will not compute the chr(0)).

  for i:=1 to 3 do begin
    StrCopy(p,s[i]);
    p:=p+StrLen(s[i])+1;
  end;

If we have copied all strings we have to terminate the list with a chr(0)

      p^:=#0;

At the end we have to unlock the memory with

  GlobalUnlock(DataHandle);

and post the wm_DropFiles message to the DropWnd:

  PostMessage(DropWnd,wm_DropFiles,DataHandle,0);


The file D&DSER.PAS is a simple Drag&Drop server. Just press the left mouse
button in the  client area and move it to the  window of a Drag&Drop client
(e.g D&DCLI,  see below) and release the button. While moving the mouse the
cursor  will  change to  a  cross, if  the  window under  the  cursor  is a
Drag&Drop client.

D&DCLI.PAS is an implementation of a simple Drag&Drop client. It
will print out the dropped files in a WinCrt window. It is nearly
the same code as the trash can in the last issue.





























                           C++ Beginner's Column
                              By Mike Wallace

     I promised in the last issue I would start a beginner's column on C++,
and I didn't want to lie to you.   I have been reading some books lately on
C++ because I don't  know anything about it.  My plan is to learn enough to
write a "Hello world" program in  C++ for Windows (for starters), gradually
move on  to more advanced programs and  try to share with  you everything I
learn along the way.  Hope this suits  you because it's the best way I  can
think of to approach  this.  If you have  any suggestions/complaints please
don't hesitate to  let me know.  We  have a ways to go before  we can start
coding so be patient  for now.  This stuff can be a little bizarre, so I'll
try to explain it as best I can.

     I've  been programming  for  about 10  years  and have  become  pretty
comfortable with Pascal, C, COBOL, FORTRAN, BASIC and the rest  of the most
popular languages, and I've noticed they have a lot of similarities when it
comes to program structure, data abstraction, etc.  If you already know how
to program and now want to learn C++, forget everything you've learned.  If
you've never programmed before, then you're a step ahead of the rest of us.
C++  is  unlike  anything  I've  seen  -  it's  a  whole  new  approach  to
programming.  The best book I've seen on the subject is Borland's excellent
"Object-Oriented Programming Guide"  that came  with Turbo Pascal  5.5.   I
hope this guide  is still packaged with the latest version  of TP - chapter
one is a great read and helped clear up some of the more mystifying aspects
of OOP for me.

     OOP is something  like the sound of  one hand clapping -  if you don't
think about  it too  hard and ignore  what you  already know, it's  easy to
imagine.   Consider an apple.  In  abstract terms, it's just an object, and
like  any object, it is described by  its physical properties (an apple has
to have  weight, for example).   Think of these properties  as functions of
the object.  It is important to keep in mind that we're not talking about a
specific apple, but any apple that  ever existed.  The function describing,
say, the weight, stays the same  - only the values going into the  function
differ.   So,  the nature  of an  apple is  intertwined with  the functions
describing it - they  can be encapsulated  to form an object.   This is  an
important concept in  OOP.   "Encapsulation" refers to  combining a  record
with the code that manipulates it to form an object.

     Let's move on  to an  example closer related  to programming:  drawing
graphics.   If we wanted  to write  a program for  drawing lines,  circles,
etc., we could  start with defining  an object called  Point, which has  as
three fields:  x coordinate (integer),  y coordinate  (integer) and  on/off
(boolean).  The first  two fields give the location of Point  and the third
says if it  is displayed (on)  or not (off).   If we  wanted to extend  our
program to  include circles, we could  a define a new  object called Circle
that  had the same  fields as Point  plus a field  for the radius  (x and y
would be the center of the circle).  To save time,  we could declare Circle
as an object of type Point with another field for the radius.  Circle  is a
descendent of Point  because Circle  has inherited the properties of Point.
This  is  another concept  important to  understanding OOP.   "Inheritance"
refers  to  defining  an object  and  using  it  as  a basis  for  defining
descendent objects,  with  each descendent  inheriting  access to  all  its
ancestors' code and data.

     Finally, let's say you want to write a routine for drawing a Point and
another  for a  Circle.   Although  the two  routines would  be implemented
differently, they're both doing  nothing more than  showing an object.   In
C++, it is possible to declare two routines with the same name, and here we








could do it with  the routine "Show."   The difference  between the two  is
that one would  be tied to the object Point and  the other would be tied to
Circle.   This is called  "polymorphism", and  is giving  an action  (here,
showing  an arbitrary object) a single name  (e.g., "Show") that is used by
different  objects in  the hierarchy  , with  each object  implementing the
action in a manner suited to that object.

     Well, that's  all for  this month.   I've stayed  away from  code here
because it's  too early to start with it.   C++ is too different than, say,
C, to jump into code,  I think [that's his  way of saying he hasn't  gotten
that  far either  - Pete].   I hope  this makes  sense so  far.   If you're
thinking, "I never did this  with Pascal", then you're starting to  get the
point.  It's not just a computer  language - it's a way of programming that
reflects  the way we think, much more so  than C, for example.  Don't think
too  hard about it and it should make more sense than what you already know
about  programming.  If none  of this makes sense, drop  me a line and I'll
see what I can do.



















































                             Beginner's Column
                       By Mike Wallace and Pete Davis

     Last month  we  covered the  .DEF  file and  started  on resources  by
describing  dialog boxes.    This  month  we'll  finish  the  .RC  file  by
explaining  menus,  and then  begin on  the C  code  for our  "Hello World"
program.
     A Windows  program  isn't a  Windows  program without  a menu.    It's
probably the  first thing you look  for when you're running  a Windows app.
If you've wondered  how to create  one yourself, you've  come to the  right
place.  You describe your menu in the .RC file using the following format:

<menu-name>    MENU
BEGIN
       POPUP "<popup menu>",
       BEGIN
                MENUITEM "<menu item 1>",  <variable>[, options]
        END
        MENUITEM "<menu bar item>",  <variable>[, options]
END

     You can have as many  menu items as you want (or will fit  on the menu
bar),  and even have popup  menus inside other popup menus  if you want.  I
kept  the  format  simple so  it  wouldn't  be  overwhelming.   Here's  the
explanation for the codes:  anything inside "<>" is required,  and anything
inside "[]" is optional.   You have to give your menu a  name.  You can put
the  POPUPs  and MENUITEMs  in any  order you  want,  but don't  forget the
BEGIN/END statements that go right after the POPUP statement.  Any MENUITEM
inside the BEGIN/END appears under that  popup menu.  MENUITEMs that appear
outside  the BEGIN/END of  a popup menu  appear on  the menu bar,  but they
won't have a  menu under them.   For each menu item,  you should give it  a
variable  (defined in a .H  file included in the .RC  file) that you'll use
when your program checks for which menu item was selected by the user.  For
any menu item, you can include the following options:

CHECKED   - The menu item has a check next to it

GRAYED    - The menu item text is grayed and inactive

HELP      - The item has a vertical line to the left.  You can also include
a "\a" at
             the beginning of the text if you want to item to appear on the
menu 
             bar's far right side.

INACTIVE  - The menu item name is displayed but cannot be activated.

MENUBARBREAK   - When used on a menu, the item is placed on a new line.  On
             popups, the item is placed in a new column.   A line separates
this 
             item from the previous one.

MENUBREAK - Same as MENUBARBREAK, except for popup menus : no dividing 
            line.


A couple of more hints: If you want to make a character in a menu item name
underscored (to allow for ALT-whatever), add an "&" before the character in
the  name.   Also, you  can  add the  line  "MENUITEM SEPARATOR"  to add  a
horizontal line between popup menu bar items.








     We're now ready to write the .RC file for "Hello World".  Here it is:

/* hello.rc */
#include <windows.h>
#include <hello.h>
amenu          MENU
BEGIN
          POPUP "&Text"
          BEGIN
                 MENUITEM "&Write",             IDM_WRITE
          END
          MENUITEM "&Quit",                      IDM_QUIT
          MENUITEM "\a&Help",                  IDM_HELP, INACTIVE
END


Here's "hello.h":
/* hello.h */
/* define menu bar items */
#define  IDM_WRITE   1
#define  IDM_QUIT       5
#define  IDM_HELP     10

/* function prototypes */
Long FAR PASCAL MainWndProc (HWND, unsigned, WORD, LONG);


The "windows.h" file  is included  with the Microsoft  Windows SDK, and  is
required for  any Windows program.  The above two  files will change as our
program grows, but it  should suit our needs  for now.  We'll describe  any
changes we make to any file we've already created.  Here's Pete to tell you
about the C code.

     Ok, so I  guess it's my turn  to talk about the coding  of this thing.
This is a real bread and water Windows program, but it's got all the basics
that you're going to find in all Windows programs, and that's what you need
at this point.

     In a normal C program you have your main() function which is the first
function to get called in  a C program. In Windows, instead of  main(), you
have WinMain(). (Real original, eh?) The WinMain function is where you take
care of all the initialization. The main things you want to do  is register
your window class. Now, this makes it sound like object  oriented stuff all
of  a sudden, and I  suppose it is, but all  you're really doing is telling
Windows  a few things  about your  window. (You have  to keep  in mind that
Windows is essentially  an object oriented  operating system. Although  our
programming  isn't  object oriented,  per se,  we  are emulating  an object
oriented programming environment.)

     Instead  of showing the Window Class structure here, I'll just discuss
it. I've labeled  the members of the  structure in the  code, so you'll  be
able to relate what I write here to the structure members in the code.

     The  hCursor is basically done by a load cursor. Most applications jut
choose the generic IDC_ARROW cursor. 

     The hIcon is where you  really get to have fun. This is  the icon that
is shown when your application is minimized.

     The hInstance is simply the instance for this application.








     The  hbrBackground  is the  class  of the  background  brush, meaning,
basically, the color or pattern used in your window. This is usually white.

     lpszMenuName  is a pointer to  a null-terminated string  which has the
resource name of your menu.

     style has several  options, most of  which are a  little more than  we
need  to  go  into  at  this  point. My  suggestion  is  use  CD_HREDRAW  |
CS_VREDRAW. This basically means to redraw the window if the  horizontal or
vertical window sizes change.

     The cbClsExtra and cbWndExtra are a bit more complex than we should be
going into at this point, so like so many other things, we'll hold them off
for another day. Just keep them NULL for now.

     After  registering  your  window class,  you  have  to initialize  the
instance. What  this means is that  in a Windows  program, you can  run the
same program several times at once  (not all Windows applications, but ones
that are written to  allow it.) Each copy of the program  running is called
an instance. The  reason you have  to initialize the  instance is  because,
each one  of those versions is going  to share the same  copy of code. (You
don't  have to share the code,  but it's bad practice not  to, so we're not
going to  say any more about  that no no.) Also,  because handling multiple
instances  of an application  can be a  bit tricky for  the beginner, we're
going to set up our code to reject attempts to run multiple instances.

     At the  end of  all of  this you set  up your  message queue.  This is
fairly simple to do and fairly generic. Most programs do this the same way.
There are  reasons for changing it,  sometimes, but we're not  going to get
into that either, at this point.

     When  you  initialize the  instance, you  also  tell Windows  what the
procedure  is that is  going to handle  the messages for  your main Window.
Here's  where the multi-tasking of  Windows takes place.  See, what Windows
does here is  that every  time something  happens in  your window,  Windows
calls this procedure and  passes along a message describing  what happened.
This  could be something  like a mouse  movement, a menu  selection, etc...
See, you never explicitly call the procedure that handles your main window,
what you do is tell Windows where the procedure is and it will know when to
call it.

     The  best  way to  handle your  main window  procedure  is to  setup a
switch/case  structure where each case  of your switch  statement handles a
different message.

example:
     /* Switch structure for message */
     switch(message) {

          case WM_CREATE:
               ....
               ....
               ....
               break;

          case WM_Another_Message:
               ....
               ....
               ....
               break;








          etc...


     Windows messages  generally start  with  WM_. The  WM meaning  Windows
Message, oddly enough. After each case would be the code to handle whatever
that  action requires. For example,  the WM_CREATE message  is called right
before a window (or dialog box for that matter) is created,  so it's a good
candidate for initializing variables and  that kind of stuff that you  want
to do every time your window is created.

     A little  side note here: There  are two types of  dialog boxes, Modal
and Modeless (Yes, one is al and  the other is el). The Modal dialog  boxes
are very similar to windows in that they are given a procedure that handles
messages that  are passed to them.  (We'll discuss Modal dialog  boxes at a
later time also. One thing at a time.)

     I digress... Anyway,  the break  after each case  statement is just  a
quick way out of the switch/case  structure. It basically means that you're
done handling that particular message.

     Ok, so what are we learning here? Well, Windows programs aren't linear
in the sense that you run  a procedure which may run another procedure  and
so on. Windows is  event driven which means  that it reacts to  events that
take  place. When you  move the mouse,  that's an event,  so your procedure
gets called. When  you hit a  mouse button, that's  another event, but  the
same  procedure  gets called.  This  procedure  should respond  differently
depending on the message it receives.

     That should  be all you need.  I've included the Hello  World code and
I've  put as much  inline documentation as  will make sense.  I suggest you
give it a whirl, and like  any of our articles, if you have  questions, let
us  know. If we've inadvertently  skipped something, send  us a message and
we'll amend our goofs.

     Next  month  you'll have  Dave Campbell  coming  to you  directly from
Arizona.  He's a hell of a  programmer, so he'll have lots  to show you and
hopefully, give you a  little different perspective  than Mike and I,  that
way if you don't understand  what we're saying, maybe you'll  understand it
when  Dave says it. So, so  long and thanks for  reading. Hope you'll treat
Dave as well as you've treated us.




























                           Using LZExpand Library
                                Alex Fedorov

     LZEXPAND.DLL is  supplied with Windows to allow  programmers to unpack
files,  previously packed with COMPRESS.EXE  utility. Here we  will look at
the  main functions  of this  library. Note,  that you  can  use EXPAND.EXE
utility to unpack files  instead of using functions from  LZEXPAND library.
Mostly,  this library is used  for installation programs.  (This article is
intended for TPW programmers).


     Data compression

     Data compression  is a task to  lower the file size  by converting the
repeated data with  some other sequences. In text  files such repeated data
can  be  spaces, mostly  used  chars or  even  the whole  strings.  Due the
compression  such repeated  sequences  are replaced  with the  shorter one.
Several data compression  algorithms exist. One of the most  popular is the
Huffman algorithm, based on  the frequencies of chars repetitions  in text.
Another  one is a run-length  encoding algorithm, where  the repeated chars
are replaced by pairs:  the first nibble contains the  count of repetitions
and the second one the char code itself. Also, the  Lempel-Ziv algorithm is
widely used and the COMPRESS.EXE utility is based on it.


     Data expansion

     Applications  use  functions   from  LZEXPAND.DLL  to   unpack  files,
compressed  with COMPRESS.EXE utility. Here  is the actions  flow to expand
one or more files.

     Unpacking one file:

          ~ Open a compressed file with LZOpenFile. Also,
          the file can be opened with OpenFile or LZInit
          functions.

          ~ Open a destination file using LZOpenFile or
          OpenFile functions.
          
          ~  Use LZCopy to copy data from source to
          destination using file handles from LZOpenFile
          or LZInit.

          ~ Close both files with LZClose.


     Unpacking several files:

     To unpack several files you perform the following actions:

          ~ Open source file with LZOpenFile or with
          OpenFile and LZInit functions.

          ~ Open destination file using LZOpenFile or
          OpenFile functions.
          
          ~ Allocate memory for copy operations with
          LZStart function.









          ~ Use CopyLZFile to copy source file to destination
          file.

          ~ Free allocated memory with LZDone function.

          ~ Close all files with LZClose function.


     Reading data from compressed files

     Instead  of unpacking the whole  file, an application  can unpack file
piece-by-piece, using LZSeek and LZRead  functions. These functions can  be
useful when we unpack the huge files.

     To  use the functions from LZEXPAND.DLL you need the unit LZEXPAND.TPU
which is supplied with Turbo Pascal for Windows 1.5 or  with Borland Pascal
for Windows.

     Here is the example of how to use LZEXPAND.DLL functions

     {       LZDEMO - The demo of LZEXPAND.DLL functions usage    }

     uses LZExpand,WinTypes,WinProcs;

     Const
      szSrc      = 'MYFILE.PAK';  {Packed file name}
     Var
      szFileName : Array[0..127] of Char;
      ofStrSrc   : TOfStruct;
      ofStrDest  : TOfStruct;
      hSrcFile   : THandle;
      hDstFile   : THandle;
      Total      : LongInt;

     Begin
     {Open compressed file}
      hSrcFile := LZOpenFile(szSrc,OfStrSrc,of_Read);

     {Get the original name of file}
      GetExpandedName(szSrc,szFileName);

     {Create the file with szFileName}
      hDstFile := LZOpenFile(szFileName,ofStrDest,of_Create);
     
     {Unpack file while copying it}
      Total := LZCopy(hSrcFile,hDstFile);
     {LZCopy returns the number of bytes written}
     
     {Close both files}
      LZClose(hSrcFile);
      LZClose(hDstFile);
     
     End.
     
     Note: In the  example above,  we used the  LZOpenFile function,  which
automatically  calls LZInit  function, which performs  some initialization.
The  result code of this function  can tell us whether or  not the file was
compressed with  COMPRESS.EXE. To do this,  you need to open  the file with
the OpenFile function (from  KERNEL) and then call LZInit  directly, giving
it the  file handle from OpenFile.  LZInit returns the file  handle. If the








value  for this  handle  is not  the same  as  the argument,  the file  was
compressed and we can unpack it. Here is the example:

          hSrcFile  := OpenFile(szSrc,ofStrSrc,of_Read);
          hCompFile := LZInit(hSrcFile);
          If hCompFile <> hSrcFile then
          
           {File was compressed with COMPRESS.EXE}
          
          Else If hCompFile = hSrcFile then
          
           {File was not compressed}
          
          Else
          
           {Some error encountered; must check LZError_XXX codes}
     

     Also note, the GetExpandedName function returns the original name only
when the file was compressed by COMPRES.EXE with /r option.


                                        Alex is a freelance programmer
                                   and the editor for "Computer Press"
                                   magazine. Alex lives in Moscow, Russia.











































                   Implementing A Linked List - Revisited
                              By Mike Wallace

     I didn't expect this to happen.  I have caused a small uproar  by last
month's  article "Implementing  a  Linked  List  Using  the  Global  Heap."
Several people had differing  opinions on the best way to do  this, and two
of them have promised articles showing two different ways to do this, which
we hope to  publish soon.   Part  of it was  my fault:  at the  end of  the
article, I intended to mention that  it was very easy to alter the  program
to use the local heap (instead of the global heap) - all you need to do  is
change the  Global commands  (e.g., GlobalAlloc)  to Local  commands (e.g.,
LocalAlloc) and the FAR pointers  to NEAR.  I arbitrarily chose  the global
heap for the program, and several people pointed out (and for good reasons)
that it's always  better to use the local heap if  at all possible.  Hope I
haven't confused anybody.  In case anyone is interested in using the method
I  proposed last  month, then  I have  bad news:  there was  a bug  in last
month's  code  involving freeing  the memory  blocks.   I  have  included a
revised version of the program with this issue.


















































           An Introductory Look at DLLs and The Use of Make Files
                               By Rod Haxton

     Whenever  one begins learning Windows he/she always seems to hear talk
about  DLLs (Dynamic  Link  Libraries). Learning  Windows  is a  very  long
process. Like anything in  the programming world there's lots to learn, and
not that much time to learn it in. Thus, many beginning Windows programmers
bypass Petzold's chapter  on DLLs until a later time.  This article may not
be of great help in understanding DLLs for Windows programmers just getting
their feet wet.  But, if you  have been writing code  for Windows and  feel
competent, and have  not yet tackled DLLs, this code may  give you a little
understanding of  how DLLs work.  Also, if  you have some  understanding of
80x86 assembly  language underneath-the-hood workings, this  will be useful
in understanding  how DLLs work in Windows. A bonus to this article is that
it  demonstrates how a  large application or  for that matter  any size app
should be laid out. The programming example accompanying this article shows
how source  code should be broken  up into seperate modules.  The demo also
makes use of Make files and  shows how they can help speed  the development
of projects, and also demonstrates how to break code up  into multiple code
segments. So often in Windows books the programs demonstrated are  built as
one application with one code  and data segment. This isn't really  what we
as developers need.

     In learning  DLLs there are  a few areas  that one should  focus on to
gain 'THE KNOWLEDGE'; this conjures up images of some  monks sitting around
reading thick books. Cutting and pasting code samples from on-line articles
or  typing them  in  will get  you something  working  but, if  you do  not
understand what is really  going on in Windows you will  be held hostage to
some unknown  events and also  your own  imagination, or the  lack thereof.
Thus, there are some things to focus on when learning about DLLs. They are:

          * DS != SS
          * Windows & DLLs entry/exit code
          * Exports & Imports
          * LibEntry & LibMain
          * WEP function


               DS != SS
               --------

     In  a regular Windows application  program the Stack  and Data Segment
are the same. If  you set up your  program to have multiple code  segments,
the Code segments  can change during Windows function calls, far calls, and
return  from far  calls.  The changing  of the  code  segments takes  place
because most code segments are flagged as  moveable and discardable. If the
code segment has been flagged as a fixed segment then the code segment will
stay put. But,  in understanding DLLs you need to concentrate on DS and SS.
As I mentioned, in regular  Windows apps DS == SS. Standard  C routines can
be  used  in non-DLL  apps. They  do  not assume  DS ==  SS,  and generally
reference pointer variables  relative to  DS.  Remember, when functions are
called  a stack frame  is created,  which holds  the passed  variables, the
returning CS:IP  address, and space is created  to hold any local variables
to the routine. Thus,  references to your passed-in near  pointer variables
are seen by the stack, because C does not make a distinction  between stack
segment-based variables and data segment-based variables.

     DLLs on  the other hand have their own data  segments.  This is one of
the  reasons  that makes  them appealing  to  those developers  writing big
applications. When a routine to a DLL is called, the calling function's, if








its not in  the DLL, DS and CS  are placed on the stack.   The DLL uses the
stack of the calling  function. The DLL's DS and CS  are given scope. Thus,
the calling app (if passing any variables to the DLL) must pass them as far
pointers  in  order  for the  variables  to have  scope.  Also,  standard C
routines  cannot be  used,  because  DS !=  SS,  and the  standard  library
routines  reference the  variables from  DS. If  you do  call a  standard C
routine or another  DLL's function  with near pointers,  when the  function
returns  the variables will  be unchanged. Ways to  get around this problem
are to  declare your local variables in your DLL  as static or pass them as
far pointers.


          APP                                 DLL
     ---------------                    ---------------
     |             |                    |             |
     |     CS      |                    |      CS     |
     ---------------                    ---------------
           DS                                  DS

                      SHARED
      SS------------------------------------------------SS


     A detailed  discussion of DS !=  SS can be found  in Charles Petzold's
'Programming Windows', and  Mike Klein's  'DLLs And  Memory Management'.  A
step to really comprehending DLLs is to understand DS != SS.



               Windows & DLLs Entry/Exit Code
               ------------------------------

     Another  aspect of  understanding DLLs  is to  understand how  Windows
loads application functions and DLLs. Again, here a little understanding of
how a MS-DOS C compiler handles function  loading and assembly language can
be helpful. Now,  if you  do not  happen to  be a  low-level system  person
and/or  have  no desire  to be,  you  may be  asking yourself  why  this is
important. Well, this really isn't important if you don't mind writing code
and not understanding what's really taking place. But remember, you will be
at a real disadvantage when a bug crops up and you go into your debugger to
find out what is wrong and you have no idea of what you're looking for. 

     Under DOS the compiler sets up segments as the following:

          mov  ax, _DATA
          mov  ds, ax

And, function entry/exit code saves registers and makes space on the  stack
for passed variables and local variables,

          push bp
          mov  bp, sp
          sub  sp, <number of bytes needed>
          .
          .
          .
          mov  sp, bp
          pop  bp
          ret       ;This  can   be  a  near   or  far  return.   Also,  if
                    ;the    function   was    called   with    the   PASCAL








                    ;directive    the    number   of    parameters   passed
                    ;to   the   stack   needs    to   be   added   to   the
                    ;return.

     Windows functions  are all set up  to be far calls.  This provides the
built-in ability  to swap and discard  code segments in and  out of memory.
The  entry exit  code for  the non-exported  far functions  looks like  the
following:

          push ds -----------------------| same as:
          pop  ax -----------------------|   mov ax, ds
          nop
          inc  bp
          push bp
          mov  bp, sp
          push ds               ----------------------   save   ds   again?
          mov  ds, ax ---------------------- here again ?
          sub  sp, <number of bytes>
          .
          .
          .
          dec  bp
          dec  bp
          mov  sp, bp
          pop  ds
          pop  bp
          dec  bp
          ret  <number of passed parameters>

Looking  at the  Windows entry/exit  code above  we see  that it  is really
similar to the DOS version.  It just does extra  work. The reason being  is
that Windows modifies the entry code when your exported function is called.
Windows replaces the first two instructions  ('push ds' and 'pop ax')  with
NOPs.  If you noticed the code above where I have stated 'here again?', the
instruction is 'mov  ds, ax'. But, now ax contains  nothing. Before it held
the value of ds. What  happens is that during LINK Windows  places into EXE
file a  table that  lists  the references  to your  far  calls and  Windows
functions. Thus, when Windows runs and calls your far function the register
ax has already been loaded with the segment location. Exported functions DS
are  handled during the registering  of window class  structures created or
with  the MakeProcInstance  for call-back  functions. The  MakeProcInstance
tells Windows to  do some 'thunking'.  Thunking handles the  setting up  of
code  and data segments. Each instance of  a Windows function will have its
own DS, but all instances will refer to one CS.

Far calls and Window functions entry code:

          nop
          nop
          nop
          inc  bp
          push bp
          mov  bp, sp
          push ds     

          mov  ds,    ax---------------->'Instance   Thunk'    located   in
                              fixed memory position.
                              mov  ax, <DS for instance>

          sub  sp, <number of bytes>










     DLLs entry code  is as simple as the  DOS version.  Because  DLLs have
their own DS and there can only be one instance of a DLL there's no need to
determine the DLL's DS at run time  or create an instance thunk. The DS  is
already known so it can be set.

          mov  ax, <DLL DS>
          inc  bp
          push bp
          mov  bp, sp
          push ds     
          mov  ds, ax



               Exports and Imports
               -------------------

     You should already know  about Exported functions if you  have written
Windows  code. But,  here's a  brief tutorial.  All Windows  functions that
receive  messages  must be  exported. The  export  tells the  compiler that
references to the exported functions will be resolved at run-time. 

     Imported functions are also  used to resolve function  references. The
IMPORTS statement  in a DEF  file tells the  Linker that the  functions are
defined elsewhere  and  relocation  info  will  be  resolved  at  run-time.
Imported functions can be handled in two ways. One is to list them in a DEF
file under  the IMPORTS statement. The other is to  place them in an import
library and link them into your code. The latter is the approach that I use
because it reduces the  headache of updating DEF files  during development.
Also, listing  the  import  functions  in  DEF  files  requires  a  lot  of
memorization when you  start dealing with multiple DLLs. Later, I will show
how I handle multiple DLLs and imports.


               LibEntry and LibMain
               --------------------

     Every Windows executable  modules needs an  entry point. When  writing
apps  for Windows this  code is  hidden from  the developer.  However, when
writing  DLLs the  source  to the  library  entry routine,  LibEntry(),  is
provided to you by the  SDK. Usually, you do not have to touch  this code -
the SDK  provides 'libentry' for you  to link into your  DLL. 'libentry' is
the object file for LibEntry(). If you are creating a resource-only DLL you
do have to modify LibEntry() a little bit. LibEntry() also calls a function
LibMain() that you must supply.

     When  the application program starts up all  DLLs tied to that app get
called. The initial  call for the DLL is the only  guaranteed time that the
library  will be  called. LibEntry()  initializes the  DLL's local  heap by
making a call to LocalInit(). Under Windows 3.0, due to  Real Mode support,
LocalInit() locks  the DLL's data segment; the  locking of the data segment
does not take place under Windows 3.1. On exit from LocalInit(), LibEntry()
calls LibMain(). If  the data  segment was locked  your LibMain()  function
must unlock it. 

     LibEntry() and LibMain() initialize your DLL and are only called once.
You will  see  in my  Make  and DEF  files  that I  place LibMain()  in  an
initialization code  segment. This way the segment will be flagged after it








is  used to be discarded and when memory becomes an issue it will be dumped
by Windows.



               WEP Function
               --------------

     The WEP() routine  is another function  that your DLL  is required  to
have. The SDK says that this function gets called once, when a DLL is about
to be unloaded. This does not seem to be the case under Windows 3.0. When I
have watched  it under Codeview, I have never  seen it called. WEP() has an
input parameter that  identifies whether the  exit is  being caused by  the
system or  the application. Whatever  the reason for the  exit WEP() should
return 1. You will notice in my examples  that I do not do any testing  for
the type of exit:  I just return  1. WEP()'s name is  made resident in  the
DLL's name table, thus it is always in memory and never gets swapped out.


               Programming Example
               -------------------

     Now that the  basics of DLLs have been discussed.  I'll focus the rest
of  this article on  a sample DLL  app that I've  written that demonstrates
DLLs,  the use  of Near/Far  function calls,  Near/Far pointers,  calling a
Dialog Box function located in a DLL, how to create  an import library, the
use of Make files, and how to create multiple code segments.

     The following  DLL example is  called RODSAPP (how  appropriate). It's
comprised of  an  application program  and  two  DLLs. The  app  files  are
rodsapp.c, winmain.c,  and wndproc.c. The file rodsapp.c  contains code for
creating and  initializing the  Windows application.    The file  winmain.c
handles the Windows message dispatcher.  The wndproc.c module is a standard
Windows function that  has a menu bar.  The menu bar is the  entry into the
DLLs. The menu items are About,  One and Two. Clicking on the About  option
demonstrates  a dialog box whose  function resides inside  a DLL (lib2a.c).
Clicking on menu option One causes a call to the testlib.dll (testlib.c).

     The function  StepOne inside  testlib.dll demonstrates  variables that
are referenced from DS and SS.  I've provided total explanations inside the
source so that understanding would be easier. 

     Clicking  on menu option Two also makes  a call to testlib.dll that in
turn calls the  DLL lib2.c. The calls  inside these DLLs  also demonstrates
what happens to variables that are referenced from DS and SS.

     The  Make  file  used with  the  program  compiles  with the  Codeview
debugger options set. I suggest  that you run the program under  Codeview a
few  times and  keep an eye  on the  DS and  SS registers. Also,  watch the
variables inside routines and  note their addresses and watch  what happens
to those variables addresses when you step into a routine inside a DLL.

     Along with the source files is  a batch program DOALL.BAT. It runs all
the Make files  and dumps any warning or error messages out to a file named
peek.

     Also, the Make file LIB.MAK creates an import library 'test.lib'. This
Make  file should be run  first in order to create  the import library that
will be linked into the DLLs. Changes to the DEF files will re-make LIB.MAK
but  the *.dll  files must  be deleted  and re-linked  with the  new import








library.


               Make File Explanation
               ---------------------

     The following is a snippet of the rodsapp.mak Make file; note that the
following statements that  begin with '*' do not appear  in the actual Make
file.

TMPDRIVE=c:\tmp

WLIB=libw mlibcew        *sets   up  a   macro  for   the  libraries   that
                         *will be used during linking

IMPLIBS=test             *the DLLs import library (see next  
                         *section    for    how     this    library     was
                         *created).


* object code of the modules used in RODSAPP.EXE
OBJ=rodsapp.obj winmain.obj wndproc.obj

* compiler option flags; a detailed meaning found in source
CFLAGS=cl /c /AM /D LINT_ARGS /Gws /W3 /Zip /Od /nologo

# Update the executable file if necessary, and if so, add the
# resource back in. The /NOE must be included when linking with 
# Windows libraries.

rodsapp.exe: $(OBJ) rodsapp.res rodsapp.def
        del $(TMPDRIVE)lk.res
        echo $(OBJ)>>$(TMPDRIVE)lk.res
        echo rodsapp.exe/align:16>>$(TMPDRIVE)lk.res
        echo rodsapp.map/map/NOD/CO/LI>>$(TMPDRIVE)lk.res
        echo $(WLIB) $(IMPLIBS)>>$(TMPDRIVE)lk.res
        echo rodsapp.def>>$(TMPDRIVE)lk.res
        link  @$(TMPDRIVE)lk.res
        rc rodsapp.res

# Update the object file if necessary

* The following demonstrates how to seperate your code into code
* segments. The -NT allows one to name the code segment. This 
* name is then placed in the modules DEF file under the SEGMENTS 
* statement and given the control flags that you wish the code 
* segment to follow.

rodsapp.obj: rodsapp.c rodsapp.h
        $(CC) $(CFLAGS) -NT Initialization_code rodsapp.c

winmain.obj: winmain.c rodsapp.h
        $(CC) $(CFLAGS)  -NT Resident_code winmain.c

wndproc.obj: wndproc.c rodsapp.h testlib.h
        $(CC) $(CFLAGS)  -NT Resident_code wndproc.c

# Update the resource if necessary
rodsapp.res: rodsapp.rc rodsapp.h
        rc -r rodsapp.rc









               DEF File Differences
               ---------------------

     The differences between a  Windows application definitions file and  a
DLL's is that  in the Windows app  DEF file there is a  NAME statement that
defines the app's name. A DLL has a LIBRARY statement to do the same thing.
A  DLL does  not need a  STUB statement  since it  cannot be  launched into
execution  without  an application  calling  it. A  DLL  also has  no STACK
statement. Since  the DLL uses the  SS of the calling  application it needs
not define a stack size.


               Conclusion
               -----------

     Things  to consider when developing applications  and using DLLs. DLLs
are not magical elements to be used for everything. If you can do something
fast and it's  only going to be used  by one application, that is  the code
will never really be used in some future app, stay away from DLLs. DLLs are
slow.  It takes numerous cycles  to load DLLs,  segment adjustments must be
made.  The DLL  far call  means that  the code  and  data segments  must be
loaded.

     Hopefully this article will help you in your understanding  of DLLs. I
hope that  the code samples  are clear enough to  help you. I  tried not to
give too  much code, which can be overwhelming when you are trying to learn
something, but just enough to represent the makeup of real projects.

     There  are other  topics under  DLLs that  I did  not cover  like User
Resource DLLs and  the handling of  global data across DLLs.  Maybe someone
else will provide an  article on User Resource DLLs in a  future article. I
plan to submit for the next issue of WPJ an article that demonstrates a way
I figured out to handle global variables across DLLs. Good luck! 

     Rod Haxton can be contacted @ (703) 883-0226 or (202) 269-3780.
































                         The Windows Help Magician
                              By Jim Youngman

     Since I  do not  program  for the  sake of  programming,  I am  always
looking for shortcuts.  The Windows  Help Magician has proven to be  one of
the best.  I think it was written  in Visual Basic, but don't let that  put
you off it.   It's a great little application  and a real time saver.   The
files it produces can be compiled with Microsoft  or Borland Help Compilers
for Windows 3.0 or 3.1.

     I am writing my first fully fledged Windows program.  It is to be used
mainly  by  computer illiterate  people and  so a  good  Help file  will be
essential.

     When  I  started  investigating  how  to  prepare  such  files  I  was
overwhelmed by the prospect: all  those control characters that have  to be
inserted!  The Windows  Help Magician eliminates all of that.  Using a well
designed interface, the  program does all of the hard work.   All I need to
do is think out the design of the Help system.  The friendly Magician gives
me a  great set of tools  for creating the index,  browse groups, hypertext
jumps, popups  and keywords.   You can  also include bitmaps  in your  help
files.

     So far I have  only played about a bit with the product.  I am looking
forward to exploring it further with the real job.


     The Windows Help Magician is available from the publishers:

               Software Interphase Incorporated
               82 Cucumber Hill Road, Foster, RI 02825, USA
               FAX (401) 397-6814
               BBS (401) 397-4601

     There is a fully operational demo  disk which is limited to help files
of 7 pages.  The full version allows 200 pages.
































                               The Last Page
                              By Mike Wallace

     This is too  cool.  Pete and I hoped a  couple of hundred people might
pick  up  the first  issue  of  WPJ (Official  motto:  "It's  not just  for
breakfast  anymore").   After three  weeks on  various bulletin  boards, we
counted over a thousand, and that doesn't even include Internet (we have no
way of  tracking the  number of  downloads there).   We've gotten  mail and
articles from such  faraway places  as Russia, Germany,  South America  and
central Jersey.  We hope the number of downloads goes up every month; if it
starts to go down, we're in trouble.  From the mail we've received,  people
seem to like it and want to help  out.  It's been overwhelming.  If  you're
thinking of writing  an article, don't be  shy.  Others are doing  it.  You
don't have  to be a professional writer (we sure aren't), and we can always
use more articles.  If you don't feel  up to writing an article, send us  a
message  and let us know  what you think about the  magazine.  Does it have
the putrid stench of rotting eggs?  Has it helped your Windows programming?
Inquiring minds want to know.   Remember: this is your magazine as  much as
our's.

     The only thing I'm disappointed about is I haven't gotten any mail for
this  column.  I really hope you people don't make me write this whole page
by myself!   As much  as I wish  I could fill  this page with  poetic prose
every month, that just ain't gonna happen.  What's  on your mind?  The only
programmers I know all  live in Washington, D.C. (Official  driving slogan:
"Death before yielding"), and here everyone is a government contractor, and
there's only so much you can talk about with a contractor before things get
really  dull.   What are  programmers doing  in, say,  California?   Texas?
Europe?  I know you people have something on your mind and you're thinking,
"If only  there  was some  sort of  internationally distributed  electronic
forum  for sharing  my most personal  thoughts with  people who  will write
about me  in their  local newspapers  and ban me  from ever  visiting their
country..."  Well, wonder  no more, because now you have  your chance.  You
can get  your 15 minutes of fame  simply by writing anything  (and I really
mean ANYTHING [He means within reason -Pete])  that both piques my interest
and,  most importantly, means I don't have to write as much.  What could be
simpler?

     While  I'm thinking about it, I want  to thank the hard-working sysops
on CompuServe,  and especially  in the  WINSDK forum.   I've  flooded these
people with questions lately and they've been great, and I really hope they
don't mind  if I  use their answers  in future  WPJ articles (ha!  ha! just
kidding!).  Seriously, these people really know their stuff and will answer
any question,  no matter how inane  (take it from someone  who's asked more
than  one inane  question).   An "Honorable  Mention" goes  to sysop  Tammy
Steele for  her wealth of  knowledge and great attitude.   Stop by  the WPJ
offices anytime to pick up your official WPJ t-shirt, Tammy.

     I'm out of room and out of time.  Hope to hear from ya'll soon.



















                         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 (Pete)

GEnie: P.DAVIS5 (Pete)

CompuServe: 71141,2071 (Mike)

WPJ BBS (703) 503-3021 (Mike and Pete)

You can also send paper mail to:

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

     As soon as we replace the hard drive, 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, soon you can expect it to
go up to 14,400. You can also expect to see a Fido-net node address  in the
near future..

     In  future issues  we will  be posting  addresses of  contributors and
columnists who don't mind you knowing their addresses. We will also contact
any  writers from the  first two  issues and  see if  they want  their mail
addresses made  available for you  to respond to  them. For now,  send your
comments to us and we'll forward them.































