home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / sys / mac / programm / 14015 < prev    next >
Encoding:
Internet Message Format  |  1992-08-14  |  6.2 KB

  1. Path: sparky!uunet!dtix!darwin.sura.net!Sirius.dfn.de!news.uni-stuttgart.de!rz.uni-karlsruhe.de!stepsun.uni-kl.de!oinone.kit.uni-kl.de!sold
  2. From: sold@kit.uni-kl.de (Christoph Sold)
  3. Newsgroups: comp.sys.mac.programmer
  4. Subject: Re: Help with piggybacking data on window records
  5. Message-ID: <sold.48.713823213@kit.uni-kl.de>
  6. Date: 14 Aug 92 20:13:33 GMT
  7. References: <1992Aug10.223248.3217@ucsvc.ucs.unimelb.edu.au>
  8. Sender: news@rhrk.uni-kl.de
  9. Organization: Universitaet Kaiserslautern
  10. Lines: 186
  11.  
  12. In article <1992Aug10.223248.3217@ucsvc.ucs.unimelb.edu.au> u2005681@ucsvc.ucs.unimelb.edu.au writes:
  13. >Subject: Help with piggybacking data on window records
  14. >From: u2005681@ucsvc.ucs.unimelb.edu.au
  15. >Date: 10 Aug 92 12:32:48 GMT
  16. >Hi People,
  17. >This is my first application so don't be too harsh.
  18. >I'm trying to piggyback data on a window record so I can keep
  19. >track of pop-up menus and icon buttons in a multi-window
  20. >application.
  21. >I store my handles in a struct called winPrivate.
  22. >When I create a new window I do the following:
  23. >
  24. >wp = GetNewWindow(rMainWindow, (Ptr)0L, (WindowPtr)-1);
  25. >myPrivate = NewHandleClear(sizeof(winPrivate));
  26. >SetWRefCon(wp, (long)myPrivate);
  27. >
  28. >This seem to allocate the space required (I check if
  29. >the allocation fails).
  30. >
  31. >When trying to retrieve the data in a routine I do the
  32. >following:
  33. >
  34. >void Routine(WindowPtr wp, .....);
  35. >{
  36. >    winPrivateHndl        dataHandle;
  37. >    short                x;
  38. >    Rect                theRect;
  39. >    
  40. >    dataHandle = (winPrivateHndl) GetWRefCon(wp);
  41. >    HLock(dataHandle);
  42. >    .
  43. >    .
  44. >    x = (*dataHandle)->x1; /* for example */
  45. >    DrawPicture((*dataHandle)->thePicHandle, &theRect);
  46. >    .
  47. >    .
  48. >    .
  49. >    HUnlock(dataHandle);
  50. >}
  51. >
  52. >I seem to be able to retrieve data this way but I am losing
  53. >memory by the kilobyte. Every time I call a routine that
  54. >accesses the piggyback data, I seem to end up with a
  55. >locked memory block (even though I UNLOCK it when I leave
  56. >the routine. When I close the window and dispose of all my
  57. >handles, I don't seem to regain any memory!
  58. >Can anybody help me with this problem?
  59. >Am I doing the piggyback thing correctly?
  60. >Am I accessing the piggybacked data correctly?
  61. >Thanks in advance for any suggestions, I am at the end of
  62. >my wisdom.
  63. >
  64. >Chris Hofflin
  65.  
  66.  
  67. Chris,
  68.  
  69. here the two ways to piggyback data into any (handle|pointer)-referenced 
  70. block:
  71.  
  72. 1) packing private data onto the back of the OS record
  73.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  74. The big idea is the OS wants n bytes, at n+1 bytes you can do what you want. 
  75. Here is a picture of this memory layout:
  76.  
  77. byte 0    +-----------+
  78.     |OS record  |
  79.     |        |
  80. byte n    +-----------+
  81. byte n+1|your data  |
  82.     |...        |
  83.  
  84.     |        |
  85.     +-----------+
  86.  
  87. To do this, you allocate _one_ memory block, and use a pointer|handle to it 
  88. as you wish. In pascal, this is define this way:
  89.  
  90. TYPE
  91.  WindowRecord = Record
  92.     {some fields here}
  93.   END; {WindowRecord}
  94.  
  95.  PrivateRecord = Record
  96.     {more fields here}
  97.   END; {PrivateRecord}
  98.  
  99.  PiggyPack = Record
  100.     w: WindowRecord;
  101.     p: PrivateRecord;
  102.   END; {PiggyPack}
  103.  
  104. Now you can pass a pointer to PiggyPack equivalent to a pointer to 
  105. WindowRecord, since both start at the same location.
  106.  
  107. Unfortunately, this will crash as soon as apple chooses to add more fields 
  108. to a (Window)Record -- since your private data is in the place new fields 
  109. will be allocated. Method 1: bad way. Don't use it, until you have written 
  110. warranty from apple the os record will never change.
  111.  
  112. 2) packing a reference to your data in a useful place
  113.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  114. Fortunately, nearly every os record has a "for your convenience"-field, 
  115. often named "refCon". Just four bytes long, this is enough to catch a 
  116. pointer or handle. It is also the way you choose (some kudos for this. well 
  117. done!). It looks in memory this way:
  118.  
  119.     +------------+
  120.     | os record  |
  121.     | ...        |    +------------+
  122.     |"refCon" ----->|private data|
  123.     +------------+    |...         |
  124.             +------------+
  125. To do this one, you have to manage your memory careful: The operating system 
  126. knows _nothing_ about the handle|pointer in the refCon field.
  127. Error #1 is to de-allocate the os record without deallocating the private 
  128. data first: This is a (major) memory leak, since the private block is still 
  129. in the heap, and is referenced by nothing else. No way to recover it.
  130. Error #2 is to de-allocate the private data without setting it's reference 
  131. variable to NULL|NIL. This way you can reference a previously freed block -- 
  132. possibly with some valid data in it. But this block will be overwritten -- 
  133. sooner or later.
  134. Knowing this two error causes, we can define the only way to do this sort of 
  135. pig(gy)-bag. Again, in Pascal:
  136.  
  137. TYPE
  138.  WindowRecord = RECORD
  139.     {some fields here}
  140.     refCon: LongInt; {four bytes apple never uses--behold the Coom 
  141. Toolbox}
  142.   END; {WindowRecord}
  143.  WindowPtr = ^WindowRecord;
  144.  
  145.  PrivateRecord = RECORD
  146.     {some private data here}
  147.   END; {PrivateRecord}
  148.  PrivatePtr = ^PrivateRecord;
  149.  
  150. VAR
  151.   w: WindowPtr;
  152.   p: PrivatePtr;
  153.  
  154. {Allocation}
  155.  
  156.  w := NewPtr(sizeOf(WindowRecord)); {allocate a window record}
  157.  w.refCon := NIL; {just to be sure, since there is no private data yet}
  158.  {.. do something with the window record, e.g.:}
  159.  wp := GetNewWindow(kMyWindow, w, Ptr(-1));
  160.  
  161.  {...}
  162.  p = NewPtr(sizeOf(PrivateRecord));{allocate a private record}
  163.  w.refCon := LongInt(p); {now refCon points to your private data}
  164.  {alternatively, use for WindowRecords only}
  165.  SetWRefCon(wp, LongInt(p));
  166.  
  167. {Deallocation}
  168.  p := w.refCon;
  169.  {for WindowRecords only, you can use}
  170.  p := GetWRefCon(wp);
  171.  ReleasePtr(p);
  172.  w.refCon := NIL; {*** important! *** see error #2}
  173.  {alternatively, for window records only}
  174.  SetWRefCon(wp, 0); {since nil is 0}
  175.  
  176.  {...}
  177.  CloseWindow(wp);
  178.  
  179.  
  180.  
  181. OK, thats the whole point. Additionally, I suggest to switch from C to 
  182. either C++ or Pascal, since both of these langauages provide strong 
  183. typechecking. This is essential for a beginner, since the compiler will 
  184. catch much more of typcal beginners typos and errors. Also recommended is 
  185. Inside Macintosh, Memory management chapters (for the theoretical 
  186. background), as well as the Programmers FAQ posted periodically here.
  187.  
  188. Hope this helped a little.
  189.  
  190. -Christoph
  191.  
  192. Christoph P. Sold                   CATS Software GmbH
  193.                                     Mussbacher Landstr.2
  194.                                     W-6730 Neustadt (Weinstrasse)
  195. ger.xse0035@applelink.apple.com     Germany
  196.  
  197. "If an apple is fun, what the heck is an appletree?"
  198.