home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / wpj_mag / wpjv1n4.zip / WPJV1N4.TXT < prev   
Text File  |  1993-04-04  |  114KB  |  2,788 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 04
  18.      and Mike Wallace                                          Apr 93
  19.      ----------------------------------------------------------------
  20.      A monthly forum for novice-advanced programmers to share ideas and concepts
  21.      about programming in the Windows (tm) environment.   Each issue is uploaded
  22.      to  the info  systems  listed below  on the  first of  the month,  but made
  23.      available at the convenience of the sysops, so allow for a couple of days.
  24.  
  25.      You can get in touch with the editors via Internet or Bitnet at:
  26.  
  27.      HJ647C at GWUVM.BITNET   or   HJ647C at GWUVM.GWU.EDU  (Pete)
  28.  
  29.      CompuServe: 71141,2071 (Mike)    71644,3570 (Pete)
  30.  
  31.      Delphi: PeteDavis
  32.  
  33.      GEnie: P.DAVIS5
  34.  
  35.      or you can send paper mail to:
  36.  
  37.      Windows Programmer's Journal
  38.      9436 Mirror Pond Dr.
  39.      Fairfax, Va. 22032
  40.  
  41.      We can also be reached by phone at: (703) 503-3165.
  42.  
  43.      The WPJ BBS can be reached at: (703) 503-3021.
  44.  
  45.      The WPJ  BBS is currently 2400 Baud (8N1). We'll  be going to 14,400 in the
  46.      near future, we hope.
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.                                      LEGAL STUFF
  60.  
  61.  
  62.      - Microsoft, MS-DOS, Microsoft Windows, Windows NT, Windows for Workgroups,
  63.      Windows for Pen Computing,  Win32, and Win32S are registered  trademarks of
  64.      Microsoft Corporation.
  65.  
  66.      - Turbo  Pascal for  Windows, Turbo  C++ for Windows,  and Borland  C++ for
  67.      Windows are registered trademarks of Borland International.
  68.  
  69.      - WordPerfect is a registered trademark of WordPerfect Corporation.
  70.  
  71.      -  Other trademarks mentioned herein  are the property  of their respective
  72.      owners.
  73.  
  74.      -  WPJ  is  available  from  the  WINSDK,  WINADV  and  MSWIN32  forums  on
  75.      CompuServe, and the IBMPC, WINDOWS and BORLAND forums on GEnie.  It is also
  76.      available on America Online in the Programming library.   On Internet, it's
  77.      available on WSMR-SIMTEL20.ARMY.MIL and FTP.CICA.INDIANA.EDU.  We upload it
  78.      by  the 1st of each  month and it  is usually available by  the 3rd or 4th,
  79.      depending on when the sysops receive it.
  80.  
  81.      -  The Windows Programmer's Journal takes no responsibility for the content
  82.      of  the   text  within  this  document.  All   text  is  the  property  and
  83.      responsibility of the individual authors. The Windows Programmer's  Journal
  84.      is solely a vehicle for allowing  articles to be collected and  distributed
  85.      in a common and easy to share form. 
  86.  
  87.      -  No part  of  the Windows  Programmer's  Journal may  be re-published  or
  88.      duplicated in  part or whole, except in the complete and unmodified form of
  89.      the Windows Programmer's Journal, without the express written permission of
  90.      each  individual author. The Windows  Programmer's Journal may  not be sold
  91.      for  profit without the express written permission of the Publishers, Peter
  92.      Davis  and  Michael  Wallace,  and  only  then  after  they  have  obtained
  93.      permission from the individual authors.
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.                          Table of Contents
  104.  
  105.      Subject                                        Page  Author(s)
  106.      -----------------------------------------------------------------
  107.      WPJ.INI .......................................  4   Pete Davis
  108.  
  109.      Letters .......................................  6   Readers
  110.  
  111.      Midlife Crisis: Windows at 32 .................  9   Pete Davis
  112.  
  113.      Beginner's Column ............................. 14    Dave Campbell
  114.  
  115.      Owner-Drawn List Boxes ........................ 25   Mike Wallace
  116.  
  117.      Beginner's Column for Turbo Pascal for Windows  30   Bill Lenson
  118.  
  119.      Hacker's Gash ................................. 31   Readers
  120.  
  121.      Microsoft's Windows Strategy .................. 34   Pete Davis
  122.  
  123.      Accessing Global Variables Across DLL ......... 38   Rod Haxton
  124.  
  125.      Getting A Piece Of The Future ................. 41   Peter Kropf
  126.  
  127.      The "ClickBar" Application .................... 44   WynApse
  128.  
  129.      Getting in Touch with Us .....................  45   Pete & Mike
  130.  
  131.      Last Page ....................................  46   Mike Wallace
  132.  
  133.      (If you're  wondering where the C++  Beginner's column is,  it's because we
  134.      haven't heard from the column's author.  We hope to have it next month. See
  135.      WPJ.INI for further explanation.)
  136.  
  137.      Windows Programmer's Journal Staff:
  138.  
  139.      Publishers ......................... Pete Davis and Mike Wallace
  140.      Editor-in-Chief .................... Pete Davis
  141.      Managing Editor .................... Mike Wallace
  142.      Contributing Editor ................ Dave Campbell
  143.      Contributing Editor ................ Bill Lenson
  144.                                           
  145.  
  146.      Contributing Writer ................ Rod Haxton
  147.      Contributing Writer ................ Peter Kropf
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.                                        WPJ.INI
  157.                                     by Pete Davis
  158.  
  159.           Crazy, crazy, crazy. That's the only  way to describe how things  have
  160.      been lately. Got some good news, some bad news and  a bit in-between. First
  161.      of all, I'll pour out some of the bad news.
  162.  
  163.           We've been unable to get in touch with the author of the C++ beginners
  164.      column. This  happens sometimes with a  magazine like this and  it could be
  165.      for any number of reasons. We will continue to try to get in touch with him
  166.      and hopefully have an article for next months issue.
  167.  
  168.           The second piece of not-so-good news is about me and you  may think of
  169.      it as good  news, depending on your opinion of me. I probably won't be able
  170.      to do quite  as much writing for  the magazine for the next  7-10 months. I
  171.      will get  in at least one article  (for the Win 32  column) each month, but
  172.      other than that, I won't be able to do much else. For one thing,  I'm going
  173.      to  have to cancel  the Install program.  I'll discuss some  points for the
  174.      Install program in a sec. I can't say  yet why I won't be able to write  as
  175.      much but hopefully,  by the next issue, I will be  able to tell you what it
  176.      is. Of course,  things might not work out,  and I'll be writing as  much as
  177.      ever for the next  7-10 months. Well, I guess that was cryptic enough. I'll
  178.      discuss it next month.
  179.  
  180.           As for the install program, it looks  like I won't be able to continue
  181.      it. I've looked into the question of installing DLLs while the something is
  182.      using  them. It  seems that  Windows'install program  puts the  files in  a
  183.      temporary directory and  copies them  in before  a restart  or shutdown  of
  184.      Windows. This is what I have been told by several people, including someone
  185.      from Microsoft. I have  been through Microsoft's  Install code in the  past
  186.      and I  don't remember  seeing  anything about  that,  but I  wasn't  really
  187.      looking in  the right places, in  retrospect. I will post this  code on the
  188.      WPJ BBS if you're interested.
  189.  
  190.           I would love for  someone to pick up the install program and finish it
  191.      off for me. If anyone's interested, please, get in touch with us.
  192.  
  193.           Let's  try to get into some good news now. The good news is that we're
  194.      going to  be covering Win32 A LOT!  This doesn't just mean  Windows NT, but
  195.      also Win32s and, eventually, Win32c (won't be released for  another year or
  196.      so). This  month I'm starting off  with some NT and  Win32c specific stuff.
  197.      Later I'll going into using the Win32s API to write 32-bit apps for Windows
  198.      3.1. There's really a lot of promise in the 32-bit application arena and we
  199.      intend on showing you all about it.
  200.  
  201.           We've also got Peter Kropf who will also be doing a Win32 column. Most
  202.      of his is going to be  discussing Windows NT so after this month,  I'll try
  203.      to leave that  to him and I'll move on to  Win32s and some less NT-specific
  204.      stuff.
  205.  
  206.           We've got Bill Lenson  who will be doing a new  column on Turbo Pascal
  207.      for  Windows for beginners. We've all been  waiting for this, so we're glad
  208.  
  209.                                         - 4 -
  210.  
  211.  
  212.  
  213.  
  214.  
  215.      to have him aboard.
  216.  
  217.           Rod  Haxton is  back with  a really interesting  way to  handle Global
  218.      variables in Windows DLLs. As with all these sort of under-the-covers weird
  219.      things, it's  not a  recommended, it's  just a  method. DLLs  shouldn't use
  220.      Global variables from the  main program, but sometimes you don't  have much
  221.      of a choice, as Rod will explain.
  222.  
  223.           Well, that's  about it for me, just  to say that next  month I hope to
  224.      have some really good news for all of you. Peace.
  225.  
  226.                                                             Pete Davis
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.                                         - 5 -
  269.  
  270.  
  271.  
  272.  
  273.  
  274.                                        Letters
  275.  
  276.      Date:  21-Mar-93 22:07 EST
  277.      From:  Eric Fildebrandt [76326,1470]
  278.      Subj:  WPJ Format
  279.  
  280.      I  have read  your past  three issues  and can't  thank you  enough.   I am
  281.      venturing  into the  Windows  programming  environment  and  need  all  the
  282.      assistance I can get.  As to the format, I really  like the WinHelp format.
  283.      It  is easily navigated  and can be  placed in a Program  Group in Windows.
  284.      This way it can be used as a reference when programming.
  285.  
  286.      I  wonder if you could discuss the best  way to change the background color
  287.      of  a window since everyone  else simply used  the default white background
  288.      using GetStockObject.   I have  tried using CreateSolidBrush  and it  works
  289.      basically, however, after I  close the window, the chosen  background color
  290.      remains as the background color for the icons in the Program Manager window
  291.      until that window is somehow refreshed.
  292.  
  293.      I am also interested in knowing how to drag and place bitmaps in  a window.
  294.      I am also really confused on how to use the WM_PAINT message to send output
  295.      to the window,  especially when that output changes during  the run-time of
  296.      the  program.  Let's  take the windows  solitaire game as an  example.  How
  297.      would  the WM_PAINT message be  used to change the display  as each card is
  298.      played, or is it?
  299.  
  300.      Thank you for  providing a forum for  those of us trying to  get acquainted
  301.      with Windows.
  302.  
  303.      Eric Fildebrandt
  304.      Electrical Engineer/Computer Programmer
  305.  
  306.      Editor [P.D.]: Eric, let me see what I can do for you here. I messed around
  307.      with some code that was supposed to be the basis for a solitaire  game that
  308.      I was going to write. The world  conspired against me and limited a day  to
  309.      24 hours, so I didn't have time to finish it, but here's what I learned. My
  310.      first attempt was to just draw the bitmaps in their locations. When a mouse
  311.      button was  pressed, I  would check the  mouse position. If  it was  over a
  312.      card,  I would pick  it up and  the move it  by BitBlt-ing it  with the XOR
  313.      operator so that you could draw it over itself to erase it. This is used in
  314.      moving. You have two  positions, old and new.  You draw over the  old (with
  315.      XOR) and draw in the new position (also with XOR) and your card just moved.
  316.      THIS IS  NOT THE  RECOMMENDED WAY.  This was a  disaster and  it was  a lot
  317.      slower than it had to be.
  318.  
  319.           If I were to go back and do this, my first move  would be to place the
  320.      card bitmaps  inside of static  objects. You could  keep track of  what the
  321.      mouse is currently above  by checking the WM_SETCURSOR message  and storing
  322.      the result in a static variable.  Then when a WM_LBUTTONDOWN message comes,
  323.      check to  see  what  the cursor  was  above.  For  a sample  of  using  the
  324.      WM_SETCURSOR, see  WPJV1N3 Hackers Gash,  topic #2. I  hope this  helps. If
  325.      anyone else has some ideas, please send them in.
  326.  
  327.                                         - 6 -
  328.  
  329.  
  330.  
  331.  
  332.  
  333.      Date:  24-Mar-93 16:15 EST
  334.      From:  Francois Bruneau [100113,1156]
  335.      Subj:  Adapt the old Memory functions of Turbo C++
  336.  
  337.      I  have some code  that works with  Turbo C++.  I don't know  how adapt the
  338.      memory functions  "memmove","memset","realloc" to  the Windows  3.1 Borland
  339.      C++ .
  340.  
  341.      For example I have code about matrix class:
  342.  
  343.      class matrix{
  344.      protected:
  345.       int lgn,col;
  346.       double* coeff;
  347.       void init(int l,int c,double* cf=0);
  348.  
  349.      public:
  350.        matrix(int l,int c,double* cf) { init(l,c,cf); }
  351.      }
  352.  
  353.      void matrix::init(int l,int c,double* cf)
  354.      { lgn=col=0; coeff=0; coeff=new double[l*c]; lgn=l; col=c;
  355.        if (cf) memmove(coeff,cf,l*c*sizeof(double));
  356.        else memset(coeff,0,l*c*sizeof(double)); }
  357.  
  358.      Elsewhere:  coeff=(double*) realloc(coeff,lgn*col*sizeof(double));
  359.  
  360.      I have no idea for the translation to GlobalLock,GlobalFree...
  361.  
  362.      Can you help me?
  363.      Francois Bruneau.
  364.  
  365.  
  366.      Editor [P.D.]: Well, Francois, I'm  not sure if I understand your  question
  367.      exactly, but  I'll we  what I  can do.  First of  all,  for allocating  the
  368.      memory, you're better of using Local memory if you  can, but if you're data
  369.      is  large, use  Global.  You'll  need  to  lock the  data  before  you  can
  370.      manipulate  it. That  means  before  doing a  memmove  or  memset, use  the
  371.      Local/GlobalLock function (This assumes you've done your Local/Global Alloc
  372.      with LMEM/GMEM_MOVEABLE!) Next,  if you're using  LocalAlloc, then you  can
  373.      use memmove and memset or their equivalent functions which are available in
  374.      all compilers. If you are using GlobalAlloc, you need to use functions that
  375.      will work  on FAR  pointers. If  these functions  aren't available in  your
  376.      compiler,   you'll   have  to   write  your   own.   Also,  be   aware  the
  377.      Local/GlobalAlloc will return a handle, not an address. To get the address,
  378.      you need to do a Local/GlobalLock.
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.                                         - 7 -
  387.  
  388.  
  389.  
  390.  
  391.      Date:  31-Mar-93 00:52 EST
  392.      From:  James F. Stoves [72561,746]
  393.      Subj:  Replacing DLL's
  394.  
  395.      Chris,
  396.           I was just  reading your letter  in WPJ  regarding the replacement  of
  397.      DLLs.  I  just installed EXCEL and  WORD on a PC  at work, and in  thinking
  398.      about it, the Install Program took over the machine.
  399.  
  400.           What   I  mean  is  that   "MICROSOFT"  logo  appeared   on  the  top,
  401.      miscellaneous propoganda in the middle, and a progress bar on the bottom.
  402.  
  403.           The window had no "system menu" or minimize/maximize block.  There was
  404.      a  cancel pushbutton, but ostensibly  that would have  shut down the entire
  405.      install  process.   My  clock (which  is set  to "always  on top")  did not
  406.      appear.  I did try "Ctrl+ESCape" once during the install process and it did
  407.      not work.   Yet the "setup" program is  launched from within Windows, so it
  408.      must be there somewhere...
  409.  
  410.           I was  wondering if  the  way Microsoft  gets  around the  "used  DLL"
  411.      problem is by making sure that all DLL's are unused by booting them out. In
  412.      other  words, causing everything to somehow be magically unloaded while the
  413.      install  is running, replacing  the DLLs,  then a  reload when  the install
  414.      process ends.  Just a thought, probably of minimal value, but presented for
  415.      your amusement.....
  416.  
  417.                                      Jim
  418.  
  419.      Editor [P.D.]: Jim, I mentioned in WPJ.INI that I've seen the code for  the
  420.      install  program. I don't remember  this part either, but  I can think of a
  421.      way it could be  done. First of all, to  get rid of everything else  on the
  422.      screen and get a bitmap on the screen, all you need is a dialog box with no
  423.      SYSMENU, no CAPTION  bar and no border  to be sized for  the entire screen.
  424.      Next, draw your bitmap on top of it. Now, why isn't your clock  showing up?
  425.      Well, for your clock  to be on top, it has to get a message letting it know
  426.      it was covered up  so it can redraw itself  on the top. Since Windows  is a
  427.      non-preemptive multi-tasking system, all  the Install program has to  do is
  428.      not release control  until it's done. You  are taught from day  one to keep
  429.      your  programs nice  and have them  yield time  on a regular  basis. If you
  430.      don't yield the  queue, nothing else  will run (except  the kernel and  any
  431.      calls you make). So,  your clock would stay  hidden. That's how I  would do
  432.      it, and  I wouldn't be suprised  if that's how the  install program handles
  433.      it. If anyone else has comments on this, I'd love to hear them.
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.                                         - 8 -
  445.  
  446.  
  447.  
  448.  
  449.  
  450.  
  451.                             Midlife Crisis: Windows at 32
  452.                                     By Pete Davis
  453.  
  454.           So, what's this  new column all about? Well, Win32 obviously, and yes,
  455.      this column  will get into the  nitty gritty of Win32  programming. I'm not
  456.      sure how  much appeal this will  have because I don't know  how many people
  457.      out there actually have it. Mike and I have  had it for a couple months now
  458.      and I just recently got the Win32 API Programmer's Reference (Pre-Release).
  459.      This wallet-buster  collection of a  whole two  books (at a  mere $90)  has
  460.      almost everything you need, NOT.  Ok, well, as you  saw in the last  issue,
  461.      Microsoft's  not known  for their  amazing book  deals, but  hey, when  the
  462.      choices  are Microsoft's API reference or Microsoft's API reference, I tend
  463.      to take the former,  or was that the latter?  Oh well, I think you  get the
  464.      picture.
  465.  
  466.           Second question: A whole  column for Win32? Well, yes.  Even Microsoft
  467.      thinks Windows NT will only take  a small percentage (10-20 percent) of the
  468.      Windows 3.1 market. But, as the title implies, this isn't just a Windows NT
  469.      column, this is a Win32 column. Win32 includes the Win32s  API which allows
  470.      Windows 3.1  to run  32-bit applications.  This has a  lot of  promise, and
  471.      we'll be talking in detail about all of this. 
  472.  
  473.           Actually, there are  going to be two Win32 columns.  The second one is
  474.      going to be more NT specific. 
  475.  
  476.           Ok,  let's get  a little  terminology covered  first. You've  got your
  477.      Windows 3.1,  Windows NT, Win32 and Win32s. Windows 3.1, well, if you don't
  478.      know what it  is, maybe you're reading  this magazine by accident.  Windows
  479.      NT,  of course,  is  Microsoft's Windows  New  Technology (NoT,  whatever).
  480.      Windows NT  is a  32 bit  operating system.  It's more  than just a  faster
  481.      Windows, though. It's a huge departure from Windows 3.x. Windows  NT is its
  482.      own operating system and runs without MS-DOS underneath (although an MS-DOS
  483.      clone runs  underneath Windows NT).  Windows NT,  unlike Windows 3.x,  is a
  484.      pre-emptive multi-tasking  operating  system.  This  means  that  while  in
  485.      Windows 3.x, if  a program locks up, so does  Windows, while, under Windows
  486.      NT, if an application locks up,  it doesn't affect the rest of  the system.
  487.      The reason  is that  in  Windows 3.x,  the multi-tasking  is  based on  the
  488.      message queue and when the message  queue stops, so does Windows. (There is
  489.      one exception: MS-DOS  sessions under Windows 3.x are  pre-emptively multi-
  490.      tasked). Windows NT handles everything based on time-slicing instead of the
  491.      message queue. This means that each application gets a short period of time
  492.      to run, then  the next application gets a  bit of time, and then  the next,
  493.      and so on, until  the first one gets to go again.  This is what pre-emptive
  494.      multi-tasking is all about.
  495.  
  496.           Oops, where  were we, oh yeah,  the last two: Win32  and Win32s. These
  497.      are both  about the same  thing. Both are  the 32-bit APIs  for programming
  498.      Windows. Win32 is the  32-bit API that you use to program under Windows NT.
  499.      The  Win32s  is  the  same  thing,   except  that  it  allows  your  32-bit
  500.      applications to run  under Windows 3.x through the use  of some trickery of
  501.      VxDs (32 bit  device drivers) and some  DLLs. The Win32s API  is actually a
  502.      subset of  the Win32  API. It doesn't  have threading,  security, and  some
  503.  
  504.                                         - 9 -
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.      other things. Actually, the functions are in the API, but  since they can't
  512.      be supported under  Windows 3.1, they  simply return a failure.  This means
  513.      that  you can program in the  features for NT, but if  it's being run under
  514.      Windows 3.1, certain features just won't work.
  515.  
  516.           So, Windows  3.x is covered with  the rest of the  magazine. The other
  517.      three, Windows NT, Win32  and Win32s are covered by this  column and the NT
  518.      column. So, that's it for the little intro on terminology.
  519.  
  520.           Win32 is big, and when I say big, I mean REAL BIG. It's about twice as
  521.      complex, programming-wise, as Windows  3.x. Now, that might not  be exactly
  522.      right, there are  some things that are  made easier, but there  are so many
  523.      new features,  that it can be very  overwhelming. I'm not going  to write a
  524.      general overview of  Win32 programming because I don't have  6 months to do
  525.      that. The best way to handle this whole thing, I guess, is to take it a bit
  526.      at a time,  so each month I'll  pick a topic to  cover and after about  600
  527.      issues, we'll start to get comfortable with the Win32 API.
  528.  
  529.           Before we get too deep  into this (and believe me, we're going  to get
  530.      in over my head, a bit),  I want to make one  thing very clear. I am not  a
  531.      Win32  expert.  I've  been going  by  what  is  quite possibly  out-of-date
  532.      documentation. I don't have the $360 for Windows NT Manuals. Microsoft says
  533.      to  use the  online documentation,  to which  I say,  'Yeah, you  try going
  534.      through a 3 meg  help file on a CD-ROM drive with 800ms access time!'. I am
  535.      going to try to  get the rest of the documentation as soon as I can. I also
  536.      have Helen Custer's 'Inside Windows NT' which is a great book, but it isn't
  537.      exactly specific on the  programming aspects. It does, however,  provide an
  538.      excellent discussion on how NT works in a general sense.
  539.  
  540.           Today  we're   going  to   talk  about  Processes   and  Threads   and
  541.      Synchronization, and all that fun stuff. Damn, that means more terminology,
  542.      doesn't it?  Well, this will be  short. Processes, in terms  of Windows NT,
  543.      are programs.  Each program is a  process. Within a single  process you can
  544.      have multiple  threads. Threads  are  basically just  procedures. The  only
  545.      difference is  that you can  have multiple threads  execute simultaneously.
  546.      This  is a  really nice  feature if  you have  multiple processors  in your
  547.      machine, because with Windows NT, you can have different threads running on
  548.      different  processors,  which makes  for  some  really nice  multi-tasking.
  549.      Synchronization is something that  comes up when you have  multiple threads
  550.      running  at once. Synchronization keeps things from getting out of control.
  551.      Since  synchronization  is  such  an integral  part  of  concurrent  thread
  552.      programming, we'll be talking about it quite a bit here.
  553.  
  554.           I'm picking threads and syncronization as a starting point for several
  555.      reasons.  It's one  of  the most  important,  yet difficult,  obstacles  to
  556.      overcome in programming  for the higher  end Win32 systems (Windows  NT and
  557.      the  yet-to-come 'Chicago'). Understanding  how threads  and syncronization
  558.      work will give you  a good understanding of how  many parts of NT  work and
  559.      interact which is essential to programming for it. In later articles I will
  560.      move to less NT-specific subjects, however.
  561.  
  562.           Let's look at an example:
  563.  
  564.                                         - 10 -
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.           Let's say you have a database program. As a feature  of your database,
  572.      a  user can  go print a  report, and  even if  it's not done  spooling your
  573.      report, it lets you go on to work with the database. So, you go select your
  574.      print report option  and then decide to  make some changes  to some of  the
  575.      records in the file. Well, what happens if you  update a record in the file
  576.      at the  same time that the  reporting thread is reading  that record? Well,
  577.      that's a  problem (and admittedly,  not the most  realistic, but  bear with
  578.      me).  Synchronization allows your update thread to keep all other processes
  579.      from touching that record  until the record is updated. It's kind of like a
  580.      database  record lock,  which is  usually handled  by the  operating system
  581.      (hence the  lack of  realism), but  it's the idea  that I'm  trying to  get
  582.      across.
  583.  
  584.           Here's another  example, you  have a  a program that  does a  bunch of
  585.      repetetive  calculations. To take  advantage of your  muliple CPUs (getting
  586.      realistic now, aren't  I.) you decide to break it up  into threads that run
  587.      concurrently  to  speed things  up.  Well, you  could send  off  a thousand
  588.      threads at  once, but sooner  or later you're  going to run out  of memory,
  589.      performance will go through the floor, etc. So, you need to keep the number
  590.      of threads limited.
  591.  
  592.           First, going  to our last  example of  the calculations, that  kind of
  593.      synchronization  requires a Semaphore.   A Semaphore  keeps a  count of how
  594.      many threads are currently using a resource (in this case, the CPU). When a
  595.      certain  number of threads, as determined by the programmer, are using this
  596.      reousource, no other threads can get to it until one of  the ones currently
  597.      using it ends, or gives up their lock. 
  598.  
  599.           Theres also  the event object  which is  set when  a particular  event
  600.      takes place.  This will release all threads waiting for the event when it's
  601.      set to the signalled state. 
  602.  
  603.           When you've got a few applications that want to use a single resource,
  604.      say a printer, you need to use a different type of synchronization called a
  605.      mutex. A  mutex is  a kind  of synchronization, like  Semaphores in  a way,
  606.      except  only one thing  can use  the resource at  a time. Since  we've just
  607.      discussed Mutex, let's go on to Critical Sections.
  608.  
  609.           Critical Sections are a lot like Mutex objects. Critical Sections work
  610.      with  blocking a single resource at  a time. The Critical Section, however,
  611.      is different from the other three objects we've  talked about in a few very
  612.      important ways. First of all,  Critical Sections only work within  a single
  613.      process (also known as a program, damn I love these fancy words). The other
  614.      synchronization objects will work within a single process, but they'll also
  615.      work across  all processes. If you want to use mutual exclusion in a single
  616.      process and not  globally, go with  the Critical Section.  If for no  other
  617.      reason, it's faster, and we're all speed mongers, aren't we?
  618.  
  619.           I'd like to back up  just a bit, for a second. I've been  saying a lot
  620.      of stuff like, 'multiple threads is great if you have multiple processors',
  621.      and  you're probably thinking, well,  I don't have  multiple processors, so
  622.      why  go through  all the trouble  of threading  if it's not  going to speed
  623.  
  624.                                         - 11 -
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.      things up?  Well, there are other  reasons for threading and  that's what I
  632.      want to  discuss for  a  second. In  a multiple  processor enironment,  the
  633.      better the  threading, the more  the operating system  can utilize all  the
  634.      processors, so it's  obviously a good idea there, I think we've established
  635.      that.  In a  single processor  environment, however,  situations can  arise
  636.      where  threading  can still  speed up  applications. Let's  say you  have a
  637.      program that has to read in some data from  a file and then create a report
  638.      from that  data. Let's also  say that before  the report can  be generated,
  639.      some initialization steps need to  occur. Well, disk usage can  really slow
  640.      down a program. Why not send off a thread to read in  the file, and then go
  641.      on  to do the initialization  while it's reading the file  and then both of
  642.      you meet back and do the report? Kind of a 'you take the high road and I'll
  643.      take the  low road' idea. This way,  the main program's not  bogged down by
  644.      the  speed of  the hard  drive quite  as much.  Threads are  also excellent
  645.      candidates for  server  software in  a  client-server system.  Each  thread
  646.      could, say, handle a client. 
  647.  
  648.           I joked earlier about how we all have multi-processor machines, right?
  649.      Well,  actually,  don't be  too  surprised  if  they start  showing  up  at
  650.      reasonable prices over the next few years. Don't laugh, look how much a 386
  651.      runs these days.  You'd probably have laughed 2 years ago if I told you the
  652.      prices  would get that low. Don't be  to surprised if you see add-on cards,
  653.      at reasonable prices, that  carry, say, 3 additional 486s  as co-processors
  654.      for  your 486, or 5 486s as co-processors, or whatever. The point being, it
  655.      could happen, and I'm betting that it will, especially now  that there's an
  656.      operating system that can handle it.
  657.  
  658.           So, on to the next thing, thread priorities. There are  five levels of
  659.      thread priority that you can assign. Now, in Unix, the way that this works,
  660.      if I  recall correctly (if you ask anyone, they'll tell you my recollection
  661.      is as  reliable as bathroom graffiti)  Unix will accept  a thread priority,
  662.      but modifies it based on  the kind of things the thread does, like disk I/O
  663.      lowers a  thread priority, and  the longer  a thread runs,  the lower  it's
  664.      priority  gets. Something like  that. Anyway, NT  lets you  set your thread
  665.      priority at one of  the 5 levels. The highest priority threads go first. As
  666.      each thread in the higher levels completes, threads in the lower levels are
  667.      run at each level one at a time, like  the first. All of this is calculated
  668.      against the process' (not the thread,  but process) base priority, which is
  669.      assigned by the operating system. This is modified by various factors, such
  670.      as  a process  running  in the  foreground has  it's base  priority raised,
  671.      whereas  a process in  the background has  it's priority lowered.  Also, to
  672.      make sure  all threads get to run, NT will temporarily raise the priorities
  673.      of threads that have been waiting for a long time. It's all pretty complex,
  674.      but the idea  of assigning priorities is just to  give the operating system
  675.      an  idea of how important you think a particular thread is. The best way to
  676.      think  of it  is this.  Take the  processes' (not  the thread,  again) base
  677.      priority. Your thread  can be assigned a priority  of -2 to +2  against the
  678.      processes'  base  priority. i.e.  the lowest  thread  priority is  the base
  679.      thread priority-2. This  is the lowest priority your thread  will ever see.
  680.      If, however, your thread's been sitting  around for a while waiting to run,
  681.      NT will give it a little boost to make sure it runs.
  682.  
  683.  
  684.                                         - 12 -
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.           I keep looking  over this and  I see  a million ways  to improve  this
  692.      article, but given the time I can't do it this month. I  know it's a lot to
  693.      absorb and it's really just meant to give you a taste. Next month I'll have
  694.      some code that  actually uses threads  and I'll explain  how it works.  I'm
  695.      also  going to start talking about  Win32s and give you  some code that you
  696.      can run  on your Windows 3.1  system with the Win32s DLLs.  To avoid adding
  697.      the space of  the API to  the magazine, for  those that aren't  interested,
  698.      I'll have  the code available  on the BBS  along with the  necessary Win32s
  699.      DLLs and VxDs.
  700.  
  701.           Don't let  this months  column scare  you off.  I probably  could have
  702.      explained  things a little  better, with a little  more time. Things should
  703.      become more clear when you see some code.
  704.  
  705.           I suggest that if you have the means  you do get a copy of the  Win32s
  706.      API and DLLs. The future of Windows is going to be 32-bits. I hate to sound
  707.      like a Microsoft  Rep, but they're right. 32-bits is  the next logical step
  708.      and  everyone's going to have to  make it eventually. Better  to hop on now
  709.      and get a jump on the competition.
  710.  
  711.           I'm sure  I'll get lots of  questions on this article  to clarify just
  712.      about everything  I've written so sloppily  here. That's fine, send  me the
  713.      mail and  I'll  be sure  to respond,  if  not personally,  as  part of  the
  714.      magazine. The real problem  was I bit off a  bit more than I can  chew this
  715.      month and I'll try not to do that again. See ya and don't forget to write.
  716.                                              
  717.  
  718.  
  719.  
  720.  
  721.  
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.                                         - 13 -
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.                                   Beginner's Column
  752.                                    By Dave Campbell
  753.  
  754.           Remember last month  I made some silly comment about getting buried in
  755.      work? I must be a prophet!! Anyway, here we are again, and with any kind of
  756.      luck next month you'll also find a review of Microsoft Visual C++ by me.  I
  757.      have been using it since January, and am convinced it is a great way to go.
  758.  
  759.           This  month we are going to add an  "ego" box with a live compile date
  760.      in it to the hello application, and talk some about menus.
  761.  
  762.  
  763.      Ego Box
  764.             
  765.  
  766.           I  like to call the "About" box an  Ego box, because when was the last
  767.      time you saw someone (me included)  that put something other than 'Look who
  768.      wrote this'  into an 'About' box?   For that reason,  we HAVE to  do an Ego
  769.      box, or  what would people think? Thanks to Jeffrey M. Richter in his great
  770.      book  "Windows  3:  A Developer's  Guide",  we  can  add  a little  bit  of
  771.      usefulness to the  Ego box by showing a live compile date. I find this very
  772.      useful for  configuration management, when I  have two (or more)  copies of
  773.      the same thing floating around for testing.
  774.  
  775.           The dialog box declaration  looks very much like the  setup dialog box
  776.      from last month:
  777.  
  778.      ABOUT DIALOG 37, 10, 144, 92
  779.      STYLE WS_POPUP | WS_DLGFRAME
  780.      FONT 8, "Helv"
  781.      BEGIN
  782.           CONTROL "Copyright (C) 1993 WynApse", -1, "STATIC", SS_CENTER | 
  783.                                 WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 8, 130, 11
  784.  
  785.           CONTROL "CompuServe: 72251,445", -1, "STATIC", SS_CENTER | WS_CHILD | 
  786.                                           WS_VISIBLE | WS_GROUP, 17, 17, 109, 8
  787.  
  788.           CONTROL "Version Timestamp:", -1, "STATIC", WS_CHILD | WS_VISIBLE,
  789.                                                                  36, 35, 71, 12
  790.  
  791.           CONTROL "", ID_VERSION, "STATIC", WS_CHILD  | WS_VISIBLE, 22, 45, 100,
  792.      9
  793.  
  794.           CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | 
  795.                                         WS_VISIBLE | WS_TABSTOP, 54, 63, 36, 24
  796.      END
  797.  
  798.           Starting at the top, the  STYLE line is different from the  setup box.
  799.      Instead  of WS_CAPTION,  we  have  WS_DLGFRAME.  For  Ego  boxes,  I  don't
  800.      generally put  a caption.  It doesn't  serve a lot  of purpose,  other than
  801.      being able to move  the box around, and how often do you do more than click
  802.      OK on  an  About box?  This  is personal  preference,  you understand.  The
  803.  
  804.                                         - 14 -
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.      WS_DLGFRAME  puts a nice frame around the  box, and serves no purpose other
  812.      than aesthetics also.
  813.  
  814.           The top three lines of the  dialog are essentially identical in  their
  815.      properties:
  816.  
  817.      CONTROL "text", ID, "class", style, x-position, y-position, 
  818.                                                               x-width, y-width
  819.  
  820.           This is the form of the generalized control statement. The first three
  821.      lines  have an ID of  -1. This is because they  are static controls, and do
  822.      not send messages back to the parent window.
  823.  
  824.      There are six control classes:
  825.  
  826.         button
  827.         static
  828.         edit
  829.         scrollbar
  830.         listbox
  831.         combobox
  832.  
  833.           At this time, we are only dealing with two of them: button and static.
  834.      The version number will be  written to the dialog box, but that  is done by
  835.      the WinApp, not by the user, so it isn't an edit box.
  836.  
  837.           The style parameter  can consist  of logical OR  chains of  individual
  838.      style declarations, of which there are a multitude. I am going to just talk
  839.      about them as we get to them.
  840.  
  841.      The first control line contains:
  842.  
  843.      SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP
  844.  
  845.      where
  846.  
  847.      SS_CENTER  : Center the text in the box
  848.      WS_CHILD   : child window
  849.      WS_VISIBLE : control is initially visible
  850.      WS_GROUP   : first item in a group [we'll deal with this later]
  851.  
  852.      The fourth control contains:
  853.  
  854.      BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP
  855.  
  856.      where
  857.  
  858.      BS_DEFPUSHBUTTON : Default pushbutton, the one selected upon startup
  859.      WS_TABSTOP       : goes along with the group declaration
  860.  
  861.           The fourth  control is different in  that it has ""  for the displayed
  862.      text, and has a  defined control ID,  ID_VERSION. ID_VERSION is defined  in
  863.  
  864.                                         - 15 -
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871.      hello.h, and is used in hello.c to place the text properly.
  872.  
  873.           HELLO.DEF  has a  slight change:  DON'T FORGET TO  PUT THE  DIALOG BOX
  874.      PROCEDURE IN THE  DEF FILE!! This means  the exports list  of the def  file
  875.      becomes:
  876.  
  877.      EXPORTS             WndProc @1
  878.                     HelloDlgProc @2
  879.                     AboutDlgProc @3
  880.  
  881.           Now  we're ready  to  discuss displaying  the  box. This  takes  place
  882.      identically to  the invocation of  the setup  box from last  month. A  menu
  883.      choice is  made, and  a  message is  sent to  our  main Windows  Procedure,
  884.      telling us the  user wants to see a dialog box.  This time, we have added a
  885.      message IDM_HELPABOUT to hello.h to handle this. The function prototype 
  886.  
  887.      BOOL FAR PASCAL AboutDlgProc(HWND, WORD, WORD, LONG);
  888.  
  889.      is listed with the other prototypes above the main body of code. "About" is
  890.      added to the system menu, which will  be explained later in this article. A
  891.      static FARPROC for the pointer to the dialog procedure is declared early in
  892.      WndProc, inline with the  one to the setup  box. Then, just below the  case
  893.      statement  for IDM_SETUP, is one for IDM_HELPABOUT. The two case statements
  894.      match with the  exception of the  name of the  dialog template to  use from
  895.      hello.dlg. The About box code is:
  896.  
  897.      case IDM_HELPABOUT :
  898.         lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc, hInst);
  899.         DialogBox(hInst, "About", hWnd, lpfnAboutDlgProc);
  900.         FreeProcInstance(lpfnAboutDlgProc);
  901.         return 0;
  902.  
  903.           We must  get a long pointer to a function, lpfnAboutDlgProc, to use in
  904.      the  DialogBox function call.  This is actually playing  a game with memory
  905.      segments and far pointers, and segment reloading to enable Windows  to find
  906.      our dialog box function  in memory. All the segmentation  manipulation that
  907.      Windows  gives  you for  free  is  through small  pieces  of memory  called
  908.      "thunks", or instance  thunks, or reload thunks which binds  a data segment
  909.      to the address of  a function. MakeProcInstance takes the procedure  in the
  910.      first parameter, and binds it to the data segment of  the application whose
  911.      handle is in the  second parameter. The return value  from MakeProcInstance
  912.      is actually an address of a reload thunk.
  913.  
  914.           Aren't you glad you know this? Now you do.......
  915.      .....now you've forgotten it, and can get on with programming Windows.
  916.  
  917.           Since you  know this, you'll  realize how important  it is to  release
  918.      that "thunk" when you're finished with it by executing the FreeProcInstance
  919.      call.  In DOS,  we could be  fairly certain  that once  our program exited,
  920.      things would get  cleaned up.  That wasn't good  programming practice  then
  921.      either,  but it worked. If we make that  kind of error in Windows, we leave
  922.      all manner of little potholes in memory, and very often run out.
  923.  
  924.                                         - 16 -
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.           The parameter "About"  in the call is  the title of the dialog  box we
  932.      built in Hello.DLG.  Because of  the 'DialogBox' call, this dialog box will
  933.      be modal,  and control  will not  return  to the  main window  until OK  is
  934.      pressed in the dialog box. 
  935.  
  936.           We do a  return 0 here since we have handled  the message, and have no
  937.      need to execute the default operation.
  938.  
  939.      That gets us to the dialog box procedure itself, 'AboutDlgProc':
  940.  
  941.      BOOL FAR PASCAL AboutDlgProc (HWND hDlg, WORD message, WORD wParam,
  942.                                                                   LONG lParam)
  943.      {
  944.      char szBuffer[100];
  945.  
  946.      switch (message)
  947.         {
  948.         case WM_INITDIALOG :
  949.            wsprintf(szBuffer, "%s at %s", (LPSTR) __DATE__, (LPSTR) __TIME__);
  950.            SetWindowText(GetDlgItem(hDlg, ID_VERSION), szBuffer);
  951.            return TRUE;
  952.  
  953.         case WM_COMMAND :
  954.            switch (wParam)
  955.               {
  956.               case IDOK :
  957.                  EndDialog(hDlg, wParam);
  958.                  return TRUE;
  959.  
  960.               default :
  961.                  return TRUE;
  962.               }
  963.  
  964.         default :
  965.            return FALSE;
  966.         }
  967.      }                                       /* AboutDlgProc */
  968.  
  969.           The WM_COMMAND switch  case is  virtually identical to  the setup  box
  970.      from  last  time,  the   new  stuff  being  the  WM_INITDIALOG   case.  The
  971.      WM_INITDIALOG message is  the first message a dialog  box receives. At that
  972.      point in time,  we fill in a message  buffer with compile date and  time in
  973.      this manner:
  974.  
  975.      wsprintf(szBuffer, "%s at %s", (LPSTR) __DATE__, (LPSTR) __TIME__);
  976.  
  977.      __DATE__ and  __TIME__ are predefined  global identifiers that  contain the
  978.      date and time that processing began on the current file.
  979.  
  980.           This line of text is inserted  into the ID_VERSION control on the face
  981.      of the dialog by the following line:
  982.  
  983.  
  984.                                         - 17 -
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.      SetWindowText(GetDlgItem(hDlg, ID_VERSION), szBuffer);
  992.  
  993.           GetDlgItem  returns the  child window's  handle  for the  control, and
  994.      allows us to insert our text into the dialog box. 
  995.  
  996.  
  997.      Menus
  998.           
  999.  
  1000.           Now  let's discuss menus. Because  everyone is familiar  with them, we
  1001.      should be able  to beat them  to death pretty  soundly. How many  menus are
  1002.      there in  Windows and how  do we  enable/disable them? Anybody?   Ok,  I'll
  1003.      address  it: There  is a  system menu which  may be  part of  any window or
  1004.      dialog box (which is just a child window). Then there is a menu that may be
  1005.      declared in the window class declaration. There are popup menus that can be
  1006.      used pretty much anywhere.
  1007.  
  1008.                    
  1009.         System Menu
  1010.  
  1011.           The  system menu is enabled/disabled with the properties of the window
  1012.      declaration.   This is invoked by clicking  the dashed line boxed in on the
  1013.      left of the caption bar (the System Menu button). This is also the menu you
  1014.      get when you single click an icon.
  1015.  
  1016.           The system menu  is enabled by including  the WS_SYSMENU style  in the
  1017.      window creation.
  1018.  
  1019.  
  1020.                         
  1021.         Application Menu
  1022.  
  1023.           The  Application menu is  declared at  class-registration time  of the
  1024.      window:
  1025.  
  1026.      wc.lpszMenuName  = szAppName;
  1027.  
  1028.           Normally, the  name of the  program is also the  name of the  menu, so
  1029.      szAppName is useable here.
  1030.  
  1031.           The  ninth parameter in  the CreateWindow call  is of type  HMENU, and
  1032.      this overrides  the menu in  the menu class.  This gives you  the option of
  1033.      having multiple windows use  the same class, and  have different menus.  If
  1034.      the one in the class is the one you want (as we are doing) leave the ninth
  1035.      parameter as NULL.
  1036.  
  1037.                    
  1038.         Popup Menus
  1039.  
  1040.           Popup menus are declared either as  part of the main menu, or possibly
  1041.      on the fly  during run-time, and may  displayed as an action  from the main
  1042.      menu, or possibly a run-time event.
  1043.  
  1044.                                         - 18 -
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.      CUA
  1053.         
  1054.  
  1055.           As with any user interface, and more importantly, an interface that is
  1056.      shared,  you  want to  provide  your  users (it  might  be  you) an  easily
  1057.      recognizeable way to  use your product. It may be cute to put the help pull
  1058.      down  on the  left side  of  the main  menu, and  it  certainly would  grab
  1059.      people's attention, but not in the way most of us would like!
  1060.  
  1061.           All of  this melts down into me stating that  in the case of menus, if
  1062.      you want  one, make  it look like  everyone elses. At  least for  the major
  1063.      pieces.  This  is called  CUA,  which stands  for  Common User  Access. The
  1064.      orignial  standard of  CUA was  developed by IBM.  The current  standard is
  1065.      Microsoft's  "Application  Design  Guide" (ISBN  1-55615-384-8).  The  most
  1066.      important point being  to be standard!  The hello.rc code  for the menu  is
  1067.      quite long, and only pieces of it will be show here:
  1068.  
  1069.      Hello menu
  1070.      begin
  1071.           popup "&File"
  1072.           begin
  1073.                menuitem "&New",              IDM_FILENEW
  1074.                menuitem "&Open...",          IDM_FILEOPEN
  1075.            .
  1076.           end
  1077.  
  1078.           popup "&Edit"
  1079.           begin
  1080.            menuitem "&Undo\tCtrl+Z",     IDM_EDITUNDO
  1081.            menuitem "&Repeat",           IDM_EDITREPEAT
  1082.            .
  1083.           end
  1084.  
  1085.           popup "&Sample"
  1086.           begin
  1087.                menuitem "&Dialog",           IDM_SAMPLEDLG
  1088.            menuitem separator
  1089.            menuitem "&Alternate..."      IDM_ALTERNATE
  1090.           end
  1091.  
  1092.           popup "&Help"                    
  1093.           begin
  1094.                menuitem "&Index",            IDM_HELPINDX
  1095.            menuitem "&Keyboard",         IDM_HELPKBD
  1096.            .
  1097.            menuitem "&About Hello",      IDM_HELPABOUT
  1098.           end
  1099.      end
  1100.  
  1101.      The menu has a basic structure:
  1102.  
  1103.  
  1104.                                         - 19 -
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111.      "Name" menu
  1112.      begin
  1113.      end
  1114.  
  1115.      inside  the begin..end pair is the  menu itself. Each entry  in our menu is
  1116.      listed as  'popup'. This means that each of the entries is a kick-off point
  1117.      for a popup, or pull-down type of menu whose structure follows.
  1118.  
  1119.           The  structure for the  popup menus is  identical to that  of the main
  1120.      menu with the exception of the word 'popup':
  1121.  
  1122.           popup "Name"
  1123.           begin
  1124.                menuitem "Sub1",          IDM_SUB1NAME
  1125.                menuitem "Sub2",          IDM_SUB2NAME
  1126.            .
  1127.           end
  1128.  
  1129.      Popups can have popups can have...you get the idea.
  1130.  
  1131.      Each menu item has three parts:
  1132.  
  1133.      1) The text that appears on the menu
  1134.      2) The ID number of the menu item
  1135.      3) An attribute for that item
  1136.  
  1137.                  
  1138.         Menu Text
  1139.  
  1140.           The  menu text is copied  directly to the menu  in the manner you type
  1141.      it, with the addition that any character preceeded by an ampersand, "&", is
  1142.      underlined in the menu.   The underlined characters, when combined with the
  1143.      Alt key, provide the user a 'hot-key'  method to that item. Without the "&"
  1144.      the user may still use the Alt key with the first letter of any menu item.
  1145.  
  1146.           Two  control characters '\t' and  '\a' are optionally  used inside the
  1147.      text. The tab character, '\t' will space the menu item in  a new column far
  1148.      enough  to  the  right to  make  room  for  the  longest text  line  in  an
  1149.      accompanying popup menu.  The '\a'  is normally  used with  HELP, and  will
  1150.      right-justify the menu selection.
  1151.  
  1152.                
  1153.         Menu ID
  1154.  
  1155.           The menu IDs  are defined as normal  in the .H  file, as we are  doing
  1156.      with Hello.H.
  1157.  
  1158.                        
  1159.         Menu Attributes
  1160.  
  1161.      The attributes are a small enough number I will list them:
  1162.  
  1163.  
  1164.                                         - 20 -
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.      1) CHECKED      - displays a check mark to the left of the menu text
  1172.      2) GRAYED       - grays out the text, and is also INACTIVE
  1173.      3) INACTIVE     - does not gray out the text, but sends no message to the
  1174.                        application
  1175.      4) MENUBREAK    - This item, and following appear in a new column
  1176.      5) MENUBARBREAK - This item, and following appear in a new column,
  1177.                        separated by a vertical line
  1178.  
  1179.           In  order to keep  the main menu  standard, I  didn't add any  of this
  1180.      stuff  to it,  however, there  is a  secondary menu,  "Hello2",  defined in
  1181.      hello.rc that shows GRAYED and CHECKED items.
  1182.  
  1183.           I took one  slight excursion from  the "standard" menuing, and  to the
  1184.      'Sample' popup, I added:
  1185.  
  1186.            menuitem separator
  1187.            menuitem "&Alternate..."      IDM_ALTERNATE
  1188.  
  1189.           Alternate is used in Hello.c to bring up the secondary  menu. When the
  1190.      second menu is being used, Grayed/Ungrayed, and One/Two show the use of the
  1191.      attributes in your code.
  1192.  
  1193.  
  1194.      System Menu
  1195.                 
  1196.  
  1197.           The system menu is not really there for us to add to, but  many people
  1198.      do, and it is definitly a quick way to get an about  box up. Since the menu
  1199.      is not defined in our code, we need to add to it at run time.  This is done
  1200.      by using  the  AppendMenu command.    A menu  pointer  (of type  HMENU)  is
  1201.      declared, and a pointer to the System Menu is captured:
  1202.  
  1203.      hMenu = GetSystemMenu(hWndMain, FALSE);
  1204.  
  1205.      Then the append is accomplished as follows:
  1206.  
  1207.      AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
  1208.      AppendMenu(hMenu, MF_STRING,IDM_SETUP, "Setup...");
  1209.  
  1210.           I like to put a separator (a horizonal line) between the default setup
  1211.      items and anything I  add. There are a few  things that need to  be handled
  1212.      when using the system menu:
  1213.  
  1214.      1) the IDs used must be < F000H to avoid conflict with the normal system
  1215.         menu commands
  1216.  
  1217.      2) any WM_SYSCOMMAND messages not captured must be passed to the default
  1218.         window processor, or else they won't get executed.
  1219.  
  1220.      From hello.c, in WndProc, we find the following code:
  1221.  
  1222.      switch (message)
  1223.  
  1224.                                         - 21 -
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.         {
  1232.         .
  1233.         case WM_SYSCOMMAND :
  1234.            switch (wParam)
  1235.               {
  1236.               case IDM_SETUP :
  1237.                  lpfnHelloDlgProc = MakeProcInstance(HelloDlgProc, hInst);
  1238.                  DialogBox(hInst, "Hello", hWnd, lpfnHelloDlgProc);
  1239.                  FreeProcInstance(lpfnHelloDlgProc);
  1240.                  return 0;
  1241.               }
  1242.  
  1243.            break;
  1244.          .
  1245.          }
  1246.      return DefWindowProc(hWnd, message, wParam, lParam);
  1247.  
  1248.      the message passed is WM_SYSCOMMAND if a menu item from  the system menu is
  1249.      selected. The item selected is passed in wParam. Therefore, a second switch
  1250.      case  is necessary  to  capture  the system  menu  commands. In  the  above
  1251.      example, IDM_SETUP is handled  locally by displaying the setup  dialog box,
  1252.      but  any  other system  commands  are  sent  along  to the  default  window
  1253.      procedure DefWindowProc. This will ensure that nothing is lost.  
  1254.  
  1255.           You could  'trap' out certain  system menu commands  at this point  by
  1256.      executing the function  yourself and  returning 0. the  normal system  menu
  1257.      options and their IDs are:
  1258.  
  1259.      Restore      SC_RESTORE
  1260.      Move         SC_MOVE
  1261.      Size         SC_SIZE
  1262.      Minimize     SC_MINIMUM
  1263.      Maximize     SC_MAXIMUM
  1264.      Close        SC_CLOSE
  1265.      Switch To    SC_TASKLIST
  1266.  
  1267.      Menu Modification
  1268.                       
  1269.  
  1270.           Just  as the system menu was  appended above, there are other commands
  1271.      that may be executed to modify menus:
  1272.  
  1273.      1) AppendMenu
  1274.      2) DeleteMenu - deletes a menu item, and destroys the item
  1275.      3) InsertMenu - Inserts an item
  1276.      4) ModifyMenu - changes an item
  1277.      5) RemoveMenu - removes an item from a menu
  1278.  
  1279.           Delete Menu would  destroy a  POPUP menu for  example, and  RemoveMenu
  1280.      would only remove the ability to bring it up from the main.
  1281.  
  1282.  
  1283.  
  1284.                                         - 22 -
  1285.  
  1286.  
  1287.  
  1288.  
  1289.  
  1290.  
  1291.      Hello.C
  1292.             
  1293.  
  1294.           Now let's look  a little closer  at the code  from Hello.C this  month
  1295.      that handles menus:
  1296.  
  1297.           As  explained  above,  the  main  application  menu  is  declared   at
  1298.      class-registration time of the window. That's  all it takes to put the menu
  1299.      up in your app. In the WM_CREATE case of WndProc, we added the line:
  1300.  
  1301.            hMainMenu = GetMenu(hWnd);
  1302.  
  1303.           This gives us a handle to restore back to the main menu "Hello", after
  1304.      we have  been using  the alternate  one. We normally  wouldn't have  had to
  1305.      capture this handle. WM_COMMAND is where the action all takes place. wParam
  1306.      is the  menu entry selected by the  user. Since we are  going to be messing
  1307.      around with the attributes in the sub-menu, we capture a menu handle inside
  1308.      this case statement for that purpose.
  1309.  
  1310.           For the menu items, all I did was to setup a print line for  each menu
  1311.      entry, and fall through to the MessageBox routine at the bottom.
  1312.  
  1313.      IDM_ALTERNATE  simply executes a SetMenu  command which switches  us to the
  1314.      alternate menu defined in hello.rc.
  1315.  
  1316.      ALTONE/ALTTWO and ALTGRAY/ALTUNGRAY  use a brute-force  method of  toggling
  1317.      each other on and off.
  1318.  
  1319.      IDM_ALTRESTORE restores the main menu we started with.
  1320.  
  1321.           Since  we  have only  one  Windows  Application,  you'll  notice  that
  1322.      independent of which menu is alive at the time, we still have to handle all
  1323.      the cases for both, all the time.
  1324.  
  1325.  
  1326.      End.
  1327.          
  1328.  
  1329.           I think  it probably takes two issues before the feedback comes in, so
  1330.      this column is running slightly open-loop at this point. In  other words, I
  1331.      am still steering. I want  some help steering, so get me  some feedback. In
  1332.      particular, I  am looking for  ideas on a  useful WinApp we  can build from
  1333.      scratch explaining as we go, hopefully building off what we've already done
  1334.      here. 
  1335.  
  1336.           I have one correction, or addition to last month's article.   I talked
  1337.      about Borland programmers needing to add:
  1338.  
  1339.      #define WINVER 0x0300
  1340.  
  1341.      ahead of  your include of windows.h  in your hello.c file  to compile under
  1342.      the 3.1 compiler for Windows 3.0. This holds true for Microsoft programmers
  1343.  
  1344.                                         - 23 -
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350.  
  1351.      also. Additionally, changing
  1352.  
  1353.      wc.lpfnWndProc   = WndProc;             /* Name of proc to handle window */
  1354.  
  1355.      to be:
  1356.  
  1357.      wc.lpfnWndProc   = (WNDPROC)WndProc;    /* Name of proc to handle window */
  1358.  
  1359.      holds true for Microsoft, too.
  1360.  
  1361.           One other thing I  noticed is that  I held a pretty  hard line on  not
  1362.      going beyond  the  page width  for  long lines.  Since  that was  my  first
  1363.      article, I didn't realise that I had a line length of about 75, and while I
  1364.      was  complaining about  long lines,  I was  displaying them,  too...sorry!!
  1365.      Please hang in there.  If you are beyond  the scope of this  article, stick
  1366.      with me - we are  going to go places together. If you are  way beyond this,
  1367.      write  us an article. If you are bogged down, just compile it, and stare at
  1368.      the source. If you want help with something, send me a note.
  1369.  
  1370.           That's it for this time. Next month we're going to add a file list box
  1371.      the hard  way, and discuss  list boxes  in general, and  how to  manipulate
  1372.      text/filenames in them. Feel free to contact me in any of the ways below. I
  1373.      want to  rat out the  things other people  are having questions  about, not
  1374.      just what I think people want to hear.
  1375.  
  1376.      Dave Campbell 
  1377.         WynApse PO Box 86247 Phoenix, AZ 85080-6247 (602)863-0411    
  1378.         CIS: 72251, 445
  1379.         Phoenix ACM BBS (602) 970-0474 - WynApse SoftWare forum
  1380.  
  1381.  
  1382.  
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.                                         - 24 -
  1405.  
  1406.  
  1407.  
  1408.  
  1409.  
  1410.  
  1411.                                 Owner-Drawn List Boxes
  1412.                                    By Mike Wallace
  1413.  
  1414.           If you've ever wanted to liven up your list boxes with color, then you
  1415.      need to know about owner-drawn list boxes.   I recently wanted to create  a
  1416.      list box and color-code  each item in the list  based upon its value.   The
  1417.      only way to do this is with an owner-drawn list box, which is just what the
  1418.      name implies -  the owner (i.e., the programmer)  has to draw the  list box
  1419.      himself.  It's a  little bit of work, but well worth the effort.  The basis
  1420.      for  any  owner-drawn control  is  the DRAWITEMSTRUCT  structure,  which is
  1421.      declared as follows:
  1422.  
  1423.           typedef struct tagDRAWITEMSTRUCT {
  1424.                UINT  CtlType;
  1425.                UINT  CtlID;
  1426.                UINT  itemID;
  1427.                UINT  itemAction;
  1428.                UINT  itemState;
  1429.                HWND  hwndItem;
  1430.                HDC   hDC;
  1431.                RECT  rcItem;
  1432.                DWORD itemData;
  1433.           } DRAWITEMSTRUCT;
  1434.  
  1435.           The  owner  of  the owner-drawn  control  receive  a  pointer to  this
  1436.      structure  as  the  lParam parameter  of  the  WM_DRAWITEM  message.   This
  1437.      structure is  described completely  in the  Microsoft documentation,  but I
  1438.      want to describe  a few (the important ones)  so you won't have to  get out
  1439.      your manuals just to read this article:
  1440.  
  1441.           hDC : the device context for the list box (very important)
  1442.  
  1443.           itemID : the index of the itme in the list box
  1444.  
  1445.           itemAction : describes the drawing action required by the
  1446.                owner and will have one of the following values:
  1447.  
  1448.                ODA_DRAWENTIRE : The entire list box needs to be drawn
  1449.  
  1450.                ODA_FOCUS      : The list box has gained or lost focus
  1451.  
  1452.                ODA_SELECT     : The selection status has changed
  1453.  
  1454.           itemState  : describes  what  the  item  will  look  like  after  it's
  1455.                been drawn; it will have one of the following values:
  1456.  
  1457.                ODS_CHECKED    : The menu item is to be checked
  1458.  
  1459.                ODS_DISABLED   : The item is to be drawn as disabled
  1460.  
  1461.                ODS_FOCUS      : The item has input focus
  1462.  
  1463.  
  1464.                                         - 25 -
  1465.  
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471.                ODS_GRAYED     : The menu item is to be grayed
  1472.  
  1473.                ODS_SELECTED   : The item has been selected by the user
  1474.  
  1475.           itemData  : contains  the  value  last assigned  to  the  list box  by
  1476.                an  LB_SETITEMDATA   message.     If   the  list   box  has   the
  1477.                LBS_HASSTRINGS  style,  this  value  is  initially  zero;   else,
  1478.                this  value is  initially  the  value  passed  to  the  list  box
  1479.                in   the  lParam   parameter  of   either  the   LB_ADDSTRING  or
  1480.                LB_INSERTSTRING message.
  1481.  
  1482.  
  1483.           Enough small talk.  On to the program...
  1484.  
  1485.           For this  example, I'm using a  dialog box containing only  a list box
  1486.      and an "OK" button.  If the user selects an item in  the list box, give the
  1487.      item a different color.   In the function handling this dialog box, we only
  1488.      care  about  the  following   four  messages:  WM_INITDIALOG,   WM_COMMAND,
  1489.      WM_DRAWITEM  and WM_MEASUREITEM.   Here's  a brief  description of  how the
  1490.      program will handle each of these messages:
  1491.  
  1492.           WM_INITDIALOG :  The dialog box is  getting created, so we  have to do
  1493.      two things: a) use the GetDlgItem() function on the list box control to get
  1494.      a handle to the list box; and b) use that handle to  fill the list box with
  1495.      an array of strings  using the SendMessage() function and  the LB_ADDSTRING
  1496.      message.
  1497.  
  1498.           WM_COMMAND : If the user presses the OK button, exit the function.
  1499.  
  1500.           WM_DRAWITEM :  If the status of any item  in the list box gets changed
  1501.      (including the initial filling of the list box), this message  gets sent to
  1502.      your function.  Check the value of the itemAction field.  For this example,
  1503.      I'll handle the ODA_DRAWENTIRE and ODA_SELECT cases with the same code that
  1504.      handles both the selected and unselected states.  For the ODA_FOCUS case, I
  1505.      will just call DrawFocusRect().
  1506.  
  1507.           WM_MEASUREITEM  : This message gets sent so  you can set the height of
  1508.      the items in the list box.  Create a device context for the dialog  box and
  1509.      then use the GetTextMetrics() function to determine the font height.
  1510.  
  1511.           The  definition for  the  dialog  box  also  needs  to  be  discussed.
  1512.      Primarily,  the list  box must  have either  the LBS_OWNERDRAWFIXED  or the
  1513.      LBS_OWNERDRAWVARIABLE  styles.   The  latter allows  each  item to  have  a
  1514.      different  height.   I'm using  the former  for this  program.   Here's the
  1515.      "ODLBOX.DLG" file:
  1516.  
  1517.  
  1518.      ODLISTBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 60, 25, 120, 120
  1519.      STYLE WS_CAPTION | WS_DLGFRAME | WS_POPUP
  1520.      CAPTION "Owner-Drawn List Box"
  1521.      BEGIN
  1522.           CONTROL "", IDB_LISTBOX, "listbox", LBS_OWNERDRAWFIXED |
  1523.  
  1524.                                         - 26 -
  1525.  
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531.                LBS_HASSTRINGS | LBS_STANDARD | WS_VSCROLL | WS_GROUP |
  1532.                WS_TABSTOP | WS_CHILD, 25, 10, 75, 85
  1533.           CONTROL "OK", IDB_OK, "button", BS_DEFPUSHBUTTON | 
  1534.                WS_TABSTOP | WS_CHILD, 40, 100, 40, 14
  1535.      END
  1536.  
  1537.           I've defined ODLISTBOX, IDB_LISTBOX and IDB_OK in the "ODLBOX.H" file.
  1538.      All that leaves is the code for the function itself.  Here it is:
  1539.  
  1540.  
  1541.      // Function to handle an owner-drawn list box
  1542.      #include <windows.h>
  1543.      #include "odlbox.h"
  1544.  
  1545.      BOOL FAR PASCAL ODListBox(HWND hDlg, unsigned message, WORD wParam,
  1546.      LONG lParam) {
  1547.  
  1548.      // define some colors for the selected text and background
  1549.      #define GREEN  RGB(0,255,0)
  1550.      #define BLUE   RGB(0,0,255)
  1551.  
  1552.      HWND hLst;                    // handle to the list box
  1553.      HDC  hDC;                     // device context handle
  1554.      LPDRAWITEMSTRUCT lpDIS;       // long pointer to DRAWITEMSTRUCT
  1555.      LPMEASUREITEMSTRUCT lpMIS;    // long pointer to MEASUREITEMSTRUCT
  1556.      TEXTMETRIC tm;                // text info structure
  1557.  
  1558.      HBRUSH hBrush;                // draws text background
  1559.      DWORD OldTextColor;           // saves old text color
  1560.      DWORD OldBkColor;             // saves old background color
  1561.  
  1562.      int NumItems;                 // number of items in list box
  1563.      int i;                        // temporary variable
  1564.  
  1565.      char textStr[80];             // list box item string buffer
  1566.      char *textItems[] =
  1567.      {                             // strings going into the list box
  1568.        "One",
  1569.        "Two",
  1570.        "Three",
  1571.        "Four",
  1572.        "Five",
  1573.        "Six",
  1574.        "Seven",
  1575.        "Eight",
  1576.        "Nine",
  1577.        "Ten"
  1578.      };
  1579.  
  1580.      NumItems= 10;
  1581.  
  1582.      switch (message) {
  1583.  
  1584.                                         - 27 -
  1585.  
  1586.  
  1587.  
  1588.  
  1589.  
  1590.  
  1591.           case WM_INITDIALOG:
  1592.                hLst= GetDlgItem(hDlg, IDB_LISTBOX);
  1593.                for(i = 0; i < NumItems; ++i)
  1594.                     SendMessage(hLst, LB_ADDSTRING, 0, (LONG)
  1595.                          (LPSTR) textItems[i]);
  1596.                SetFocus(GetDlgItem(hDlg, IDB_OK));
  1597.                break;
  1598.  
  1599.           case WM_COMMAND:
  1600.  
  1601.                if(wParam == IDB_OK) {
  1602.                     EndDialog(hDlg, NULL);
  1603.                     return TRUE;
  1604.                }
  1605.                break;
  1606.  
  1607.           case WM_DRAWITEM:
  1608.  
  1609.                // copy the DRAWITEMSTRUCT pointer from lParam
  1610.                lpDIS= (LPDRAWITEMSTRUCT)lParam;
  1611.  
  1612.                // if no items in the list box yet, set focus
  1613.                if(lpDIS->itemID == -1) {
  1614.                  DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
  1615.                  return TRUE;
  1616.                }
  1617.  
  1618.                // draw items in list box and check for selection
  1619.                if((lpDIS->itemAction & ODA_DRAWENTIRE) ||
  1620.                     (lpDIS->itemAction & ODA_SELECT)) {
  1621.  
  1622.                     // Get the text string and save in textStr
  1623.                     SendMessage(hLst, LB_GETTEXT, (WORD)lpDIS->itemID,
  1624.                          (LONG) (LPSTR) textStr);
  1625.  
  1626.                     // Handle the selection state
  1627.                     if (lpDIS->itemState & ODS_SELECTED) {
  1628.  
  1629.                          // text was selected, so make it green on blue
  1630.                          // first, draw and fill background
  1631.                          hBrush= CreateSolidBrush(BLUE);
  1632.                          FillRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem,
  1633.                               hBrush);
  1634.                          DeleteObject(hBrush);
  1635.  
  1636.                          // set colors and output the text
  1637.                          OldTextColor= SetTextColor(lpDIS->hDC, GREEN);
  1638.                          OldBkColor= SetBkColor(lpDIS->hDC, BLUE);
  1639.                          TextOut(lpDIS->hDC, (int)(lpDIS->rcItem.left),
  1640.                               (int)(lpDIS->rcItem.top), (LPSTR)textStr,
  1641.                               lstrlen(textStr));
  1642.  
  1643.  
  1644.                                         - 28 -
  1645.  
  1646.  
  1647.  
  1648.  
  1649.  
  1650.  
  1651.                          // restore old colors
  1652.                          SetTextColor(lpDIS->hDC, OldTextColor);
  1653.                          SetBkColor(lpDIS->hDC, OldBkColor);
  1654.  
  1655.                     }
  1656.                     else {
  1657.  
  1658.                          // item not selected, so make it black on white
  1659.                          // first, draw and fill background
  1660.                          hBrush= GetStockObject(WHITE_BRUSH);
  1661.                          FillRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem,
  1662.                               hBrush);
  1663.  
  1664.                          // next, draw the text
  1665.                          TextOut(lpDIS->hDC, (int)(lpDIS->rcItem.left),
  1666.                               (int)(lpDIS->rcItem.top), (LPSTR)textStr,
  1667.                               lstrlen(textStr));
  1668.  
  1669.                     }
  1670.  
  1671.                     // Check for focus state
  1672.                     if(lpDIS->itemState & ODS_FOCUS)
  1673.                       DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
  1674.  
  1675.                     return TRUE;
  1676.  
  1677.                }
  1678.  
  1679.                if(lpDIS->itemAction & ODA_FOCUS) {
  1680.  
  1681.                     DrawFocusRect(lpDIS->hDC, (LPRECT)&lpDIS->rcItem);
  1682.                     return TRUE;
  1683.  
  1684.                }
  1685.                break;
  1686.  
  1687.           case WM_MEASUREITEM:
  1688.  
  1689.                /* get and use height of current font */
  1690.                lpMIS= (LPMEASUREITEMSTRUCT)lParam;    // copy info ptr
  1691.                hDC= GetDC(hDlg);                  // create a DC
  1692.                GetTextMetrics(hDC, &tm);          // get text info
  1693.                lpMIS->itemHeight= tm.tmHeight;    // get text height
  1694.                ReleaseDC(hDlg, hDC);              // free the DC
  1695.                return TRUE;
  1696.  
  1697.      } /* switch(message) - end */
  1698.      return FALSE;
  1699.  
  1700.      } /* ODListBox() - end */
  1701.  
  1702.  
  1703.  
  1704.                                         - 29 -
  1705.  
  1706.  
  1707.  
  1708.  
  1709.  
  1710.  
  1711.                     Beginner's Column for Turbo Pascal for Windows
  1712.                                     By Bill Lenson
  1713.  
  1714.      Welcome one, welcome all to the first of, hopefully, many beginner's Pascal
  1715.      columns.  If you've just purchased Turbo Pascal for Windows (TPW) or had it
  1716.      for a while I think this column will  be of interest to you.  I'll try  not
  1717.      to go  too fast so  everyone gets lost but  not too slow  that nothing gets
  1718.      said either.  Hey, I'm a programmer but I haven't forgotten what  it's like
  1719.      learning  a new language.   Pascal is  different from most  languages and I
  1720.      think it will be a lot of fun.
  1721.  
  1722.      How  much computer experience  do you need  to understand this  stuff?  Not
  1723.      much.  You  should have a basic grasp of USING  windows and know enough DOS
  1724.      (or Windows File Manager if you prefer) to make directories and copy files.
  1725.      That's it.  Everything else will be covered in the articles.
  1726.  
  1727.      All too  often I've seen  people try to  learn a  language like Pascal  and
  1728.      ultimately get frustrated after a  month or two.  Their problem  is simple:
  1729.      they may have picked up some really neat tricks to  develop simple programs
  1730.      but they lack the fundamentals needed  to soundly write large programs.  To
  1731.      be a really  good Pascal programmer you will  need to learn lots  of really
  1732.      scary  things.   First  you  will need  to  learn the  fundamentals  of the
  1733.      language.   This isn't TOO bad  because Pascal programs are  fairly easy to
  1734.      read.   Next, you'll need to  learn algorithms and data  structures.  These
  1735.      are  the building blocks of any program.   Thirdly, given a problem, you'll
  1736.      need to know how to analyze  it and produce a program to turn  concept into
  1737.      reality.
  1738.  
  1739.      Finally,  you must  learn  all the  extensions your  particular environment
  1740.      offers  to Pascal.  For  this column we're using  Windows so you'll need to
  1741.      become  aware of the thousand or so  functions available to you in Windows.
  1742.      To complicate matters, you  can't effectively learn these  things one at  a
  1743.      time.  To be a successful learner, you need  to be exposed to everything at
  1744.      once but not so much of each that you'll run screaming into the night.
  1745.  
  1746.      Have I scared  anyone?  I hope  not.  Pascal isn't a  difficult language to
  1747.      learn  if you  take it in  small steps.   I  was fortunate enough  to start
  1748.      learning  "3rd generation"  languages out  of a  BASIC book  in 1981  which
  1749.      introduced  the language in  7 steps.   Two years later  I started learning
  1750.      Pascal  in University.   By applying  small, logical  steps (or  at least I
  1751.      should  have - hindsight  is 20-20) I  could have dramatically  reduced the
  1752.      learning in my first  four month  course into a couple of weeks.  Pascal is
  1753.      a much  more robust  language than  BASIC and  will require probably  three
  1754.      times  that many steps to  learn.  Hey,  I was looking for  a name for this
  1755.      column.  "Pascal in  21 Steps".  I like  it.  Anyway, the emphasis  in each
  1756.      step (column)  will be to study  problem solving as you  learn the language
  1757.      and introduce Windows extensions as you go.
  1758.  
  1759.      That's it for the first Turbo Pascal for Windows  column.  Next month we'll
  1760.      start in  on the  writing your  first Pascal program.   Things  will really
  1761.      start to move then.  See you next month.
  1762.  
  1763.  
  1764.                                         - 30 -
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.  
  1771.      Bill  Lenson holds a  Bachelor of Computer  Science from  the University of
  1772.      Windsor.  He  is  currently  employed  at  Price  Waterhouse  Canada  as  a
  1773.      consultant in their  National Technology  Services department.   Bill is  a
  1774.      team leader in  the development of a major Windows software package written
  1775.      in C++ and Pascal.
  1776.  
  1777.  
  1778.  
  1779.  
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.  
  1787.  
  1788.  
  1789.  
  1790.  
  1791.  
  1792.  
  1793.  
  1794.  
  1795.  
  1796.  
  1797.  
  1798.  
  1799.  
  1800.  
  1801.  
  1802.  
  1803.  
  1804.  
  1805.  
  1806.  
  1807.  
  1808.  
  1809.  
  1810.  
  1811.  
  1812.  
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.  
  1821.  
  1822.  
  1823.  
  1824.                                         - 31 -
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.                                     Hacker's Gash
  1832.  
  1833.  
  1834.           This  month's column  is by Wim  Harrison (hope  I have  the last name
  1835.      right; I forgot to write it down after downloading his note).
  1836.  
  1837.      4 States of a button
  1838.      --------------------
  1839.           I  read with great interest,  and mounting despair,  the article about
  1840.      bitmapped buttons in WPJ 1-3. Yet again we have someone (just the latest in
  1841.      a long list) repeating the MS line that only 3 button states are needed.
  1842.  
  1843.           NOT! A button has  4 states - Normal, Focussed-not  pressed, Focussed-
  1844.      pressed, and  disabled (count  'em -  4). Everyone seems  to omit  the last
  1845.      state - disabled.
  1846.  
  1847.           What I  do is to have a normal  button (not focussed, not pressed) but
  1848.      with the international 'no entry'  red diagonal bar across it. Then  if you
  1849.      do a call to 'EnableWindow( hButton, FALSE)' it immediately acquires a  red
  1850.      bar to show it is not available. Even Borland don't catch this, and I think
  1851.      it adds greatly to the user friendliness of the system.
  1852.  
  1853.           I have included the source (the Pascal version, I have C code as well)
  1854.      for the code I use. I use the following:
  1855.  
  1856.        ID + 100 = Normal
  1857.        ID + 200 = Focussed
  1858.        ID + 300 = Pressed
  1859.        ID + 400 = Disabled - the special one.
  1860.  
  1861.      Note it takes only one extra line to handle this
  1862.  
  1863.      ------------------------ Cut here --------------------------
  1864.  
  1865.      PROCEDURE DrawControl( hWind : HWND; lpInfo : PDRAWITEMSTRUCT );
  1866.      BEGIN
  1867.         IF ( lpInfo^.CtlType <> ODT_BUTTON ) THEN
  1868.            Exit;
  1869.         ResID := ( lpInfo^.CtlID MOD 100 );
  1870.         Inc( ResID, 100 );
  1871.      { }
  1872.         IF ( lpInfo^.itemState AND ODS_DISABLED ) <> 0 THEN
  1873.              Inc( ResID, 300 )
  1874.         ELSE
  1875.            IF ( lpInfo^.itemState AND ODS_SELECTED ) <> 0 THEN
  1876.                 Inc( ResID, 200 )
  1877.            ELSE
  1878.               IF ( lpInfo^.itemState AND ODS_FOCUS ) <> 0 THEN
  1879.                  Inc( ResID, 100 );
  1880.  
  1881.         hBM := LoadBitmap( System.hInstance, MAKEINTRESOURCE( ResID ) );
  1882.         IF ( hBM = 0 ) THEN
  1883.  
  1884.                                         - 32 -
  1885.  
  1886.  
  1887.  
  1888.  
  1889.  
  1890.  
  1891.            Exit;
  1892.         IF  ( ( lpInfo^.itemAction AND ODA_DRAWENTIRE ) <> 0 ) OR
  1893.             ( ( lpInfo^.itemAction AND ODA_FOCUS      ) <> 0 ) OR
  1894.             ( ( lpInfo^.itemAction AND ODA_SELECT     ) <> 0 ) THEN
  1895.             BEGIN
  1896.                hMemDC := CreateCompatibleDC( lpInfo^.hDC );
  1897.                hOldbm := SelectObject( hMemDC, hBM );
  1898.                IF ( hOldbm <> 0 ) THEN
  1899.                   BEGIN
  1900.                      StretchBlt(lpInfo^.hDC,
  1901.                                 lpInfo^.rcItem.left, lpInfo^.rcItem.top,
  1902.                                 lpInfo^.rcItem.right - lpInfo^.rcItem.left,
  1903.                                 lpInfo^.rcItem.bottom - lpInfo^.rcItem.top,
  1904.                                 hMemDC, 0, 0, 63, 39, SRCCOPY);
  1905.                      SelectObject( hMemDC, hOldbm );
  1906.                   END;
  1907.                 DeleteDC( hMemDC );
  1908.              END;
  1909.         DeleteObject( hbm );
  1910.  
  1911.      END;
  1912.  
  1913.      ------------------------------ CUT HERE -------------------------------
  1914.      This is called from the main (dialog) proc to handle all custom button draw
  1915.      requests.
  1916.  
  1917.      BTW the 63, 39 values above are because I use 64x40 buttons.
  1918.  
  1919.  
  1920.  
  1921.  
  1922.  
  1923.  
  1924.  
  1925.  
  1926.  
  1927.  
  1928.  
  1929.  
  1930.  
  1931.  
  1932.  
  1933.  
  1934.  
  1935.  
  1936.  
  1937.  
  1938.  
  1939.  
  1940.  
  1941.  
  1942.  
  1943.  
  1944.                                         - 33 -
  1945.  
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951.                              Microsoft's Windows Strategy
  1952.                                     By Pete Davis
  1953.  
  1954.           Well,  in  March I  got  the honor  of  going to  a  Microsoft Windows
  1955.      Strategy seminar put  on by our buddies over at  Microsoft. It was actually
  1956.      pretty  interesting  (any seminar  goer  can tell  you that  most  are real
  1957.      sleepers.) I have to admit that at  any seminar, the temptation to cop some
  1958.      Zs  is pretty high and  this one was  no different, but there  was a lot of
  1959.      interesting stuff for me to  relay. (Otherwise I wouldn't be  writing this,
  1960.      right?)
  1961.  
  1962.           What are  the  big things  in  Microsoft's future?  Well, OLE  2.0  is
  1963.      probably at the  top of the  list, according to  Microsoft. This is both  a
  1964.      good thing and a bad thing. They  showed a very impressive demo of OLE  2.0
  1965.      in action and I  think everyone there was ooing and ahing.  But, as I said,
  1966.      there is  also a bad side, that  being that OLE isn't  the easiest thing in
  1967.      the world to  program. Seeing as that's the case,  we're obviously going to
  1968.      have  to cover  it  here at  some point  and I'll  start looking  into that
  1969.      myself.
  1970.  
  1971.           My personal opinion,  especially after  talking to a  few experts,  is
  1972.      that OLE 2.0 won't  really pan out the way Microsoft wants. In all honesty,
  1973.      it's just too much of  a pain to program  and it's very document  oriented.
  1974.      Microsoft might try to argue otherwise, but I don't think EVERY program can
  1975.      be considered document-based. Microsoft, for some reason, thinks they  are.
  1976.      Maybe I'm wrong, but we'll see in the near future, won't we.
  1977.  
  1978.           What can OLE 2.0 do for you?  OLE 2.0 is VASTLY improved over 1.0.  If
  1979.      you're familiar  with 1.0, picture  this. Let's say  you were  in Microsoft
  1980.      Word and you have an OLE link to an Excel spreadsheet.  Let's say that link
  1981.      shows  maybe 5 columns and 3 rows. Well, in 1.0, when you double clicked on
  1982.      the Word  version, boom, Microsoft Excel pops up a big old window with your
  1983.      spreadsheet. Not  too bad, but try  to picture the 2.0  version. You double
  1984.      click  on your link  and boom, nothing happens.  Well, not exactly nothing,
  1985.      but it's real hard to notice. First of all, the title line that used to say
  1986.      'Microsoft  Word ....' whatever, has now changed to 'Microsoft Excel ....'.
  1987.      The  menu bar has changed to the Excel  menu bar. Any tool bars are changed
  1988.      over to Excel tool bars. The column headers A-F and row headers 1-3 show up
  1989.      right around your existing  copy of the spreadsheet. (Not the  entire Excel
  1990.      window.)  The weird  thing is, the  rest of  your document  is right there,
  1991.      unchanged. It looks like you're still  in Word. The most noticable thing is
  1992.      the column and row headers which suddenly surround your spreadsheet. If you
  1993.      have  bitmaps and graphs and  stuff in your document,  and they were on the
  1994.      screen before  you double-clicked,  they're still  there  after you  double
  1995.      click. Pretty neat, eh?
  1996.  
  1997.           On  top of  all that,  let's say  you have,  not only  a few  rows and
  1998.      columns,  but also,  say a  link to a  graph based  on the  numbers in your
  1999.      spreadsheet, in  the document.  Well, again,  you can  double click  on the
  2000.      graph, and almost  magically, you're in  Excel and  you hardly noticed  the
  2001.      change. Let's say you modify the values in the spreadsheet. Well, the graph
  2002.      changes immediately. Let's say  you move the  bar graphs bars? The  numbers
  2003.  
  2004.                                         - 34 -
  2005.  
  2006.  
  2007.  
  2008.  
  2009.  
  2010.  
  2011.      change to coincide with the graphs changes. It's really pretty cool. 
  2012.  
  2013.           Well,  can't just rave  about the great  parts, writing code  to do it
  2014.      can't be easy. Haven't seen  the API for OLE 2.0 yet, but I've  seen it for
  2015.      1.0 and it  isn't exactly a piece of cake. You  can be sure 2.0 isn't going
  2016.      to be easier.
  2017.  
  2018.           What were some other things.... 'Cairo', that's what. If you're around
  2019.      Microsoft types,  you've heard of  Cairo for  some time now.  Cairo is  the
  2020.      secret  (and I use  that in  terms of how  secret anything in  this country
  2021.      usually gets) codename  for Microsoft's 'Advanced'  operating system.  That
  2022.      was  about all I've  known for a  while. Got  a little more  news about it,
  2023.      though.  Cairo is going to be the  next version of Windows NT, essentially.
  2024.      It's going to be very object  oriented, more so than the existing operating
  2025.      system. What's more is Cairo is going to be based heavily on the use of OLE
  2026.      2.0, so it's time to start brushing up on those OLE 2.0 skills.
  2027.  
  2028.           Microsoft is  going to be  supporting 5 versions of  Windows, over the
  2029.      next few years. They are, from bottom to top, Modular Windows, Windows 3.1,
  2030.      Windows 3.1 for  Workgroups, Windows  NT, and Windows  NT Advanced  Server.
  2031.      Obviously,  this list  could be  kinda grouped  into a  set of  3 operating
  2032.      systems, but I'm giving it to you the way they fed it to me. Anyway, we all
  2033.      know  what Windows 3.1 is, I hope, and  just think of 3.1 for Workgroups as
  2034.      the network version  with some nifty  mail packages and  stuff. There,  two
  2035.      down and three to go.
  2036.  
  2037.           Modular Windows is going to be the kinda odd one. It's going to be for
  2038.      several different types of  hardware, including some sort  of Nintendo-like
  2039.      box, though it's  purpose won't be to  be a game machine, but  in the sense
  2040.      that it plugs into the TV and has a little controller and no keyboard. It's
  2041.      also going into the Pen computers and such. They had a long list of things,
  2042.      but no, I couldn't find Windows for Toasters in there, though they did make
  2043.      a passing reference about  Fax machines, and I don't know  about you, but I
  2044.      can dial  a phone and press  start without Windows, myself.  Maybe it's for
  2045.      the thinking impaired. Modular Windows is essentially a cut down version of
  2046.      Windows 3.1. It has a subset of the API and a bunch of DLLs and unnecessary
  2047.      stuff are removed. The idea is to get it down to 1 meg. They said they'd be
  2048.      specializing it for  each machine  it was  used on to  keep the  size at  a
  2049.      minimum. You could tell that they were really counting on getting computers
  2050.      into every household, one way or another. 
  2051.  
  2052.           Actually, some of the  ideas sounded pretty cool and  they're actually
  2053.      working with different  vendors to try to  make some of  it a reality.  For
  2054.      example, one demo they showed was a program for working  with Cable TV. You
  2055.      could watch  Cable, but let's  say you  were watching MTV,  and a  band you
  2056.      liked was on.  Well, with a little  extra bandwidth that's not  used by the
  2057.      TV, but is used by  your little Windows Cable  Box, you have access to  all
  2058.      kinds of information,  like what the name of the band  is, a list of albums
  2059.      and songs, when they'll be playing in  your area, and if you want, you  can
  2060.      click  on a button  to order  your tickets. Want  the CD?  Click on another
  2061.      button and they'll send  it to you and bill you  through the cable company.
  2062.      Now,  I don't  want to  sound like  one of  those idiots  from the  50s who
  2063.  
  2064.                                         - 35 -
  2065.  
  2066.  
  2067.  
  2068.  
  2069.  
  2070.  
  2071.      thought everyone in the 70s would have a helicopter in there back yard, but
  2072.      I really think this kinda thing is going to happen. (By the way, later I'll
  2073.      be  coming back to that helicopter  thing, 'cause I got a  bit to say about
  2074.      it.) They're  actually  working  with cable  box  manufacturers  and  cable
  2075.      companies to  make this stuff  a reality. It's  some pretty neat  stuff and
  2076.      it's  about time!  They're saying  they think  this kind  of stuff  will be
  2077.      available,  large-scale,  by  '95.  Well,  I've  never  been  too  fond  of
  2078.      Microsoft's predictions, as far as timing, so I'm going to take a  safe bet
  2079.      with '97, but I definately think it'll be there.
  2080.  
  2081.           Then there's  NT. See my column  on NT programming yet?  Check it out.
  2082.      I'm  clueless when it comes to NT programming, therefore, over-qualified to
  2083.      be teaching it.  Anyway, their NT  stuff was pretty impressive.  Looks like
  2084.      they're  already heavy into building add-on stuff, like SNA servers (by the
  2085.      way, that's the only thing I really  thought OS/2 had on NT, not anymore, I
  2086.      guess.) They're really  pushing the idea of programming with  the Win32 and
  2087.      Win32s APIs and making everything portable between all the Windows systems.
  2088.      Good luck, I say. I'd like to see it, but people are always going to try to
  2089.      exploit the specific  nooks and crannys that each  different version has to
  2090.      offer, and that's just life. 
  2091.  
  2092.           NT, staying or going? It's here to stay. It's not going to be on every
  2093.      desktop and Microsoft knows it, hence the Win32s API, but it will be fairly
  2094.      popular. It's going to be best for workstation stuff, software development,
  2095.      servers,  and the like. Personally, I love NT as a development environment.
  2096.      Compile your 3.1 programs in  the DOS box and  test them under NT. If  they
  2097.      crash, who cares, you don't have to re-boot, ever. Great time saver.
  2098.  
  2099.           Microsoft's going crazy. API-crazy, that is. They must  have mentioned
  2100.      6 or  7 of  them  while I  was awake.  They've got  the  Sockets API,  Open
  2101.      Database Connectivity (ODBC) API, SNA  API, Win32 and Win32s API,  Mail API
  2102.      (MAPI), and,  of course, PAPI, the Pizza API. Actually, the last was a joke
  2103.      about an API to  order Pizza for you, but I wouldn't be suprised to see it.
  2104.      They've got APIs left and right and what I  want to know is, who's going to
  2105.      have  time to learn half of them?  When we start sending out resumes, we're
  2106.      not  going to be  writing that  we know how  to program for  Windows, we're
  2107.      going to be listing the APIs we know how to program for Windows. The ones I
  2108.      listed above are  just the tip of the iceberg. There  are a ton of them out
  2109.      there. In an effort to help consolidate on some of this, Microsoft has come
  2110.      up with the SPI, or Service Provider Interface. This  is sort of an API for
  2111.      the APIs. The ODBC API is a good example of how this works. What happens is
  2112.      you  program  for the  ODBC API.  Then, the  guys  that write  the database
  2113.      software, like Oracle, Sybase,  DBase, and all those  guys, write the  SPI.
  2114.      That way, no  matter which database program you're using  the you just have
  2115.      to write for the ODBC API. Sounds good, right? Well, yeah, that's fine, but
  2116.      I've  been programming for a long time,  and I know programmer's. The first
  2117.      thing they're going  to do  is get a  hold of  a bunch of  SPIs, find  neat
  2118.      little  tricks they can  use that require  them to bypass  ODBC, because it
  2119.      won't  support them or something,  and then have  these 'hard-wired' tricks
  2120.      for  specific databases.  Maybe  I'm wrong  but  people have  been  talking
  2121.      standards  for years and what do  we have? Undocumented DOS and Undocmented
  2122.      Windows. People are  always going to be bypassing  these standard things so
  2123.  
  2124.                                         - 36 -
  2125.  
  2126.  
  2127.  
  2128.  
  2129.  
  2130.  
  2131.      they can make their programs jump through hoops.
  2132.  
  2133.           The worst case of this was someone who was talking to me about writing
  2134.      a standard set of APIs for programming in a GUI environment that would then
  2135.      have the equivelent of SPIs (remember  those) for each GUI, like Windows or
  2136.      X-Windows. Then you'd just  have to program  for one API  and it would  re-
  2137.      compile for each different  GUI interface. Yeah, right. Sorry,  it'll never
  2138.      happen. What happens when you want to use NetBIOS? Sorry, X-Windows doesn't
  2139.      have NetBIOS,  so your universal API won't either, so you're S.O.L. Anyway,
  2140.      just wanted to make that clear that that will not happen.
  2141.  
  2142.           Ok, so back to Microsoft going API crazy. Well, I have to give them an
  2143.      'A' for  effort. They're really busting their  collective hump to get tools
  2144.      out there for  us developpers. Over the next year or two, you can expect to
  2145.      see a rich collection  of APIs to do everything from getting  data off of a
  2146.      Nintendo  machine via smoke signals to APIs for ordering Pizza. Microsoft's
  2147.      really trying  to standardize and I  applaud their effort, but  I've seen a
  2148.      lot of people try to do that in this industry, so I remain skeptical.
  2149.  
  2150.           Another new catch-phrase  (or catch-acronym,  as the case  may be)  is
  2151.      WOSA which stands for  Windows Open Services Architecture. This  includes a
  2152.      lot of the  API and SPI stuff.  WOSA is the collection of  all these front-
  2153.      ends  (APIs) with changeable back-ends (SPIs) for different engines. I just
  2154.      felt a need to throw the catch-acronym at you. I didn't want you to hear it
  2155.      a few weeks later and then say, 'That's what Pete was writing about, but he
  2156.      didn't  call it  that. What an  idiot!' Well,  I'm not  an idiot,  I'm just
  2157.      stupid.
  2158.  
  2159.           Well, that about  wraps it up. What  do I think about all  of this? Do
  2160.      you care? Do I care? Cool. You Better. Of Course. In that order. I like the
  2161.      idea of having a ton of APIs to play with. I've always been a bit of an API
  2162.      nut, so I'll  be messing  with everything I  can get my  hands on. I  think
  2163.      Microsoft's going in the right  direction and I think Bill's going  to keep
  2164.      raking in the bucks. I hope the cable-tv stuff happens and I hope I can run
  2165.      Windows on my coffee  maker in the near  future. I can't make good  coffee,
  2166.      maybe  Windows can.  Hey, and  maybe Windows  to flush  my toilet,  wash my
  2167.      clothes and mow my lawn.  That's not too much to ask for, is  it? Well, you
  2168.      may be laughing but Bill's probably  working these problems out in his head
  2169.      as you read this. We'll see if he can do it.
  2170.  
  2171.      P.S. Bet you thought I forgot  about that helicopter nonsense. Well, I did,
  2172.      and  after re-reading,  I'm  adding this.  I'm  convinced Man  has  evolved
  2173.      tremendously since the 50's. Let's face it, we all know, now, that everyone
  2174.      having a  helicopter in their driveway  is a ridiculous idea.  Most drivers
  2175.      can't drive. Let's just say that if helicopters were that popular, I'd live
  2176.      underground. 'nuff said.
  2177.  
  2178.  
  2179.  
  2180.  
  2181.  
  2182.  
  2183.  
  2184.                                         - 37 -
  2185.  
  2186.  
  2187.  
  2188.  
  2189.  
  2190.  
  2191.                         Accessing Global Variables Across DLL
  2192.                                     by Rod Haxton
  2193.  
  2194.           In the February issue of WPJ I wrote an introductory DLL article. This
  2195.      month  I wish to  share with the many  readers of the  WPJ of a  way that I
  2196.      discovered  by  necessity  of  handling  global  variables across  DLLs.  I
  2197.      describe my approach as a 'kludge' but, to me it is a fairly good 'kludge'.
  2198.      Like anything done against  the norm there  are some risks; like  receiving
  2199.      flammable E-mail  about going against Windows  standards, and possibilities
  2200.      that  Microsoft will change some things and  therefore in later versions my
  2201.      approach will not work. All of these are possibilities but, I can live with
  2202.      those for now. Why? Because I think that it is a feasible kludge and what I
  2203.      will show you is nothing that Windows has not been doing  since version 2.0
  2204.      and it has  not changed yet. That is not to  say that they will not change,
  2205.      but that for now it seems safe to say that they will not.
  2206.  
  2207.           Here's some background information on why  I chose to use the method I
  2208.      came  up with. Windows already  supplies ways of  handling global variables
  2209.      across  DLLs,  for  instance,  shared  memory,  passing  far  pointers  and
  2210.      redeclaring   the variables in  the DLL. These  methods are workable  and I
  2211.      strongly  suggest  that  they be used.  Well, here's the  background. I was
  2212.      given  the task  of converting  two DOS  applications over  to Windows  and
  2213.      making them into  one  package. My mission was to  get it up and running as
  2214.      quickly  as possible.  The original  DOS application  made use  of numerous
  2215.      global variables.  So, I decided to  do a straight port,  and after demoing
  2216.      the port and management making their decision, I would convert the App over
  2217.      to  DLLs. Well,  the  first  two steps  (ported  and  mgmt. decision)  were
  2218.      completed 7 months later. So, now the big job was to fix up everything over
  2219.      to DLLs. This was no problem except for the numerous global variables. Hind
  2220.      sight told  me I was stupid for not   dealing with them initially. Handling
  2221.      the  global variables  the way Microsoft  suggests would mean  that a great
  2222.      portion of the code  would have to  be rewritten, and  you know that  there
  2223.      just is never any  time to do that. So, I  began to think to myself,  and I
  2224.      remembered reading about Micheal  Geary's FIXDS. The same logic  he applied
  2225.      to  not  having to  call  'MakeProcInstance' also  applied  to  what I  was
  2226.      thinking.
  2227.  
  2228.           The stack  segment (SS) for DLLs  is that of the  calling application.
  2229.      And, the calling apps. DS == SS. Therefore, any global variables (CONST and
  2230.      BSS)  defined in the application  is shared with  the DLL via  SS. The only
  2231.      problem is  that you  have no  clear way of  accessing those  variables. In
  2232.      Windows global  variables in segments do not change their offsets, only the
  2233.      segments  can be changed due to memory  management. Thus, the offset values
  2234.      of the  global variables  will always  be at the  same location  inside the
  2235.      segment. Knowing this, how do we determine those offsets? The answer is the
  2236.      MAP file  that the  compiler will supply  for you. The  MAP file  lists all
  2237.      global symbols  defined in the  object file(s), sorted  by name and  a list
  2238.      sorted by address. With this information in hand we can make a file  of all
  2239.      the global  variables used in the  program. The global list  should use the
  2240.      same case  as the actual  definitions. Also, since  the MAP file  sorts the
  2241.      variables by  name and thats what we are looking for, the matching variable
  2242.      names and  their offsets, our list  file should be sorted,  this will speed
  2243.  
  2244.                                         - 38 -
  2245.  
  2246.  
  2247.  
  2248.  
  2249.  
  2250.  
  2251.      the search.  I  wrote a  utility  program that  I call  "getoff.exe",  that
  2252.      searches  the  MAP  file  and  creates  an  output  constants  file of  the
  2253.      variables, i.e.,
  2254.  
  2255.      GLOBAL HEADER FILE  INPUT FILE FORMAT   OUTPUT FILE FORMAT
  2256.      ------------------  -----------------   -------------------
  2257.      int variableA;      variableA      #define VARIABLEA 0x0001
  2258.      int variableB;      variableB      #define VARIABLEB 0x0002
  2259.      int variableC;      variableC      #define VARIABLEC 0x0003
  2260.  
  2261.      The outputted constant file is to be included in the DLL modules.  I forgot
  2262.      to mention one thing. The global variables must be declared inside the DLLs
  2263.      also. The  cleanest way would be to  include them in a  global header file.
  2264.      Now with the  use of some in-line assembly code the global variables can be
  2265.      accessed and updated inside the DLL.
  2266.  
  2267.                     #include "consts.h"
  2268.                     #include "global.h"
  2269.                     .
  2270.                     .
  2271.                     .
  2272.                     /* this code sets up the variables inside the DLL */
  2273.                     _asm mov  ax, ss:[VARIABLEA]
  2274.                     _asm mov  [variableA], ax
  2275.  
  2276.                     _asm mov  ax, ss:[VARIABLEB]
  2277.                     _asm mov  [variableB], ax
  2278.  
  2279.                     _asm mov  ax, ss:[VARIABLEC]
  2280.                     _asm mov  [variableC], ax
  2281.  
  2282.                     /* now use the variables like normal */
  2283.                     variableC= variableB;
  2284.                     variableB= variableA;
  2285.                     variableA= variableC;
  2286.  
  2287.                     /* when finish reasign the values to the global */
  2288.                     /* variables defined in the application      */
  2289.                     _asm mov  ax, [variableA]
  2290.                     _asm mov  ss:[VARIABLEA], ax
  2291.  
  2292.                     _asm mov  ax, [variableB]
  2293.                     _asm mov  ss:[VARIABLEB], ax
  2294.  
  2295.                     _asm mov  ax, [variableC]
  2296.                     _asm mov  ss:[VARIABLEC], ax
  2297.  
  2298.  
  2299.           This is all it takes to accomplish the task of  using global variables
  2300.      across DLLs. I created (for my company's purposes) entry/exit routines that
  2301.      handle  the assigning and re-assigning  of the variables,  only because our
  2302.      application has over 100 global variables. 
  2303.  
  2304.                                         - 39 -
  2305.  
  2306.  
  2307.  
  2308.  
  2309.  
  2310.  
  2311.           Included  with  this  document is  the  "getoff.exe"  utility and  its
  2312.      source, and  source and  executable  example of  a DLL  accessing a  global
  2313.      variable. To run "getoff"  type 'getoff <mapfile name> <input  file>'. As I
  2314.      stated,  this is only a  kludge, and so this method  should only be used if
  2315.      you do  not  have  time  to rewrite  code  and  you have  too  many  global
  2316.      variables.  If you  have  the  fortunate  pleasure  of  creating  your  own
  2317.      application try to stay away from global variables, but if you must, handle
  2318.      them the way Microsoft suggests.
  2319.  
  2320.      Rod Haxton can be reached at (202) 269-3780.
  2321.  
  2322.  
  2323.  
  2324.  
  2325.  
  2326.  
  2327.  
  2328.  
  2329.  
  2330.  
  2331.  
  2332.  
  2333.  
  2334.  
  2335.  
  2336.  
  2337.  
  2338.  
  2339.  
  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.                                         - 40 -
  2365.  
  2366.  
  2367.  
  2368.  
  2369.  
  2370.  
  2371.                             Getting A Piece Of The Future
  2372.                                     By Peter Kropf
  2373.  
  2374.           A few months  ago, a computer  trade publication ran  an article in  a
  2375.      regular column  stating that anyone can  obtain a beta copy  of Windows NT.
  2376.      It would  cost $69 without hard copy documentation, or $399 with a document
  2377.      set.  There have been other short blurbs that  I had read which gave a very
  2378.      brief view of Windows NT.  Here was a chance to get the real thing.
  2379.  
  2380.           While waiting for the package to arrive from Microsoft, a  trip to the
  2381.      local  book store  turned up  a book  called "Inside  Windows NT"  by Helen
  2382.      Custer.  The book was written during  the development process.  At times it
  2383.      seems to  read like  a  marketing brochure,  but on  the  whole, I  enjoyed
  2384.      reading  it.   The  first  two  chapters were  outstanding.    They gave  a
  2385.      wonderful overview to  the various features and concepts of Windows NT. The
  2386.      remaining chapters discuss the  features and concepts in much  more detail,
  2387.      but the  detail still remained at the surface  level.  Most of the features
  2388.      described read like VMS, The Next Generation.  For those  of you that don't
  2389.      know, Windows NT's chief driver is David Cutler, the same man who drove the
  2390.      initial development  of  Digital's  VMS  operating  system.  After  reading
  2391.      through the book, I was very anxious to try Windows NT.
  2392.  
  2393.           There were a few hurdles to  overcome before getting the system up and
  2394.      running.   The distribution media  is CD-ROM only.  What  that means is you
  2395.      must actually have a  CD-ROM drive.   Some of us (namely  me) are a  little
  2396.      slow. Until  the media, computer and  user were all physically  in the same
  2397.      place, it just didn't click.
  2398.  
  2399.           The  first  drive  purchased  is  a  bundled  package,  one  of  those
  2400.      multimedia  upgrade kits.  Sound  card/SCSI port/CD-ROM all  in one. Great.
  2401.      Well, not so great.   The SCSI port is  not on the list of  those currently
  2402.      supported  by Windows  NT.   That  means Windows  NT can  not be  installed
  2403.      directly from the CD-ROM.  Instead, all the required pieces are copied to a
  2404.      temporary  working directory and a bootable starter floppy is created while
  2405.      running under MS-DOS.   The system is then  booted from the floppy and  the
  2406.      installation  of  Windows NT  actually begins.    Once the  installation is
  2407.      complete,  Windows NT is booted directly from the hard disk.  But, the SCSI
  2408.      port on the sound card is not currently recognized by Windows NT, therefore
  2409.      the  CD-ROM drive cannot  be accessed. That  isn't really too  bad until an
  2410.      attempt  is made to change  the configuration.   It tries to  read from the
  2411.      temporary  load  directory.   But  that  directory  was  deleted after  the
  2412.      installation completed!   (The solution here  was to boot  under MS-DOS and
  2413.      copy the needed files into a directory that NT can then read.)
  2414.  
  2415.           What's that you say?   Most hardware vendors have a 30 day  money back
  2416.      guarantee/exchange policy?   Gee you're right.   Back the upgrade kit goes.
  2417.      A faster drive which is accessible from NT is  required.  Why? Well I don't
  2418.      know.   Just because,  that's why.   An Adaptec  1542B with a  Texel CD-ROM
  2419.      drive does  the trick.  Now  my multimedia windows applications  can access
  2420.      the CD-ROM directly while  running under NT. Of course a sound  card is now
  2421.      needed to allow complete multimedia.
  2422.  
  2423.  
  2424.                                         - 41 -
  2425.  
  2426.  
  2427.  
  2428.  
  2429.  
  2430.  
  2431.           After  the  installation  completed,  poking  around  the  directories
  2432.      reveals some interesting things.   There are a  few new files in  C:\ which
  2433.      are required by NT.
  2434.  
  2435.           WINNT          Directory structure for NT.
  2436.           NTDETECT.COM   Machine boot process
  2437.           NTLDR          Machine boot process
  2438.           USERS          Directory structure for NT users.
  2439.           BOOT.INI       NT initialization information
  2440.           CONFIG.NT      NT's version of CONFIG.SYS
  2441.           AUTOEXEC.NT    NT's version of AUTOEXEC.BAT
  2442.           PAGEFILE.SYS   NT's primary page file.
  2443.           BOOTSECT.DOS   Purpose unknown. Hidden file.
  2444.  
  2445.           When the machines boots, it goes through the standard hardware testing
  2446.      and then loads NTDETECT/NTLDR/BOOTSECT.DOS.  (At this time, I'm not certain
  2447.      of the relevance of these three files, their order and use at boot time are
  2448.      still  unclear to me.)  A menu is  displayed with the  entries in BOOT.INI:
  2449.      Windows NT from C:\winnt and the previous operating system from  C:\.  This
  2450.      allows either one to  be easily booted.  A  timer is set for 30  seconds by
  2451.      default to  wait for a selection.  After either  the timer has reached zero
  2452.      or the user has selected an OS, the highlighted entry is booted.
  2453.  
  2454.           MS-DOS  boots without any  problems.  It's  nice to be  able to easily
  2455.      select which system to use.
  2456.  
  2457.           Selecting  NT to  boot begins  a much  different process.   First  the
  2458.      kernel and device drivers are loaded.  Then  all the known file systems are
  2459.      checked.  (NT supports FAT, HPFS and NTFS.)  If the file systems need to be
  2460.      rebuilt or  fixed, this is where it would  happen.  All the partitions here
  2461.      are setup as FAT.  So far, the checking process has never complained and no
  2462.      repair work  has ever been  done.  After  everything is checked,  NT begins
  2463.      working.   A bitmap screen  is displayed  stating that this  is Windows  NT
  2464.      BetaOctober '92 Release.
  2465.  
  2466.           Once NT has started all the required processes, a message is displayed
  2467.      indicating  that CTRL-ALT-DEL  are to  be pressed  to login.   The standard
  2468.      CTRL-ALT-DEL to reboot the system whenever  a problem occurs is gone. NT is
  2469.      a true pre-emptive multitasking  operating system.  One of the  things this
  2470.      being along with it is  the fact that disk  I/O is now buffered in  memory.
  2471.      Powering down the  system without  first requesting buffers  to be  flushed
  2472.      will most  certainly cause file corruption.   Anyone whohas  ever crashed a
  2473.      Unix  system will  understand. The CTRL-ALT-DEL  sequence will  also ensure
  2474.      that the real logon screen is  being displayed, not an attempt at capturing
  2475.      passwords.
  2476.  
  2477.           Once signed  on, most  things look  the same.   There are  several new
  2478.      features  and programs available such as user maintenance, disk maintenance
  2479.      and event log review, but their explanations are for a later time. Pressing
  2480.      CTRL-ALT-DEL  after signing  on  brings up  a  window which  allows  almost
  2481.      complete control  over  the work  currently  being done.    A task  can  be
  2482.      stopped, the user can be logged off, the system can be shutdown, along with
  2483.  
  2484.                                         - 42 -
  2485.  
  2486.  
  2487.  
  2488.  
  2489.  
  2490.  
  2491.      a few others.  Shutting down the system has two options, one for a complete
  2492.      poweroff, and the second to shutdown NT and then reboot.  The second option
  2493.      behaves  much like CTRL-ALT-DEL while  running under MS-  DOS, allowing the
  2494.      system to be shutdown and rebooted in the event of a major problem.
  2495.  
  2496.           This brings to  a close a first look at getting  NT running on a Intel
  2497.      486-based machine.   Since NT  will run  on many  other hardware  platforms
  2498.      including  the Mips  R4000 and  Digital's  Alpha, getting  a system  up and
  2499.      running on  those machines might be  a little different.   The next article
  2500.      will take a look at the additional features and programs available from the
  2501.      Program Manager.
  2502.  
  2503.  
  2504.  
  2505.  
  2506.  
  2507.  
  2508.  
  2509.  
  2510.  
  2511.  
  2512.  
  2513.  
  2514.  
  2515.  
  2516.  
  2517.  
  2518.  
  2519.  
  2520.  
  2521.  
  2522.  
  2523.  
  2524.  
  2525.  
  2526.  
  2527.  
  2528.  
  2529.  
  2530.  
  2531.  
  2532.  
  2533.  
  2534.  
  2535.  
  2536.  
  2537.  
  2538.  
  2539.  
  2540.  
  2541.  
  2542.  
  2543.  
  2544.                                         - 43 -
  2545.  
  2546.  
  2547.  
  2548.  
  2549.  
  2550.  
  2551.                               The "ClickBar" Application
  2552.  
  2553.      ClickBar consists  of a Dynamic  Dialog pair that  allows C developers  for
  2554.      Windows 3.0/3.1 to  insert a "toolbar"  into their application.  Microsoft,
  2555.      Borland, etc. developers may display a toolbar or tool palette inside their
  2556.      application, according to a DLG script in their .RC or .DLG file.
  2557.  
  2558.      Borland developers  may install  ClickBar as  a  custom control,  providing
  2559.      three   custom  widgets added to  the Resource Workshop  palette. These are
  2560.      three   different button profiles  defining 69 custom  button images total.
  2561.      The  buttons   may be  placed and  assigned attributes  identically to  the
  2562.      intrinsic Resource  Workshop widgets.
  2563.  
  2564.      Source is provided for a complete example of using the tools, including the
  2565.      use of custom (owner-drawn) bitmaps for buttons.
  2566.  
  2567.      Version 1.5 uses single-image bitmaps to reduce  the DLL size, and includes
  2568.      source for a subclass example for inserting a toolbar.
  2569.  
  2570.      Registration is $35 and includes a registration number and printed manual.
  2571.  
  2572.                    WynApse
  2573.                    PO Box 86247               (602) 863-0411
  2574.                    Phoenix, AZ 85050-6247     CIS: 72251,445
  2575.  
  2576.  
  2577.  
  2578.  
  2579.  
  2580.  
  2581.  
  2582.  
  2583.  
  2584.  
  2585.  
  2586.  
  2587.  
  2588.  
  2589.  
  2590.  
  2591.  
  2592.  
  2593.  
  2594.  
  2595.  
  2596.  
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602.  
  2603.  
  2604.                                         - 44 -
  2605.  
  2606.  
  2607.  
  2608.  
  2609.  
  2610.  
  2611.                               Getting in touch with us:
  2612.  
  2613.      Internet and Bitnet:
  2614.  
  2615.      HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (Pete)
  2616.  
  2617.      GEnie: P.DAVIS5 (Pete)
  2618.  
  2619.      CompuServe: 71141,2071 (Mike)
  2620.  
  2621.      WPJ BBS (703) 503-3021 (Mike and Pete)
  2622.  
  2623.      You can also send paper mail to:
  2624.  
  2625.      Windows Programmer's Journal
  2626.      9436 Mirror Pond Drive
  2627.      Fairfax, VA   22032
  2628.            U.S.A.
  2629.  
  2630.           In future issues we  will be posting e-mail addresses  of contributors
  2631.      and columnists who  don't mind  you knowing their  addresses. We will  also
  2632.      contact any  writers from previous issues  and see if they  want their mail
  2633.      addresses made  available for you  to respond to  them. For now,  send your
  2634.      comments to us and we'll forward them.
  2635.  
  2636.  
  2637.  
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.  
  2644.  
  2645.  
  2646.  
  2647.  
  2648.  
  2649.  
  2650.  
  2651.  
  2652.  
  2653.  
  2654.  
  2655.  
  2656.  
  2657.  
  2658.  
  2659.  
  2660.  
  2661.  
  2662.  
  2663.  
  2664.                                         - 45 -
  2665.  
  2666.  
  2667.  
  2668.  
  2669.  
  2670.  
  2671.                                     The Last Page
  2672.                                    by Mike Wallace
  2673.  
  2674.           Got  this in the mail  today.  WPJ has the  coolest readers.  Hope you
  2675.      like it.
  2676.  
  2677.      Date:  01-Apr-93 12:41 EST
  2678.      From:  Mike Strock   >INTERNET:MikeS@asymetrix.com
  2679.      Subj:  Humor:  Health Tips for the 90s
  2680.  
  2681.      BURNOUT PREVENTION AND RECOVERY
  2682.  
  2683.      1. STOP DENYING.  Listen to the wisdom of your body.  Begin to freely admit
  2684.      the stresses  and pressures which  have manifested physically,  mentally or
  2685.      emotionally.
  2686.  
  2687.      MICROSOFT   VIEW:  Work   until   the  physical   pain   forces  you   into
  2688.      unconsciousness.
  2689.  
  2690.      2.  AVOID ISOLATION.    Don't  do  everything  alone!    Develop  or  renew
  2691.      intimacies with  friends and  loved ones.   Closeness  not only brings  new
  2692.      insights, but also is anathema to agitation and depression.
  2693.  
  2694.      MICROSOFT  VIEW: Shut your office  door and lock it from  the inside if you
  2695.      can  so no  one  will  distract  you.  They're just  trying  to  hurt  your
  2696.      productivity.
  2697.  
  2698.      3. CHANGE YOUR CIRCUMSTANCES.  If your job, your relationships, a situation
  2699.      or a person  is dragging you under, try to alter  your circumstances, or if
  2700.      necessary, leave.
  2701.  
  2702.      MICROSOFT VIEW: If you  feel something is dragging you down, suppress those
  2703.      thoughts. This is a weakness. Drink more coffee (it's free).
  2704.  
  2705.      4. DIMINISH INTENSITY IN YOUR LIFE.   Pinpoint those areas or aspects which
  2706.      summon  up the most concentrated intensity and work toward alleviating that
  2707.      pressure.
  2708.  
  2709.      MICROSOFT  VIEW:  Increase   intensity.    Maximum   intensity  =   maximum
  2710.      productivity.  If you find yourself  relaxed and with  your mind wandering,
  2711.      you are probably having a detrimental effect on the stock price.
  2712.  
  2713.      5. STOP OVERNURTURING.   If you routinely take  on other people's  problems
  2714.      and  responsibilities,  learn to  gracefully disengage.    Try to  get some
  2715.      nurturing for yourself.
  2716.  
  2717.      MICROSOFT VIEW: Always attempt to do everything. You ARE responsible for it
  2718.      all.  Perhaps you haven't thoroughly read your job description.
  2719.  
  2720.      6.  LEARN TO SAY "NO".   You'll help diminish intensity  by speaking up for
  2721.      yourself.  This means refusing additional requests or demands  on your time
  2722.      or emotions.
  2723.  
  2724.                                         - 46 -
  2725.  
  2726.  
  2727.  
  2728.  
  2729.  
  2730.  
  2731.      MICROSOFT VIEW:  Never say no to  anything.  It shows  weakness, and lowers
  2732.      the stock price. Never put off until tomorrow what you can do at midnight.
  2733.  
  2734.      7. BEGIN TO BACK OFF AND DETACH.  Learn  to delegate, not only at work, but
  2735.      also at  home and with  friends.  In  this case, detachment  means rescuing
  2736.      yourself for yourself.
  2737.  
  2738.      MICROSOFT VIEW: Delegating is a sign of weakness. Don't let someone else do
  2739.      it (See # 5).
  2740.  
  2741.      8.  REASSESS YOUR VALUES.   Try to sort out the  meaningful values from the
  2742.      temporary  and  fleeting, the  essential  from  the  nonessential.   You'll
  2743.      conserve energy and time, and begin to feel more centered.
  2744.  
  2745.      MICROSOFT VIEW: Stop  thinking about your own problems. This is selfish. If
  2746.      your values  change, we will make  an announcement at the  company meeting.
  2747.      Until then, if someone  calls you and questions your priorities,  tell them
  2748.      that  you are  unable  to comment  on this  and  give them  the  number for
  2749.      Microsoft Marketing. It will be taken care of.
  2750.  
  2751.      9. LEARN TO PACE  YOURSELF.  Try to take life in moderation.  You only have
  2752.      so  much energy  available.  Ascertain  what is  wanted and  needed in your
  2753.      life, then begin to balance work with love, pleasure and relaxation.
  2754.  
  2755.      MICROSOFT  VIEW: A  balanced  life is  a  myth perpetuated  by  the Borland
  2756.      Marketing Team.  Don't be a  fool: the only thing that matters is  work and
  2757.      productivity.
  2758.  
  2759.      10. TAKE CARE OF  YOUR BODY.  Don't skip  meals, abuse yourself with  rigid
  2760.      diets, disregard your need for sleep or break the doctor appointments. Take
  2761.      care of yourself nutritionally.
  2762.  
  2763.      MICROSOFT VIEW: Your  body serves your mind, your mind  serves the company.
  2764.      Push the mind and the body will follow. Drink Mountain Dew (it's free).
  2765.  
  2766.      11. DIMINISH  WORRY AND ANXIETY.   Try to keep superstitious  worrying to a
  2767.      minimum  - it changes nothing.  You'll have a better grip on your situation
  2768.      if you  spend less  time worrying and  more time taking  care of  your real
  2769.      needs.
  2770.  
  2771.      MICROSOFT VIEW:  If you're not  worrying about work,  you must not  be very
  2772.      committed to it.  We'll find someone who is.
  2773.  
  2774.      12. KEEP  YOUR SENSE OF HUMOR.   Begin to bring joy  and happy moments into
  2775.      your life.  Very few people suffer burnout when they're having fun.
  2776.  
  2777.      MICROSOFT VIEW: So, you think your work is funny?  We'll discuss  this with
  2778.      your manager on Friday.  At 7:00 pm.
  2779.  
  2780.  
  2781.  
  2782.  
  2783.  
  2784.                                         - 47 -
  2785.  
  2786.  
  2787.  
  2788.