home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / c / WPJ1_2.ZIP / WPJV1N2.TXT < prev   
Encoding:
Text File  |  1993-02-01  |  74.6 KB  |  2,047 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.     WW     WW     WW      PPPPPPPP              JJ
  8.     WW     WW     WW      PP    PP              JJ
  9.      WW   WWWW   WW       PP    PP              JJ
  10.      WW  WW  WW  WW       PPPPPPPP              JJ
  11.      WW  WW  WW  WW       PP             JJ     JJ
  12.       WWWW    WWWW        PP              JJ   JJ
  13.        WW      WW         PP               JJJJJ
  14.  
  15. ----------------------------------------------------------------
  16. The Windows Programmer's Journal                       Volume 01
  17. Copyright 1993 by Peter J. Davis                       Number 02
  18. and Mike Wallace                                          Feb 93
  19. ----------------------------------------------------------------
  20. A monthly forum for novice-advanced programmers to share ideas and concepts
  21. about programming in the Windows (tm) environment.
  22.  
  23. You can get in touch with the editor via Internet or Bitnet at:
  24.  
  25. HJ647C at GWUVM.BITNET   or   HJ647C at GWUVM.GWU.EDU
  26.  
  27. CompuServe: 71141,2071
  28.  
  29. or you can send paper mail to:
  30.  
  31. Windows Programmer's Journal
  32. 9436 Mirror Pond Dr.
  33. Fairfax, Va. 22032
  34.  
  35. The two GWUVM IDs are Pete's and CompuServe is Mike's.
  36.  
  37. We can also be reached by phone at: (703) 503-3165.
  38.  
  39. Microsoft, MS-DOS,  Microsoft Windows, Windows NT,  Windows for Workgroups,
  40. Windows for Pen Computing,  Win32, and Win32S are registered  trademarks of
  41. Microsoft Corporation.
  42.  
  43. Turbo  Pascal  for Windows,  Turbo C++  for  Windows, and  Borland  C++ for
  44. Windows are registered trademarks of Borland International.
  45.  
  46. WordPerfect is a registered trademark of WordPerfect Corporation.
  47.  
  48. WPJ is available  from the WINSDK, WINADV and MSWIN32 forums on CompuServe,
  49. and the  IBMPC, WINDOWS and  BORLAND forums  on GEnie.   On Internet,  it's
  50. available on WSMR-SIMTEL20.ARMY.MIL and FTP.CICA.INDIANA.EDU.  We upload it
  51. by  the 1st  of each  month and  is usually  available by  the 3rd  or 4th,
  52. depending on when the sysops receive it.
  53.  
  54. The Windows Programmer's Journal takes no responsibility for the content of
  55. the text within this document. All  text is the property and responsibility
  56. of the individual  authors. The  Windows Programmer's Journal  is solely  a
  57. vehicle for  allowing articles to be collected  and distributed in a common
  58. and easy to share form. No part  of the Windows Programmer's Journal may be
  59. re-published or  duplicated in  part or whole,  except in the  complete and
  60. unmodified form  of the Windows  Programmer's Journal, without  the express
  61. written  permission of  each  individual author.  The Windows  Programmer's
  62. Journal  may not be sold for  profit without the express written permission
  63. of  the  Editor, Peter  J.  Davis,  and only  then  after  he has  obtained
  64. permission from the individual authors.
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.                     Table of Contents
  74.  
  75. Subject                                        Page Author(s)
  76. -----------------------------------------------------------------
  77. WPJ.INI .......................................  3  Pete Davis
  78.  
  79. Letters .......................................  5  Readers
  80.  
  81. Install Program Part II .......................  7  Pete Davis
  82.  
  83. Programming a Drag&Drop Server ................  9  Andreas Furrer
  84.  
  85. C++ Beginner's Column ......................... 12  Mike Wallace
  86.  
  87. Beginner's   Corner   (C)   .........................   14     Pete   Davis
  88.                                                     & Mike Wallace
  89.  
  90. Using LZExpand Library ........................ 18  Alex Fedorov
  91.  
  92. Implementing a Linked List - Revisited ........ 21  Mike Wallace
  93.  
  94. An Introductory Look at DLLs and Make Files ... 22  Rod Haxton
  95.  
  96. The Windows Help Magician ..................... 29  Jim Youngman
  97.  
  98. Last Page ....................................  30  Mike Wallace
  99.  
  100. Getting in Touch with Us .....................  31  Pete & Mike
  101.  
  102.  
  103.  
  104.  
  105. Windows Programmer's Journal Staff:
  106.  
  107. Publishers ......................... Pete Davis and Mike Wallace
  108. Editor-in-Chief .................... Pete Davis
  109. Managing Editor .................... Mike Wallace
  110. Contributing Writer ................ Andreas Furrer
  111. Contributing Writer ................ Alex Federov
  112. Contributing Writer ................ Rod Haxton
  113. Contributing Writer ................ Jim Youngman
  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.  
  141.                                   WPJ.INI
  142.                                By Pete Davis
  143.  
  144.      Well, welcome to the second issue of the Windows Programmer's Journal.
  145. I  don't really know  what to  say. We've  been totally  blown away  by the
  146. response  we've been getting.  I'm writing this  on January 15th  and as of
  147. today, on Compuserve and  GEnie (the only two places we  can really see how
  148. many  issues are being downloaded) we've counted 873 downloads. That number
  149. goes up  every day and it doesn't include all  of the other places that the
  150. Windows  Programmer's Journal is available. We've gotten letters from a lot
  151. of you  with good and  bad things to  say. (When I  say bad, I  really mean
  152. critical.) Criticism is fine and  we're even going to publish some of it in
  153. this issue.
  154.  
  155.      We've also  received a terrific  response from Andrew  Schulman, whose
  156. book  we reviewed in  the last issue.  We'll show an  excerpt from that and
  157. other letters in the letters column. 
  158.  
  159.      One  of the criticisms  that was  most discussed  was the  Linked List
  160. article written  by Mike.  We  should be  receiving an  article from  Peter
  161. Shroesbree for  the next issue, showing an alternate way of doing it. We'll
  162. also have a  third article, showing yet  another way of doing this  in next
  163. month's issue, done by Rod Haxton,  who's writing an article in this issue.
  164. Since this has  become a  bit of a  hot topic,  we're going to  do a  short
  165. article in next  month's issue  about the advantages  and disadvantages  of
  166. each of these methods.
  167.  
  168.      We'd  also like to welcome David Campbell.   In March, he'll be taking
  169. over the beginner's  column. David has a good bit  of experience in Windows
  170. programming and is quite a hacker. He has shareware and commercial software
  171. on the market, so his experience will be valuable to all of us.
  172.  
  173.      Speaking of experience, I suppose it's time to kind of spill the beans
  174. about Mike and I.  So as not to confuse  anyone, neither Mike nor I  have a
  175. lot  of experience  programming  Windows. We  are  not authorities  on  the
  176. subject, but we don't think  that means we don't know a few  things that we
  177. can share. We're both learning a lot all the time. The linked list  article
  178. is an  example. All I'm  trying to say  is, don't  say, "Well, the  Windows
  179. Programmer's Journal says this, so it must  be true."  Not that you  would,
  180. but we all  can make mistakes and we're  not always going to be  right. The
  181. good thing is that there are obviously  a lot of you out there reading this
  182. and with your help, we can make corrections.
  183.  
  184.      We have another  article from Andreas Furrer this month. Last month he
  185. wrote  an article about  programming a Drag  & Drop client  in Windows 3.1.
  186. This month he's going  to talk about writing a Drag  & Drop server program.
  187. We've also  got an article by Alex  Federov of Moscow, Russia  on using the
  188. LZEXPAND.DLL. 
  189.  
  190.      Just got my  sample issue of Windows Tech Journal.  Ahem... How do you
  191. spell cancel? Nah, it ain't  that bad, just not really my type of magazine,
  192. I guess. Had an offer for Windows NT Developer.  12 issues for a mere $129.
  193. No thanks, I'll buy the book.
  194.  
  195.      Sorry, I digress. Geez, let's see, I'm going to be  writing the second
  196. part to the install program. I'm basically covering a lot of the stuff Alex
  197. Federov is covering.  His sample, however, is  written in Turbo Pascal  for
  198. Windows.  I was supposed to do an article on printing, this month, but I've
  199. been really busy, so I'm going to have to put it off until the  next issue.
  200. I'll share  a really  wonderful  experience with  you  about my  trials  in
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209. learning to print also.
  210.  
  211.      Ah, and  I almost forgot. We're going to do  a reader poll next month.
  212. Here's the question. What  format would you like  to see WPJ in? We've  had
  213. suggestions for a lot of different  formats. Mike is leaning in the Windows
  214. Write direction. That's ok,  but it doesn't quite have the power  of a real
  215. word processor, which is a pain when putting the whole thing together. Dave
  216. Campbell suggested Windows WINHELP format.  I've seen a sample, and I  have
  217. to  say,  it's  pretty damn  impressive.  We've  also  had suggestions  for
  218. Postscript and TeX. Now, the problem with Postscript,  as I see it, is it's
  219. BIG. That means it'll take longer for you to download. If you're getting it
  220. off Compuserve or  GEnie, or some other pay system, it costs you. As far as
  221. TeX, I  don't know how  popular it  is. Personally I've  never used it  and
  222. don't know  anyone who  has (though  I've heard good  things about  it), so
  223. unless we get a huge outcry for the TeX format, I don't think we'll go that
  224. way. That leaves  the regular text  format that you're  getting it in  now,
  225. Write format, or  WinHelp format. Now, before you cast  your votes, we will
  226. be distributing the March issue in all three of those formats. After March,
  227. tell us what you think. I just wanted to give everyone a heads-up on that.
  228.  
  229.      One  final note: We mentioned our BBS in  the last issue. Well, we had
  230. it up for  about 3 days and  before anyone had a  chance to call, the  hard
  231. drive got wiped out. I've  been trying to get the thing  back together, but
  232. the hard drive is really  getting unreliable. What it looks like  I'm going
  233. to have to  do is get rid of it and replace it. I currently have two 65 meg
  234. Seagates  which have  done their  time.  The main  one (C:  drive) is  just
  235. getting a little too flakey,  so we're going to toss it and  probably throw
  236. in a 600 meg hard drive that we saw a good deal on. (We have two  machines,
  237. so we're  going to network  them so that  Mike can use  the 600 meg  on his
  238. machine too.)  Anyway, we don't know if we'll have  it up this month. If we
  239. don't, it'll be next month. Sorry for the problems there.
  240.  
  241.      I'd like to thank everyone who's  reading the magazine and sending  in
  242. their comments and suggestions. It helps us to do a better job and it helps
  243. you get a better magazine. We really appreciate your comments and we'd like
  244. you to  keep them coming.  Also, as  always, please, please,  send us  your
  245. articles. We want them!!!!
  246.  
  247.      By the way, it's now January 31  and the number of downloads on  GEnie
  248. and Compuserve alone are about 1200, total. Sorry, just about  broke my arm
  249. patting myself on the back there. 'Scuse me while I pump up our egos a bit.
  250. We'll try not to do that too often.
  251.  
  252.      And remember, if you read it  in the Programmer's Journal, it might be
  253. right!
  254.  
  255.                                                   _Pete Davis
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.                                   Letters
  278.  
  279. Date:  04-Jan-93 13:48 EST
  280. From:  Andrew Schulman [76320,302]
  281. Subj:  Windows Programmer's Journal
  282.  
  283.      Thanks  very much  for sending the  magazine.   Of course,  I read the
  284. review of UndocWin  very carefully, and read the rest  pretty carefully.  I
  285. guess my main question  is, Why the heck are you guys doing this?  You both
  286. write well.  The material is interesting and  entertaining.  So why are you
  287. giving it away  for free?   Doesn't make  any sense  to me.   You could  be
  288. making  money from  your  writing, though  not  necessarily with  your  own
  289. magazine.   But clearly you  could write  for MSJ, WDDJ,  or Dr. Dobb's  (I
  290. won't mention that other magazine that covers Windows programming...).  So,
  291. like, why give the stuff away? 
  292.  
  293.      Thanks  for the kind review of UndocWin.   If you are looking for more
  294. stuff on  how Windows operates,  I think  you'll be pleased  with the  book
  295. "Windows Internals" that Matt Pietrek is just finishing up.  It will appear
  296. in the series  of books I am editing for  Addison-Wesley, probably in March
  297. or  April.   Most of the  book is  typeset already.   It  presents detailed
  298. pseudocode for many  of the key Windows API functions.  For example, if you
  299. want to know what CreateWindow or RegisterClass or GetMessage or ShowWindow
  300. or GlobalAlloc actually does, in sometimes painful detail, this is it.
  301.  
  302.      UndocNT?  Well, that's an interesting question.  Microsoft has   asked
  303. me that question too.   As you know, the  entire NT API (as opposed  to the
  304. Win32 API) is right  now undocumented.  Helen Custer's book "Inside Windows
  305. NT"  does a good job of showing in a conceptual-overview sort of way how NT
  306. works, but as she  herself says in  the preface the book's  goal is to  how
  307. "exactly how NT sort of  works"  Exactly sort  of!  A brief examination  of
  308. the NT process viewer,  PVIEW.EXE, shows that there is  some dynamite stuff
  309. at the NT API layer that currently  isn't available via Win32.  (Ray Duncan
  310. was  who  put me  on  to  looking  at PVIEW;  I  looked  at it  first  with
  311. Microsoft's COFF -DUMP,  and have  since been modifying  my Windows  Source
  312. product to disassemble PE files.) 
  313.  
  314.      So there's a  lot of interesting stuff in NT.   And Microsoft actually
  315. seems to look _favorably_ on an Undocumented NT book.  This way, they don't
  316. have to document it!
  317.  
  318.      There's just  one problem:  to do a book  like UndocDOS or UndocWin or
  319. UndocNT takes  a long time.   Basically, it's not  worth doing such  a book
  320. unless you're going to sell a  lot of copies.  And  I do not think that  NT
  321. anything is  going to sell  a lot of  copies for a few  years.  To  me, the
  322. whole thing is reminiscent  of OS/2 in a lot of ways.   (In a lots of ways,
  323. it's not  reminiscent of OS/2 of  course:  Microsoft has  clearly learned a
  324. lot of lessons, but I think it's also repeating some of the same mistakes.)
  325. Me, I'm putting my money on Win32s rather  than NT.  I told one of the guys
  326. at Microsoft  that I would  start working on  it after they  sold a million
  327. copies of NT.  I'm not holding my breath. 
  328.  
  329.      In looking over  this letter, I  realize that the phrases  "money" and
  330. "sell" keep appearing.  This must say something about me.  :-)
  331.  
  332. Regards,
  333. Andrew
  334.  
  335. [Thanks  for the  kind  review of  WPJ,  Andrew, and  the  tip on  "Windows
  336. Internals" - I look forward to reading it. -Mike]
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345. Date:  10-Jan-93 03:22 EST
  346. From:  Alex Fedorov [72400,274]
  347. Subj:  WPJ
  348.  
  349. Mike--
  350.  
  351.      Here is Alex Fedorov from Moscow,  Russia.  Yesterday I downloaded the
  352. 1st  issue of  WPJ. This is  great! I've  a whole  set of  Peter's previous
  353. magazine - Pascal News Letter. I liked it. I'm working as an editor for our
  354. "Computer Press" magazine - the most popular computer magazine here. Before
  355. that I've worked  as tech support person for Borland Pascal  for one of its
  356. distributors here.  Reading  WPJ.INI section,  I've realized  that you  are
  357. looking for authors. I would like to offer a set  of articles, dedicated to
  358. changes in  Windows 3.1 - new DLLs, concepts and APIs from Turbo Pascal for
  359. Windows.   These articles  were prepared for  publication here  and can  be
  360. translated in  a short time. The  articles cover new  kernel API functions,
  361. TrueType  fonts,  OLE/DDEML,  COMMDLG,  Drag  and  Drop,  VER and  TOOLHELP
  362. libraries.   Beside the  texts, there is  plenty of examples,  which can be
  363. used like small utilities.
  364.  
  365.      Please  let me know  if this is  interesting for beginner/intermediate
  366. section of WPJ. Also, I've plenty of hacks for advanced users. 
  367.  
  368.                                    Let me know if you need more
  369.                                    information.
  370.   
  371.                                    Sincerely, Alex
  372.  
  373. [Glad you liked the 1st issue, Alex.  Hope the rest go over as well.  We've
  374. included  your first  article in  this issue  and plan  to include  more in
  375. future issues. -Mike] 
  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.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.                 Install Program Part II: File Decompression
  414.                                By Pete Davis
  415.  
  416.      Well, I don't know where my head's been, but I think I found  it. Last
  417. time  I  was  discussing  how  much   I  was  dreading  coming  up  with  a
  418. decompression  algorithm and it  occurred to me  that I don't  need to. The
  419. LZEXPAND.DLL has all the routines we need for decompression. I was still in
  420. the  Windows  3.0  mindset.  When  I  did  my  first  install  program  the
  421. LZEXPAND.DLL  wasn't available  to me, so  I didn't  even consider  it last
  422. month. Several of you mentioned this to me also. In retrospect, it seems so
  423. obvious. Oh well.... You should also  read Alex Fedorov's article on  using
  424. LZEXPAND under Turbo Pascal in this issue.
  425.  
  426.      Ok, so for those of you that don't know, LZEXPAND.DLL is a set of file
  427. decompression  routines  supplied  with  Windows 3.1.  Because  I  want  to
  428. maintain 3.0 compatibility (a bad  habit I pick up from work, I guess) I am
  429. supplying the LZEXPAND.DLL file with this issue.
  430.  
  431.      This article isn't going to be too long  because, thanks to Microsoft,
  432. the LZEXPAND.DLL takes all the work out of file decompression. They make it
  433. as easy as opening, reading, and closing a file. 
  434.  
  435.      One feature we're going to  have in our program is two  of those nifty
  436. little progress bars that shows us how far we are through our installation.
  437. One is going  to show progress  for the entire  installation. The other  is
  438. going to handle  progress for the current file. This is where we run into a
  439. bit  of a problem.  In the past  I used the  .ZIP format and  that kept the
  440. total uncompressed  file size  internally so  I could  figure out how  many
  441. bytes the file was going to be uncompressed at run-time. I have been unable
  442. to find a way  to do that with the LZEXPAND.DLL so we're going to have that
  443. in our SETUP.INF file.
  444.  
  445.      Let me run off on a little tangent here and explain the SETUP.INF. The
  446. SETUP.INF  is going  to be  the file  that makes  our installation  program
  447. generic. The SETUP.INF  file is going to keep information  like the name of
  448. the Application  group, the default destination  directory, whether certain
  449. files will go  into sub-directories within  the application directory,  how
  450. large each  file is un-compressed, what  the compressed filename  is on the
  451. installation  diskette and so on and  so on. We're also  going to break the
  452. rules a  bit. I mentioned earlier  the trouble that Mike got  into with his
  453. article about doing Global linked lists. Well, we're going to use his 'bad'
  454. example and in  this case, I  believe I can  justify it.  First of all,  an
  455. install  program has, in this programmer's mind,  every right to hog up the
  456. CPU.  (Just  try to  run  another  program while  the  floppy drive's  busy
  457. anyway.) Second, it's going to be  playing around with Program Manager, and
  458. when that's going  on, you don't want  the user clicking around  everywhere
  459. and  screwing up the installation, so, we're going  to hog up the CPU. That
  460. means that whatever  global memory is there is ours for the taking and gosh
  461. darnit, we're going  to take what  we want! So, bear  with me on  our nasty
  462. little global linked list. (That will be in next months issue).
  463.  
  464.      Well,  that little  side-track got  a little  longer than  I expected.
  465. Anyway, back to  LZEXPAND. So, we know the uncompressed  file size from our
  466. SETUP.INF.  What's left is to get our current progress. That's pretty easy.
  467. The way it works is that when you read  from a compressed file, you have to
  468. allocate the buffer. That means that if the buffer is, say, 20k, then every
  469. time  20k of data  is decompressed, we  have to write  out the data  in the
  470. buffer to our uncompressed file on the destination disk. So, all we have to
  471. do  is  update  our  progress  bar  by 20k  and  whatever  percent  of  the
  472. installation that is. The formulas are really simple. 
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.      The   commands  we're  going  to   be  concerned  about  are:  LZInit,
  482. GetExpandedName, LZRead, and LZClose. 
  483.  
  484.      The LZInit function essentially allocates memory for the decompression
  485. algorithm  and initializes some data that the algorithm uses. The prototype
  486. is:
  487.  
  488. HFILE LZInit(HFILE SrcFile)
  489.  
  490.      SrcFile is the file  handle received from a regular  OpenFile function
  491. call.  We use this handle  only for the  LZInit, but we keep  the file open
  492. until the end of our  decompression. If the return value from LZInit is the
  493. same  as SrcFile, then that means our  file isn't compressed. If the return
  494. value  is greater  than  0,  then it  is  a  special  file handle  for  our
  495. compressed file. If the return value is less than 0, then we have an error.
  496.  
  497.      After we  do the LZInit, we  have to do  a GetExpandedName to  get the
  498. filename of our file as  it was prior to  being compressed. We'll use  this
  499. filename when we open the output file to write the  uncompressed version of
  500. the file. The prototype for the GetExpandedName is:
  501.  
  502. int GetExpandedName(LPCSTR lpszSource, LPSTR lpszBuffer);
  503.  
  504.      lpszSource  is a pointer  to the string  that has the  filename of the
  505. compressed file.  lpszBuffer will have the  name of the file  prior to it's
  506. compression. This  is the filename that  we will use when  writing the file
  507. back. The return value is TRUE if successful.
  508.  
  509.      After that, of course, is the LZRead which, again (isn't this just the
  510. most bizarre thing) is a lot like the _lread function. It's prototype:
  511.  
  512. int LZRead(HFILE hf, void FAR* lpvBuf, int cb);
  513.  
  514.      hf  is the  file handle  we returned  from the  LZInit. lpvBuf  is our
  515. buffer to hold the  data we read. cb is  the number of bytes read  from the
  516. file.  This is the  number we'll use  to write the  data out to  our output
  517. file.
  518.  
  519.      Last, but not least, the LZClose. It's simply:
  520.  
  521. void LZClose(HFILE hf);
  522.  
  523.      where hf is the file handle to close. 
  524.  
  525.      That's  about all  we need.  It's pretty  simple. There  are other  LZ
  526. commands  and maybe  at some  point I'll  have a  discussion of  the entire
  527. library of  commands. At this  point, though, it's confession  time. I must
  528. admit I have no  code to go with this article this month. Fear not, it will
  529. be in next  months issue. I'm  hoping to wrap up  the entire thing  in next
  530. months issue,  and with  several other  people helping  out in next  months
  531. issue, that just  might be possible. Anyway, until then,  mer i beaucoup et
  532. au r voir. (Just trying to be a little international there.)
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.           Programming a Drag&Drop Server for Windows 3.1 with TPW
  550.                              by Andreas Furrer
  551.  
  552.      Last issue I explained  how to implement  a client for Drag&Drop  with
  553. File Manager. This was easy because it is well documented by Microsoft. But
  554. now, what if we  want to be the server  for Drag&Drop (e.g. if you  want to
  555. program your own file manager)?
  556.  
  557.      There  is no documentation from  Microsoft for this,  so the following
  558. can change with the next version of Windows.
  559.  
  560.      The first we have to do is capturing the mouse. This is done by
  561.  
  562.   SetCapture(HWindow);
  563.  
  564. where HWindow is  the handle of  the window that  should receive the  mouse
  565. messages. Now we will receive WM_MouseMove messages every time the mouse is
  566. moved even if the mouse is not in your client window.
  567.  
  568.      If the mouse was  moved, we have to detect if the  window at the point
  569. of the cursor is registered to accept dropped files.
  570.  
  571. So we have to process WM_MOUSEMOVE messages:
  572.   1) You can get  the current position of the  cursor when the message  was
  573. sent by:
  574.  
  575.        Point.X := LoWord(GetMessagePos);
  576.        Point.Y := HiWord(GetMessagePos);
  577.  
  578.   2) Now we can get the window at this Point:
  579.  
  580.        DragWnd := WindowFromPoint(Point);
  581.  
  582.   3) To check if the DragWnd is registered to accept dropped  files we have
  583. to check if  the window has the exStyle ws_Ex_AcceptFiles.  If the Style is
  584. set, we  will set the cursor  to a cross, if  not we will  set the standard
  585. cursor: 
  586.  
  587.        if GetWindowLong(DragWnd,gwl_ExStyle) and ws_Ex_AcceptFiles =
  588.                   ws_Ex_AcceptFiles then
  589.          SetCursor(LoadCursor(0,idc_Cross))
  590.        else
  591.          SetCursor(LoadCursor(0,idc_Arrow));
  592.  
  593.      ws_Ex_AcceptFiles has a value of $00000010;
  594.  
  595.  
  596.      Now if the mouse button is released we have to release the capture and
  597. set the default cursor with
  598.  
  599.   ReleaseCapture;
  600.   SetCursor(LoadCursor(0,idc_Arrow));
  601.  
  602.      Get the DropWnd under the  cursor (see above) and if the  window under
  603. the  mouse is  a D&D  window  (see above)  we have  to post  a wm_DropFiles
  604. message to it. But in this message we have to set wParam to a handle with a
  605. Drag&Drop structure and the format of this structure is not documented.
  606.  
  607. I found out that the structure looks like this:
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.   type PDragDropStruct =^TDragDropStruct;
  618.        TDragDropStruct = record
  619.          DataOffset      : word;
  620.          DropPoint       : TPoint;
  621.          DropInNonClient : bool;
  622.          Data            : array[0..0] of char;
  623.        end;
  624.  
  625. The meanings of the parts of this structure are:
  626.   1) DataOffset :
  627.        This is the offset where the filenames begin.
  628.   2) DropPoint
  629.        This is the point where the mouse was released.
  630.        The coordinates are client coordinates.
  631.   3) DropInNonClient
  632.        This flag is set if the mouse was released in the non-client area
  633.        of the window (e.g., title bar).
  634.   4) Data
  635.        Here is the beginning of the data. All filenames are separated by a
  636.        chr(0) and the end of this list is terminated by another chr(0).
  637.  
  638. Now we have to do the following:
  639. 1) Allocate memory for the Drag&Drop structure
  640. 2) Lock the memory
  641. 3) Set the data
  642. 4) Unlock the memory
  643. 5) Use the Handle to the memory as wParam
  644.  
  645. For example we want to have 3 files in the Drag&Drop structure
  646.  
  647. const s : array[1..3,0..255] of char=('C:\autoexec.bat',
  648.                                       'C:\config.sys',
  649.                                       'C:\dos\command.com');
  650.  
  651. We have to compute the length of all the strings
  652.  
  653.   l := 0;
  654.   for i := 1 to 3 do
  655.     l := l+ StrLen(s[i]);
  656.  
  657. and have to allocate memory for the  whole structure. The memory must be of
  658. the type gmem_DDEShare.
  659.  
  660.   DataHandle := GlobalAlloc(gmem_DDEShare,sizeof(TDragDropStruct)+l);
  661.  
  662. To set the data we lock the memory
  663.  
  664.   DataPtr := GlobalLock(DataHandle);
  665.  
  666. and fill the fields of the structure:
  667.  
  668.   with PDragDropStruct(DataPtr)^ do begin
  669.     DataOffset:=Data-DataPtr;
  670.     DropInNonClient:=(
  671.       DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient);
  672.     ScreenToClient(DropWnd,Point);
  673.     DropPoint   :=Point;
  674.   end;
  675.  
  676. where
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683.  
  684.  
  685.   DefWindowProc(DropWnd,wm_NCHitTest,0,longint(Point))<>htClient
  686.  
  687. will test if the cursor is not in the client area of the window.
  688.  
  689. The last data  we have to set are the filenames.  We do this with a pointer
  690. p. Initially we set p to the field data of the structure.
  691.  
  692.   p:=PDragDropStruct(DataPtr)^.Data;
  693.  
  694. Now  we copy each string to  p and set p at the  end of the string plus one
  695. (StrLen will not compute the chr(0)).
  696.  
  697.   for i:=1 to 3 do begin
  698.     StrCopy(p,s[i]);
  699.     p:=p+StrLen(s[i])+1;
  700.   end;
  701.  
  702. If we have copied all strings we have to terminate the list with a chr(0)
  703.  
  704.       p^:=#0;
  705.  
  706. At the end we have to unlock the memory with
  707.  
  708.   GlobalUnlock(DataHandle);
  709.  
  710. and post the wm_DropFiles message to the DropWnd:
  711.  
  712.   PostMessage(DropWnd,wm_DropFiles,DataHandle,0);
  713.  
  714.  
  715. The file D&DSER.PAS is a simple Drag&Drop server. Just press the left mouse
  716. button in the  client area and move it to the  window of a Drag&Drop client
  717. (e.g D&DCLI,  see below) and release the button. While moving the mouse the
  718. cursor  will  change to  a  cross, if  the  window under  the  cursor  is a
  719. Drag&Drop client.
  720.  
  721. D&DCLI.PAS is an implementation of a simple Drag&Drop client. It
  722. will print out the dropped files in a WinCrt window. It is nearly
  723. the same code as the trash can in the last issue.
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749.  
  750.  
  751.  
  752.  
  753.                            C++ Beginner's Column
  754.                               By Mike Wallace
  755.  
  756.      I promised in the last issue I would start a beginner's column on C++,
  757. and I didn't want to lie to you.   I have been reading some books lately on
  758. C++ because I don't  know anything about it.  My plan is to learn enough to
  759. write a "Hello world" program in  C++ for Windows (for starters), gradually
  760. move on  to more advanced programs and  try to share with  you everything I
  761. learn along the way.  Hope this suits  you because it's the best way I  can
  762. think of to approach  this.  If you have  any suggestions/complaints please
  763. don't hesitate to  let me know.  We  have a ways to go before  we can start
  764. coding so be patient  for now.  This stuff can be a little bizarre, so I'll
  765. try to explain it as best I can.
  766.  
  767.      I've  been programming  for  about 10  years  and have  become  pretty
  768. comfortable with Pascal, C, COBOL, FORTRAN, BASIC and the rest  of the most
  769. popular languages, and I've noticed they have a lot of similarities when it
  770. comes to program structure, data abstraction, etc.  If you already know how
  771. to program and now want to learn C++, forget everything you've learned.  If
  772. you've never programmed before, then you're a step ahead of the rest of us.
  773. C++  is  unlike  anything  I've  seen  -  it's  a  whole  new  approach  to
  774. programming.  The best book I've seen on the subject is Borland's excellent
  775. "Object-Oriented Programming Guide"  that came  with Turbo Pascal  5.5.   I
  776. hope this guide  is still packaged with the latest version  of TP - chapter
  777. one is a great read and helped clear up some of the more mystifying aspects
  778. of OOP for me.
  779.  
  780.      OOP is something  like the sound of  one hand clapping -  if you don't
  781. think about  it too  hard and ignore  what you  already know, it's  easy to
  782. imagine.   Consider an apple.  In  abstract terms, it's just an object, and
  783. like  any object, it is described by  its physical properties (an apple has
  784. to have  weight, for example).   Think of these properties  as functions of
  785. the object.  It is important to keep in mind that we're not talking about a
  786. specific apple, but any apple that  ever existed.  The function describing,
  787. say, the weight, stays the same  - only the values going into the  function
  788. differ.   So,  the nature  of an  apple is  intertwined with  the functions
  789. describing it - they  can be encapsulated  to form an object.   This is  an
  790. important concept in  OOP.   "Encapsulation" refers to  combining a  record
  791. with the code that manipulates it to form an object.
  792.  
  793.      Let's move on  to an  example closer related  to programming:  drawing
  794. graphics.   If we wanted  to write  a program for  drawing lines,  circles,
  795. etc., we could  start with defining  an object called  Point, which has  as
  796. three fields:  x coordinate (integer),  y coordinate  (integer) and  on/off
  797. (boolean).  The first  two fields give the location of Point  and the third
  798. says if it  is displayed (on)  or not (off).   If we  wanted to extend  our
  799. program to  include circles, we could  a define a new  object called Circle
  800. that  had the same  fields as Point  plus a field  for the radius  (x and y
  801. would be the center of the circle).  To save time,  we could declare Circle
  802. as an object of type Point with another field for the radius.  Circle  is a
  803. descendent of Point  because Circle  has inherited the properties of Point.
  804. This  is  another concept  important to  understanding OOP.   "Inheritance"
  805. refers  to  defining  an object  and  using  it  as  a basis  for  defining
  806. descendent objects,  with  each descendent  inheriting  access to  all  its
  807. ancestors' code and data.
  808.  
  809.      Finally, let's say you want to write a routine for drawing a Point and
  810. another  for a  Circle.   Although  the two  routines would  be implemented
  811. differently, they're both doing  nothing more than  showing an object.   In
  812. C++, it is possible to declare two routines with the same name, and here we
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821. could do it with  the routine "Show."   The difference  between the two  is
  822. that one would  be tied to the object Point and  the other would be tied to
  823. Circle.   This is called  "polymorphism", and  is giving  an action  (here,
  824. showing  an arbitrary object) a single name  (e.g., "Show") that is used by
  825. different  objects in  the hierarchy  , with  each object  implementing the
  826. action in a manner suited to that object.
  827.  
  828.      Well, that's  all for  this month.   I've stayed  away from  code here
  829. because it's  too early to start with it.   C++ is too different than, say,
  830. C, to jump into code,  I think [that's his  way of saying he hasn't  gotten
  831. that  far either  - Pete].   I hope  this makes  sense so  far.   If you're
  832. thinking, "I never did this  with Pascal", then you're starting to  get the
  833. point.  It's not just a computer  language - it's a way of programming that
  834. reflects  the way we think, much more so  than C, for example.  Don't think
  835. too  hard about it and it should make more sense than what you already know
  836. about  programming.  If none  of this makes sense, drop  me a line and I'll
  837. see what I can do.
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871.  
  872.  
  873.  
  874.  
  875.  
  876.  
  877.  
  878.  
  879.  
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887.  
  888.  
  889.                              Beginner's Column
  890.                        By Mike Wallace and Pete Davis
  891.  
  892.      Last month  we  covered the  .DEF  file and  started  on resources  by
  893. describing  dialog boxes.    This  month  we'll  finish  the  .RC  file  by
  894. explaining  menus,  and then  begin on  the C  code  for our  "Hello World"
  895. program.
  896.      A Windows  program  isn't a  Windows  program without  a menu.    It's
  897. probably the  first thing you look  for when you're running  a Windows app.
  898. If you've wondered  how to create  one yourself, you've  come to the  right
  899. place.  You describe your menu in the .RC file using the following format:
  900.  
  901. <menu-name>    MENU
  902. BEGIN
  903.        POPUP "<popup menu>",
  904.        BEGIN
  905.                 MENUITEM "<menu item 1>",  <variable>[, options]
  906.         END
  907.         MENUITEM "<menu bar item>",  <variable>[, options]
  908. END
  909.  
  910.      You can have as many  menu items as you want (or will fit  on the menu
  911. bar),  and even have popup  menus inside other popup menus  if you want.  I
  912. kept  the  format  simple so  it  wouldn't  be  overwhelming.   Here's  the
  913. explanation for the codes:  anything inside "<>" is required,  and anything
  914. inside "[]" is optional.   You have to give your menu a  name.  You can put
  915. the  POPUPs  and MENUITEMs  in any  order you  want,  but don't  forget the
  916. BEGIN/END statements that go right after the POPUP statement.  Any MENUITEM
  917. inside the BEGIN/END appears under that  popup menu.  MENUITEMs that appear
  918. outside  the BEGIN/END of  a popup menu  appear on  the menu bar,  but they
  919. won't have a  menu under them.   For each menu item,  you should give it  a
  920. variable  (defined in a .H  file included in the .RC  file) that you'll use
  921. when your program checks for which menu item was selected by the user.  For
  922. any menu item, you can include the following options:
  923.  
  924. CHECKED   - The menu item has a check next to it
  925.  
  926. GRAYED    - The menu item text is grayed and inactive
  927.  
  928. HELP      - The item has a vertical line to the left.  You can also include
  929. a "\a" at
  930.              the beginning of the text if you want to item to appear on the
  931. menu 
  932.              bar's far right side.
  933.  
  934. INACTIVE  - The menu item name is displayed but cannot be activated.
  935.  
  936. MENUBARBREAK   - When used on a menu, the item is placed on a new line.  On
  937.              popups, the item is placed in a new column.   A line separates
  938. this 
  939.              item from the previous one.
  940.  
  941. MENUBREAK - Same as MENUBARBREAK, except for popup menus : no dividing 
  942.             line.
  943.  
  944.  
  945. A couple of more hints: If you want to make a character in a menu item name
  946. underscored (to allow for ALT-whatever), add an "&" before the character in
  947. the  name.   Also, you  can  add the  line  "MENUITEM SEPARATOR"  to add  a
  948. horizontal line between popup menu bar items.
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956.  
  957.      We're now ready to write the .RC file for "Hello World".  Here it is:
  958.  
  959. /* hello.rc */
  960. #include <windows.h>
  961. #include <hello.h>
  962. amenu          MENU
  963. BEGIN
  964.           POPUP "&Text"
  965.           BEGIN
  966.                  MENUITEM "&Write",             IDM_WRITE
  967.           END
  968.           MENUITEM "&Quit",                      IDM_QUIT
  969.           MENUITEM "\a&Help",                  IDM_HELP, INACTIVE
  970. END
  971.  
  972.  
  973. Here's "hello.h":
  974. /* hello.h */
  975. /* define menu bar items */
  976. #define  IDM_WRITE   1
  977. #define  IDM_QUIT       5
  978. #define  IDM_HELP     10
  979.  
  980. /* function prototypes */
  981. Long FAR PASCAL MainWndProc (HWND, unsigned, WORD, LONG);
  982.  
  983.  
  984. The "windows.h" file  is included  with the Microsoft  Windows SDK, and  is
  985. required for  any Windows program.  The above two  files will change as our
  986. program grows, but it  should suit our needs  for now.  We'll describe  any
  987. changes we make to any file we've already created.  Here's Pete to tell you
  988. about the C code.
  989.  
  990.      Ok, so I  guess it's my turn  to talk about the coding  of this thing.
  991. This is a real bread and water Windows program, but it's got all the basics
  992. that you're going to find in all Windows programs, and that's what you need
  993. at this point.
  994.  
  995.      In a normal C program you have your main() function which is the first
  996. function to get called in  a C program. In Windows, instead of  main(), you
  997. have WinMain(). (Real original, eh?) The WinMain function is where you take
  998. care of all the initialization. The main things you want to do  is register
  999. your window class. Now, this makes it sound like object  oriented stuff all
  1000. of  a sudden, and I  suppose it is, but all  you're really doing is telling
  1001. Windows  a few things  about your  window. (You have  to keep  in mind that
  1002. Windows is essentially  an object oriented  operating system. Although  our
  1003. programming  isn't  object oriented,  per se,  we  are emulating  an object
  1004. oriented programming environment.)
  1005.  
  1006.      Instead  of showing the Window Class structure here, I'll just discuss
  1007. it. I've labeled  the members of the  structure in the  code, so you'll  be
  1008. able to relate what I write here to the structure members in the code.
  1009.  
  1010.      The  hCursor is basically done by a load cursor. Most applications jut
  1011. choose the generic IDC_ARROW cursor. 
  1012.  
  1013.      The hIcon is where you  really get to have fun. This is  the icon that
  1014. is shown when your application is minimized.
  1015.  
  1016.      The hInstance is simply the instance for this application.
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.      The  hbrBackground  is the  class  of the  background  brush, meaning,
  1026. basically, the color or pattern used in your window. This is usually white.
  1027.  
  1028.      lpszMenuName  is a pointer to  a null-terminated string  which has the
  1029. resource name of your menu.
  1030.  
  1031.      style has several  options, most of  which are a  little more than  we
  1032. need  to  go  into  at  this  point. My  suggestion  is  use  CD_HREDRAW  |
  1033. CS_VREDRAW. This basically means to redraw the window if the  horizontal or
  1034. vertical window sizes change.
  1035.  
  1036.      The cbClsExtra and cbWndExtra are a bit more complex than we should be
  1037. going into at this point, so like so many other things, we'll hold them off
  1038. for another day. Just keep them NULL for now.
  1039.  
  1040.      After  registering  your  window class,  you  have  to initialize  the
  1041. instance. What  this means is that  in a Windows  program, you can  run the
  1042. same program several times at once  (not all Windows applications, but ones
  1043. that are written to  allow it.) Each copy of the program  running is called
  1044. an instance. The  reason you have  to initialize the  instance is  because,
  1045. each one  of those versions is going  to share the same  copy of code. (You
  1046. don't  have to share the code,  but it's bad practice not  to, so we're not
  1047. going to  say any more about  that no no.) Also,  because handling multiple
  1048. instances  of an application  can be a  bit tricky for  the beginner, we're
  1049. going to set up our code to reject attempts to run multiple instances.
  1050.  
  1051.      At the  end of  all of  this you set  up your  message queue.  This is
  1052. fairly simple to do and fairly generic. Most programs do this the same way.
  1053. There are  reasons for changing it,  sometimes, but we're not  going to get
  1054. into that either, at this point.
  1055.  
  1056.      When  you  initialize the  instance, you  also  tell Windows  what the
  1057. procedure  is that is  going to handle  the messages for  your main Window.
  1058. Here's  where the multi-tasking of  Windows takes place.  See, what Windows
  1059. does here is  that every  time something  happens in  your window,  Windows
  1060. calls this procedure and  passes along a message describing  what happened.
  1061. This  could be something  like a mouse  movement, a menu  selection, etc...
  1062. See, you never explicitly call the procedure that handles your main window,
  1063. what you do is tell Windows where the procedure is and it will know when to
  1064. call it.
  1065.  
  1066.      The  best  way to  handle your  main window  procedure  is to  setup a
  1067. switch/case  structure where each case  of your switch  statement handles a
  1068. different message.
  1069.  
  1070. example:
  1071.      /* Switch structure for message */
  1072.      switch(message) {
  1073.  
  1074.           case WM_CREATE:
  1075.                ....
  1076.                ....
  1077.                ....
  1078.                break;
  1079.  
  1080.           case WM_Another_Message:
  1081.                ....
  1082.                ....
  1083.                ....
  1084.                break;
  1085.  
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091.  
  1092.  
  1093.           etc...
  1094.  
  1095.  
  1096.      Windows messages  generally start  with  WM_. The  WM meaning  Windows
  1097. Message, oddly enough. After each case would be the code to handle whatever
  1098. that  action requires. For example,  the WM_CREATE message  is called right
  1099. before a window (or dialog box for that matter) is created,  so it's a good
  1100. candidate for initializing variables and  that kind of stuff that you  want
  1101. to do every time your window is created.
  1102.  
  1103.      A little  side note here: There  are two types of  dialog boxes, Modal
  1104. and Modeless (Yes, one is al and  the other is el). The Modal dialog  boxes
  1105. are very similar to windows in that they are given a procedure that handles
  1106. messages that  are passed to them.  (We'll discuss Modal dialog  boxes at a
  1107. later time also. One thing at a time.)
  1108.  
  1109.      I digress... Anyway,  the break  after each case  statement is just  a
  1110. quick way out of the switch/case  structure. It basically means that you're
  1111. done handling that particular message.
  1112.  
  1113.      Ok, so what are we learning here? Well, Windows programs aren't linear
  1114. in the sense that you run  a procedure which may run another procedure  and
  1115. so on. Windows is  event driven which means  that it reacts to  events that
  1116. take  place. When you  move the mouse,  that's an event,  so your procedure
  1117. gets called. When  you hit a  mouse button, that's  another event, but  the
  1118. same  procedure  gets called.  This  procedure  should respond  differently
  1119. depending on the message it receives.
  1120.  
  1121.      That should  be all you need.  I've included the Hello  World code and
  1122. I've  put as much  inline documentation as  will make sense.  I suggest you
  1123. give it a whirl, and like  any of our articles, if you have  questions, let
  1124. us  know. If we've inadvertently  skipped something, send  us a message and
  1125. we'll amend our goofs.
  1126.  
  1127.      Next  month  you'll have  Dave Campbell  coming  to you  directly from
  1128. Arizona.  He's a hell of a  programmer, so he'll have lots  to show you and
  1129. hopefully, give you a  little different perspective  than Mike and I,  that
  1130. way if you don't understand  what we're saying, maybe you'll  understand it
  1131. when  Dave says it. So, so  long and thanks for  reading. Hope you'll treat
  1132. Dave as well as you've treated us.
  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.  
  1161.                            Using LZExpand Library
  1162.                                 Alex Fedorov
  1163.  
  1164.      LZEXPAND.DLL is  supplied with Windows to allow  programmers to unpack
  1165. files,  previously packed with COMPRESS.EXE  utility. Here we  will look at
  1166. the  main functions  of this  library. Note,  that you  can  use EXPAND.EXE
  1167. utility to unpack files  instead of using functions from  LZEXPAND library.
  1168. Mostly,  this library is used  for installation programs.  (This article is
  1169. intended for TPW programmers).
  1170.  
  1171.  
  1172.      Data compression
  1173.  
  1174.      Data compression  is a task to  lower the file size  by converting the
  1175. repeated data with  some other sequences. In text  files such repeated data
  1176. can  be  spaces, mostly  used  chars or  even  the whole  strings.  Due the
  1177. compression  such repeated  sequences  are replaced  with the  shorter one.
  1178. Several data compression  algorithms exist. One of the most  popular is the
  1179. Huffman algorithm, based on  the frequencies of chars repetitions  in text.
  1180. Another  one is a run-length  encoding algorithm, where  the repeated chars
  1181. are replaced by pairs:  the first nibble contains the  count of repetitions
  1182. and the second one the char code itself. Also, the  Lempel-Ziv algorithm is
  1183. widely used and the COMPRESS.EXE utility is based on it.
  1184.  
  1185.  
  1186.      Data expansion
  1187.  
  1188.      Applications  use  functions   from  LZEXPAND.DLL  to   unpack  files,
  1189. compressed  with COMPRESS.EXE utility. Here  is the actions  flow to expand
  1190. one or more files.
  1191.  
  1192.      Unpacking one file:
  1193.  
  1194.           ~ Open a compressed file with LZOpenFile. Also,
  1195.           the file can be opened with OpenFile or LZInit
  1196.           functions.
  1197.  
  1198.           ~ Open a destination file using LZOpenFile or
  1199.           OpenFile functions.
  1200.           
  1201.           ~  Use LZCopy to copy data from source to
  1202.           destination using file handles from LZOpenFile
  1203.           or LZInit.
  1204.  
  1205.           ~ Close both files with LZClose.
  1206.  
  1207.  
  1208.      Unpacking several files:
  1209.  
  1210.      To unpack several files you perform the following actions:
  1211.  
  1212.           ~ Open source file with LZOpenFile or with
  1213.           OpenFile and LZInit functions.
  1214.  
  1215.           ~ Open destination file using LZOpenFile or
  1216.           OpenFile functions.
  1217.           
  1218.           ~ Allocate memory for copy operations with
  1219.           LZStart function.
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228.  
  1229.           ~ Use CopyLZFile to copy source file to destination
  1230.           file.
  1231.  
  1232.           ~ Free allocated memory with LZDone function.
  1233.  
  1234.           ~ Close all files with LZClose function.
  1235.  
  1236.  
  1237.      Reading data from compressed files
  1238.  
  1239.      Instead  of unpacking the whole  file, an application  can unpack file
  1240. piece-by-piece, using LZSeek and LZRead  functions. These functions can  be
  1241. useful when we unpack the huge files.
  1242.  
  1243.      To  use the functions from LZEXPAND.DLL you need the unit LZEXPAND.TPU
  1244. which is supplied with Turbo Pascal for Windows 1.5 or  with Borland Pascal
  1245. for Windows.
  1246.  
  1247.      Here is the example of how to use LZEXPAND.DLL functions
  1248.  
  1249.      {       LZDEMO - The demo of LZEXPAND.DLL functions usage    }
  1250.  
  1251.      uses LZExpand,WinTypes,WinProcs;
  1252.  
  1253.      Const
  1254.       szSrc      = 'MYFILE.PAK';  {Packed file name}
  1255.      Var
  1256.       szFileName : Array[0..127] of Char;
  1257.       ofStrSrc   : TOfStruct;
  1258.       ofStrDest  : TOfStruct;
  1259.       hSrcFile   : THandle;
  1260.       hDstFile   : THandle;
  1261.       Total      : LongInt;
  1262.  
  1263.      Begin
  1264.      {Open compressed file}
  1265.       hSrcFile := LZOpenFile(szSrc,OfStrSrc,of_Read);
  1266.  
  1267.      {Get the original name of file}
  1268.       GetExpandedName(szSrc,szFileName);
  1269.  
  1270.      {Create the file with szFileName}
  1271.       hDstFile := LZOpenFile(szFileName,ofStrDest,of_Create);
  1272.      
  1273.      {Unpack file while copying it}
  1274.       Total := LZCopy(hSrcFile,hDstFile);
  1275.      {LZCopy returns the number of bytes written}
  1276.      
  1277.      {Close both files}
  1278.       LZClose(hSrcFile);
  1279.       LZClose(hDstFile);
  1280.      
  1281.      End.
  1282.      
  1283.      Note: In the  example above,  we used the  LZOpenFile function,  which
  1284. automatically  calls LZInit  function, which performs  some initialization.
  1285. The  result code of this function  can tell us whether or  not the file was
  1286. compressed with  COMPRESS.EXE. To do this,  you need to open  the file with
  1287. the OpenFile function (from  KERNEL) and then call LZInit  directly, giving
  1288. it the  file handle from OpenFile.  LZInit returns the file  handle. If the
  1289.  
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295.  
  1296.  
  1297. value  for this  handle  is not  the same  as  the argument,  the file  was
  1298. compressed and we can unpack it. Here is the example:
  1299.  
  1300.           hSrcFile  := OpenFile(szSrc,ofStrSrc,of_Read);
  1301.           hCompFile := LZInit(hSrcFile);
  1302.           If hCompFile <> hSrcFile then
  1303.           
  1304.            {File was compressed with COMPRESS.EXE}
  1305.           
  1306.           Else If hCompFile = hSrcFile then
  1307.           
  1308.            {File was not compressed}
  1309.           
  1310.           Else
  1311.           
  1312.            {Some error encountered; must check LZError_XXX codes}
  1313.      
  1314.  
  1315.      Also note, the GetExpandedName function returns the original name only
  1316. when the file was compressed by COMPRES.EXE with /r option.
  1317.  
  1318.  
  1319.                                         Alex is a freelance programmer
  1320.                                    and the editor for "Computer Press"
  1321.                                    magazine. Alex lives in Moscow, Russia.
  1322.  
  1323.  
  1324.  
  1325.  
  1326.  
  1327.  
  1328.  
  1329.  
  1330.  
  1331.  
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337.  
  1338.  
  1339.  
  1340.  
  1341.  
  1342.  
  1343.  
  1344.  
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350.  
  1351.  
  1352.  
  1353.  
  1354.  
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360.  
  1361.  
  1362.  
  1363.  
  1364.  
  1365.                    Implementing A Linked List - Revisited
  1366.                               By Mike Wallace
  1367.  
  1368.      I didn't expect this to happen.  I have caused a small uproar  by last
  1369. month's  article "Implementing  a  Linked  List  Using  the  Global  Heap."
  1370. Several people had differing  opinions on the best way to do  this, and two
  1371. of them have promised articles showing two different ways to do this, which
  1372. we hope to  publish soon.   Part  of it was  my fault:  at the  end of  the
  1373. article, I intended to mention that  it was very easy to alter the  program
  1374. to use the local heap (instead of the global heap) - all you need to do  is
  1375. change the  Global commands  (e.g., GlobalAlloc)  to Local  commands (e.g.,
  1376. LocalAlloc) and the FAR pointers  to NEAR.  I arbitrarily chose  the global
  1377. heap for the program, and several people pointed out (and for good reasons)
  1378. that it's always  better to use the local heap if  at all possible.  Hope I
  1379. haven't confused anybody.  In case anyone is interested in using the method
  1380. I  proposed last  month, then  I have  bad news:  there was  a bug  in last
  1381. month's  code  involving freeing  the memory  blocks.   I  have  included a
  1382. revised version of the program with this issue.
  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.  
  1433.            An Introductory Look at DLLs and The Use of Make Files
  1434.                                By Rod Haxton
  1435.  
  1436.      Whenever  one begins learning Windows he/she always seems to hear talk
  1437. about  DLLs (Dynamic  Link  Libraries). Learning  Windows  is a  very  long
  1438. process. Like anything in  the programming world there's lots to learn, and
  1439. not that much time to learn it in. Thus, many beginning Windows programmers
  1440. bypass Petzold's chapter  on DLLs until a later time.  This article may not
  1441. be of great help in understanding DLLs for Windows programmers just getting
  1442. their feet wet.  But, if you  have been writing code  for Windows and  feel
  1443. competent, and have  not yet tackled DLLs, this code may  give you a little
  1444. understanding of  how DLLs work.  Also, if  you have some  understanding of
  1445. 80x86 assembly  language underneath-the-hood workings, this  will be useful
  1446. in understanding  how DLLs work in Windows. A bonus to this article is that
  1447. it  demonstrates how a  large application or  for that matter  any size app
  1448. should be laid out. The programming example accompanying this article shows
  1449. how source  code should be broken  up into seperate modules.  The demo also
  1450. makes use of Make files and  shows how they can help speed  the development
  1451. of projects, and also demonstrates how to break code up  into multiple code
  1452. segments. So often in Windows books the programs demonstrated are  built as
  1453. one application with one code  and data segment. This isn't really  what we
  1454. as developers need.
  1455.  
  1456.      In learning  DLLs there are  a few areas  that one should  focus on to
  1457. gain 'THE KNOWLEDGE'; this conjures up images of some  monks sitting around
  1458. reading thick books. Cutting and pasting code samples from on-line articles
  1459. or  typing them  in  will get  you something  working  but, if  you do  not
  1460. understand what is really  going on in Windows you will  be held hostage to
  1461. some unknown  events and also  your own  imagination, or the  lack thereof.
  1462. Thus, there are some things to focus on when learning about DLLs. They are:
  1463.  
  1464.           * DS != SS
  1465.           * Windows & DLLs entry/exit code
  1466.           * Exports & Imports
  1467.           * LibEntry & LibMain
  1468.           * WEP function
  1469.  
  1470.  
  1471.                DS != SS
  1472.                --------
  1473.  
  1474.      In  a regular Windows application  program the Stack  and Data Segment
  1475. are the same. If  you set up your  program to have multiple code  segments,
  1476. the Code segments  can change during Windows function calls, far calls, and
  1477. return  from far  calls.  The changing  of the  code  segments takes  place
  1478. because most code segments are flagged as  moveable and discardable. If the
  1479. code segment has been flagged as a fixed segment then the code segment will
  1480. stay put. But,  in understanding DLLs you need to concentrate on DS and SS.
  1481. As I mentioned, in regular  Windows apps DS == SS. Standard  C routines can
  1482. be  used  in non-DLL  apps. They  do  not assume  DS ==  SS,  and generally
  1483. reference pointer variables  relative to  DS.  Remember, when functions are
  1484. called  a stack frame  is created,  which holds  the passed  variables, the
  1485. returning CS:IP  address, and space is created  to hold any local variables
  1486. to the routine. Thus,  references to your passed-in near  pointer variables
  1487. are seen by the stack, because C does not make a distinction  between stack
  1488. segment-based variables and data segment-based variables.
  1489.  
  1490.      DLLs on  the other hand have their own data  segments.  This is one of
  1491. the  reasons  that makes  them appealing  to  those developers  writing big
  1492. applications. When a routine to a DLL is called, the calling function's, if
  1493.  
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501. its not in  the DLL, DS and CS  are placed on the stack.   The DLL uses the
  1502. stack of the calling  function. The DLL's DS and CS  are given scope. Thus,
  1503. the calling app (if passing any variables to the DLL) must pass them as far
  1504. pointers  in  order  for the  variables  to have  scope.  Also,  standard C
  1505. routines  cannot be  used,  because  DS !=  SS,  and the  standard  library
  1506. routines  reference the  variables from  DS. If  you do  call a  standard C
  1507. routine or another  DLL's function  with near pointers,  when the  function
  1508. returns  the variables will  be unchanged. Ways to  get around this problem
  1509. are to  declare your local variables in your DLL  as static or pass them as
  1510. far pointers.
  1511.  
  1512.  
  1513.           APP                                 DLL
  1514.      ---------------                    ---------------
  1515.      |             |                    |             |
  1516.      |     CS      |                    |      CS     |
  1517.      ---------------                    ---------------
  1518.            DS                                  DS
  1519.  
  1520.                       SHARED
  1521.       SS------------------------------------------------SS
  1522.  
  1523.  
  1524.      A detailed  discussion of DS !=  SS can be found  in Charles Petzold's
  1525. 'Programming Windows', and  Mike Klein's  'DLLs And  Memory Management'.  A
  1526. step to really comprehending DLLs is to understand DS != SS.
  1527.  
  1528.  
  1529.  
  1530.                Windows & DLLs Entry/Exit Code
  1531.                ------------------------------
  1532.  
  1533.      Another  aspect of  understanding DLLs  is to  understand how  Windows
  1534. loads application functions and DLLs. Again, here a little understanding of
  1535. how a MS-DOS C compiler handles function  loading and assembly language can
  1536. be helpful. Now,  if you  do not  happen to  be a  low-level system  person
  1537. and/or  have  no desire  to be,  you  may be  asking yourself  why  this is
  1538. important. Well, this really isn't important if you don't mind writing code
  1539. and not understanding what's really taking place. But remember, you will be
  1540. at a real disadvantage when a bug crops up and you go into your debugger to
  1541. find out what is wrong and you have no idea of what you're looking for. 
  1542.  
  1543.      Under DOS the compiler sets up segments as the following:
  1544.  
  1545.           mov  ax, _DATA
  1546.           mov  ds, ax
  1547.  
  1548. And, function entry/exit code saves registers and makes space on the  stack
  1549. for passed variables and local variables,
  1550.  
  1551.           push bp
  1552.           mov  bp, sp
  1553.           sub  sp, <number of bytes needed>
  1554.           .
  1555.           .
  1556.           .
  1557.           mov  sp, bp
  1558.           pop  bp
  1559.           ret       ;This  can   be  a  near   or  far  return.   Also,  if
  1560.                     ;the    function   was    called   with    the   PASCAL
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.                     ;directive    the    number   of    parameters   passed
  1570.                     ;to   the   stack   needs    to   be   added   to   the
  1571.                     ;return.
  1572.  
  1573.      Windows functions  are all set up  to be far calls.  This provides the
  1574. built-in ability  to swap and discard  code segments in and  out of memory.
  1575. The  entry exit  code for  the non-exported  far functions  looks like  the
  1576. following:
  1577.  
  1578.           push ds -----------------------| same as:
  1579.           pop  ax -----------------------|   mov ax, ds
  1580.           nop
  1581.           inc  bp
  1582.           push bp
  1583.           mov  bp, sp
  1584.           push ds               ----------------------   save   ds   again?
  1585.           mov  ds, ax ---------------------- here again ?
  1586.           sub  sp, <number of bytes>
  1587.           .
  1588.           .
  1589.           .
  1590.           dec  bp
  1591.           dec  bp
  1592.           mov  sp, bp
  1593.           pop  ds
  1594.           pop  bp
  1595.           dec  bp
  1596.           ret  <number of passed parameters>
  1597.  
  1598. Looking  at the  Windows entry/exit  code above  we see  that it  is really
  1599. similar to the DOS version.  It just does extra  work. The reason being  is
  1600. that Windows modifies the entry code when your exported function is called.
  1601. Windows replaces the first two instructions  ('push ds' and 'pop ax')  with
  1602. NOPs.  If you noticed the code above where I have stated 'here again?', the
  1603. instruction is 'mov  ds, ax'. But, now ax contains  nothing. Before it held
  1604. the value of ds. What  happens is that during LINK Windows  places into EXE
  1605. file a  table that  lists  the references  to your  far  calls and  Windows
  1606. functions. Thus, when Windows runs and calls your far function the register
  1607. ax has already been loaded with the segment location. Exported functions DS
  1608. are  handled during the registering  of window class  structures created or
  1609. with  the MakeProcInstance  for call-back  functions. The  MakeProcInstance
  1610. tells Windows to  do some 'thunking'.  Thunking handles the  setting up  of
  1611. code  and data segments. Each instance of  a Windows function will have its
  1612. own DS, but all instances will refer to one CS.
  1613.  
  1614. Far calls and Window functions entry code:
  1615.  
  1616.           nop
  1617.           nop
  1618.           nop
  1619.           inc  bp
  1620.           push bp
  1621.           mov  bp, sp
  1622.           push ds     
  1623.  
  1624.           mov  ds,    ax---------------->'Instance   Thunk'    located   in
  1625.                               fixed memory position.
  1626.                               mov  ax, <DS for instance>
  1627.  
  1628.           sub  sp, <number of bytes>
  1629.  
  1630.  
  1631.  
  1632.  
  1633.  
  1634.  
  1635.  
  1636.  
  1637.  
  1638.  
  1639.      DLLs entry code  is as simple as the  DOS version.  Because  DLLs have
  1640. their own DS and there can only be one instance of a DLL there's no need to
  1641. determine the DLL's DS at run time  or create an instance thunk. The DS  is
  1642. already known so it can be set.
  1643.  
  1644.           mov  ax, <DLL DS>
  1645.           inc  bp
  1646.           push bp
  1647.           mov  bp, sp
  1648.           push ds     
  1649.           mov  ds, ax
  1650.  
  1651.  
  1652.  
  1653.                Exports and Imports
  1654.                -------------------
  1655.  
  1656.      You should already know  about Exported functions if you  have written
  1657. Windows  code. But,  here's a  brief tutorial.  All Windows  functions that
  1658. receive  messages  must be  exported. The  export  tells the  compiler that
  1659. references to the exported functions will be resolved at run-time. 
  1660.  
  1661.      Imported functions are also  used to resolve function  references. The
  1662. IMPORTS statement  in a DEF  file tells the  Linker that the  functions are
  1663. defined elsewhere  and  relocation  info  will  be  resolved  at  run-time.
  1664. Imported functions can be handled in two ways. One is to list them in a DEF
  1665. file under  the IMPORTS statement. The other is to  place them in an import
  1666. library and link them into your code. The latter is the approach that I use
  1667. because it reduces the  headache of updating DEF files  during development.
  1668. Also, listing  the  import  functions  in  DEF  files  requires  a  lot  of
  1669. memorization when you  start dealing with multiple DLLs. Later, I will show
  1670. how I handle multiple DLLs and imports.
  1671.  
  1672.  
  1673.                LibEntry and LibMain
  1674.                --------------------
  1675.  
  1676.      Every Windows executable  modules needs an  entry point. When  writing
  1677. apps  for Windows this  code is  hidden from  the developer.  However, when
  1678. writing  DLLs the  source  to the  library  entry routine,  LibEntry(),  is
  1679. provided to you by the  SDK. Usually, you do not have to touch  this code -
  1680. the SDK  provides 'libentry' for you  to link into your  DLL. 'libentry' is
  1681. the object file for LibEntry(). If you are creating a resource-only DLL you
  1682. do have to modify LibEntry() a little bit. LibEntry() also calls a function
  1683. LibMain() that you must supply.
  1684.  
  1685.      When  the application program starts up all  DLLs tied to that app get
  1686. called. The initial  call for the DLL is the only  guaranteed time that the
  1687. library  will be  called. LibEntry()  initializes the  DLL's local  heap by
  1688. making a call to LocalInit(). Under Windows 3.0, due to  Real Mode support,
  1689. LocalInit() locks  the DLL's data segment; the  locking of the data segment
  1690. does not take place under Windows 3.1. On exit from LocalInit(), LibEntry()
  1691. calls LibMain(). If  the data  segment was locked  your LibMain()  function
  1692. must unlock it. 
  1693.  
  1694.      LibEntry() and LibMain() initialize your DLL and are only called once.
  1695. You will  see  in my  Make  and DEF  files  that I  place LibMain()  in  an
  1696. initialization code  segment. This way the segment will be flagged after it
  1697.  
  1698.  
  1699.  
  1700.  
  1701.  
  1702.  
  1703.  
  1704.  
  1705. is  used to be discarded and when memory becomes an issue it will be dumped
  1706. by Windows.
  1707.  
  1708.  
  1709.  
  1710.                WEP Function
  1711.                --------------
  1712.  
  1713.      The WEP() routine  is another function  that your DLL  is required  to
  1714. have. The SDK says that this function gets called once, when a DLL is about
  1715. to be unloaded. This does not seem to be the case under Windows 3.0. When I
  1716. have watched  it under Codeview, I have never  seen it called. WEP() has an
  1717. input parameter that  identifies whether the  exit is  being caused by  the
  1718. system or  the application. Whatever  the reason for the  exit WEP() should
  1719. return 1. You will notice in my examples  that I do not do any testing  for
  1720. the type of exit:  I just return  1. WEP()'s name is  made resident in  the
  1721. DLL's name table, thus it is always in memory and never gets swapped out.
  1722.  
  1723.  
  1724.                Programming Example
  1725.                -------------------
  1726.  
  1727.      Now that the  basics of DLLs have been discussed.  I'll focus the rest
  1728. of  this article on  a sample DLL  app that I've  written that demonstrates
  1729. DLLs,  the use  of Near/Far  function calls,  Near/Far pointers,  calling a
  1730. Dialog Box function located in a DLL, how to create  an import library, the
  1731. use of Make files, and how to create multiple code segments.
  1732.  
  1733.      The following  DLL example is  called RODSAPP (how  appropriate). It's
  1734. comprised of  an  application program  and  two  DLLs. The  app  files  are
  1735. rodsapp.c, winmain.c,  and wndproc.c. The file rodsapp.c  contains code for
  1736. creating and  initializing the  Windows application.    The file  winmain.c
  1737. handles the Windows message dispatcher.  The wndproc.c module is a standard
  1738. Windows function that  has a menu bar.  The menu bar is the  entry into the
  1739. DLLs. The menu items are About,  One and Two. Clicking on the About  option
  1740. demonstrates  a dialog box whose  function resides inside  a DLL (lib2a.c).
  1741. Clicking on menu option One causes a call to the testlib.dll (testlib.c).
  1742.  
  1743.      The function  StepOne inside  testlib.dll demonstrates  variables that
  1744. are referenced from DS and SS.  I've provided total explanations inside the
  1745. source so that understanding would be easier. 
  1746.  
  1747.      Clicking  on menu option Two also makes  a call to testlib.dll that in
  1748. turn calls the  DLL lib2.c. The calls  inside these DLLs  also demonstrates
  1749. what happens to variables that are referenced from DS and SS.
  1750.  
  1751.      The  Make  file  used with  the  program  compiles  with the  Codeview
  1752. debugger options set. I suggest  that you run the program under  Codeview a
  1753. few  times and  keep an eye  on the  DS and  SS registers. Also,  watch the
  1754. variables inside routines and  note their addresses and watch  what happens
  1755. to those variables addresses when you step into a routine inside a DLL.
  1756.  
  1757.      Along with the source files is  a batch program DOALL.BAT. It runs all
  1758. the Make files  and dumps any warning or error messages out to a file named
  1759. peek.
  1760.  
  1761.      Also, the Make file LIB.MAK creates an import library 'test.lib'. This
  1762. Make  file should be run  first in order to create  the import library that
  1763. will be linked into the DLLs. Changes to the DEF files will re-make LIB.MAK
  1764. but  the *.dll  files must  be deleted  and re-linked  with the  new import
  1765.  
  1766.  
  1767.  
  1768.  
  1769.  
  1770.  
  1771.  
  1772.  
  1773. library.
  1774.  
  1775.  
  1776.                Make File Explanation
  1777.                ---------------------
  1778.  
  1779.      The following is a snippet of the rodsapp.mak Make file; note that the
  1780. following statements that  begin with '*' do not appear  in the actual Make
  1781. file.
  1782.  
  1783. TMPDRIVE=c:\tmp
  1784.  
  1785. WLIB=libw mlibcew        *sets   up  a   macro  for   the  libraries   that
  1786.                          *will be used during linking
  1787.  
  1788. IMPLIBS=test             *the DLLs import library (see next  
  1789.                          *section    for    how     this    library     was
  1790.                          *created).
  1791.  
  1792.  
  1793. * object code of the modules used in RODSAPP.EXE
  1794. OBJ=rodsapp.obj winmain.obj wndproc.obj
  1795.  
  1796. * compiler option flags; a detailed meaning found in source
  1797. CFLAGS=cl /c /AM /D LINT_ARGS /Gws /W3 /Zip /Od /nologo
  1798.  
  1799. # Update the executable file if necessary, and if so, add the
  1800. # resource back in. The /NOE must be included when linking with 
  1801. # Windows libraries.
  1802.  
  1803. rodsapp.exe: $(OBJ) rodsapp.res rodsapp.def
  1804.         del $(TMPDRIVE)lk.res
  1805.         echo $(OBJ)>>$(TMPDRIVE)lk.res
  1806.         echo rodsapp.exe/align:16>>$(TMPDRIVE)lk.res
  1807.         echo rodsapp.map/map/NOD/CO/LI>>$(TMPDRIVE)lk.res
  1808.         echo $(WLIB) $(IMPLIBS)>>$(TMPDRIVE)lk.res
  1809.         echo rodsapp.def>>$(TMPDRIVE)lk.res
  1810.         link  @$(TMPDRIVE)lk.res
  1811.         rc rodsapp.res
  1812.  
  1813. # Update the object file if necessary
  1814.  
  1815. * The following demonstrates how to seperate your code into code
  1816. * segments. The -NT allows one to name the code segment. This 
  1817. * name is then placed in the modules DEF file under the SEGMENTS 
  1818. * statement and given the control flags that you wish the code 
  1819. * segment to follow.
  1820.  
  1821. rodsapp.obj: rodsapp.c rodsapp.h
  1822.         $(CC) $(CFLAGS) -NT Initialization_code rodsapp.c
  1823.  
  1824. winmain.obj: winmain.c rodsapp.h
  1825.         $(CC) $(CFLAGS)  -NT Resident_code winmain.c
  1826.  
  1827. wndproc.obj: wndproc.c rodsapp.h testlib.h
  1828.         $(CC) $(CFLAGS)  -NT Resident_code wndproc.c
  1829.  
  1830. # Update the resource if necessary
  1831. rodsapp.res: rodsapp.rc rodsapp.h
  1832.         rc -r rodsapp.rc
  1833.  
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.  
  1841.  
  1842.                DEF File Differences
  1843.                ---------------------
  1844.  
  1845.      The differences between a  Windows application definitions file and  a
  1846. DLL's is that  in the Windows app  DEF file there is a  NAME statement that
  1847. defines the app's name. A DLL has a LIBRARY statement to do the same thing.
  1848. A  DLL does  not need a  STUB statement  since it  cannot be  launched into
  1849. execution  without  an application  calling  it. A  DLL  also has  no STACK
  1850. statement. Since  the DLL uses the  SS of the calling  application it needs
  1851. not define a stack size.
  1852.  
  1853.  
  1854.                Conclusion
  1855.                -----------
  1856.  
  1857.      Things  to consider when developing applications  and using DLLs. DLLs
  1858. are not magical elements to be used for everything. If you can do something
  1859. fast and it's  only going to be used  by one application, that is  the code
  1860. will never really be used in some future app, stay away from DLLs. DLLs are
  1861. slow.  It takes numerous cycles  to load DLLs,  segment adjustments must be
  1862. made.  The DLL  far call  means that  the code  and  data segments  must be
  1863. loaded.
  1864.  
  1865.      Hopefully this article will help you in your understanding  of DLLs. I
  1866. hope that  the code samples  are clear enough to  help you. I  tried not to
  1867. give too  much code, which can be overwhelming when you are trying to learn
  1868. something, but just enough to represent the makeup of real projects.
  1869.  
  1870.      There  are other  topics under  DLLs that  I did  not cover  like User
  1871. Resource DLLs and  the handling of  global data across DLLs.  Maybe someone
  1872. else will provide an  article on User Resource DLLs in a  future article. I
  1873. plan to submit for the next issue of WPJ an article that demonstrates a way
  1874. I figured out to handle global variables across DLLs. Good luck! 
  1875.  
  1876.      Rod Haxton can be contacted @ (703) 883-0226 or (202) 269-3780.
  1877.  
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  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.                          The Windows Help Magician
  1910.                               By Jim Youngman
  1911.  
  1912.      Since I  do not  program  for the  sake of  programming,  I am  always
  1913. looking for shortcuts.  The Windows  Help Magician has proven to be  one of
  1914. the best.  I think it was written  in Visual Basic, but don't let that  put
  1915. you off it.   It's a great little application  and a real time saver.   The
  1916. files it produces can be compiled with Microsoft  or Borland Help Compilers
  1917. for Windows 3.0 or 3.1.
  1918.  
  1919.      I am writing my first fully fledged Windows program.  It is to be used
  1920. mainly  by  computer illiterate  people and  so a  good  Help file  will be
  1921. essential.
  1922.  
  1923.      When  I  started  investigating  how  to  prepare  such  files  I  was
  1924. overwhelmed by the prospect: all  those control characters that have  to be
  1925. inserted!  The Windows  Help Magician eliminates all of that.  Using a well
  1926. designed interface, the  program does all of the hard work.   All I need to
  1927. do is think out the design of the Help system.  The friendly Magician gives
  1928. me a  great set of tools  for creating the index,  browse groups, hypertext
  1929. jumps, popups  and keywords.   You can  also include bitmaps  in your  help
  1930. files.
  1931.  
  1932.      So far I have  only played about a bit with the product.  I am looking
  1933. forward to exploring it further with the real job.
  1934.  
  1935.  
  1936.      The Windows Help Magician is available from the publishers:
  1937.  
  1938.                Software Interphase Incorporated
  1939.                82 Cucumber Hill Road, Foster, RI 02825, USA
  1940.                FAX (401) 397-6814
  1941.                BBS (401) 397-4601
  1942.  
  1943.      There is a fully operational demo  disk which is limited to help files
  1944. of 7 pages.  The full version allows 200 pages.
  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.  
  1974.  
  1975.  
  1976.  
  1977.                                The Last Page
  1978.                               By Mike Wallace
  1979.  
  1980.      This is too  cool.  Pete and I hoped a  couple of hundred people might
  1981. pick  up  the first  issue  of  WPJ (Official  motto:  "It's  not just  for
  1982. breakfast  anymore").   After three  weeks on  various bulletin  boards, we
  1983. counted over a thousand, and that doesn't even include Internet (we have no
  1984. way of  tracking the  number of  downloads there).   We've gotten  mail and
  1985. articles from such  faraway places  as Russia, Germany,  South America  and
  1986. central Jersey.  We hope the number of downloads goes up every month; if it
  1987. starts to go down, we're in trouble.  From the mail we've received,  people
  1988. seem to like it and want to help  out.  It's been overwhelming.  If  you're
  1989. thinking of writing  an article, don't be  shy.  Others are doing  it.  You
  1990. don't have  to be a professional writer (we sure aren't), and we can always
  1991. use more articles.  If you don't feel  up to writing an article, send us  a
  1992. message  and let us know  what you think about the  magazine.  Does it have
  1993. the putrid stench of rotting eggs?  Has it helped your Windows programming?
  1994. Inquiring minds want to know.   Remember: this is your magazine as  much as
  1995. our's.
  1996.  
  1997.      The only thing I'm disappointed about is I haven't gotten any mail for
  1998. this  column.  I really hope you people don't make me write this whole page
  1999. by myself!   As much  as I wish  I could fill  this page with  poetic prose
  2000. every month, that just ain't gonna happen.  What's  on your mind?  The only
  2001. programmers I know all  live in Washington, D.C. (Official  driving slogan:
  2002. "Death before yielding"), and here everyone is a government contractor, and
  2003. there's only so much you can talk about with a contractor before things get
  2004. really  dull.   What are  programmers doing  in, say,  California?   Texas?
  2005. Europe?  I know you people have something on your mind and you're thinking,
  2006. "If only  there  was some  sort of  internationally distributed  electronic
  2007. forum  for sharing  my most personal  thoughts with  people who  will write
  2008. about me  in their  local newspapers  and ban me  from ever  visiting their
  2009. country..."  Well, wonder  no more, because now you have  your chance.  You
  2010. can get  your 15 minutes of fame  simply by writing anything  (and I really
  2011. mean ANYTHING [He means within reason -Pete])  that both piques my interest
  2012. and,  most importantly, means I don't have to write as much.  What could be
  2013. simpler?
  2014.  
  2015.      While  I'm thinking about it, I want  to thank the hard-working sysops
  2016. on CompuServe,  and especially  in the  WINSDK forum.   I've  flooded these
  2017. people with questions lately and they've been great, and I really hope they
  2018. don't mind  if I  use their answers  in future  WPJ articles (ha!  ha! just
  2019. kidding!).  Seriously, these people really know their stuff and will answer
  2020. any question,  no matter how inane  (take it from someone  who's asked more
  2021. than  one inane  question).   An "Honorable  Mention" goes  to sysop  Tammy
  2022. Steele for  her wealth of  knowledge and great attitude.   Stop by  the WPJ
  2023. offices anytime to pick up your official WPJ t-shirt, Tammy.
  2024.  
  2025.      I'm out of room and out of time.  Hope to hear from ya'll soon.
  2026.  
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.  
  2036.  
  2037.  
  2038.  
  2039.  
  2040.  
  2041.  
  2042.  
  2043.  
  2044.  
  2045.                          Getting in touch with us:
  2046.  
  2047.      Right  now there are  only four ways to  get in touch  with us. If you
  2048. have access to the Internet or BITNET, you can get in touch with us at:
  2049.  
  2050. HJ647C at GWUVM.GWU.EDU -or- HJ647C at GWUVM.BITNET (Pete)
  2051.  
  2052. GEnie: P.DAVIS5 (Pete)
  2053.  
  2054. CompuServe: 71141,2071 (Mike)
  2055.  
  2056. WPJ BBS (703) 503-3021 (Mike and Pete)
  2057.  
  2058. You can also send paper mail to:
  2059.  
  2060. Windows Programmer's Journal
  2061. 9436 Mirror Pond Drive
  2062. Fairfax, VA   22032
  2063.       U.S.A.
  2064.  
  2065.      As soon as we replace the hard drive, the Windows Programmer's Journal
  2066. BBS  can be reached at:  (703) 503-3021. You  can get in  touch with either
  2067. Mike or Pete  at this  number. The BBS  is going to  be relatively new,  so
  2068. don't be surprised if it's a little buggy in the beginning. Right now  it's
  2069. only 2400 baud as my 9600 baud modem  died on me, soon you can expect it to
  2070. go up to 14,400. You can also expect to see a Fido-net node address  in the
  2071. near future..
  2072.  
  2073.      In  future issues  we will  be posting  addresses of  contributors and
  2074. columnists who don't mind you knowing their addresses. We will also contact
  2075. any  writers from the  first two  issues and  see if  they want  their mail
  2076. addresses made  available for you  to respond to  them. For now,  send your
  2077. comments to us and we'll forward them.
  2078.  
  2079.  
  2080.  
  2081.  
  2082.  
  2083.  
  2084.  
  2085.  
  2086.  
  2087.  
  2088.  
  2089.  
  2090.  
  2091.  
  2092.  
  2093.  
  2094.  
  2095.  
  2096.  
  2097.  
  2098.  
  2099.  
  2100.  
  2101.  
  2102.  
  2103.  
  2104.  
  2105.  
  2106.  
  2107.  
  2108.  
  2109.