





              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 07
          and Mike Wallace                                          Aug 93
          ----------------------------------------------------------------
          A monthly  forum for  novice-advanced programmers to  share ideas
          and concepts  about programming in the  Windows (tm) environment.
          Each  issue is uploaded  to the info systems  listed below on the
          first of the month, but made available at the convenience  of the
          sysops, so allow for a couple of days.

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

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

          CompuServe: 71141,2071 (Mike)

          GEnie: P.DAVIS5

          or you can send paper mail to:

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

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

          The WPJ BBS can be reached at: (703) 503-3021.

          The WPJ  BBS  is currently  2400 Baud  (8N1). We'll  be going  to
          14,400 in the near future, we hope.

















                                     LEGAL STUFF

          - 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.

          - Other  trademarks mentioned herein  are the  property of  their
          respective owners.

          - WPJ is available from the WINSDK, WINADV and MSWIN32  forums on
          CompuServe, and the IBMPC, WINDOWS  and BORLAND forums on  Genie.
          It  is  also  available  on  America  Online  in  the Programming
          library.  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 it 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  Publishers, Peter  Davis and
          Michael  Wallace,   and  only  then  after   they  have  obtained
          permission from the individual authors.


























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

          Letters ...................................     6 Readers

          Beginner's Column .........................     7 Dave Campbell

          Window's Programmer's Guide to Serial......    17 David Falconer

          Pascal in 21 Steps ........................    22 Bill Lenson

          Hacker's Gash .............................    35 Dennis Chuah

          ObjectWindows How-To ......................    41 Rodney Brown

          Creating Help Files .......................    43 Todd Snoddy

          GDI See GDI Do ............................    48 Bernard Andrys

          Windows++ .................................    57 Philip Sloss

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

          Last Page .................................    63 Mike Wallace


          Windows Programmer's Journal Staff:

          Publishers ......................... Pete Davis and Mike Wallace
          Editor-in-Chief .................... Pete Davis
          Managing Editor .................... Mike Wallace
          Contributing Editor ................ Dave Campbell
          Contributing Editor ................ Bill Lenson
          Contributing Editor ................ Dennis Chuah
          Contributing Editor ................ Mike Strock

          Contributing Writer ................ Rodney Brown
          Contributing Writer ................ Todd Snoddy
          Contributing Writer ................ Bernard Andrys
          Contributing Writer ................ David Falconer
          Contributing Writer ................ Philip Sloss












                                       WPJ.INI
                                    By Pete Davis

               Another month, another  issue. We  didn't do  an issue  last
          month because we didn't have enough articles early enough, but it
          gave us a chance to collect a lot of articles for this issue plus
          a few for  next month's issue.  That should give  us a good  head
          start.

               This month you'll notice a survey accompanying the magazine.
          We're considering putting the magazine in print. Through the help
          of  a publishing company, this  may very well  happen. That would
          mean some major  changes which I  want to get  out into the  open
          right away.

               First of all, yes, the magazine would cost money. What would
          that money get you? It would get  you 12 issues a year of a great
          magazine. Mike and I would be doing this for a living. That means
          that the articles  would undergo serious  editing, code and  text
          would  be checked and double-checked. We'd have time to make sure
          everything is right.  At the moment,  Mike and  I are doing  this
          part time and can barely  afford to spend more than a few hours a
          month to work on the magazine.

               In our current form,  it's almost impossible to do  any real
          editing.  Why?  Well, we  can't pay  the  authors, and  it's hard
          enough  to get articles. If we made it difficult, people wouldn't
          write for us.  Paying the authors  would fix that.  We'd also  be
          able  to  get  some of  the  big  names  out there,  like  Andrew
          Schulman, Matt Pietrek, etc.

               What wouldn't change? One  of our hottest areas is  help for
          beginners.  As long  as  I ever  have  anything to  do with  this
          magazine,  that won't  change. We  will always  be a  place where
          beginners can  turn for information  and help. We'd  also provide
          the  more advanced articles  that we've  been providing  over the
          past 6 issues. 

               Going into print would also allow us to reach a much broader
          audience than we reach now. We'd be able to get to the people who
          can't or haven't found us online.

               People  who subscribe prior to  the first printed issue will
          get a discount of about 25% off the regular  subscription rate of
          around $25.  These numbers might change since we're still working
          out the details.

               We're hoping  you will all  go for  this. In all  honesty, I
          don't  know how long  the magazine would  be able  to survive for
          free. Mike  and I  both do  a several things  for a  living. That

                                        - 4 -









          doesn't leave much time  to work on  the magazine and things  are
          only getting worse. If we could make our living off the magazine,
          we  could devote all of  our time to it, which  we'd both like to
          do.

                Anyway, fill out  the survey and  send it to  my userid  on
          CompuServe, the Internet, or via regular mail. Next month we will
          draw a name  from all the people  who responded. The  winner will
          get a choice between:

           - The "Win32 Reference" manuals (a 5-book set)

           - A combo of  the "Windows API Bible", "Windows  Internals", and
          "Undocumented Windows"

           - The Windows NT Resource Kit


               Send the response to me at:

          CompuServe: 71644,3570
          Internet: 71644.3570@compuserve.com

          or regular mail to:

          WPJ Survey
          9436 Mirror Pond Dr.
          Fairfax, Va. 22032  U.S.A.

               We look forward to getting your responses. 

               Peace.

           
             _Pete Davis
















                                        - 5 -










                                       Letters

          Date:  22-Jun-93 09:10 EDT
          From:  Scott Guthrie [100060,471]
          Subj:  Install Program Prob with In use DLL's

          Mike and Pete,

               I  just today downloaded issues  2-5 of your  Journal, and I
          must  say I'm impressed.  Unfortunately, you seem to have ditched
          the Install program for  a  variety of reasons, only one of which
          I  may  know the  answer to.    Microsoft provides  an exportable
          function   in  the   USER.EXE  module   of  Windows   3.1  called
          ExitWindowsExec which  will exit  Windows and run  the executable
          indicated  in the  call and  then  (when the  executable releases
          control of the  processor) RESTARTS Windows.   The executable  it
          runs can  include up  to a 128  byte Path and  file name,  and an
          additional  128   bytes  of  parameters,  switches,   etc.    The
          documentation  I have  read for  this function  says that  it was
          included  in  Win3.1  precisely  for  the  use  of  SETUP/INSTALL
          programs to use when  they need to modify code that  is currently
          in  use by Windows (e.g., DLLs).   Sorry I wasn't quicker off the
          mark on this, but I'm not even sure it is going to help you, as I
          haven't been able to get it to work precisely as advertised.

                                        Cheers,
                                             Scott Guthrie
























                                        - 6 -










                                  Beginner's Column
                                   By Dave Campbell


               Let's see, I know I've got  some code here that will show me
          how
          to put a dialog box into a DLL...no, not that file. Ok, ok, unzip
          that entire  disk with a -v  option into a file,  and just search
          the thing. Oh, no! Guess I must have dumped it.

               I sure hate it when  I do that, don't you? Me too.  And this
          month,  since I want  to follow up  on my promise  of putting the
          file open  dialog box  into a DLL,  I had  to redo  it. But  that
          wasn't all bad, since I'm going to explain it anyway.

               The  end result of  this month's column is  going to be code
          that runs identical to  that of last month, the  difference being
          that some  of the code  no longer resides  in the executable.  To
          accomplish this,  we are  going to  pull some  of  the code  from
          Hello.EXE and put  it into  a dynamic link  library (DLL)  called
          FileO.DLL. That's all there is to it. Now for next month...


          DLL short-course
                          
               DLLs  many times  are very  complex pieces  of code,  and by
          their very nature are reasonably tricky to program. That does not
          mean we should be afraid to make use of  the power offered to us.
          We just need to be careful when using them, and follow the rules.

               Most all of  us are  familiar with ".LIB"  files. These  are
          very much like a collection of  ".OBJ" files that we can pull out
          during the  building of our  file, and save  having to  write the
          code again. These  LIBs may  be locally built,  and contain  code
          personally  written,  or  may  be  third-party libraries  costing
          hundreds  of dollars.  In  either case,  the  code from  the  LIB
          becomes part  of your EXE file  after the build is  completed. If
          you use the LIB for three different modules, you will have pieces
          of that  LIB file in all three of your executables. That takes up
          space on your hard disk, and also in memory at execution time.

               Execution time? Well,  maybe not in DOS, but what  if we had
          written three TSRs and used a third-party library for some of the
          functionality, and then loaded all three? It would be possible to
          have, at run-time, three exact copies of the same code in memory.
          Kinda wasteful, huh?

               I hope I'm not boring everyone, I'm simply trying to set the
          stage for  the  power of  a  DLL. DLL  stands for  "Dynamic  Link
          Library", and  as  the  name  implies, the  linking  takes  place

                                        - 7 -










          dynamically,  or at run-time. In  our TSR example  above, if DLLs
          were  available to  us in  the DOS  world, only  one copy  of the
          common code  would have  been needed,  thereby saving  disk space
          because the EXE files would be smaller, and saving memory at run-
          time because the common code would only be loaded once.

               That's  exactly what we get  with DLLs in Microsoft Windows.
          When a call is made to a function in a DLL, Windows executes  the
          function as if  the function  were local to  the window  running.
          The previous sentence  is literally  correct, and is  one of  the
          sticky parts of programming DLLs.


          DS != SS
                  
               I have no intention of  digging into this at the depth  that
          is available in much of the literature,  but I am going to try to
          give an  explanation of what  DS !=  SS means, since  it is  used
          quite often. The  primary thing to remember  is that DLLs  do not
          have their  own stacks. The calling application's stack gets used
          during  execution  of  the DLL.  This  is  a  problem because  of
          near/far  references to  data. In  Windows programming,  all near
          pointers are assumed to  be DS-relative. To avoid a  problem with
          this,  either explicitly declare pointers to be FAR, or cast them
          that way as they are used.


          Hello.C
                 
               First let's take a look at Hello.C. There's been quite a bit
          of code removed,  and a little  added in. I  want to discuss  the
          additions first.

               In the include  section of  Hello.C, a #include  of the  new
          "fileo.h" was  added. This is necessary  because some definitions
          that were in Hello.H  are now residing in  FileO.H, and our  file
          needs information about it. Almost any DLL that you will be using
          from a third-party vendor will have a DLL  included that you will
          have to  link with. Normally the DLL  will have the prototypes of
          the functions to call, and any data definitions, or messages that
          could be passed.

               Next  in the global definition area, we define a HANDLE type
          named "hFileo". This will be used to identify the DLL after it is
          loaded by our program.

          HANDLE hFileo;

               Next, a  prototype was added for  "DoFileOpenDlg". This will
          be the launch point to get into the DLL to use the dialog  box we

                                        - 8 -










          created two months ago:

          void DoFileOpenDlg(void);

               WinMain now contains the following code:

          hFileo = LoadLibrary("FILEO.DLL");
          if (hFileo < 32)
             {
             FreeLibrary(hFileo);
             MessageBox(GetFocus(),"Dynamic Link Library FILEO.DLL must be
                        present", szAppName, MB_ICONEXCLAMATION |MB_OK);
             return 0;
             }

               This  is the code that loads (possibly) the DLL into memory.
          I say possibly because  if Windows finds the DLL  already loaded,
          the currently loaded  copy is  used. If the  load is  successful,
          LoadLibrary will return a value greater than or equal to 32. This
          magic  number is HINSTANCE_ERROR, and any return value of this or
          lower is  an error. On error,  we report the reason  to the user,
          and exit.

               Before we  exit our WinMain, we must free up the DLL. We are
          only concerned with cleaning up after ourselves. Windows will not
          allow the DLL  to be removed if others are  using it. That's what
          makes the system so nice to use:

          FreeLibrary(hFileo);

               WndProc is clean until we get to "case IDM_FILEOPEN":

          case IDM_FILEOPEN :
               DoFileOpenDlg();
               lstrcpy(OutMsg, szFileName);
               break;

               Instead  of calling the dialog box procedure as we have done
          in the  past, we are now  calling a local procedure  that will do
          that work  for us.  The code  could  have been  inserted at  this
          point, but for  ease of reading, and comparison, it is cleaner to
          have it be isolated.

               A  change has been made in  the reporting of the filename in
          that  it  is  transfered  locally  through  the  global  variable
          "szFileName". That will become clear shortly:


          DoFileOpenDlg
                       

                                        - 9 -










               This procedure is new to Hello, and as I said  above, is the
          launcher for the  DLL function.  The mystery takes  place in  the
          first variable declared:

          FARPROC lpfnFileOpenDlgProc = 
                                GetProcAddress(hFileo,"FileOpenDlgProc");

               This  declares a far pointer  to a function  inside the DLL.
          GetProcAddress retrieves that pointer for us by  name, given that
          we know  the handle for the  DLL. We know that  because we loaded
          it, "hFileo".  We also know the  function name "FileOpenDlgProc",
          because we wrote that function two months ago. It just happens to
          be  external  to  our program  at  this  point.  To execute  that
          function, we do the following:

          (*lpfnFileOpenDlgProc)();

               The  file name selected  will be passed  back via Hello.INI,
          and we retrieve that into szFileName, to be used above:

          GetPrivateProfileString("FileO", "FileName",
                                  "NoName", szFileName, 128, "Hello.ini");

               The remainder of  Hello.C is identical to the  previous code
          with the exception of the Fileo.C portions removed.


          Hello.DLG
                   
               Hello.DLG is now split  between Hello.DLG and Fileo.DLG, but
          nothing is added or removed, other than the split.


          Hello.H
                 
               Hello.H is split between Hello.H and Fileo.H.


          Hello.DEF
                   
               Hello.DEF  is identical to before with  the exception of the
          exported FileOpenDlgProc function being removed.


          FILEO
               
               Fileo is a simple  DLL and contains the primary  pieces that
          every DLL contains:

                                   LibMain and WEP

                                        - 10 -










               To simplify some of  our code, and avoid any  nastiness that
          may take  away from the simplicity, static variables were defined
          for  the filename and extension, and declared in the beginning of
          the Fileo code:

          static HANDLE hInst;
          static char szFileName[128];
          static char szFileSpec[16] = "*.EXE";
          static char szDefExt[5]    = "EXE";
          static WORD wFileAttr      = DDL_DRIVES | DDL_DIRECTORY;


          LibMain
                 
               The  LibMain function is called by LibEntry, which is called
          by  Windows when  the  DLL is  loaded.  The LibEntry  routine  is
          provided  in the  LIBENTRY.OBJ module.  LibEntry initializes  the
          DLL's heap (if a HEAPSIZE value is specified in the DLL's module-
          definition file) before calling the LibMain function.

               This simply unlocks  the data segment of  the library (which
          is locked by the LocalInit call in LIBENTRY) and returns 1.

          int FAR PASCAL LibMain (HANDLE hInstance, WORD wDataSeg, 
                                  WORD wHeapSize, LPSTR lpszCmdLine)
          {
          if (wHeapSize > 0)
             UnlockData(0);

          hInst = hInstance;

          return 1;
          }

               LibMain is  the place to  allocate any memory  necessary for
          use in the DLL, and to do any setup functions.


          WEP
             
               WEP  is  called by  Windows when  the  DLL is  released, and
          provides a place for us to  do cleanup before exiting. In Windows
          3.1, WEP  is no longer necessary,  but if we are  trying to write
          DLLS to be globally useful, WEP should be included.

          int FAR PASCAL WEP (int bSystemExit) {
          /*---------------------------------------------------------------
            get rid of things you allocated in the LibMain proc here
          ---------------------------------------------------------------*/


                                        - 11 -










          return TRUE;
          }  /* WEP */


               In the case of Fileo, WEP has no functionality.

          Fileo Code
                    
               The  code  body  for  Fileo consists  of  the  two functions
          "lstrchr"  and  "FileOpenDlgProc"  from  the  old  Hello.C  file.
          "lstrchr" has no changes at all, and was simply copied here.


          FileOpenDlgProc
                         
               This function  was stripped  straight from the  old Hello.C,
          modified slightly, and renamed  "DoFileOpenDlgProc". It no longer
          attempts  to open the file  selected, the name  is simply shipped
          back to Hello.C via an ini file, "Hello.INI"

               This is all accomplished  through the one exported function,
          "FileOpenDlgProc"


          FileOpenDlgProc
                         
               This function is small,  and consists of the lines  from the
          old Hello.C WndProc switch case:

          lpfnDoFileOpenDlgProc = 
                                 MakeProcInstance(DoFileOpenDlgProc,
          hInst);

          DialogBox(hInst, "FILEOPEN", GetFocus(), lpfnDoFileOpenDlgProc);
          FreeProcInstance(lpfnDoFileOpenDlgProc);

          followed by the Hello.INI write of the filename:

          WritePrivateProfileString("FileO",     "FileName",    szFileName,
          "Hello.ini");


          Fileo.DEF
                   
               The  DEF file will be recognizable, and has few changes from
          the  EXE DEF  file.  As  explained  above,  there  is  no  stack,
          therefore no  STACKSIZE. WEP  must be  exported,  and our  single
          exported function "FileOpenDlgProc" is there:

          LIBRARY     FileO

                                        - 12 -










          DESCRIPTION 'FileOpen DLL'

          EXETYPE     WINDOWS

          STUB        'WINSTUB.EXE'

          CODE        MOVEABLE PRELOAD
          DATA        MOVEABLE PRELOAD SINGLE

          HEAPSIZE    8192

          EXPORTS     WEP                 @1 RESIDENTNAME
                      FileOpenDlgProc


          Fileo.mak
                   
               The make  file  is cryptic  as ever,  but recognizable.  The
          changes are few, and easy to spot.

               Amazingly enough, that's all there is to writing and using a
          very simple DLL. I've glossed over many of the  nasties, and have
          purposefully avoided others.  The bottom  line is we  have a  DLL
          that's useable and easy to read.


          Make Files
                    
               I  am providing 3 make  files with this  code. HELLO.MAK and
          FILEO.MAK are the Borland make files for Hello.EXE and Fileo.DLL.
          MHELLO.MAK is the  Microsoft make  file for Hello.EXE.  Try as  I
          may, I could  not produce a working  make file for Microsoft  for
          FILEO.DLL. The  Hello.EXE that  I produce with  either make  file
          works with the Fileo.DLL I produce from Borland, but I ran out of
          ideas  trying to produce a make file for Microsoft for Fileo.DLL.
          So,  the proof is left to  the student. The first  one to send me
          one that works gets mentioned here next month.


          ICONS
               
               Did you  really think I was  going to leave and  not mention
          last  month's program?  Unfortunately,  I was so  late getting my
          article in that I ran the magazine late, and my "Go Suns" hit the
          streets after the  Bulls took the third  in a row.  Oh  well, the
          idea still stands. Animated icons is something we don't see a lot
          of in Microsoft Windows. Building all the icon images is probably
          the reason  why. I  was going  to take  a shot  at doing a  sweep
          second-hand  clock,  and  got bored  after  15  seconds worth  of
          images.

                                        - 13 -












                 
               The work for the  animated icons starts in WinMain,  where a
          timer
          is started:

          SetTimer(hWndMain, ID_TIMER, 500,
                      MakeProcInstance((FARPROC)TimerProc, hInst));

               Windows allows  up to 16  timers to be running  at any given
          time.   Normally, SetTimer would  be checked for  a return value,
          and if  the value  is  NULL, display  a  message about  too  many
          timers.

               The first  parameter  is  the handle  to  the  window  whose
          procedure will receive the WM_TIMER messages.

               The second parameter is  the timer ID, to identify  which of
          16 possibles you now have running.

               The third parameter is a word  specifying the timer interval
          in milliseconds (1-65535). In our case, this is 500 msec, or  1/2
          second.

               The fourth parameter is the instance handle of this window.


          InitInstance
                      
               Inside InitInstance, we now are loading an Icon, and this is
          the "WPJ" icon that will show  on the group screen, and for short
          periods of time when iconized:

          wc.hIcon          =  LoadIcon(hInstance, "WPJ");  /* Generic Icon
          */

          and this value is saved in a global:

          hIconMain = wc.hIcon;


          WndProc
                 
               The WM_PAINT message handler is  altered to handle the  icon
          painting:

             case WM_PAINT :
                if (IsIconic(hWnd))
                   {

                                        - 14 -










                   BeginPaint(hWnd, &ps);

          /*---------------------------------------------------------------
            Erase the background of the window with what's on the desktop.
            This is so the desktop bitmap will show through the transparent
            areas of the icon. 
          ---------------------------------------------------------------*/

                   DefWindowProc(hWnd,   WM_ICONERASEBKGND,   (WORD)ps.hdc,
          0L);

          /*---------------------------------------------------------------
            Now draw the icon. 
          ---------------------------------------------------------------*/
                   DrawIcon(ps.hdc, 0,0, hIcon);
                   EndPaint(hWnd, &ps);
                   }

               Notice that the icon  drawn is passed by the  generic handle
          "hIcon". This will  allow us to change the icon  image inside the
          Timer proc.

               One more thing needs to be done inside WndProc, and that  is
          how  to  handle  the  icon when  it  is  dragged  on the  screen.
          Fortunately,  Windows  sends  a  message  while  in  that  state,
          WM_QUERYDRAGICON:

             case WM_QUERYDRAGICON:
                return((LONG)(WORD)hIconMain);

               Consequently,  when our  WndProc receives  that message,  we
          return the default "WPJ" icon, for the duration of the drag.


          TimerProc
                   
               The only function our timer proc does in this application is
          toggle the two bitmaps GO.ICO and SUNS.ICO:

          BOOL FAR  PASCAL TimerProc(HWND hWnd, WORD  message, WORD wParam,
          LONG lParam)
          {
          static BOOL which = 0;

          if (IsIconic(hWnd))
             {
             if (which = !which)
                {
                hIcon = LoadIcon(hInst, "GO");
                InvalidateRect(hWnd, NULL, FALSE);

                                        - 15 -










                SendMessage(hWndMain, WM_PAINT, NULL, NULL);
                }
             else
                {
                hIcon = LoadIcon(hInst, "SUNS");
                InvalidateRect(hWnd, NULL, FALSE);
                SendMessage(hWndMain, WM_PAINT, NULL, NULL);
                }
             }
          }

               Depending on the entry value of the static variable "which",
          one  of the two icons is loaded,  and the entire window (the icon
          area)  is invalidated for painting, and a  message is sent to our
          own WndProc to execute  the WM_PAINT command, which we  know from
          above will repaint the icon.


          Why
             
               All of this is entertaining, sort of, but not useful. I have
          simply shown how  a timer works,  and tried to  take some of  the
          mystery out by doing something stupid.

               What  if,  instead of  painting icons  on  a timer,  we were
          painting windows? And, what if those windows were over the top of
          everything  else, so that on  a timer, the  screen would suddenly
          get painted over.  Why that  sounds like a  screen-saver!   Well,
          kinda-sorta. We wouldn't want to do  that on a hard timer, but it
          is close. Close enough that, given enough time, there will be the
          start of a series in the next issue called "Screen Savers Inside-
          Out". One more mystery unfurled.


          EndDialog
                   
               That's about  all there is  to say  about the code  for this
          month.   Unless  something changes,  I'm going to  discuss common
          dialogs and show how to do all this the easy way next time.  Feel
          free  to contact me in any of the ways below.  Thanks to those of
          you that have e-mailed me questions, keep them coming.  

          Dave Campbell 
             WynApse PO Box 86247 Phoenix, AZ 85080-6247 (602)863-0411    
             wynapse@indirect.com
             CIS: 72251,445
             Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum




                                        - 16 -










                                     Book Review
              Title: Windows Programmer's Guide to Serial Communications
                               Author: Timothy S. Monk
                              Publisher: SAMS Publishing
                                  By David Falconer

          Book Details:
          ISBN 0-672-30030-3
          Includes Software Disk.
          $39.95 USA

               I have been searching for ages for a book which would  teach
          me how to do Comms programming in Windows.  Judging by the amount
          of questions in the Borland Windows forum on Compuserve, I am not
          alone  in this quest.   The book  that seems to  be most commonly
          recommended  is Timothy  Monk's  "Windows Programmer's  Guide  to
          Serial Communications", so  I bought a  copy to see  what it  was
          like.

               Perhaps I should  explain a little about me, so  you have an
          idea of the role the book was intended to play.  I'm not a novice
          programmer,  but not that experienced either, and I'm very new to
          Windows programming.   Having worked  my way  through Petzold,  I
          decided I was ready to tackle Comms, which is what I wanted to do
          in the first place!   Also, I learn best by  trial and error, and
          was looking for  something to get me started and  that would also
          act as  a reference later  on.   I have not  started putting  the
          knowledge  I have  obtained from  this book  into practice  yet -
          priorities change - but I thought I would share what it's like as
          a primer.

               Firstly, this  is not a  primer for  Windows programming  in
          general.  As a novice,  I often found myself with Monk's  book in
          one hand  and Petzold  in the other,  but the  Monk does  provide
          little  snippets  of  basic  stuff that  Petzold  doesn't  cover;
          connecting an application to a help file, for example.  The other
          assumption  that is made is  that you have  some familiarity with
          DOS serial Comms - at least the terms used.

               The  book is laid out  in 7 chapters  and 3 appendices, over
          the  course of which you  develop a fully  working Comms program,
          called  TSMTERM, starting with the very basics and ending up with
          an XMODEM  file transfer  protocol implementation.   Each chapter
          starts with an  overview of  what will be  covered, and  finishes
          with  a  summary  of what  has  been achieved.    There  are code
          segments  everywhere, and these are  as much an  integral part of
          the text  as the writing  between them is;  often it is  from the
          code  that  you  find  exactly  how  a  particular  function,  or
          technique, is implemented.  Fortunately all  the code, plus fully
          compiled executables are provided  on the accomanying disk, which

                                        - 17 -










          saves on  a lot  of  typing!   Each time  the  code is  modified,
          advanced upon in the text, a completely new set of source code is
          provided on the disk.   This means a hefty 3 Megabytes  of memory
          is needed for the files, but it saves getting confused over which
          version of which bit of the program you should be working with at
          any one stage.  The areas that the chapters cover are:

          Chapter 1: Serial Communications

               This   chapter  contains   an  overview   of  serial   Comms
          procedures, starting  with the hardware;  the RS-232 link,  the 3
          UARTS commonly found on  the PC (8250/16450 and the  newer 16550)
          in  quite a  bit of detail  and finally  the COM  ports and their
          adresses  and interrupts.    Monk then  goes  on to  discuss  the
          principles  of   DOS  Comms  programming,  with   code  segments,
          including a look at ring buffers.  The final part  of the chapter
          discusses what is going to happen in the rest of the book, by way
          of a "design brief" for the TSMTERM program.

          Chapter 2: Windows Communications Basics.

               This is basically in two major sections.  In the first, Monk
          outlines  the 17  functions  of the  Windows Communications  API,
          which are fully documented in Appendix A, and shows how these can
          be used in  a typical  Comms session of  open port,  send/receive
          characters, close  port.  These  initial examples use  polling of
          the port in the main  message loop of the Windows application  as
          the  method  of  getting  information  from  the  port  into  the
          application.   Message-based methods, which were  introduced with
          Windows 3.1, crop up later.   In the second half of  the chapter,
          Monk creates  his own API  for use  with the TSMTERM  program, in
          order to simplify some  of the trickier aspects of using  the raw
          function calls.   These are then all encapsulated in a DLL.  This
          is done very matter-of-factly,  but the code for the  LibMain and
          WEP functions are provided and briefly explained.

          Chapter 3: Terminal Emulation

               Again,  this chapter  is in  two sections.   The  first part
          covers terminal emulations,  including the full specification  of
          an ANSI terminal,  which is then implemented in a  DLL.  There is
          also  a word about finite state machines, on which principles the
          ANSI emulation is based.   The second part starts  assembling the
          application from the  components created so far.   The processing
          of  the  basic Windows  messages is  covered,  as is  the Windows
          procedure, although this is of quite a complex variety,  covering
          menu commands  as well  as the  more  straight forward  messages.
          Knowledge  of Dialog Box methods are assumed, but I learned quite
          a lot about their implementation from studying the code.  This is
          a fully fledged application,  and so includes an "about"  box and

                                        - 18 -










          interfaces  to  a  basic  help  file.    As  well  as  the   ANSI
          implementation, the  program also  allows the  user  to choose  a
          basic TTY emulation.

          Chapter 4: Errors, Events, and Flow Control

               The  good practice  of calling  GetCommError( )  after every
          read, write or  port poll is introduced  and TSMCOMM.DLL, created
          in chapter 2, is modified to include error processing.  A similar
          process is then gone through for communications events using  the
          GetCommEventMask(  ) function  and  its associates.   After  both
          modifications to the  DLL, the main application  is also modified
          to give  the user a choice  of how to monitor  errors and events.
          Finally there is a brief discussion of XON/XOFF and hardware flow
          control,  after  which both  methods  are  added to  TSMCOMM.DLL.
          Again the main application is modified to give  the user a choice
          of what to use.

          Chapter 5: Message-Based Communications

               In     Windows     3.1     Microsoft      introduced     the
          EnableCommNotification( )  function which  adds a new  message to
          the  Windows  system.   This  is  as  close as  Windows  gets  to
          interrupt driven  communications procedures, as the  Comms system
          is  interacted with in response to a received message rather than
          having to  be polled  in the  message loop.   Chapter 5  gives an
          overview of how this system  works and then adds the facility  to
          TSMCOMM.DLL, and modifies  the application to  give the user  the
          choice of system.

          Chapter 6: Modem Communications

               Chapter 6 starts with a look at where modems fit into serial
          communications systems.  The command set for Hayes modems is then
          examined  and a  modem  API is  implemented  in MODEM.DLL,  which
          includes setup,  dial  and hangup  routines.   A  modem  commands
          section is then  added to the main application.   As an extention
          of this, a dialing  directory is implemented, where the  user can
          store  the names of systems,  their phone numbers,  plus the port
          settings: Baud  rate, start, stop  and data bits.   This too,  is
          then added to the main program.

          Chapter 7: File Transfer

               To  enable the TSMTERM  program to  download files  from the
          bulletin  boards whose  numbers are stored  in the  newly created
          address  book,  Monk  adds   the  popular  XMODEM  file  transfer
          protocol.   The chapter starts with a discussion of the protocol;
          the  packet, error checking,  transmission, reception, errors and
          timeouts.  The protocol  is then implemented in another  DLL, and

                                        - 19 -










          has  options for using checksum  or CRC error  correction.  These
          functions are then added to  the main program.  Selection  of the
          file for transmission is  carried out by use of the Common Dialog
          Box "Open File",  so use of  this feature of  Windows 3.1 can  be
          followed by examining the source code.

          Appendix A: Windows Serial Communications API Reference

               As mentioned  above, this provides the  documentaion for the
          functions and  structures provided by Windows  for communications
          systems.   It includes the Windows 3.1 amendments and marks where
          the Window 3.1 implementation is different from 3.0.

          Appendix B: TSM Communications API Reference.

               This  provides a  full function  by function  description of
          Monk's own API, as used in the TSMTERM program.  It describes the
          functions created  throughout the book which  are in TSMCOMM.DLL,
          MODEM.DLL and XMODEM.DLL.   It is a useful summary  and reference
          section.

          Appendix C: ASCII Character reference.

               This is  a table in two  parts.  Part one  gives the decimal
          value, hex value,  display character and  description for all  of
          the 7  bit basic ASCII  characters.   Part two provides  the same
          information for the extra members of the extended PC set.

               I found the book helpful and  easy to follow.  The layout is
          a  bit strange, with funny bits of ornamentation around the edges
          of  the  pages, but  you  soon get  used  to it.    It  goes from
          communications basics  to quite an  advanced program in  only 413
          pages  (including the  appendices) so  it obviously  doesn't hang
          around  when  explaining  things to  make  sure  you  have got  a
          particular point.   But that's the nice thing about books; if you
          find you have missed  something, you can always  go back and  re-
          examine it.

               As a  practical introduction  to  Windows Communications,  I
          would heartily reccommend this book.  There may be others that do
          the job too, but if there are I haven't found them and what I see
          here, I like.

               I  confess that I haven't used the program, TSMTERM, and nor
          am I  likely to;  that's not  why I  bought the book.   I  wanted
          something that dissected a Windows Comms program, so I would know
          how to do it for myself, and that's what I seem to have got.   As
          I  mentioned at  the  outset,  my  own  project  has  been  "back
          burnered"  for a while,  but I have no  qualms about tackling the
          Comms aspect head on.

                                        - 20 -










               Dialog  boxes are another matter  though.  Ah  well, back to
          Petzold...

               The author can be reached on CompuServe at 100063,1205.















































                                        - 21 -










                                  Pascal in 21 Steps
                  (A Beginner's Column for Turbo Pascal for Windows)
                                    By Bill Lenson


                            Step Two - Divide and Conquer

          REVIEW

               Last  month we  talked about  how to  write a  simple Pascal
          program.  We showed you what variables and commands are.  We also
          covered basic data types  like integers, characters, and strings.
          Even  though  the  examples  where  quite simple  and  didn't  do
          anything  practical, the purpose of that  column was to introduce
          the basic program structure.

               This month we pick  up the pace quite a bit.   By the end of
          this column you should  be able to read input  from the keyboard,
          decide if the input is valid,  repeat actions over and over,  and
          break your code up  into chunks called functions and  procedures.
          All  this  and  we'll  even  show  you  how  to  write  a  simple
          calculator.


          KEYBOARD IN / SCREEN OUT

               Reading information from the keyboard is not that difficult.
          There  are some  tricks to it  though to  make your  life easier.
          Last  month you used the 'writeln' statement to write text to the
          screen.  To read text you use 'readln'.

               Readln (pronounced  'read line')  pauses  execution of  your
          program until you type something and press the <Enter>  key.  For
          example,

                                      Readln(s);

          lets you  type in some text  and when you press  <Enter>, puts it
          into the variable s.  s can be any data type  but some are better
          than others.  If  the s 'parameter' to the  readln 'procedure' is
          an integer then you are only allowed to enter numbers.  If it's a
          string type you  can enter anything. When I say  'only allowed to
          enter a number', I mean that you can type in  non-numbers but the
          program will crash  when you press <Enter>.  This  is bad. Let me
          illustrate.  Type in the following program.

          program Bad_Code;
          uses WINCRT;
          var
              num : integer;

                                        - 22 -










          begin
              readln(num);
              writeln(num);
          end.

               When you  run this program a window  will be created and the
          cursor  will flash.   Type  in the number  23 and  press <Enter>.
          Sure  enough, 23  gets  assigned to  the  num variable  and  gets
          displayed in  the  window by  the writeln(num)  statement.   Now,
          rerun the program  but type in Hello  and press <Enter>.   CRASH.
          Pascal tries to convert Hello into  an integer so it can store it
          into the num variable.   Since it doesn't know how  to do this it
          bombs.   It's a  poor  program that  lets the  user  crash it  so
          easily.   Try to make the  next program blow  up.  Bet  you can't
          (poor bet, there is a way but I'm not going to tell you how until
          next month).

          program Better_Code;
          uses WINCRT;
          var
              numstr : string;
          begin
              write('Please type a number and press <Enter> : ');
              readln(numstr);
              write('The number you typed was : ');
              writeln(numstr);
          end.

               No  matter what you type  in the program  spits it back onto
          the  screen.    The  only  thing limiting  in  this  code  is the
          programmer has no way to control what the user types.   You can't
          be sure the user types a number in the above example.  We'll show
          you how to do that in the next section.

          DECISIONS, DECISIONS

               Quite  often you  want  a program  to do  one  thing when  a
          certain  input is  typed in  and do  something else  when another
          thing is entered.   The most common way  to do this in  Pascal is
          the IF statement.

               Before I  show you the IF  statement, let me first  show you
          how  you can convert a number stored  as a string into an integer
          data type.   Why we  need to do  this will become  clear shortly.
          Try the following code.

          program String_2_Number;
          uses WINCRT;
          var
              numstr : string;

                                        - 23 -










              num    : integer;
              errcod : integer;
          begin
              write('Please type a number and press <Enter> : ');
              readln(numstr);
              val(numstr, num, errcod);
              writeln('The number you typed was : ', num);
                  { Notice  we combined  two write  statements into  one by
          passing }
                  { two parameters separated by a comma.                   
             } end.


               This  program is  similar to  those above  but if  you don't
          enter a  number a zero is  printed instead of what  you typed in.
          The val procedure tries to convert a string into a number, and if
          it can't it puts a zero in  num and a number greater than zero in
          the errcod parameter.

               Another thing to note  about the above program is  the stuff
          enclosed in { and }.  These are comments and allow the programmer
          to  describe what is happening in  the code.  All programs should
          have  comments that let other programmers (or yourself) look at a
          program and tell what the  code does.  You can put anything  in a
          comment as long as  it starts with a { and ends with  a }.  As an
          aside, sometimes  you'll see older Pascal  programs with comments
          that start  with a (* and  end in a *).   These work  too but the
          convention these days is to use the braces.

               I've  been talking for a while about numbers and strings and
          how  we want  a number but  we need  to enter  a string  and then
          convert it to a  number. What's all the hubbub about  numbers and
          strings?  Why not just  leave them as strings?  The  answer is in
          the operations you can do to different data types in Pascal.  For
          instance, you can't add two numbers together if they're stored in
          a  string.  Also, you can't concatenate  (stick one string on the
          end of another) two numbers together if they're stored in integer
          types.   Pascal is  a typed language meaning  that data is always
          stored in  variables of a certain  type.  Each type  has it's own
          set of built-in  operations.   Some string  operations convert  a
          string to  upper  case  letters  from lower  case,  extract  some
          characters from  the middle of  a string,  convert a string  to a
          number, and so on.  Most integer functions are math based such as
          adding  two numbers,  subtracting  two numbers,  multiplying  two
          numbers, and so on.

               This  section is  about Pascal  decision making  and program
          flow  control using  the  IF statement  so  let's give  a  simple
          example.


                                        - 24 -










          program Better_String_2_Number;
          uses WINCRT;
          var
              numstr : string;
              num    : integer;
              errcod : integer;
          begin
              write('Please type a number and press <Enter> : ');
              readln(numstr);
              val(numstr, num, errcod);
              if (errcod <> 0) then
                  writeln('ERROR: The number you entered was invalid.')
              else
                  writeln('The number you typed was : ', num);
          end.


               The IF statement needs only a little explanation.  First the
          '<>'  in  Pascal  means  'not  equal to'.    Also,  there  are no
          semicolon  (;)  before  else's  since  the  whole  if..then..else
          combination makes  a complete  statement and  last month  we said
          that semicolons only come at the end of a statement  (ugh!).  So,
          the above is  described as, 'If errcod is not  equal to zero then
          write  an  error message  else write  the  number entered  to the
          window'.

               In  the above,  the  stuff  (I  didn't  say  this  was  fine
          literature)  between  the   IF  and  the   THEN  is  called   the
          'condition'.  Conditions are  logical statements where we compare
          things.  The things  we compare are usually either  two variables
          or a variable  and a value  like we do  in the above code.  Let's
          assume we have two variables var1 and var2.  Some simple 'logical
          operations' we can do are:

          Logical Operation         Tests if...
          =================         =====================================
          (var1 <> var2)       ==>  var1 not equal to var2
          (var1 = var2)        ==>  var1 equals var2
          (var1 > var2)        ==>  var1 is greater than var2
          (var1 >= var2)       ==>  var1 is greater than or equal to var2
          (var1 < var2)        ==>  var1 is less than var2
          (var1 <= var2)       ==>  var1 is less than or equal to var2

               We'll use  logical operations with IF  statements many times
          in the  future so don't worry if they look a little strange right
          now.  Let's now move  on to see how we can  repeat something over
          and over.


          LOOPS

                                        - 25 -










               The  process  of repeating  something  in  Pascal is  called
          looping.  There are four  ways to loop but  only two of them  are
          commonly used, one seldom used and one is absolutely forbidden to
          be used.   The last two  will be covered at  a later time.   This
          section presents the first two: the FOR and WHILE loops.

               The  FOR loop repeats some  block of code  a fixed number of
          times.  Let's give a simple example:

          program For_loop;
          uses WINCRT;
          var
              x : integer;
          begin
              for x := 1 to 50 do
                  write('Hello ');
          end.

               This program writes 50  'Hello''s on the screen.   It's much
          simpler than typing out  50 write statements.  The  FOR statement
          is read  'for x equals  one to fifty  do write hello'.   In other
          words,  x is  assigned  the number  one.   The next  statement is
          executed (the write).   x is increased by one  and checked to see
          if it's greater than 50.  If it is, the FOR statement is finished
          and the statement after the write is executed.  If  it isn't, the
          write is executed  and then x is increased by  one and checked to
          see if  it's greater  than 50.   And so  on.   In other words  we
          repeat the write 50 times while  we increase x from 1 to 50.   On
          the 51st loop, the FOR is exited.

               Let's try another.

          program For_loop_2;
          uses WINCRT;
          var
              x : integer;
          begin
              for x := 1 to 10 do
                  writeln(x);
          end.

               This example loops  10 times  and writes the  contents of  x
          each time through the loop.  In  other words, the numbers 1 to 10
          are written on the screen. The starting number doesn't have to be
          1, we could have said:

              for x := 5 to 15 do
                  writeln(x);

          which would write the 10 numbers from 5 to 15 on the screen.

                                        - 26 -










               The WHILE loop  is a  little different.   WHILE will  repeat
          until some condition is met.  For example:


          program While_loop;
          uses WINCRT;
          var
              x : integer;
          begin
              x := 1;
              while (x <= 10) do begin
                  writeln(x);
                  x := x + 1;
              end;
          end.

               This program  acts just  like the For_loop_2  program above.
          In  it we assign the value one to  the x variable.  Next, while x
          is less than or equal to the value ten (it starts at one so it is
          less  than 10)  repeat  everything  between  the  begin  and  end
          statement.   What's between the begin and end is the meat of this
          WHILE loop.  In it we write the x variable to the screen and then
          we add one to x.  That adding one to x looks a little funny.   We
          say 'x is assigned  the value of x plus one.   In other words, we
          do the stuff on the right of the ':=' and then  put the result in
          the variable on the left of the ':='.  If we said 'x := x + 2' we
          would see every other number from 1 to 10 (i.e., 1, 3, 5, 7, 9).

               FOR  loops are often used  when we know  in advance how many
          times we  will be looping.   WHILE loops, on the  other hand, are
          used  when we  don't know how  many times  we'll be  looping.  In
          common programming practice, we would typically use FOR  loops to
          initialize array variables (a  future topic), or repeat something
          that never changes in the number of iterations.  WHILE loops  are
          commonly  used  for  reading input  from  users  or  files.   For
          example,  reading keyboard input  until the user  types some exit
          command the  program knows about.  We'll  illustrate each looping
          technique in more detail next month.


          HINDSIGHT is 20-20 in PASCAL

               Before  we dive  into a  larger program,  I thought  I would
          point  something  out  about  Pascal that  beginners  must  know.
          Statements in Pascal cannot see things written  after the current
          line.   On  the flip side  of the  coin, statements  can only see
          things in the code  that occur on lines  previous to the  current
          one.  In  other words, when the compiler compiles  your code into
          machine language, it starts at the top and remembers each line as
          it comes across it.  This is while variables are  declared BEFORE

                                        - 27 -










          they  are  used. In  the future  you'll  see that  procedures and
          functions must be made before they are used.  As an example:

          var
              x : integer;
          begin
              x := 3;
              y := 27;
          ...

               The x:=3 works  because x  has been declared  as an  integer
          before it was used.  The y:=27 causes  a compile error because  y
          has not been declared yet.  It may be declared some time later in
          the program but that would be too late.

               Why I'm bringing this up now is it should help  a little bit
          when we take  a look at procedures and functions.   For now, just
          declare variables in the var section before you use them in code.


          THE CALCULATOR - ATTEMPT #1

               Let's  take a little break from learning the language to try
          to apply what we've  learned up until  now.  The  best way to  do
          that is by writing an example program.  From past experience, the
          quickest  way to  learn  a language  (or a  new  language) is  by
          writing  example programs.  You  must type these  programs in and
          test them for yourselves for maximum learning benefit.

               In this section  we'll try to build a simple calculator.  It
          won't do a heck of a lot but I'm sure it  will make understanding
          of the language easier.   OK, so what's this  calculator supposed
          to do?  The first  thing is it should ask the user  for a number,
          an operation to  perform, and  then another number.   Once  these
          have  been entered,  the program will  spit out the  answer.  The
          operations  it can  perform  are addition  (+), subtraction  (-),
          multiplication (*  ), and division (/).   One catch to  watch out
          for is  division.  You  don't want the  user dividing by  zero as
          this  is an  error and  will cause  your program  to crash.   You
          therefore  need to print an error message yourself if they try to
          divide by zero.

               Overwhelmed?   Don't  worry.   There  are  ways to  look  at
          problems  and break them down into smaller problems that are more
          manageable.  Let me show you the program and I'll explain what it
          does.


          program Calculator_Number_1;
          uses WINCRT;

                                        - 28 -










          var
              numstr1   : string;
              numstr2   : string;
              operation : string;
              num1      : integer;
              num2      : integer;
              errcod    : integer;
          begin
              writeln('Calculator Example #1');
              writeln;
              write('Please type a number and press <Enter> : ');
              readln(numstr1);
              write('Please enter the operation  to perform (+, -, *,  /) :
          ');
              readln(operation);
              write('Please type a number and press <Enter> : ');
              readln(numstr2);
              val(numstr1, num1, errcod);
              val(numstr2, num2, errcod);
              if (operation = '+') then
                  writeln('Answer: ', num1+num2)
              else
                  if (operation = '-') then
                      writeln('Answer: ', num1-num2)
                  else
                      if (operation = '*') then
                          writeln('Answer: ', num1*num2)
                      else
                          if (operation = '/') and (num2 <> 0) then
                              writeln('Answer: ', num1 div num2)
                          else
                              writeln('Error in input.  Program ending.');
          end.


               You should be able  to read through this program if you take
          it slowly line by  line.  The  first thing we  do is declare  all
          necessary variables. Then we ask the user for  each number and an
          operation.  The user must press <Enter> after each input.   Next,
          we  convert the number strings to integers. Notice we don't check
          for an  error  in  converting  the number  strings,  numstr1  and
          numstr2.  We don't care what they enter.  If they enter something
          invalid  the integer  we get  from the  conversion is  just zero.
          It's left as an exercise for the reader to put in  checks to test
          for  invalid entries, report  the problem  and exit  the program.
          TIP: You might want to look up the  HALT procedure if you want to
          try this exercise.

               OK, after the numbers are converted we perform the series of
          IF  statement tests to perform the  appropriate operation.  Check

                                        - 29 -










          out the last test for division.  The condition statement in  that
          if has two conditions: (operation = '/') and (num2  <> 0).  If we
          were  to  read  the last  IF  statement,  it  would be  described
          something  like: 'if the operation is division and the num2 isn't
          0  then write the  answer, else write  an error  message'.  Words
          like  'and' which separate  conditions will be  discussed in more
          detail in upcoming months columns.

               The programs are starting to look a little messy and I'm not
          using any comments (a bad habit but it won't help you to learn if
          I  always tell you what I'm doing).   We need to tidy things up a
          bit.


          PROCEDURES

               A  typical Windows  program  can be  several thousand  lines
          long.  If we have one big mainline, things will get beyond messy.
          Can  you imagine  thousands of statements  between one  begin and
          end?  I  can't.  Programmers get around this  problem by breaking
          up the code  into chunks and giving a name to  each piece.  These
          'chunks' are called procedures and functions.

               Suppose  the mainline  of the  calculator program  above was
          written as:

          begin
              Display_Title;
              Get_Inputs;
              Convert_Strings_to_Numbers;
              Display_Calculations;
          end.

               Isn't this  a little more intuitive?   All we need  to do is
          tell  the program  what each of  these procedures does.   This is
          simple in this case.  We simply take the groups of code that goes
          with each procedure and presto.

               Here's the next calculator.  Notice it's a little bigger but
          it's  also broken up into nice manageable sections.  Also notice,
          the procedures  are written  after the variable  declarations but
          before  the mainline.   This  way, the  procedures can  'see' the
          variables because they're declare before it, and the mainline can
          'see' the procedures because they're declared before it.


          program Calculator_Number_1;
          uses WINCRT;
          var
              numstr1   : string;

                                        - 30 -










              numstr2   : string;
              operation : string;
              num1      : integer;
              num2      : integer;
              errcod    : integer;

              procedure Display_Title;
              begin
                  writeln('Calculator Example #1');
                  writeln;
              end;

              procedure Get_Inputs;
              begin
                  write('Please type a number and press <Enter> : ');
                  readln(numstr1);
                  write('Please enter the operation to perform (+, -, *, /)
          : ');
                  readln(operation);
                  write('Please type a number and press <Enter> : ');
                  readln(numstr2);
              end;

              procedure Convert_Strings_to_Numbers;
              begin
                  val(numstr1, num1, errcod);
                  val(numstr2, num2, errcod);
              end;

              procedure Display_Calculations;
              begin
                  if (operation = '+') then
                      writeln('Answer: ', num1+num2)
                  else
                      if (operation = '-') then
                          writeln('Answer: ', num1-num2)
                      else
                          if (operation = '*') then
                              writeln('Answer: ', num1*num2)
                          else
                              if (operation = '/') and (num2 <> 0) then
                                  writeln('Answer: ', num1 div num2)
                              else
                                  writeln('Error   in   input.      Program
          ending.');
              end;

          begin
              Display_Title;
              Get_Inputs;

                                        - 31 -










              Convert_Strings_to_Numbers;
              Display_Calculations;
          end.

               Voila!  Procedures are  just like a little program  within a
          program but  they don't get executed until you call them as we do
          in  the calculator  mainline. The  mainline is  always  the first
          thing   that  gets  called  in   a  program.     It  gets  called
          automatically when the program is started.   All other procedures
          and functions get  called from the mainline.   When looking at  a
          program for  the first time,  skip down to  the mainline  and see
          what  procedures are  called.   Some  may  be predefined  in  the
          language  such as  writeln and others  may be user  defined as in
          Display_Title.

               Usually  each procedure will have  a lot of  comments at the
          beginning of it.  Even though  they are often  small, it's  still
          best to  make the reader aware of what each procedure does.  It's
          also  good practice to put a ton  of comments at the beginning of
          the  program  to  describe  what  it  does  (a  sort  of  program
          overview).

          It's interesting  to  note  that  a procedure  can  call  another
          procedure.   Such  is the  case  in Display_Title  for  instance.
          Display_Title  calls the procedure writeln.  We can write our own
          procedures and have another one call  it as long as it's declared
          BEFORE  the one calling  it.  For instance,  we could have called
          Display_Title from Get_Inputs but it didn't seem logical to me to
          do that.  We could have though.  This chaining of procedures is a
          very powerful feature indeed.


          FUNCTIONS

               A function is almost exactly  the same as a procedure.   The
          only  difference  is  a  function 'returns'  a  result  whereas a
          procedure simply gets called and carries out it's instructions.

               What do I  mean, 'returns a  result'?  Well,  let's look  at
          math functions  such as square root  of a number, the  sine of an
          angle,  etc..   Then  there's string  functions  such as  get the
          string length, concatenate two strings together, etc..  There are
          conversion functions  such  as  convert a  string  to  a  number,
          convert  a number to a string,  etc..  Functions do something and
          then return some result.

               Function results have to  be of a data type such as integer,
          string, char, or any other  type.  One interesting characteristic
          of functions is they can be used in expressions.  Expressions are
          the  right side of assignments (:=) or parameters to functions or

                                        - 32 -










          procedures such as writeln.   Let's give a couple  examples using
          the SQRT (square root) function.

          x := SQRT(9);
              {calculate the square root of 9 and assign that value to x}

          x := SQRT(y);
              {calculate the square root of the contents of y and assign to
          x}

          writeln(SQRT(y));
              {write the square root of y to the screen}


               Some  functions can be very  simple (such as  add the number
          three to  a  variable and  return  the result),  or may  be  more
          complicated  (such as  a function  used to  calculate mortgages).
          Let's show how  to write one  of the simple  ones this month -  a
          function that simply returns the math number PI divided by  2.  I
          think you  should be getting the  jist of how to  write a program
          show I'll only show a function and how to call it.

          function PI_DIV_2 : integer;
          begin
             PI_DIV_2 := PI div 2;
          end;

          ...

          begin
             ...
             writeln(PI_DIV_2);
             ...
             x := PI_DIV_2 + 4;
             ...
          end.


               Instead  of procedure,  we start  a function  with the  word
          function.    Also,  we must  tell  what  type  of value  will  be
          returned.   That's the ': integer'  part of the header.   To tell
          the function to  return the desired value, we appear  to assign a
          variable  with  the same  name as  the  function with  the return
          result (in this case, the return result is 'PI div 2').  Once the
          function  is  defined,  you  can  use  it  any  way  you  would a
          predefined function.


          NEXT MONTH


                                        - 33 -










               To  wrap  up, functions  and  procedures  are very  powerful
          additions to the Pascal language.   We've touched on them  here a
          little  but you will see them over and over in the future and I'm
          sure you'll get very used to using them.

               Next month  I'll show how to pass  a parameter to a function
          you  define, just  like SQRT  takes one  parameter and  returns a
          result.   I'll  also  show more  data  types, arrays,  constants,
          introduce you  to  controlling the  compiler  in your  code,  and
          perhaps even how to write a simple game.  See you then!


               If you wish to contact me, please do so at  the following e-
          mail addresses:

          From            Send e-mail to
          ===========     ===============
          Compuserve:     >INTERNET:bill.lenson%canrem@uunet.ca
          Internet:       bill.lenson%canrem@uunet.ca
































                                        - 34 -










                                    Hacker's Gash 
                                   By Dennis Chuah

               This  article contains a few  of the tips,  tricks and traps
          from my Windows  Programming laboratory  book.  As  I mainly  use
          Borland  C++, most of the discussion here will be slightly biased
          to  Borland  C++.   However  some  issues  also  concern  Windows
          programming in general.

               It is  sad that the Windows API  documentation[1] leaves out
          certain bits  of information  that is  sometimes  crucial to  the
          correct usage  of the  API.   Take MakeProcInstance  for example.
          The  documentation  states this  function  must only  be  used to
          access  functions from  instances  of the  current module.   This
          implies that  MakeProcInstance will  create a  procedure instance
          given  a hInstance and an  exported procedure address provided it
          is  called from the task  that is associated  with the hInstance.
          This  is not always the case.  Take  a look at the following code
          extract: 

          Somewhere in the application ...

          void CALLBACK SomeProc (void);
          .
          .
          FARPROC lpfnSomeProc;
          lpfnSomeProc   =   MakeProcInstanceForMe  (hInstance,   (FARPROC)
          SomeProc);
          if (lpfnSomeProc == SomeProc) MessageBeep (0);

          And somewhere else in the application's DLL ...

          FARPROC  WINAPI  MakeProcInstanceForMe (HINSTANCE  hInst, FARPROC
          lpfnFarProc)   {return MakeProcInstance (hInst, lpfnFarProc);
           }

               MakeProcInstanceForMe  will return  the address  of SomeProc
          instead   of   the  procedure   instance.      This  is   because
          MakeProcInstance  will always  return the same  procedure address
          passed to it  when it is  called from a  DLL, regardless of  what
          hInstance it is passed, a point missed out in the documentation. 
          Note:  the documentation merely  states that  MakeProcInstance is
          not required for library modules.  Hence:

          Trap: Never  use MakeProcInstance to create  a procedure instance
          from  a DLL.  Always create the  procedure instance  first before
          passing it to a DLL.

          Tip: Use "smart  callbacks" prologue  and epilogue  code if  your
          compiler supports it.   This usually  assumes DS is equal  to SS.

                                        - 35 -










          For most applications this  is true, except  if you swap data  or
          stack    segments.    Callback procedures  compiled  with  "smart
          callbacks"  do not  need  procedure instances  to  bind the  data
          segment.  The compiler just copies SS to DS in the prologue code.
          As there is no need for  procedure instances, there is no need to
          list it in the EXPORTS section of the module definition file.

          Tip:  Callback procedures in DLLs  need not (and  should not) use
          MakeProcInstance  to create  procedure  instance.   The  compiler
          always assumes that DS is not equal  to SS and there is only  one
          data segment.  It will load the correct data segment.

               Still on  the subject of Windows API, there is a very little
          known  (and very little documented) header  file in Borland C++'s
          Include directory called WINDOWSX.H.   A wealth of macros  can be
          found  in this  header file.     For example,  the GlobalAllocPtr
          macro  API  allocates memory  on the  global  heap, locks  it and
          returns a pointer to the  locked memory.  This is similar  to the
          malloc function that C programmers are more familiar with.  Using
          GlobalAllocPtr  also saves from having to keep track of a handle.
          Simple call GlobalFreePtr when  the block of memory is  no longer
          required.  Note:  Locking memory has its history in the real mode
          version  of Windows.  In protected mode, locking memory no longer
          has any  meaning so it is all right to keep a block memory locked
          for its lifetime.

          Trick: The way GlobalAllocPtr is  defined can cause the  compiler
          to generate a "Code has no effect" warning.  To  get around this,
          place a void typecast over GlobalAllocPtr when you call it.

          For example:
               DWORD far *lpDword;
                 .
                 .
               lpDword = GlobalAllocPtr (GHND, sizeof (DWORD) * 20);
                 .
                 .
               if (lpDword != NULL) (void) GlobalFreePtr (lpDword);

               WINDOWSX.H also contains declarations for  the Control Macro
          API.   Using this API  instead of sending  control messages makes
          your code easier to read.

               Edit_SetTabStops (hEdit, nTabs, lpTabs);

          is more legible than;

               SendMessage (hEdit, EM_SETTABSTOPS, (WPARAM) nTabs,
                    (LPARAM) (const int far *) lpTabs);


                                        - 36 -










               In  addition,  WINDOWSX.H  also  contains  declarations  for
          message crackers.  By using these macros, you will make your code
          more  portable.  I have one criticism  though, the macros are not
          defined to  allow a pointer to  be passed to the  message handler
          functions.   If you haven't  used WINDOWSX.H  before, I  strongly
          encourage you to start now.


          Metafiles:

               A metafile is a series of GDI calls.  It can  be stored as a
          physical  disk  file or  represented by  a  handle to  a metafile
          (stored in memory).

          Tip:  Use  a drawing  package (such  as  Corel Draw)  to generate
          metafiles that can be included as a user-defined resource in your
          Windows application.  This  way, you can draw graphics  using the
          powerful drawing tools of such  packages and include the  graphic
          in your application.

          Tip:  Including  a metafile  as  a  user-defined resource  in  an
          application: Say the metafile name is METAFILE.WMF.

          ... somewhere in the resource header file (say RES.H):

          /* assign an ID value for metafile resource types */
          #define METAFILE         2000
          #define MYMETAFILEID     100

          and somewhere in the resource definition file:

          #include "res.h"
            .
            .
          MYMETAFILEID METAFILE "metafile.wmf"

          To use the metafile:

          #include "res.h"
            .
            .
          HGLOBAL handle;
          HMETAFILE hMetafile;
          HDC hDc;
          RECT rect;
            .
            .
          /* Load the metafile */
          handle = LoadResource (hInstance,
             FindResource (hInstance, MAKEINTRESOURCE (MYMETAFILEID),

                                        - 37 -










             MAKEINTRESOURCE (METAFILE)));

          /* no need to retrieve pointer as we only need the handle */
          LockResource (handle); 
          hMetafile   =   (HMETAFILE)  SetMetafileBitsBetter   ((HMETAFILE)
          handle);
          UnlockResource (handle);

          /* Then draw it */
          hDc = GetDC (hWnd);
          GetClientRect (hWnd, &rect);
          SetMapMode (hDc, MM_ANISOTROPIC);
          SetViewportExt (hDc, rect.right, rect.bottom);
          PlayMetaFile (hDc, hMetafile);
          ReleaseDC (hWnd, hDc);

          /* Clean up */
          DeleteObject (hMetafile);
          FreeResource (handle);


               It is important  to set the  mapping mode to  MM_ANISOTROPIC
          and the viewport extents to rectangle in which the metafile is to
          be drawn.  This ensures  that the whole metafile is  drawn inside
          the specified  rectangle.  However, some  metafiles behaves badly
          and will  draw outside the  specified rectangle.   Most metafiles
          sets the window extent and origin, and draws within the limits of
          the  coordinates specified.   However,  this behaviour  cannot be
          guaranteed for all metafiles.

          Trap:    Forgetting    to    call    LockResource    can    cause
          SetMetafileBitsBetter to return NULL.

          Trap:  Metafiles with  placeable headers  cannot be  processed by
          Windows so make sure you save your metafile without the placeable
          header.

          Miscellaneous:

          Trap:  Be very careful when  allocating memory in  a DLL.  Memory
          allocated by a  DLL belongs  to the application  that called  the
          DLL.   Passing the  handle or pointer  to the block  of memory to
          another application will most likely cause a GP fault.   If a DLL
          needs to  share memory  between applications, use  the GMEM_SHARE
          flag  when calling  GlobalAlloc.   This,  however, poses  another
          problem.    Memory blocks  allocated  with  the GMEM_SHARE  flag,
          although  can be  shared, still  belongs to the  application that
          allocated it and  will be freed when  the application terminates.
          If another application calls  the DLL to access the  memory after
          the application that allocated the memory terminates, a  GP fault

                                        - 38 -










          will occur.   The following diagram better  illustrates this (see
          the Help file - Ed.).


          Tip: So, the lessons here are:

          a)  if possible, let the application allocate memory and pass the
          handle/pointer to the DLL

          b) if the DLL must allocate memory, make sure it is used only for
          the application that caused it to be allocated

          c) if the DLL has to allocate memory that will  be shared between
          applications, write a small  application that allocates memory on
          behalf of  the DLL.   This application  has to be  active for  at
          least  the life  of  the  DLL.    (See  accompanying  article  --
          Allocating Shareable Memory (in next month's issue - Ed.))

          Notes:
          [1]  -  I  define Windows  API  documentation  to  be information
          documented  in  Windows API  Vols 1-3.   I  know there  are other
          sources  of  information,  such  as the  numerous  articles  from
          Microsoft.  However, it  is my opinion that any  information that
          is not  included in a function's entry in the Windows API manuals
          should  be classified as "undocumented".   If the  set of manuals
          are  to be the primary  source of reference  material for Windows
          programming,  it  would  be   safe  to  assume  that  information
          documented   elsewhere  is  not   widely  accessible  to  Windows
          programmers and therefore undocumented.


          About the author:

          I am currently doing  a PhD. degree in Electrical  And Electronic
          Engineering  at the  University  Of Canterbury.   My  programming
          experience dates back to the  days when "real programmers"  coded
          with Z80  machine code.  For  the past two years I  have taken an
          interest  in  Windows programming.    Please  send any  comments,
          questions, criticisms to me via:

          email: chuah@elec.canterbury.ac.nz

          or post mail:

          Dennis Chuah
          c/o The Electronic and Electrical Engineering Department
          University of Canterbury
          Private Bag
          Christchurch
          New Zealand.

                                        - 39 -










               All mail (including hate  mail) is appreciated.  I  will try
          to  answer all questions personally, or if the answer has general
          appeal,  in the next issue. If you  are sending me e-mail, please
          make  sure you provide me with an  address that I can reach (most
          Internet and Bitnet nodes are reachable, and so is CompuServe).














































                                        - 40 -










                                     Book Review
                             Title: ObjectWindows How-To
                                  Author: Gary Syck
                             Publisher: Waite Group Press
                                  By Rodney M. Brown

               The  other day,  I was  in my  local  WaldenBooks bookstore,
          browsing over the  crop of C/C++ books.  One  book that caught my
          attention  was   "ObjectWindows  How-To".     This  book   offers
          hints/tips  on   programming  in   Borland  C++/Turbo   C++  with
          ObjectWindows.

               The  book  is organized  by problems,  with the  solution or
          "How-To" following.  Each solution is graded in complexity; Easy,
          Moderate  and Hard.    After the  solution  is explained,  it  is
          followed  with the author's C++ code.   The C++ code is great for
          beginners.    The  author  placed comments  throughout  the  code
          explaining  what each function does.  The author also wrote a 2-3
          page explanation of the code he wrote.

               This book is a great reference.  It is filled with solutions
          to printing, changing the appearance/color of windows, etc. Below
          is a list of all the problems that are explained in the book:

                   1.  Making An ObjectWindows Application.
                   2.  Changing the Class Information & Style of a Window.
                   3.  Adding control windows to a window.
                   4.  Adding menus to a program.
                   5.  Creating an MDI application.
                   6.  Making and Using DLLs.
                   7.  Using the TDialog object class.
                   8.  Making a file selection dialog.
                   9.  Making a text search dialog.
                  10.  Using text controls.
                  11.  Using list box and combo box controls.
                  12.  Using check box and radio button controls.
                  13.  Using string tables.
                  14.  Converting programs to another language.
                  15.  Loading different menus from a resource file.
                  16.  Adding and Deleting menu items.
                  17.  Changing the attributes of a menu item.
                  18.  Changing the check marks in menus.
                  19.  Using bitmaps as menu items.
                  20.  Creating pop-up menus.
                  21.  Creating a text editor.
                  22.  Getting input from the keyboard.
                  23.  Getting input from the mouse.
                  24.  Using the serial port.
                  25.  Using the sound interface.
                  26.  Handling the printer.

                                        - 41 -










                  27.  Drawing in a window.
                  28.  Drawing different shapes.
                  29.  Using bitmaps.
                  30.  Using fonts.
                  31.  Using metafiles.
                  32.  Using the color palette.
                  33.  Making 3-d dialog windows.
                  34.  Creating custom controls. 
                  35.  Making a screen saver.
                  36.  Making nonrectangular windows.
                  37.  Using complex shapes as windows.
                  38.  Creating a file object.
                  39.  Saving different objects in a file.
                  40.  Reading and writing parts of the file.
                  41.  Creating a DDE server.
                  42.  Creating a DDE client.
                  43.  Getting updated data from the server.
                  44.  Executing commands on the server.
                  45.  Getting Drag-and-Drop files.
                  46.  Creating an OLE client.
                  47.  Creating an OLE server.

               I hope I didn't bore you listing all of the subjects covered
          in the  book.  It is a great reference book for Borland C++/Turbo
          C++ ObjectWindows programmers.   I predict  that this book  won't
          spend much time on my bookshelf.


          Contacting me online:

          CompuServe: 72163,2165
          America Online: RodneyB172

          You can also contact me at the following Internet addresses:

          CompuServe: 72163.2165@compuserve.com
          America Online: RodneyB172@aol.com














                                        - 42 -










                                 Creating Help Files
                                    By Todd Snoddy

               Like most of the readers of  Windows Programmer's Journal, I
          enjoy  Windows programming.  Although I  don't currently have the
          blessing?/curse? of being a "full time programmer", I do consider
          myself  to  be  a   dedicated  and  serious  Windows  programming
          hobbyist.  I  would like to use the opportunity that WPJ provides
          to  share   with  you some  of  the tools  I use  to  increase my
          productivity.  As  my busy schedule  permits, I  am hoping to  be
          able  to  review  different  programming  utilities  in  upcoming
          issues.

               I  would like  to  be able  to  concentrate mainly  on  both
          shareware  and free  software.   Although  I don't  have anything
          against commercial  software, many of the  software packages sold
          commercially are rather  expensive, putting it out  of the budget
          of  most  hobbyists  or  small  business  users.    In  addition,
          shareware  has  many   advantages  besides  usually  being   less
          expensive.   Many of the shareware products available fill a void
          that isn't quite covered by the major software publishers because
          they don't take  the time  to develop something  that won't  have
          mass market appeal.  I'll try to point out some of these products
          in the future.  Also,  the quality of modern shareware  can often
          approach or surpass that of commercial software.

               My  review topic this  month will be Windows  help files.  I
          will cover a few tools that I use to  develop my help files with,
          and actually  present a sample help  file that can be  used as an
          example for your own help  files.  The tools that I  will discuss
          are  free,  and are  available  from  various sources,  including
          CompuServe and numerous Internet ftp sites.

               Before I get started with that however, I would like to take
          a brief moment to tell  you a little about myself so that you can
          get an idea of my perspective.   I am currently in the U.S.  Army
          and  stationed  at  Ft.  Riley,  KS.    I    work  as a  computer
          technician/soldier during the day, and in my free time I do a lot
          of  Windows  programming  on  personal projects.    I  am  almost
          entirely self taught, and am competent in C, Pascal and assembly.
          I have been programming Windows for  around two years now, and  C
          for about  seven years.   Prior to  that, I programmed  BASIC for
          several years.  As mentioned before, programming is a major hobby
          of mine, but I also like to read and play pool, usually 9 ball.

               Now to  the good stuff.  Currently, there is only one vendor
          who  makes a compiler capable of creating Windows help files, and
          that is  of course Microsoft.   This  help compiler takes  a file
          that  contains a  special  formatting language  called Rich  Text
          Format, or  RTF, and converts it into a HLP file that can be used

                                        - 43 -










          by the WinHelp engine included with Windows.

               Contrary to  what Microsoft would  like to have  us believe,
          it's not  necessary to use an  RTF word processor like  their own
          (whose name we all know) to create Windows  help files.  Although
          the actual format of the HLP file is considered by many to be one
          of the best kept  secrets in the industry, there  are several low
          cost  or  free  utilities  available to  generate  the  RTF  file
          necessary for input to the Windows help compiler.

               When I first wanted to create my own help files, I looked at
          several utilities to  see what was available,  especially since I
          didn't have several  hundred dollars  extra to  buy an  expensive
          word processor.  The one that I found that was overall easiest to
          use is  RTFGEN, by David Baldwin.   This is an  excellent utility
          whose  use is free, not even shareware.  With David's permission,
          an older command line version is included with this issue of WPJ,
          along with  the  Pascal source  code,  although a  newer  Windows
          version is available  for free as well.  For a small fee, you can
          even obtain the source for the Windows version.

               RTFGEN's  sole purpose  is  to convert  standard ASCII  text
          files into  an  acceptable  RTF  file recognizable  by  the  help
          compiler.   Using RTFGEN for  creating your help  files is almost
          like using a programming language like C.  Many people say that C
          is a  high level  language with  the flexibility  of a  low level
          language like assembler.    RTFGEN will let you mix straight  RTF
          code  with your  help source  file for  maximum control  over the
          desired  output, or  you can  use the  default settings  and just
          specify the  actual topic information  and let RTFGEN  handle the
          rest.  RTFGEN  has some  special keywords that  will actually  be
          converted into RTF automatically,  so you don't have to  get your
          hands dirty if you really don't want to.

               Creating  a help  file  with RTFGEN  involves  a few  steps.
          First, you  need  to plan  the  layout of  the  help file.    The
          importance of this step can't be  overstated.  A well thought out
          layout  makes a big  difference in the apparent   quality of your
          product, especially when the user is totally lost and in  a blind
          panic  tries to bring up  the online help  instead of opening the
          manual.

               The next step would be to create the help source files.  For
          this  task, I use a  free Windows editor  called the Programmer's
          File Editor by Alan Phillips, but it can be done using any editor
          that  reads and  writes standard   ASCII  files, like  DOS's EDIT
          command, or even the Windows Notepad.  

               The  help  source  files   contain  the  actual  help  topic
          information,  including  the  topic text,  keywords,  and  browse

                                        - 44 -










          sequences.   These files will  have the RTFGEN  commands in them,
          and  may also  have  RTF statements  for   added  flexibility  or
          control  of the help file.  Each help topic will be in a specific
          format, and this will be covered shortly.

               After creating the help source files, we are almost ready to
          compile them into a HLP file.  However, before this  can be done,
          the source files  need to be processed by RTFGEN.  This procedure
          converts the special RTFGEN  commands into RTF automatically.  If
          you have any actual RTF statements in  the source file along with
          the  rest of  the  text, it  will  be left  alone  and passed  on
          unmodified.   This allows  the ultimate  in customization  of the
          help file.

               There is  one final step required  before actually compiling
          the help file.   This is  to create a  Help Project file,  or HPJ
          file.   This file specifies certain options to the help compiler,
          including the source files  for the help file,   bitmaps, and any
          help macros used.  I won't cover this subject in  more depth here
          as  it is  documented  in other  places  like the  help  compiler
          documentation.     By  the  way,  another   excellent  source  of
          information on  the format of the  HPJ file as well  as help file
          creation in general  is the Help Author's Guide.   This is a help
          file created  by  someone  at  Microsoft  but  is  not  supported
          officially by them.  It is usually distributed as HAG.ZIP and can
          be  found   on  Compuserve  and   Internet  ftp  sites   such  as
          FTP.CICA.INDIANA.EDU.   It contains a complete  reference for the
          RTF command syntax.

               That's  all you  need to  create a  help file.   That's all?
          Well, as mentioned before, the help  topics must be in a specific
          format.  David Baldwin's documentation for RTFGEN does a good job
          of explaining how to use  it, but I'll briefly cover some  of the
          highlights.

               First, every RTFGEN command is started by a \ character, and
          most are terminated by a ` character.  For example,  to specify a
          topic title, the command would be:

          \title Selecting Background and Foreground Colors.`

               This  statement specifies what text will be displayed in the
          Go To list  box when the  user tries to  search for the  keywords
          "background colors, selecting".  See Figure 1 for an example (see
          the Help file - Ed.).

               In  Figure  1,  the text  shown  in  the upper  list  box is
          specified by the topic  keywords.  To get the  currently selected
          text  to be  used for  the shown  topic, the  following statement
          would be used:

                                        - 45 -










          \keyword background colors, selecting`

               Every  topic  in  the help  file  has  to have  some  way to
          distinguish it as an individual topic and separate it from  every
          other topic.  This is known as the topic name.  The topic name is
          never actually  seen by the person viewing  the help file, but is
          instead used  as an  internal marker  to identify the  individual
          topic to the help system.  In RTFGEN, the topic is specified by a
          statement like:

          \topic SelectingColors`

               In the help source  file, all of the above  statements would
          be  grouped together in the topic heading.   The topic heading is
          separated from the rest of  the topic text by using a  minimum of
          five  = characters at the end of the  heading.  In practice, this
          would look like:

          \topic SelectingColors`
          \title Selecting Background and Foreground Colors.`
          \keyword background colors, selecting`
          =====

          This  is the  sample topic  text for  selecting a  background and
          foreground color.

          ------

               In  the above example, the  actual topic text  follows the =
          character, and is  terminated by five or more - characters.  This
          is how RTFGEN determines the separation between topics, and based
          on  their position, it will generate the appropriate RTF code for
          the help compiler.

               RTFGEN can be used to generate hypertext jumps or popup text
          as well.  For example, if you have some concepts  in a topic that
          the  user may  not be  familiar with,  you can  designate certain
          keywords in the topic that the  user can select on that brings up
          a  popup window with a more detailed description or definition of
          the keyword.

               To define a hypertext  jump with RTFGEN, the text  that will
          be selected  by the  user  to jump  to the  other  topic will  be
          enclosed  in brackets  along  with the  name of  the topic  to be
          jumped to.   For example, Figure  2 shows a typical  display of a
          hypertext jump (see the Help file - Ed.).

               To  duplicate   this  affect  using  RTFGEN,  the  following
          statement would be used in your help source file.


                                        - 46 -










          [Choosing Fonts and Font Sizes:ChoosingFonts]

               In this example, the ChoosingFonts will represents the topic
          name that will be jumped to when the hypertext link is selected.

               If instead you wanted to use a hypertext popup window  for a
          definition,  then you would use two sets of brackets.  An example
          of this is shown below (see the Help file for Figure 3 - Ed.).

          picture elements ([[pels:pels_def]]).

               Since  I am  a firm  believer in  the concept  of explaining
          something and  then giving an example  of how to do  it, a sample
          help  source file  is included,  along with  all of  the required
          files to build it, except for  the actual help compiler. You will
          need  the Windows 3.1  version of the help  compiler to build the
          sample.   After  studying  the  sample  files,  as  well  as  the
          documentation  for  RTFGEN, you  should be  well  on your  way to
          creating your own help files.

               To compile the sample into a help file, use the command:

          SAMPLGEN sample

               This will invoke the SAMPLGEN.BAT batch file to convert your
          source file into RTF, and if everything goes ok, it will then run
          the help compiler.

               There  are many ways to customize your help files, and I may
          cover  some techniques in future  issues of WPJ  as time permits,
          but  if you want to learn some  techniques on your own, then beg,
          borrow,  steal, or  otherwise  obtain a  copy  of the  previously
          mentioned  Help Author's Guide.   You can't beat  the price since
          it's free,  and  it is  full  of useful  information  on RTF  and
          creating help files.

               I welcome any comments  anyone may have on this  article, as
          well as suggestions for  other products to review in  the future.
          I can  be reached on America Online  at TSnoddy, on Compuserve at
          71044,1653,  and  on   the  Internet  at   tsnoddy@nyx.cs.du.edu.
          Although I'm very often quite busy,  I will try to respond to any
          messages.

               Also, if you do decide to start using RTFGEN, please contact
          the author  and let him know  what you think  of it.    The world
          needs  more software authors who are willing to make useful tools
          like  this  available  for   free,  and  when  someone  makes   a
          contribution like that, receiving  feedback from users provides a
          reason  to produce other useful utilities too.  The author, David
          Baldwin, can be reached on Compuserve at 76327, 53.

                                        - 47 -










                                    Gdi See Gdi Do
                            Graphics Animation in Windows
                                  By Bernard Andrys

               In this series of articles, I will discuss  the writing of a
          space invaders style  game for Windows  3.1 in C.   The  articles
          will  be  directed to  people  who  understand programming  (such
          BASIC) and  know a  little about Windows  but are new  to Windows
          programming in C.

               Experienced  C programmers  will  immediately recognize  the
          poor  style of my code.   In some cases, I will  be doing this on
          purpose.   If a reader is new  to C AND Windows, they're probably
          going  to have just as much of  a problem following the C code as
          trying to follow the  Windows specific areas of programming.   (I
          know  that I sure  had problems learning both  at the same time.)
          As a result,  I will try to stick with  easy to understand syntax
          like  "x=x+1" instead of the  C shorthand "++x".   Later articles
          will use more of the shorthand notation as I and  the readers get
          comfortable with C.   The other reason for the  bad style is that
          my coding philosophy  is "Well it  works... so  I guess its  good
          enough."  This doesn't mean, however, that I don't  want to learn
          how to  write C better.   If you are an  experience C programmer,
          then  please drop  me  a  line  about  how  I  could  improve  my
          programming style.

               What  will  be different  is how  we  go about  writting the
          program.   I think that the  best way to learn  programming is to
          write a working program,  no matter how poorly written,  and then
          refine it as you  learn more.  So I will  start with the standard
          "do  nothing" windows program that just creates a window.  Future
          articles  will take this basic  program and add  the missle base,
          missle  firing, invaders, invaders firing, and of course the ufo.
          From  this simple  program we  add features  and fix  problems in
          future articles.  Some of the improved features will be 256 color
          bitmaps and digitized sound.   A couple of  the problems that  we
          will  need  to  deal  with  are  friendly  multitasking  and  the
          efficient drawing of bitmaps.  Once the game is finished, I would
          like to write about converting the program to C++.

               If you are new to Windows  programming in C then before  you
          go  on to  read  the  program below,  you'll  need  two books  as
          references.   The first is "The C Programming Language" by Dennis
          Ritchie and Brian Kernigan.   The second is "Programming Windows"
          by  Charles Petzold version  3.0.  These  two books have  all the
          basics of C and Windows programming in C.

               If you are knowledgeable about Windows programming in C then
          check  out the "Duncan" format of my  Windows C code.  There's no
          case  switch statement  for  processing messages.    An array  of

                                        - 48 -










          structures contains the  list of messages  that our program  will
          respond  to along  with  the function  that  is called  for  each
          message.

               A  final note before the  program starts:   This program was
          written using Quick  C for Windows.   As far as I know,  I didn't
          write anything that was compiler dependant (except the make file,
          but  then I didn't write  it, Quick C  wrote it for me).   If you
          have any  problems compiling it, drop  me a line so  I can remove
          any  compiler dependancies  in  future  articles.   I  have  been
          meaning  to purchase Turbo C++  for Windows and/or  Visual C++ so
          expect make  files for one or both of those compilers in the near
          future.


          // START OF PROGRAM LISTING

          /* invid.c */

          /*
          There are two  types of  ways of  adding comments  into C  source
          code.
          The first  way to  add a comment  is to put  a   / *   before the
          comment
          and a  * /  at the end of the comment.  (I had to add a space
          between the / and * because  otherwise the C compiler would think
          that
          it  really  was a  comment.   You  can't  put comments  inside of
          comments.)
          The other way to add a comment in your source code is to put a //
          at
          the start of the comment.   The comment will start at the //  and
          go to
          the end of the line.
          */

          #include <windows.h>
          #include "invid.h"

          /*
          The #include statement allows you to include another file in your
          source code.   This saves the  hassle of cutting and  pasting the
          code in.  The file  that you include is put inside a pair  of < >
          signs or  a pair of  " ".   Using < and  > tells the  compiler to
          search  through  the  path  defined  by  an  INCLUDE  environment
          variable (use SET INCLUDE = path to include files).  If you use "
          "  instead, it  tells  the compiler  to  only check  the  current
          subdirectory.   You normally use < and > for files that come with
          with the compiler.  Quotes are normally used for your own include
          files.  Every Windows program needs to include <windows.h>.  C by

                                        - 49 -










          itself  doesn't   have  any  functions  for   handling  character
          input/output,  character  strings   and  other  basic  functions.
          Therefore  most  C  programs  will  also  include  <stdio.h>  and
          <stdlib.h> to have a bunch of functions to work with.

          My own  file "invid.h"  contains my global  variable declarations
          and function prototypes.   You should already know that  a global
          variable is  a variable that  all functions can  share.  In  C, a
          global variable  is  created by  declaring a  variable above  the
          function  main()  ( or  for  Windows, the  function  WinMain() ).
          Normally you put your global variables at the top of your program
          after the #include files (or in your own #include file).   Global
          variables  should  normally be  avoided  because  they make  your
          program larger and make your code harder to manage as it grows.

          Function prototypes are a list of the functions  that are in your
          program.  A function  prototype includes the data types  that the
          function  will return and the data types of the parameters of the
          function.   If you were  to write a  function called DrawPixel(),
          you would write:

          int DrawPixel( int x, int y)
          {
               ...the function's code goes here
          }

          Int is the data type that the function returns.  DrawPixel is the
          name of the function.  X and y are the  function's arguments with
          int  x and  int y  saying  that the  arguments are  of data  type
          integer.  To make a function prototype just copy:

          int DrawPixel (int x, int y)

          from your program, paste it at the top of your program (or put it
          in a separate  #include file like I did with  invid.h), and add a
          semi-colon to the end of the line.

          The function prototype for function DrawPixel(x, y) is:
          int DrawPixel (int x, int y);

          The function  prototype tells  the compiler about  your DrawPixel
          function before  its used.  This  lets the compiler check  to see
          that you use your DrawPixel function with the right data types.
          */

          struct decodeWord {
               WORD Code;
               LONG (*Fxn)(HWND, WORD, WORD, LONG); };

          struct decodeWord messages[] = {

                                        - 50 -










               WM_CREATE, DoCreate,
               WM_DESTROY, DoDestroy, } ;

          /*
          I  have  used a  different method  for  having a  Windows program
          respond to  messages  than  what  is  normally  seen  in  Windows
          programming books.  It is  a method that I first saw  used by Ray
          Duncan  in PC Magazine. Instead of a large switch case statement,
          it uses an  array of structures that list the  messages that your
          program will respond to and the function that is called when that
          message is received.  (I'm going to skip covering  the details of
          arrays  and structures in C  for now. Otherwise,  I wouldn't have
          anything to write about  in future articles!) This  format allows
          you to easily add new messages without having to deal with a long
          and messy switch case statement.  To use the Duncan
          format, simply add the message that your program will respond to,
          a comma,  the name of the  function that will be  called when you
          receive that message, and then another comma.  In the case above,
          if  we  wanted to  have our  program  respond to  a WM_SYSCOMMAND
          message (this  is the message sent  when you click on  the system
          menu of a window) we would make the following change to the lines
          above.

          struct decodeWord messages[] = {
               WM_CREATE, DoCreate,
               WM_SYSCOMMAND, DoSysCommand,   // the  Windows Message,  Our
          Function
               WM_DESTROY, DoDestroy, } ;

          Now when  Windows sends a  WM_SYSCOMMAND message to  our program,
          our  program will run the  function DoSysCommand.   (I could have
          called the function anything I wanted.)   We would then go to the
          bottom of the program code and write the function DoSysCommand().
          */


          int PASCAL WinMain (HANDLE hInstance,
               HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
          /*
          This is  start of  the Windows  program.   (A  regular C  program
          starts  with a function called main().)  The keyword PASCAL tells
          the C compiler that this function  will be called with the PASCAL
          calling convention.   This means  that the code  that is  written
          inside of this function  has access to the actual  variables that
          are   passed  as  parameters   (i.e.,  hInstance,  hPrevInstance,
          lpszCmdParam,  nCmdShow).  A normal function in C doesn't let you
          change the original variable, it gives the function a copy of the
          variable to play with.

          If  the keyword PASCAL was  NOT used above,  then hInstance would

                                        - 51 -










          contain a duplicate of the number that Windows uses to keep track
          of which copy of this program  we have in memory. (In Windows, we
          can  have the same program loaded several  times.)  If we changed
          the value of  hInstance, it wouldn't  change what Windows  thinks
          hInstance  contains.   It  would only  change  what our  function
          thinks hInstance is.

          Using the  keyword PASCAL  means that if  we change the  value of
          hInstance,  it  will  change  what Windows  thinks  the  value of
          hInstance  is as well.  This can  be very dangerous so you should
          use care when dealing  with the parameters to functions  that are
          declared  using  the  PASCAL keyword.    So  why  use the  PASCAL
          keyword?  There are  three reasons for using the  PASCAL keyword.
          The first is  that when  writing parts of  a program, it's  often
          easier to  use the  keyword PASCAL  to get  access to  the actual
          arguments  than to have  to deal with creating  a group of global
          variables  or  use a  pointer  to the  arguements  to get  to the
          original  variable.  The next  reason is that  the PASCAL calling
          convention  for functions  makes  programs a  little smaller  and
          makes them  run a  little faster.   The last  reason is  that any
          function that Windows will  call in your program must  be declare
          as a  PASCAL function.   A simple  Windows program  only has  the
          functions Winmain()  and WinProc() called by  Windows.  Winmain()
          is the  start of your program  and WinProc() is  the name usually
          given to the function  that Windows calls when  it has a  message
          for  your program. A function  that Windows calls  inside of your
          program is called a callback function and  all callback functions
          must  use  the PASCAL  keyword.   I  won't  spend  any time  here
          discussing callback  functions because using  them is a  lot more
          messy  than just  adding  the keyword  PASCAL  to the  function's
          declaration.
          */

          {
               MSG msg ;
          /*
          Declare a variable msg of data type MSG (message).   This will be
          the  variable that will  hold any messages  that are  sent to our
          program.
          */
               if (!hPrevInstance) InitApplication(hInstance);
          /*
          hPrevInstance is a  number that  Windows passes to  WinMain as  a
          parameter when run.   The number identifies the previous  copy of
          our program that is currently running.

          If  this is the only  copy of the  program running, hPrevInstance
          contains 0.  In C, the if() statement executes the next statement
          if  what  is in  the  parenthese's is  true  (and in  C,  true is
          anything except 0).  The ! operator  in C performs a  logical NOT

                                        - 52 -










          operation.  A logical NOT operator changes a 0 to a 1 or a 1 to a
          0.   Therefore  if  hPrevInstance  is  0  (no  previous  instance
          running)   then   !hPrevInstance   equals   1   (True).   So   if
          !hPrevInstance  is true  then "if  (!hPrevstance)" runs  the next
          statement which  is InitApplication().   Once you've seen  this a
          couple of times, you'll automatically translate a statement like:

          if (!hPrevInstance) InitApplication(hInstance);

          to mean:
          If there is not a previous instance of our program in memory then
          run the function InitApplication().

          InitApplication is a  function that  we will write  to setup  the
          information for this window that can be shared between all copies
          of our program that are running.
          */
               InitInstance(hInstance, nCmdShow);
          /*
          Call  InitInstance().   This  is the  function  that sets  up the
          information  for this  program's  window that is  unique for this
          particular copy in memory.
          */
               while (GetMessage (&msg, NULL, 0, 0))
               {
                    TranslateMessage (&msg) ;
                    DispatchMessage (&msg) ;
               }
          /*
          This is the  message loop that keeps  our program running.   Your
          program  runs in  this  infinite loop  as  long as  the  function
          GetMessage()  returns TRUE (In C, TRUE is anything other than 0.)
          The GetMessage() function  returns FALSE if a WM_QUIT  message is
          received.   This  means that  the  while loop  will  stop if  our
          program receives a WM_QUIT message and our WinMain() program will
          continue to the lines below.
          */
               return (msg.wParam) ;
          }
          /*
          This is the  end of our Program.  What  follows are the functions
          that WinMain calls and the functions that we call when we receive
          a  message as  defined at the  top of  this program  in the array
          messages[].
          */


          BOOL InitApplication(HANDLE hInstance)
          /*
          InitApplication  will be  the  data that  is  shared between  all

                                        - 53 -










          instances of our program.
          */
          {
               WNDCLASS wndclass;

               wndclass.style = 0 ;
               wndclass.lpfnWndProc = WndProc ;
          /*
          For this program WndProc() will be  the name of the function that
          windows calls when it has a message for our program.
          */
               wndclass.cbClsExtra = 0 ;
               wndclass.cbWndExtra = 0 ;
               wndclass.hInstance = hInstance ;
               wndclass.hIcon = LoadIcon (hInstance, szAppName) ;
          /*
          Load our icon for this program.  szAppName is a  variable defined
          in invid.h.  (this is just a short cut so that if I use this code
          to  make  a different  program, I  can  just change  the variable
          szAppName  in  invid.h instead  of having  to  go through  all my
          source code to see where I used the name  of my program.)  Take a
          look  at the file invid.rc for  the rest of the information about
          how you add an icon.
          */
               wndclass.hCursor = LoadCursor (hInstance, IDC_ARROW) ;
               wndclass.hbrBackground = GetStockObject (BLACK_BRUSH) ;
          /*
          the background of our window will be painted black.
          */
               wndclass.lpszMenuName = NULL ;
               wndclass.lpszClassName = szAppName ;

               return(RegisterClass (&wndclass));
          }


          BOOL InitInstance(HANDLE hInstance, WORD nCmdShow)
          /*
          The InitInstance() function will initialize the data that will be
          unique for a particular copy of the program that is in running.
          */

          {
               hWnd = CreateWindow (szAppName,
                    "Invid",
                    DS_SYSMODAL | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
          /*
          The  flags DS_SYSMODAL  etc. are  constants defined  in windows.h
          that tell windows  how the window  should look.   An | symbol  is
          used between  the flags because it is  the C operator for logical

                                        - 54 -










          OR.   If you have the  binary numbers 1000  and 0100 then  1000 |
          0100  = 1100.   So by putting  an | symbol between  each flag, we
          combine the  different flags  into a  single number  that Windows
          uses to figure out how the window should look.
          */
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    WINDOW_WIDTH, WINDOW_HEIGHT ,
          /*
          A  normal  Windows  program   would  use  the  Windows  constants
          CW_USEDEFAULT above.  However, since this is a graphic game whose
          window  cannot be  resized (see  DS_SYSMODAL flag above),  we are
          going  to  define precisely  the size  of  the window  in pixels.
          WINDOW_WIDTH and WINDOW_HEIGHT are constants that I've defined in
          "invid.h".
          */
                    NULL,
                    NULL,
                    hInstance,
                    NULL) ;

               ShowWindow (hWnd, nCmdShow) ;
               UpdateWindow (hWnd) ;
               return (TRUE);
          /*
          In <windows.h> TRUE is defined as 1 and FALSE is defined as 0.
          */
          }

          long  FAR PASCAL WndProc (HWND hWnd, WORD wMsg, WORD wParam, LONG
          lParam)
          /*
          This is the function that Windows calls whenever it has a message
          for our  window.  WinProc  goes through  each item  in the  array
          messages[]  (which was  defined at  the top  of our  program) and
          checks to see if the  message it received matches the  message in
          the array.   If the message does match, then it runs the function
          that goes with that message.
          */
          {
               int i;

               for(i=0; i < dim(messages); i++)
               {
                    if(wMsg == messages[i].Code)
                         return((*messages[i].Fxn)(hWnd,    wMsg,   wParam,
          lParam));
               }

               return(DefWindowProc(hWnd, wMsg, wParam, lParam));
          }

                                        - 55 -











          LONG DoCreate(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
          /*
          This is where we will load our bitmaps and initialize some of our
          variables.    The program  doesn't do  anything  yet so  there is
          nothing to create.
          */
          {
          return 0;
          }


          LONG DoDestroy(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
          /*
          The  program doesn't create anything  yet so there  is nothing to
          destroy before the program exits.
          */
          {
               PostQuitMessage (0) ;
               return 0 ;
          }


          // END OF PROGRAM LISTING


               So that's  it for this month.  Don't you just hate all these
          programs that do ABSOLUTELY  NOTHING.  I sure do!   Unfortunately
          this article is  already a bit long so you'll  have to wait until
          next  month before we turn this "do nothing" Windows program into
          a nifty little space invaders style game. If you'd like a peek at
          where I'm  going  with  this  article, run  peek.exe.  (You  will
          probably need to play with the delay= value in the invid.ini file
          that is created in your Windows subdirectory after the program is
          run the first time.)


          About the author:

          (short version)
          SWM 25 ISO SWF.  Enjoys long walks, sun, surf, skiing.

          (long version)
          Bernard  Andrys is a network  engineer for CSI,  an ISDN hardware
          and software development company.   He holds a bachelor's  degree
          in  Mechanical Engineering  from  the University  of Maryland  at
          College  Park.   He  can  be  reached  through  the  Internet  at
          andrys@csisdn.com or on the Windows Programmer's Journal BBS.



                                        - 56 -










                               Book Review:  Windows++
                                   By Philip Sloss

               I started trying to write Windows programs the old-fashioned
          way -- copying examples from magazines and books.   This is still
          my  preferred method when it  comes to things  I don't understand
          clearly.  ("Things I Don't Understand Clearly" -- this is such an
          all-encompassing topic,  that brevity  and disk space  prevent me
          from  fully  explaining  it;  however,  you  will  find  examples
          sprinkled  throughout the  rest  of this  article.)   I  do  like
          trolling  the book  stores  looking for  interesting examples  on
          Windows programming, and one of my first finds was a book  called
          "Windows++."

                  "Windows++: Writing Reusable Windows Code in C++"

               Often, you can find out an important thing in the preface to
          a  book  or article:  what the  book is  about.   The  preface of
          "Windows++" states that it is "essentially a recipe for  building
          a C++ class  library interface to Windows."  What  really sold me
          on this book was that the author, Paul DiLascia, actually *shows*
          how to  do this.  Instead of finishing  the book with a jumble of
          ideas that you  have to put together, Paul  goes the whole twelve
          yards, and shows how to put the library together.  The end result
          is that "Windows++"  is not just a  book on how to  build a class
          library, it is a class library.

               Armed  with (or,  rather, disarmed  with) a  general naivete
          about Windows  programming and a  lack of enthusiasm  for writing
          long  repetitious code, I decided to use the Windows++ library to
          write  Windows programs.  The  book and the  library are mutually
          beneficial: not only  does the  library serve the  book, but  the
          book  is the perfect reference for  the library!  When I'm having
          problems, I can see  how something was implemented in  the source
          code, and  read a detailed  explanation of it  in the book.   The
          book is also educational on Windows programming in general.

               A couple of points:  First, class libraries are very helpful
          and  can  be  of  great  benefit.    Microsoft's  Visual  C++  is
          permanently  entwined  in  their  class  library,  the  Microsoft
          Foundation Class Library (MFC).   MFC is the primary  reason that
          Visual C++  is so useful.  Second, and just as important, I think
          that one still  has to spend time  learning Windows the "C"  way.
          There is no way around it, in my smug, slight opinion.

               For  example, I'll use someone I'm on speaking terms with --
          me.  Shortly  after purchasing  "Windows++," I went  and got  the
          bible -- "Programming Windows" by Charles Petzold.  What happened
          with  me was that I quickly began  asking a lot of questions like
          "Well, how  does this work?"  (Compiler  errors will cause one to

                                        - 57 -










          speak out  loud to no one  in particular.) It helped  to know how
          Windows++  calls were mapped to  the Windows API,  because then I
          had  some clue as  to what to  expect.  The  general consensus is
          that  Mr.  Petzold's  book  is  the  best  there  is  on  Windows
          programming fundamentals -- I agree.

               In  other  words,  while  I'm  led  to  believe  that  class
          libraries like MFC and Windows++ can greatly simplify one's work,
          I still think  most beginning  Windows programmers are  in for  a
          future showdown with the Windows API.

                                    "Hello, World"

               The proliferation of the  phrase "Hello, World" has extended
          beyond computer programming and now has completely taken over the
          information age. The standard introduction to just about anything
          -- renting  a car, sky diving without  a parachute (also known as
          sky jumping or sky  plunging), underwater basket cooking --  is a
          square with the  words "Hello, World"  in the middle  of it.   On
          your first parachute-less  sky dive, this is a good  thing to aim
          for,  as  it will  allow the  authorities  to easily  locate your
          remains.

               Windows  programming  adds a  system  menu,  title bar,  and
          maximize/minimize  buttons  to the  "Hello,  World"  square.   In
          addition, it requires a rather detailed preparation of structures
          and  calls to  functions  with  423  parameters.    It  is  also,
          apparently, the basis for beginning a Windows class library.

               In C, the  "Hello, World" program looks  like this (adapted,
          with few alterations, from Petzold's "Programming Windows"; those
          of you who have seen this countless  times before, please try not
          to become physically ill):

          ////////////////////////////////////////
          #define STRICT
          #include <windows.h>

          LRESULT CALLBACK _export WndProc (HWND, UINT, WPARAM, LPARAM);

          int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                              LPCSTR lpszCmdParam, int nCmdShow)
          {
               HWND        hwnd;
               MSG         msg;
               WNDCLASS    wndclass;
               static char szAppName[] = "Hello";

               if (!hPrevInstance) {
                    wndclass.style         = CS_HREDRAW | CS_VREDRAW;

                                        - 58 -










                    wndclass.lpfnWndProc   = WndProc;
                    wndclass.cbClsExtra    = 0;
                    wndclass.cbWndExtra    = 0;
                    wndclass.hInstance     = hInstance;
                    wndclass.hIcon                      =  LoadIcon  (NULL,
          IDI_APPLICATION);
                    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
                    wndclass.hbrBackground                                =
          (HBRUSH)GetStockObject(WHITE_BRUSH);
                    wndclass.lpszMenuName  = NULL;
                    wndclass.lpszClassName = szAppName;

                    RegisterClass (&wndclass);
               } 

               hwnd = CreateWindowEx(NULL,       // extended window style
                              szAppName,         // window class name
                              "The Hello Program",  // window caption
                              WS_OVERLAPPEDWINDOW,  // window style
                              CW_USEDEFAULT,        // initial x position
                              CW_USEDEFAULT,        // initial y position
                              CW_USEDEFAULT,        // initial x size
                              CW_USEDEFAULT,        // initial y size
                              NULL,          // parent window handle
                              NULL,          // window menu handle
                              hInstance,     // program instance handle
                              NULL);         // creation parameters

               ShowWindow (hwnd, nCmdShow);
               UpdateWindow (hwnd);

               while (GetMessage (&msg, NULL, 0, 0)) {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
               }
               return msg.wParam;
          }

          LRESULT CALLBACK _export WndProc (HWND hwnd, UINT message,
                                            WPARAM wParam, LPARAM lParam)
          {
               HDC         hdc;
               PAINTSTRUCT ps;
               RECT        rect;

               switch (message) {
                    case WM_PAINT:
                         hdc = BeginPaint (hwnd, &ps);
                         GetClientRect (hwnd, &rect);
                         DrawText (hdc, "Hello, Windows!", -1, &rect,

                                        - 59 -










                             DT_SINGLELINE | DT_CENTER | DT_VCENTER);
                         EndPaint (hwnd, &ps);
                         return 0;

                    case WM_DESTROY:
                         PostQuitMessage (0);
                         return 0;
               }

               return DefWindowProc (hwnd, message, wParam, lParam);
          }

               Again,  all this  gets you is  a window that  can be closed,
          with a  line of text in  it (although it  does help pad  out this
          article).  And, for the most part, all programs have to have this
          code  somewhere in them.   This is where  the class library comes
          in.   A  class library  does repetitive  things like  filling the
          WNDCLASS  structure and calling CreateWindowEx() with the correct
          parameters for  you.   You only  have to  define  the styles  and
          parameters specific to your application.

                   What "Hello, World" looks like using "Windows++"

               For purposes of  introduction, one of the first  sections in
          the book shows what the Windows++ version of "Hello, World" looks
          like.  It reduces the long, C-style program to this:

          #include <wpp.h>   // main Windows++ header file

          APPCLASS HelloWin : public WPMainWin {
          public:
               HelloWin() { createWin("Hello"); }
               void paint(WPPaintStruct &ps) {
                    WPRect clientArea = this;
                    ps.drawText(clientArea, "Hello, Windows++.",
                         DT_SINGLELINE | DT_CENTER | DT_VCENTER);
               }
          };

          void WPApp::main()
          {
               mainWin = new HelloWin;
               run();
          }

               As the "Hello, World" example is a do-nothing program,  this
          program has very  little code  -- a nice  correspondence.  For  a
          detailed explanation of how this  is orchestrated, I strongly and
          emphatically suggest purchasing "Windows++."  


                                        - 60 -










                                What's the Difference?

               What separates "Windows++"  from some of the  other books on
          C++ Windows  programming is  that "Windows++" is  primarily about
          how the library fits together.  Often, all one gets is the source
          code to a  class library at the  back of the book and/or  on disk
          and  instructions on how to use it.  "Windows++" shows how anyone
          can build their  own library -- it  discusses some of  the issues
          one  has to  deal with,  and some  of the  standard and  extended
          features one  should consider  incorporating in a  class library.
          At  the same time, there are several instructive examples of real
          Windows programs written with the Windows++ class library.

               And finally, in the last chapter, the reader is shown how to
          put the class library into a  dynamic link library (DLL), and the
          issues and problems that any library has to deal with  to put C++
          classes into a DLL.


                             "How About a Sudden Ending?"

               So,  summing up:  "long, redundant code -- bad, reusable C++
          Windows classes -- good."  And a  good book on how to make a  C++
          class library for Windows is "Windows++."



          About the Author: An Unauthorized Autobiography of Philip Sloss

               Born from a crude  genetic experiment mixing the genes  of a
          human sperm with  tree sap, Mr.  Sloss has led  a far from  legal
          existence since  his grudging inception  into the  world.   After
          being  developed in an artificial womb,  he was raised in a large
          culture  of athlete's foot fungus.   Mr. Sloss  was accepted into
          the   aerospace  engineering  department   at  San   Diego  State
          University, and in May  of 1992, having advanced  to the rank  of
          graduate, he left college and began a career in unemployment.  He
          is  now   under  under  psychiatric  observation   for  "behavior
          unsuitable to inert objects."  Hospital officials report that Mr.
          Sloss' main hobby is spotting lint.











                                        - 61 -










                              Getting in touch with us:

          Internet and Bitnet:

          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.

               In future  issues we  will be  posting  e-mail addresses  of
          contributors  and columnists  who  don't mind  you knowing  their
          addresses. We will also contact any  writers from previous 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.


























                                        - 62 -










                                    The Last Page
                                   By Mike Wallace

               I got this in the mail a few days ago from Mike Strock...

               Here is a wonderful  quote I think you will  just love.
               It comes from the Journal American, page d6, in the 2nd
               article, 3rd paragraph in the 4th column.

               "Electronic bulletin boards are fast becoming a popular
               way  to get  copies  of  programs  for  free,  but  the
               practice  is  illegal.   Bulletin boards  are computers
               that can be reached by other computers via modem.  Most
               of  them require  the  new users  to upload  an illegal
               program  onto  their  machines  (thereby  incriminating
               themselves) before they are allowed to down-load  other
               programs for free,  said Alison Gilligan, international
               anti-piracy specialist at Microsoft."


               Bulletin  boards  have  been  blamed  for spreading  illegal
          copies of software almost  since the day they  started appearing.
          Software companies  have long complained their  very existence is
          in  danger due  to  these BBSs  spreading  free copies  of  their
          software.   Is this fair  to the majority of  BBSs?  No,  I don't
          think so.   I've been on a  lot of boards,  and most of the  ones
          I've seen aren't doing anything illegal.  Maybe  you need to know
          someone  to  get  onto  the  illegal  boards,  but  that  doesn't
          legitimize the above  quote from  Microsoft.  The  trend in  this
          country to  blame others for your own "bad luck" gets out of hand
          sometimes.   Say you start  up a commercial  software company and
          nobody buys  your app.  Does  that mean everyone has  a free copy
          obtained  from a  BBS?   Maybe,  but there's  also a  chance your
          program isn't worth buying,  or people don't even know  about it.
          It's hard  to buy every commercial program you want when each one
          may  cost $200-300, or more.  The  software companies say this is
          to  recoup their  losses  from illegal  (unpaid) copies  floating
          around.   I think  this may  have the opposite  effect -  who can
          afford  to  buy  software that's  so  expensive?    Now, I'm  not
          condoning software piracy.  Besides being  illegal and immoral, I
          think everybody  loses when  nobody's paying for  their software.
          The  concept  of "shareware"  should  be  extended to  commercial
          software.  Will this  ever happen?  Never mind whether  it's even
          feasible.  I  would probably own more software if  I could try it
          out first and then pay for it if I decide I'll use it.  But as it
          is, I can't  afford to  pay big bucks  for a program  that I  may
          never use  once I've  tried it  out.  So,  the result  is there's
          probably a  lot of good software for sale that would make my life
          easier,  but I'll never know about it.   The same can probably be
          said   for  a  lot  of  computer   users.    Hmmmm...sounds  like

                                        - 63 -










          everybody's losing again.

               A  lot of these companies only appear  to be in the business
          of manufacturing software so they can make a lot of  money, and I
          think the people putting out quality software are.  Take Borland,
          for example.   They put out  a lot of good  programs, and they're
          reaping the benefits.   Microsoft too.   Why they're  complaining
          about  BBSs is  beyond me.   Let's look  at one  BBS and  see how
          Microsoft has benefited from  it: the WPJ BBS.   Besides carrying
          WPJ, there's a lot of other software (all legal) available from a
          CD-ROM that can be accessed by  anybody that calls our BBS.  Most
          of  it  is  devoted  to products  produced  by  Microsoft  (e.g.,
          Windows), and  we're just part of  a much larger  network of BBSs
          all  over the  world  supporting  Microsoft.    True,  a  lot  of
          commercial software companies live  off Microsoft by writing apps
          helping  people run  Windows, but  it goes  both  ways: Microsoft
          benefits by having so many  companies support their products with
          add-on programs  or  whatever.   If  I  was going  to  choose  an
          operating system for my computer, one thing I would look at would
          be  the third-party  support, and  Microsoft is  the overwhelming
          leader  in that  area  for  IBM-compatible  PCs.    So,  to  hear
          Microsoft complaining about BBSs is more  than a little annoying.
          Sounds like it's biting the hand that feeds it.




























                                        - 64 -



