home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / wpj_mag / wpjv1n7.zip / WPJV1N7.TXT < prev   
Text File  |  1993-08-02  |  152KB  |  3,829 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.               WW     WW     WW      PPPPPPPP              JJ
  8.               WW     WW     WW      PP    PP              JJ
  9.                WW   WWWW   WW       PP    PP              JJ
  10.                WW  WW  WW  WW       PPPPPPPP              JJ
  11.                WW  WW  WW  WW       PP             JJ     JJ
  12.                 WWWW    WWWW        PP              JJ   JJ
  13.                  WW      WW         PP               JJJJJ
  14.  
  15.           ----------------------------------------------------------------
  16.           The Windows Programmer's Journal                        Volume 01
  17.           Copyright 1993 by Peter J. Davis                        Number 07
  18.           and Mike Wallace                                          Aug 93
  19.           ----------------------------------------------------------------
  20.           A monthly  forum for  novice-advanced programmers to  share ideas
  21.           and concepts  about programming in the  Windows (tm) environment.
  22.           Each  issue is uploaded  to the info systems  listed below on the
  23.           first of the month, but made available at the convenience  of the
  24.           sysops, so allow for a couple of days.
  25.  
  26.           You can get in touch with the editors via Internet or Bitnet at:
  27.  
  28.           HJ647C at GWUVM.BITNET   or   HJ647C at GWUVM.GWU.EDU  (Pete)
  29.  
  30.           CompuServe: 71141,2071 (Mike)
  31.  
  32.           GEnie: P.DAVIS5
  33.  
  34.           or you can send paper mail to:
  35.  
  36.           Windows Programmer's Journal
  37.           9436 Mirror Pond Dr.
  38.           Fairfax, Va. 22032
  39.  
  40.           We can also be reached by phone at: (703) 503-3165.
  41.  
  42.           The WPJ BBS can be reached at: (703) 503-3021.
  43.  
  44.           The WPJ  BBS  is currently  2400 Baud  (8N1). We'll  be going  to
  45.           14,400 in the near future, we hope.
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.                                      LEGAL STUFF
  62.  
  63.           - Microsoft,  MS-DOS, Microsoft Windows, Windows  NT, Windows for
  64.           Workgroups,  Windows for  Pen  Computing, Win32,  and Win32S  are
  65.           registered trademarks of Microsoft Corporation.
  66.  
  67.           -  Turbo Pascal for Windows,  Turbo C++ for  Windows, and Borland
  68.           C++   for   Windows   are  registered   trademarks   of   Borland
  69.           International.
  70.  
  71.           -  WordPerfect   is  a   registered   trademark  of   WordPerfect
  72.           Corporation.
  73.  
  74.           - Other  trademarks mentioned herein  are the  property of  their
  75.           respective owners.
  76.  
  77.           - WPJ is available from the WINSDK, WINADV and MSWIN32  forums on
  78.           CompuServe, and the IBMPC, WINDOWS  and BORLAND forums on  Genie.
  79.           It  is  also  available  on  America  Online  in  the Programming
  80.           library.  On Internet,  it's available on  WSMR-SIMTEL20.ARMY.MIL
  81.           and FTP.CICA.INDIANA.EDU.  We upload it by  the 1st of each month
  82.           and it is usually available by the 3rd or 4th,  depending on when
  83.           the sysops receive it.
  84.  
  85.           - The  Windows Programmer's  Journal takes no  responsibility for
  86.           the content  of the text  within this  document. All text  is the
  87.           property  and  responsibility  of  the  individual  authors.  The
  88.           Windows  Programmer's Journal  is solely  a vehicle  for allowing
  89.           articles  to be collected and distributed in a common and easy to
  90.           share form.
  91.  
  92.           - No part of the Windows Programmer's Journal may be re-published
  93.           or  duplicated in  part  or whole,  except  in the  complete  and
  94.           unmodified form of the  Windows Programmer's Journal, without the
  95.           express written permission of each individual author. The Windows
  96.           Programmer's Journal  may  not be  sold  for profit  without  the
  97.           express  written permission  of the  Publishers, Peter  Davis and
  98.           Michael  Wallace,   and  only  then  after   they  have  obtained
  99.           permission from the individual authors.
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.           Subject                                         Page Author(s)
  125.           ---------------------------------------------------- ------
  126.           WPJ.INI ...................................     4 Pete Davis
  127.  
  128.           Letters ...................................     6 Readers
  129.  
  130.           Beginner's Column .........................     7 Dave Campbell
  131.  
  132.           Window's Programmer's Guide to Serial......    17 David Falconer
  133.  
  134.           Pascal in 21 Steps ........................    22 Bill Lenson
  135.  
  136.           Hacker's Gash .............................    35 Dennis Chuah
  137.  
  138.           ObjectWindows How-To ......................    41 Rodney Brown
  139.  
  140.           Creating Help Files .......................    43 Todd Snoddy
  141.  
  142.           GDI See GDI Do ............................    48 Bernard Andrys
  143.  
  144.           Windows++ .................................    57 Philip Sloss
  145.  
  146.           Getting in Touch with Us ..................    62 Pete & Mike
  147.  
  148.           Last Page .................................    63 Mike Wallace
  149.  
  150.  
  151.           Windows Programmer's Journal Staff:
  152.  
  153.           Publishers ......................... Pete Davis and Mike Wallace
  154.           Editor-in-Chief .................... Pete Davis
  155.           Managing Editor .................... Mike Wallace
  156.           Contributing Editor ................ Dave Campbell
  157.           Contributing Editor ................ Bill Lenson
  158.           Contributing Editor ................ Dennis Chuah
  159.           Contributing Editor ................ Mike Strock
  160.  
  161.           Contributing Writer ................ Rodney Brown
  162.           Contributing Writer ................ Todd Snoddy
  163.           Contributing Writer ................ Bernard Andrys
  164.           Contributing Writer ................ David Falconer
  165.           Contributing Writer ................ Philip Sloss
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.                                        WPJ.INI
  177.                                     By Pete Davis
  178.  
  179.                Another month, another  issue. We  didn't do  an issue  last
  180.           month because we didn't have enough articles early enough, but it
  181.           gave us a chance to collect a lot of articles for this issue plus
  182.           a few for  next month's issue.  That should give  us a good  head
  183.           start.
  184.  
  185.                This month you'll notice a survey accompanying the magazine.
  186.           We're considering putting the magazine in print. Through the help
  187.           of  a publishing company, this  may very well  happen. That would
  188.           mean some major  changes which I  want to get  out into the  open
  189.           right away.
  190.  
  191.                First of all, yes, the magazine would cost money. What would
  192.           that money get you? It would get  you 12 issues a year of a great
  193.           magazine. Mike and I would be doing this for a living. That means
  194.           that the articles  would undergo serious  editing, code and  text
  195.           would  be checked and double-checked. We'd have time to make sure
  196.           everything is right.  At the moment,  Mike and  I are doing  this
  197.           part time and can barely  afford to spend more than a few hours a
  198.           month to work on the magazine.
  199.  
  200.                In our current form,  it's almost impossible to do  any real
  201.           editing.  Why?  Well, we  can't pay  the  authors, and  it's hard
  202.           enough  to get articles. If we made it difficult, people wouldn't
  203.           write for us.  Paying the authors  would fix that.  We'd also  be
  204.           able  to  get  some of  the  big  names  out there,  like  Andrew
  205.           Schulman, Matt Pietrek, etc.
  206.  
  207.                What wouldn't change? One  of our hottest areas is  help for
  208.           beginners.  As long  as  I ever  have  anything to  do with  this
  209.           magazine,  that won't  change. We  will always  be a  place where
  210.           beginners can  turn for information  and help. We'd  also provide
  211.           the  more advanced articles  that we've  been providing  over the
  212.           past 6 issues. 
  213.  
  214.                Going into print would also allow us to reach a much broader
  215.           audience than we reach now. We'd be able to get to the people who
  216.           can't or haven't found us online.
  217.  
  218.                People  who subscribe prior to  the first printed issue will
  219.           get a discount of about 25% off the regular  subscription rate of
  220.           around $25.  These numbers might change since we're still working
  221.           out the details.
  222.  
  223.                We're hoping  you will all  go for  this. In all  honesty, I
  224.           don't  know how long  the magazine would  be able  to survive for
  225.           free. Mike  and I  both do  a several things  for a  living. That
  226.  
  227.                                         - 4 -
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.           doesn't leave much time  to work on  the magazine and things  are
  236.           only getting worse. If we could make our living off the magazine,
  237.           we  could devote all of  our time to it, which  we'd both like to
  238.           do.
  239.  
  240.                 Anyway, fill out  the survey and  send it to  my userid  on
  241.           CompuServe, the Internet, or via regular mail. Next month we will
  242.           draw a name  from all the people  who responded. The  winner will
  243.           get a choice between:
  244.  
  245.            - The "Win32 Reference" manuals (a 5-book set)
  246.  
  247.            - A combo of  the "Windows API Bible", "Windows  Internals", and
  248.           "Undocumented Windows"
  249.  
  250.            - The Windows NT Resource Kit
  251.  
  252.  
  253.                Send the response to me at:
  254.  
  255.           CompuServe: 71644,3570
  256.           Internet: 71644.3570@compuserve.com
  257.  
  258.           or regular mail to:
  259.  
  260.           WPJ Survey
  261.           9436 Mirror Pond Dr.
  262.           Fairfax, Va. 22032  U.S.A.
  263.  
  264.                We look forward to getting your responses. 
  265.  
  266.                Peace.
  267.  
  268.            
  269.              _Pete Davis
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.                                         - 5 -
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.                                        Letters
  296.  
  297.           Date:  22-Jun-93 09:10 EDT
  298.           From:  Scott Guthrie [100060,471]
  299.           Subj:  Install Program Prob with In use DLL's
  300.  
  301.           Mike and Pete,
  302.  
  303.                I  just today downloaded issues  2-5 of your  Journal, and I
  304.           must  say I'm impressed.  Unfortunately, you seem to have ditched
  305.           the Install program for  a  variety of reasons, only one of which
  306.           I  may  know the  answer to.    Microsoft provides  an exportable
  307.           function   in  the   USER.EXE  module   of  Windows   3.1  called
  308.           ExitWindowsExec which  will exit  Windows and run  the executable
  309.           indicated  in the  call and  then  (when the  executable releases
  310.           control of the  processor) RESTARTS Windows.   The executable  it
  311.           runs can  include up  to a 128  byte Path and  file name,  and an
  312.           additional  128   bytes  of  parameters,  switches,   etc.    The
  313.           documentation  I have  read for  this function  says that  it was
  314.           included  in  Win3.1  precisely  for  the  use  of  SETUP/INSTALL
  315.           programs to use when  they need to modify code that  is currently
  316.           in  use by Windows (e.g., DLLs).   Sorry I wasn't quicker off the
  317.           mark on this, but I'm not even sure it is going to help you, as I
  318.           haven't been able to get it to work precisely as advertised.
  319.  
  320.                                         Cheers,
  321.                                              Scott Guthrie
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.                                         - 6 -
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.                                   Beginner's Column
  356.                                    By Dave Campbell
  357.  
  358.  
  359.                Let's see, I know I've got  some code here that will show me
  360.           how
  361.           to put a dialog box into a DLL...no, not that file. Ok, ok, unzip
  362.           that entire  disk with a -v  option into a file,  and just search
  363.           the thing. Oh, no! Guess I must have dumped it.
  364.  
  365.                I sure hate it when  I do that, don't you? Me too.  And this
  366.           month,  since I want  to follow up  on my promise  of putting the
  367.           file open  dialog box  into a DLL,  I had  to redo  it. But  that
  368.           wasn't all bad, since I'm going to explain it anyway.
  369.  
  370.                The  end result of  this month's column is  going to be code
  371.           that runs identical to  that of last month, the  difference being
  372.           that some  of the code  no longer resides  in the executable.  To
  373.           accomplish this,  we are  going to  pull some  of  the code  from
  374.           Hello.EXE and put  it into  a dynamic link  library (DLL)  called
  375.           FileO.DLL. That's all there is to it. Now for next month...
  376.  
  377.  
  378.           DLL short-course
  379.                           
  380.                DLLs  many times  are very  complex pieces  of code,  and by
  381.           their very nature are reasonably tricky to program. That does not
  382.           mean we should be afraid to make use of  the power offered to us.
  383.           We just need to be careful when using them, and follow the rules.
  384.  
  385.                Most all of  us are  familiar with ".LIB"  files. These  are
  386.           very much like a collection of  ".OBJ" files that we can pull out
  387.           during the  building of our  file, and save  having to  write the
  388.           code again. These  LIBs may  be locally built,  and contain  code
  389.           personally  written,  or  may  be  third-party libraries  costing
  390.           hundreds  of dollars.  In  either case,  the  code from  the  LIB
  391.           becomes part  of your EXE file  after the build is  completed. If
  392.           you use the LIB for three different modules, you will have pieces
  393.           of that  LIB file in all three of your executables. That takes up
  394.           space on your hard disk, and also in memory at execution time.
  395.  
  396.                Execution time? Well,  maybe not in DOS, but what  if we had
  397.           written three TSRs and used a third-party library for some of the
  398.           functionality, and then loaded all three? It would be possible to
  399.           have, at run-time, three exact copies of the same code in memory.
  400.           Kinda wasteful, huh?
  401.  
  402.                I hope I'm not boring everyone, I'm simply trying to set the
  403.           stage for  the  power of  a  DLL. DLL  stands for  "Dynamic  Link
  404.           Library", and  as  the  name  implies, the  linking  takes  place
  405.  
  406.                                         - 7 -
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.           dynamically,  or at run-time. In  our TSR example  above, if DLLs
  416.           were  available to  us in  the DOS  world, only  one copy  of the
  417.           common code  would have  been needed,  thereby saving  disk space
  418.           because the EXE files would be smaller, and saving memory at run-
  419.           time because the common code would only be loaded once.
  420.  
  421.                That's  exactly what we get  with DLLs in Microsoft Windows.
  422.           When a call is made to a function in a DLL, Windows executes  the
  423.           function as if  the function  were local to  the window  running.
  424.           The previous sentence  is literally  correct, and is  one of  the
  425.           sticky parts of programming DLLs.
  426.  
  427.  
  428.           DS != SS
  429.                   
  430.                I have no intention of  digging into this at the depth  that
  431.           is available in much of the literature,  but I am going to try to
  432.           give an  explanation of what  DS !=  SS means, since  it is  used
  433.           quite often. The  primary thing to remember  is that DLLs  do not
  434.           have their  own stacks. The calling application's stack gets used
  435.           during  execution  of  the DLL.  This  is  a  problem because  of
  436.           near/far  references to  data. In  Windows programming,  all near
  437.           pointers are assumed to  be DS-relative. To avoid a  problem with
  438.           this,  either explicitly declare pointers to be FAR, or cast them
  439.           that way as they are used.
  440.  
  441.  
  442.           Hello.C
  443.                  
  444.                First let's take a look at Hello.C. There's been quite a bit
  445.           of code removed,  and a little  added in. I  want to discuss  the
  446.           additions first.
  447.  
  448.                In the include  section of  Hello.C, a #include  of the  new
  449.           "fileo.h" was  added. This is necessary  because some definitions
  450.           that were in Hello.H  are now residing in  FileO.H, and our  file
  451.           needs information about it. Almost any DLL that you will be using
  452.           from a third-party vendor will have a DLL  included that you will
  453.           have to  link with. Normally the DLL  will have the prototypes of
  454.           the functions to call, and any data definitions, or messages that
  455.           could be passed.
  456.  
  457.                Next  in the global definition area, we define a HANDLE type
  458.           named "hFileo". This will be used to identify the DLL after it is
  459.           loaded by our program.
  460.  
  461.           HANDLE hFileo;
  462.  
  463.                Next, a  prototype was added for  "DoFileOpenDlg". This will
  464.           be the launch point to get into the DLL to use the dialog  box we
  465.  
  466.                                         - 8 -
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.           created two months ago:
  476.  
  477.           void DoFileOpenDlg(void);
  478.  
  479.                WinMain now contains the following code:
  480.  
  481.           hFileo = LoadLibrary("FILEO.DLL");
  482.           if (hFileo < 32)
  483.              {
  484.              FreeLibrary(hFileo);
  485.              MessageBox(GetFocus(),"Dynamic Link Library FILEO.DLL must be
  486.                         present", szAppName, MB_ICONEXCLAMATION |MB_OK);
  487.              return 0;
  488.              }
  489.  
  490.                This  is the code that loads (possibly) the DLL into memory.
  491.           I say possibly because  if Windows finds the DLL  already loaded,
  492.           the currently loaded  copy is  used. If the  load is  successful,
  493.           LoadLibrary will return a value greater than or equal to 32. This
  494.           magic  number is HINSTANCE_ERROR, and any return value of this or
  495.           lower is  an error. On error,  we report the reason  to the user,
  496.           and exit.
  497.  
  498.                Before we  exit our WinMain, we must free up the DLL. We are
  499.           only concerned with cleaning up after ourselves. Windows will not
  500.           allow the DLL  to be removed if others are  using it. That's what
  501.           makes the system so nice to use:
  502.  
  503.           FreeLibrary(hFileo);
  504.  
  505.                WndProc is clean until we get to "case IDM_FILEOPEN":
  506.  
  507.           case IDM_FILEOPEN :
  508.                DoFileOpenDlg();
  509.                lstrcpy(OutMsg, szFileName);
  510.                break;
  511.  
  512.                Instead  of calling the dialog box procedure as we have done
  513.           in the  past, we are now  calling a local procedure  that will do
  514.           that work  for us.  The code  could  have been  inserted at  this
  515.           point, but for  ease of reading, and comparison, it is cleaner to
  516.           have it be isolated.
  517.  
  518.                A  change has been made in  the reporting of the filename in
  519.           that  it  is  transfered  locally  through  the  global  variable
  520.           "szFileName". That will become clear shortly:
  521.  
  522.  
  523.           DoFileOpenDlg
  524.                        
  525.  
  526.                                         - 9 -
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.                This procedure is new to Hello, and as I said  above, is the
  536.           launcher for the  DLL function.  The mystery takes  place in  the
  537.           first variable declared:
  538.  
  539.           FARPROC lpfnFileOpenDlgProc = 
  540.                                 GetProcAddress(hFileo,"FileOpenDlgProc");
  541.  
  542.                This  declares a far pointer  to a function  inside the DLL.
  543.           GetProcAddress retrieves that pointer for us by  name, given that
  544.           we know  the handle for the  DLL. We know that  because we loaded
  545.           it, "hFileo".  We also know the  function name "FileOpenDlgProc",
  546.           because we wrote that function two months ago. It just happens to
  547.           be  external  to  our program  at  this  point.  To execute  that
  548.           function, we do the following:
  549.  
  550.           (*lpfnFileOpenDlgProc)();
  551.  
  552.                The  file name selected  will be passed  back via Hello.INI,
  553.           and we retrieve that into szFileName, to be used above:
  554.  
  555.           GetPrivateProfileString("FileO", "FileName",
  556.                                   "NoName", szFileName, 128, "Hello.ini");
  557.  
  558.                The remainder of  Hello.C is identical to the  previous code
  559.           with the exception of the Fileo.C portions removed.
  560.  
  561.  
  562.           Hello.DLG
  563.                    
  564.                Hello.DLG is now split  between Hello.DLG and Fileo.DLG, but
  565.           nothing is added or removed, other than the split.
  566.  
  567.  
  568.           Hello.H
  569.                  
  570.                Hello.H is split between Hello.H and Fileo.H.
  571.  
  572.  
  573.           Hello.DEF
  574.                    
  575.                Hello.DEF  is identical to before with  the exception of the
  576.           exported FileOpenDlgProc function being removed.
  577.  
  578.  
  579.           FILEO
  580.                
  581.                Fileo is a simple  DLL and contains the primary  pieces that
  582.           every DLL contains:
  583.  
  584.                                    LibMain and WEP
  585.  
  586.                                         - 10 -
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.                To simplify some of  our code, and avoid any  nastiness that
  596.           may take  away from the simplicity, static variables were defined
  597.           for  the filename and extension, and declared in the beginning of
  598.           the Fileo code:
  599.  
  600.           static HANDLE hInst;
  601.           static char szFileName[128];
  602.           static char szFileSpec[16] = "*.EXE";
  603.           static char szDefExt[5]    = "EXE";
  604.           static WORD wFileAttr      = DDL_DRIVES | DDL_DIRECTORY;
  605.  
  606.  
  607.           LibMain
  608.                  
  609.                The  LibMain function is called by LibEntry, which is called
  610.           by  Windows when  the  DLL is  loaded.  The LibEntry  routine  is
  611.           provided  in the  LIBENTRY.OBJ module.  LibEntry initializes  the
  612.           DLL's heap (if a HEAPSIZE value is specified in the DLL's module-
  613.           definition file) before calling the LibMain function.
  614.  
  615.                This simply unlocks  the data segment of  the library (which
  616.           is locked by the LocalInit call in LIBENTRY) and returns 1.
  617.  
  618.           int FAR PASCAL LibMain (HANDLE hInstance, WORD wDataSeg, 
  619.                                   WORD wHeapSize, LPSTR lpszCmdLine)
  620.           {
  621.           if (wHeapSize > 0)
  622.              UnlockData(0);
  623.  
  624.           hInst = hInstance;
  625.  
  626.           return 1;
  627.           }
  628.  
  629.                LibMain is  the place to  allocate any memory  necessary for
  630.           use in the DLL, and to do any setup functions.
  631.  
  632.  
  633.           WEP
  634.              
  635.                WEP  is  called by  Windows when  the  DLL is  released, and
  636.           provides a place for us to  do cleanup before exiting. In Windows
  637.           3.1, WEP  is no longer necessary,  but if we are  trying to write
  638.           DLLS to be globally useful, WEP should be included.
  639.  
  640.           int FAR PASCAL WEP (int bSystemExit) {
  641.           /*---------------------------------------------------------------
  642.             get rid of things you allocated in the LibMain proc here
  643.           ---------------------------------------------------------------*/
  644.  
  645.  
  646.                                         - 11 -
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.           return TRUE;
  656.           }  /* WEP */
  657.  
  658.  
  659.                In the case of Fileo, WEP has no functionality.
  660.  
  661.           Fileo Code
  662.                     
  663.                The  code  body  for  Fileo consists  of  the  two functions
  664.           "lstrchr"  and  "FileOpenDlgProc"  from  the  old  Hello.C  file.
  665.           "lstrchr" has no changes at all, and was simply copied here.
  666.  
  667.  
  668.           FileOpenDlgProc
  669.                          
  670.                This function  was stripped  straight from the  old Hello.C,
  671.           modified slightly, and renamed  "DoFileOpenDlgProc". It no longer
  672.           attempts  to open the file  selected, the name  is simply shipped
  673.           back to Hello.C via an ini file, "Hello.INI"
  674.  
  675.                This is all accomplished  through the one exported function,
  676.           "FileOpenDlgProc"
  677.  
  678.  
  679.           FileOpenDlgProc
  680.                          
  681.                This function is small,  and consists of the lines  from the
  682.           old Hello.C WndProc switch case:
  683.  
  684.           lpfnDoFileOpenDlgProc = 
  685.                                  MakeProcInstance(DoFileOpenDlgProc,
  686.           hInst);
  687.  
  688.           DialogBox(hInst, "FILEOPEN", GetFocus(), lpfnDoFileOpenDlgProc);
  689.           FreeProcInstance(lpfnDoFileOpenDlgProc);
  690.  
  691.           followed by the Hello.INI write of the filename:
  692.  
  693.           WritePrivateProfileString("FileO",     "FileName",    szFileName,
  694.           "Hello.ini");
  695.  
  696.  
  697.           Fileo.DEF
  698.                    
  699.                The  DEF file will be recognizable, and has few changes from
  700.           the  EXE DEF  file.  As  explained  above,  there  is  no  stack,
  701.           therefore no  STACKSIZE. WEP  must be  exported,  and our  single
  702.           exported function "FileOpenDlgProc" is there:
  703.  
  704.           LIBRARY     FileO
  705.  
  706.                                         - 12 -
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.           DESCRIPTION 'FileOpen DLL'
  716.  
  717.           EXETYPE     WINDOWS
  718.  
  719.           STUB        'WINSTUB.EXE'
  720.  
  721.           CODE        MOVEABLE PRELOAD
  722.           DATA        MOVEABLE PRELOAD SINGLE
  723.  
  724.           HEAPSIZE    8192
  725.  
  726.           EXPORTS     WEP                 @1 RESIDENTNAME
  727.                       FileOpenDlgProc
  728.  
  729.  
  730.           Fileo.mak
  731.                    
  732.                The make  file  is cryptic  as ever,  but recognizable.  The
  733.           changes are few, and easy to spot.
  734.  
  735.                Amazingly enough, that's all there is to writing and using a
  736.           very simple DLL. I've glossed over many of the  nasties, and have
  737.           purposefully avoided others.  The bottom  line is we  have a  DLL
  738.           that's useable and easy to read.
  739.  
  740.  
  741.           Make Files
  742.                     
  743.                I  am providing 3 make  files with this  code. HELLO.MAK and
  744.           FILEO.MAK are the Borland make files for Hello.EXE and Fileo.DLL.
  745.           MHELLO.MAK is the  Microsoft make  file for Hello.EXE.  Try as  I
  746.           may, I could  not produce a working  make file for Microsoft  for
  747.           FILEO.DLL. The  Hello.EXE that  I produce with  either make  file
  748.           works with the Fileo.DLL I produce from Borland, but I ran out of
  749.           ideas  trying to produce a make file for Microsoft for Fileo.DLL.
  750.           So,  the proof is left to  the student. The first  one to send me
  751.           one that works gets mentioned here next month.
  752.  
  753.  
  754.           ICONS
  755.                
  756.                Did you  really think I was  going to leave and  not mention
  757.           last  month's program?  Unfortunately,  I was so  late getting my
  758.           article in that I ran the magazine late, and my "Go Suns" hit the
  759.           streets after the  Bulls took the third  in a row.  Oh  well, the
  760.           idea still stands. Animated icons is something we don't see a lot
  761.           of in Microsoft Windows. Building all the icon images is probably
  762.           the reason  why. I  was going  to take  a shot  at doing a  sweep
  763.           second-hand  clock,  and  got bored  after  15  seconds worth  of
  764.           images.
  765.  
  766.                                         - 13 -
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.                  
  778.                The work for the  animated icons starts in WinMain,  where a
  779.           timer
  780.           is started:
  781.  
  782.           SetTimer(hWndMain, ID_TIMER, 500,
  783.                       MakeProcInstance((FARPROC)TimerProc, hInst));
  784.  
  785.                Windows allows  up to 16  timers to be running  at any given
  786.           time.   Normally, SetTimer would  be checked for  a return value,
  787.           and if  the value  is  NULL, display  a  message about  too  many
  788.           timers.
  789.  
  790.                The first  parameter  is  the handle  to  the  window  whose
  791.           procedure will receive the WM_TIMER messages.
  792.  
  793.                The second parameter is  the timer ID, to identify  which of
  794.           16 possibles you now have running.
  795.  
  796.                The third parameter is a word  specifying the timer interval
  797.           in milliseconds (1-65535). In our case, this is 500 msec, or  1/2
  798.           second.
  799.  
  800.                The fourth parameter is the instance handle of this window.
  801.  
  802.  
  803.           InitInstance
  804.                       
  805.                Inside InitInstance, we now are loading an Icon, and this is
  806.           the "WPJ" icon that will show  on the group screen, and for short
  807.           periods of time when iconized:
  808.  
  809.           wc.hIcon          =  LoadIcon(hInstance, "WPJ");  /* Generic Icon
  810.           */
  811.  
  812.           and this value is saved in a global:
  813.  
  814.           hIconMain = wc.hIcon;
  815.  
  816.  
  817.           WndProc
  818.                  
  819.                The WM_PAINT message handler is  altered to handle the  icon
  820.           painting:
  821.  
  822.              case WM_PAINT :
  823.                 if (IsIconic(hWnd))
  824.                    {
  825.  
  826.                                         - 14 -
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.                    BeginPaint(hWnd, &ps);
  836.  
  837.           /*---------------------------------------------------------------
  838.             Erase the background of the window with what's on the desktop.
  839.             This is so the desktop bitmap will show through the transparent
  840.             areas of the icon. 
  841.           ---------------------------------------------------------------*/
  842.  
  843.                    DefWindowProc(hWnd,   WM_ICONERASEBKGND,   (WORD)ps.hdc,
  844.           0L);
  845.  
  846.           /*---------------------------------------------------------------
  847.             Now draw the icon. 
  848.           ---------------------------------------------------------------*/
  849.                    DrawIcon(ps.hdc, 0,0, hIcon);
  850.                    EndPaint(hWnd, &ps);
  851.                    }
  852.  
  853.                Notice that the icon  drawn is passed by the  generic handle
  854.           "hIcon". This will  allow us to change the icon  image inside the
  855.           Timer proc.
  856.  
  857.                One more thing needs to be done inside WndProc, and that  is
  858.           how  to  handle  the  icon when  it  is  dragged  on the  screen.
  859.           Fortunately,  Windows  sends  a  message  while  in  that  state,
  860.           WM_QUERYDRAGICON:
  861.  
  862.              case WM_QUERYDRAGICON:
  863.                 return((LONG)(WORD)hIconMain);
  864.  
  865.                Consequently,  when our  WndProc receives  that message,  we
  866.           return the default "WPJ" icon, for the duration of the drag.
  867.  
  868.  
  869.           TimerProc
  870.                    
  871.                The only function our timer proc does in this application is
  872.           toggle the two bitmaps GO.ICO and SUNS.ICO:
  873.  
  874.           BOOL FAR  PASCAL TimerProc(HWND hWnd, WORD  message, WORD wParam,
  875.           LONG lParam)
  876.           {
  877.           static BOOL which = 0;
  878.  
  879.           if (IsIconic(hWnd))
  880.              {
  881.              if (which = !which)
  882.                 {
  883.                 hIcon = LoadIcon(hInst, "GO");
  884.                 InvalidateRect(hWnd, NULL, FALSE);
  885.  
  886.                                         - 15 -
  887.  
  888.  
  889.  
  890.  
  891.  
  892.  
  893.  
  894.  
  895.                 SendMessage(hWndMain, WM_PAINT, NULL, NULL);
  896.                 }
  897.              else
  898.                 {
  899.                 hIcon = LoadIcon(hInst, "SUNS");
  900.                 InvalidateRect(hWnd, NULL, FALSE);
  901.                 SendMessage(hWndMain, WM_PAINT, NULL, NULL);
  902.                 }
  903.              }
  904.           }
  905.  
  906.                Depending on the entry value of the static variable "which",
  907.           one  of the two icons is loaded,  and the entire window (the icon
  908.           area)  is invalidated for painting, and a  message is sent to our
  909.           own WndProc to execute  the WM_PAINT command, which we  know from
  910.           above will repaint the icon.
  911.  
  912.  
  913.           Why
  914.              
  915.                All of this is entertaining, sort of, but not useful. I have
  916.           simply shown how  a timer works,  and tried to  take some of  the
  917.           mystery out by doing something stupid.
  918.  
  919.                What  if,  instead of  painting icons  on  a timer,  we were
  920.           painting windows? And, what if those windows were over the top of
  921.           everything  else, so that on  a timer, the  screen would suddenly
  922.           get painted over.  Why that  sounds like a  screen-saver!   Well,
  923.           kinda-sorta. We wouldn't want to do  that on a hard timer, but it
  924.           is close. Close enough that, given enough time, there will be the
  925.           start of a series in the next issue called "Screen Savers Inside-
  926.           Out". One more mystery unfurled.
  927.  
  928.  
  929.           EndDialog
  930.                    
  931.                That's about  all there is  to say  about the code  for this
  932.           month.   Unless  something changes,  I'm going to  discuss common
  933.           dialogs and show how to do all this the easy way next time.  Feel
  934.           free  to contact me in any of the ways below.  Thanks to those of
  935.           you that have e-mailed me questions, keep them coming.  
  936.  
  937.           Dave Campbell 
  938.              WynApse PO Box 86247 Phoenix, AZ 85080-6247 (602)863-0411    
  939.              wynapse@indirect.com
  940.              CIS: 72251,445
  941.              Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum
  942.  
  943.  
  944.  
  945.  
  946.                                         - 16 -
  947.  
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.                                      Book Review
  956.               Title: Windows Programmer's Guide to Serial Communications
  957.                                Author: Timothy S. Monk
  958.                               Publisher: SAMS Publishing
  959.                                   By David Falconer
  960.  
  961.           Book Details:
  962.           ISBN 0-672-30030-3
  963.           Includes Software Disk.
  964.           $39.95 USA
  965.  
  966.                I have been searching for ages for a book which would  teach
  967.           me how to do Comms programming in Windows.  Judging by the amount
  968.           of questions in the Borland Windows forum on Compuserve, I am not
  969.           alone  in this quest.   The book  that seems to  be most commonly
  970.           recommended  is Timothy  Monk's  "Windows Programmer's  Guide  to
  971.           Serial Communications", so  I bought a  copy to see  what it  was
  972.           like.
  973.  
  974.                Perhaps I should  explain a little about me, so  you have an
  975.           idea of the role the book was intended to play.  I'm not a novice
  976.           programmer,  but not that experienced either, and I'm very new to
  977.           Windows programming.   Having worked  my way  through Petzold,  I
  978.           decided I was ready to tackle Comms, which is what I wanted to do
  979.           in the first place!   Also, I learn best by  trial and error, and
  980.           was looking for  something to get me started and  that would also
  981.           act as  a reference later  on.   I have not  started putting  the
  982.           knowledge  I have  obtained from  this book  into practice  yet -
  983.           priorities change - but I thought I would share what it's like as
  984.           a primer.
  985.  
  986.                Firstly, this  is not a  primer for  Windows programming  in
  987.           general.  As a novice,  I often found myself with Monk's  book in
  988.           one hand  and Petzold  in the other,  but the  Monk does  provide
  989.           little  snippets  of  basic  stuff that  Petzold  doesn't  cover;
  990.           connecting an application to a help file, for example.  The other
  991.           assumption  that is made is  that you have  some familiarity with
  992.           DOS serial Comms - at least the terms used.
  993.  
  994.                The  book is laid out  in 7 chapters  and 3 appendices, over
  995.           the  course of which you  develop a fully  working Comms program,
  996.           called  TSMTERM, starting with the very basics and ending up with
  997.           an XMODEM  file transfer  protocol implementation.   Each chapter
  998.           starts with an  overview of  what will be  covered, and  finishes
  999.           with  a  summary  of what  has  been achieved.    There  are code
  1000.           segments  everywhere, and these are  as much an  integral part of
  1001.           the text  as the writing  between them is;  often it is  from the
  1002.           code  that  you  find  exactly  how  a  particular  function,  or
  1003.           technique, is implemented.  Fortunately all  the code, plus fully
  1004.           compiled executables are provided  on the accomanying disk, which
  1005.  
  1006.                                         - 17 -
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.           saves on  a lot  of  typing!   Each time  the  code is  modified,
  1016.           advanced upon in the text, a completely new set of source code is
  1017.           provided on the disk.   This means a hefty 3 Megabytes  of memory
  1018.           is needed for the files, but it saves getting confused over which
  1019.           version of which bit of the program you should be working with at
  1020.           any one stage.  The areas that the chapters cover are:
  1021.  
  1022.           Chapter 1: Serial Communications
  1023.  
  1024.                This   chapter  contains   an  overview   of  serial   Comms
  1025.           procedures, starting  with the hardware;  the RS-232 link,  the 3
  1026.           UARTS commonly found on  the PC (8250/16450 and the  newer 16550)
  1027.           in  quite a  bit of detail  and finally  the COM  ports and their
  1028.           adresses  and interrupts.    Monk then  goes  on to  discuss  the
  1029.           principles  of   DOS  Comms  programming,  with   code  segments,
  1030.           including a look at ring buffers.  The final part  of the chapter
  1031.           discusses what is going to happen in the rest of the book, by way
  1032.           of a "design brief" for the TSMTERM program.
  1033.  
  1034.           Chapter 2: Windows Communications Basics.
  1035.  
  1036.                This is basically in two major sections.  In the first, Monk
  1037.           outlines  the 17  functions  of the  Windows Communications  API,
  1038.           which are fully documented in Appendix A, and shows how these can
  1039.           be used in  a typical  Comms session of  open port,  send/receive
  1040.           characters, close  port.  These  initial examples use  polling of
  1041.           the port in the main  message loop of the Windows application  as
  1042.           the  method  of  getting  information  from  the  port  into  the
  1043.           application.   Message-based methods, which were  introduced with
  1044.           Windows 3.1, crop up later.   In the second half of  the chapter,
  1045.           Monk creates  his own API  for use  with the TSMTERM  program, in
  1046.           order to simplify some  of the trickier aspects of using  the raw
  1047.           function calls.   These are then all encapsulated in a DLL.  This
  1048.           is done very matter-of-factly,  but the code for the  LibMain and
  1049.           WEP functions are provided and briefly explained.
  1050.  
  1051.           Chapter 3: Terminal Emulation
  1052.  
  1053.                Again,  this chapter  is in  two sections.   The  first part
  1054.           covers terminal emulations,  including the full specification  of
  1055.           an ANSI terminal,  which is then implemented in a  DLL.  There is
  1056.           also  a word about finite state machines, on which principles the
  1057.           ANSI emulation is based.   The second part starts  assembling the
  1058.           application from the  components created so far.   The processing
  1059.           of  the  basic Windows  messages is  covered,  as is  the Windows
  1060.           procedure, although this is of quite a complex variety,  covering
  1061.           menu commands  as well  as the  more  straight forward  messages.
  1062.           Knowledge  of Dialog Box methods are assumed, but I learned quite
  1063.           a lot about their implementation from studying the code.  This is
  1064.           a fully fledged application,  and so includes an "about"  box and
  1065.  
  1066.                                         - 18 -
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075.           interfaces  to  a  basic  help  file.    As  well  as  the   ANSI
  1076.           implementation, the  program also  allows the  user  to choose  a
  1077.           basic TTY emulation.
  1078.  
  1079.           Chapter 4: Errors, Events, and Flow Control
  1080.  
  1081.                The  good practice  of calling  GetCommError( )  after every
  1082.           read, write or  port poll is introduced  and TSMCOMM.DLL, created
  1083.           in chapter 2, is modified to include error processing.  A similar
  1084.           process is then gone through for communications events using  the
  1085.           GetCommEventMask(  ) function  and  its associates.   After  both
  1086.           modifications to the  DLL, the main application  is also modified
  1087.           to give  the user a choice  of how to monitor  errors and events.
  1088.           Finally there is a brief discussion of XON/XOFF and hardware flow
  1089.           control,  after  which both  methods  are  added to  TSMCOMM.DLL.
  1090.           Again the main application is modified to give  the user a choice
  1091.           of what to use.
  1092.  
  1093.           Chapter 5: Message-Based Communications
  1094.  
  1095.                In     Windows     3.1     Microsoft      introduced     the
  1096.           EnableCommNotification( )  function which  adds a new  message to
  1097.           the  Windows  system.   This  is  as  close as  Windows  gets  to
  1098.           interrupt driven  communications procedures, as the  Comms system
  1099.           is  interacted with in response to a received message rather than
  1100.           having to  be polled  in the  message loop.   Chapter 5  gives an
  1101.           overview of how this system  works and then adds the facility  to
  1102.           TSMCOMM.DLL, and modifies  the application to  give the user  the
  1103.           choice of system.
  1104.  
  1105.           Chapter 6: Modem Communications
  1106.  
  1107.                Chapter 6 starts with a look at where modems fit into serial
  1108.           communications systems.  The command set for Hayes modems is then
  1109.           examined  and a  modem  API is  implemented  in MODEM.DLL,  which
  1110.           includes setup,  dial  and hangup  routines.   A  modem  commands
  1111.           section is then  added to the main application.   As an extention
  1112.           of this, a dialing  directory is implemented, where the  user can
  1113.           store  the names of systems,  their phone numbers,  plus the port
  1114.           settings: Baud  rate, start, stop  and data bits.   This too,  is
  1115.           then added to the main program.
  1116.  
  1117.           Chapter 7: File Transfer
  1118.  
  1119.                To  enable the TSMTERM  program to  download files  from the
  1120.           bulletin  boards whose  numbers are stored  in the  newly created
  1121.           address  book,  Monk  adds   the  popular  XMODEM  file  transfer
  1122.           protocol.   The chapter starts with a discussion of the protocol;
  1123.           the  packet, error checking,  transmission, reception, errors and
  1124.           timeouts.  The protocol  is then implemented in another  DLL, and
  1125.  
  1126.                                         - 19 -
  1127.  
  1128.  
  1129.  
  1130.  
  1131.  
  1132.  
  1133.  
  1134.  
  1135.           has  options for using checksum  or CRC error  correction.  These
  1136.           functions are then added to  the main program.  Selection  of the
  1137.           file for transmission is  carried out by use of the Common Dialog
  1138.           Box "Open File",  so use of  this feature of  Windows 3.1 can  be
  1139.           followed by examining the source code.
  1140.  
  1141.           Appendix A: Windows Serial Communications API Reference
  1142.  
  1143.                As mentioned  above, this provides the  documentaion for the
  1144.           functions and  structures provided by Windows  for communications
  1145.           systems.   It includes the Windows 3.1 amendments and marks where
  1146.           the Window 3.1 implementation is different from 3.0.
  1147.  
  1148.           Appendix B: TSM Communications API Reference.
  1149.  
  1150.                This  provides a  full function  by function  description of
  1151.           Monk's own API, as used in the TSMTERM program.  It describes the
  1152.           functions created  throughout the book which  are in TSMCOMM.DLL,
  1153.           MODEM.DLL and XMODEM.DLL.   It is a useful summary  and reference
  1154.           section.
  1155.  
  1156.           Appendix C: ASCII Character reference.
  1157.  
  1158.                This is  a table in two  parts.  Part one  gives the decimal
  1159.           value, hex value,  display character and  description for all  of
  1160.           the 7  bit basic ASCII  characters.   Part two provides  the same
  1161.           information for the extra members of the extended PC set.
  1162.  
  1163.                I found the book helpful and  easy to follow.  The layout is
  1164.           a  bit strange, with funny bits of ornamentation around the edges
  1165.           of  the  pages, but  you  soon get  used  to it.    It  goes from
  1166.           communications basics  to quite an  advanced program in  only 413
  1167.           pages  (including the  appendices) so  it obviously  doesn't hang
  1168.           around  when  explaining  things to  make  sure  you  have got  a
  1169.           particular point.   But that's the nice thing about books; if you
  1170.           find you have missed  something, you can always  go back and  re-
  1171.           examine it.
  1172.  
  1173.                As a  practical introduction  to  Windows Communications,  I
  1174.           would heartily reccommend this book.  There may be others that do
  1175.           the job too, but if there are I haven't found them and what I see
  1176.           here, I like.
  1177.  
  1178.                I  confess that I haven't used the program, TSMTERM, and nor
  1179.           am I  likely to;  that's not  why I  bought the book.   I  wanted
  1180.           something that dissected a Windows Comms program, so I would know
  1181.           how to do it for myself, and that's what I seem to have got.   As
  1182.           I  mentioned at  the  outset,  my  own  project  has  been  "back
  1183.           burnered"  for a while,  but I have no  qualms about tackling the
  1184.           Comms aspect head on.
  1185.  
  1186.                                         - 20 -
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.                Dialog  boxes are another matter  though.  Ah  well, back to
  1196.           Petzold...
  1197.  
  1198.                The author can be reached on CompuServe at 100063,1205.
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240.  
  1241.  
  1242.  
  1243.  
  1244.  
  1245.  
  1246.                                         - 21 -
  1247.  
  1248.  
  1249.  
  1250.  
  1251.  
  1252.  
  1253.  
  1254.  
  1255.                                   Pascal in 21 Steps
  1256.                   (A Beginner's Column for Turbo Pascal for Windows)
  1257.                                     By Bill Lenson
  1258.  
  1259.  
  1260.                             Step Two - Divide and Conquer
  1261.  
  1262.           REVIEW
  1263.  
  1264.                Last  month we  talked about  how to  write a  simple Pascal
  1265.           program.  We showed you what variables and commands are.  We also
  1266.           covered basic data types  like integers, characters, and strings.
  1267.           Even  though  the  examples  where  quite simple  and  didn't  do
  1268.           anything  practical, the purpose of that  column was to introduce
  1269.           the basic program structure.
  1270.  
  1271.                This month we pick  up the pace quite a bit.   By the end of
  1272.           this column you should  be able to read input  from the keyboard,
  1273.           decide if the input is valid,  repeat actions over and over,  and
  1274.           break your code up  into chunks called functions and  procedures.
  1275.           All  this  and  we'll  even  show  you  how  to  write  a  simple
  1276.           calculator.
  1277.  
  1278.  
  1279.           KEYBOARD IN / SCREEN OUT
  1280.  
  1281.                Reading information from the keyboard is not that difficult.
  1282.           There  are some  tricks to it  though to  make your  life easier.
  1283.           Last  month you used the 'writeln' statement to write text to the
  1284.           screen.  To read text you use 'readln'.
  1285.  
  1286.                Readln (pronounced  'read line')  pauses  execution of  your
  1287.           program until you type something and press the <Enter>  key.  For
  1288.           example,
  1289.  
  1290.                                       Readln(s);
  1291.  
  1292.           lets you  type in some text  and when you press  <Enter>, puts it
  1293.           into the variable s.  s can be any data type  but some are better
  1294.           than others.  If  the s 'parameter' to the  readln 'procedure' is
  1295.           an integer then you are only allowed to enter numbers.  If it's a
  1296.           string type you  can enter anything. When I say  'only allowed to
  1297.           enter a number', I mean that you can type in  non-numbers but the
  1298.           program will crash  when you press <Enter>.  This  is bad. Let me
  1299.           illustrate.  Type in the following program.
  1300.  
  1301.           program Bad_Code;
  1302.           uses WINCRT;
  1303.           var
  1304.               num : integer;
  1305.  
  1306.                                         - 22 -
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.           begin
  1316.               readln(num);
  1317.               writeln(num);
  1318.           end.
  1319.  
  1320.                When you  run this program a window  will be created and the
  1321.           cursor  will flash.   Type  in the number  23 and  press <Enter>.
  1322.           Sure  enough, 23  gets  assigned to  the  num variable  and  gets
  1323.           displayed in  the  window by  the writeln(num)  statement.   Now,
  1324.           rerun the program  but type in Hello  and press <Enter>.   CRASH.
  1325.           Pascal tries to convert Hello into  an integer so it can store it
  1326.           into the num variable.   Since it doesn't know how  to do this it
  1327.           bombs.   It's a  poor  program that  lets the  user  crash it  so
  1328.           easily.   Try to make the  next program blow  up.  Bet  you can't
  1329.           (poor bet, there is a way but I'm not going to tell you how until
  1330.           next month).
  1331.  
  1332.           program Better_Code;
  1333.           uses WINCRT;
  1334.           var
  1335.               numstr : string;
  1336.           begin
  1337.               write('Please type a number and press <Enter> : ');
  1338.               readln(numstr);
  1339.               write('The number you typed was : ');
  1340.               writeln(numstr);
  1341.           end.
  1342.  
  1343.                No  matter what you type  in the program  spits it back onto
  1344.           the  screen.    The  only  thing limiting  in  this  code  is the
  1345.           programmer has no way to control what the user types.   You can't
  1346.           be sure the user types a number in the above example.  We'll show
  1347.           you how to do that in the next section.
  1348.  
  1349.           DECISIONS, DECISIONS
  1350.  
  1351.                Quite  often you  want  a program  to do  one  thing when  a
  1352.           certain  input is  typed in  and do  something else  when another
  1353.           thing is entered.   The most common way  to do this in  Pascal is
  1354.           the IF statement.
  1355.  
  1356.                Before I  show you the IF  statement, let me first  show you
  1357.           how  you can convert a number stored  as a string into an integer
  1358.           data type.   Why we  need to do  this will become  clear shortly.
  1359.           Try the following code.
  1360.  
  1361.           program String_2_Number;
  1362.           uses WINCRT;
  1363.           var
  1364.               numstr : string;
  1365.  
  1366.                                         - 23 -
  1367.  
  1368.  
  1369.  
  1370.  
  1371.  
  1372.  
  1373.  
  1374.  
  1375.               num    : integer;
  1376.               errcod : integer;
  1377.           begin
  1378.               write('Please type a number and press <Enter> : ');
  1379.               readln(numstr);
  1380.               val(numstr, num, errcod);
  1381.               writeln('The number you typed was : ', num);
  1382.                   { Notice  we combined  two write  statements into  one by
  1383.           passing }
  1384.                   { two parameters separated by a comma.                   
  1385.              } end.
  1386.  
  1387.  
  1388.                This  program is  similar to  those above  but if  you don't
  1389.           enter a  number a zero is  printed instead of what  you typed in.
  1390.           The val procedure tries to convert a string into a number, and if
  1391.           it can't it puts a zero in  num and a number greater than zero in
  1392.           the errcod parameter.
  1393.  
  1394.                Another thing to note  about the above program is  the stuff
  1395.           enclosed in { and }.  These are comments and allow the programmer
  1396.           to  describe what is happening in  the code.  All programs should
  1397.           have  comments that let other programmers (or yourself) look at a
  1398.           program and tell what the  code does.  You can put anything  in a
  1399.           comment as long as  it starts with a { and ends with  a }.  As an
  1400.           aside, sometimes  you'll see older Pascal  programs with comments
  1401.           that start  with a (* and  end in a *).   These work  too but the
  1402.           convention these days is to use the braces.
  1403.  
  1404.                I've  been talking for a while about numbers and strings and
  1405.           how  we want  a number but  we need  to enter  a string  and then
  1406.           convert it to a  number. What's all the hubbub about  numbers and
  1407.           strings?  Why not just  leave them as strings?  The  answer is in
  1408.           the operations you can do to different data types in Pascal.  For
  1409.           instance, you can't add two numbers together if they're stored in
  1410.           a  string.  Also, you can't concatenate  (stick one string on the
  1411.           end of another) two numbers together if they're stored in integer
  1412.           types.   Pascal is  a typed language meaning  that data is always
  1413.           stored in  variables of a certain  type.  Each type  has it's own
  1414.           set of built-in  operations.   Some string  operations convert  a
  1415.           string to  upper  case  letters  from lower  case,  extract  some
  1416.           characters from  the middle of  a string,  convert a string  to a
  1417.           number, and so on.  Most integer functions are math based such as
  1418.           adding  two numbers,  subtracting  two numbers,  multiplying  two
  1419.           numbers, and so on.
  1420.  
  1421.                This  section is  about Pascal  decision making  and program
  1422.           flow  control using  the  IF statement  so  let's give  a  simple
  1423.           example.
  1424.  
  1425.  
  1426.                                         - 24 -
  1427.  
  1428.  
  1429.  
  1430.  
  1431.  
  1432.  
  1433.  
  1434.  
  1435.           program Better_String_2_Number;
  1436.           uses WINCRT;
  1437.           var
  1438.               numstr : string;
  1439.               num    : integer;
  1440.               errcod : integer;
  1441.           begin
  1442.               write('Please type a number and press <Enter> : ');
  1443.               readln(numstr);
  1444.               val(numstr, num, errcod);
  1445.               if (errcod <> 0) then
  1446.                   writeln('ERROR: The number you entered was invalid.')
  1447.               else
  1448.                   writeln('The number you typed was : ', num);
  1449.           end.
  1450.  
  1451.  
  1452.                The IF statement needs only a little explanation.  First the
  1453.           '<>'  in  Pascal  means  'not  equal to'.    Also,  there  are no
  1454.           semicolon  (;)  before  else's  since  the  whole  if..then..else
  1455.           combination makes  a complete  statement and  last month  we said
  1456.           that semicolons only come at the end of a statement  (ugh!).  So,
  1457.           the above is  described as, 'If errcod is not  equal to zero then
  1458.           write  an  error message  else write  the  number entered  to the
  1459.           window'.
  1460.  
  1461.                In  the above,  the  stuff  (I  didn't  say  this  was  fine
  1462.           literature)  between  the   IF  and  the   THEN  is  called   the
  1463.           'condition'.  Conditions are  logical statements where we compare
  1464.           things.  The things  we compare are usually either  two variables
  1465.           or a variable  and a value  like we do  in the above code.  Let's
  1466.           assume we have two variables var1 and var2.  Some simple 'logical
  1467.           operations' we can do are:
  1468.  
  1469.           Logical Operation         Tests if...
  1470.           =================         =====================================
  1471.           (var1 <> var2)       ==>  var1 not equal to var2
  1472.           (var1 = var2)        ==>  var1 equals var2
  1473.           (var1 > var2)        ==>  var1 is greater than var2
  1474.           (var1 >= var2)       ==>  var1 is greater than or equal to var2
  1475.           (var1 < var2)        ==>  var1 is less than var2
  1476.           (var1 <= var2)       ==>  var1 is less than or equal to var2
  1477.  
  1478.                We'll use  logical operations with IF  statements many times
  1479.           in the  future so don't worry if they look a little strange right
  1480.           now.  Let's now move  on to see how we can  repeat something over
  1481.           and over.
  1482.  
  1483.  
  1484.           LOOPS
  1485.  
  1486.                                         - 25 -
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.                The  process  of repeating  something  in  Pascal is  called
  1496.           looping.  There are four  ways to loop but  only two of them  are
  1497.           commonly used, one seldom used and one is absolutely forbidden to
  1498.           be used.   The last two  will be covered at  a later time.   This
  1499.           section presents the first two: the FOR and WHILE loops.
  1500.  
  1501.                The  FOR loop repeats some  block of code  a fixed number of
  1502.           times.  Let's give a simple example:
  1503.  
  1504.           program For_loop;
  1505.           uses WINCRT;
  1506.           var
  1507.               x : integer;
  1508.           begin
  1509.               for x := 1 to 50 do
  1510.                   write('Hello ');
  1511.           end.
  1512.  
  1513.                This program writes 50  'Hello''s on the screen.   It's much
  1514.           simpler than typing out  50 write statements.  The  FOR statement
  1515.           is read  'for x equals  one to fifty  do write hello'.   In other
  1516.           words,  x is  assigned  the number  one.   The next  statement is
  1517.           executed (the write).   x is increased by one  and checked to see
  1518.           if it's greater than 50.  If it is, the FOR statement is finished
  1519.           and the statement after the write is executed.  If  it isn't, the
  1520.           write is executed  and then x is increased by  one and checked to
  1521.           see if  it's greater  than 50.   And so  on.   In other words  we
  1522.           repeat the write 50 times while  we increase x from 1 to 50.   On
  1523.           the 51st loop, the FOR is exited.
  1524.  
  1525.                Let's try another.
  1526.  
  1527.           program For_loop_2;
  1528.           uses WINCRT;
  1529.           var
  1530.               x : integer;
  1531.           begin
  1532.               for x := 1 to 10 do
  1533.                   writeln(x);
  1534.           end.
  1535.  
  1536.                This example loops  10 times  and writes the  contents of  x
  1537.           each time through the loop.  In  other words, the numbers 1 to 10
  1538.           are written on the screen. The starting number doesn't have to be
  1539.           1, we could have said:
  1540.  
  1541.               for x := 5 to 15 do
  1542.                   writeln(x);
  1543.  
  1544.           which would write the 10 numbers from 5 to 15 on the screen.
  1545.  
  1546.                                         - 26 -
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.                The WHILE loop  is a  little different.   WHILE will  repeat
  1556.           until some condition is met.  For example:
  1557.  
  1558.  
  1559.           program While_loop;
  1560.           uses WINCRT;
  1561.           var
  1562.               x : integer;
  1563.           begin
  1564.               x := 1;
  1565.               while (x <= 10) do begin
  1566.                   writeln(x);
  1567.                   x := x + 1;
  1568.               end;
  1569.           end.
  1570.  
  1571.                This program  acts just  like the For_loop_2  program above.
  1572.           In  it we assign the value one to  the x variable.  Next, while x
  1573.           is less than or equal to the value ten (it starts at one so it is
  1574.           less  than 10)  repeat  everything  between  the  begin  and  end
  1575.           statement.   What's between the begin and end is the meat of this
  1576.           WHILE loop.  In it we write the x variable to the screen and then
  1577.           we add one to x.  That adding one to x looks a little funny.   We
  1578.           say 'x is assigned  the value of x plus one.   In other words, we
  1579.           do the stuff on the right of the ':=' and then  put the result in
  1580.           the variable on the left of the ':='.  If we said 'x := x + 2' we
  1581.           would see every other number from 1 to 10 (i.e., 1, 3, 5, 7, 9).
  1582.  
  1583.                FOR  loops are often used  when we know  in advance how many
  1584.           times we  will be looping.   WHILE loops, on the  other hand, are
  1585.           used  when we  don't know how  many times  we'll be  looping.  In
  1586.           common programming practice, we would typically use FOR  loops to
  1587.           initialize array variables (a  future topic), or repeat something
  1588.           that never changes in the number of iterations.  WHILE loops  are
  1589.           commonly  used  for  reading input  from  users  or  files.   For
  1590.           example,  reading keyboard input  until the user  types some exit
  1591.           command the  program knows about.  We'll  illustrate each looping
  1592.           technique in more detail next month.
  1593.  
  1594.  
  1595.           HINDSIGHT is 20-20 in PASCAL
  1596.  
  1597.                Before  we dive  into a  larger program,  I thought  I would
  1598.           point  something  out  about  Pascal that  beginners  must  know.
  1599.           Statements in Pascal cannot see things written  after the current
  1600.           line.   On  the flip side  of the  coin, statements  can only see
  1601.           things in the code  that occur on lines  previous to the  current
  1602.           one.  In  other words, when the compiler compiles  your code into
  1603.           machine language, it starts at the top and remembers each line as
  1604.           it comes across it.  This is while variables are  declared BEFORE
  1605.  
  1606.                                         - 27 -
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615.           they  are  used. In  the future  you'll  see that  procedures and
  1616.           functions must be made before they are used.  As an example:
  1617.  
  1618.           var
  1619.               x : integer;
  1620.           begin
  1621.               x := 3;
  1622.               y := 27;
  1623.           ...
  1624.  
  1625.                The x:=3 works  because x  has been declared  as an  integer
  1626.           before it was used.  The y:=27 causes  a compile error because  y
  1627.           has not been declared yet.  It may be declared some time later in
  1628.           the program but that would be too late.
  1629.  
  1630.                Why I'm bringing this up now is it should help  a little bit
  1631.           when we take  a look at procedures and functions.   For now, just
  1632.           declare variables in the var section before you use them in code.
  1633.  
  1634.  
  1635.           THE CALCULATOR - ATTEMPT #1
  1636.  
  1637.                Let's  take a little break from learning the language to try
  1638.           to apply what we've  learned up until  now.  The  best way to  do
  1639.           that is by writing an example program.  From past experience, the
  1640.           quickest  way to  learn  a language  (or a  new  language) is  by
  1641.           writing  example programs.  You  must type these  programs in and
  1642.           test them for yourselves for maximum learning benefit.
  1643.  
  1644.                In this section  we'll try to build a simple calculator.  It
  1645.           won't do a heck of a lot but I'm sure it  will make understanding
  1646.           of the language easier.   OK, so what's this  calculator supposed
  1647.           to do?  The first  thing is it should ask the user  for a number,
  1648.           an operation to  perform, and  then another number.   Once  these
  1649.           have  been entered,  the program will  spit out the  answer.  The
  1650.           operations  it can  perform  are addition  (+), subtraction  (-),
  1651.           multiplication (*  ), and division (/).   One catch to  watch out
  1652.           for is  division.  You  don't want the  user dividing by  zero as
  1653.           this  is an  error and  will cause  your program  to crash.   You
  1654.           therefore  need to print an error message yourself if they try to
  1655.           divide by zero.
  1656.  
  1657.                Overwhelmed?   Don't  worry.   There  are  ways to  look  at
  1658.           problems  and break them down into smaller problems that are more
  1659.           manageable.  Let me show you the program and I'll explain what it
  1660.           does.
  1661.  
  1662.  
  1663.           program Calculator_Number_1;
  1664.           uses WINCRT;
  1665.  
  1666.                                         - 28 -
  1667.  
  1668.  
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674.  
  1675.           var
  1676.               numstr1   : string;
  1677.               numstr2   : string;
  1678.               operation : string;
  1679.               num1      : integer;
  1680.               num2      : integer;
  1681.               errcod    : integer;
  1682.           begin
  1683.               writeln('Calculator Example #1');
  1684.               writeln;
  1685.               write('Please type a number and press <Enter> : ');
  1686.               readln(numstr1);
  1687.               write('Please enter the operation  to perform (+, -, *,  /) :
  1688.           ');
  1689.               readln(operation);
  1690.               write('Please type a number and press <Enter> : ');
  1691.               readln(numstr2);
  1692.               val(numstr1, num1, errcod);
  1693.               val(numstr2, num2, errcod);
  1694.               if (operation = '+') then
  1695.                   writeln('Answer: ', num1+num2)
  1696.               else
  1697.                   if (operation = '-') then
  1698.                       writeln('Answer: ', num1-num2)
  1699.                   else
  1700.                       if (operation = '*') then
  1701.                           writeln('Answer: ', num1*num2)
  1702.                       else
  1703.                           if (operation = '/') and (num2 <> 0) then
  1704.                               writeln('Answer: ', num1 div num2)
  1705.                           else
  1706.                               writeln('Error in input.  Program ending.');
  1707.           end.
  1708.  
  1709.  
  1710.                You should be able  to read through this program if you take
  1711.           it slowly line by  line.  The  first thing we  do is declare  all
  1712.           necessary variables. Then we ask the user for  each number and an
  1713.           operation.  The user must press <Enter> after each input.   Next,
  1714.           we  convert the number strings to integers. Notice we don't check
  1715.           for an  error  in  converting  the number  strings,  numstr1  and
  1716.           numstr2.  We don't care what they enter.  If they enter something
  1717.           invalid  the integer  we get  from the  conversion is  just zero.
  1718.           It's left as an exercise for the reader to put in  checks to test
  1719.           for  invalid entries, report  the problem  and exit  the program.
  1720.           TIP: You might want to look up the  HALT procedure if you want to
  1721.           try this exercise.
  1722.  
  1723.                OK, after the numbers are converted we perform the series of
  1724.           IF  statement tests to perform the  appropriate operation.  Check
  1725.  
  1726.                                         - 29 -
  1727.  
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.           out the last test for division.  The condition statement in  that
  1736.           if has two conditions: (operation = '/') and (num2  <> 0).  If we
  1737.           were  to  read  the last  IF  statement,  it  would be  described
  1738.           something  like: 'if the operation is division and the num2 isn't
  1739.           0  then write the  answer, else write  an error  message'.  Words
  1740.           like  'and' which separate  conditions will be  discussed in more
  1741.           detail in upcoming months columns.
  1742.  
  1743.                The programs are starting to look a little messy and I'm not
  1744.           using any comments (a bad habit but it won't help you to learn if
  1745.           I  always tell you what I'm doing).   We need to tidy things up a
  1746.           bit.
  1747.  
  1748.  
  1749.           PROCEDURES
  1750.  
  1751.                A  typical Windows  program  can be  several thousand  lines
  1752.           long.  If we have one big mainline, things will get beyond messy.
  1753.           Can  you imagine  thousands of statements  between one  begin and
  1754.           end?  I  can't.  Programmers get around this  problem by breaking
  1755.           up the code  into chunks and giving a name to  each piece.  These
  1756.           'chunks' are called procedures and functions.
  1757.  
  1758.                Suppose  the mainline  of the  calculator program  above was
  1759.           written as:
  1760.  
  1761.           begin
  1762.               Display_Title;
  1763.               Get_Inputs;
  1764.               Convert_Strings_to_Numbers;
  1765.               Display_Calculations;
  1766.           end.
  1767.  
  1768.                Isn't this  a little more intuitive?   All we need  to do is
  1769.           tell  the program  what each of  these procedures does.   This is
  1770.           simple in this case.  We simply take the groups of code that goes
  1771.           with each procedure and presto.
  1772.  
  1773.                Here's the next calculator.  Notice it's a little bigger but
  1774.           it's  also broken up into nice manageable sections.  Also notice,
  1775.           the procedures  are written  after the variable  declarations but
  1776.           before  the mainline.   This  way, the  procedures can  'see' the
  1777.           variables because they're declare before it, and the mainline can
  1778.           'see' the procedures because they're declared before it.
  1779.  
  1780.  
  1781.           program Calculator_Number_1;
  1782.           uses WINCRT;
  1783.           var
  1784.               numstr1   : string;
  1785.  
  1786.                                         - 30 -
  1787.  
  1788.  
  1789.  
  1790.  
  1791.  
  1792.  
  1793.  
  1794.  
  1795.               numstr2   : string;
  1796.               operation : string;
  1797.               num1      : integer;
  1798.               num2      : integer;
  1799.               errcod    : integer;
  1800.  
  1801.               procedure Display_Title;
  1802.               begin
  1803.                   writeln('Calculator Example #1');
  1804.                   writeln;
  1805.               end;
  1806.  
  1807.               procedure Get_Inputs;
  1808.               begin
  1809.                   write('Please type a number and press <Enter> : ');
  1810.                   readln(numstr1);
  1811.                   write('Please enter the operation to perform (+, -, *, /)
  1812.           : ');
  1813.                   readln(operation);
  1814.                   write('Please type a number and press <Enter> : ');
  1815.                   readln(numstr2);
  1816.               end;
  1817.  
  1818.               procedure Convert_Strings_to_Numbers;
  1819.               begin
  1820.                   val(numstr1, num1, errcod);
  1821.                   val(numstr2, num2, errcod);
  1822.               end;
  1823.  
  1824.               procedure Display_Calculations;
  1825.               begin
  1826.                   if (operation = '+') then
  1827.                       writeln('Answer: ', num1+num2)
  1828.                   else
  1829.                       if (operation = '-') then
  1830.                           writeln('Answer: ', num1-num2)
  1831.                       else
  1832.                           if (operation = '*') then
  1833.                               writeln('Answer: ', num1*num2)
  1834.                           else
  1835.                               if (operation = '/') and (num2 <> 0) then
  1836.                                   writeln('Answer: ', num1 div num2)
  1837.                               else
  1838.                                   writeln('Error   in   input.      Program
  1839.           ending.');
  1840.               end;
  1841.  
  1842.           begin
  1843.               Display_Title;
  1844.               Get_Inputs;
  1845.  
  1846.                                         - 31 -
  1847.  
  1848.  
  1849.  
  1850.  
  1851.  
  1852.  
  1853.  
  1854.  
  1855.               Convert_Strings_to_Numbers;
  1856.               Display_Calculations;
  1857.           end.
  1858.  
  1859.                Voila!  Procedures are  just like a little program  within a
  1860.           program but  they don't get executed until you call them as we do
  1861.           in  the calculator  mainline. The  mainline is  always  the first
  1862.           thing   that  gets  called  in   a  program.     It  gets  called
  1863.           automatically when the program is started.   All other procedures
  1864.           and functions get  called from the mainline.   When looking at  a
  1865.           program for  the first time,  skip down to  the mainline  and see
  1866.           what  procedures are  called.   Some  may  be predefined  in  the
  1867.           language  such as  writeln and others  may be user  defined as in
  1868.           Display_Title.
  1869.  
  1870.                Usually  each procedure will have  a lot of  comments at the
  1871.           beginning of it.  Even though  they are often  small, it's  still
  1872.           best to  make the reader aware of what each procedure does.  It's
  1873.           also  good practice to put a ton  of comments at the beginning of
  1874.           the  program  to  describe  what  it  does  (a  sort  of  program
  1875.           overview).
  1876.  
  1877.           It's interesting  to  note  that  a procedure  can  call  another
  1878.           procedure.   Such  is the  case  in Display_Title  for  instance.
  1879.           Display_Title  calls the procedure writeln.  We can write our own
  1880.           procedures and have another one call  it as long as it's declared
  1881.           BEFORE  the one calling  it.  For instance,  we could have called
  1882.           Display_Title from Get_Inputs but it didn't seem logical to me to
  1883.           do that.  We could have though.  This chaining of procedures is a
  1884.           very powerful feature indeed.
  1885.  
  1886.  
  1887.           FUNCTIONS
  1888.  
  1889.                A function is almost exactly  the same as a procedure.   The
  1890.           only  difference  is  a  function 'returns'  a  result  whereas a
  1891.           procedure simply gets called and carries out it's instructions.
  1892.  
  1893.                What do I  mean, 'returns a  result'?  Well,  let's look  at
  1894.           math functions  such as square root  of a number, the  sine of an
  1895.           angle,  etc..   Then  there's string  functions  such as  get the
  1896.           string length, concatenate two strings together, etc..  There are
  1897.           conversion functions  such  as  convert a  string  to  a  number,
  1898.           convert  a number to a string,  etc..  Functions do something and
  1899.           then return some result.
  1900.  
  1901.                Function results have to  be of a data type such as integer,
  1902.           string, char, or any other  type.  One interesting characteristic
  1903.           of functions is they can be used in expressions.  Expressions are
  1904.           the  right side of assignments (:=) or parameters to functions or
  1905.  
  1906.                                         - 32 -
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.           procedures such as writeln.   Let's give a couple  examples using
  1916.           the SQRT (square root) function.
  1917.  
  1918.           x := SQRT(9);
  1919.               {calculate the square root of 9 and assign that value to x}
  1920.  
  1921.           x := SQRT(y);
  1922.               {calculate the square root of the contents of y and assign to
  1923.           x}
  1924.  
  1925.           writeln(SQRT(y));
  1926.               {write the square root of y to the screen}
  1927.  
  1928.  
  1929.                Some  functions can be very  simple (such as  add the number
  1930.           three to  a  variable and  return  the result),  or may  be  more
  1931.           complicated  (such as  a function  used to  calculate mortgages).
  1932.           Let's show how  to write one  of the simple  ones this month -  a
  1933.           function that simply returns the math number PI divided by  2.  I
  1934.           think you  should be getting the  jist of how to  write a program
  1935.           show I'll only show a function and how to call it.
  1936.  
  1937.           function PI_DIV_2 : integer;
  1938.           begin
  1939.              PI_DIV_2 := PI div 2;
  1940.           end;
  1941.  
  1942.           ...
  1943.  
  1944.           begin
  1945.              ...
  1946.              writeln(PI_DIV_2);
  1947.              ...
  1948.              x := PI_DIV_2 + 4;
  1949.              ...
  1950.           end.
  1951.  
  1952.  
  1953.                Instead  of procedure,  we start  a function  with the  word
  1954.           function.    Also,  we must  tell  what  type  of value  will  be
  1955.           returned.   That's the ': integer'  part of the header.   To tell
  1956.           the function to  return the desired value, we appear  to assign a
  1957.           variable  with  the same  name as  the  function with  the return
  1958.           result (in this case, the return result is 'PI div 2').  Once the
  1959.           function  is  defined,  you  can  use  it  any  way  you  would a
  1960.           predefined function.
  1961.  
  1962.  
  1963.           NEXT MONTH
  1964.  
  1965.  
  1966.                                         - 33 -
  1967.  
  1968.  
  1969.  
  1970.  
  1971.  
  1972.  
  1973.  
  1974.  
  1975.                To  wrap  up, functions  and  procedures  are very  powerful
  1976.           additions to the Pascal language.   We've touched on them  here a
  1977.           little  but you will see them over and over in the future and I'm
  1978.           sure you'll get very used to using them.
  1979.  
  1980.                Next month  I'll show how to pass  a parameter to a function
  1981.           you  define, just  like SQRT  takes one  parameter and  returns a
  1982.           result.   I'll  also  show more  data  types, arrays,  constants,
  1983.           introduce you  to  controlling the  compiler  in your  code,  and
  1984.           perhaps even how to write a simple game.  See you then!
  1985.  
  1986.  
  1987.                If you wish to contact me, please do so at  the following e-
  1988.           mail addresses:
  1989.  
  1990.           From            Send e-mail to
  1991.           ===========     ===============
  1992.           Compuserve:     >INTERNET:bill.lenson%canrem@uunet.ca
  1993.           Internet:       bill.lenson%canrem@uunet.ca
  1994.  
  1995.  
  1996.  
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002.  
  2003.  
  2004.  
  2005.  
  2006.  
  2007.  
  2008.  
  2009.  
  2010.  
  2011.  
  2012.  
  2013.  
  2014.  
  2015.  
  2016.  
  2017.  
  2018.  
  2019.  
  2020.  
  2021.  
  2022.  
  2023.  
  2024.  
  2025.  
  2026.                                         - 34 -
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.                                     Hacker's Gash 
  2036.                                    By Dennis Chuah
  2037.  
  2038.                This  article contains a few  of the tips,  tricks and traps
  2039.           from my Windows  Programming laboratory  book.  As  I mainly  use
  2040.           Borland  C++, most of the discussion here will be slightly biased
  2041.           to  Borland  C++.   However  some  issues  also  concern  Windows
  2042.           programming in general.
  2043.  
  2044.                It is  sad that the Windows API  documentation[1] leaves out
  2045.           certain bits  of information  that is  sometimes  crucial to  the
  2046.           correct usage  of the  API.   Take MakeProcInstance  for example.
  2047.           The  documentation  states this  function  must only  be  used to
  2048.           access  functions from  instances  of the  current module.   This
  2049.           implies that  MakeProcInstance will  create a  procedure instance
  2050.           given  a hInstance and an  exported procedure address provided it
  2051.           is  called from the task  that is associated  with the hInstance.
  2052.           This  is not always the case.  Take  a look at the following code
  2053.           extract: 
  2054.  
  2055.           Somewhere in the application ...
  2056.  
  2057.           void CALLBACK SomeProc (void);
  2058.           .
  2059.           .
  2060.           FARPROC lpfnSomeProc;
  2061.           lpfnSomeProc   =   MakeProcInstanceForMe  (hInstance,   (FARPROC)
  2062.           SomeProc);
  2063.           if (lpfnSomeProc == SomeProc) MessageBeep (0);
  2064.  
  2065.           And somewhere else in the application's DLL ...
  2066.  
  2067.           FARPROC  WINAPI  MakeProcInstanceForMe (HINSTANCE  hInst, FARPROC
  2068.           lpfnFarProc)   {return MakeProcInstance (hInst, lpfnFarProc);
  2069.            }
  2070.  
  2071.                MakeProcInstanceForMe  will return  the address  of SomeProc
  2072.           instead   of   the  procedure   instance.      This  is   because
  2073.           MakeProcInstance  will always  return the same  procedure address
  2074.           passed to it  when it is  called from a  DLL, regardless of  what
  2075.           hInstance it is passed, a point missed out in the documentation. 
  2076.           Note:  the documentation merely  states that  MakeProcInstance is
  2077.           not required for library modules.  Hence:
  2078.  
  2079.           Trap: Never  use MakeProcInstance to create  a procedure instance
  2080.           from  a DLL.  Always create the  procedure instance  first before
  2081.           passing it to a DLL.
  2082.  
  2083.           Tip: Use "smart  callbacks" prologue  and epilogue  code if  your
  2084.           compiler supports it.   This usually  assumes DS is equal  to SS.
  2085.  
  2086.                                         - 35 -
  2087.  
  2088.  
  2089.  
  2090.  
  2091.  
  2092.  
  2093.  
  2094.  
  2095.           For most applications this  is true, except  if you swap data  or
  2096.           stack    segments.    Callback procedures  compiled  with  "smart
  2097.           callbacks"  do not  need  procedure instances  to  bind the  data
  2098.           segment.  The compiler just copies SS to DS in the prologue code.
  2099.           As there is no need for  procedure instances, there is no need to
  2100.           list it in the EXPORTS section of the module definition file.
  2101.  
  2102.           Tip:  Callback procedures in DLLs  need not (and  should not) use
  2103.           MakeProcInstance  to create  procedure  instance.   The  compiler
  2104.           always assumes that DS is not equal  to SS and there is only  one
  2105.           data segment.  It will load the correct data segment.
  2106.  
  2107.                Still on  the subject of Windows API, there is a very little
  2108.           known  (and very little documented) header  file in Borland C++'s
  2109.           Include directory called WINDOWSX.H.   A wealth of macros  can be
  2110.           found  in this  header file.     For example,  the GlobalAllocPtr
  2111.           macro  API  allocates memory  on the  global  heap, locks  it and
  2112.           returns a pointer to the  locked memory.  This is similar  to the
  2113.           malloc function that C programmers are more familiar with.  Using
  2114.           GlobalAllocPtr  also saves from having to keep track of a handle.
  2115.           Simple call GlobalFreePtr when  the block of memory is  no longer
  2116.           required.  Note:  Locking memory has its history in the real mode
  2117.           version  of Windows.  In protected mode, locking memory no longer
  2118.           has any  meaning so it is all right to keep a block memory locked
  2119.           for its lifetime.
  2120.  
  2121.           Trick: The way GlobalAllocPtr is  defined can cause the  compiler
  2122.           to generate a "Code has no effect" warning.  To  get around this,
  2123.           place a void typecast over GlobalAllocPtr when you call it.
  2124.  
  2125.           For example:
  2126.                DWORD far *lpDword;
  2127.                  .
  2128.                  .
  2129.                lpDword = GlobalAllocPtr (GHND, sizeof (DWORD) * 20);
  2130.                  .
  2131.                  .
  2132.                if (lpDword != NULL) (void) GlobalFreePtr (lpDword);
  2133.  
  2134.                WINDOWSX.H also contains declarations for  the Control Macro
  2135.           API.   Using this API  instead of sending  control messages makes
  2136.           your code easier to read.
  2137.  
  2138.                Edit_SetTabStops (hEdit, nTabs, lpTabs);
  2139.  
  2140.           is more legible than;
  2141.  
  2142.                SendMessage (hEdit, EM_SETTABSTOPS, (WPARAM) nTabs,
  2143.                     (LPARAM) (const int far *) lpTabs);
  2144.  
  2145.  
  2146.                                         - 36 -
  2147.  
  2148.  
  2149.  
  2150.  
  2151.  
  2152.  
  2153.  
  2154.  
  2155.                In  addition,  WINDOWSX.H  also  contains  declarations  for
  2156.           message crackers.  By using these macros, you will make your code
  2157.           more  portable.  I have one criticism  though, the macros are not
  2158.           defined to  allow a pointer to  be passed to the  message handler
  2159.           functions.   If you haven't  used WINDOWSX.H  before, I  strongly
  2160.           encourage you to start now.
  2161.  
  2162.  
  2163.           Metafiles:
  2164.  
  2165.                A metafile is a series of GDI calls.  It can  be stored as a
  2166.           physical  disk  file or  represented by  a  handle to  a metafile
  2167.           (stored in memory).
  2168.  
  2169.           Tip:  Use  a drawing  package (such  as  Corel Draw)  to generate
  2170.           metafiles that can be included as a user-defined resource in your
  2171.           Windows application.  This  way, you can draw graphics  using the
  2172.           powerful drawing tools of such  packages and include the  graphic
  2173.           in your application.
  2174.  
  2175.           Tip:  Including  a metafile  as  a  user-defined resource  in  an
  2176.           application: Say the metafile name is METAFILE.WMF.
  2177.  
  2178.           ... somewhere in the resource header file (say RES.H):
  2179.  
  2180.           /* assign an ID value for metafile resource types */
  2181.           #define METAFILE         2000
  2182.           #define MYMETAFILEID     100
  2183.  
  2184.           and somewhere in the resource definition file:
  2185.  
  2186.           #include "res.h"
  2187.             .
  2188.             .
  2189.           MYMETAFILEID METAFILE "metafile.wmf"
  2190.  
  2191.           To use the metafile:
  2192.  
  2193.           #include "res.h"
  2194.             .
  2195.             .
  2196.           HGLOBAL handle;
  2197.           HMETAFILE hMetafile;
  2198.           HDC hDc;
  2199.           RECT rect;
  2200.             .
  2201.             .
  2202.           /* Load the metafile */
  2203.           handle = LoadResource (hInstance,
  2204.              FindResource (hInstance, MAKEINTRESOURCE (MYMETAFILEID),
  2205.  
  2206.                                         - 37 -
  2207.  
  2208.  
  2209.  
  2210.  
  2211.  
  2212.  
  2213.  
  2214.  
  2215.              MAKEINTRESOURCE (METAFILE)));
  2216.  
  2217.           /* no need to retrieve pointer as we only need the handle */
  2218.           LockResource (handle); 
  2219.           hMetafile   =   (HMETAFILE)  SetMetafileBitsBetter   ((HMETAFILE)
  2220.           handle);
  2221.           UnlockResource (handle);
  2222.  
  2223.           /* Then draw it */
  2224.           hDc = GetDC (hWnd);
  2225.           GetClientRect (hWnd, &rect);
  2226.           SetMapMode (hDc, MM_ANISOTROPIC);
  2227.           SetViewportExt (hDc, rect.right, rect.bottom);
  2228.           PlayMetaFile (hDc, hMetafile);
  2229.           ReleaseDC (hWnd, hDc);
  2230.  
  2231.           /* Clean up */
  2232.           DeleteObject (hMetafile);
  2233.           FreeResource (handle);
  2234.  
  2235.  
  2236.                It is important  to set the  mapping mode to  MM_ANISOTROPIC
  2237.           and the viewport extents to rectangle in which the metafile is to
  2238.           be drawn.  This ensures  that the whole metafile is  drawn inside
  2239.           the specified  rectangle.  However, some  metafiles behaves badly
  2240.           and will  draw outside the  specified rectangle.   Most metafiles
  2241.           sets the window extent and origin, and draws within the limits of
  2242.           the  coordinates specified.   However,  this behaviour  cannot be
  2243.           guaranteed for all metafiles.
  2244.  
  2245.           Trap:    Forgetting    to    call    LockResource    can    cause
  2246.           SetMetafileBitsBetter to return NULL.
  2247.  
  2248.           Trap:  Metafiles with  placeable headers  cannot be  processed by
  2249.           Windows so make sure you save your metafile without the placeable
  2250.           header.
  2251.  
  2252.           Miscellaneous:
  2253.  
  2254.           Trap:  Be very careful when  allocating memory in  a DLL.  Memory
  2255.           allocated by a  DLL belongs  to the application  that called  the
  2256.           DLL.   Passing the  handle or pointer  to the block  of memory to
  2257.           another application will most likely cause a GP fault.   If a DLL
  2258.           needs to  share memory  between applications, use  the GMEM_SHARE
  2259.           flag  when calling  GlobalAlloc.   This,  however, poses  another
  2260.           problem.    Memory blocks  allocated  with  the GMEM_SHARE  flag,
  2261.           although  can be  shared, still  belongs to the  application that
  2262.           allocated it and  will be freed when  the application terminates.
  2263.           If another application calls  the DLL to access the  memory after
  2264.           the application that allocated the memory terminates, a  GP fault
  2265.  
  2266.                                         - 38 -
  2267.  
  2268.  
  2269.  
  2270.  
  2271.  
  2272.  
  2273.  
  2274.  
  2275.           will occur.   The following diagram better  illustrates this (see
  2276.           the Help file - Ed.).
  2277.  
  2278.  
  2279.           Tip: So, the lessons here are:
  2280.  
  2281.           a)  if possible, let the application allocate memory and pass the
  2282.           handle/pointer to the DLL
  2283.  
  2284.           b) if the DLL must allocate memory, make sure it is used only for
  2285.           the application that caused it to be allocated
  2286.  
  2287.           c) if the DLL has to allocate memory that will  be shared between
  2288.           applications, write a small  application that allocates memory on
  2289.           behalf of  the DLL.   This application  has to be  active for  at
  2290.           least  the life  of  the  DLL.    (See  accompanying  article  --
  2291.           Allocating Shareable Memory (in next month's issue - Ed.))
  2292.  
  2293.           Notes:
  2294.           [1]  -  I  define Windows  API  documentation  to  be information
  2295.           documented  in  Windows API  Vols 1-3.   I  know there  are other
  2296.           sources  of  information,  such  as the  numerous  articles  from
  2297.           Microsoft.  However, it  is my opinion that any  information that
  2298.           is not  included in a function's entry in the Windows API manuals
  2299.           should  be classified as "undocumented".   If the  set of manuals
  2300.           are  to be the primary  source of reference  material for Windows
  2301.           programming,  it  would  be   safe  to  assume  that  information
  2302.           documented   elsewhere  is  not   widely  accessible  to  Windows
  2303.           programmers and therefore undocumented.
  2304.  
  2305.  
  2306.           About the author:
  2307.  
  2308.           I am currently doing  a PhD. degree in Electrical  And Electronic
  2309.           Engineering  at the  University  Of Canterbury.   My  programming
  2310.           experience dates back to the  days when "real programmers"  coded
  2311.           with Z80  machine code.  For  the past two years I  have taken an
  2312.           interest  in  Windows programming.    Please  send any  comments,
  2313.           questions, criticisms to me via:
  2314.  
  2315.           email: chuah@elec.canterbury.ac.nz
  2316.  
  2317.           or post mail:
  2318.  
  2319.           Dennis Chuah
  2320.           c/o The Electronic and Electrical Engineering Department
  2321.           University of Canterbury
  2322.           Private Bag
  2323.           Christchurch
  2324.           New Zealand.
  2325.  
  2326.                                         - 39 -
  2327.  
  2328.  
  2329.  
  2330.  
  2331.  
  2332.  
  2333.  
  2334.  
  2335.                All mail (including hate  mail) is appreciated.  I  will try
  2336.           to  answer all questions personally, or if the answer has general
  2337.           appeal,  in the next issue. If you  are sending me e-mail, please
  2338.           make  sure you provide me with an  address that I can reach (most
  2339.           Internet and Bitnet nodes are reachable, and so is CompuServe).
  2340.  
  2341.  
  2342.  
  2343.  
  2344.  
  2345.  
  2346.  
  2347.  
  2348.  
  2349.  
  2350.  
  2351.  
  2352.  
  2353.  
  2354.  
  2355.  
  2356.  
  2357.  
  2358.  
  2359.  
  2360.  
  2361.  
  2362.  
  2363.  
  2364.  
  2365.  
  2366.  
  2367.  
  2368.  
  2369.  
  2370.  
  2371.  
  2372.  
  2373.  
  2374.  
  2375.  
  2376.  
  2377.  
  2378.  
  2379.  
  2380.  
  2381.  
  2382.  
  2383.  
  2384.  
  2385.  
  2386.                                         - 40 -
  2387.  
  2388.  
  2389.  
  2390.  
  2391.  
  2392.  
  2393.  
  2394.  
  2395.                                      Book Review
  2396.                              Title: ObjectWindows How-To
  2397.                                   Author: Gary Syck
  2398.                              Publisher: Waite Group Press
  2399.                                   By Rodney M. Brown
  2400.  
  2401.                The  other day,  I was  in my  local  WaldenBooks bookstore,
  2402.           browsing over the  crop of C/C++ books.  One  book that caught my
  2403.           attention  was   "ObjectWindows  How-To".     This  book   offers
  2404.           hints/tips  on   programming  in   Borland  C++/Turbo   C++  with
  2405.           ObjectWindows.
  2406.  
  2407.                The  book  is organized  by problems,  with the  solution or
  2408.           "How-To" following.  Each solution is graded in complexity; Easy,
  2409.           Moderate  and Hard.    After the  solution  is explained,  it  is
  2410.           followed  with the author's C++ code.   The C++ code is great for
  2411.           beginners.    The  author  placed comments  throughout  the  code
  2412.           explaining  what each function does.  The author also wrote a 2-3
  2413.           page explanation of the code he wrote.
  2414.  
  2415.                This book is a great reference.  It is filled with solutions
  2416.           to printing, changing the appearance/color of windows, etc. Below
  2417.           is a list of all the problems that are explained in the book:
  2418.  
  2419.                    1.  Making An ObjectWindows Application.
  2420.                    2.  Changing the Class Information & Style of a Window.
  2421.                    3.  Adding control windows to a window.
  2422.                    4.  Adding menus to a program.
  2423.                    5.  Creating an MDI application.
  2424.                    6.  Making and Using DLLs.
  2425.                    7.  Using the TDialog object class.
  2426.                    8.  Making a file selection dialog.
  2427.                    9.  Making a text search dialog.
  2428.                   10.  Using text controls.
  2429.                   11.  Using list box and combo box controls.
  2430.                   12.  Using check box and radio button controls.
  2431.                   13.  Using string tables.
  2432.                   14.  Converting programs to another language.
  2433.                   15.  Loading different menus from a resource file.
  2434.                   16.  Adding and Deleting menu items.
  2435.                   17.  Changing the attributes of a menu item.
  2436.                   18.  Changing the check marks in menus.
  2437.                   19.  Using bitmaps as menu items.
  2438.                   20.  Creating pop-up menus.
  2439.                   21.  Creating a text editor.
  2440.                   22.  Getting input from the keyboard.
  2441.                   23.  Getting input from the mouse.
  2442.                   24.  Using the serial port.
  2443.                   25.  Using the sound interface.
  2444.                   26.  Handling the printer.
  2445.  
  2446.                                         - 41 -
  2447.  
  2448.  
  2449.  
  2450.  
  2451.  
  2452.  
  2453.  
  2454.  
  2455.                   27.  Drawing in a window.
  2456.                   28.  Drawing different shapes.
  2457.                   29.  Using bitmaps.
  2458.                   30.  Using fonts.
  2459.                   31.  Using metafiles.
  2460.                   32.  Using the color palette.
  2461.                   33.  Making 3-d dialog windows.
  2462.                   34.  Creating custom controls. 
  2463.                   35.  Making a screen saver.
  2464.                   36.  Making nonrectangular windows.
  2465.                   37.  Using complex shapes as windows.
  2466.                   38.  Creating a file object.
  2467.                   39.  Saving different objects in a file.
  2468.                   40.  Reading and writing parts of the file.
  2469.                   41.  Creating a DDE server.
  2470.                   42.  Creating a DDE client.
  2471.                   43.  Getting updated data from the server.
  2472.                   44.  Executing commands on the server.
  2473.                   45.  Getting Drag-and-Drop files.
  2474.                   46.  Creating an OLE client.
  2475.                   47.  Creating an OLE server.
  2476.  
  2477.                I hope I didn't bore you listing all of the subjects covered
  2478.           in the  book.  It is a great reference book for Borland C++/Turbo
  2479.           C++ ObjectWindows programmers.   I predict  that this book  won't
  2480.           spend much time on my bookshelf.
  2481.  
  2482.  
  2483.           Contacting me online:
  2484.  
  2485.           CompuServe: 72163,2165
  2486.           America Online: RodneyB172
  2487.  
  2488.           You can also contact me at the following Internet addresses:
  2489.  
  2490.           CompuServe: 72163.2165@compuserve.com
  2491.           America Online: RodneyB172@aol.com
  2492.  
  2493.  
  2494.  
  2495.  
  2496.  
  2497.  
  2498.  
  2499.  
  2500.  
  2501.  
  2502.  
  2503.  
  2504.  
  2505.  
  2506.                                         - 42 -
  2507.  
  2508.  
  2509.  
  2510.  
  2511.  
  2512.  
  2513.  
  2514.  
  2515.                                  Creating Help Files
  2516.                                     By Todd Snoddy
  2517.  
  2518.                Like most of the readers of  Windows Programmer's Journal, I
  2519.           enjoy  Windows programming.  Although I  don't currently have the
  2520.           blessing?/curse? of being a "full time programmer", I do consider
  2521.           myself  to  be  a   dedicated  and  serious  Windows  programming
  2522.           hobbyist.  I  would like to use the opportunity that WPJ provides
  2523.           to  share   with  you some  of  the tools  I use  to  increase my
  2524.           productivity.  As  my busy schedule  permits, I  am hoping to  be
  2525.           able  to  review  different  programming  utilities  in  upcoming
  2526.           issues.
  2527.  
  2528.                I  would like  to  be able  to  concentrate mainly  on  both
  2529.           shareware  and free  software.   Although  I don't  have anything
  2530.           against commercial  software, many of the  software packages sold
  2531.           commercially are rather  expensive, putting it out  of the budget
  2532.           of  most  hobbyists  or  small  business  users.    In  addition,
  2533.           shareware  has  many   advantages  besides  usually  being   less
  2534.           expensive.   Many of the shareware products available fill a void
  2535.           that isn't quite covered by the major software publishers because
  2536.           they don't take  the time  to develop something  that won't  have
  2537.           mass market appeal.  I'll try to point out some of these products
  2538.           in the future.  Also,  the quality of modern shareware  can often
  2539.           approach or surpass that of commercial software.
  2540.  
  2541.                My  review topic this  month will be Windows  help files.  I
  2542.           will cover a few tools that I use to  develop my help files with,
  2543.           and actually  present a sample help  file that can be  used as an
  2544.           example for your own help  files.  The tools that I  will discuss
  2545.           are  free,  and are  available  from  various sources,  including
  2546.           CompuServe and numerous Internet ftp sites.
  2547.  
  2548.                Before I get started with that however, I would like to take
  2549.           a brief moment to tell  you a little about myself so that you can
  2550.           get an idea of my perspective.   I am currently in the U.S.  Army
  2551.           and  stationed  at  Ft.  Riley,  KS.    I    work  as a  computer
  2552.           technician/soldier during the day, and in my free time I do a lot
  2553.           of  Windows  programming  on  personal projects.    I  am  almost
  2554.           entirely self taught, and am competent in C, Pascal and assembly.
  2555.           I have been programming Windows for  around two years now, and  C
  2556.           for about  seven years.   Prior to  that, I programmed  BASIC for
  2557.           several years.  As mentioned before, programming is a major hobby
  2558.           of mine, but I also like to read and play pool, usually 9 ball.
  2559.  
  2560.                Now to  the good stuff.  Currently, there is only one vendor
  2561.           who  makes a compiler capable of creating Windows help files, and
  2562.           that is  of course Microsoft.   This  help compiler takes  a file
  2563.           that  contains a  special  formatting language  called Rich  Text
  2564.           Format, or  RTF, and converts it into a HLP file that can be used
  2565.  
  2566.                                         - 43 -
  2567.  
  2568.  
  2569.  
  2570.  
  2571.  
  2572.  
  2573.  
  2574.  
  2575.           by the WinHelp engine included with Windows.
  2576.  
  2577.                Contrary to  what Microsoft would  like to have  us believe,
  2578.           it's not  necessary to use an  RTF word processor like  their own
  2579.           (whose name we all know) to create Windows  help files.  Although
  2580.           the actual format of the HLP file is considered by many to be one
  2581.           of the best kept  secrets in the industry, there  are several low
  2582.           cost  or  free  utilities  available to  generate  the  RTF  file
  2583.           necessary for input to the Windows help compiler.
  2584.  
  2585.                When I first wanted to create my own help files, I looked at
  2586.           several utilities to  see what was available,  especially since I
  2587.           didn't have several  hundred dollars  extra to  buy an  expensive
  2588.           word processor.  The one that I found that was overall easiest to
  2589.           use is  RTFGEN, by David Baldwin.   This is an  excellent utility
  2590.           whose  use is free, not even shareware.  With David's permission,
  2591.           an older command line version is included with this issue of WPJ,
  2592.           along with  the  Pascal source  code,  although a  newer  Windows
  2593.           version is available  for free as well.  For a small fee, you can
  2594.           even obtain the source for the Windows version.
  2595.  
  2596.                RTFGEN's  sole purpose  is  to convert  standard ASCII  text
  2597.           files into  an  acceptable  RTF  file recognizable  by  the  help
  2598.           compiler.   Using RTFGEN for  creating your help  files is almost
  2599.           like using a programming language like C.  Many people say that C
  2600.           is a  high level  language with  the flexibility  of a  low level
  2601.           language like assembler.    RTFGEN will let you mix straight  RTF
  2602.           code  with your  help source  file for  maximum control  over the
  2603.           desired  output, or  you can  use the  default settings  and just
  2604.           specify the  actual topic information  and let RTFGEN  handle the
  2605.           rest.  RTFGEN  has some  special keywords that  will actually  be
  2606.           converted into RTF automatically,  so you don't have to  get your
  2607.           hands dirty if you really don't want to.
  2608.  
  2609.                Creating  a help  file  with RTFGEN  involves  a few  steps.
  2610.           First, you  need  to plan  the  layout of  the  help file.    The
  2611.           importance of this step can't be  overstated.  A well thought out
  2612.           layout  makes a big  difference in the apparent   quality of your
  2613.           product, especially when the user is totally lost and in  a blind
  2614.           panic  tries to bring up  the online help  instead of opening the
  2615.           manual.
  2616.  
  2617.                The next step would be to create the help source files.  For
  2618.           this  task, I use a  free Windows editor  called the Programmer's
  2619.           File Editor by Alan Phillips, but it can be done using any editor
  2620.           that  reads and  writes standard   ASCII  files, like  DOS's EDIT
  2621.           command, or even the Windows Notepad.  
  2622.  
  2623.                The  help  source  files   contain  the  actual  help  topic
  2624.           information,  including  the  topic text,  keywords,  and  browse
  2625.  
  2626.                                         - 44 -
  2627.  
  2628.  
  2629.  
  2630.  
  2631.  
  2632.  
  2633.  
  2634.  
  2635.           sequences.   These files will  have the RTFGEN  commands in them,
  2636.           and  may also  have  RTF statements  for   added  flexibility  or
  2637.           control  of the help file.  Each help topic will be in a specific
  2638.           format, and this will be covered shortly.
  2639.  
  2640.                After creating the help source files, we are almost ready to
  2641.           compile them into a HLP file.  However, before this  can be done,
  2642.           the source files  need to be processed by RTFGEN.  This procedure
  2643.           converts the special RTFGEN  commands into RTF automatically.  If
  2644.           you have any actual RTF statements in  the source file along with
  2645.           the  rest of  the  text, it  will  be left  alone  and passed  on
  2646.           unmodified.   This allows  the ultimate  in customization  of the
  2647.           help file.
  2648.  
  2649.                There is  one final step required  before actually compiling
  2650.           the help file.   This is  to create a  Help Project file,  or HPJ
  2651.           file.   This file specifies certain options to the help compiler,
  2652.           including the source files  for the help file,   bitmaps, and any
  2653.           help macros used.  I won't cover this subject in  more depth here
  2654.           as  it is  documented  in other  places  like the  help  compiler
  2655.           documentation.     By  the  way,  another   excellent  source  of
  2656.           information on  the format of the  HPJ file as well  as help file
  2657.           creation in general  is the Help Author's Guide.   This is a help
  2658.           file created  by  someone  at  Microsoft  but  is  not  supported
  2659.           officially by them.  It is usually distributed as HAG.ZIP and can
  2660.           be  found   on  Compuserve  and   Internet  ftp  sites   such  as
  2661.           FTP.CICA.INDIANA.EDU.   It contains a complete  reference for the
  2662.           RTF command syntax.
  2663.  
  2664.                That's  all you  need to  create a  help file.   That's all?
  2665.           Well, as mentioned before, the help  topics must be in a specific
  2666.           format.  David Baldwin's documentation for RTFGEN does a good job
  2667.           of explaining how to use  it, but I'll briefly cover some  of the
  2668.           highlights.
  2669.  
  2670.                First, every RTFGEN command is started by a \ character, and
  2671.           most are terminated by a ` character.  For example,  to specify a
  2672.           topic title, the command would be:
  2673.  
  2674.           \title Selecting Background and Foreground Colors.`
  2675.  
  2676.                This  statement specifies what text will be displayed in the
  2677.           Go To list  box when the  user tries to  search for the  keywords
  2678.           "background colors, selecting".  See Figure 1 for an example (see
  2679.           the Help file - Ed.).
  2680.  
  2681.                In  Figure  1,  the text  shown  in  the upper  list  box is
  2682.           specified by the topic  keywords.  To get the  currently selected
  2683.           text  to be  used for  the shown  topic, the  following statement
  2684.           would be used:
  2685.  
  2686.                                         - 45 -
  2687.  
  2688.  
  2689.  
  2690.  
  2691.  
  2692.  
  2693.  
  2694.  
  2695.           \keyword background colors, selecting`
  2696.  
  2697.                Every  topic  in  the help  file  has  to have  some  way to
  2698.           distinguish it as an individual topic and separate it from  every
  2699.           other topic.  This is known as the topic name.  The topic name is
  2700.           never actually  seen by the person viewing  the help file, but is
  2701.           instead used  as an  internal marker  to identify the  individual
  2702.           topic to the help system.  In RTFGEN, the topic is specified by a
  2703.           statement like:
  2704.  
  2705.           \topic SelectingColors`
  2706.  
  2707.                In the help source  file, all of the above  statements would
  2708.           be  grouped together in the topic heading.   The topic heading is
  2709.           separated from the rest of  the topic text by using a  minimum of
  2710.           five  = characters at the end of the  heading.  In practice, this
  2711.           would look like:
  2712.  
  2713.           \topic SelectingColors`
  2714.           \title Selecting Background and Foreground Colors.`
  2715.           \keyword background colors, selecting`
  2716.           =====
  2717.  
  2718.           This  is the  sample topic  text for  selecting a  background and
  2719.           foreground color.
  2720.  
  2721.           ------
  2722.  
  2723.                In  the above example, the  actual topic text  follows the =
  2724.           character, and is  terminated by five or more - characters.  This
  2725.           is how RTFGEN determines the separation between topics, and based
  2726.           on  their position, it will generate the appropriate RTF code for
  2727.           the help compiler.
  2728.  
  2729.                RTFGEN can be used to generate hypertext jumps or popup text
  2730.           as well.  For example, if you have some concepts  in a topic that
  2731.           the  user may  not be  familiar with,  you can  designate certain
  2732.           keywords in the topic that the  user can select on that brings up
  2733.           a  popup window with a more detailed description or definition of
  2734.           the keyword.
  2735.  
  2736.                To define a hypertext  jump with RTFGEN, the text  that will
  2737.           be selected  by the  user  to jump  to the  other  topic will  be
  2738.           enclosed  in brackets  along  with the  name of  the topic  to be
  2739.           jumped to.   For example, Figure  2 shows a typical  display of a
  2740.           hypertext jump (see the Help file - Ed.).
  2741.  
  2742.                To  duplicate   this  affect  using  RTFGEN,  the  following
  2743.           statement would be used in your help source file.
  2744.  
  2745.  
  2746.                                         - 46 -
  2747.  
  2748.  
  2749.  
  2750.  
  2751.  
  2752.  
  2753.  
  2754.  
  2755.           [Choosing Fonts and Font Sizes:ChoosingFonts]
  2756.  
  2757.                In this example, the ChoosingFonts will represents the topic
  2758.           name that will be jumped to when the hypertext link is selected.
  2759.  
  2760.                If instead you wanted to use a hypertext popup window  for a
  2761.           definition,  then you would use two sets of brackets.  An example
  2762.           of this is shown below (see the Help file for Figure 3 - Ed.).
  2763.  
  2764.           picture elements ([[pels:pels_def]]).
  2765.  
  2766.                Since  I am  a firm  believer in  the concept  of explaining
  2767.           something and  then giving an example  of how to do  it, a sample
  2768.           help  source file  is included,  along with  all of  the required
  2769.           files to build it, except for  the actual help compiler. You will
  2770.           need  the Windows 3.1  version of the help  compiler to build the
  2771.           sample.   After  studying  the  sample  files,  as  well  as  the
  2772.           documentation  for  RTFGEN, you  should be  well  on your  way to
  2773.           creating your own help files.
  2774.  
  2775.                To compile the sample into a help file, use the command:
  2776.  
  2777.           SAMPLGEN sample
  2778.  
  2779.                This will invoke the SAMPLGEN.BAT batch file to convert your
  2780.           source file into RTF, and if everything goes ok, it will then run
  2781.           the help compiler.
  2782.  
  2783.                There  are many ways to customize your help files, and I may
  2784.           cover  some techniques in future  issues of WPJ  as time permits,
  2785.           but  if you want to learn some  techniques on your own, then beg,
  2786.           borrow,  steal, or  otherwise  obtain a  copy  of the  previously
  2787.           mentioned  Help Author's Guide.   You can't beat  the price since
  2788.           it's free,  and  it is  full  of useful  information  on RTF  and
  2789.           creating help files.
  2790.  
  2791.                I welcome any comments  anyone may have on this  article, as
  2792.           well as suggestions for  other products to review in  the future.
  2793.           I can  be reached on America Online  at TSnoddy, on Compuserve at
  2794.           71044,1653,  and  on   the  Internet  at   tsnoddy@nyx.cs.du.edu.
  2795.           Although I'm very often quite busy,  I will try to respond to any
  2796.           messages.
  2797.  
  2798.                Also, if you do decide to start using RTFGEN, please contact
  2799.           the author  and let him know  what you think  of it.    The world
  2800.           needs  more software authors who are willing to make useful tools
  2801.           like  this  available  for   free,  and  when  someone  makes   a
  2802.           contribution like that, receiving  feedback from users provides a
  2803.           reason  to produce other useful utilities too.  The author, David
  2804.           Baldwin, can be reached on Compuserve at 76327, 53.
  2805.  
  2806.                                         - 47 -
  2807.  
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814.  
  2815.                                     Gdi See Gdi Do
  2816.                             Graphics Animation in Windows
  2817.                                   By Bernard Andrys
  2818.  
  2819.                In this series of articles, I will discuss  the writing of a
  2820.           space invaders style  game for Windows  3.1 in C.   The  articles
  2821.           will  be  directed to  people  who  understand programming  (such
  2822.           BASIC) and  know a  little about Windows  but are new  to Windows
  2823.           programming in C.
  2824.  
  2825.                Experienced  C programmers  will  immediately recognize  the
  2826.           poor  style of my code.   In some cases, I will  be doing this on
  2827.           purpose.   If a reader is new  to C AND Windows, they're probably
  2828.           going  to have just as much of  a problem following the C code as
  2829.           trying to follow the  Windows specific areas of programming.   (I
  2830.           know  that I sure  had problems learning both  at the same time.)
  2831.           As a result,  I will try to stick with  easy to understand syntax
  2832.           like  "x=x+1" instead of the  C shorthand "++x".   Later articles
  2833.           will use more of the shorthand notation as I and  the readers get
  2834.           comfortable with C.   The other reason for the  bad style is that
  2835.           my coding philosophy  is "Well it  works... so  I guess its  good
  2836.           enough."  This doesn't mean, however, that I don't  want to learn
  2837.           how to  write C better.   If you are an  experience C programmer,
  2838.           then  please drop  me  a  line  about  how  I  could  improve  my
  2839.           programming style.
  2840.  
  2841.                What  will  be different  is how  we  go about  writting the
  2842.           program.   I think that the  best way to learn  programming is to
  2843.           write a working program,  no matter how poorly written,  and then
  2844.           refine it as you  learn more.  So I will  start with the standard
  2845.           "do  nothing" windows program that just creates a window.  Future
  2846.           articles  will take this basic  program and add  the missle base,
  2847.           missle  firing, invaders, invaders firing, and of course the ufo.
  2848.           From  this simple  program we  add features  and fix  problems in
  2849.           future articles.  Some of the improved features will be 256 color
  2850.           bitmaps and digitized sound.   A couple of  the problems that  we
  2851.           will  need  to  deal  with  are  friendly  multitasking  and  the
  2852.           efficient drawing of bitmaps.  Once the game is finished, I would
  2853.           like to write about converting the program to C++.
  2854.  
  2855.                If you are new to Windows  programming in C then before  you
  2856.           go  on to  read  the  program below,  you'll  need  two books  as
  2857.           references.   The first is "The C Programming Language" by Dennis
  2858.           Ritchie and Brian Kernigan.   The second is "Programming Windows"
  2859.           by  Charles Petzold version  3.0.  These  two books have  all the
  2860.           basics of C and Windows programming in C.
  2861.  
  2862.                If you are knowledgeable about Windows programming in C then
  2863.           check  out the "Duncan" format of my  Windows C code.  There's no
  2864.           case  switch statement  for  processing messages.    An array  of
  2865.  
  2866.                                         - 48 -
  2867.  
  2868.  
  2869.  
  2870.  
  2871.  
  2872.  
  2873.  
  2874.  
  2875.           structures contains the  list of messages  that our program  will
  2876.           respond  to along  with  the function  that  is called  for  each
  2877.           message.
  2878.  
  2879.                A  final note before the  program starts:   This program was
  2880.           written using Quick  C for Windows.   As far as I know,  I didn't
  2881.           write anything that was compiler dependant (except the make file,
  2882.           but  then I didn't write  it, Quick C  wrote it for me).   If you
  2883.           have any  problems compiling it, drop  me a line so  I can remove
  2884.           any  compiler dependancies  in  future  articles.   I  have  been
  2885.           meaning  to purchase Turbo C++  for Windows and/or  Visual C++ so
  2886.           expect make  files for one or both of those compilers in the near
  2887.           future.
  2888.  
  2889.  
  2890.           // START OF PROGRAM LISTING
  2891.  
  2892.           /* invid.c */
  2893.  
  2894.           /*
  2895.           There are two  types of  ways of  adding comments  into C  source
  2896.           code.
  2897.           The first  way to  add a comment  is to put  a   / *   before the
  2898.           comment
  2899.           and a  * /  at the end of the comment.  (I had to add a space
  2900.           between the / and * because  otherwise the C compiler would think
  2901.           that
  2902.           it  really  was a  comment.   You  can't  put comments  inside of
  2903.           comments.)
  2904.           The other way to add a comment in your source code is to put a //
  2905.           at
  2906.           the start of the comment.   The comment will start at the //  and
  2907.           go to
  2908.           the end of the line.
  2909.           */
  2910.  
  2911.           #include <windows.h>
  2912.           #include "invid.h"
  2913.  
  2914.           /*
  2915.           The #include statement allows you to include another file in your
  2916.           source code.   This saves the  hassle of cutting and  pasting the
  2917.           code in.  The file  that you include is put inside a pair  of < >
  2918.           signs or  a pair of  " ".   Using < and  > tells the  compiler to
  2919.           search  through  the  path  defined  by  an  INCLUDE  environment
  2920.           variable (use SET INCLUDE = path to include files).  If you use "
  2921.           "  instead, it  tells  the compiler  to  only check  the  current
  2922.           subdirectory.   You normally use < and > for files that come with
  2923.           with the compiler.  Quotes are normally used for your own include
  2924.           files.  Every Windows program needs to include <windows.h>.  C by
  2925.  
  2926.                                         - 49 -
  2927.  
  2928.  
  2929.  
  2930.  
  2931.  
  2932.  
  2933.  
  2934.  
  2935.           itself  doesn't   have  any  functions  for   handling  character
  2936.           input/output,  character  strings   and  other  basic  functions.
  2937.           Therefore  most  C  programs  will  also  include  <stdio.h>  and
  2938.           <stdlib.h> to have a bunch of functions to work with.
  2939.  
  2940.           My own  file "invid.h"  contains my global  variable declarations
  2941.           and function prototypes.   You should already know that  a global
  2942.           variable is  a variable that  all functions can  share.  In  C, a
  2943.           global variable  is  created by  declaring a  variable above  the
  2944.           function  main()  ( or  for  Windows, the  function  WinMain() ).
  2945.           Normally you put your global variables at the top of your program
  2946.           after the #include files (or in your own #include file).   Global
  2947.           variables  should  normally be  avoided  because  they make  your
  2948.           program larger and make your code harder to manage as it grows.
  2949.  
  2950.           Function prototypes are a list of the functions  that are in your
  2951.           program.  A function  prototype includes the data types  that the
  2952.           function  will return and the data types of the parameters of the
  2953.           function.   If you were  to write a  function called DrawPixel(),
  2954.           you would write:
  2955.  
  2956.           int DrawPixel( int x, int y)
  2957.           {
  2958.                ...the function's code goes here
  2959.           }
  2960.  
  2961.           Int is the data type that the function returns.  DrawPixel is the
  2962.           name of the function.  X and y are the  function's arguments with
  2963.           int  x and  int y  saying  that the  arguments are  of data  type
  2964.           integer.  To make a function prototype just copy:
  2965.  
  2966.           int DrawPixel (int x, int y)
  2967.  
  2968.           from your program, paste it at the top of your program (or put it
  2969.           in a separate  #include file like I did with  invid.h), and add a
  2970.           semi-colon to the end of the line.
  2971.  
  2972.           The function prototype for function DrawPixel(x, y) is:
  2973.           int DrawPixel (int x, int y);
  2974.  
  2975.           The function  prototype tells  the compiler about  your DrawPixel
  2976.           function before  its used.  This  lets the compiler check  to see
  2977.           that you use your DrawPixel function with the right data types.
  2978.           */
  2979.  
  2980.           struct decodeWord {
  2981.                WORD Code;
  2982.                LONG (*Fxn)(HWND, WORD, WORD, LONG); };
  2983.  
  2984.           struct decodeWord messages[] = {
  2985.  
  2986.                                         - 50 -
  2987.  
  2988.  
  2989.  
  2990.  
  2991.  
  2992.  
  2993.  
  2994.  
  2995.                WM_CREATE, DoCreate,
  2996.                WM_DESTROY, DoDestroy, } ;
  2997.  
  2998.           /*
  2999.           I  have  used a  different method  for  having a  Windows program
  3000.           respond to  messages  than  what  is  normally  seen  in  Windows
  3001.           programming books.  It is  a method that I first saw  used by Ray
  3002.           Duncan  in PC Magazine. Instead of a large switch case statement,
  3003.           it uses an  array of structures that list the  messages that your
  3004.           program will respond to and the function that is called when that
  3005.           message is received.  (I'm going to skip covering  the details of
  3006.           arrays  and structures in C  for now. Otherwise,  I wouldn't have
  3007.           anything to write about  in future articles!) This  format allows
  3008.           you to easily add new messages without having to deal with a long
  3009.           and messy switch case statement.  To use the Duncan
  3010.           format, simply add the message that your program will respond to,
  3011.           a comma,  the name of the  function that will be  called when you
  3012.           receive that message, and then another comma.  In the case above,
  3013.           if  we  wanted to  have our  program  respond to  a WM_SYSCOMMAND
  3014.           message (this  is the message sent  when you click on  the system
  3015.           menu of a window) we would make the following change to the lines
  3016.           above.
  3017.  
  3018.           struct decodeWord messages[] = {
  3019.                WM_CREATE, DoCreate,
  3020.                WM_SYSCOMMAND, DoSysCommand,   // the  Windows Message,  Our
  3021.           Function
  3022.                WM_DESTROY, DoDestroy, } ;
  3023.  
  3024.           Now when  Windows sends a  WM_SYSCOMMAND message to  our program,
  3025.           our  program will run the  function DoSysCommand.   (I could have
  3026.           called the function anything I wanted.)   We would then go to the
  3027.           bottom of the program code and write the function DoSysCommand().
  3028.           */
  3029.  
  3030.  
  3031.           int PASCAL WinMain (HANDLE hInstance,
  3032.                HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
  3033.           /*
  3034.           This is  start of  the Windows  program.   (A  regular C  program
  3035.           starts  with a function called main().)  The keyword PASCAL tells
  3036.           the C compiler that this function  will be called with the PASCAL
  3037.           calling convention.   This means  that the code  that is  written
  3038.           inside of this function  has access to the actual  variables that
  3039.           are   passed  as  parameters   (i.e.,  hInstance,  hPrevInstance,
  3040.           lpszCmdParam,  nCmdShow).  A normal function in C doesn't let you
  3041.           change the original variable, it gives the function a copy of the
  3042.           variable to play with.
  3043.  
  3044.           If  the keyword PASCAL was  NOT used above,  then hInstance would
  3045.  
  3046.                                         - 51 -
  3047.  
  3048.  
  3049.  
  3050.  
  3051.  
  3052.  
  3053.  
  3054.  
  3055.           contain a duplicate of the number that Windows uses to keep track
  3056.           of which copy of this program  we have in memory. (In Windows, we
  3057.           can  have the same program loaded several  times.)  If we changed
  3058.           the value of  hInstance, it wouldn't  change what Windows  thinks
  3059.           hInstance  contains.   It  would only  change  what our  function
  3060.           thinks hInstance is.
  3061.  
  3062.           Using the  keyword PASCAL  means that if  we change the  value of
  3063.           hInstance,  it  will  change  what Windows  thinks  the  value of
  3064.           hInstance  is as well.  This can  be very dangerous so you should
  3065.           use care when dealing  with the parameters to functions  that are
  3066.           declared  using  the  PASCAL keyword.    So  why  use the  PASCAL
  3067.           keyword?  There are  three reasons for using the  PASCAL keyword.
  3068.           The first is  that when  writing parts of  a program, it's  often
  3069.           easier to  use the  keyword PASCAL  to get  access to  the actual
  3070.           arguments  than to have  to deal with creating  a group of global
  3071.           variables  or  use a  pointer  to the  arguements  to get  to the
  3072.           original  variable.  The next  reason is that  the PASCAL calling
  3073.           convention  for functions  makes  programs a  little smaller  and
  3074.           makes them  run a  little faster.   The last  reason is  that any
  3075.           function that Windows will  call in your program must  be declare
  3076.           as a  PASCAL function.   A simple  Windows program  only has  the
  3077.           functions Winmain()  and WinProc() called by  Windows.  Winmain()
  3078.           is the  start of your program  and WinProc() is  the name usually
  3079.           given to the function  that Windows calls when  it has a  message
  3080.           for  your program. A function  that Windows calls  inside of your
  3081.           program is called a callback function and  all callback functions
  3082.           must  use  the PASCAL  keyword.   I  won't  spend  any time  here
  3083.           discussing callback  functions because using  them is a  lot more
  3084.           messy  than just  adding  the keyword  PASCAL  to the  function's
  3085.           declaration.
  3086.           */
  3087.  
  3088.           {
  3089.                MSG msg ;
  3090.           /*
  3091.           Declare a variable msg of data type MSG (message).   This will be
  3092.           the  variable that will  hold any messages  that are  sent to our
  3093.           program.
  3094.           */
  3095.                if (!hPrevInstance) InitApplication(hInstance);
  3096.           /*
  3097.           hPrevInstance is a  number that  Windows passes to  WinMain as  a
  3098.           parameter when run.   The number identifies the previous  copy of
  3099.           our program that is currently running.
  3100.  
  3101.           If  this is the only  copy of the  program running, hPrevInstance
  3102.           contains 0.  In C, the if() statement executes the next statement
  3103.           if  what  is in  the  parenthese's is  true  (and in  C,  true is
  3104.           anything except 0).  The ! operator  in C performs a  logical NOT
  3105.  
  3106.                                         - 52 -
  3107.  
  3108.  
  3109.  
  3110.  
  3111.  
  3112.  
  3113.  
  3114.  
  3115.           operation.  A logical NOT operator changes a 0 to a 1 or a 1 to a
  3116.           0.   Therefore  if  hPrevInstance  is  0  (no  previous  instance
  3117.           running)   then   !hPrevInstance   equals   1   (True).   So   if
  3118.           !hPrevInstance  is true  then "if  (!hPrevstance)" runs  the next
  3119.           statement which  is InitApplication().   Once you've seen  this a
  3120.           couple of times, you'll automatically translate a statement like:
  3121.  
  3122.           if (!hPrevInstance) InitApplication(hInstance);
  3123.  
  3124.           to mean:
  3125.           If there is not a previous instance of our program in memory then
  3126.           run the function InitApplication().
  3127.  
  3128.           InitApplication is a  function that  we will write  to setup  the
  3129.           information for this window that can be shared between all copies
  3130.           of our program that are running.
  3131.           */
  3132.                InitInstance(hInstance, nCmdShow);
  3133.           /*
  3134.           Call  InitInstance().   This  is the  function  that sets  up the
  3135.           information  for this  program's  window that is  unique for this
  3136.           particular copy in memory.
  3137.           */
  3138.                while (GetMessage (&msg, NULL, 0, 0))
  3139.                {
  3140.                     TranslateMessage (&msg) ;
  3141.                     DispatchMessage (&msg) ;
  3142.                }
  3143.           /*
  3144.           This is the  message loop that keeps  our program running.   Your
  3145.           program  runs in  this  infinite loop  as  long as  the  function
  3146.           GetMessage()  returns TRUE (In C, TRUE is anything other than 0.)
  3147.           The GetMessage() function  returns FALSE if a WM_QUIT  message is
  3148.           received.   This  means that  the  while loop  will  stop if  our
  3149.           program receives a WM_QUIT message and our WinMain() program will
  3150.           continue to the lines below.
  3151.           */
  3152.                return (msg.wParam) ;
  3153.           }
  3154.           /*
  3155.           This is the  end of our Program.  What  follows are the functions
  3156.           that WinMain calls and the functions that we call when we receive
  3157.           a  message as  defined at the  top of  this program  in the array
  3158.           messages[].
  3159.           */
  3160.  
  3161.  
  3162.           BOOL InitApplication(HANDLE hInstance)
  3163.           /*
  3164.           InitApplication  will be  the  data that  is  shared between  all
  3165.  
  3166.                                         - 53 -
  3167.  
  3168.  
  3169.  
  3170.  
  3171.  
  3172.  
  3173.  
  3174.  
  3175.           instances of our program.
  3176.           */
  3177.           {
  3178.                WNDCLASS wndclass;
  3179.  
  3180.                wndclass.style = 0 ;
  3181.                wndclass.lpfnWndProc = WndProc ;
  3182.           /*
  3183.           For this program WndProc() will be  the name of the function that
  3184.           windows calls when it has a message for our program.
  3185.           */
  3186.                wndclass.cbClsExtra = 0 ;
  3187.                wndclass.cbWndExtra = 0 ;
  3188.                wndclass.hInstance = hInstance ;
  3189.                wndclass.hIcon = LoadIcon (hInstance, szAppName) ;
  3190.           /*
  3191.           Load our icon for this program.  szAppName is a  variable defined
  3192.           in invid.h.  (this is just a short cut so that if I use this code
  3193.           to  make  a different  program, I  can  just change  the variable
  3194.           szAppName  in  invid.h instead  of having  to  go through  all my
  3195.           source code to see where I used the name  of my program.)  Take a
  3196.           look  at the file invid.rc for  the rest of the information about
  3197.           how you add an icon.
  3198.           */
  3199.                wndclass.hCursor = LoadCursor (hInstance, IDC_ARROW) ;
  3200.                wndclass.hbrBackground = GetStockObject (BLACK_BRUSH) ;
  3201.           /*
  3202.           the background of our window will be painted black.
  3203.           */
  3204.                wndclass.lpszMenuName = NULL ;
  3205.                wndclass.lpszClassName = szAppName ;
  3206.  
  3207.                return(RegisterClass (&wndclass));
  3208.           }
  3209.  
  3210.  
  3211.           BOOL InitInstance(HANDLE hInstance, WORD nCmdShow)
  3212.           /*
  3213.           The InitInstance() function will initialize the data that will be
  3214.           unique for a particular copy of the program that is in running.
  3215.           */
  3216.  
  3217.           {
  3218.                hWnd = CreateWindow (szAppName,
  3219.                     "Invid",
  3220.                     DS_SYSMODAL | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
  3221.           /*
  3222.           The  flags DS_SYSMODAL  etc. are  constants defined  in windows.h
  3223.           that tell windows  how the window  should look.   An | symbol  is
  3224.           used between  the flags because it is  the C operator for logical
  3225.  
  3226.                                         - 54 -
  3227.  
  3228.  
  3229.  
  3230.  
  3231.  
  3232.  
  3233.  
  3234.  
  3235.           OR.   If you have the  binary numbers 1000  and 0100 then  1000 |
  3236.           0100  = 1100.   So by putting  an | symbol between  each flag, we
  3237.           combine the  different flags  into a  single number  that Windows
  3238.           uses to figure out how the window should look.
  3239.           */
  3240.                     CW_USEDEFAULT, CW_USEDEFAULT,
  3241.                     WINDOW_WIDTH, WINDOW_HEIGHT ,
  3242.           /*
  3243.           A  normal  Windows  program   would  use  the  Windows  constants
  3244.           CW_USEDEFAULT above.  However, since this is a graphic game whose
  3245.           window  cannot be  resized (see  DS_SYSMODAL flag above),  we are
  3246.           going  to  define precisely  the size  of  the window  in pixels.
  3247.           WINDOW_WIDTH and WINDOW_HEIGHT are constants that I've defined in
  3248.           "invid.h".
  3249.           */
  3250.                     NULL,
  3251.                     NULL,
  3252.                     hInstance,
  3253.                     NULL) ;
  3254.  
  3255.                ShowWindow (hWnd, nCmdShow) ;
  3256.                UpdateWindow (hWnd) ;
  3257.                return (TRUE);
  3258.           /*
  3259.           In <windows.h> TRUE is defined as 1 and FALSE is defined as 0.
  3260.           */
  3261.           }
  3262.  
  3263.           long  FAR PASCAL WndProc (HWND hWnd, WORD wMsg, WORD wParam, LONG
  3264.           lParam)
  3265.           /*
  3266.           This is the function that Windows calls whenever it has a message
  3267.           for our  window.  WinProc  goes through  each item  in the  array
  3268.           messages[]  (which was  defined at  the top  of our  program) and
  3269.           checks to see if the  message it received matches the  message in
  3270.           the array.   If the message does match, then it runs the function
  3271.           that goes with that message.
  3272.           */
  3273.           {
  3274.                int i;
  3275.  
  3276.                for(i=0; i < dim(messages); i++)
  3277.                {
  3278.                     if(wMsg == messages[i].Code)
  3279.                          return((*messages[i].Fxn)(hWnd,    wMsg,   wParam,
  3280.           lParam));
  3281.                }
  3282.  
  3283.                return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  3284.           }
  3285.  
  3286.                                         - 55 -
  3287.  
  3288.  
  3289.  
  3290.  
  3291.  
  3292.  
  3293.  
  3294.  
  3295.  
  3296.           LONG DoCreate(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  3297.           /*
  3298.           This is where we will load our bitmaps and initialize some of our
  3299.           variables.    The program  doesn't do  anything  yet so  there is
  3300.           nothing to create.
  3301.           */
  3302.           {
  3303.           return 0;
  3304.           }
  3305.  
  3306.  
  3307.           LONG DoDestroy(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
  3308.           /*
  3309.           The  program doesn't create anything  yet so there  is nothing to
  3310.           destroy before the program exits.
  3311.           */
  3312.           {
  3313.                PostQuitMessage (0) ;
  3314.                return 0 ;
  3315.           }
  3316.  
  3317.  
  3318.           // END OF PROGRAM LISTING
  3319.  
  3320.  
  3321.                So that's  it for this month.  Don't you just hate all these
  3322.           programs that do ABSOLUTELY  NOTHING.  I sure do!   Unfortunately
  3323.           this article is  already a bit long so you'll  have to wait until
  3324.           next  month before we turn this "do nothing" Windows program into
  3325.           a nifty little space invaders style game. If you'd like a peek at
  3326.           where I'm  going  with  this  article, run  peek.exe.  (You  will
  3327.           probably need to play with the delay= value in the invid.ini file
  3328.           that is created in your Windows subdirectory after the program is
  3329.           run the first time.)
  3330.  
  3331.  
  3332.           About the author:
  3333.  
  3334.           (short version)
  3335.           SWM 25 ISO SWF.  Enjoys long walks, sun, surf, skiing.
  3336.  
  3337.           (long version)
  3338.           Bernard  Andrys is a network  engineer for CSI,  an ISDN hardware
  3339.           and software development company.   He holds a bachelor's  degree
  3340.           in  Mechanical Engineering  from  the University  of Maryland  at
  3341.           College  Park.   He  can  be  reached  through  the  Internet  at
  3342.           andrys@csisdn.com or on the Windows Programmer's Journal BBS.
  3343.  
  3344.  
  3345.  
  3346.                                         - 56 -
  3347.  
  3348.  
  3349.  
  3350.  
  3351.  
  3352.  
  3353.  
  3354.  
  3355.                                Book Review:  Windows++
  3356.                                    By Philip Sloss
  3357.  
  3358.                I started trying to write Windows programs the old-fashioned
  3359.           way -- copying examples from magazines and books.   This is still
  3360.           my  preferred method when it  comes to things  I don't understand
  3361.           clearly.  ("Things I Don't Understand Clearly" -- this is such an
  3362.           all-encompassing topic,  that brevity  and disk space  prevent me
  3363.           from  fully  explaining  it;  however,  you  will  find  examples
  3364.           sprinkled  throughout the  rest  of this  article.)   I  do  like
  3365.           trolling  the book  stores  looking for  interesting examples  on
  3366.           Windows programming, and one of my first finds was a book  called
  3367.           "Windows++."
  3368.  
  3369.                   "Windows++: Writing Reusable Windows Code in C++"
  3370.  
  3371.                Often, you can find out an important thing in the preface to
  3372.           a  book  or article:  what the  book is  about.   The  preface of
  3373.           "Windows++" states that it is "essentially a recipe for  building
  3374.           a C++ class  library interface to Windows."  What  really sold me
  3375.           on this book was that the author, Paul DiLascia, actually *shows*
  3376.           how to  do this.  Instead of finishing  the book with a jumble of
  3377.           ideas that you  have to put together, Paul  goes the whole twelve
  3378.           yards, and shows how to put the library together.  The end result
  3379.           is that "Windows++"  is not just a  book on how to  build a class
  3380.           library, it is a class library.
  3381.  
  3382.                Armed  with (or,  rather, disarmed  with) a  general naivete
  3383.           about Windows  programming and a  lack of enthusiasm  for writing
  3384.           long  repetitious code, I decided to use the Windows++ library to
  3385.           write  Windows programs.  The  book and the  library are mutually
  3386.           beneficial: not only  does the  library serve the  book, but  the
  3387.           book  is the perfect reference for  the library!  When I'm having
  3388.           problems, I can see  how something was implemented in  the source
  3389.           code, and  read a detailed  explanation of it  in the book.   The
  3390.           book is also educational on Windows programming in general.
  3391.  
  3392.                A couple of points:  First, class libraries are very helpful
  3393.           and  can  be  of  great  benefit.    Microsoft's  Visual  C++  is
  3394.           permanently  entwined  in  their  class  library,  the  Microsoft
  3395.           Foundation Class Library (MFC).   MFC is the primary  reason that
  3396.           Visual C++  is so useful.  Second, and just as important, I think
  3397.           that one still  has to spend time  learning Windows the "C"  way.
  3398.           There is no way around it, in my smug, slight opinion.
  3399.  
  3400.                For  example, I'll use someone I'm on speaking terms with --
  3401.           me.  Shortly  after purchasing  "Windows++," I went  and got  the
  3402.           bible -- "Programming Windows" by Charles Petzold.  What happened
  3403.           with  me was that I quickly began  asking a lot of questions like
  3404.           "Well, how  does this work?"  (Compiler  errors will cause one to
  3405.  
  3406.                                         - 57 -
  3407.  
  3408.  
  3409.  
  3410.  
  3411.  
  3412.  
  3413.  
  3414.  
  3415.           speak out  loud to no one  in particular.) It helped  to know how
  3416.           Windows++  calls were mapped to  the Windows API,  because then I
  3417.           had  some clue as  to what to  expect.  The  general consensus is
  3418.           that  Mr.  Petzold's  book  is  the  best  there  is  on  Windows
  3419.           programming fundamentals -- I agree.
  3420.  
  3421.                In  other  words,  while  I'm  led  to  believe  that  class
  3422.           libraries like MFC and Windows++ can greatly simplify one's work,
  3423.           I still think  most beginning  Windows programmers are  in for  a
  3424.           future showdown with the Windows API.
  3425.  
  3426.                                     "Hello, World"
  3427.  
  3428.                The proliferation of the  phrase "Hello, World" has extended
  3429.           beyond computer programming and now has completely taken over the
  3430.           information age. The standard introduction to just about anything
  3431.           -- renting  a car, sky diving without  a parachute (also known as
  3432.           sky jumping or sky  plunging), underwater basket cooking --  is a
  3433.           square with the  words "Hello, World"  in the middle  of it.   On
  3434.           your first parachute-less  sky dive, this is a good  thing to aim
  3435.           for,  as  it will  allow the  authorities  to easily  locate your
  3436.           remains.
  3437.  
  3438.                Windows  programming  adds a  system  menu,  title bar,  and
  3439.           maximize/minimize  buttons  to the  "Hello,  World"  square.   In
  3440.           addition, it requires a rather detailed preparation of structures
  3441.           and  calls to  functions  with  423  parameters.    It  is  also,
  3442.           apparently, the basis for beginning a Windows class library.
  3443.  
  3444.                In C, the  "Hello, World" program looks  like this (adapted,
  3445.           with few alterations, from Petzold's "Programming Windows"; those
  3446.           of you who have seen this countless  times before, please try not
  3447.           to become physically ill):
  3448.  
  3449.           ////////////////////////////////////////
  3450.           #define STRICT
  3451.           #include <windows.h>
  3452.  
  3453.           LRESULT CALLBACK _export WndProc (HWND, UINT, WPARAM, LPARAM);
  3454.  
  3455.           int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  3456.                               LPCSTR lpszCmdParam, int nCmdShow)
  3457.           {
  3458.                HWND        hwnd;
  3459.                MSG         msg;
  3460.                WNDCLASS    wndclass;
  3461.                static char szAppName[] = "Hello";
  3462.  
  3463.                if (!hPrevInstance) {
  3464.                     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  3465.  
  3466.                                         - 58 -
  3467.  
  3468.  
  3469.  
  3470.  
  3471.  
  3472.  
  3473.  
  3474.  
  3475.                     wndclass.lpfnWndProc   = WndProc;
  3476.                     wndclass.cbClsExtra    = 0;
  3477.                     wndclass.cbWndExtra    = 0;
  3478.                     wndclass.hInstance     = hInstance;
  3479.                     wndclass.hIcon                      =  LoadIcon  (NULL,
  3480.           IDI_APPLICATION);
  3481.                     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
  3482.                     wndclass.hbrBackground                                =
  3483.           (HBRUSH)GetStockObject(WHITE_BRUSH);
  3484.                     wndclass.lpszMenuName  = NULL;
  3485.                     wndclass.lpszClassName = szAppName;
  3486.  
  3487.                     RegisterClass (&wndclass);
  3488.                } 
  3489.  
  3490.                hwnd = CreateWindowEx(NULL,       // extended window style
  3491.                               szAppName,         // window class name
  3492.                               "The Hello Program",  // window caption
  3493.                               WS_OVERLAPPEDWINDOW,  // window style
  3494.                               CW_USEDEFAULT,        // initial x position
  3495.                               CW_USEDEFAULT,        // initial y position
  3496.                               CW_USEDEFAULT,        // initial x size
  3497.                               CW_USEDEFAULT,        // initial y size
  3498.                               NULL,          // parent window handle
  3499.                               NULL,          // window menu handle
  3500.                               hInstance,     // program instance handle
  3501.                               NULL);         // creation parameters
  3502.  
  3503.                ShowWindow (hwnd, nCmdShow);
  3504.                UpdateWindow (hwnd);
  3505.  
  3506.                while (GetMessage (&msg, NULL, 0, 0)) {
  3507.                     TranslateMessage(&msg);
  3508.                     DispatchMessage(&msg);
  3509.                }
  3510.                return msg.wParam;
  3511.           }
  3512.  
  3513.           LRESULT CALLBACK _export WndProc (HWND hwnd, UINT message,
  3514.                                             WPARAM wParam, LPARAM lParam)
  3515.           {
  3516.                HDC         hdc;
  3517.                PAINTSTRUCT ps;
  3518.                RECT        rect;
  3519.  
  3520.                switch (message) {
  3521.                     case WM_PAINT:
  3522.                          hdc = BeginPaint (hwnd, &ps);
  3523.                          GetClientRect (hwnd, &rect);
  3524.                          DrawText (hdc, "Hello, Windows!", -1, &rect,
  3525.  
  3526.                                         - 59 -
  3527.  
  3528.  
  3529.  
  3530.  
  3531.  
  3532.  
  3533.  
  3534.  
  3535.                              DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  3536.                          EndPaint (hwnd, &ps);
  3537.                          return 0;
  3538.  
  3539.                     case WM_DESTROY:
  3540.                          PostQuitMessage (0);
  3541.                          return 0;
  3542.                }
  3543.  
  3544.                return DefWindowProc (hwnd, message, wParam, lParam);
  3545.           }
  3546.  
  3547.                Again,  all this  gets you is  a window that  can be closed,
  3548.           with a  line of text in  it (although it  does help pad  out this
  3549.           article).  And, for the most part, all programs have to have this
  3550.           code  somewhere in them.   This is where  the class library comes
  3551.           in.   A  class library  does repetitive  things like  filling the
  3552.           WNDCLASS  structure and calling CreateWindowEx() with the correct
  3553.           parameters for  you.   You only  have to  define  the styles  and
  3554.           parameters specific to your application.
  3555.  
  3556.                    What "Hello, World" looks like using "Windows++"
  3557.  
  3558.                For purposes of  introduction, one of the first  sections in
  3559.           the book shows what the Windows++ version of "Hello, World" looks
  3560.           like.  It reduces the long, C-style program to this:
  3561.  
  3562.           #include <wpp.h>   // main Windows++ header file
  3563.  
  3564.           APPCLASS HelloWin : public WPMainWin {
  3565.           public:
  3566.                HelloWin() { createWin("Hello"); }
  3567.                void paint(WPPaintStruct &ps) {
  3568.                     WPRect clientArea = this;
  3569.                     ps.drawText(clientArea, "Hello, Windows++.",
  3570.                          DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  3571.                }
  3572.           };
  3573.  
  3574.           void WPApp::main()
  3575.           {
  3576.                mainWin = new HelloWin;
  3577.                run();
  3578.           }
  3579.  
  3580.                As the "Hello, World" example is a do-nothing program,  this
  3581.           program has very  little code  -- a nice  correspondence.  For  a
  3582.           detailed explanation of how this  is orchestrated, I strongly and
  3583.           emphatically suggest purchasing "Windows++."  
  3584.  
  3585.  
  3586.                                         - 60 -
  3587.  
  3588.  
  3589.  
  3590.  
  3591.  
  3592.  
  3593.  
  3594.  
  3595.                                 What's the Difference?
  3596.  
  3597.                What separates "Windows++"  from some of the  other books on
  3598.           C++ Windows  programming is  that "Windows++" is  primarily about
  3599.           how the library fits together.  Often, all one gets is the source
  3600.           code to a  class library at the  back of the book and/or  on disk
  3601.           and  instructions on how to use it.  "Windows++" shows how anyone
  3602.           can build their  own library -- it  discusses some of  the issues
  3603.           one  has to  deal with,  and some  of the  standard and  extended
  3604.           features one  should consider  incorporating in a  class library.
  3605.           At  the same time, there are several instructive examples of real
  3606.           Windows programs written with the Windows++ class library.
  3607.  
  3608.                And finally, in the last chapter, the reader is shown how to
  3609.           put the class library into a  dynamic link library (DLL), and the
  3610.           issues and problems that any library has to deal with  to put C++
  3611.           classes into a DLL.
  3612.  
  3613.  
  3614.                              "How About a Sudden Ending?"
  3615.  
  3616.                So,  summing up:  "long, redundant code -- bad, reusable C++
  3617.           Windows classes -- good."  And a  good book on how to make a  C++
  3618.           class library for Windows is "Windows++."
  3619.  
  3620.  
  3621.  
  3622.           About the Author: An Unauthorized Autobiography of Philip Sloss
  3623.  
  3624.                Born from a crude  genetic experiment mixing the genes  of a
  3625.           human sperm with  tree sap, Mr.  Sloss has led  a far from  legal
  3626.           existence since  his grudging inception  into the  world.   After
  3627.           being  developed in an artificial womb,  he was raised in a large
  3628.           culture  of athlete's foot fungus.   Mr. Sloss  was accepted into
  3629.           the   aerospace  engineering  department   at  San   Diego  State
  3630.           University, and in May  of 1992, having advanced  to the rank  of
  3631.           graduate, he left college and began a career in unemployment.  He
  3632.           is  now   under  under  psychiatric  observation   for  "behavior
  3633.           unsuitable to inert objects."  Hospital officials report that Mr.
  3634.           Sloss' main hobby is spotting lint.
  3635.  
  3636.  
  3637.  
  3638.  
  3639.  
  3640.  
  3641.  
  3642.  
  3643.  
  3644.  
  3645.  
  3646.                                         - 61 -
  3647.  
  3648.  
  3649.  
  3650.  
  3651.  
  3652.  
  3653.  
  3654.  
  3655.                               Getting in touch with us:
  3656.  
  3657.           Internet and Bitnet:
  3658.  
  3659.           HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (Pete)
  3660.  
  3661.           GEnie: P.DAVIS5 (Pete)
  3662.  
  3663.           CompuServe: 71141,2071 (Mike)
  3664.  
  3665.           WPJ BBS (703) 503-3021 (Mike and Pete)
  3666.  
  3667.           You can also send paper mail to:
  3668.  
  3669.           Windows Programmer's Journal
  3670.           9436 Mirror Pond Drive
  3671.           Fairfax, VA   22032
  3672.                 U.S.A.
  3673.  
  3674.                In future  issues we  will be  posting  e-mail addresses  of
  3675.           contributors  and columnists  who  don't mind  you knowing  their
  3676.           addresses. We will also contact any  writers from previous issues
  3677.           and see if they want their mail addresses made available for  you
  3678.           to respond to them. For  now, send your comments to us  and we'll
  3679.           forward them.
  3680.  
  3681.  
  3682.  
  3683.  
  3684.  
  3685.  
  3686.  
  3687.  
  3688.  
  3689.  
  3690.  
  3691.  
  3692.  
  3693.  
  3694.  
  3695.  
  3696.  
  3697.  
  3698.  
  3699.  
  3700.  
  3701.  
  3702.  
  3703.  
  3704.  
  3705.  
  3706.                                         - 62 -
  3707.  
  3708.  
  3709.  
  3710.  
  3711.  
  3712.  
  3713.  
  3714.  
  3715.                                     The Last Page
  3716.                                    By Mike Wallace
  3717.  
  3718.                I got this in the mail a few days ago from Mike Strock...
  3719.  
  3720.                Here is a wonderful  quote I think you will  just love.
  3721.                It comes from the Journal American, page d6, in the 2nd
  3722.                article, 3rd paragraph in the 4th column.
  3723.  
  3724.                "Electronic bulletin boards are fast becoming a popular
  3725.                way  to get  copies  of  programs  for  free,  but  the
  3726.                practice  is  illegal.   Bulletin boards  are computers
  3727.                that can be reached by other computers via modem.  Most
  3728.                of  them require  the  new users  to upload  an illegal
  3729.                program  onto  their  machines  (thereby  incriminating
  3730.                themselves) before they are allowed to down-load  other
  3731.                programs for free,  said Alison Gilligan, international
  3732.                anti-piracy specialist at Microsoft."
  3733.  
  3734.  
  3735.                Bulletin  boards  have  been  blamed  for spreading  illegal
  3736.           copies of software almost  since the day they  started appearing.
  3737.           Software companies  have long complained their  very existence is
  3738.           in  danger due  to  these BBSs  spreading  free copies  of  their
  3739.           software.   Is this fair  to the majority of  BBSs?  No,  I don't
  3740.           think so.   I've been on a  lot of boards,  and most of the  ones
  3741.           I've seen aren't doing anything illegal.  Maybe  you need to know
  3742.           someone  to  get  onto  the  illegal  boards,  but  that  doesn't
  3743.           legitimize the above  quote from  Microsoft.  The  trend in  this
  3744.           country to  blame others for your own "bad luck" gets out of hand
  3745.           sometimes.   Say you start  up a commercial  software company and
  3746.           nobody buys  your app.  Does  that mean everyone has  a free copy
  3747.           obtained  from a  BBS?   Maybe,  but there's  also a  chance your
  3748.           program isn't worth buying,  or people don't even know  about it.
  3749.           It's hard  to buy every commercial program you want when each one
  3750.           may  cost $200-300, or more.  The  software companies say this is
  3751.           to  recoup their  losses  from illegal  (unpaid) copies  floating
  3752.           around.   I think  this may  have the opposite  effect -  who can
  3753.           afford  to  buy  software that's  so  expensive?    Now, I'm  not
  3754.           condoning software piracy.  Besides being  illegal and immoral, I
  3755.           think everybody  loses when  nobody's paying for  their software.
  3756.           The  concept  of "shareware"  should  be  extended to  commercial
  3757.           software.  Will this  ever happen?  Never mind whether  it's even
  3758.           feasible.  I  would probably own more software if  I could try it
  3759.           out first and then pay for it if I decide I'll use it.  But as it
  3760.           is, I can't  afford to  pay big bucks  for a program  that I  may
  3761.           never use  once I've  tried it  out.  So,  the result  is there's
  3762.           probably a  lot of good software for sale that would make my life
  3763.           easier,  but I'll never know about it.   The same can probably be
  3764.           said   for  a  lot  of  computer   users.    Hmmmm...sounds  like
  3765.  
  3766.                                         - 63 -
  3767.  
  3768.  
  3769.  
  3770.  
  3771.  
  3772.  
  3773.  
  3774.  
  3775.           everybody's losing again.
  3776.  
  3777.                A  lot of these companies only appear  to be in the business
  3778.           of manufacturing software so they can make a lot of  money, and I
  3779.           think the people putting out quality software are.  Take Borland,
  3780.           for example.   They put out  a lot of good  programs, and they're
  3781.           reaping the benefits.   Microsoft too.   Why they're  complaining
  3782.           about  BBSs is  beyond me.   Let's look  at one  BBS and  see how
  3783.           Microsoft has benefited from  it: the WPJ BBS.   Besides carrying
  3784.           WPJ, there's a lot of other software (all legal) available from a
  3785.           CD-ROM that can be accessed by  anybody that calls our BBS.  Most
  3786.           of  it  is  devoted  to products  produced  by  Microsoft  (e.g.,
  3787.           Windows), and  we're just part of  a much larger  network of BBSs
  3788.           all  over the  world  supporting  Microsoft.    True,  a  lot  of
  3789.           commercial software companies live  off Microsoft by writing apps
  3790.           helping  people run  Windows, but  it goes  both  ways: Microsoft
  3791.           benefits by having so many  companies support their products with
  3792.           add-on programs  or  whatever.   If  I  was going  to  choose  an
  3793.           operating system for my computer, one thing I would look at would
  3794.           be  the third-party  support, and  Microsoft is  the overwhelming
  3795.           leader  in that  area  for  IBM-compatible  PCs.    So,  to  hear
  3796.           Microsoft complaining about BBSs is more  than a little annoying.
  3797.           Sounds like it's biting the hand that feeds it.
  3798.  
  3799.  
  3800.  
  3801.  
  3802.  
  3803.  
  3804.  
  3805.  
  3806.  
  3807.  
  3808.  
  3809.  
  3810.  
  3811.  
  3812.  
  3813.  
  3814.  
  3815.  
  3816.  
  3817.  
  3818.  
  3819.  
  3820.  
  3821.  
  3822.  
  3823.  
  3824.  
  3825.  
  3826.                                         - 64 -
  3827.  
  3828.  
  3829.