home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / drgrnd.zip / drgrendr.doc < prev    next >
Text File  |  1993-07-27  |  11KB  |  220 lines

  1. DRGRENDR.EXE is a sample program for OS/2 Drag/Drop facilities (aka Direct
  2. Manipulation). It implements source rendering after the drop. This sample is
  3. single-threaded. As many times you will want to do the post-drop rendering in
  4. separate threads so as not to hold up the User Interface, I have a sample
  5. called DRGTHRND.EXE (DRaG THread ReNDering) that does this. It is more complex
  6. because of the multiple threads, so you will probably want to understand this
  7. program first before moving on to that one.
  8.  
  9. DRGRENDR creates 2 frame windows with containers as their client windows. One
  10. of the windows plays the role of a 'drag' window, the other plays the role of a
  11. 'drop' window. Their roles are not interchangeable, not because it was a problem
  12. to program, rather because the roles of the dragger (called the source window)
  13. and the droppee (called the target window) are 2 different ones and it is
  14. easier to understand their roles if they cannot mix.
  15.  
  16. The reason that containers are used is not to make the program more complex. On
  17. the contrary, containers make Drag/Drop easier to program because the app does
  18. not have to draw representations of things that can be dragged and dropped. The
  19. container provides simple facilities to place draggable icons into its window.
  20. Listboxes were considered but containers are visually easier to understand.
  21.  
  22. NOTE THAT THE TOOLKIT HAS A DRAG/DROP SAMPLE CALLED 'DRAGDROP' THAT IS A VERY
  23. GOOD DRAG/DROP SAMPLE PROGRAM.
  24.  
  25. To run this sample program, type DRGRENDR on the command line. The 2 windows
  26. will appear on the bottom of your display. The left-hand container is the 'drag'
  27. container, the right one is the 'drop' container. Drag one or more icons from
  28. the 'drag' container to the 'drop' container. Then double-click on any of the
  29. icons that are created in the 'drop' container. A listbox window will be
  30. displayed that lists the contents of a 'database table'.
  31.  
  32. This is what happens on the drag/drop:
  33.  
  34. First, there are 2 files that are in the .zip file that represent a database of
  35. sorts (a very simple representation). The files are named dbase_?.db. Have a
  36. look at one of them. Here is part of dbase_1.db:
  37.  
  38. TABLEKEY=>table_1
  39. This is row 1 for the table_1 table in dbase_1
  40. This is row 2 for the table_1 table in dbase_1
  41. This is row 3 for the table_1 table in dbase_1
  42. This is row 4 for the table_1 table in dbase_1
  43. This is row 5 for the table_1 table in dbase_1
  44. TABLEKEY=>table_2
  45. This is row 1 for the table_2 table in dbase_1
  46. This is row 2 for the table_2 table in dbase_1
  47. This is row 3 for the table_2 table in dbase_1
  48. This is row 4 for the table_2 table in dbase_1
  49. This is row 5 for the table_2 table in dbase_1
  50. TABLEKEY=>end_of_database
  51.  
  52.  
  53. DRGRENDR scans all dbase_?.db files at startup. Every time it finds a
  54. TABLEKEY=> record, it creates an icon in the 'drag' container that represents
  55. the table whose name follows the TABLEKEY=> literal. When it encounters an
  56. 'end_of_databse' record it assumes end-of-file. So the simulation here is of
  57. multiple databases each with multiple tables. The text under each icon is
  58. created by concatenating the database name with the table name. For instance,
  59. the table_2 table in the dbase_1.db file would be represented by an icon with
  60. 'dbase_1:table_2' as its text.
  61.  
  62. When you drag an icon from the 'drag' container (hereafter referred to as the
  63. 'source' window) to the 'drop' container ('target' window) and drop it,
  64. rendering takes place. This rendering causes the source window to copy the rows
  65. from the specified table to a file whose name was provided by the target. When
  66. the source indicates that the rendering is complete, the target inserts an icon
  67. into its container that now represents that file. Double-clicking on an icon in
  68. the 'drop' window will bring up a listbox that displays the contents of the
  69. file.
  70.  
  71. This is meant to simulate a real-world scenario where the source represents its
  72. contents by icons and its contents are really in a database that most targets
  73. would not be able to read on their own (i.e. they don't know the format, don't
  74. know SQL, etc.)
  75.  
  76. Here is the message flow once the user has begun to drag an icon from the
  77. source window:
  78.  
  79.     SOURCE                                    TARGET
  80.     ──────                                    ──────
  81.  
  82.     CN_INITDRAG .............................
  83.     ......................................... CN_DRAGOVER
  84.     ......................................... CN_DROP (send DM_RENDER to source)
  85.     DM_RENDER ...............................
  86.     (do the rendering) ......................
  87.     (send DM_RENDERCOMPLETE to target)....... DM_RENDERCOMPLETE
  88.                                                 (send DM_ENDCONVERSATION to src)
  89.     DM_ENDCONVERSATION.......................
  90.  
  91. This is basically it. Of course it is more complicated than this in real life
  92. as problems can happen in any of these steps that alter the flow of control.
  93.  
  94. Note that until DM_RENDER time, everything is done as a group of items, i.e.
  95. all DRAGITEM's are lumped together with a DRAGINFO structure and the DRAGINFO
  96. structure is passed with the messages. When the target gets the CN_DROP, at that
  97. point all messages are on an individual DRAGITEM basis. If the user is only
  98. dragging one icon, there is no difference. With multiple icons this really
  99. comes into play.
  100.  
  101. Note also that the CN_ messages are WM_CONTROL messages sent by the container
  102. to its owner when it gets the normal PM messages. The reason for this is so that
  103. the container can provide its owner with more information than it would normally
  104. get with the regular PM messages. The mapping goes like this:
  105.  
  106.   PM message (container gets this)       Message sent by container to owner
  107.   ────────────────────────────────       ──────────────────────────────────
  108.  
  109.   WM_BEGINDRAG ......................... CN_INITDRAG
  110.   DM_DRAGOVER .......................... CN_DRAGOVER
  111.   DM_DROP .............................. CN_DROP
  112.  
  113. The ValueSet control also provides this type of interface to its owner.
  114. Obviously if your program just uses a normal client window you would use the
  115. messages on the left-hand side.
  116.  
  117. THE MOST IMPORTANT THING that you need to know about Drag/Drop is that the
  118. information passed between the source and target is in shared memory so it has
  119. to be freed by both sides when they are done with it. Since you don't allocate
  120. the shared memory (PMDRAG.DLL does), it is more difficult to think in terms of
  121. freeing it. The memory that has to be freed is the DRAGINFO structure and all
  122. the string handles in it and its attached DRAGITEM structures, and any
  123. DRAGTRANSFER structures that were used (during rendering) and their string
  124. handles.
  125.  
  126. You use DrgFreeDraginfo() to free the DRAGINFO structure and
  127. DrgFreeDragtransfer() to free the DRAGTRANSFER structures. The DRAGINFO
  128. structure is allocated by the source when it starts the drag (using the
  129. DrgAllocDraginfo() API), and PM takes care of disbursing this memory to
  130. processes that need it when they call DrgAccessDraginfo(). The DRAGTRANSFER
  131. structures are allocated by the target (using the DrgAllocDragtransfer() API)
  132. when drop processing starts. Whenever it communicates with the source, it uses
  133. DrgSend/PostTransferMsg() API's that cause PM to give their process access to
  134. the DRAGTRANSFER structure.
  135.  
  136. Here are the documented times for freeing these structures when rendering is
  137. involved (as in this sample program):
  138.  
  139. SOURCE
  140. ──────
  141.  
  142. If DrgDrag() returns NULLHANDLE (which it will if the user hits F1 or Esc during
  143. the drop so that there is no target window), it should make the following calls:
  144.  
  145.     DrgDeleteDraginfoStrHandles();
  146.     DrgFreeDragInfo();
  147.  
  148. DrgDeleteDraginfoStrHandles() deletes all the string handles in all the
  149. DRAGITEMs associated with the DRAGINFO structure. DrgFreeDraginfo() frees the
  150. DRAGINFO structure.
  151.  
  152. If DrgDrag() doesn't return NULLHANDLE, that means a drop occurred and the
  153. return value is the target's window handle. In this case, it is the target's
  154. responsibility to delete the string handles but the source needs to free the
  155. DRAGINFO structure and the DRAGTRANSFER structures. Here's what it should do:
  156.  
  157.   When the source is done rendering, it posts the DM_RENDERCOMPLETE message to
  158.   the target. After it posts this message it needs to call DrgFreeDragtransfer()
  159.   for the DRAGITEM that it just rendered.
  160.  
  161.   Under DM_ENDCONVERSATION, when the DM_ENDCONVERSATION for the *last* DRAGITEM
  162.   comes thru, the source needs to call DrgFreeDraginfo(). Keep in mind that
  163.   this means a global counter must be used (or store it in a window word like
  164.   this program does) so it can keep track of when the last one comes thru.
  165.  
  166.  
  167. TARGET
  168. ──────
  169.  
  170. If rendering does not take place for some reason, the target needs to make the
  171. following calls under the CN_DROP (or DM_DROP if not a container owner) message:
  172.  
  173.     DrgDeleteDraginfoStrHandles();
  174.     DrgFreeDraginfo();
  175.  
  176. If rendering does take place:
  177.  
  178.   After the target completes processing the DM_RENDERCOMPLETE message it will
  179.   send the source a DM_ENDCONVERSATION message. At this point it should call
  180.   DrgFreeDragtransfer() for the DRAGITEM that it just processed. It must also
  181.   call DrgDeleteStrHandle() for all HSTR's in the DRAGTRANSFER structure. These
  182.   would normally be DRAGTRANSFER.hstrSelectedRMF and
  183.   DRAGTRANSFER.hstrRenderToName.
  184.  
  185.   If the last DRAGITEM is being processed (also must be implemented with a
  186.   counter), DrgDeleteDraginfoStrHandles() and DrgFreeDraginfo() must be called.
  187.  
  188.  
  189. DRGRENDR frees these structures when the documentation recommends freeing them
  190. (as illustrated above). Unfortunately the documentation isn't real clear on
  191. this and you have to search to find it. REMEMBER THAT IF YOUR APPLICATION DOES
  192. NOT FREE THESE STRUCTURES WHEN IT IS SUPPOSED TO THAT YOUR APP COULD SCREW UP
  193. OTHER APPS IF IT ALLOWS DIRECT MANIPULATION TO OCCUR WITH OTHER APPS. This is
  194. an important thing to note. If direct manipulation is not done properly it
  195. could lead to a PM resource leak because shared memory might never be freed
  196. that should be freed.
  197.  
  198.  
  199. DRGRENDR.EXE is built from 3 source modules:
  200.  
  201. DRGRENDR.C - base code that creates all windows and contains the window procs
  202. DBACCESS.C - functions that access the 'databases'
  203. DRAG.C     - contains all Drag/Drop related code.
  204.  
  205. Hope this sample program helps someone.
  206.  
  207. ===============================================================================
  208. GLOBAL HISTORY
  209.  
  210. 7-19-93 - Completed coding.
  211.  
  212. ===============================================================================
  213.  
  214. Rick Fishman
  215. Code Blazers, Inc.
  216. 4113 Apricot
  217. Irvine, CA 92720
  218.  
  219. CIS ID: 72251,750
  220.