home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / drgrnd.zip / drag.c < prev    next >
C/C++ Source or Header  |  1993-07-28  |  59KB  |  1,257 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drag.c                 AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  07-16-93                                           *
  5.  *                                                                   *
  6.  * MODULE DESCRIPTION:                                               *
  7.  *                                                                   *
  8.  *  Part of the 'DRGRENDR' drag/drop sample program.                 *
  9.  *                                                                   *
  10.  *  This module handles all the Drag/Drop processing for the         *
  11.  *  DRGRENDR.EXE sample program.                                     *
  12.  *                                                                   *
  13.  * NOTES:                                                            *
  14.  *                                                                   *
  15.  *  We use the DRM_FISHMAN rendering mechanism. This is a fairly     *
  16.  *  simple protocol that requires rendering on the drop.             *
  17.  *                                                                   *
  18.  * FUNCTIONS AVALABLE TO OTHER MODULES:                              *
  19.  *                                                                   *
  20.  *   dragInit                                                        *
  21.  *   dragOver                                                        *
  22.  *   dragDrop                                                        *
  23.  *                                                                   *
  24.  *                                                                   *
  25.  * HISTORY:                                                          *
  26.  *                                                                   *
  27.  *  07-16-93 - Program coded.                                        *
  28.  *                                                                   *
  29.  *  Rick Fishman                                                     *
  30.  *  Code Blazers, Inc.                                               *
  31.  *  4113 Apricot                                                     *
  32.  *  Irvine, CA. 92720                                                *
  33.  *  CIS ID: 72251,750                                                *
  34.  *                                                                   *
  35.  *********************************************************************/
  36.  
  37. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  38.  
  39. /*********************************************************************/
  40. /*------- Include relevant sections of the OS/2 header files --------*/
  41. /*********************************************************************/
  42.  
  43. #define  INCL_DOSERRORS
  44. #define  INCL_DOSPROCESS
  45. #define  INCL_SHLERRORS
  46. #define  INCL_WINDIALOGS
  47. #define  INCL_WINERRORS
  48. #define  INCL_WINFRAMEMGR
  49. #define  INCL_WININPUT
  50. #define  INCL_WINSTDCNR
  51. #define  INCL_WINSTDDRAG
  52. #define  INCL_WINWINDOWMGR
  53.  
  54. /**********************************************************************/
  55. /*----------------------------- INCLUDES -----------------------------*/
  56. /**********************************************************************/
  57.  
  58. #include <os2.h>
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include "drgrendr.h"
  63.  
  64. /*********************************************************************/
  65. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  66. /*********************************************************************/
  67.  
  68. #define DRAG_RMF  "<DRM_FISHMAN,DRF_UNKNOWN>" // Rendering Mechanism/Format
  69.  
  70. /**********************************************************************/
  71. /*---------------------------- STRUCTURES ----------------------------*/
  72. /**********************************************************************/
  73.  
  74.  
  75. /**********************************************************************/
  76. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  77. /**********************************************************************/
  78.  
  79. int     CountSelectedRecs   ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  80.                               PBOOL pfUseSelectedRecs );
  81. void    SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
  82.                               PDRAGIMAGE pDragImage );
  83. void    SetOneDragItem      ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  84.                               PDRAGINFO pDragInfo, PDRAGIMAGE pDragImage,
  85.                               int iOffset );
  86. void    ProcessDroppedItem  ( HWND hwndFrame, PDRAGINFO pDragInfo,
  87.                               PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer );
  88. void    FindTempFile        ( PSZ szTempFileName );
  89. MRESULT Render              ( HWND hwndFrame, PDRAGTRANSFER pDragXfer );
  90. void    DoTheRendering      ( PDRAGTRANSFER pDragXfer );
  91. MRESULT RenderComplete      ( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
  92.                               USHORT fsRender );
  93. MRESULT EndConversation     ( HWND hwndFrame );
  94. void    RemoveSourceEmphasis( HWND hwndFrame );
  95. void    TargetCleanup       ( HWND hwndFrame );
  96. void    SourceCleanup       ( HWND hwndFrame );
  97.  
  98. FNWP wpSource, wpTarget;
  99.  
  100. /**********************************************************************/
  101. /*------------------------ GLOBAL VARIABLES --------------------------*/
  102. /**********************************************************************/
  103.  
  104. char szDroppedOnCnrTitle[] = "Open a table by double-clicking on it!";
  105.  
  106. /**********************************************************************/
  107. /*--------------------------- dragMessage ----------------------------*/
  108. /*                                                                    */
  109. /*  A DM_ MESSAGE WAS RECEIVED BY THE FRAME WINDOW PROCEDURE.         */
  110. /*                                                                    */
  111. /*  PARMS: frame window handle,                                       */
  112. /*         message id,                                                */
  113. /*         mp1 of the message,                                        */
  114. /*         mp2 of the message                                         */
  115. /*                                                                    */
  116. /*  NOTES:                                                            */
  117. /*                                                                    */
  118. /*  RETURNS: return code of message                                   */
  119. /*                                                                    */
  120. /*--------------------------------------------------------------------*/
  121. /**********************************************************************/
  122. MRESULT dragMessage( HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2 )
  123. {
  124.     switch( msg )
  125.     {
  126.         // We only want to respond yes or no here so as not to hold up the
  127.         // target window. All rendering will be done in the UM_DO_THE_RENDERING
  128.         // message.
  129.  
  130.         case DM_RENDER:          // The SOURCE window gets this message
  131.         {
  132.             MRESULT mr = Render( hwndFrame, (PDRAGTRANSFER) mp1 );
  133.  
  134.             if( mr )
  135.                 WinPostMsg( hwndFrame, UM_DO_THE_RENDERING, mp1, NULL );
  136.  
  137.             return mr;
  138.         }
  139.  
  140.         case UM_DO_THE_RENDERING:
  141.  
  142.             DoTheRendering( (PDRAGTRANSFER) mp1 );
  143.             return 0;
  144.  
  145.  
  146.         case DM_ENDCONVERSATION: // The SOURCE window gets this message
  147.  
  148.             return EndConversation( hwndFrame );
  149.  
  150.  
  151.         case DM_RENDERCOMPLETE:  // The TARGET window gets this message
  152.         {
  153.             PDRAGTRANSFER pDragXfer = (PDRAGTRANSFER) mp1;
  154.  
  155.             // If the source gets this message it means that it requested a
  156.             // a retry and the target said no. So complete the loop... Note that
  157.             // pDragXfer->pditem->hwndItem is the source window.
  158.  
  159.             if( hwndFrame == pDragXfer->pditem->hwndItem )
  160.                 DrgPostTransferMsg( pDragXfer->hwndClient, DM_RENDERCOMPLETE,
  161.                                     pDragXfer, DMFL_RENDERFAIL, 0, FALSE );
  162.             else
  163.                 return RenderComplete( hwndFrame, (PDRAGTRANSFER) mp1,
  164.                                        SHORT1FROMMP( mp2 ) );
  165.  
  166.             return 0;
  167.         }
  168.     }
  169.  
  170.     return 0;
  171. }
  172.  
  173. /**********************************************************************/
  174. /*----------------------------- dragInit -----------------------------*/
  175. /*                                                                    */
  176. /*  PROCESS CN_INITDRAG NOTIFY MESSAGE.                               */
  177. /*                                                                    */
  178. /*  PARMS: frame window handle,                                       */
  179. /*         pointer to the CNRDRAGINIT structure                       */
  180. /*                                                                    */
  181. /*  NOTES: the CN_INITDRAG message is equivalent to the WM_BEGINDRAG  */
  182. /*         message. The reason I mention this is because if the source*/
  183. /*         window in the drag is not a container you will get the     */
  184. /*         WM_BEGINDRAG message.                                      */
  185. /*                                                                    */
  186. /*         WM_BEGINDRAG is sent to windows to allow them to know that */
  187. /*         the user is requesting a drag from their window. This      */
  188. /*         message contains only the x,y coordinates of the mouse at  */
  189. /*         the time of WM_BEGINDRAG.                                  */
  190. /*                                                                    */
  191. /*         The reason for CN_INITDRAG is first so that the container  */
  192. /*         can notify its owner when it gets a WM_BEGINDRAG message   */
  193. /*         and second so that the container can give its owner more   */
  194. /*         info, like what container record the mouse pointer is over.*/
  195. /*         To accomplish this, the container packages up this informa-*/
  196. /*         tion in a CNRDRAGINIT structure and sends that structure   */
  197. /*         along with the CN_INITDRAG message.                        */
  198. /*                                                                    */
  199. /*  RETURNS: nothing                                                  */
  200. /*                                                                    */
  201. /*--------------------------------------------------------------------*/
  202. /**********************************************************************/
  203. void dragInit( HWND hwndFrame, PCNRDRAGINIT pcdi )
  204. {
  205.     PCNRREC     pCnrRecUnderMouse = (PCNRREC) pcdi->pRecord;
  206.     PDRAGIMAGE  pDragImage = NULL;
  207.     PDRAGINFO   pDragInfo = NULL;
  208.     BOOL        fUseSelectedRecs;
  209.     PINSTANCE   pi = INSTDATA( hwndFrame );
  210.     int         cRecs;
  211.  
  212.     if( !pi )
  213.     {
  214.         Msg( "dragInit cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  215.         return;
  216.     }
  217.  
  218.     // pSavedDragInfo is used during drop processing. When the drop is complete
  219.     // (the source gets a DM_ENDCONVERSATION message from the target), the
  220.     // source will free the DRAGINFO structure and set this field to NULL.
  221.     // So pSavedDragInfo is non-NULL if a drop has not yet completed. In this
  222.     // case we make it easy on ourselves by not allowing another drag. The
  223.     // reason for this is that if we allow another drag to take place we will
  224.     // need to overwrite this pSavedDragInfo field in which case the drop
  225.     // processing would not free the right DRAGINFO structure. Obviously in a
  226.     // commercial app you'd want to use a different mechanism for storing the
  227.     // DRAGINFO structure, like a linked list, so you could start another drag
  228.     // while the drop is in progress.
  229.  
  230.     if( pi->pSavedDragInfo )
  231.     {
  232.         WinAlarm( HWND_DESKTOP, WA_WARNING );
  233.         return;
  234.     }
  235.  
  236.     // Count the records that have CRA_SELECTED emphasis. Also return whether
  237.     // or not we should process the CRA_SELECTED records. If the container
  238.     // record under the mouse does not have this emphasis, we shouldn't. In that
  239.     // case we would just process the record under the mouse.
  240.  
  241.     cRecs = CountSelectedRecs( hwndFrame, pCnrRecUnderMouse, &fUseSelectedRecs);
  242.  
  243.     if( cRecs )
  244.     {
  245.         int iDragImageArraySize = cRecs * sizeof( DRAGIMAGE );
  246.  
  247.         // Allocate an array of DRAGIMAGE structures. Each structure contains
  248.         // info about an image that will be under the mouse pointer during the
  249.         // drag. This image will represent a container record being dragged.
  250.  
  251.         pDragImage = (PDRAGIMAGE) malloc( iDragImageArraySize );
  252.  
  253.         if( pDragImage )
  254.         {
  255.             memset( pDragImage, 0, iDragImageArraySize );
  256.  
  257.             // Let PM allocate enough memory for a DRAGINFO structure as well
  258.             // as a DRAGITEM structure for each record being dragged. It will
  259.             // allocate shared memory so other processes can participate in the
  260.             // drag/drop.
  261.  
  262.             pDragInfo = DrgAllocDraginfo( cRecs );
  263.  
  264.             if( pDragInfo )
  265.             {
  266.                 pi->pSavedDragInfo = pDragInfo;
  267.                 pi->cDragItems = cRecs;
  268.             }
  269.             else
  270.                 Msg( "DrgAllocDraginfo failed. RC(%X)", HWNDERR( hwndFrame ) );
  271.         }
  272.         else
  273.             Msg( "Out of memory in dragInit" );
  274.     }
  275.  
  276.     if( cRecs && pDragInfo && pDragImage )
  277.     {
  278.         // Set the data from the container records into the DRAGITEM and
  279.         // DRAGIMAGE structures. If we are to process CRA_SELECTED container
  280.         // records, do them all in one function. If not, pass a pointer to the
  281.         // container record under the mouse to a different function that will
  282.         // fill in just one DRAGITEM / DRAGIMAGE structure.
  283.  
  284.         if( fUseSelectedRecs )
  285.             SetSelectedDragItems( hwndFrame, cRecs, pDragInfo, pDragImage );
  286.         else
  287.             SetOneDragItem( hwndFrame, pCnrRecUnderMouse, pDragInfo,
  288.                             pDragImage, 0 );
  289.  
  290.         // If DrgDrag returns NULLHANDLE, that means the user hit Esc or F1
  291.         // while the drag was going on so the target didn't have a chance to
  292.         // delete the string handles. So it is up to the source window to do
  293.         // it. Unfortunately there doesn't seem to be a way to determine
  294.         // whether the NULLHANDLE means Esc was pressed as opposed to there
  295.         // being an error in the drag operation. So we don't attempt to figure
  296.         // that out. To us, a NULLHANDLE means Esc was pressed...
  297.  
  298.         if( !DrgDrag( hwndFrame, pDragInfo, pDragImage, cRecs, VK_ENDDRAG,
  299.                       NULL ) )
  300.         {
  301.             if( !DrgDeleteDraginfoStrHandles( pDragInfo ) )
  302.                 Msg( "dragInit DrgDeleteDraginfoStrHandles RC(%X)",
  303.                      HWNDERR( hwndFrame ) );
  304.  
  305.             if( !DrgFreeDraginfo( pDragInfo ) )
  306.                 Msg( "dragInit DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  307.  
  308.             pi->pSavedDragInfo = NULL;
  309.         }
  310.  
  311.         // Take off source emphasis from the records that were dragged
  312.  
  313.         RemoveSourceEmphasis( hwndFrame );
  314.     }
  315.  
  316.     if( pDragImage )
  317.         free( pDragImage );
  318. }
  319.  
  320. /**********************************************************************/
  321. /*----------------------------- dragOver -----------------------------*/
  322. /*                                                                    */
  323. /*  PROCESS CN_DRAGOVER NOTIFY MESSAGE.                               */
  324. /*                                                                    */
  325. /*  PARMS: frame window handle,                                       */
  326. /*         pointer to the CNRDRAGINFO structure                       */
  327. /*                                                                    */
  328. /*  NOTES: The container sends the CN_DRAGOVER message to its owner   */
  329. /*         when it gets a DM_DRAGOVER message. The container takes    */
  330. /*         the info it gets on the DM_DRAGOVER message and combines   */
  331. /*         it with other container-specific dragover info into a      */
  332. /*         CNRDRAGINFO structure, then passes a pointer to that       */
  333. /*         structure to its owner in the CN_DRAGOVER message.         */
  334. /*                                                                    */
  335. /*         In this program, all we care about is that the other       */
  336. /*         window can handle the DRM_FISHMAN protocol and that the    */
  337. /*         window is not trying to drop on itself. Strangely enough,  */
  338. /*         the DRM_FISHMAN protocol is not in widespread use <g>.     */
  339. /*                                                                    */
  340. /*  RETURNS: return value from CN_DRAGOVER processing                 */
  341. /*                                                                    */
  342. /*--------------------------------------------------------------------*/
  343. /**********************************************************************/
  344. MRESULT dragOver( HWND hwndFrame, PCNRDRAGINFO pcdi )
  345. {
  346.     USHORT    usDrop, usDefaultOp;
  347.     PDRAGINFO pDragInfo = pcdi->pDragInfo;
  348.     PDRAGITEM pDragItem;
  349.  
  350.     if( !DrgAccessDraginfo( pDragInfo ) )
  351.     {
  352.         Msg( "dragOver DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  353.         return MRFROM2SHORT( DOR_NEVERDROP, 0 );
  354.     }
  355.  
  356.     // Don't allow a window to drop on itself
  357.  
  358.     if( pDragInfo->hwndSource == hwndFrame )
  359.         return MRFROM2SHORT( DOR_NEVERDROP, 0 );
  360.  
  361.     // We're only concerned with the first item being dragged. We "assume" that
  362.     // if the first item is using the DRM_FISHMAN protocol then all others are.
  363.     // In a real-world program you would want to check all dragitems.
  364.  
  365.     pDragItem = DrgQueryDragitemPtr( pDragInfo, 0 );
  366.  
  367.     if( pDragItem )
  368.     {
  369.         // We will only allow DRM_FISHMAN items to be dropped on us
  370.  
  371.         if( DrgVerifyRMF( pDragItem, "DRM_FISHMAN", NULL ) )
  372.         {
  373.             usDrop = DOR_DROP;
  374.  
  375.             // We only allow a logical 'copy' operation to take place, so this
  376.             // will change the pointer to be a 'copy' (halftoned) pointer
  377.             // during the drag when the pointer is over our window.
  378.  
  379.             usDefaultOp = DO_COPY;
  380.         }
  381.         else
  382.         {
  383.             usDrop = DOR_NEVERDROP;
  384.             usDefaultOp = 0;
  385.         }
  386.     }
  387.     else
  388.         Msg( "dragOver DrgQueryDragitemPtr RC(%X)", HWNDERR( hwndFrame ) );
  389.  
  390.     // Free our handle to the shared memory if the source window is not in our
  391.     // process.
  392.  
  393.     if( !DrgFreeDraginfo( pDragInfo ) &&
  394.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  395.         Msg( "dragOver DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  396.  
  397.     return MRFROM2SHORT( usDrop, usDefaultOp );
  398. }
  399.  
  400. /**********************************************************************/
  401. /*---------------------------- dragDrop ------------------------------*/
  402. /*                                                                    */
  403. /*  PROCESS CN_DROP NOTIFY MESSAGE.                                   */
  404. /*                                                                    */
  405. /*  PARMS: frame window handle,                                       */
  406. /*         pointer to the CNRDRAGINFO structure                       */
  407. /*                                                                    */
  408. /*  NOTES: The container sends the CN_DROP message to its owner when  */
  409. /*         it gets a DM_DROP message. The container takes the info it */
  410. /*         gets on the DM_DROP message and combines it with other     */
  411. /*         container-specific dragover info into a CNRDRAGINFO        */
  412. /*         structure, then passes a pointer to that structure to its  */
  413. /*         owner in the CN_DROP message.                              */
  414. /*                                                                    */
  415. /*  RETURNS: nothing                                                  */
  416. /*                                                                    */
  417. /*--------------------------------------------------------------------*/
  418. /**********************************************************************/
  419. void dragDrop( HWND hwndFrame, PCNRDRAGINFO pcdi )
  420. {
  421.     PDRAGINFO     pDragInfo = pcdi->pDragInfo;
  422.     PINSTANCE     pi = INSTDATA( hwndFrame );
  423.     PDRAGITEM     pDragItem;
  424.     PDRAGTRANSFER pDragXfer;
  425.     int           i, cItemsToRender, cItemsRendered;
  426.  
  427.     if( !pi )
  428.     {
  429.         Msg( "dragDrop cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  430.         return;
  431.     }
  432.  
  433.     // Save this info so it can be used on the last DM_RENDERCOMPLETE message.
  434.  
  435.     pi->pSavedDragInfo = pDragInfo;
  436.     pi->cDragItems     = pDragInfo->cditem;
  437.  
  438.     if( !DrgAccessDraginfo( pDragInfo ) )
  439.     {
  440.         Msg( "dragDrop DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  441.         return;
  442.     }
  443.  
  444.     cItemsToRender = cItemsRendered = pDragInfo->cditem;
  445.  
  446.     // We allocate an array of DRAGTRANSFER structures. One by one each will
  447.     // be passed on a DM_RENDER message. On DM_RENDERCOMPLETE messages we will
  448.     // free each one. PM takes care of freeing the whole array after it gets
  449.     // back as many DrgFreeDragTransfer's as were allocated here.
  450.  
  451.     pDragXfer = DrgAllocDragtransfer( pDragInfo->cditem );
  452.     if( !pDragXfer )
  453.     {
  454.         Msg( "dragDrop DrgAllocDragtransfer RC(%X)", HWNDERR( hwndFrame ) );
  455.         return;
  456.     }
  457.  
  458.     // Process each DragItem. First get a pointer to it, then call a function
  459.     // that starts the rendering happening.
  460.  
  461.     for( i = 0; i < pDragInfo->cditem; i++ )
  462.     {
  463.         pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
  464.  
  465.         if( pDragItem )
  466.             ProcessDroppedItem( hwndFrame, pDragInfo, pDragItem,pDragXfer + i );
  467.         else
  468.         {
  469.             Msg( "dragDrop DrgQueryDragitemPtr RC(%X)", HWNDERR( hwndFrame ) );
  470.             --cItemsRendered;
  471.         }
  472.     }
  473.  
  474.     if( !cItemsRendered )
  475.     {
  476.         // Clean up after ourselves if we weren't able to do
  477.         // any rendering. Normally this cleanup would be done
  478.         // under the last DM_RENDERCOMPLETE message but we don't
  479.         // get those messages if we aren't rendering.
  480.  
  481.         TargetCleanup( hwndFrame );
  482.     }
  483.     else if( cItemsToRender != cItemsRendered )
  484.     {
  485.         // Only *some* items weren't rendered. If the rendering for all items
  486.         // that got sent DM_RENDER messages is complete, the target resources
  487.         // wouldn't have been freed because the counter wouldn't have been zero,
  488.         // so we need to free them in this case.
  489.  
  490.         if( pi->cDragItems )
  491.             pi->cDragItems -= (cItemsToRender - cItemsRendered);
  492.         else
  493.             TargetCleanup( hwndFrame );
  494.     }
  495. }
  496.  
  497. /**********************************************************************/
  498. /*------------------------ CountSelectedRecs -------------------------*/
  499. /*                                                                    */
  500. /*  COUNT THE NUMBER OF RECORDS THAT ARE CURRENTLY SELECTED.          */
  501. /*                                                                    */
  502. /*  PARMS: frame window handle,                                       */
  503. /*         pointer to the record that was under the pointer,          */
  504. /*         address of BOOL - should we process selected records?      */
  505. /*                                                                    */
  506. /*  NOTES:                                                            */
  507. /*                                                                    */
  508. /*  RETURNS: number of records to process                             */
  509. /*                                                                    */
  510. /*--------------------------------------------------------------------*/
  511. /**********************************************************************/
  512. int CountSelectedRecs( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  513.                        PBOOL pfUseSelectedRecs )
  514. {
  515.     int cRecs = 0;
  516.  
  517.     *pfUseSelectedRecs = FALSE;
  518.  
  519.     // If the record under the mouse is NULL, we must be over whitespace, in
  520.     // which case we don't want to drag any records.
  521.  
  522.     if( pCnrRecUnderMouse )
  523.     {
  524.         PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  525.  
  526.         // Count the records with 'selection' emphasis. These are the records
  527.         // we want to drag, unless the container record under the mouse does
  528.         // not have selection emphasis. If that is the case, we only want to
  529.         // process that one.
  530.  
  531.         while( pCnrRec )
  532.         {
  533.             pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  534.                                                    CM_QUERYRECORDEMPHASIS,
  535.                                                    MPFROMP( pCnrRec ),
  536.                                                    MPFROMSHORT( CRA_SELECTED ));
  537.  
  538.             if( pCnrRec == (PCNRREC) -1 )
  539.                 Msg( "CountSelectedRecs..CM_QUERYRECORDEMPHASIS RC(%X)",
  540.                      HWNDERR( hwndFrame ) );
  541.             else if( pCnrRec )
  542.             {
  543.                 if( pCnrRec == pCnrRecUnderMouse )
  544.                     *pfUseSelectedRecs = TRUE;
  545.  
  546.                 cRecs++;
  547.             }
  548.         }
  549.  
  550.         if( !(*pfUseSelectedRecs) )
  551.             cRecs = 1;
  552.     }
  553.  
  554.     return cRecs;
  555. }
  556.  
  557. /**********************************************************************/
  558. /*----------------------- SetSelectedDragItems -----------------------*/
  559. /*                                                                    */
  560. /*  FILL THE DRAGINFO STRUCT WITH DRAGITEM STRUCTS FOR SELECTED RECS. */
  561. /*                                                                    */
  562. /*  PARMS: frame window handle,                                       */
  563. /*         count of selected records,                                 */
  564. /*         pointer to allocated DRAGINFO struct,                      */
  565. /*         pointer to allocated DRAGIMAGE array                       */
  566. /*                                                                    */
  567. /*  NOTES:                                                            */
  568. /*                                                                    */
  569. /*  RETURNS: nothing                                                  */
  570. /*                                                                    */
  571. /*--------------------------------------------------------------------*/
  572. /**********************************************************************/
  573. void SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
  574.                            PDRAGIMAGE pDragImage )
  575. {
  576.     PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  577.     int     i;
  578.  
  579.     for( i = 0; i < cRecs; i++, pDragImage++ )
  580.     {
  581.         pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  582.                                                CM_QUERYRECORDEMPHASIS,
  583.                                                MPFROMP( pCnrRec ),
  584.                                                MPFROMSHORT( CRA_SELECTED ) );
  585.  
  586.         if( pCnrRec == (PCNRREC) -1 )
  587.             Msg( "SetSelectedDragItems..CM_QUERYRECORDEMPHASIS RC(%X)",
  588.                  HWNDERR( hwndFrame ) );
  589.         else
  590.             SetOneDragItem( hwndFrame, pCnrRec, pDragInfo, pDragImage, i );
  591.     }
  592. }
  593.  
  594. /**********************************************************************/
  595. /*-------------------------- SetOneDragItem --------------------------*/
  596. /*                                                                    */
  597. /*  SET ONE DRAGITEM STRUCT INTO A DRAGINFO STRUCT.                   */
  598. /*                                                                    */
  599. /*  PARMS: frame window handle,                                       */
  600. /*         pointer to CNRREC that contains current container record,  */
  601. /*         pointer to allocated DRAGINFO struct,                      */
  602. /*         pointer to allocated DRAGIMAGE array,                      */
  603. /*         record offset into DRAGINFO struct to place DRAGITEM       */
  604. /*                                                                    */
  605. /*  NOTES: Fill in a DRAGITEM struct and 'set' it into the DRAGINFO   */
  606. /*         shared memory. Also fill in a DRAGIMAGE structure so PM    */
  607. /*         knows what image to use in representing this item.         */
  608. /*                                                                    */
  609. /*  RETURNS: nothing                                                  */
  610. /*                                                                    */
  611. /*--------------------------------------------------------------------*/
  612. /**********************************************************************/
  613. void SetOneDragItem( HWND hwndFrame, PCNRREC pCnrRec, PDRAGINFO pDragInfo,
  614.                      PDRAGIMAGE pDragImage, int iOffset )
  615. {
  616.     DRAGITEM DragItem;
  617.     PCH      pchColon = NULL;
  618.  
  619.     memset( &DragItem, 0, sizeof DragItem );
  620.  
  621.     // hwndDragItem is the window that will get the DM_RENDER and
  622.     // DM_RENDERCOMPLETE messages.
  623.  
  624.     DragItem.hwndItem = hwndFrame;
  625.  
  626.     // ulItemID is used to store information that can be used at drop time. Here
  627.     // we store the container record pointer.
  628.  
  629.     DragItem.ulItemID = (ULONG) pCnrRec;
  630.  
  631.     // hstrType identifies 'types' when it is necessary to differentiate. A
  632.     // good example is if you are dragging file names (DRM_OS2FILE) and need to
  633.     // pass the file type to the target (i.e. DRT_BITMAP would mean the file
  634.     // contained a bitmap, DRT_TEXT is an ascii file, etc. )
  635.  
  636.     DragItem.hstrType = DrgAddStrHandle( DRT_UNKNOWN );
  637.  
  638.     // This is the rendering mechanism/format. This establishes the protocol
  639.     // that we will be using during the Drag/Drop operation. In this program we
  640.     // only use DRM_FISHMAN which means rendering will take place after the
  641.     // drop using a predefined and agreed-upon mechanism. Any target objects
  642.     // that OK this type of protocol must know how to handle themselves after
  643.     // the drop.
  644.  
  645.     DragItem.hstrRMF = DrgAddStrHandle( DRAG_RMF );
  646.  
  647.     // This will contain our 'database file' name. We have multiple 'database'
  648.     // files, each with their own set of 'tables'. This field identifies the
  649.     // 'database' name. The text for each container record has been set (in the
  650.     // InsertRecords function in drgrendr.c) to "database:table". So we
  651.     // temporarily set the colon to a null-terminator for the database name so
  652.     // we can create a stringhandle for the database name.
  653.  
  654.     pchColon = strchr( pCnrRec->szTableName, ':' );
  655.     if( pchColon )
  656.         *pchColon = 0;
  657.     else                  // This should never happen! Play it safe though.
  658.         pchColon = pCnrRec->szTableName;
  659.  
  660.     DragItem.hstrContainerName = DrgAddStrHandle( pCnrRec->szTableName );
  661.  
  662.     // This will contain the table name (minus the database name)
  663.  
  664.     DragItem.hstrSourceName = DrgAddStrHandle( pchColon + 1 );
  665.  
  666.     // Replace the colon that we overwrote with a 0 earlier
  667.  
  668.     if( pchColon != pCnrRec->szTableName )
  669.         *pchColon = ':';
  670.  
  671.     // Suggested target name is the same as the source name. We *could* ask the
  672.     // target to call it something else but we don't need that functionality
  673.     // in this program.
  674.  
  675.     DragItem.hstrTargetName = DragItem.hstrSourceName;
  676.  
  677.     // Allow the user to only 'copy' this item. 'Move doesn't make sense since
  678.     // the records will always stay in the source container.
  679.  
  680.     DragItem.fsSupportedOps = DO_COPYABLE;
  681.  
  682.     // Set the DRAGITEM struct into the memory allocated by
  683.     // DrgAllocDraginfo()
  684.  
  685.     DrgSetDragitem( pDragInfo, &DragItem, sizeof DragItem, iOffset );
  686.  
  687.     // Fill in the DRAGIMAGE structure
  688.  
  689.     pDragImage->cb       = sizeof( DRAGIMAGE );
  690.     pDragImage->hImage   = pCnrRec->mrc.hptrIcon; // DragImage under mouse
  691.     pDragImage->fl       = DRG_ICON;              // hImage is an HPOINTER
  692.     pDragImage->cxOffset = 5 * iOffset;           // Image offset from mouse ptr
  693.     pDragImage->cyOffset = 5 * iOffset;           // Image offset from mouse ptr
  694.  
  695.     // Set source emphasis for this container record
  696.  
  697.     if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETRECORDEMPHASIS,
  698.                         MPFROMP( pCnrRec ), MPFROM2SHORT( TRUE, CRA_SOURCE ) ) )
  699.         Msg( "SetOneDragItem..CM_SETRECORDEMPHASIS RC(%X)",
  700.              HWNDERR( hwndFrame ) );
  701. }
  702.  
  703. /**********************************************************************/
  704. /*------------------------ ProcessDroppedItem ------------------------*/
  705. /*                                                                    */
  706. /*  PROCESS A DRAGITEM THAT HAS BEEN DROPPED ON US                    */
  707. /*                                                                    */
  708. /*  PARMS: frame window handle,                                       */
  709. /*         pointer to the DRAGINFO structure,                         */
  710. /*         pointer to DRAGITEM structure,                             */
  711. /*         pointer to DRAGTRANSFER structure to use on DM_RENDER msg  */
  712. /*                                                                    */
  713. /*  NOTES:                                                            */
  714. /*                                                                    */
  715. /*  RETURNS: nothing                                                  */
  716. /*                                                                    */
  717. /*--------------------------------------------------------------------*/
  718. /**********************************************************************/
  719. void ProcessDroppedItem( HWND hwndFrame, PDRAGINFO pDragInfo,
  720.                          PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer )
  721. {
  722.     PSZ     pszString, pszLoc;
  723.     ULONG   cbString;
  724.     MRESULT mr;
  725.     char    szTempFileName[ CCHMAXPATH ];
  726.  
  727.     // We will ask the source to 'render' into a temporary file. This next
  728.     // function gets a temporary file name to use.
  729.  
  730.     FindTempFile( szTempFileName );
  731.  
  732.     // Form a 'database:table' string by combining the database found in
  733.     // hstrContainerName with the table found in hstrSourceName.
  734.  
  735.     cbString = DrgQueryStrNameLen( pDragItem->hstrContainerName ) +
  736.                DrgQueryStrNameLen( pDragItem->hstrSourceName ) +
  737.                2;  // Null terminator plus colon
  738.  
  739.     pszString = pszLoc = _alloca( cbString );
  740.  
  741.     DrgQueryStrName( pDragItem->hstrContainerName, cbString, pszLoc );
  742.     strcat( pszString, ":" );
  743.     pszLoc += strlen( pszString );
  744.     cbString -= strlen( pszString );
  745.     DrgQueryStrName( pDragItem->hstrSourceName, cbString, pszLoc );
  746.  
  747.     // Fill in the DRAGTRANSFER structure. This structure is used throughout
  748.     // the rendering process and is exchanged between the source and the
  749.     // target.
  750.  
  751.     memset( pDragXfer, 0, sizeof( DRAGTRANSFER ) );
  752.     pDragXfer->cb               = sizeof( DRAGTRANSFER );
  753.  
  754.     // hwndClient identifies the target window
  755.  
  756.     pDragXfer->hwndClient       = hwndFrame;
  757.     pDragXfer->pditem           = pDragItem;
  758.  
  759.     // hstrSelectedRMF is the Rendering Mechanism/Format used during the
  760.     // rendering. Remember that the hstrRMF field of the DRAGITEM structure
  761.     // can contain multiple mechanisms and formats. When we get down to the
  762.     // rendering stage we can use only one. In this program we only ever
  763.     // offered one so we use the same one that was placed in DRAGITEM.hstrRMF.
  764.     // In the real world we would first put the most native mechanism/format
  765.     // combination into hstrSelectedRMF and send the source a DM_RENDER. If the
  766.     // source responded to the DM_RENDER by returning DMFL_RENDERRETRY, we would
  767.     // then use the 'next best' RMF and try again by sending another DM_RENDER
  768.     // with the new hstrSelectedRMF. We'd do this until one was agreed upon.
  769.  
  770.     pDragXfer->hstrSelectedRMF  = DrgAddStrHandle( DRAG_RMF );
  771.  
  772.     // hstrRenderToName is the file name that we are asking the source to
  773.     // render into. In this program the source will copy the rows from the
  774.     // requested database:table into this file.
  775.  
  776.     pDragXfer->hstrRenderToName = DrgAddStrHandle( szTempFileName );
  777.  
  778.     // usOperation is where we'd indicate 'copy' or 'move'. In this program we
  779.     // will only do a logical copy operation so this field isn't even looked at.
  780.     // Typically this will stay the same as the usOperation field in the
  781.     // DRAGINFO field because that contains the last operation selected by the
  782.     // user.
  783.  
  784.     pDragXfer->usOperation      = pDragInfo->usOperation;
  785.  
  786.     // ulTargetInfo is a convenient place to store something between render
  787.     // messages.
  788.  
  789.     pDragXfer->ulTargetInfo     = 0;
  790.  
  791.     // Initialize this to 0. The source will place something in here if it
  792.     // returns FALSE from DM_RENDER.
  793.  
  794.     pDragXfer->fsReply          = 0;
  795.  
  796.     // If the source wanted to be notified before a render is to be sent,
  797.     // do it. This program doesn't use this mechanism but the multi-threaded
  798.     // version of this program does.
  799.  
  800.     if( pDragItem->fsControl & DC_PREPARE )
  801.          DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDERPREPARE,
  802.                              pDragXfer, NULL );
  803.  
  804.     // Tell the source to render
  805.  
  806.     mr = DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDER, pDragXfer, NULL );
  807.  
  808.     // MRESULT will be NULL if the source could not render
  809.  
  810.     if( !mr )
  811.     {
  812.         // If the source wants us to retry with another mechanism, tell it
  813.         // 'no' because all we can handle is DRM_FISHMAN.
  814.  
  815.         if( pDragXfer->fsReply & DMFL_RENDERRETRY )
  816.             DrgPostTransferMsg( pDragItem->hwndItem, DM_RENDERCOMPLETE,
  817.                                 pDragXfer, DMFL_RENDERFAIL, 0, FALSE );
  818.  
  819.         // If the source wants us to render, tell it 'no way'. It is the one
  820.         // that requested rendering in the first place.
  821.  
  822.         if( pDragXfer->fsReply & DMFL_NATIVERENDER )
  823.             DrgSendTransferMsg( pDragItem->hwndItem, DM_ENDCONVERSATION,
  824.                                 MPFROMLONG( pDragItem->ulItemID ),
  825.                                 MPFROMLONG( DMFL_TARGETFAIL ) );
  826.     }
  827. }
  828.  
  829. /**********************************************************************/
  830. /*-------------------------- FindTempFile ----------------------------*/
  831. /*                                                                    */
  832. /*  FIND AN AVAILABLE TEMPORARY FILE NAME.                            */
  833. /*                                                                    */
  834. /*  PARMS: pointer to buffer to hold filename                         */
  835. /*                                                                    */
  836. /*  NOTES: This is a rudimentary method for getting a temporary file  */
  837. /*         name. Usually you'd want to check the TEMP or TMP          */
  838. /*         environment variables first and use that as the directory  */
  839. /*         in which to place the temporary files. For a sample        */
  840. /*         program, this will do fine. Basically we just get use      */
  841. /*         the current path and a base filename and figure out an     */
  842. /*         extension by finding the first available one.              */
  843. /*                                                                    */
  844. /*  RETURNS: nothing                                                  */
  845. /*                                                                    */
  846. /*--------------------------------------------------------------------*/
  847. /**********************************************************************/
  848. void FindTempFile( PSZ pszTempFileName )
  849. {
  850.     PSZ         pszFileExt;
  851.     FILESTATUS3 fs;
  852.     int         i;
  853.     APIRET      rc;
  854.     FILE        *fhTemp;
  855.  
  856.     strcpy( pszTempFileName, szCurrentPath );
  857.     strcat( pszTempFileName, BASE_TEMPFILE_NAME );
  858.     strcat( pszTempFileName, "." );
  859.  
  860.     pszFileExt = pszTempFileName + strlen( pszTempFileName );
  861.  
  862.     for( i = 0; i < 1000; i++ )
  863.     {
  864.         _itoa( i, pszFileExt, 10 );
  865.  
  866.         rc = DosQueryPathInfo( pszTempFileName, FIL_STANDARD, &fs, sizeof fs );
  867.         if( rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND )
  868.         {
  869.             // Create the file so it exists and we won't try and use it for the
  870.             // next temporary file.
  871.  
  872.             fhTemp = fopen( pszTempFileName, "w" );
  873.             fclose( fhTemp );
  874.             break;
  875.         }
  876.     }
  877.  
  878.     if( i >= 1000 )
  879.         Msg( "Can't get a temporary file name!!!" );
  880. }
  881.  
  882. /**********************************************************************/
  883. /*----------------------------- Render -------------------------------*/
  884. /*                                                                    */
  885. /*  PROCESS A DM_RENDER MESSAGE                                       */
  886. /*                                                                    */
  887. /*  PARMS: frame window handle,                                       */
  888. /*         pointer to a DRAGTRANSFER structure                        */
  889. /*                                                                    */
  890. /*  NOTES: This is a SOURCE window message                            */
  891. /*                                                                    */
  892. /*  RETURNS: MRESULT explaining the rendering availability            */
  893. /*                                                                    */
  894. /*--------------------------------------------------------------------*/
  895. /**********************************************************************/
  896. MRESULT Render( HWND hwndFrame, PDRAGTRANSFER pDragXfer )
  897. {
  898.     hwndFrame=hwndFrame;    // Keep the compiler happy
  899.     pDragXfer=pDragXfer;
  900.  
  901.     // Normally here we would check some things and return TRUE if everything
  902.     // looked OK or we would return FALSE and set pDragXfer->fsReply to the
  903.     // reason for the FALSE. A typical reason to return FALSE would be if
  904.     // pDragXfer->hstrSelectedRMF was something we couldn't support or
  905.     // pDragXfer->usOperation was something we didn't want to do. In that case
  906.     // we'd return FALSE and set fsReply to DMFL_RENDERRETRY. It would then be
  907.     // up to the target to change its parameters and send us another DM_RENDER.
  908.  
  909.     return (MRESULT) TRUE;
  910. }
  911.  
  912. /**********************************************************************/
  913. /*------------------------- DoTheRendering ---------------------------*/
  914. /*                                                                    */
  915. /*  DO THE RENDERING.                                                 */
  916. /*                                                                    */
  917. /*  PARMS: pointer to a DRAGTRANSFER structure                        */
  918. /*                                                                    */
  919. /*  NOTES: This is a SOURCE window message                            */
  920. /*                                                                    */
  921. /*  RETURNS: nothing                                                  */
  922. /*                                                                    */
  923. /*--------------------------------------------------------------------*/
  924. /**********************************************************************/
  925. void DoTheRendering( PDRAGTRANSFER pDragXfer )
  926. {
  927.     PSZ   pszTableName, pszFileName, pszLoc;
  928.     ULONG cbString, flStatus = DMFL_RENDEROK;
  929.  
  930.     // Form the 'database:table' string by combining the database name which
  931.     // is stored in hstrContainerName with the table name which is stored in
  932.     // hstrSourceName.
  933.  
  934.     cbString = DrgQueryStrNameLen( pDragXfer->pditem->hstrContainerName ) +
  935.                DrgQueryStrNameLen( pDragXfer->pditem->hstrSourceName ) +
  936.                2;  // Null terminator plus colon
  937.  
  938.     pszTableName = pszLoc = _alloca( cbString );
  939.  
  940.     DrgQueryStrName( pDragXfer->pditem->hstrContainerName, cbString, pszLoc );
  941.     strcat( pszTableName, ":" );
  942.     pszLoc += strlen( pszTableName );
  943.     cbString -= strlen( pszTableName );
  944.     DrgQueryStrName( pDragXfer->pditem->hstrSourceName, cbString, pszLoc );
  945.  
  946.     // Get the file name that we (the source) should be rendering to. This
  947.     // name was decided by the target before it sent us the DM_RENDER message.
  948.  
  949.     cbString = DrgQueryStrNameLen( pDragXfer->hstrRenderToName ) + 1;
  950.     pszFileName = _alloca( cbString );
  951.     DrgQueryStrName( pDragXfer->hstrRenderToName, cbString, pszFileName );
  952.  
  953.     // Call this function which will copy the database data into the file.
  954.  
  955.     if( !dbRenderToFile( pszTableName, pszFileName ) )
  956.         flStatus = DMFL_RENDERFAIL;
  957.  
  958.     // Tell the target that we're done.
  959.  
  960.     DrgPostTransferMsg( pDragXfer->hwndClient, DM_RENDERCOMPLETE, pDragXfer,
  961.                         flStatus, 0, FALSE );
  962.  
  963.     // Bot the target and the source must free this. Since we're done at the
  964.     // source, it is time to free it.
  965.  
  966.     DrgFreeDragtransfer( pDragXfer );
  967. }
  968.  
  969. /**********************************************************************/
  970. /*------------------------- RenderComplete ---------------------------*/
  971. /*                                                                    */
  972. /*  PROCESS A DM_RENDERCOMPLETE MESSAGE                               */
  973. /*                                                                    */
  974. /*  PARMS: frame window handle,                                       */
  975. /*         pointer to a DRAGTRANSFER structure,                       */
  976. /*         flags describing the render operation                      */
  977. /*                                                                    */
  978. /*  NOTES: This is a TARGET window message sent by the source when it */
  979. /*         has completed the rendering.                               */
  980. /*                                                                    */
  981. /*  RETURNS: zero                                                     */
  982. /*                                                                    */
  983. /*--------------------------------------------------------------------*/
  984. /**********************************************************************/
  985. MRESULT RenderComplete( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
  986.                         USHORT fsRender )
  987. {
  988.     BOOL      fSuccess = TRUE;
  989.     ULONG     flStatus = DMFL_TARGETSUCCESSFUL;
  990.     PINSTANCE pi = INSTDATA( hwndFrame );
  991.  
  992.     // If the source responded with RENDEROK, that means we can count on the
  993.     // hstrRenderToFile file containing the data from the table in the database.
  994.     // In that case we insert a record into the 'drop' container that will
  995.     // represent that rendered file. The user can double-click on that icon and
  996.     // bring up a listbox with the file dumped into it.
  997.  
  998.     if( fsRender & DMFL_RENDEROK )
  999.     {
  1000.         PSZ          pszLoc;
  1001.         RECORDINSERT ri;
  1002.         PCNRREC      pCnrRec;
  1003.  
  1004.         memset( &ri, 0, sizeof( RECORDINSERT ) );
  1005.         ri.cb                 = sizeof( RECORDINSERT );
  1006.         ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  1007.         ri.pRecordParent      = (PRECORDCORE) NULL;
  1008.         ri.zOrder             = (USHORT) CMA_TOP;
  1009.         ri.cRecordsInsert     = 1;
  1010.         ri.fInvalidateRecord  = TRUE;
  1011.  
  1012.         pCnrRec = WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_ALLOCRECORD,
  1013.                                      MPFROMLONG( EXTRA_BYTES ),
  1014.                                      MPFROMLONG( 1 ) );
  1015.         if( pCnrRec )
  1016.         {
  1017.             DrgQueryStrName( pDragXfer->pditem->hstrContainerName,
  1018.                          sizeof( pCnrRec->szTableName ), pCnrRec->szTableName );
  1019.             strcat( pCnrRec->szTableName, ":" );
  1020.             pszLoc = pCnrRec->szTableName + strlen( pCnrRec->szTableName );
  1021.             DrgQueryStrName( pDragXfer->pditem->hstrSourceName,
  1022.                              sizeof( pCnrRec->szTableName ) -
  1023.                                     (pszLoc - pCnrRec->szTableName), pszLoc );
  1024.  
  1025.             DrgQueryStrName( pDragXfer->hstrRenderToName,
  1026.                              sizeof( pCnrRec->szRenderedFileName ),
  1027.                              pCnrRec->szRenderedFileName );
  1028.  
  1029.             pCnrRec->flAttr       = RECATTR_OPENABLE;
  1030.             pCnrRec->mrc.pszIcon  = (PSZ) &pCnrRec->szTableName;
  1031.             pCnrRec->mrc.hptrIcon = hptrOpenMe;
  1032.  
  1033.             if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_INSERTRECORD,
  1034.                                     MPFROMP( pCnrRec ), MPFROMP( &ri ) ) )
  1035.             {
  1036.                 fSuccess = FALSE;
  1037.                 Msg( "RenderComplete CM_INSERTRECORD RC(%X)",
  1038.                      HWNDERR( hwndFrame ) );
  1039.             }
  1040.         }
  1041.         else
  1042.         {
  1043.             fSuccess = FALSE;
  1044.             Msg( "RenderComplete CM_ALLOCRECORD RC(%X)", HWNDERR( hwndFrame ) );
  1045.         }
  1046.     }
  1047.     else
  1048.         fSuccess = FALSE;
  1049.  
  1050.     if( fSuccess )
  1051.     {
  1052.         CNRINFO cnri;
  1053.  
  1054.         cnri.cb           = sizeof( CNRINFO );
  1055.         cnri.pszCnrTitle  = szDroppedOnCnrTitle;
  1056.         WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETCNRINFO,
  1057.                            MPFROMP( &cnri ), MPFROMLONG( CMA_CNRTITLE ) );
  1058.     }
  1059.     else
  1060.     {
  1061.         // Delete the temporary file if the render failed.
  1062.  
  1063.         char szRenderToName[ CCHMAXPATH ];
  1064.  
  1065.         DrgQueryStrName( pDragXfer->hstrRenderToName, sizeof szRenderToName,
  1066.                          szRenderToName );
  1067.         DosDelete( szRenderToName );
  1068.         flStatus = DMFL_TARGETFAIL;
  1069.     }
  1070.  
  1071.     // Tell the source that we're all done here. At this point the Drag/Drop
  1072.     // is finally done.
  1073.  
  1074.     DrgSendTransferMsg( pDragXfer->pditem->hwndItem, DM_ENDCONVERSATION,
  1075.                         MPFROMLONG( pDragXfer->pditem->ulItemID ),
  1076.                         MPFROMLONG( flStatus ) );
  1077.  
  1078.     // It is the target's responsibility to delete the string handles.
  1079.  
  1080.     DrgDeleteStrHandle( pDragXfer->hstrSelectedRMF );
  1081.     DrgDeleteStrHandle( pDragXfer->hstrRenderToName );
  1082.  
  1083.     // Both the source and target must free the DRAGTRANSFER structure. The
  1084.     // source will have done this before it sent us the DM_RENDERCOMPLETE
  1085.     // message.
  1086.  
  1087.     DrgFreeDragtransfer( pDragXfer );
  1088.  
  1089.     // We need to keep a running total to know when all items in the drop have
  1090.     // been processed. When that happens, it is time to free the resources that
  1091.     // were allocated to the drop as a whole rather than to an indidvidual item.
  1092.  
  1093.     if( --pi->cDragItems == 0 )
  1094.         TargetCleanup( hwndFrame );
  1095.  
  1096.     return 0;
  1097. }
  1098.  
  1099. /**********************************************************************/
  1100. /*-------------------------- EndConversation -------------------------*/
  1101. /*                                                                    */
  1102. /*  FREE THE RESOURCES USED BY DRAG/DROP PROCESSING. ONLY DO THIS IF  */
  1103. /*  THIS IS THE LAST ITEM (there is one end-conversation message sent */
  1104. /*  to us for each item dropped).                                     */
  1105. /*                                                                    */
  1106. /*  PARMS: frame window handle                                        */
  1107. /*                                                                    */
  1108. /*  NOTES: This is a SOURCE window message that the target sends after*/
  1109. /*         it is done processing the DM_RENDERCOMPLETE message that   */
  1110. /*         the source sent it.                                        */
  1111. /*                                                                    */
  1112. /*  RETURNS: nothing                                                  */
  1113. /*                                                                    */
  1114. /*--------------------------------------------------------------------*/
  1115. /**********************************************************************/
  1116. MRESULT EndConversation( HWND hwndFrame )
  1117. {
  1118.     PINSTANCE pi = INSTDATA( hwndFrame );
  1119.  
  1120.     if( !pi )
  1121.     {
  1122.         Msg( "EndConversation cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
  1123.         return 0;
  1124.     }
  1125.  
  1126.     // We need to keep a running total to know when all items in the drop have
  1127.     // been processed. When that happens, it is time to free the resources that
  1128.     // were allocated to the drag as a whole rather than to an indidvidual item.
  1129.  
  1130.     if( --pi->cDragItems == 0 )
  1131.         SourceCleanup( hwndFrame );
  1132.  
  1133.     return 0;
  1134. }
  1135.  
  1136. /**********************************************************************/
  1137. /*----------------------- RemoveSourceEmphasis -----------------------*/
  1138. /*                                                                    */
  1139. /*  REMOVE SOURCE EMPHASIS FROM THE DRAGGED RECORDS.                  */
  1140. /*                                                                    */
  1141. /*  PARMS: frame window handle                                        */
  1142. /*                                                                    */
  1143. /*  NOTES:                                                            */
  1144. /*                                                                    */
  1145. /*  RETURNS: nothing                                                  */
  1146. /*                                                                    */
  1147. /*--------------------------------------------------------------------*/
  1148. /**********************************************************************/
  1149. void RemoveSourceEmphasis( HWND hwndFrame )
  1150. {
  1151.     PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  1152.  
  1153.     // For every record with source emphasis, remove it.
  1154.  
  1155.     while( pCnrRec )
  1156.     {
  1157.         pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  1158.                                             CM_QUERYRECORDEMPHASIS,
  1159.                                             MPFROMP( pCnrRec ),
  1160.                                             MPFROMSHORT( CRA_SOURCE ) );
  1161.  
  1162.         if( pCnrRec == (PCNRREC) -1 )
  1163.             Msg( "RemoveSourceEmphasis..CM_QUERYRECORDEMPHASIS RC(%X)",
  1164.                  HWNDERR( hwndFrame ) );
  1165.         else if( pCnrRec )
  1166.             if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  1167.                                     CM_SETRECORDEMPHASIS, MPFROMP( pCnrRec ),
  1168.                                     MPFROM2SHORT( FALSE, CRA_SOURCE ) ) )
  1169.                 Msg( "RemoveSourceEmphasis..CM_SETRECORDEMPHASIS RC(%X)",
  1170.                      HWNDERR( hwndFrame ) );
  1171.     }
  1172. }
  1173.  
  1174. /**********************************************************************/
  1175. /*--------------------------- TargetCleanup --------------------------*/
  1176. /*                                                                    */
  1177. /*  FREE THE RESOURCES USED BY DRAG/DROP PROCESSING FOR THE TARGET    */
  1178. /*                                                                    */
  1179. /*  PARMS: frame window handle                                        */
  1180. /*                                                                    */
  1181. /*  NOTES:                                                            */
  1182. /*                                                                    */
  1183. /*  RETURNS: nothing                                                  */
  1184. /*                                                                    */
  1185. /*--------------------------------------------------------------------*/
  1186. /**********************************************************************/
  1187. void TargetCleanup( HWND hwndFrame )
  1188. {
  1189.     PINSTANCE pi = INSTDATA( hwndFrame );
  1190.  
  1191.     if( !pi )
  1192.     {
  1193.         Msg( "TargetCleanup cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
  1194.         return;
  1195.     }
  1196.  
  1197.     // It is the target's responsibility to delete the string resources. This
  1198.     // one API frees all the strings in all DRAGITEM structures.
  1199.  
  1200.     if( !DrgDeleteDraginfoStrHandles( pi->pSavedDragInfo ) )
  1201.         Msg( "TargetCleanup DrgDeleteDraginfoStrHandles RC(%X)",
  1202.              HWNDERR( hwndFrame ) );
  1203.  
  1204.     // Both the source and target must free the DRAGINFO structure.
  1205.  
  1206.     if( !DrgFreeDraginfo( pi->pSavedDragInfo ) &&
  1207.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  1208.         Msg( "TargetCleanup DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  1209.  
  1210.     pi->pSavedDragInfo = NULL;
  1211.     pi->cDragItems     = 0;
  1212. }
  1213.  
  1214. /**********************************************************************/
  1215. /*--------------------------- SourceCleanup --------------------------*/
  1216. /*                                                                    */
  1217. /*  FREE THE RESOURCES USED BY DRAG/DROP PROCESSING FOR THE SOURCE    */
  1218. /*                                                                    */
  1219. /*  PARMS: frame window handle                                        */
  1220. /*                                                                    */
  1221. /*  NOTES:                                                            */
  1222. /*                                                                    */
  1223. /*  RETURNS: nothing                                                  */
  1224. /*                                                                    */
  1225. /*--------------------------------------------------------------------*/
  1226. /**********************************************************************/
  1227. void SourceCleanup( HWND hwndFrame )
  1228. {
  1229.     PINSTANCE pi = INSTDATA( hwndFrame );
  1230.  
  1231.     if( !pi )
  1232.     {
  1233.         Msg( "SourceCleanup cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
  1234.         return;
  1235.     }
  1236.  
  1237.     // Free the shared memory we got access to using DrgAccessDragInfo. If
  1238.     // the source process is the same as the target process, we get the
  1239.     // PMERR_SOURCE_SAME_AS_TARGET message. It's ok to get that - it just
  1240.     // means that we don't need to free the structure because the target
  1241.     // process already freed it.
  1242.  
  1243.     if( !DrgFreeDraginfo( pi->pSavedDragInfo ) &&
  1244.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  1245.         Msg( "SourceCleanup DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  1246.  
  1247.     // This is important because the NULL-ness of pSavedDragInfo lets the
  1248.     // dragInit function know that another drag is now possible.
  1249.  
  1250.     pi->pSavedDragInfo = NULL;
  1251.     pi->cDragItems     = 0;
  1252. }
  1253.  
  1254. /*************************************************************************
  1255.  *                     E N D     O F     S O U R C E                     *
  1256.  *************************************************************************/
  1257.