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