home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / c / WPJ1_1.ZIP / WPJV1N1.TXT < prev   
Encoding:
Text File  |  1993-01-01  |  70.9 KB  |  1,916 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.     WW     WW     WW      PPPPPPPP              JJ
  7.     WW     WW     WW      PP    PP              JJ
  8.      WW   WWWW   WW       PP    PP              JJ
  9.      WW  WW  WW  WW       PPPPPPPP              JJ
  10.      WW  WW  WW  WW       PP             JJ     JJ
  11.       WWWW    WWWW        PP              JJ   JJ
  12.        WW      WW         PP               JJJJJ
  13.  
  14. ----------------------------------------------------------------
  15. The Windows Programmer's Journal                       Volume 01
  16. Copyright 1992 by Peter J. Davis                       Number 01
  17. and Mike Wallace                                          Jan 93
  18. ----------------------------------------------------------------
  19. A monthly forum for novice-advanced programmers to share ideas and concepts
  20. about programming in the Windows (tm) environment.
  21.  
  22. You can get in touch with the editor via Internet or Bitnet at:
  23.  
  24. HJ647C at GWUVM.BITNET   or   HJ647C at GWUVM.GWU.EDU
  25.  
  26. CompuServe: 71141,2071
  27.  
  28. or you can send paper mail to:
  29.  
  30. Windows Programmer's Journal
  31. 9436 Mirror Pond Dr.
  32. Fairfax, Va. 22032
  33.  
  34. The two GWUVM IDs are Pete's and CompuServe is Mike's.
  35.  
  36. We can also be reached by phone at: (703) 503-3165.
  37.  
  38. Microsoft, MS-DOS, Microsoft  Windows, Windows NT, Windows  for Workgroups,
  39. Windows for Pen  Computing, Win32, and Win32S are  registered trademarks of
  40. Microsoft Corporation.
  41.  
  42. Turbo  Pascal for  Windows,  Turbo C++  for Windows,  and  Borland C++  for
  43. Windows are registered trademarks of Borland International.
  44.  
  45. WordPerfect is a registered trademark of WordPerfect Corporation.
  46.  
  47. The Windows Programmer's Journal takes no responsibility for the content of
  48. the text within this document. All text  is the property and responsibility
  49. of the  individual authors.  The Windows Programmer's  Journal is  solely a
  50. vehicle for allowing  articles to be collected and  distributed in a common
  51. and easy to  share form. No part of the Windows Programmer's Journal may be
  52. re-published or duplicated  in part  or whole, except  in the complete  and
  53. unmodified form of  the Windows Programmer's  Journal, without the  express
  54. written  permission of  each individual  author.  The Windows  Programmer's
  55. Journal may  not be sold for profit  without the express written permission
  56. of  the  Editor,  Peter J.  Davis,  and  only then  after  he  has obtained
  57. permission from the individual authors.
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.                     Table of Contents
  73.  
  74. Subject                                      Page Author(s)
  75. -----------------------------------------------------------------
  76. WPJ.INI ......................................   3  Pete Davis
  77.  
  78. Off Topic ....................................   6  Pete & Mike
  79.  
  80. Beginner's  Corner   (C)  ........................        8     Pete  Davis
  81.                                                   & Mike Wallace
  82.  
  83. A Drag and Drop Trashcan (TPW) ...............  16  Andreas Furrer
  84.  
  85. Using DDE to Communicate With Program Manager.  18  Pete Davis
  86.  
  87. Implementing a Linked List in the Global Heap.  22  Mike Wallace
  88.  
  89. Book Review ..................................  26  Pete Davis
  90.  
  91. Last Page ....................................  28  Mike Wallace
  92.  
  93. Getting in Touch with Us .....................  29  Pete & Mike
  94.  
  95.  
  96.  
  97.  
  98. Windows Programmer's Journal Staff:
  99.  
  100. Publishers ......................... Pete Davis and Mike Wallace
  101. Editor-in-Chief .................... Pete Davis
  102. Managing Editor .................... Mike Wallace
  103. Contributing Writer ................ Andreas Furrer
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.                                   WPJ.INI
  141.  
  142.  
  143.      First of all, I'd  like to introduce myself. My name is Pete Davis and
  144. I was the editor of  the Pascal NewsLetter, a  journal similar to this  one
  145. which lasted  1 year for  6 issues. I  unfortunately had an  accident which
  146. left me unable to continue the newsletter for some time.  By the time I was
  147. back in shape  and ready to  go, someone had  picked up the newsletter  and
  148. re-started it. It  was nice to see  that there was enough interest  that it
  149. could continue without me. In the past year I have developed an interest in
  150. Windows programming using  C, so I guess at this point,  I'm more suited to
  151. Windows programming anyway.
  152.  
  153.      Well, it sure is nice to have  a "magazine" again. I guess I have  the
  154. same problem  now that  I had  with the  Pascal NewsLetter:  What is  it? A
  155. magazine? A Journal? A NewsLetter? Well, I never quite got it  figured out.
  156. The  Pascal  NewsLetter  was  originally   intended  to  be  just  that,  a
  157. newsletter,  but in  its prime it  was over  30 pages single-spaced,  so it
  158. wasn't exactly a newsletter.
  159.  
  160.      What,  you may ask, is the purpose of  this thing anyway? Well, I love
  161. to program.  I know  a lot  of other  people out  there, techno-geeks  like
  162. myself, love it also. As with Pascal, I'm  finding there aren't a whole lot
  163. of magazines which  cover Windows programming. That's fine,  it just leaves
  164. more readers for us, I  suppose. Not to mention, this is free. There aren't
  165. any free ones for Windows programming (or if there are,  I haven't heard of
  166. them). I like to teach people how to program and I can't think of an easier
  167. way to get such a large audience and have it all be free. 
  168.  
  169.      In this magazine, you  won't just be hearing Mike and I ramble on, but
  170. you'll  be hearing  from  a lot  of  people. Not  professors,  not industry
  171. experts, but people like you and me, regular programmers who like what they
  172. do and  want to share their ideas and experiences with us. No one gets paid
  173. and no one has to pay. That's the idea. 
  174.  
  175.      If the initial response  we got, when  we first started asking  people
  176. about  doing  this, is  any indication,  there  are going  to be  a  LOT of
  177. readers. That means  we should also have  a lot of  writers. You'll find  a
  178. file in this  .ZIP file with the name SUBMIT.TXT. It is simple instructions
  179. on how to submit an  article. There aren't any solid rules and  it's easier
  180. than you'd probably expect, so please consider sending in an article.
  181.  
  182.      Right now, things are real open  to regular columnists. I had  several
  183. with  the Pascal  NewsLetter and  their  columns were  very well  received.
  184. Since we don't  have a regular columnist  for a beginners column  yet, Mike
  185. and I are  going to start it up  ourselves, but I hope someone  will try to
  186. pitch in  and give us a hand  with it. When I did  the Pascal NewsLetter, I
  187. had  a regular writer for  a beginners column  and it was  the most popular
  188. column in the  magazine. There's  a reason  for that.  There are  a lot  of
  189. people trying  to get started and  just can't seem  to get the hang  of the
  190. basics. Programming Windows is a lot different than  programming in DOS and
  191. it's not as easy to  pick up, but with a little persistence,  anyone can do
  192. it.
  193.  
  194.      Other columns that we'd like to see are ones that address  things like
  195. C++ for Windows and Turbo Pascal for Windows. We'd like to hear from you if
  196. you want to tackle any of these. It's not a lot of work and only requires a
  197. few hours each month. Most of us can make at least that much time.
  198.  
  199.      The Pascal NewsLetter came out irregularly, but we'd really like to do
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208. this on a monthly basis if possible. If we don't get enough submissions, we
  209. might  have to make it every two months.  We should be able to let you know
  210. by the second or third issue.
  211.  
  212.      As far as things we'd like to see in the newsletter:
  213.  
  214.      * Software  and book  reviews, maybe even  reviews of  Windows related
  215.      hardware. I'd like to see reviews every month.
  216.  
  217.      * As I  mentioned before, I  want a beginners column  for plain C  for
  218.      Windows  as  well as  one for  Turbo  Pascal for  Windows and  C++ for
  219.      Windows.
  220.  
  221.      *  As far as  one-time articles, perhaps  one on programming  DLLs and
  222.      special considerations that need to be made for writing them.
  223.  
  224.      * Articles on DDE and OLE programming.
  225.  
  226.      *  Articles  on  network  programming in  Windows  for  Workgroups and
  227.      Windows NT.
  228.  
  229.      * Printing text and graphics in Windows
  230.  
  231.      * Memory management
  232.  
  233.      *  Using different  memory models and  how to handle  multiple code or
  234.      data segments.
  235.  
  236.      * Programming TCP/IP and Sockets under Windows NT
  237.  
  238.      *  Maybe reviews  of Windows  NT while it's  still in  the pre-release
  239.      stage  to let people  who don't  have it know  what it's  like and how
  240.      Microsoft is progressing with it.
  241.  
  242.  
  243.      That should be enough to  start with. Please take the time  and try to
  244. contribute. You  don't have to be an expert.  In the Pascal NewsLetter, the
  245. beginner's column was written by a guy who was just learning Pascal. He did
  246. a fantastic  job, and as I said earlier, it  was the most popular column. I
  247. had  an article submitted  to me by  someone who didn't  speak English very
  248. well, so he wrote it in his native tongue, German, and I had it translated.
  249. I had a 16 year-old high  school student who submitted a terrific  article,
  250. so  anyone can do it. You just need to  take the time.  The writing in this
  251. magazine is  pretty informal. People seemed  to like that about  the Pascal
  252. NewsLetter.  They said it was  easier to relate to than regular  magazines,
  253. so I'm going to stick with that format.
  254.  
  255.      As for the format,  I'm going to try  to keep it  like I did with  the
  256. Pascal NewsLetter,  in that  it's just  a plain  text file  with Form  Feed
  257. characters at page breaks. If there's a big push to go with something  like
  258. the Windows Write  format, that can be done too. Personally, I prefer using
  259. WordPerfect (just  what  I'm used  to)  and it  makes  it pretty  easy  for
  260. handling formatting and getting articles from different people in different
  261. formats.
  262.  
  263.      In  fact,  as  far  as  anything  about  the  magazine,  if  you  have
  264. suggestions, we'd love to hear them. If you think  we should change the way
  265. we're doing something, then you might not be the only one. If we get enough
  266. suggestions for  things, or if it's  just something we  should obviously be
  267. doing then we'll make the change.
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.      Well, that's  enough of  my rambling on  for now.  Hope you  guys (and
  277. gals)  like  the  magazine. I'm  open  to  suggestions and  I  love  to get
  278. feedback, good and  bad, about the magazine, so  feel free to get  in touch
  279. with me or Mike at the address on the cover page.
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.                                  Off Topic
  345.                               By Pete and Mike
  346.  
  347.      This is exactly what  the title says, off  topic. Mike and I have  two
  348. computers that we want to sell, so we figured we may as well throw those in
  349. here. Both machines are identical. They are:
  350.  
  351. IBM PS/2 Model 70-486 (8570-B61)
  352.  
  353.      Both machines have 2MB RAM and 60 MB  hard drives. They come with 8512
  354. Color VGA  monitors and the IBM  Enhanced Keyboards. The machines  are less
  355. than 4 months old and barely used.
  356.  
  357.      The  cost  is  $1,500.00   and  includes  shipping  anywhere   in  the
  358. continental United States. Shipping outside of the United States is covered
  359. by the buyer.
  360.  
  361.      These machines are  really in excellent condition.  We've checked them
  362. out thoroughly and  there aren't any problems  with them. We'll throw  in a
  363. guarantee that if there  are problems with them  sometime  within the first
  364. month, you  can  return the  computer for  a full  refund.  Of course  this
  365. doesn't include any damage applied after the purchase.
  366.  
  367.      Well, that's  our little  pitch for our  computers. We  don't normally
  368. sell computers, so hopefully this will be the only ad we throw  in here for
  369. computers.
  370.  
  371.      Our next off-topic thing is something Mike and I discussed and both of
  372. us agreed that it wasn't  something we wanted to do  but felt that for  the
  373. magazine's best interest, we would. We are asking for donations. Neither of
  374. us is looking to make a fortune in contributions (And I'd be willing to put
  375. money  down that we don't). The idea behind  it is this. We want to be able
  376. to  support Windows  programming  with  different  compilers,  Windows  NT,
  377. Windows for  Workgroups, etc. The  donations would be used  specifically to
  378. get the software  so we could either  work with these environments  for our
  379. own articles or use them  to test programs and articles sent  in by others.
  380. Our address is  at the end  of the article. Send  in what you  believe this
  381. magazine is worth.  We want to put  together the best Windows  magazine out
  382. there, but  we're not rich, so we'll  do what we can with  what we have. If
  383. you do want to send a donation, see the last page for our address. Make the
  384. check payable to Pete Davis.
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.                              Beginner's Corner
  413.                              By Pete Davis and
  414.                                 Mike Wallace
  415.  
  416.  
  417.      Well, since this is the first issue and we don't have a writer for the
  418. beginner's column yet, Mike and I are going to split  it between the two of
  419. us. I'm a  strong believer in the  beginner's column because once  you make
  420. the  first few  steps,  you  get hooked.  Unfortunately,  few books  really
  421. address the  beginner so  someone has  to help  them get  started. We  must
  422. assume that the  reader is familiar  with the C  language. Covering both  a
  423. beginners column for C and for Windows would be far too great a task. There
  424. are several good books out for C  programming and there's also the C  News,
  425. which, like  this magazine is a  file which is available on  many BBSes and
  426. the Internet. It's a great place to start learning C and I highly recommend
  427. it. Also, although formally,  all C routines are  called functions, we  use
  428. the  words procedure,  function,  and  routine  fairly  interchangeably.  A
  429. function tends to imply that some result is returned to the calling routine
  430. so I tend to use it in that manner.
  431.  
  432.      In  almost every  beginners  book on  programming,  the first  program
  433. written is the infamous "HELLO WORLD" program. We're going to do that here,
  434. but in a sort of round-about way. We're not just going to  show you the one
  435. simple program, but  we're going to go  to great lengths in  explaining the
  436. different  parts of  a Windows  program  first. For  example, I'm  going to
  437. specifically cover how Windows  works and then the .DEF file  which is used
  438. to tell  the compiler how your  code and data is supposed  to be configured
  439. when it's linked. Then Mike and I are  going to go in-depth into the .RC or
  440. Resource source file. The .RC file has the definitions of all the resources
  441. of your program. It has your  dialog boxes, menus, icons, bitmaps, etc.  We
  442. won't actually  get to the  "HELLO WORLD" program  itself until the  second
  443. issue. 
  444.  
  445.      To a beginner, it may seem a bit overwhelming that we're going to have
  446. to  cover so much just to do a  "HELLO WORLD" program, but the truth is, we
  447. don't HAVE to cover  all of it. When  you actually see the  program, you'll
  448. see how simple it really is. We'd just  like to give you an overview of the
  449. parts of a Windows program first and then show you a specific example. We'd
  450. also like this article to be a sort of reference on how to create more than
  451. just the simple resources and definitions (.RC and .DEF files) for a "HELLO
  452. WORLD" program.
  453.  
  454.                              How Windows Works
  455.  
  456.      Too some of you who  are beyond the very basics, some of  this you may
  457. already  know, but it may be a good idea  to read anyway. Some of this is a
  458. simplified  explanation,  but  the point  is  to get  the  concept  easy to
  459. understand. Later we can be a little more specific.
  460.  
  461.      Windows  is what is called a non-preemptive multi-tasking environment.
  462. A preemptive  multi-tasking environment is  one where the  operating system
  463. allocates a  certain amount of  time to  each task. It  then runs one  task
  464. until it has  used its share of time  and then runs another  task until its
  465. time has run out and so  on until it gets back to the  first task. Windows,
  466. on the  other  hand, will  run  a procedure  from  your program  until  the
  467. procedure  is  completed and  then  it will  run a  procedure  from another
  468. program until it  is completed. What this  means is that a  Windows program
  469. can take over the  CPU entirely, if it wants, but that  defeats the purpose
  470. of programming for  a multi-tasking environment.  (There is one  exception,
  471. and  that is  DOS sessions running  under Windows,  which are handled  in a
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480. preemptive manner, but this is not our topic and won't be discussed in this
  481. column.)
  482.  
  483.      In  a  Windows  program,  the  initialization  of  the  program  first
  484. 'registers' itself  with Windows.  It does  this by  telling Windows a  few
  485. parameters that it needs  to know about the program and to  set-up the main
  486. message-loop, then  telling Windows where  the main window procedure  is. A
  487. message-loop procedure is  one that accepts messages from  Windows that are
  488. sent to your program.
  489.  
  490.      Messages in Windows  are a way of telling your program  what the  user
  491. is doing, or a way for  your program to tell Windows or some  other program
  492. what to  do. Windows messages  usually come  in the  form of  WM_something,
  493. where  the WM_  stands for  Windows  Message. For  example, when  you first
  494. create your Main Window, one of the first messages passed to your procedure
  495. is  WM_CREATE. When you receive the WM_CREATE  message, you know Windows is
  496. about to create your window and if you want to initialize certain variables
  497. to be  handled by that procedure, you want to do it now. Or, if you receive
  498. the WM_CLOSE  message, you know that Windows is  about to close your window
  499. and end  your program. You may want  to, at this point, ask  the user if he
  500. wants to save his files or ask if he really wants to quit.
  501.  
  502.      Messages are the  heart of the  Windows multi-tasking environment  and
  503. when we create  our "HELLO WORLD" program, you'll see a little more clearly
  504. how this works.
  505.  
  506.      In  your programs, you will create windows  and dialog boxes. When you
  507. do that,  you need  to tell Windows  the name and  location of  a procedure
  508. which is going to handle the messages used by the window or dialog box. The
  509. procedure  then gets  all messages  pertaining to  that specific  window or
  510. dialog  box.  Each  of these  procedures  is  a lot  like  the  main window
  511. procedure to Windows. This  is unlike a regular DOS C program  in which the
  512. program always controls  which procedure is called next  and is responsible
  513. for making its own calls. In a Windows program, you tell Windows where your
  514. procedures are and  it will run  them in response  to certain commands  and
  515. user actions.
  516.  
  517.      This may  seem a little  unclear, but all  I can  say is stick  around
  518. until the  end of the second part of the article and it may make more sense
  519. in terms of a real program. This is, essentially, how Windows works. If you
  520. have questions, please feel free to contact us in one of the ways mentioned
  521. on the first page  and we will try  to be more  clear in the areas  readers
  522. seem confused about in the second part of this article.
  523.  
  524.                                The .DEF File
  525.                  (Also known as the Module Definition File)
  526.  
  527.      The .DEF file is what the compiler uses to find out how to handle your
  528. program as  a whole and how to handle  individual routines in your program.
  529. We're going to go fairly in-depth into the different things you can do in a
  530. .DEF file, but in  the second part of the article, you'll see a very simple
  531. application .DEF file and see exactly what  parts are basic. I will try  to
  532. distinguish between  the things that  you always must  have and then  parts
  533. that are optional or rarely used.
  534.  
  535.      I will show  each parameter,  a summary  of its  purpose and  options,
  536. followed by how it  would appear in the .DEF file. The  .DEF file is simply
  537. an ASCII text file that you type in with your program editor.
  538.  
  539.      The first parameter is the NAME.  In general, this should  be the same
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548. as the name of the executable. Also, in the cases of Dynamic Link Libraries
  549. (DLLs), this is replaced by the LIBRARY parameter.
  550.  
  551. NAME myprog         (for a regular Windows program)
  552. or
  553. LIBRARY mydll       (for a DLL)
  554.  
  555.      The  next parameter  is the  DESCRIPTION.  This is  inserted into  the
  556. header  of your executable, but  serves no real  purpose other than perhaps
  557. allowing you to keep track of version and/or copyright information.
  558.  
  559. DESCRIPTION 'My first Windows Program'
  560.  
  561.      The EXETYPE parameter tells the compiler which environment the program
  562. will be run under. For Windows, it is simply:
  563.  
  564. EXETYPE WINDOWS
  565.  
  566.      The next  parameter is the WINSTUB program.  The WINSTUB is simply the
  567. name of a program that is run in the event that someone  tried to execute a
  568. Windows program  under DOS. This  may be familiar  to you. The  most common
  569. WINSTUB is the one that says, 'This program requires Microsoft Windows.' In
  570. theory this program  can be almost anything  you want. A programmer  could,
  571. for example, have  both a DOS and  Windows version of his/her  program with
  572. the DOS  version simply being a WINSTUB in  the Windows version. In a later
  573. article, I'll provide source code for a  WINSTUB that will allow a user  to
  574. run your  Window program from DOS. This is done by running Windows with the
  575. name of  the program as the parameter (i.e.,  the user types 'TESTPROG' and
  576. the stub from TESTPROG executes the command: 
  577. 'WIN TESTPROG'). The  possibilities are enormous  and it would  be nice  at
  578. some point  to see  some more creative  uses of  the WINSTUB  besides 'This
  579. program  requires  Microsoft Windows.'  Anyway, the  standard WINSTUB  is a
  580. program called  WINSTUB.EXE which comes  with most Windows compilers.   The
  581. syntax is as follows:
  582.  
  583. WINSTUB 'WINSTUB.EXE'
  584.  
  585.      The next section covers  the code and data  segments. Windows has  the
  586. Small, Medium, Compact and Large memory models. The memory model determines
  587. whether or  not  there are  multiple  code and/or  data segments.  See  the
  588. following table:
  589.  
  590. Model          # Data Segments          # Code Segments
  591. ----------------------------------------------------------
  592. Small          Single                   Single
  593. Compact        Multiple                 Single
  594. Medium         Single                   Multiple
  595. Large          Multiple                 Multiple
  596.  
  597.      For now,  we'll stick mostly with  Small or Medium models,  as they're
  598. the easiest to use. We  will go into the different models in later articles
  599. to discuss the advantages and disadvantages of each and how to  program for
  600. them.
  601.  
  602.      Each code and data segment  can have different options telling Windows
  603. how to handle  them. Most segments,  you want to  give the option  MOVEABLE
  604. which means that  the Windows memory manager can move the segment around in
  605. memory to make room for other things if needed. There may be occasions when
  606. you would want a segment set to FIXED.  For example, if  you were writing a
  607. program that was  working with DOS on a  fairly low level, it  is useful to
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616. have things set for FIXED so DOS will always know where they are. This  is,
  617. however, in the advanced arena, so we'll be avoiding it.
  618.  
  619.      The PRELOAD  option tells  Windows to  automatically load  the segment
  620. into memory before the program  is actually executed. The LOADONCALL option
  621. tells Windows only to  load the segment when it is needed.  This helps keep
  622. memory available for other processes.  In general, you want your main  CODE
  623. and DATA segments set for PRELOAD.
  624.  
  625.      The DISCARDABLE  option tells the  Windows memory manager that  it can
  626. remove that segment from memory all together when it needs more memory. The
  627. memory manager will  then re-load the segment  the next time it  is needed.
  628. This is fine for most CODE segments where the contents of the code does not
  629. change. In  DATA segments,  the contents  of the  data will  change as  the
  630. program is run and  because of this, you do not want  it to be discardable.
  631. The discardable segments are  not saved before they  are discarded, so  any
  632. changes made to them are lost. Making a DATA segment discardable would give
  633. unknown results.
  634.  
  635.      The SINGLE option tells windows  tells Windows that although there may
  636. be multiple copies of the program running at once, that this segment may be
  637. shared. This is  useful for a CODE segment where several copies of the same
  638. program can use  the same copy  of the code, thus  saving memory. The  DATA
  639. segment, however, would be different from one running program  to the next,
  640. so the SINGLE option  wouldn't really be  appropriate. (Because of the  way
  641. Windows  handles DLLs,  they data  segments MUST  be SINGLE.  This requires
  642. special handling on the  part of the programmer to handle multiple programs
  643. using the same DLL. We'll discuss this another day.)
  644.  
  645.      The MULTIPLE option  tells Windows to  create a separate  copy of  the
  646. segment for  each copy (instance)  of the program  that is being  executed.
  647. This is useful for  DATA segments. If your CODE segment is  single and your
  648. DATA segment is multiple, you can  share the CODE segment and save  memory,
  649. but each copy (instance) of the program will have its own data.
  650.  
  651.      The following is an example for a Small model program. It has one code
  652. segment and one data segment.
  653.   CODE    PRELOAD MOVEABLE
  654.   DATA    PRELOAD MOVEABLE MULTIPLE
  655.  
  656.      The next parameters are Heapsize and Stacksize. Heapsize refers to how
  657. much space  is available for  local dynamic memory  allocation. If you  are
  658. familiar with dynamic memory allocation in regular C programming, then this
  659. is nothing really new to  you. The only real  difference is in Windows  you
  660. have Global and Local heaps. For now, let's just keep the Heapsize at about
  661. 4096. This is a nice safe size for  the types of programs we're going to be
  662. doing for a while.
  663.  
  664.      The  stacksize tells Windows how much space  to make available for the
  665. stack.  The  stack   is  where  Windows  keeps  a  lot   of  it's  variable
  666. declarations. It  also  keeps  information  when you  call  procedures  and
  667. functions here.  As with Heapsize, 4096 should do  fine for the time being.
  668. The syntax is as follows:
  669.  
  670. HEAPSIZE  4096
  671. STACKSIZE 4096
  672.  
  673.      The next section is the EXPORTS and IMPORTS sections. The exports  are
  674. procedures that  will be called by  something other than  your own program.
  675. For  example, your  main window  procedure that  receives all  the messages
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683.  
  684. regarding your  main window  is an exported  procedure. Any  procedure that
  685. accepts messages,  for that matter, are Exported.  These procedures receive
  686. their  messages from  Windows and  are  called by  Windows. Each  procedure
  687. exported  should be followed  by an @n  where n  is an integer  number. The
  688. number  is an unique  index number that  Windows uses to help  it keep your
  689. program organized. It's  not required, but it does help speed things up for
  690. Windows and I suggest you use it all the time.
  691.  
  692.      Imports are functions that you want to use from external sources, like
  693. a DLL, or some other source. To use those, you simply need to list them. If
  694. they  come  from  a  DLL,  you  need  to  do  the  name  in  the  form  of:
  695. DLLNAME.FUNCTIONNAME.
  696.  
  697. EXPORTS        MainWndProc    @1
  698.                ADlgProc       @2
  699.  
  700. IMPORTS        SHELL.DRAGQUERYFILE
  701.  
  702.  
  703.      Well, that  about covers  the .DEF file.  As we start  to use  it more
  704. regularly, you'll  see how the  different sections affect the  program. So,
  705. we'll end this section with a sample .DEF file.
  706.  
  707.  
  708. NAME           MYPROG
  709. DESCRIPTION    "My first Windows program"
  710. EXETYPE        WINDOWS
  711. STUB           'WINSTUB.EXE'
  712. CODE           PRELOAD MOVEABLE
  713. DATA           PRELOAD MOVEABLE MULTIPLE
  714. HEAPSIZE       4096
  715. STACKSIZE      4096
  716. EXPORTS        MainWndProc    @1
  717.  
  718.  
  719.  
  720.  
  721.                                 The .RC File
  722.  
  723.      The  .RC  file  is  used  to  define  the   resources  for  a  Windows
  724. application.   Resources  include  icons,  cursors,  menus,  dialog  boxes,
  725. bitmaps, fonts, string  tables, accelerators, custom resources  and version
  726. information;  in other words, the gist of  a Windows program.  The .RC file
  727. can contain either  definitions for one or  more of each of  these resource
  728. types or tell Windows where to find the definition(s).  I'll start with the
  729. dialog box format this issue.
  730.  
  731.      A dialog box  is a type of  window allowing the user to,  for example,
  732. select an item from  a list box, pick a printer, select a  drive for a file
  733. directory, etc.   In other words, whenever you want  to display information
  734. to the user or get  input, use a dialog box.   The "About" box is a  dialog
  735. box.  The difference between a dialog box  and a window is that a window is
  736. normally  used  for  drawing  graphics  and  a  dialog  box  displays  text
  737. ("dialog").  You define a dialog  box with the DIALOG statement, which  has
  738. the following format:
  739.  
  740. name DIALOG [load option] [memory option] col, row, width, height
  741. [option statements]
  742. BEGIN
  743.    [dialog box items]
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752. END
  753.  
  754. Description of parameters:
  755.  
  756.      name - unique (to your program) name for the dialog box
  757.  
  758.      load  option - determines  when the dialog box  is loaded into memory;
  759. if specified, must be either PRELOAD or LOADONCALL.  PRELOAD  tells Windows
  760. to  load the dialog box  when the application  starts.  This  makes the box
  761. appear quicker, but takes up memory since it must stay in memory throughout
  762. execution of your  program, even if your  program never loads it  (based on
  763. user input, for example).   The default, LOADONCALL, tells Windows  to load
  764. it when necessary.
  765.  
  766.      memory option - combination of  FIXED, MOVEABLE and DISCARDABLE.  This
  767. should normally be  "MOVEABLE DISCARDABLE" (notice there's no  comma).  See
  768. the article  "Implementing a Linked List  in the Global Heap"  elsewhere in
  769. this issue for a discussion of these attributes.
  770.  
  771.      row,col,width,height  - position  and  size  of  the dialog  box;  col
  772. (column) and  row specify  the location  of the  upper left  corner of  the
  773. dialog box relative to the upper left corner of the window which called it.
  774. All dimensions are in dialog base units.
  775.  
  776.      option  stmts  - describe  the  dialog  box;  can include  the  STYLE,
  777. CAPTION, MENU, CLASS and FONT.  These are described below.
  778.  
  779.           STYLE  - Format  "STYLE style".   Valid  values for  style are  a
  780.      subset of the styles for windows.   Any window style starting with WS_
  781.      or DS_ can be used (except for WS_MINIMIZEBOX and WS_MAXIMIZEBOX), and
  782.      combined with "|".  These are listed below:
  783.  
  784. DS_LOCALEDIT -  Forces memory used  by dialog boxes into  the application's
  785. data segment.
  786.  
  787. DS_MODALFRAME - Creates a dialog box with a modal frame.
  788.  
  789. DS_NOIDLEMSG - No  WM_ENTERIDLE messages  are sent from  the dialog box  if
  790. created with this style.  WM_ENTERIDLE  messages are normally used to alert
  791. the application  that the dialog box is displayed  but no user activity has
  792. happened yet.
  793.  
  794. DS_SYSMODAL - System modal dialog box.  This means no other window can gain
  795. the input focus until this dialog box is closed.
  796.  
  797. WS_BORDER - Border on the dialog box.
  798.  
  799. WS_CAPTION - Caption on the dialog box; can't be used with WS_DLGFRAME
  800.  
  801. WS_CHILD - Create a child dialog box; can't be used with WS_POPUP.
  802.  
  803. WS_CHILDWINDOW - Same as WS_CHILD.
  804.  
  805. WS_CLIPCHILDREN - When  creating a parent dialog box,  specifies that child
  806. dialog boxes will be clipped at the boundary of the parent.
  807.  
  808. WS_CLIPSIBLINGS  - Used  with WS_CHILD;  keeps "sibling" dialog  boxes from
  809. overlapping.
  810.  
  811. WS_DISABLED  - the  dialog box  is initially  disabled (cannot  receive the
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820. input focus).
  821.  
  822. WS_DLGFRAME - Double border.
  823.  
  824. WS_GROUP - The control can be reached via the direction keys (arrows).
  825.  
  826. WS_HSCROLL - Horizontal scroll bar.
  827.  
  828. WS_ICONIC - Initially iconic; used with WS_OVERLAPPED.
  829.  
  830. WS_MAXIMIZE - Initially maximized.
  831.  
  832. WS_MAXIMIZEBOX  - Maximize box in the upper right corner.
  833.  
  834. WS_MINIMIZE - same as WS_ICONIC.
  835.  
  836. WS_MINIMIZEBOX - Minimize box in the upper right corner.
  837.  
  838. WS_OVERLAPPED - Caption and border.
  839.  
  840. WS_OVERLAPPEDWINDOW -  Combination of WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU
  841. and WS_THICKFRAME (standard parent window style).
  842.  
  843. WS_POPUP - Popup dialog box (can't be used with WS_CHILD).
  844.  
  845. WS_POPUPWINDOW   -  Combination  of   WS_POPUP,  WS_BORDER  and  WS_SYSMENU
  846. (standard popup window style)
  847.  
  848. WS_SYSMENU - System menu.
  849.  
  850. WS_TABSTOP - Specifies at which control the tab key stops.
  851.  
  852. WS_THICKFRAME - Thick frame (used to size the dialog box).
  853.  
  854. WS_VISIBLE - Initially visible.
  855.  
  856. WS_VSCROLL - Vertical scroll bar.
  857.  
  858.      Example : STYLE DLGFRAME | WS_VISIBLE
  859.  
  860.  
  861.           CAPTION  - Format "CAPTION text".   Gives a  caption of "text" to
  862.      dialog boxes defined with the WS_CAPTION style.
  863.  
  864.           MENU -  Format "MENU menuname".   Assigns menu "menuname"  to the
  865.      dialog box.  The menu is normally defined in the .RC file.
  866.  
  867.           CLASS -  Format "CLASS classname".  Causes a class other than the
  868.      class of the parent window to be used for the dialog box.
  869.  
  870.           FONT -  Format "FONT  pointsize, typeface".  Determines the  font
  871.      size used  for the dialog box, which in  turn determines the sizing of
  872.      every control and the dialog box itself.  Example : FONT 10, "Helv"
  873.  
  874.  
  875.  
  876. Defining Dialog Box Items:
  877.  
  878.      Defining the  objects in  a  dialog box  (e.g.,  a check  box)  occurs
  879. between  the  "BEGIN"  and "END"  statements.    A  lot  of  these  control
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887.  
  888. statements have as part of their parameter  list "col, row, width, height".
  889. These give the size and location of the object, and must be integers.  Some
  890. objects have  a "text" field,  which can be  any string enclosed  in quotes
  891. (e.g., "Cancel").   Most of the time, the optional "style" parameter can be
  892. either WS_TABSTOP or  WS_GROUP or  the two  combined using "|".   The  "id"
  893. parameter  is a  unique identifier  assigned  by the  programmer, with  the
  894. exception of static text controls, which are usually given an ID value of -
  895. 1  since they  are never selected.   The  control statements  are described
  896. below:
  897.  
  898. CHECKBOX - Format  "CHECKBOX text, id, col, row, width,  height [, style]".
  899. Defines a check box control.
  900.  
  901. COMBOBOX - Format "COMBOBOX id, col, row, width, height [,style]".  Defines
  902. a combo  box control.  This is a combination of an edit control and a drop-
  903. down list box.  The optional style parameter can include any combination of
  904. WS_TABSTOP, WS_GROUP, WS_DISABLED and WS_VSCROLL.
  905.  
  906. CONTROL - Format "CONTROL text, id, class, style, col, row, width, height".
  907. Specifies all forms  of child  window controls  within a dialog  box.   The
  908. "class"  parameter can be  either "button", "combobox",  "edit", "listbox",
  909. "scrollbar" or  "static".  The "style" parameter can  be any of the allowed
  910. values for CreateWindow().
  911.  
  912. CTEXT  -  Format  "CTEXT text,  id,  col, row,  width,  height  [, style]".
  913. Defines a centered static text control.
  914.  
  915. DEFPUSHBUTTON - Format "DEFPUSHBUTTON text,  id, col, row, width, height [,
  916. style]".  Defines the default pushbutton for a dialog box.
  917.  
  918. EDITTEXT  -  Format "EDITTEXT  id,  col,  row,  width, height  [,  style]".
  919. Defines  an editable text control in a dialog box.  The style parameter can
  920. be  any  combination  of  WS_TABSTOP,  WS_GROUP,   WS_VSCROLL,  WS_HSCROLL,
  921. WS_BORDER and WS_DISABLED.  Text is aligned  based on ES_LEFT, ES_CENTER or
  922. ES_RIGHT.
  923.  
  924. GROUPBOX - Format "GROUPBOX text,  id, col, row, width, height  [, style]".
  925. Draws a rectangle  with a title  at the  top left around  a group of  other
  926. controls.
  927.  
  928. ICON  - Format "ICON text, id, col, row  [, style]".  Places an icon in the
  929. dialog  box.   The "text"  parameter  is the  name of  the icon  as defined
  930. elsewhere  in the .RC file with an  ICON statement.  The only allowed style
  931. is SS_ICON.
  932.  
  933. LISTBOX - Format "LISTBOX id, col, row, width, height [, style]".  Places a
  934. list box in  the dialog box.   An example of  a list box  is, if you  run a
  935. Windows application  and select "File Open..."  from the menu  bar, the box
  936. that appears with a list of the filenames available for opening.   Possible
  937. values for "style" are any styles allowed in CreateWindow().
  938.  
  939. LTEXT - Format "LTEXT text, id, col, row, width, height [,style]".  Defines
  940. a left-justified static text control.  
  941.  
  942. PUSHBUTTON  - Format  "PUSHBUTTON  text,  id, col,  row,  width, height  [,
  943. style]".  Defines a  pushbutton for a dialog  box.  The allowed styles  are
  944. WS_TABSTOP, WS_DISABLED and WS_GROUP.
  945.  
  946. RADIOBUTTON  - Format  "RADIOBUTTON text,  id, col,  row, width,  height [,
  947. style]".  Defines a radio button in a dialog box.
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956. RTEXT - Format "RTEXT text, id, col, row, width, height [,style]".  Defines
  957. a right-justified static text control.  
  958.  
  959. SCROLLBAR  - Format  "SCROLLBAR id,  col,  row, width,  height [,  style]".
  960. Defines a scroll bar within a dialog box.
  961.  
  962.  
  963.      Here is an  example of  the DIALOG  statement that could  be used  for
  964. showing a list of  printers and letting the user select one.  It includes a
  965. list box to hold the printer names and three buttons: OK, RESET and CANCEL.
  966.  
  967.  
  968. IDL_PRINT DIALOG LOADONCALL MOVEABLE DISCARDABLE 78, 40, 124, 58
  969. CAPTION "Select a Printer"
  970. STYLE WS_OVERLAPPED | WS_DLGFRAME | WS_CAPTION | WS_POPUP
  971. BEGIN
  972.   LISTBOX IDL_LIST, 32, 6, 60, 27, LBS_STANDARD |WS_HSCROLL |WS_BORDER
  973.   DEFPUSHBUTTON "OK", IDL_OK, 4, 40, 37, 14, WS_GROUP
  974.   PUSHBUTTON "Reset", IDL_RESET, 44, 40, 37, 14, WS_GROUP
  975.   PUSHBUTTON "Cancel", IDL_CANCEL, 84, 40, 37, 14, WS_GROUP
  976. END
  977.  
  978.  
  979.      That's all for now about dialog boxes.  We'll continue next month with
  980. more resource types.   If you don't like the format and have  an idea for a
  981. better one, drop us a note.
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.           Programming Drag&Drop with Windows 3.1
  1025.                     by Andreas Furrer
  1026.  
  1027.  
  1028.      This  article describes writing  applications that uses  Drag&Drop. At
  1029. the end of this article is an  example of an application that makes the use
  1030. of Drag&Drop. The program is written in Turbo Pascal for Windows (1.0), but
  1031. many  of  the  things you'll  learn  in  this article  will  port  to other
  1032. languages.
  1033.  
  1034.      A nice new feature of Windows 3.1 is Drag&Drop (D&D). With D&D you can
  1035. use the  File Manager to select files and  drop them onto an application to
  1036. perform some action on the files (e.g., print them).
  1037.  
  1038.      In Windows 3.1 there  are a lot of applications that  make use of D&D.
  1039. For  example, if you want to read a text  file you can simply pick it up in
  1040. File Manager and drop it onto the window or the icon for Notepad or you can
  1041. print files by dropping them onto your Print Manager.
  1042.  
  1043.      You can also use D&D for your own applications.
  1044.  
  1045.      D&D is supported  by the new SHELL.DLL. There are  four procedures and
  1046. one new message.  The declarations in Pascal are:
  1047.  
  1048.  
  1049.   const  wm_DropFiles = $0233;
  1050.  
  1051.   procedure DragAcceptFiles(Wnd: HWnd; Accept: Bool);
  1052.                             external 'SHELL' index 9;
  1053.  
  1054.   function  DragQueryFile(Drop: THandle; FileIndex: Word;
  1055.                           FileName: PChar;MaxChars: Word): Word;
  1056.                           external 'SHELL' index 11;
  1057.  
  1058.   function  DragQueryPoint(Drop: THandle; var Pt: TPoint): Bool;
  1059.                            external 'SHELL' index 13;
  1060.  
  1061.   procedure DragFinish(Drop: THandle);
  1062.                        external 'SHELL' index 12;
  1063.  
  1064.      To use D&D with your application, you  first have to register at least
  1065. one Window of your application to accept dropped files.
  1066. This will be done by:
  1067.  
  1068.   DragAcceptFiles(HWindow,true);
  1069.  
  1070.      Now this HWindow  will receive wm_DropFiles message if  some files are
  1071. dropped onto it.  If you want to  undo the registration just pass  false as
  1072. the second parameter to the function above. This should always be done when
  1073. your window is destroyed.
  1074.  
  1075.      If  someone  drags some  files  onto your  window  you will  receive a
  1076. wm_DropFiles  message. The  word parameter  (wparam) of  this message  is a
  1077. handle  to a  global data  structure. This  structure contains  information
  1078. about the  dropped files and you have to use  this handle for all Drag&Drop
  1079. procedures. LParam is not used with this message.
  1080.  
  1081.      Now you  can get information about the dragged  files. You have to use
  1082. the following two functions:
  1083.  
  1084.  
  1085.  
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091.  
  1092. DragQueryFile:
  1093.  
  1094.   function  DragQueryFile(Drop: THandle; FileIndex: Word;
  1095.                           FileName: PChar;MaxChars: Word): Word;
  1096.                           external 'SHELL' index 11;
  1097.  
  1098.      With  this function you  will get the  filename of one  of the dragged
  1099. files.  You  have to  pass the  handle  of the  D&D structure  (received by
  1100. wm_DropFiles),  the index of the  file (0 is  the first), a  buffer for the
  1101. filename  and the size  of the buffer  to this function.  The function will
  1102. copy the filename into the buffer and return the number of copied chars. To
  1103. get the number of dropped files you can use $ffff as index.
  1104.  
  1105. DragQueryPoint:
  1106.  
  1107.   function  DragQueryPoint(Drop: THandle; var Pt: TPoint): Bool;
  1108.                            external 'SHELL' index 13;
  1109.  
  1110.      With this  function you  can get  the position  of the  cursor at  the
  1111. moment when the files were dropped. You have to pass the handle for the D&D
  1112. structure (received by wm_DropFiles), and a variable of type TPoint to this
  1113. function. The return value is true, if the files were dropped in the client
  1114. area of the window, otherwise (for the non-client area) it is false.
  1115.  
  1116.      At the  end of your D&D procedure you  have to tell Windows to release
  1117. the memory of the D&D data structure. This will be done with the DragFinish
  1118. function. Again  you have to pass  the handle of the D&D  structure to this
  1119. function.
  1120.  
  1121.      A  simple  application  for  demonstrating  D&D  is  a  Trashcan.  The
  1122. accompanying code will implement a Trashcan which will delete all files and
  1123. directories you dropped into its icon. See the TRASH.PAS file.
  1124.  
  1125.      After  starting Trashcan, you can easily delete files and directories.
  1126. Just select the files or directories in File Manager and drag them onto the
  1127. icon  of trashcan.  If you have  selected a  hidden, read-only or  a system
  1128. file, you will be asked if you really want to delete it.
  1129.  
  1130.      To build Trashcan,  you first have to open TRASH.RC  with the resource
  1131. workshop and save it as  TRASH.RES in the .RES format. Now you  can compile
  1132. TRASH.PAS and you will get TRASH.EXE.
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139.  
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.                       A Custom Install Program: Part I
  1161.                Using DDE to Communicate with Program Manager
  1162.                                By Pete Davis
  1163.  
  1164.      This is going to be a four part article  on writing an Install program
  1165. for Windows  applications. I haven't completed  the program yet so  I don't
  1166. even know exactly how it's going to turn out. My main problem at this point
  1167. is that I really want to have a file compression algorithm for the files to
  1168. be installed. The main problem is  my laziness. I'm not really in the  mood
  1169. to write  a unzip  program, but  since I'm  having trouble  coming up  with
  1170. alternatives, that may be my only possibility.
  1171.  
  1172.      This program is going to be loosely  based on one I wrote in the past.
  1173. I can't  use any of  that code because  it is  now the property  of someone
  1174. else, so  I have to  start from scratch.  There are essentially  three main
  1175. sections  which I will discuss separately. There's  the part that runs last
  1176. (which I'll be discussing first)  which involves telling Program Manager to
  1177. create our program group(s) and  application icon(s). The second part reads
  1178. and interprets a SETUP.INF file to get parameters of the installation, such
  1179. as what  files are to  be installed, what disk  they're on, whether  or not
  1180. they're executables, what  is the default directory, etc. The third part is
  1181. the  previously  mentioned   decompression  routines.  (If  anyone   has  a
  1182. decompression algorithm they'd like to donate, that would be terrific.) The
  1183. last article  will tie  all these  parts together  and make  them all  work
  1184. together.
  1185.  
  1186.      One thing  of extra interest  will be that the  decompression routines
  1187. will be  in a DLL.  When I originally wrote  my first install  program, the
  1188. UNZIP algorithm I used required a lot of memory and it was either make it a
  1189. DLL or  give it it's own  data segment. I  still haven't spent  enough time
  1190. with  multiple data segment  programs, so  I stuck with  the easy (or  so I
  1191. thought) method, the DLL.
  1192.  
  1193.      The first  part I  want to discuss  is using  DDE to  communicate with
  1194. Program Manager. This  was the most challenging part for me the last time I
  1195. wrote an  Install program, so it seems to me that it would be the part that
  1196. would be most interesting for a lot of people.
  1197.  
  1198.      My first few attempt at creating program groups were pathetic cludges.
  1199. My main aim at the time  was just to create the program group  files myself
  1200. and make the appropriate modifications to the PROGMAN.INI file. This turned
  1201. out to be a little more difficult than I expected  and I soon abandoned it.
  1202. The next thought was  to just create my own program group files and install
  1203. them as part of the installation process.  This was a workable solution but
  1204. would  not  allow for  installing  the  code in  anything  but  the default
  1205. directory. 
  1206.  
  1207.      About the time I was mulling over  the good and bad points of the last
  1208. option, I came across a little snippet about using DDE to  communicate with
  1209. Program Manager. After  a lot of  reading and looking  at source code  from
  1210. different sources I finally got a handle one it. This, incidentally, was my
  1211. first attempt with DDE so it was doubly challenging.
  1212.  
  1213.      My first attempt at the DDE  was itself a bit of a cludge.  Instead of
  1214. trying to follow all of the normal  DDE protocols, I just tried to force my
  1215. commands on Program  Manager without the  proper acknowledgements. (Ok,  so
  1216. I'm a  little lazy.) This  was only partially  successful and I  soon broke
  1217. down and went the whole nine yards. From my experience with it, I have only
  1218. this  to  say:  Follow the  protocol.  Don't  try to  force  DDE  down some
  1219. applications neck, 'cause it's gonna puke.
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.      Since this article doesn't discuss DDE in general, I'm not going to go
  1229. in depth about variations in DDE. That will be discussed in a later article
  1230. by me or  someone else (hopefully!). The way DDE with Program Manager works
  1231. is  something like this.  You put together  a string of  commands and place
  1232. them in a globally allocated space. A typical Program Manager command is:
  1233. [CreateGroup(My  Group)] You then send a  WM_DDE_EXECUTE command to Program
  1234. Manager  and pass it  the handle of your  globally allocated string. That's
  1235. about all there is, in theory. In practice, there's a lot that needs to  be
  1236. done.
  1237.  
  1238.      The segment  of DDE code provided  with this issue is  called PMDDE.C.
  1239. This  contains routines  which will be  called by  the main program,  so it
  1240. isn't  a  runable  module in  itself.  It  can be  included  with  your own
  1241. programs,  however. Additionally,  since  I  haven't  finished  the  entire
  1242. program yet, there's no way to be sure that it all works. Well, that's just
  1243. a  little splash of real life. If it  doesn't work when I'm done, then I'll
  1244. just have to fix it and provide any fixes required. I debated whether to do
  1245. this  article now or  wait until  I had the  whole program together,  but I
  1246. decided  that even  if there are  mistakes, the  algorithm itself  is still
  1247. valid, and the final product will work.
  1248.  
  1249.      The best way to handle a DDE conversation is to create a window that's
  1250. sole purpose is to handle your DDE conversation.  In our case, and in most,
  1251. the window that handles the DDE conversation is not the main window and  it
  1252. is usually not  a window in the sense  that it's visible. It  is simply the
  1253. procedure which handles  the DDE messages that  we want. In our  case we'll
  1254. call this procedure the  DDEWndProc. The creation of this window is handled
  1255. in the main program, but I'll give you an idea of what the code looks like.
  1256.  
  1257. /* This code is executed when the main windows procedure 
  1258.    receives the WM_CREATE message                       
  1259.    wc is a WNDCLASS variable.
  1260.    hDDEProc  is a static HWND                       */
  1261.  
  1262.      wc.style            = 0;
  1263.      wc.lpfnWndProc      = DDEWndProc;
  1264.      wc.cbClsExtra       = 0;
  1265.      wc.cbWndExtra       = 0;
  1266.      wc.hInstance        = hInstance;
  1267.      wc.hIcon            = NULL;
  1268.      wc.hCursor          = NULL;
  1269.      wc.hbrBackground    = NULL;
  1270.      wc.lpszMenuName     = NULL;
  1271.      wc.lpszClassName    = "DDEWndProc";
  1272.  
  1273.      RegisterClass(&wc);
  1274.      hDDEProc = CreateWindow("DDEWndProc", NULL, WS_CHILD,
  1275.                          0, 0, 0, 0 hWnd, NULL, hInstance, NULL);
  1276.  
  1277.      if (!hDDEProc)
  1278.           MessageBox(hWnd, "DDE Window won't come up.", "ERROR",
  1279.                                               MB_OK);
  1280.      That's all  there is to  creating this blank  little window. The  next
  1281. thing on our list is to handle the actual DDE conversation.
  1282.  
  1283.      Under the WM_CREATE  of our DDEWndProc procedure,  we need to add  two
  1284. global  atoms.  These  are  the   Application  and  Topic  names  that  our
  1285. conversation is supposed to  deal with. When  you start a DDE  conversation
  1286. and you want to  contact a DDE server application (Program  Manager in this
  1287. case) so you need to use the Application and Topic. Essentially what you do
  1288.  
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.  
  1296. is  send  a WM_DDE_INITIATE  message with  the application  and topic  as a
  1297. parameter.   (These   are   actually   one   parameter   by   passing   the
  1298. MAKELONG(Application, Topic) as a long in the message parameter.  You  also
  1299. need to pass the handle for your DDEWndProc in this message so that Program
  1300. Manager will  know  how to  get back  in  touch with  us.  Notice that  the
  1301. SendMessage  has a  -1  for  the first  parameter.  This  tells Windows  to
  1302. essentially broadcast the message to all programs that are running.
  1303.  
  1304.      The  DDEWndProc will handle several other messages. One of them is the
  1305. WM_DDE_ACK message. This message is  used to acknowledge responses from the
  1306. DDE server (Program  manager.) This  part is  not quite so  intuitive as  I
  1307. learned.  First  of  all,  this  part  has  to  be  broken  up.  If  you're
  1308. acknowledging the WM_DDE_INITIATE (which we sent first thing. Don't tell me
  1309. you already forgot what I wrote in the last paragraph!)  Ok, so here we are
  1310. sitting around with  nothing to do and BOOM, we get an acknowledgement from
  1311. our WM_DDE_INITIATE.  Well, it's about time. So the  first thing we want to
  1312. do is make sure  we grab the handle  of Program Manager. This is  passed as
  1313. the wParam of  the WM_DDE_ACK message sent  by Program Manager in  reply to
  1314. our  WM_DDE_INITIATE message.  With all of  the other  messages we  send to
  1315. Program Manager, we will now know exactly  who to send them to and not have
  1316. to broadcast all of our messages.
  1317.  
  1318.      At this point I'd like  to mention one thing about DDE.  There are two
  1319. ways  to  send  Windows  messages.  You  can  use  the SendMessage  or  the
  1320. PostMessage  procedures.  Both functions  do  the  same  thing except  with
  1321. SendMessage, the  message is sent and execution stops until the receiver of
  1322. the message has finished processing  the message. With PostMessage, control
  1323. returns  to  the  calling  program   immediately.  With  DDE  you  use  the
  1324. SendMessage only for  the WM_DDE_INITIATE message.  For all other  messages
  1325. you use the PostMessage procedure.
  1326.  
  1327.      In our DDEWndProc  we need to handle  the WM_DDE_ACK message.  This is
  1328. sent by Program  Manager in response to all of our messages. We're actually
  1329. going to break  that process into two  parts, though. The first  WM_DDE_ACK
  1330. that  we  get  is in  response  to  our WM_DDE_INITIATE.  When  we  get the
  1331. acknowledgement we then have to make sure that Program Manager will  handle
  1332. our  conversation.  We  also  need   to  grab  Program  Manager's   handle.
  1333. Additionally, the lParam of  each WM_DDE_ACK is probably going to have some
  1334. data that  it points  to that  we need  to delete.  In the  WM_DDE_INITIATE
  1335. response the  handles for two atoms are sent back to us. In this case, they
  1336. happen  to be  the same  two atoms  we  sent, so  we just  delete them.  In
  1337. response to our WM_DDE_EXECUTE messages, we get a Global Memory handle that
  1338. is also the same one we sent to Program Manager (you'll see this later)  so
  1339. we have to free it.
  1340.  
  1341.      That  basically handles  all  the  rough stuff.  To  send commands  to
  1342. Program  Manager  we   need  to  use  the  GlobalAlloc   command  with  the
  1343. GMEM_DDESHARE option  so that we can  share the data  with Program Manager.
  1344. The data is actually just  text strings that we pass to  Program Manager to
  1345. execute as commands.  These are commands  like CreateGroup, AddItem,  etc..
  1346. The commands we'll use are:
  1347.  
  1348. * CreateGroup(Group Name[, Group Path])
  1349.  
  1350.      Where Group Name is  the name of the Program Group you  want to add to
  1351. Program Manager. Group Path is optional and specifies the path of the group
  1352. file. In our case, we'll let program manager decide where to put that.
  1353.  
  1354. * AddItem(Program [, Program Name, IconPath, IconNum, X, Y, DefDir, HotKey,
  1355. Minimize]
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.  
  1363.  
  1364.      Just adds an Program item to the group you've created. The  Program is
  1365. that Path and the Filename of the  executable. Program Name is the name you
  1366. want to  give it under Program Manager. Those are  the only two we're going
  1367. to cover for now.
  1368.  
  1369.      The other  messages we're going  to handle is the  WM_CREATE_PMGRP and
  1370. WM_ADD_ITEM. These are custom messages that we're going to define in our .h
  1371. file. The first is  used to create the program group  under Program Manager
  1372. and the second is going to be create any items we're putting in the program
  1373. group. The lParam of these messages is going  to be a handle for Atoms that
  1374. are going to have the names of the program group and the file names.
  1375.  
  1376.      We'll then create the entire string that we want like:
  1377. "[CreateGroup(New Group)][ShowGroup(New Group)]" 
  1378. and pass  this off to Program Manager with a WM_DDE_EXECUTE message. Notice
  1379. that all commands are in brackets. Don't know why but just use 'em.
  1380.  
  1381.      That  about covers the  PMDDE.C. I might  modify it  before the fourth
  1382. article in this series, but if I do I'll pass it along. 
  1383.  
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.  
  1406.  
  1407.  
  1408.  
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414.  
  1415.  
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422.  
  1423.  
  1424.  
  1425.  
  1426.  
  1427.  
  1428.  
  1429.  
  1430.  
  1431.  
  1432.                Implementing a Linked List in the Global Heap
  1433.                               By Mike Wallace
  1434.  
  1435.      The ability to  implement a linked list  is almost a requirement  if a
  1436. platform  wants to get  taken seriously.   If you don't know  what a linked
  1437. list is, let me  explain.  Using an array to store  data internally is fine
  1438. if you have a good idea of how  many items you'll need to store, which will
  1439. determine the size  of the array (which  must be stated explicitly  in your
  1440. code prior to  compiling).  However, if  you don't have a  reasonable upper
  1441. bound, you have two solutions:  either make  the array as large as possible
  1442. and  hope it  always  works, or  allocate memory  dynamically.   The  first
  1443. solution isn't  good enough.  It usually means  a lot of wasted memory, and
  1444. in Windows, that's memory you can't afford to lose.  The second solution is
  1445. a  bit more  difficult  to implement,  but  is  the only  way  to go.    By
  1446. allocating memory  dynamically (that is,  at run-time),  you only  allocate
  1447. exactly enough memory  needed to hold your data.   This is the  method that
  1448. produces a linked list, so called because the data is stored in a "list" of
  1449. memory blocks (nodes),  where each block holds an item of data plus another
  1450. field giving  the memory  location of  the next  node in  the "list",  thus
  1451. "linking" the data.
  1452.  
  1453.      I recently had  to implement a linked  list for a Windows  program but
  1454. could not find any good  examples of how to do this, so I had to reason the
  1455. problem out.  It turned out to not be as difficult as I expected, but there
  1456. are some  things you need to keep in  mind when implementing a linked list.
  1457. Microsoft advises that when allocating a memory block, make it moveable and
  1458. discardable.   Why?  Windows is  more efficient if it can  move your memory
  1459. block around while the program is running in order to  make the most of the
  1460. available memory.  However, a consequence of this is that you cannot  use a
  1461. pointer when linking two consecutive nodes in the list because  Windows can
  1462. (and will) move each node  around in memory as it sees  fit.  So, I had  to
  1463. use a handle since  that would guarantee the address stored in  it (for the
  1464. next  node) would  always  be valid.    The tricky  part  was that  Windows
  1465. requires  a memory  block to  be  locked when  accessing a  node  by handle
  1466. because that ensures the node won't be moved until you unlock the block.
  1467.  
  1468.      At the end of this article I've included the source code for a routine
  1469. which allocates ten nodes in  the global heap, stores in each node a number
  1470. between 1 and 10 (the numbers are stored consecutively), then traverses the
  1471. list and prints (to  a file) the  value stored in  each node, and  finally,
  1472. retraverses the list and frees each node  one at a time.  Included with the
  1473. Windows  Programmer's Journal package is  all the code  and files needed to
  1474. run the program.   All of the files  have a filename of "linklist",  except
  1475. the  batch  file which  is  run to  compile  the program,  which  is called
  1476. "makelist.bat".
  1477.  
  1478.      The beginning of the function contains declarations for the  variables
  1479. needed to  implement the  linked list.   The _listmarker  structure is  the
  1480. structure  of each node in the  list.  The LISTMARKER  variable has to be a
  1481. FAR pointer to the structure since the function uses the global heap.   The
  1482. LISTMARKER variables  (tailPos, tempPos and  headPos) are used  to traverse
  1483. the list.  Finally, "fp" is a file pointer to the output file.
  1484.  
  1485.      After  the function  opens the  output  file for  writing,  it does  a
  1486. GlobalAlloc to allocate a block on the  global heap for the first node.  If
  1487. "NULL"  is returned, it means there  was not enough room  for the node of a
  1488. size of FileMarker, so the function  displays a message to that effect  and
  1489. returns to the  calling routine.  Otherwise, the  allocated block is locked
  1490. (so  the block  doesn't move while  its fields are  getting assigned), gets
  1491. initialized and then  gets unlocked.  The "hMem" handle points to the first
  1492.  
  1493.  
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500. node for the duration of the function.  This algorithm is repeated for each
  1501. successive node, using tailPos to point to the current end of the list.
  1502.  
  1503.      The function then traverses the linked list, printing out the value of
  1504. the "value" field to the output  file.  This is done by locking  each node,
  1505. performing a  "fprintf" on the "value"  field and then unlocking  the node.
  1506. The output file is then closed.
  1507.  
  1508.      Finally, the function traverses  the list, freeing each node  one at a
  1509. time.  This  is done by locking  each node, saving  its handle to the  next
  1510. node, unlocking the  current node and then  freeing it.  This  algorithm is
  1511. repeated until the list has been traversed.
  1512.  
  1513.      That is the entire algorithm.  This is the first time I have written a
  1514. linked list in Windows, so there may be more efficient methods of attaining
  1515. the same ends.   If you can find any,  please send in your suggestions  and
  1516. we'll print them.
  1517.  
  1518.  
  1519. void FAR PASCAL MakeList (HWND hWnd)
  1520. {
  1521.      /* local variables */
  1522.      short           i;
  1523.      static HANDLE   hMem, hMem2, hMem3;
  1524.  
  1525.      /* structure of each node in linked list */
  1526.      typedef struct _listmarker {
  1527.  
  1528.           short   value;
  1529.           HANDLE  next;
  1530.  
  1531.      } ListMarker;
  1532.  
  1533.      /* declare a far pointer to the above structure */
  1534.      typedef ListMarker FAR *LISTMARKER;
  1535.  
  1536.      LISTMARKER tailPos, tempPos, headPos;
  1537.  
  1538.      /* pointer to output file */
  1539.      FILE *fp;
  1540.  
  1541.      /* Open output file for writing */
  1542.      fp= fopen("data.out", "w");
  1543.  
  1544.      /* Build initial linked list of the numbers 1 to 10 */
  1545.      if((hMem= GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, 
  1546.           sizeof(ListMarker))) == NULL) {
  1547.  
  1548.           /* Not enough memory, so beep, show a message and return */
  1549.           MessageBeep(0);
  1550.           MessageBox(hWnd, "Out of allocation memory!", "ERROR", MB_OK);
  1551.  
  1552.           return;
  1553.  
  1554.      }
  1555.  
  1556. /* Lock the first node, save a value, set next to NULL and unlock */
  1557.      tailPos= headPos= (LISTMARKER) GlobalLock(hMem);
  1558.      headPos->value= 1;
  1559.      headPos->next= NULL;
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.      GlobalUnlock(hMem);
  1569.  
  1570. /* Allocate a node for each of the numbers between 2 and 10 and link */
  1571.      for (i=2; i < 11; i++) {
  1572.  
  1573.           /* setup index lookup lists */
  1574.           if((tailPos->next= GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, 
  1575.                sizeof(ListMarker))) == NULL) {
  1576.  
  1577.                MessageBeep(0);
  1578.                MessageBox(hWnd, "Out of allocation memory!", "ERROR",
  1579.                                    MB_OK);
  1580.  
  1581.                return;
  1582.  
  1583.           }  /* If - End */
  1584.  
  1585.           /* Lock the next node, save  the value, and set its next  to NULL
  1586. */
  1587.           hMem2= tailPos->next;
  1588.           tempPos= (LISTMARKER) GlobalLock(hMem2);
  1589.           tailPos= tempPos;
  1590.           tailPos->value= i;
  1591.           tailPos->next= NULL;
  1592.  
  1593.           GlobalUnlock(hMem2);
  1594.  
  1595.      }  /* While - End */
  1596.  
  1597.      /* Lock the 1st node and write out its "value" field */
  1598.      tailPos= headPos= (LISTMARKER) GlobalLock(hMem);
  1599.      fprintf(fp, "%d\n", tailPos->value);
  1600.  
  1601.      /* Save the handle to the next node */
  1602.      hMem2= tailPos->next;
  1603.  
  1604.      /* Unlock the 1st node */
  1605.      GlobalUnlock(hMem);
  1606.  
  1607.      /* Go through list and print out "value" until no more nodes */
  1608.      while (hMem2 != NULL) {
  1609.  
  1610.           /* Lock the next node and save to tailPos */
  1611.           tempPos= (LISTMARKER) GlobalLock(hMem2);
  1612.           tailPos= tempPos;
  1613.  
  1614.           fprintf(fp, "%d\n", tailPos->value);
  1615.  
  1616. /* Get the handle to the next node and then unlock the current one */
  1617.           hMem2= tailPos->next;
  1618.           GlobalUnlock(hMem2);
  1619.  
  1620.      } /* While - End */
  1621.  
  1622.      /* Close the output file */
  1623.      fclose(fp);
  1624.  
  1625.      /* free nodes in the list */
  1626.      tempPos= (LISTMARKER) GlobalLock(hMem);
  1627.      hMem2= tempPos->next;
  1628.  
  1629.  
  1630.  
  1631.  
  1632.  
  1633.  
  1634.  
  1635.  
  1636.      tempPos= (LISTMARKER) GlobalLock(tempPos->next);
  1637.      GlobalUnlock(hMem);
  1638.      GlobalFree(hMem);
  1639.  
  1640.      while(tempPos->next != NULL) {
  1641.  
  1642.         hMem3= tempPos->next;
  1643.         tempPos= (LISTMARKER) GlobalLock(tempPos->next);
  1644.         GlobalUnlock(hMem2);
  1645.         GlobalFree(hMem2);
  1646.         hMem2=hMem3;
  1647.  
  1648.      }
  1649.  
  1650.      GlobalUnlock(hMem2);
  1651.      GlobalFree(hMem2);
  1652.  
  1653.      return;
  1654.  
  1655. } /* MakeList */
  1656.  
  1657.  
  1658.  
  1659.  
  1660.  
  1661.  
  1662.  
  1663.  
  1664.  
  1665.  
  1666.  
  1667.  
  1668.  
  1669.  
  1670.  
  1671.  
  1672.  
  1673.  
  1674.  
  1675.  
  1676.  
  1677.  
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688.  
  1689.  
  1690.  
  1691.  
  1692.  
  1693.  
  1694.  
  1695.  
  1696.  
  1697.  
  1698.  
  1699.  
  1700.  
  1701.  
  1702.  
  1703.  
  1704.                                 Book Reviews
  1705.                                By Pete Davis
  1706.  
  1707.  
  1708. Undocumented  Windows: A Programmer's  Guide to Reserved  Microsoft Windows
  1709. API Functions
  1710.  
  1711. by Andrew Schulman, David Maxey, and Matt Peitrek
  1712. Addison-Wesley Publishing Company
  1713. ISBN 0-201-60834-0
  1714.  
  1715.  
  1716.      Well,  away with the  formality and on  to the book  review. If you're
  1717. comfortable  with programming Windows,  then I have  only two words  to you
  1718. regarding this book:  BUY IT! This is  the one of the  best references, not
  1719. only for finding functions that Microsoft 'forgot' to tell us about, but it
  1720. also  gives an  incredible  amount of  insight into  how  the internals  of
  1721. Windows operates. Not to take  away from Maxey and Peitrek, but  Schulman's
  1722. fingerprints are all over this book. 
  1723.  
  1724.      This book  is very well  organized. Each chapter  is divided in  a way
  1725. that's easy to  understand and covers specific  topics.  It's hard  to know
  1726. where to start with  this book, it has it  all. It has chapters on  KERNEL,
  1727. USER,  GDI, and  SYSTEM  calls. It  has a  chapter on  undocumented Windows
  1728. messages.  There are  great  chapters  on how  to  disassemble and  examine
  1729. Windows  executables.  This is  particularly  useful for  the  true Windows
  1730. hacker.
  1731.  
  1732.      The  book also comes  with a load  of utilities  for examining Windows
  1733. executables. I have actually found several of these utilities useful simply
  1734. for debugging  my  own code.  Some  of the  utilities  will tell  you  what
  1735. undocumented calls a program  is making. This is a neat little  way to find
  1736. out who's got an inside track at  Microsoft. Of course, with the release of
  1737. Undocumented  Windows,  many of  these  calls  are going  to  be  used more
  1738. frequently.
  1739.  
  1740.      Microsoft's  humor in naming  some of these  calls (e.g. BozosLiveHere
  1741. and  TabTheTextOutForWimps)  are  accented with  the  authors'  humor. When
  1742. discussing  how a  certain utility  sometimes "decides  that a  function is
  1743. undocumented  when  in fact  it's  documented.  (It's  sort of  like  one's
  1744. coworker who every week thinks he's found a bug in the compiler)." The book
  1745. is a joy to read just for the humor alone.
  1746.  
  1747.      Although there are a lot of functions listed (well over a hundred, I'd
  1748. guesstimate), the true value of this book lies in its discussion of Windows
  1749. and  how Windows  operates. There  is  more in  this book  on  the internal
  1750. operations of Windows  than any ten books  I've seen. He also  discusses at
  1751. length the politics at Microsoft regarding the undocumented functions. 
  1752.  
  1753.      Well, I've talked  about all  the reasons  that I like  the book,  but
  1754. let's  discuss  it's usefulness.  Is  it  useful?  Well, for  its  in-depth
  1755. discussion   of  Windows  internals,  yes.  The  functions  themselves  are
  1756. scattered in a lot of different areas  of programming. Some would be useful
  1757. to some people while others would be useful to others. For example, someone
  1758. working on  a Windows debugger would be very  interested in task queues and
  1759. the  like  whereas  a  programmer  of  a painting  package  might  be  more
  1760. interested in the GDI function calls.  There are tons of functions and  the
  1761. documentation of each one is more complete than the documentation Microsoft
  1762. provides for most of it's 'documented' functions. 
  1763.  
  1764.  
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.  
  1771.  
  1772.      Schulman and  Co. have done a  fantastic job on this book  and I don't
  1773. think  I  could give  it a  higher  recommendation. I  look forward  to his
  1774. Undocumented NT (maybe? perhaps?).
  1775.  
  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.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.                                  Last Page
  1841.                               By Mike Wallace
  1842.  
  1843.      Well, it's happened.
  1844.      The  first issue  of Window's  Programmer's  Journal (official  motto:
  1845. Apply directly to infected areas) is done,  and I feel good about it.  Why?
  1846. Because it's the first magazine I've seen that is fully devoted  to Windows
  1847. programming and  it's more  than just  product reviews.   Pete  and I  were
  1848. hungry  for something like WPJ  but couldn't find  anything that was really
  1849. helpful, so we thought,  "Let's do one ourselves."   It's been fun  so far,
  1850. and hopefully  we'll get lots  of articles from  ya'll so we  can fill each
  1851. issue with solutions  to your Windows programming  problems.  If you  think
  1852. you have an idea for an article, send it in!  If you just want to submit an
  1853. outline for an article to see if we'd be interested before you write a full
  1854. article, do it!  The magazine can't last long without help from you people,
  1855. and if you've done something cool in Windows, we want to hear about it!  If
  1856. you have any questions  about Windows, ask!  We're going to start a letters
  1857. column as  soon as  we have enough  letters to  fill one,  and if we  can't
  1858. answer  your questions, we'll submit them to the rest of our readers to get
  1859. an answer.  We're not just doing  this as part of our work-release program,
  1860. we  want to  learn everything we  can about  programming in Windows,  and I
  1861. haven't seen any magazines that are as devoted to it as I'd like, and we're
  1862. not looking for  articles written  by people  with Ph.D.s -  we'll take  an
  1863. article from anybody.  Future issues will depend on it.
  1864.  
  1865.      Speaking of future issues,  we have a few ideas about  what you'll see
  1866. soon.   Pete's going to write  an article about how to  print under Windows
  1867. 3.0 & 3.1, we'll  continue our beginner's column, start a  column on how to
  1868. program C++  (written by  me - since  I don't  know anything  about C++,  I
  1869. seemed overly  qualified to write a beginner's  column on it), some product
  1870. reviews  of books and  software, and just  yesterday I bought  a Windows NT
  1871. workstation  and Pete has the pre-release of NT, so we're going to tell you
  1872. all about that and try to write some programs for it.
  1873.  
  1874.      Coming Soon!   The WPJ BBS!   By Jan. 1st (if we're  lucky, and by the
  1875. 5th if we're not  quite so lucky), you  can send your articles  and letters
  1876. directly to us.   We also plan on putting the SIMTEL20 CD-ROM  on it so you
  1877. can download anything you  want.  It's a  great CD full of stuff  you never
  1878. knew  you needed but  can't live without  once you get  it.   We'll also be
  1879. getting the  CICA CD-ROM  of Windows shareware  and public  domain software
  1880. soon.  See  the "How to get  in contact with us" section  elsewhere in this
  1881. issue for more info.
  1882.  
  1883.      If you're wondering  about the point of  this column, this is  where I
  1884. get to  rant and rave about anything  I'd like.  If you  don't want to read
  1885. it,  don't.  You won't miss  anything of earth-shattering importance.  I'll
  1886. try to make it interesting, but there's no telling what will  happen here -
  1887. you'll have  to wait and see.  If there's anything on your mind you want to
  1888. talk about it, send me a note and if it sounds like it would be of interest
  1889. to other  readers, I'll write what I  can about it.  This  is your forum as
  1890. much as  mine.   One of  my minors  in school  (Va. Tech,  by the  way -  I
  1891. graduated in  '89 with a BS in Computer  Science) was philosophy (the other
  1892. was math - I knew you were wondering about that!), so just  because I don't
  1893. know anything  about a  subject won't stop  me from writing  about it.   If
  1894. there's anything  you want to get  off your chest,  tell me about it.   I'm
  1895. always looking for a good discussion about anything.
  1896.  
  1897.      That's the  first issue.   Hope you  liked it;  hope we're  around for
  1898. awhile.   This could be  a lot of fun, and  we want you to  join us.  Until
  1899. next month, may you look like the late Totie Fields!
  1900.  
  1901.  
  1902.  
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908.                          Getting in touch with us:
  1909.  
  1910.  
  1911.      Right now there are  only four ways  to get in touch  with us. If  you
  1912. have access to the Internet or BITNET, you can get in touch with us at:
  1913.  
  1914. HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (both Pete)
  1915.  
  1916. CompuServe: 71141,2071 (Mike)
  1917.  
  1918. WPJ BBS (703) 503-3021
  1919.  
  1920. You can also send paper mail to:
  1921.  
  1922. Windows Programmer's Journal
  1923. 9436 Mirror Pond Drive
  1924. Fairfax, VA   22032
  1925.       U.S.A.
  1926.  
  1927.  
  1928.      Also, around January  1st, we'll be setting  up a BBS  specifically to
  1929. support  the WPJ,  but  we'll  also be  offering  the  SIMTEL20 CD-ROM  for
  1930. downloads. The SIMTEL20  system is  one of  the largest  sources of  public
  1931. domain and shareware  software. We'll also be  adding more CDs later  as we
  1932. can afford it.
  1933.  
  1934.      Anyway, the Windows Programmer's Journal  BBS can be reached at: (703)
  1935. 503-3021. You can get in touch with either Mike or Pete at this number. The
  1936. BBS is going to  be relatively new, so don't be surprised  if it's a little
  1937. buggy in the beginning. Right now it's only 2400 baud as my 9600 baud modem
  1938. died on me,  but in the first  month or two you  can expect it to  go up to
  1939. 14,400.  You can also expect  to see a Fido-net node  address by the second
  1940. issue.
  1941.  
  1942.  
  1943.  
  1944.  
  1945.  
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951.  
  1952.  
  1953.  
  1954.  
  1955.  
  1956.  
  1957.  
  1958.  
  1959.  
  1960.  
  1961.  
  1962.  
  1963.  
  1964.  
  1965.  
  1966.  
  1967.  
  1968.  
  1969.  
  1970.  
  1971.  
  1972.  
  1973.