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

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  drag.c                 AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  07-20-93                                           *
  5.  *                                                                   *
  6.  * MODULE DESCRIPTION:                                               *
  7.  *                                                                   *
  8.  *  Part of the 'DRGDROP' drag/drop sample program.                  *
  9.  *                                                                   *
  10.  *  This module handles all the Drag/Drop processing for the         *
  11.  *  DRGDROP.EXE sample program.                                      *
  12.  *                                                                   *
  13.  * NOTES:                                                            *
  14.  *                                                                   *
  15.  *  There is no source rendering done in this sample program. For a  *
  16.  *  sample that does that, get my DRGRENDR.EXE sample, or            *
  17.  *  DRGTHRND.EXE that does rendering in secondary threads.           *
  18.  *                                                                   *
  19.  * FUNCTIONS AVALABLE TO OTHER MODULES:                              *
  20.  *                                                                   *
  21.  *   dragMessage                                                     *
  22.  *   dragInit                                                        *
  23.  *   dragOver                                                        *
  24.  *   dragLeave                                                       *
  25.  *   dragDrop                                                        *
  26.  *                                                                   *
  27.  *                                                                   *
  28.  * HISTORY:                                                          *
  29.  *                                                                   *
  30.  *  07-20-93 - Program coded.                                        *
  31.  *                                                                   *
  32.  *  Rick Fishman                                                     *
  33.  *  Code Blazers, Inc.                                               *
  34.  *  4113 Apricot                                                     *
  35.  *  Irvine, CA. 92720                                                *
  36.  *  CIS ID: 72251,750                                                *
  37.  *                                                                   *
  38.  *********************************************************************/
  39.  
  40. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  41.  
  42. /*********************************************************************/
  43. /*------- Include relevant sections of the OS/2 header files --------*/
  44. /*********************************************************************/
  45.  
  46. #define  INCL_DEV
  47. #define  INCL_DOSERRORS
  48. #define  INCL_DOSPROCESS
  49. #define  INCL_SHLERRORS
  50. #define  INCL_WINDIALOGS
  51. #define  INCL_WINERRORS
  52. #define  INCL_WINFRAMEMGR
  53. #define  INCL_WININPUT
  54. #define  INCL_WINPOINTERS
  55. #define  INCL_WINSTDCNR
  56. #define  INCL_WINSTDDRAG
  57. #define  INCL_WINWINDOWMGR
  58.  
  59. /**********************************************************************/
  60. /*----------------------------- INCLUDES -----------------------------*/
  61. /**********************************************************************/
  62.  
  63. #include <os2.h>
  64. #include <ctype.h>
  65. #include <stdio.h>
  66. #include <stdlib.h>
  67. #include <string.h>
  68. #include "drgdrop.h"
  69.  
  70. /*********************************************************************/
  71. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  72. /*********************************************************************/
  73.  
  74. #define DOC_NAME  "DrgDrop"
  75.  
  76. /**********************************************************************/
  77. /*---------------------------- STRUCTURES ----------------------------*/
  78. /**********************************************************************/
  79.  
  80.  
  81. /**********************************************************************/
  82. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  83. /**********************************************************************/
  84.  
  85. int     CountSelectedRecs   ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  86.                               PBOOL pfUseSelectedRecs );
  87. void    SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
  88.                               PDRAGIMAGE pDragImage );
  89. void    SetOneDragItem      ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  90.                               PDRAGINFO pDragInfo, PDRAGIMAGE pDragImage,
  91.                               int iOffset );
  92. USHORT  DetermineDefaultOp  ( PDRAGINFO pDragInfo );
  93. void    ProcessDroppedItem  ( HWND hwndFrame, PDRAGITEM pDragItem );
  94. MRESULT DiscardObjects      ( HWND hwndFrame, PDRAGINFO pDragInfo );
  95. MRESULT PrintObject         ( HWND hwndFrame, PDRAGITEM pDragItem,
  96.                               PPRINTDEST pPrintDest );
  97. MRESULT EndConversation     ( HWND hwndFrame, PCNRREC pCnrRec, ULONG flSuccess);
  98. void    DragoverNotify      ( HWND hwndFrame, PDRAGINFO pDraginfo, MRESULT mr );
  99. void    RemoveSourceEmphasis( HWND hwndFrame );
  100.  
  101. FNWP wpSource, wpTarget;
  102.  
  103. /**********************************************************************/
  104. /*------------------------ GLOBAL VARIABLES --------------------------*/
  105. /**********************************************************************/
  106.  
  107. extern char szDragCnrTitle[];
  108.  
  109. /**********************************************************************/
  110. /*--------------------------- dragMessage ----------------------------*/
  111. /*                                                                    */
  112. /*  A DM_ MESSAGE WAS RECEIVED BY THE FRAME WINDOW PROCEDURE.         */
  113. /*                                                                    */
  114. /*  PARMS: frame window handle,                                       */
  115. /*         message id,                                                */
  116. /*         mp1 of the message,                                        */
  117. /*         mp2 of the message                                         */
  118. /*                                                                    */
  119. /*  NOTES:                                                            */
  120. /*                                                                    */
  121. /*  RETURNS: return code of message                                   */
  122. /*                                                                    */
  123. /*--------------------------------------------------------------------*/
  124. /**********************************************************************/
  125. MRESULT dragMessage( HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2 )
  126. {
  127.     switch( msg )
  128.     {
  129.         case DM_ENDCONVERSATION: // The SOURCE window gets this message
  130.             return EndConversation( hwndFrame, (PCNRREC) mp1, (ULONG) mp2 );
  131.  
  132.         case DM_PRINTOBJECT:
  133.             return PrintObject( hwndFrame, (PDRAGITEM) mp1, (PPRINTDEST) mp2 );
  134.  
  135.         case DM_DISCARDOBJECT:
  136.             return DiscardObjects( hwndFrame, (PDRAGINFO) mp1 );
  137.  
  138.         // The rest of these messages aren't really processed in this program.
  139.         // They are just used to display the contents of the Drag/Drop
  140.         // structures and to minimally process the message to allow the
  141.         // Drag/Drop operation to continue. None of the DrgDragFiles() messages
  142.         // are processed in this program.
  143.  
  144.         case DM_DRAGOVERNOTIFY:
  145.             DragoverNotify( hwndFrame, (PDRAGINFO) mp1, (MRESULT) mp2 );
  146.             return 0;
  147.  
  148.         case DM_DROPHELP:
  149.             dbgInsert( INSTDATA( hwndFrame )->hwndDebug,
  150.                        "DM_DROPHELP received" );
  151.             return 0;
  152.  
  153.         case DM_RENDER:
  154.             showDragTransfer( hwndFrame, "DM_RENDER (returning TRUE)",
  155.                               (PDRAGTRANSFER) mp1 );
  156.             return (MRESULT) TRUE;
  157.  
  158.         case DM_RENDERCOMPLETE:
  159.             showDragTransfer( hwndFrame, "DM_RENDERCOMPLETE",
  160.                              (PDRAGTRANSFER) mp1 );
  161.             return 0;
  162.  
  163.         case DM_RENDERPREPARE:
  164.             showDragTransfer( hwndFrame, "DM_RENDERPREPARE",
  165.                              (PDRAGTRANSFER) mp1 );
  166.             return (MRESULT) TRUE;
  167.     }
  168.  
  169.     return 0;
  170. }
  171.  
  172. /**********************************************************************/
  173. /*----------------------------- dragInit -----------------------------*/
  174. /*                                                                    */
  175. /*  PROCESS CN_INITDRAG NOTIFY MESSAGE.                               */
  176. /*                                                                    */
  177. /*  PARMS: frame window handle,                                       */
  178. /*         pointer to the CNRDRAGINIT structure                       */
  179. /*                                                                    */
  180. /*  NOTES: the CN_INITDRAG message is equivalent to the WM_BEGINDRAG  */
  181. /*         message. The reason I mention this is because if the source*/
  182. /*         window in the drag is not a container you will get the     */
  183. /*         WM_BEGINDRAG message.                                      */
  184. /*                                                                    */
  185. /*         WM_BEGINDRAG is sent to windows to allow them to know that */
  186. /*         the user is requesting a drag from their window. This      */
  187. /*         message contains only the x,y coordinates of the mouse at  */
  188. /*         the time of WM_BEGINDRAG.                                  */
  189. /*                                                                    */
  190. /*         The reason for CN_INITDRAG is first so that the container  */
  191. /*         can notify its owner when it gets a WM_BEGINDRAG message   */
  192. /*         and second so that the container can give its owner more   */
  193. /*         info, like what container record the mouse pointer is over.*/
  194. /*         To accomplish this, the container packages up this informa-*/
  195. /*         tion in a CNRDRAGINIT structure and sends that structure   */
  196. /*         along with the CN_INITDRAG message.                        */
  197. /*                                                                    */
  198. /*  RETURNS: nothing                                                  */
  199. /*                                                                    */
  200. /*--------------------------------------------------------------------*/
  201. /**********************************************************************/
  202. void dragInit( HWND hwndFrame, PCNRDRAGINIT pcdi )
  203. {
  204.     PCNRREC     pCnrRecUnderMouse = (PCNRREC) pcdi->pRecord;
  205.     PDRAGIMAGE  pDragImage = NULL;
  206.     PDRAGINFO   pDragInfo = NULL;
  207.     BOOL        fUseSelectedRecs;
  208.     PINSTANCE   pi = INSTDATA( hwndFrame );
  209.     int         cRecs;
  210.  
  211.     if( !pi )
  212.     {
  213.         Msg( "dragInit cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  214.         return;
  215.     }
  216.  
  217.     // pSavedDragInfo is used during drop processing. When the drop is complete
  218.     // (the source gets a DM_ENDCONVERSATION message from the target), the
  219.     // source will free the DRAGINFO structure and set this field to NULL.
  220.     // So pSavedDragInfo is non-NULL if a drop has not yet completed. In this
  221.     // case we make it easy on ourselves by not allowing another drag. The
  222.     // reason for this is that if we allow another drag to take place we will
  223.     // need to overwrite this pSavedDragInfo field in which case the drop
  224.     // processing would not free the right DRAGINFO structure. Obviously in a
  225.     // commercial app you'd want to use a different mechanism for storing the
  226.     // DRAGINFO structure, like a linked list, so you could start another drag
  227.     // while the drop is in progress.
  228.  
  229.     if( pi->pSavedDragInfo )
  230.     {
  231.         WinAlarm( HWND_DESKTOP, WA_WARNING );
  232.         return;
  233.     }
  234.  
  235.     // Count the records that have CRA_SELECTED emphasis. Also return whether
  236.     // or not we should process the CRA_SELECTED records. If the container
  237.     // record under the mouse does not have this emphasis, we shouldn't. In that
  238.     // case we would just process the record under the mouse.
  239.  
  240.     cRecs = CountSelectedRecs( hwndFrame, pCnrRecUnderMouse, &fUseSelectedRecs);
  241.  
  242.     if( cRecs )
  243.     {
  244.         int iDragImageArraySize = cRecs * sizeof( DRAGIMAGE );
  245.  
  246.         // Allocate an array of DRAGIMAGE structures. Each structure contains
  247.         // info about an image that will be under the mouse pointer during the
  248.         // drag. This image will represent a container record being dragged.
  249.  
  250.         pDragImage = (PDRAGIMAGE) malloc( iDragImageArraySize );
  251.  
  252.         if( pDragImage )
  253.         {
  254.             memset( pDragImage, 0, iDragImageArraySize );
  255.  
  256.             // Let PM allocate enough memory for a DRAGINFO structure as well
  257.             // as a DRAGITEM structure for each record being dragged. It will
  258.             // allocate shared memory so other processes can participate in the
  259.             // drag/drop.
  260.  
  261.             pDragInfo = DrgAllocDraginfo( cRecs );
  262.  
  263.             if( pDragInfo )
  264.             {
  265.                 pi->pSavedDragInfo = pDragInfo;
  266.                 pi->cDragItems = cRecs;
  267.             }
  268.             else
  269.                 Msg( "DrgAllocDraginfo failed. RC(%X)", HWNDERR( hwndFrame ) );
  270.         }
  271.         else
  272.             Msg( "Out of memory in dragInit" );
  273.     }
  274.  
  275.     if( cRecs && pDragInfo && pDragImage )
  276.     {
  277.         // Make sure the data in the dlgInfo structure is current.
  278.  
  279.         bookRefreshDlgInfo();
  280.  
  281.         // Set the data from the container records into the DRAGITEM and
  282.         // DRAGIMAGE structures. If we are to process CRA_SELECTED container
  283.         // records, do them all in one function. If not, pass a pointer to the
  284.         // container record under the mouse to a different function that will
  285.         // fill in just one DRAGITEM / DRAGIMAGE structure.
  286.  
  287.         if( fUseSelectedRecs )
  288.             SetSelectedDragItems( hwndFrame, cRecs, pDragInfo, pDragImage );
  289.         else
  290.             SetOneDragItem( hwndFrame, pCnrRecUnderMouse, pDragInfo,
  291.                             pDragImage, 0 );
  292.  
  293.         showDragInfo( hwndFrame, "CN_INITDRAG", pDragInfo );
  294.  
  295.         // If DrgDrag returns NULLHANDLE, that means the user hit Esc or F1
  296.         // while the drag was going on so the target didn't have a chance to
  297.         // delete the string handles. So it is up to the source window to do
  298.         // it. Unfortunately there doesn't seem to be a way to determine
  299.         // whether the NULLHANDLE means Esc was pressed as opposed to there
  300.         // being an error in the drag operation. So we don't attempt to figure
  301.         // that out. To us, a NULLHANDLE means Esc was pressed...
  302.  
  303.         if( !DrgDrag( hwndFrame, pDragInfo, pDragImage, cRecs, VK_ENDDRAG,
  304.                       NULL ) )
  305.         {
  306.             if( !DrgDeleteDraginfoStrHandles( pDragInfo ) )
  307.                 Msg( "dragInit DrgDeleteDraginfoStrHandles RC(%X)",
  308.                      HWNDERR( hwndFrame ) );
  309.  
  310.             if( !DrgFreeDraginfo( pDragInfo ) )
  311.                 Msg( "dragInit DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  312.  
  313.             pi->pSavedDragInfo = NULL;
  314.         }
  315.  
  316.         // Take off source emphasis from the records that were dragged
  317.  
  318.         RemoveSourceEmphasis( hwndFrame );
  319.     }
  320.  
  321.     if( pDragImage )
  322.         free( pDragImage );
  323. }
  324.  
  325. /**********************************************************************/
  326. /*----------------------------- dragOver -----------------------------*/
  327. /*                                                                    */
  328. /*  PROCESS CN_DRAGOVER NOTIFY MESSAGE.                               */
  329. /*                                                                    */
  330. /*  PARMS: frame window handle,                                       */
  331. /*         pointer to the CNRDRAGINFO structure                       */
  332. /*                                                                    */
  333. /*  NOTES: The container sends the CN_DRAGOVER message to its owner   */
  334. /*         when it gets a DM_DRAGOVER message. The container takes    */
  335. /*         the info it gets on the DM_DRAGOVER message and combines   */
  336. /*         it with other container-specific dragover info into a      */
  337. /*         CNRDRAGINFO structure, then passes a pointer to that       */
  338. /*         structure to its owner in the CN_DRAGOVER message.         */
  339. /*                                                                    */
  340. /*  RETURNS: return value from CN_DRAGOVER processing                 */
  341. /*           1st USHORT (Drop Indicator)                              */
  342. /*                                                                    */
  343. /*             - DOR_DROP      - OK to drop                           */
  344. /*             - DOR_NODROP    - Not OK to drop at this x,y           */
  345. /*             - DOR_NODROPOP  - Not OK to drop because of the        */
  346. /*                               drop operation.                      */
  347. /*             - DOR_NEVERDROP - Not OK to drop and never will be OK  */
  348. /*                               to drop.                             */
  349. /*                                                                    */
  350. /*           2nd USHORT (Default Operation)                           */
  351. /*                                                                    */
  352. /*             - DO_COPY       - 'Copy' is the default operation      */
  353. /*             - DO_LINK       - 'Link' is the default operation      */
  354. /*             - DO_MOVE       - 'Move' is the default operation      */
  355. /*                                                                    */
  356. /*                                                                    */
  357. /*--------------------------------------------------------------------*/
  358. /**********************************************************************/
  359. MRESULT dragOver( HWND hwndFrame, PCNRDRAGINFO pcdi )
  360. {
  361.     USHORT    usDrop, usDefaultOp = 0;
  362.     PDRAGINFO pDragInfo = pcdi->pDragInfo;
  363.     PDRAGITEM pDragItem;
  364.     PINSTANCE pi = INSTDATA( hwndFrame );
  365.     int       i;
  366.  
  367.     if( !pi )
  368.     {
  369.         Msg( "dragOver cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  370.         return MRFROM2SHORT( DOR_NEVERDROP, 0 );
  371.     }
  372.  
  373.     // Note that the default operation doesn't mean anything if usDrop is not
  374.     // DOR_DROP.
  375.  
  376.     usDrop = 0;
  377.  
  378.     if( !DrgAccessDraginfo( pDragInfo ) )
  379.     {
  380.         Msg( "dragOver DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  381.         return MRFROM2SHORT( DOR_NEVERDROP, 0 );
  382.     }
  383.  
  384.     // We only want to display the full DRAGINFO structure in the debug window
  385.     // if it is the first DM_DRAGOVER message while over our window. If we
  386.     // display all of them the drag operation takes a real performance hit. If
  387.     // the drag operation changes (i.e. from a 'copy' to a 'move'), we
  388.     // re-display the DRAGINFO structure. We clear the fDragoverInProgress flag
  389.     // in the DM_DRAGLEAVE message.
  390.  
  391.     if( pi->fDragoverInProgress )
  392.         if( pi->usDragoverOp == pDragInfo->usOperation )
  393.             dbgInsert( pi->hwndDebug, " *** repeat DM_DRAGOVER" );
  394.         else
  395.         {
  396.             pi->usDragoverOp = pDragInfo->usOperation;
  397.             showDragInfo( hwndFrame, "DM_DRAGOVER", pDragInfo );
  398.         }
  399.     else
  400.     {
  401.         pi->usDragoverOp = pDragInfo->usOperation;
  402.         pi->fDragoverInProgress = TRUE;
  403.         showDragInfo( hwndFrame, "DM_DRAGOVER", pDragInfo );
  404.     }
  405.  
  406.     // Don't allow a window to drop on itself. Normally a container would allow
  407.     // this but it adds complexity to the drop code because the container would
  408.     // have to be set up without CCS_AUTOPOSITION and it would have to remove
  409.     // and re-insert the record so that it would stay in its proper new position.
  410.     // Code for this is in my CNRADV.ZIP program. Since it doesn't benefit a
  411.     // Drag/Drop sample I left it out of this program.
  412.  
  413.     if( pDragInfo->hwndSource == hwndFrame )
  414.         usDrop = DOR_NEVERDROP;
  415.  
  416.     // If the user hasn't changed the default of allowing all drops, we simply
  417.     // return and allow the drop with whatever operation is currently in
  418.     // progress. The reason for allowing all drops is so you can see exactly
  419.     // what would be in the DRAGITEM's and the DRAGINFO on the drop (in the
  420.     // debug window. If the user doesn't change this default in the dialog box,
  421.     // we allow the drop to happen but we don't do anything on the drop on an
  422.     // unacceptable combination except to send a DM_ENDCONVERSATION message with
  423.     // a return code of DMFL_TARGETFAIL.
  424.  
  425.     if( !usDrop && dlgInfo.fAllowAllDrops )
  426.     {
  427.         usDrop = DOR_DROP;
  428.         usDefaultOp = pDragInfo->usOperation;
  429.     }
  430.  
  431.     // If the current operation is 'unknown', we don't want to play guessing
  432.     // games so we'll ignore it. We'll allow the user to change the operation
  433.     // with the Shift,Ctrl keys and then we'll go further.
  434.  
  435.     if( !usDrop && pDragInfo->usOperation == DO_UNKNOWN )
  436.         usDrop = DOR_NODROPOP;
  437.  
  438.     // We must set the operation that we want to perform on the drop. This may
  439.     // mean changing the operation that the user is currently indicating that
  440.     // they want to do. For instance, we may change a 'move' operation to a
  441.     // 'copy'. We could also decide that we can't drop given the current
  442.     // operation. In any case, if we change the operation, the images being
  443.     // dragged will be changed automatically by PM. For example, if we change
  444.     // the operation from a move to a copy, PM will halftone the images.
  445.  
  446.     if( !usDrop || usDrop == DOR_DROP )
  447.         usDefaultOp = DetermineDefaultOp( pDragInfo );
  448.  
  449.     // Check each item. If one fails, we don't allow the drop. Note that you
  450.     // *could* accept the drop if some failed but that just makes the drop
  451.     // more difficult. What you would do is return DMFL_TARGETFAIL on the
  452.     // DM_ENDCONVERSATION message for the items that you cannot support.
  453.     // Normally all items use the same criteria though. So most-times if one
  454.     // item is ok, all items are ok.
  455.  
  456.     if( !usDrop )
  457.         for( i = 0; i < pDragInfo->cditem; i++ )
  458.         {
  459.             pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
  460.  
  461.             if( pDragItem )
  462.             {
  463.                 // Only allow a drop if the operation is able to be provided.
  464.  
  465.                 if( ((pDragItem->fsSupportedOps & DO_COPYABLE) &&
  466.                                     (usDefaultOp == DO_COPY)) ||
  467.                      ((pDragItem->fsSupportedOps & DO_MOVEABLE) &&
  468.                                     (usDefaultOp == DO_MOVE)) )
  469.                 {
  470.                     // The NULL as the last parameter means we don't care
  471.                     // about the Format, just the Rendering Mechanism.
  472.  
  473.                     if( DrgVerifyRMF( pDragItem, "DRM_OS2FILE", NULL ) )
  474.                         usDrop = DOR_DROP;
  475.                     else
  476.                     {
  477.                         usDrop = DOR_NEVERDROP;
  478.                         break;
  479.                     }
  480.                 }
  481.                 else
  482.                 {
  483.                    usDrop = DOR_NODROPOP;
  484.                    break;
  485.                 }
  486.             }
  487.             else
  488.                 Msg( "dragOver DrgQueryDragitemPtr RC(%X)", HWNDERR(hwndFrame));
  489.         }
  490.  
  491.     // If the user requested, via the Settings notebook, to use a specific
  492.     // drop action and default operation, use it.
  493.  
  494.     if( dlgInfo.fUseDlgDragOvers )
  495.     {
  496.         usDrop      = dlgInfo.usDragOverDrop;
  497.         usDefaultOp = dlgInfo.usDragOverDefOp;
  498.     }
  499.  
  500.     // Free our handle to the shared memory if the source window is not in our
  501.     // process.
  502.  
  503.     if( !DrgFreeDraginfo( pDragInfo ) &&
  504.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  505.         Msg( "dragOver DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  506.  
  507.     return MRFROM2SHORT( usDrop, usDefaultOp );
  508. }
  509.  
  510. /**********************************************************************/
  511. /*--------------------------- dragLeave ------------------------------*/
  512. /*                                                                    */
  513. /*  PROCESS CN_DRAGLEAVE NOTIFY MESSAGE.                              */
  514. /*                                                                    */
  515. /*  PARMS: frame window handle,                                       */
  516. /*         pointer to the CNRDRAGINFO structure                       */
  517. /*                                                                    */
  518. /*  NOTES: The container sends the CN_DRAGLEAVE message to its owner  */
  519. /*         when it gets a DM_DRAGLEAVE message. The container takes   */
  520. /*         the info it gets on the DM_DRAGLEAVE message and combines  */
  521. /*         it with other container-specific dragleave info into a     */
  522. /*         CNRDRAGINFO structure, then passes a pointer to that       */
  523. /*         structure to its owner in the CN_DRAGLEAVE message.        */
  524. /*                                                                    */
  525. /*  RETURNS: nothing                                                  */
  526. /*                                                                    */
  527. /*--------------------------------------------------------------------*/
  528. /**********************************************************************/
  529. void dragLeave( HWND hwndFrame, PCNRDRAGINFO pcdi )
  530. {
  531.     PDRAGINFO pDragInfo = pcdi->pDragInfo;
  532.     PINSTANCE pi = INSTDATA( hwndFrame );
  533.  
  534.     if( !pi )
  535.     {
  536.         Msg( "dragLeave cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  537.         return;
  538.     }
  539.  
  540.     pi->fDragoverInProgress = FALSE;
  541.  
  542.     if( !DrgAccessDraginfo( pDragInfo ) )
  543.     {
  544.         Msg( "dragLeave DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  545.         return;
  546.     }
  547.  
  548.     showDragInfo( hwndFrame, "DM_DRAGLEAVE", pDragInfo );
  549.  
  550.     if( !DrgFreeDraginfo( pDragInfo ) &&
  551.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  552.         Msg( "dragDrop DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  553. }
  554.  
  555. /**********************************************************************/
  556. /*---------------------------- dragDrop ------------------------------*/
  557. /*                                                                    */
  558. /*  PROCESS CN_DROP NOTIFY MESSAGE.                                   */
  559. /*                                                                    */
  560. /*  PARMS: frame window handle,                                       */
  561. /*         pointer to the CNRDRAGINFO structure                       */
  562. /*                                                                    */
  563. /*  NOTES: The container sends the CN_DROP message to its owner when  */
  564. /*         it gets a DM_DROP message. The container takes the info it */
  565. /*         gets on the DM_DROP message and combines it with other     */
  566. /*         container-specific dragover info into a CNRDRAGINFO        */
  567. /*         structure, then passes a pointer to that structure to its  */
  568. /*         owner in the CN_DROP message.                              */
  569. /*                                                                    */
  570. /*  RETURNS: nothing                                                  */
  571. /*                                                                    */
  572. /*--------------------------------------------------------------------*/
  573. /**********************************************************************/
  574. void dragDrop( HWND hwndFrame, PCNRDRAGINFO pcdi )
  575. {
  576.     PDRAGINFO pDragInfo = pcdi->pDragInfo;
  577.     PDRAGITEM pDragItem;
  578.     HWND      hwndCnr = WinWindowFromID( hwndFrame, FID_CLIENT );
  579.     CNRINFO   cnri;
  580.     BOOL      fRecordsExisted = FALSE;
  581.     int       i;
  582.     PINSTANCE pi = INSTDATA( hwndFrame );
  583.  
  584.     if( !pi )
  585.     {
  586.         Msg( "dragDrop cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
  587.         return;
  588.     }
  589.  
  590.     if( !DrgAccessDraginfo( pDragInfo ) )
  591.     {
  592.         Msg( "dragDrop DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  593.         return;
  594.     }
  595.  
  596.     showDragInfo( hwndFrame, "DM_DROP", pDragInfo );
  597.  
  598.     // Check if there are records in the container. If not, and we insert some
  599.     // later, we want to change the title of the container.
  600.  
  601.     WinSendMsg( hwndCnr, CM_QUERYCNRINFO, MPFROMP( &cnri ),
  602.                 MPFROMLONG( sizeof cnri ) );
  603.     if( cnri.cRecords )
  604.         fRecordsExisted = TRUE;
  605.  
  606.     // Process each DragItem. First get a pointer to it, then call a function
  607.     // that does the drop processing.
  608.  
  609.     for( i = 0; i < pDragInfo->cditem; i++ )
  610.     {
  611.         pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
  612.  
  613.         if( pDragItem )
  614.             ProcessDroppedItem( hwndFrame, pDragItem );
  615.         else
  616.             Msg( "dragDrop DrgQueryDragitemPtr RC(%X)", HWNDERR( hwndFrame ) );
  617.     }
  618.  
  619.     // If records were added to an empty container, change the title to give
  620.     // different instructions.
  621.  
  622.     if( !fRecordsExisted )
  623.     {
  624.         WinSendMsg( hwndCnr, CM_QUERYCNRINFO, MPFROMP( &cnri ),
  625.                     MPFROMLONG( sizeof cnri ) );
  626.         if( cnri.cRecords )
  627.         {
  628.             cnri.cb           = sizeof( CNRINFO );
  629.             cnri.pszCnrTitle  = szDragCnrTitle;
  630.             WinSendMsg( hwndCnr, CM_SETCNRINFO, MPFROMP( &cnri ),
  631.                         MPFROMLONG( CMA_CNRTITLE ) );
  632.         }
  633.     }
  634.  
  635.     // If a drop happens, the DM_DRAGLEAVE doesn't get sent so we must turn off
  636.     // that flag here.
  637.  
  638.     pi->fDragoverInProgress = FALSE;
  639.  
  640.     // It is the target's responsibility to delete the string resources. This
  641.     // one API frees all the strings in all DRAGITEM structures.
  642.  
  643.     if( !DrgDeleteDraginfoStrHandles( pDragInfo ) )
  644.         Msg( "dragDrop DrgDeleteDraginfoStrHandles RC(%X)", HWNDERR(hwndFrame));
  645.  
  646.     // Both the source and target must free the DRAGINFO structure.
  647.  
  648.     if( !DrgFreeDraginfo( pDragInfo ) &&
  649.         PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  650.         Msg( "dragDrop DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  651. }
  652.  
  653. /**********************************************************************/
  654. /*------------------------ CountSelectedRecs -------------------------*/
  655. /*                                                                    */
  656. /*  COUNT THE NUMBER OF RECORDS THAT ARE CURRENTLY SELECTED.          */
  657. /*                                                                    */
  658. /*  PARMS: frame window handle,                                       */
  659. /*         pointer to the record that was under the pointer,          */
  660. /*         address of BOOL - should we process selected records?      */
  661. /*                                                                    */
  662. /*  NOTES:                                                            */
  663. /*                                                                    */
  664. /*  RETURNS: number of records to process                             */
  665. /*                                                                    */
  666. /*--------------------------------------------------------------------*/
  667. /**********************************************************************/
  668. int CountSelectedRecs( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
  669.                        PBOOL pfUseSelectedRecs )
  670. {
  671.     int cRecs = 0;
  672.  
  673.     *pfUseSelectedRecs = FALSE;
  674.  
  675.     // If the record under the mouse is NULL, we must be over whitespace, in
  676.     // which case we don't want to drag any records.
  677.  
  678.     if( pCnrRecUnderMouse )
  679.     {
  680.         PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  681.  
  682.         // Count the records with 'selection' emphasis. These are the records
  683.         // we want to drag, unless the container record under the mouse does
  684.         // not have selection emphasis. If that is the case, we only want to
  685.         // process that one.
  686.  
  687.         while( pCnrRec )
  688.         {
  689.             pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  690.                                                    CM_QUERYRECORDEMPHASIS,
  691.                                                    MPFROMP( pCnrRec ),
  692.                                                    MPFROMSHORT( CRA_SELECTED ));
  693.  
  694.             if( pCnrRec == (PCNRREC) -1 )
  695.                 Msg( "CountSelectedRecs..CM_QUERYRECORDEMPHASIS RC(%X)",
  696.                      HWNDERR( hwndFrame ) );
  697.             else if( pCnrRec )
  698.             {
  699.                 if( pCnrRec == pCnrRecUnderMouse )
  700.                     *pfUseSelectedRecs = TRUE;
  701.  
  702.                 cRecs++;
  703.             }
  704.         }
  705.  
  706.         if( !(*pfUseSelectedRecs) )
  707.             cRecs = 1;
  708.     }
  709.  
  710.     return cRecs;
  711. }
  712.  
  713. /**********************************************************************/
  714. /*----------------------- SetSelectedDragItems -----------------------*/
  715. /*                                                                    */
  716. /*  FILL THE DRAGINFO STRUCT WITH DRAGITEM STRUCTS FOR SELECTED RECS. */
  717. /*                                                                    */
  718. /*  PARMS: frame window handle,                                       */
  719. /*         count of selected records,                                 */
  720. /*         pointer to allocated DRAGINFO struct,                      */
  721. /*         pointer to allocated DRAGIMAGE array                       */
  722. /*                                                                    */
  723. /*  NOTES:                                                            */
  724. /*                                                                    */
  725. /*  RETURNS: nothing                                                  */
  726. /*                                                                    */
  727. /*--------------------------------------------------------------------*/
  728. /**********************************************************************/
  729. void SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
  730.                            PDRAGIMAGE pDragImage )
  731. {
  732.     PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  733.     int     i;
  734.  
  735.     for( i = 0; i < cRecs; i++, pDragImage++ )
  736.     {
  737.         pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  738.                                                CM_QUERYRECORDEMPHASIS,
  739.                                                MPFROMP( pCnrRec ),
  740.                                                MPFROMSHORT( CRA_SELECTED ) );
  741.  
  742.         if( pCnrRec == (PCNRREC) -1 )
  743.             Msg( "SetSelectedDragItems..CM_QUERYRECORDEMPHASIS RC(%X)",
  744.                  HWNDERR( hwndFrame ) );
  745.         else
  746.             SetOneDragItem( hwndFrame, pCnrRec, pDragInfo, pDragImage, i );
  747.     }
  748. }
  749.  
  750. /**********************************************************************/
  751. /*-------------------------- SetOneDragItem --------------------------*/
  752. /*                                                                    */
  753. /*  SET ONE DRAGITEM STRUCT INTO A DRAGINFO STRUCT.                   */
  754. /*                                                                    */
  755. /*  PARMS: frame window handle,                                       */
  756. /*         pointer to CNRREC that contains current container record,  */
  757. /*         pointer to allocated DRAGINFO struct,                      */
  758. /*         pointer to allocated DRAGIMAGE array,                      */
  759. /*         record offset into DRAGINFO struct to place DRAGITEM       */
  760. /*                                                                    */
  761. /*  NOTES: Fill in a DRAGITEM struct and 'set' it into the DRAGINFO   */
  762. /*         shared memory. Also fill in a DRAGIMAGE structure so PM    */
  763. /*         knows what image to use in representing this item.         */
  764. /*                                                                    */
  765. /*  RETURNS: nothing                                                  */
  766. /*                                                                    */
  767. /*--------------------------------------------------------------------*/
  768. /**********************************************************************/
  769. void SetOneDragItem( HWND hwndFrame, PCNRREC pCnrRec, PDRAGINFO pDragInfo,
  770.                      PDRAGIMAGE pDragImage, int iOffset )
  771. {
  772.     DRAGITEM DragItem;
  773.     PCH      pchBackslash;
  774.     char     chTemp;
  775.  
  776.     memset( &DragItem, 0, sizeof DragItem );
  777.  
  778.     // hwndDragItem is the window that will get the DM_RENDER and
  779.     // DM_RENDERCOMPLETE messages.
  780.  
  781.     DragItem.hwndItem = hwndFrame;
  782.  
  783.     // ulItemID is used to store information that can be used at drop time. Here
  784.     // we store the container record pointer, unless the user has overridden
  785.     // the item ID thru the settings notebook.
  786.  
  787.     if( dlgInfo.fUseDlgItemID )
  788.         DragItem.ulItemID = dlgInfo.ulItemID;
  789.     else
  790.         DragItem.ulItemID = (ULONG) pCnrRec;
  791.  
  792.     // hstrType identifies 'types' when it is necessary to differentiate. A
  793.     // good example is if you are dragging file names (DRM_OS2FILE) and need to
  794.     // pass the file type to the target (i.e. DRT_BITMAP would mean the file
  795.     // contained a bitmap, DRT_TEXT is an ascii file, etc. ). We use the value
  796.     // that was last entered in the settings notebook. It defaults to
  797.     // DRT_UNKNOWN if nothing was entered. This means that the file type is not
  798.     // known.
  799.  
  800.     DragItem.hstrType = DrgAddStrHandle( dlgInfo.szType );
  801.  
  802.     // We get the RMF from the global DLGINFO structure that can be modified
  803.     // thru the settings notebook. The default hstrRMF is
  804.     // "(DRM_OS2FILE,DRM_PRINT,DRM_DISCARD)x(DRF_TEXT)". This would equate to
  805.     // allowing a 'file-based' drop as well as allowing drops on the printer
  806.     // and shredder and using 'text'-based communication.
  807.  
  808.     DragItem.hstrRMF = DrgAddStrHandle( dlgInfo.fUseManualRMF ?
  809.                                 dlgInfo.szManualRMF : dlgInfo.szGeneratedRMF );
  810.  
  811.     // This will contain the directory of the file. Temporarily remove the
  812.     // filename part of it so we can insert just the directory. After we create
  813.     // the stringhande, replace that first character of the file name. If the
  814.     // 'Override program values' checkbox was checked in the Settings notebook
  815.     // we will use the values that the user keyed in. Otherwise we get the
  816.     // values from the file that is being dragged.
  817.  
  818.     pchBackslash = strrchr( pCnrRec->szFullFileName, '\\' );
  819.     if( pchBackslash )
  820.     {
  821.         chTemp = *(pchBackslash + 1);
  822.         *(pchBackslash + 1) = 0;
  823.     }
  824.  
  825.     if( dlgInfo.fUseDlgDragNames )
  826.         DragItem.hstrContainerName = DrgAddStrHandle( dlgInfo.szContainerName);
  827.     else
  828.         DragItem.hstrContainerName = DrgAddStrHandle( pCnrRec->szFullFileName );
  829.  
  830.     if( pchBackslash )
  831.         *(pchBackslash + 1) = chTemp;
  832.  
  833.     // This will contain the file name
  834.  
  835.     if( dlgInfo.fUseDlgDragNames )
  836.         DragItem.hstrSourceName = DrgAddStrHandle( dlgInfo.szSourceName );
  837.     else
  838.         DragItem.hstrSourceName = DrgAddStrHandle( pCnrRec->szFileName );
  839.  
  840.     // Suggested target name is the same as the source name. We *could* ask the
  841.     // target to call it something else but we don't need that functionality
  842.     // in this program. If the user wants us to use the target name that was
  843.     // specified in the Settings notebook, we do.
  844.  
  845.     if( dlgInfo.fUseDlgDragNames )
  846.         DragItem.hstrTargetName = DrgAddStrHandle( dlgInfo.szTargetName );
  847.     else
  848.         DragItem.hstrTargetName = DragItem.hstrSourceName;
  849.  
  850.     // Get these values from the Settings notebook. The default is no control
  851.     // flags. These flags are used to specify miscellaneous things about the
  852.     // item being dragged.
  853.  
  854.     DragItem.fsControl = dlgInfo.fsControl;
  855.  
  856.     // Get these values from the Settings notebook. The default is to allow
  857.     // the user to copy and move this file (DO_MOVEABLE | DO_COPYABLE).
  858.  
  859.     DragItem.fsSupportedOps = dlgInfo.fsSupportedOps;
  860.  
  861.     // Set the DRAGITEM struct into the memory allocated by
  862.     // DrgAllocDraginfo()
  863.  
  864.     DrgSetDragitem( pDragInfo, &DragItem, sizeof DragItem, iOffset );
  865.  
  866.     // Fill in the DRAGIMAGE structure
  867.  
  868.     pDragImage->cb       = sizeof( DRAGIMAGE );
  869.     pDragImage->hImage   = pCnrRec->mrc.hptrIcon; // DragImage under mouse
  870.     pDragImage->fl       = DRG_ICON;              // hImage is an HPOINTER
  871.     pDragImage->cxOffset = 5 * iOffset;           // Image offset from mouse ptr
  872.     pDragImage->cyOffset = 5 * iOffset;           // Image offset from mouse ptr
  873.  
  874.     // Set source emphasis for this container record
  875.  
  876.     if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETRECORDEMPHASIS,
  877.                         MPFROMP( pCnrRec ), MPFROM2SHORT( TRUE, CRA_SOURCE ) ) )
  878.         Msg( "SetOneDragItem..CM_SETRECORDEMPHASIS RC(%X)",
  879.              HWNDERR( hwndFrame ) );
  880. }
  881.  
  882. /**********************************************************************/
  883. /*----------------------- DetermineDefaultOp -------------------------*/
  884. /*                                                                    */
  885. /*  DETERMINE THE DEFAULT OPERATION BASED ON THE INFO IN DRAGINFO.    */
  886. /*                                                                    */
  887. /*  PARMS: pointer to the DRAGINFO structure                          */
  888. /*                                                                    */
  889. /*  NOTES:                                                            */
  890. /*                                                                    */
  891. /*  RETURNS: default operation. could be one of these                 */
  892. /*             - DO_COPY       - 'Copy' is the default operation      */
  893. /*             - DO_LINK       - 'Link' is the default operation      */
  894. /*             - DO_MOVE       - 'Move' is the default operation      */
  895. /*                                                                    */
  896. /*                                                                    */
  897. /*--------------------------------------------------------------------*/
  898. /**********************************************************************/
  899. USHORT DetermineDefaultOp( PDRAGINFO pDragInfo )
  900. {
  901.     USHORT usDefaultOp = 0;
  902.  
  903.     if( pDragInfo->usOperation == DO_DEFAULT )
  904.     {
  905.         PDRAGITEM pDragItem = DrgQueryDragitemPtr( pDragInfo, 0 );
  906.         char      szSourcePath[ CCHMAXPATH ];
  907.  
  908.         *szSourcePath = 0;  // quicker than a memset for our purposes
  909.  
  910.         // If the current operation is DO_DEFAULT, we need to determine what
  911.         // the default operation will be over our window. We rely on the first
  912.         // DRAGITEM to make this decision - probably not a great idea, but the
  913.         // toolkit sample does this too <g>...
  914.  
  915.         DrgQueryStrName( pDragItem->hstrContainerName, sizeof szSourcePath,
  916.                          szSourcePath );
  917.  
  918.         // If the source and target are on the drive, make it a move.
  919.         // Otherwise if it is on a floppy drive or it is RemovableMedia,
  920.         // make it a copy.
  921.  
  922.         if( toupper( *szSourcePath ) == toupper( *szCurrentPath ) )
  923.             usDefaultOp = DO_MOVE;
  924.         else
  925.             if( toupper( *szSourcePath == 'A' ) ||
  926.                 toupper( *szSourcePath == 'B' ) ||
  927.                 pDragItem->fsControl & DC_REMOVEABLEMEDIA )
  928.                 usDefaultOp = DO_COPY;
  929.             else
  930.                 usDefaultOp = DO_MOVE;
  931.     }
  932.     else
  933.         usDefaultOp = pDragInfo->usOperation;
  934.  
  935.     return usDefaultOp;
  936. }
  937.  
  938. /**********************************************************************/
  939. /*------------------------ ProcessDroppedItem ------------------------*/
  940. /*                                                                    */
  941. /*  PROCESS A DRAGITEM THAT HAS BEEN DROPPED ON US                    */
  942. /*                                                                    */
  943. /*  PARMS: frame window handle,                                       */
  944. /*         pointer to DRAGITEM structure                              */
  945. /*                                                                    */
  946. /*  NOTES:                                                            */
  947. /*                                                                    */
  948. /*  RETURNS: nothing                                                  */
  949. /*                                                                    */
  950. /*--------------------------------------------------------------------*/
  951. /**********************************************************************/
  952. void ProcessDroppedItem( HWND hwndFrame, PDRAGITEM pDragItem )
  953. {
  954.     ULONG ulSuccess = DMFL_TARGETSUCCESSFUL;
  955.  
  956.     if( !DrgVerifyRMF( pDragItem, "DRM_OS2FILE", NULL ) )
  957.     {
  958.         // We can only handle the DRM_OS2FILE Rendering Mechanism in this
  959.         // program. Normally we would have weeded out non-DRM_OS2FILE drags
  960.         // on the DRAGOVER messages but we allow all kinds of drags in this
  961.         // program so we can show in the debug window what would have been
  962.         // dropped. So we allow the drop but issue a TargetFailed message on
  963.         // the drop if a non-OS2FILE.
  964.  
  965.         ulSuccess = DMFL_TARGETFAIL;
  966.     }
  967.     else if( !pDragItem->hstrSourceName )
  968.     {
  969.         // One of the standards of the DRM_OS2FILE protocol is that if the
  970.         // hstrSourceName (the file-name part of a fully-qualified file) is
  971.         // NULL we need to ask the source to render. We don't handle rendering
  972.         // in this program (check my DRGRENDR.EXE program) so we fail the drop.
  973.  
  974.         ulSuccess = DMFL_TARGETFAIL;
  975.     }
  976.     else
  977.     {
  978.         PCNRREC      pCnrRec;
  979.         RECORDINSERT ri;
  980.         HWND         hwndCnr = WinWindowFromID( hwndFrame, FID_CLIENT );
  981.  
  982.         memset( &ri, 0, sizeof ri );
  983.         ri.cb                 = sizeof( RECORDINSERT );
  984.         ri.pRecordOrder       = (PRECORDCORE) CMA_END;
  985.         ri.pRecordParent      = (PRECORDCORE) NULL;
  986.         ri.zOrder             = (USHORT) CMA_TOP;
  987.         ri.cRecordsInsert     = 1;
  988.         ri.fInvalidateRecord  = TRUE;
  989.  
  990.         pCnrRec = WinSendMsg( hwndCnr, CM_ALLOCRECORD, MPFROMLONG(EXTRA_BYTES),
  991.                               MPFROMLONG( 1 ) );
  992.  
  993.         if( pCnrRec )
  994.         {
  995.             PSZ pszLoc;
  996.  
  997.             DrgQueryStrName( pDragItem->hstrContainerName,
  998.                              sizeof pCnrRec->szFullFileName,
  999.                              pCnrRec->szFullFileName );
  1000.             pszLoc = pCnrRec->szFullFileName + strlen( pCnrRec->szFullFileName);
  1001.             if( pCnrRec->szFullFileName[ strlen(pCnrRec->szFullFileName) - 1 ]
  1002.                                                                        != '\\' )
  1003.                 pCnrRec->szFullFileName[ strlen(pCnrRec->szFileName) - 1 ]
  1004.                                                                        = '\\';
  1005.             DrgQueryStrName( pDragItem->hstrSourceName,
  1006.                              sizeof pCnrRec->szFullFileName -
  1007.                                    (pszLoc - pCnrRec->szFullFileName), pszLoc );
  1008.  
  1009.             pCnrRec->mrc.hptrIcon = WinLoadFileIcon( pCnrRec->szFullFileName,
  1010.                                                      FALSE );
  1011.             if( !pCnrRec->mrc.hptrIcon )
  1012.                 pCnrRec->mrc.hptrIcon =
  1013.                     WinQuerySysPointer( HWND_DESKTOP, SPTR_QUESICON, FALSE );
  1014.  
  1015.             DrgQueryStrName( pDragItem->hstrSourceName,
  1016.                              sizeof pCnrRec->szFileName, pCnrRec->szFileName );
  1017.  
  1018.             pCnrRec->mrc.pszIcon  = (PSZ) &pCnrRec->szFileName;
  1019.  
  1020.             if( !WinSendMsg( hwndCnr, CM_INSERTRECORD,
  1021.                              MPFROMLONG( pCnrRec ), MPFROMP( &ri ) ) )
  1022.                 Msg( "ProcessDroppedItem CM_INSERTRECORD RC(%X)",
  1023.                      HWNDERR( hwndFrame ) );
  1024.         }
  1025.         else
  1026.             Msg( "ProcessDroppedItem CM_ALLOCRECORD RC(%X)", HWNDERR(hwndFrame));
  1027.     }
  1028.  
  1029.     // Tell the source how the drop went for this item
  1030.  
  1031.     DrgSendTransferMsg( pDragItem->hwndItem, DM_ENDCONVERSATION,
  1032.                         MPFROMLONG( pDragItem->ulItemID ),
  1033.                         MPFROMLONG( ulSuccess ) );
  1034. }
  1035.  
  1036. /**********************************************************************/
  1037. /*--------------------------- PrintObject ----------------------------*/
  1038. /*                                                                    */
  1039. /*  PROCESS DM_PRINTOBJECT MESSAGE.                                   */
  1040. /*                                                                    */
  1041. /*  PARMS: frame window handle,                                       */
  1042. /*         pointer to DRAGITEM structure,                             */
  1043. /*         pointer to PRINTDEST structure                             */
  1044. /*                                                                    */
  1045. /*  NOTES:                                                            */
  1046. /*                                                                    */
  1047. /*  RETURNS: DRR_SOURCE or DRR_TARGET or DRR_ABORT                    */
  1048. /*                                                                    */
  1049. /*--------------------------------------------------------------------*/
  1050. /**********************************************************************/
  1051. MRESULT PrintObject( HWND hwndFrame, PDRAGITEM pDragItem, PPRINTDEST pPrintDest)
  1052. {
  1053.     HAB     hab = ANCHOR( hwndFrame );
  1054.     PCNRREC pCnrRec = (PCNRREC) pDragItem->ulItemID;
  1055.     HDC     hdc;
  1056.  
  1057.     showDragItem( hwndFrame, "DM_PRINTOBJECT", pDragItem, 0 );
  1058.  
  1059.     // If the user specified that they wanted to use their own item ID and
  1060.     // entered it in the settings notebook, we assume it is not a container
  1061.     // record pointer so we don't do anything.
  1062.  
  1063.     if( dlgInfo.fUseDlgItemID )
  1064.         return (MRESULT) DRR_SOURCE;
  1065.  
  1066.     // If the user, via the Settings notebook, told us not to do the printing
  1067.     // ourselves, just return with the reply that they want.
  1068.  
  1069.     if( dlgInfo.ulPrinterReply != DRR_SOURCE )
  1070.         return (MRESULT) dlgInfo.ulPrinterReply;
  1071.  
  1072.     // Get a printer device context using the information returned from PM
  1073.     // in the PRINTDEST structure
  1074.  
  1075.     hdc = DevOpenDC( hab, pPrintDest->lType, pPrintDest->pszToken,
  1076.                      pPrintDest->lCount, pPrintDest->pdopData, NULLHANDLE );
  1077.  
  1078.     if( pCnrRec && hdc )
  1079.     {
  1080.         LONG lBytes, lError;
  1081.  
  1082.         // If PM is telling us that we should let the user decide on job
  1083.         // properties, we accommodate it by putting up the job properties
  1084.         // dialog box.
  1085.  
  1086.         if( pPrintDest->fl & PD_JOB_PROPERTY )
  1087.             DevPostDeviceModes( hab,
  1088.                           ((PDEVOPENSTRUC) pPrintDest->pdopData)->pdriv,
  1089.                           ((PDEVOPENSTRUC) pPrintDest->pdopData)->pszDriverName,
  1090.                           pPrintDest->pszPrinter, NULL, DPDM_POSTJOBPROP );
  1091.  
  1092.         // Tell the spooler that we are starting a document.
  1093.  
  1094.         lError = DevEscape( hdc, DEVESC_STARTDOC, strlen( DOC_NAME ),
  1095.                             DOC_NAME, &lBytes, NULL );
  1096.  
  1097.         if( lError == DEV_OK )
  1098.         {
  1099.             char szPrintLine[ 100 ];
  1100.  
  1101.             sprintf( szPrintLine, "Printing %s\n", pCnrRec->szFullFileName );
  1102.  
  1103.             // Write the line to the printer
  1104.  
  1105.             lError = DevEscape( hdc, DEVESC_RAWDATA, strlen( szPrintLine ),
  1106.                                 szPrintLine, &lBytes, NULL );
  1107.  
  1108.             if( lError == DEVESC_ERROR )
  1109.                 Msg( "Bad DevEscape RAWDATA. RC(%X)", HWNDERR( hwndFrame ) );
  1110.  
  1111.             // Tell the spooler that we are done printing this document
  1112.  
  1113.             lError = DevEscape( hdc, DEVESC_ENDDOC, 0, NULL, &lBytes, NULL );
  1114.  
  1115.             if( lError == DEVESC_ERROR )
  1116.                 Msg( "Bad DevEscape ENDDOC. RC(%X)", HWNDERR( hwndFrame ) );
  1117.         }
  1118.         else
  1119.             Msg( "Bad DevEscape STARTDOC for %s. RC(%X)", DOC_NAME,
  1120.                  HWNDERR( hwndFrame ) );
  1121.     }
  1122.  
  1123.     if( hdc )
  1124.         DevCloseDC( hdc );
  1125.     else
  1126.         Msg( "DevOpenDC failed. RC(%X)", HWNDERR( hwndFrame ) );
  1127.  
  1128.     // Tell PM that we are doing the printing. We could return DRR_TARGET
  1129.     // which would leave the printing burden on the printer object or DRR_ABORT
  1130.     // which would tell PM to abort the drop.
  1131.  
  1132.     showPrintReply( hwndFrame, "source DM_PRINTOBJECT reply: ", DRR_SOURCE );
  1133.  
  1134.     return (MRESULT) dlgInfo.ulPrinterReply;
  1135. }
  1136.  
  1137. /**********************************************************************/
  1138. /*-------------------------- DiscardObjects --------------------------*/
  1139. /*                                                                    */
  1140. /*  PROCESS DM_DISCARDOBJECT MESSAGE.                                 */
  1141. /*                                                                    */
  1142. /*  PARMS: frame window handle,                                       */
  1143. /*         pointer to DRAGINFO structure                              */
  1144. /*                                                                    */
  1145. /*  NOTE: We get a DM_DISCARDOBJECT message for each record being     */
  1146. /*        dropped. Since we get a DRAGINFO pointer the first time,    */
  1147. /*        we process all records the first time around. The rest of   */
  1148. /*        the times we go thru the motions but don't really do        */
  1149. /*        anything.                                                   */
  1150. /*                                                                    */
  1151. /*                                                                    */
  1152. /*  OUTPUT: DRR_SOURCE or DRR_TARGET or DRR_ABORT                     */
  1153. /*                                                                    */
  1154. /*--------------------------------------------------------------------*/
  1155. /**********************************************************************/
  1156. MRESULT DiscardObjects( HWND hwndFrame, PDRAGINFO pDragInfo )
  1157. {
  1158.     HWND      hwndCnr = WinWindowFromID( hwndFrame, FID_CLIENT );
  1159.     int       i, cRecsToDiscard;
  1160.     PDRAGITEM pDragItem;
  1161.     PCNRREC   *apCnrRec;
  1162.  
  1163.     showDragInfo( hwndFrame, "DM_DISCARDOBJECT", pDragInfo );
  1164.  
  1165.     // If the user specified that they wanted to use their own item ID and
  1166.     // entered it in the settings notebook, we assume it is not a container
  1167.     // record pointer so we don't do anything.
  1168.  
  1169.     if( dlgInfo.fUseDlgItemID )
  1170.         return (MRESULT) DRR_SOURCE;
  1171.  
  1172.     // If the user, via the Settings notebook, told us not to do the shredding
  1173.     // ourselves, just return with the reply that they want.
  1174.  
  1175.     if( dlgInfo.ulShredderReply != DRR_SOURCE )
  1176.         return (MRESULT) dlgInfo.ulShredderReply;
  1177.  
  1178.     // Allocate memory for an array of container record pointers. This array
  1179.     // will be used during the CM_REMOVERECORD message to remove all dropped
  1180.     // records in one shot
  1181.  
  1182.     apCnrRec = (PCNRREC *) _alloca( pDragInfo->cditem * sizeof( PCNRREC ) );
  1183.  
  1184.     memset( apCnrRec, 0, pDragInfo->cditem * sizeof( PCNRREC ) );
  1185.  
  1186.     cRecsToDiscard = pDragInfo->cditem;
  1187.  
  1188.     for( i = 0; i < pDragInfo->cditem; i++ )
  1189.     {
  1190.         pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
  1191.  
  1192.         if( pDragItem )
  1193.             apCnrRec[ i ] = (PCNRREC) pDragItem->ulItemID;
  1194.         else
  1195.         {
  1196.             cRecsToDiscard--;
  1197.             Msg( "DiscardObjects DrgQueryDragitemPtr RC(%X)",
  1198.                  HWNDERR( hwndFrame ) );
  1199.         }
  1200.     }
  1201.  
  1202.     if( cRecsToDiscard )
  1203.     {
  1204.         // If CMA_FREE is used on CM_REMOVERECORD, the program traps on the
  1205.         // second DM_DISCARDOBJECT. So we can't blindly use CMA_FREE on the
  1206.         // CM_REMOVERECORD call. See comment below.
  1207.  
  1208.         int cRecsLeft = (int) WinSendMsg( hwndCnr, CM_REMOVERECORD,
  1209.                  MPFROMP( apCnrRec ),
  1210.                  MPFROM2SHORT( cRecsToDiscard, CMA_INVALIDATE ) );
  1211.  
  1212.         // -1 means invalid parameter. The problem is that we get as many
  1213.         // DM_DISCARDOBJECT messages as there are records dragged but the
  1214.         // first one has enough info to process all of them. The messages
  1215.         // after the first are irrelevant because we already did the
  1216.         // removing. Since subsequent DM_DISCARDOBJECT messages will cause
  1217.         // the above to fail (records were already moved the first time),
  1218.         // we need to not try and free the records here. If we do, we'll
  1219.         // trap because they were freed the first time.
  1220.  
  1221.         if( cRecsLeft != -1 )
  1222.             WinSendMsg( hwndCnr, CM_FREERECORD, MPFROMP( apCnrRec ),
  1223.                         MPFROMSHORT( cRecsToDiscard ) );
  1224.     }
  1225.  
  1226.     // Tell PM that we are doing the discarding. We could return DRR_TARGET
  1227.     // which would leave the discarding burden on the shredder or DRR_ABORT
  1228.     // which would tell PM to abort the drop.
  1229.  
  1230.     showPrintReply( hwndFrame, "source DM_DISCARDOBJECT reply: ", DRR_SOURCE );
  1231.  
  1232.     return (MRESULT) dlgInfo.ulShredderReply;
  1233. }
  1234.  
  1235. /**********************************************************************/
  1236. /*-------------------------- EndConversation -------------------------*/
  1237. /*                                                                    */
  1238. /*  FREE THE RESOURCES USED BY DRAG/DROP PROCESSING. ONLY DO THIS IF  */
  1239. /*  THIS IS THE LAST ITEM (there is one end-conversation message sent */
  1240. /*  to us for each item dropped).                                     */
  1241. /*                                                                    */
  1242. /*  PARMS: frame window handle,                                       */
  1243. /*         pointer to Container record that was dropped,              */
  1244. /*         success indicator                                          */
  1245. /*                                                                    */
  1246. /*  NOTES: This is a SOURCE window message that the target sends after*/
  1247. /*         it is done processing the DM_RENDERCOMPLETE message that   */
  1248. /*         the source sent it.                                        */
  1249. /*                                                                    */
  1250. /*  RETURNS: MRESULT value                                            */
  1251. /*                                                                    */
  1252. /*--------------------------------------------------------------------*/
  1253. /**********************************************************************/
  1254. MRESULT EndConversation( HWND hwndFrame, PCNRREC pCnrRec, ULONG flSuccess )
  1255. {
  1256.     PINSTANCE pi = INSTDATA( hwndFrame );
  1257.     char      szPrefix[ 50 ];
  1258.     BOOL      fCnrRecOK = TRUE;
  1259.  
  1260.     if( !pi )
  1261.     {
  1262.         Msg( "EndConversation cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
  1263.         return 0;
  1264.     }
  1265.  
  1266.     sprintf( szPrefix, "*** DM_ENDCONVERSATION for ulItemId %p: ", pCnrRec );
  1267.     showRenderReply( hwndFrame, szPrefix, flSuccess );
  1268.  
  1269.     // If the user specified that they wanted to use their own item ID and
  1270.     // entered it in the settings notebook, we assume it is not a container
  1271.     // record pointer so we don't do anything.
  1272.  
  1273.     if( dlgInfo.fUseDlgItemID )
  1274.         fCnrRecOK = FALSE;
  1275.  
  1276.     // If the drop was successful and it was a move operation, remove the
  1277.     // record from our container.
  1278.  
  1279.     if( (flSuccess & DMFL_TARGETSUCCESSFUL) && pCnrRec && fCnrRecOK )
  1280.         if( pi->pSavedDragInfo->usOperation == DO_MOVE )
  1281.             WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_REMOVERECORD,
  1282.                                MPFROMP( &pCnrRec ),
  1283.                                MPFROM2SHORT( 1, CMA_INVALIDATE | CMA_FREE ) );
  1284.  
  1285.     // We need to keep a running total to know when all items in the drop have
  1286.     // been processed. When that happens, it is time to free the resources that
  1287.     // were allocated to the drag as a whole rather than to an indidvidual item.
  1288.  
  1289.     if( --pi->cDragItems == 0 )
  1290.     {
  1291.         // Free the shared memory we got access to using DrgAccessDragInfo. If
  1292.         // the source process is the same as the target process, we get the
  1293.         // PMERR_SOURCE_SAME_AS_TARGET message. It's ok to get that - it just
  1294.         // means that we don't need to free the structure because the target
  1295.         // process already freed it.
  1296.  
  1297.         if( !DrgFreeDraginfo( pi->pSavedDragInfo ) &&
  1298.             PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
  1299.             Msg( "SourceCleanup DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
  1300.  
  1301.         // This is important because the NULL-ness of pSavedDragInfo lets the
  1302.         // dragInit function know that another drag is now possible.
  1303.  
  1304.         pi->pSavedDragInfo = NULL;
  1305.         pi->cDragItems     = 0;
  1306.     }
  1307.  
  1308.     // We need to know when the first DM_DRAGOVERNOTIFY message was hit so we
  1309.     // know how to display the message in the debug window. Here we turn that
  1310.     // flag off so that the DragoverNotify function knows when it gets the first
  1311.     // DM_DRAGOVERNOTIFY in a drag.
  1312.  
  1313.     pi->fGotFirstDragoverNotify = FALSE;
  1314.  
  1315.     return 0;
  1316. }
  1317.  
  1318. /**********************************************************************/
  1319. /*-------------------------- DragoverNotify --------------------------*/
  1320. /*                                                                    */
  1321. /*  PROCESS THE DM_DRAGOVERNOTIFY MESSAGE.                            */
  1322. /*                                                                    */
  1323. /*  PARMS: frame window handle,                                       */
  1324. /*         pointer to the DRAGINFO structure,                         */
  1325. /*         MRESULT that the target window returned                    */
  1326. /*                                                                    */
  1327. /*  NOTES: This is a SOURCE window message that PM sends to the source*/
  1328. /*         after the target has processed a DM_DRAGOVER message. It   */
  1329. /*         allows the source to see what's happening at the target    */
  1330. /*         end.                                                       */
  1331. /*                                                                    */
  1332. /*  RETURNS: MRESULT value                                            */
  1333. /*                                                                    */
  1334. /*--------------------------------------------------------------------*/
  1335. /**********************************************************************/
  1336. void DragoverNotify( HWND hwndFrame, PDRAGINFO pDragInfo, MRESULT mr )
  1337. {
  1338.     PINSTANCE pi = INSTDATA( hwndFrame );
  1339.  
  1340.     if( !pi )
  1341.     {
  1342.         Msg( "DragoverNotify cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
  1343.         return;
  1344.     }
  1345.  
  1346.     // We only want to display the full DRAGINFO structure in the debug window
  1347.     // if it is the first DM_DRAGOVERNOTIFY message while over our window. If we
  1348.     // display all of them the drag operation takes a real performance hit. If
  1349.     // the target's response (MRESULT) changes, we redisplay the DRAGINFO
  1350.     // structure. We clear the fDragInProgress flag in the DM_ENDCONVERSATION
  1351.     // message.
  1352.  
  1353.     if( pi->fGotFirstDragoverNotify )
  1354.         if( pi->mrDragoverNotify == mr )
  1355.             dbgInsert( pi->hwndDebug, " *** repeat DM_DRAGOVERNOTIFY" );
  1356.         else
  1357.         {
  1358.             pi->mrDragoverNotify = mr;
  1359.             showDragoverNotifyInfo( hwndFrame, pDragInfo, mr );
  1360.         }
  1361.     else
  1362.     {
  1363.         pi->mrDragoverNotify = mr;
  1364.         pi->fGotFirstDragoverNotify = TRUE;
  1365.         showDragoverNotifyInfo( hwndFrame, pDragInfo, mr );
  1366.     }
  1367.  
  1368. }
  1369.  
  1370. /**********************************************************************/
  1371. /*----------------------- RemoveSourceEmphasis -----------------------*/
  1372. /*                                                                    */
  1373. /*  REMOVE SOURCE EMPHASIS FROM THE DRAGGED RECORDS.                  */
  1374. /*                                                                    */
  1375. /*  PARMS: frame window handle                                        */
  1376. /*                                                                    */
  1377. /*  NOTES:                                                            */
  1378. /*                                                                    */
  1379. /*  RETURNS: nothing                                                  */
  1380. /*                                                                    */
  1381. /*--------------------------------------------------------------------*/
  1382. /**********************************************************************/
  1383. void RemoveSourceEmphasis( HWND hwndFrame )
  1384. {
  1385.     PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
  1386.  
  1387.     // For every record with source emphasis, remove it.
  1388.  
  1389.     while( pCnrRec )
  1390.     {
  1391.         pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  1392.                                             CM_QUERYRECORDEMPHASIS,
  1393.                                             MPFROMP( pCnrRec ),
  1394.                                             MPFROMSHORT( CRA_SOURCE ) );
  1395.  
  1396.         if( pCnrRec == (PCNRREC) -1 )
  1397.             Msg( "RemoveSourceEmphasis..CM_QUERYRECORDEMPHASIS RC(%X)",
  1398.                  HWNDERR( hwndFrame ) );
  1399.         else if( pCnrRec )
  1400.             if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
  1401.                                     CM_SETRECORDEMPHASIS, MPFROMP( pCnrRec ),
  1402.                                     MPFROM2SHORT( FALSE, CRA_SOURCE ) ) )
  1403.                 Msg( "RemoveSourceEmphasis..CM_SETRECORDEMPHASIS RC(%X)",
  1404.                      HWNDERR( hwndFrame ) );
  1405.     }
  1406. }
  1407.  
  1408. /*************************************************************************
  1409.  *                     E N D     O F     S O U R C E                     *
  1410.  *************************************************************************/
  1411.