home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************
- * *
- * MODULE NAME : drag.c AUTHOR: Rick Fishman *
- * DATE WRITTEN: 07-16-93 *
- * *
- * MODULE DESCRIPTION: *
- * *
- * Part of the 'DRGRENDR' drag/drop sample program. *
- * *
- * This module handles all the Drag/Drop processing for the *
- * DRGRENDR.EXE sample program. *
- * *
- * NOTES: *
- * *
- * We use the DRM_FISHMAN rendering mechanism. This is a fairly *
- * simple protocol that requires rendering on the drop. *
- * *
- * FUNCTIONS AVALABLE TO OTHER MODULES: *
- * *
- * dragInit *
- * dragOver *
- * dragDrop *
- * *
- * *
- * HISTORY: *
- * *
- * 07-16-93 - Program coded. *
- * *
- * Rick Fishman *
- * Code Blazers, Inc. *
- * 4113 Apricot *
- * Irvine, CA. 92720 *
- * CIS ID: 72251,750 *
- * *
- *********************************************************************/
-
- #pragma strings(readonly) // used for debug version of memory mgmt routines
-
- /*********************************************************************/
- /*------- Include relevant sections of the OS/2 header files --------*/
- /*********************************************************************/
-
- #define INCL_DOSERRORS
- #define INCL_DOSPROCESS
- #define INCL_SHLERRORS
- #define INCL_WINDIALOGS
- #define INCL_WINERRORS
- #define INCL_WINFRAMEMGR
- #define INCL_WININPUT
- #define INCL_WINSTDCNR
- #define INCL_WINSTDDRAG
- #define INCL_WINWINDOWMGR
-
- /**********************************************************************/
- /*----------------------------- INCLUDES -----------------------------*/
- /**********************************************************************/
-
- #include <os2.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "drgrendr.h"
-
- /*********************************************************************/
- /*------------------- APPLICATION DEFINITIONS -----------------------*/
- /*********************************************************************/
-
- #define DRAG_RMF "<DRM_FISHMAN,DRF_UNKNOWN>" // Rendering Mechanism/Format
-
- /**********************************************************************/
- /*---------------------------- STRUCTURES ----------------------------*/
- /**********************************************************************/
-
-
- /**********************************************************************/
- /*----------------------- FUNCTION PROTOTYPES ------------------------*/
- /**********************************************************************/
-
- int CountSelectedRecs ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
- PBOOL pfUseSelectedRecs );
- void SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
- PDRAGIMAGE pDragImage );
- void SetOneDragItem ( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
- PDRAGINFO pDragInfo, PDRAGIMAGE pDragImage,
- int iOffset );
- void ProcessDroppedItem ( HWND hwndFrame, PDRAGINFO pDragInfo,
- PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer );
- void FindTempFile ( PSZ szTempFileName );
- MRESULT Render ( HWND hwndFrame, PDRAGTRANSFER pDragXfer );
- void DoTheRendering ( PDRAGTRANSFER pDragXfer );
- MRESULT RenderComplete ( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
- USHORT fsRender );
- MRESULT EndConversation ( HWND hwndFrame );
- void RemoveSourceEmphasis( HWND hwndFrame );
- void TargetCleanup ( HWND hwndFrame );
- void SourceCleanup ( HWND hwndFrame );
-
- FNWP wpSource, wpTarget;
-
- /**********************************************************************/
- /*------------------------ GLOBAL VARIABLES --------------------------*/
- /**********************************************************************/
-
- char szDroppedOnCnrTitle[] = "Open a table by double-clicking on it!";
-
- /**********************************************************************/
- /*--------------------------- dragMessage ----------------------------*/
- /* */
- /* A DM_ MESSAGE WAS RECEIVED BY THE FRAME WINDOW PROCEDURE. */
- /* */
- /* PARMS: frame window handle, */
- /* message id, */
- /* mp1 of the message, */
- /* mp2 of the message */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: return code of message */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- MRESULT dragMessage( HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2 )
- {
- switch( msg )
- {
- // We only want to respond yes or no here so as not to hold up the
- // target window. All rendering will be done in the UM_DO_THE_RENDERING
- // message.
-
- case DM_RENDER: // The SOURCE window gets this message
- {
- MRESULT mr = Render( hwndFrame, (PDRAGTRANSFER) mp1 );
-
- if( mr )
- WinPostMsg( hwndFrame, UM_DO_THE_RENDERING, mp1, NULL );
-
- return mr;
- }
-
- case UM_DO_THE_RENDERING:
-
- DoTheRendering( (PDRAGTRANSFER) mp1 );
- return 0;
-
-
- case DM_ENDCONVERSATION: // The SOURCE window gets this message
-
- return EndConversation( hwndFrame );
-
-
- case DM_RENDERCOMPLETE: // The TARGET window gets this message
- {
- PDRAGTRANSFER pDragXfer = (PDRAGTRANSFER) mp1;
-
- // If the source gets this message it means that it requested a
- // a retry and the target said no. So complete the loop... Note that
- // pDragXfer->pditem->hwndItem is the source window.
-
- if( hwndFrame == pDragXfer->pditem->hwndItem )
- DrgPostTransferMsg( pDragXfer->hwndClient, DM_RENDERCOMPLETE,
- pDragXfer, DMFL_RENDERFAIL, 0, FALSE );
- else
- return RenderComplete( hwndFrame, (PDRAGTRANSFER) mp1,
- SHORT1FROMMP( mp2 ) );
-
- return 0;
- }
- }
-
- return 0;
- }
-
- /**********************************************************************/
- /*----------------------------- dragInit -----------------------------*/
- /* */
- /* PROCESS CN_INITDRAG NOTIFY MESSAGE. */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to the CNRDRAGINIT structure */
- /* */
- /* NOTES: the CN_INITDRAG message is equivalent to the WM_BEGINDRAG */
- /* message. The reason I mention this is because if the source*/
- /* window in the drag is not a container you will get the */
- /* WM_BEGINDRAG message. */
- /* */
- /* WM_BEGINDRAG is sent to windows to allow them to know that */
- /* the user is requesting a drag from their window. This */
- /* message contains only the x,y coordinates of the mouse at */
- /* the time of WM_BEGINDRAG. */
- /* */
- /* The reason for CN_INITDRAG is first so that the container */
- /* can notify its owner when it gets a WM_BEGINDRAG message */
- /* and second so that the container can give its owner more */
- /* info, like what container record the mouse pointer is over.*/
- /* To accomplish this, the container packages up this informa-*/
- /* tion in a CNRDRAGINIT structure and sends that structure */
- /* along with the CN_INITDRAG message. */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void dragInit( HWND hwndFrame, PCNRDRAGINIT pcdi )
- {
- PCNRREC pCnrRecUnderMouse = (PCNRREC) pcdi->pRecord;
- PDRAGIMAGE pDragImage = NULL;
- PDRAGINFO pDragInfo = NULL;
- BOOL fUseSelectedRecs;
- PINSTANCE pi = INSTDATA( hwndFrame );
- int cRecs;
-
- if( !pi )
- {
- Msg( "dragInit cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
- return;
- }
-
- // pSavedDragInfo is used during drop processing. When the drop is complete
- // (the source gets a DM_ENDCONVERSATION message from the target), the
- // source will free the DRAGINFO structure and set this field to NULL.
- // So pSavedDragInfo is non-NULL if a drop has not yet completed. In this
- // case we make it easy on ourselves by not allowing another drag. The
- // reason for this is that if we allow another drag to take place we will
- // need to overwrite this pSavedDragInfo field in which case the drop
- // processing would not free the right DRAGINFO structure. Obviously in a
- // commercial app you'd want to use a different mechanism for storing the
- // DRAGINFO structure, like a linked list, so you could start another drag
- // while the drop is in progress.
-
- if( pi->pSavedDragInfo )
- {
- WinAlarm( HWND_DESKTOP, WA_WARNING );
- return;
- }
-
- // Count the records that have CRA_SELECTED emphasis. Also return whether
- // or not we should process the CRA_SELECTED records. If the container
- // record under the mouse does not have this emphasis, we shouldn't. In that
- // case we would just process the record under the mouse.
-
- cRecs = CountSelectedRecs( hwndFrame, pCnrRecUnderMouse, &fUseSelectedRecs);
-
- if( cRecs )
- {
- int iDragImageArraySize = cRecs * sizeof( DRAGIMAGE );
-
- // Allocate an array of DRAGIMAGE structures. Each structure contains
- // info about an image that will be under the mouse pointer during the
- // drag. This image will represent a container record being dragged.
-
- pDragImage = (PDRAGIMAGE) malloc( iDragImageArraySize );
-
- if( pDragImage )
- {
- memset( pDragImage, 0, iDragImageArraySize );
-
- // Let PM allocate enough memory for a DRAGINFO structure as well
- // as a DRAGITEM structure for each record being dragged. It will
- // allocate shared memory so other processes can participate in the
- // drag/drop.
-
- pDragInfo = DrgAllocDraginfo( cRecs );
-
- if( pDragInfo )
- {
- pi->pSavedDragInfo = pDragInfo;
- pi->cDragItems = cRecs;
- }
- else
- Msg( "DrgAllocDraginfo failed. RC(%X)", HWNDERR( hwndFrame ) );
- }
- else
- Msg( "Out of memory in dragInit" );
- }
-
- if( cRecs && pDragInfo && pDragImage )
- {
- // Set the data from the container records into the DRAGITEM and
- // DRAGIMAGE structures. If we are to process CRA_SELECTED container
- // records, do them all in one function. If not, pass a pointer to the
- // container record under the mouse to a different function that will
- // fill in just one DRAGITEM / DRAGIMAGE structure.
-
- if( fUseSelectedRecs )
- SetSelectedDragItems( hwndFrame, cRecs, pDragInfo, pDragImage );
- else
- SetOneDragItem( hwndFrame, pCnrRecUnderMouse, pDragInfo,
- pDragImage, 0 );
-
- // If DrgDrag returns NULLHANDLE, that means the user hit Esc or F1
- // while the drag was going on so the target didn't have a chance to
- // delete the string handles. So it is up to the source window to do
- // it. Unfortunately there doesn't seem to be a way to determine
- // whether the NULLHANDLE means Esc was pressed as opposed to there
- // being an error in the drag operation. So we don't attempt to figure
- // that out. To us, a NULLHANDLE means Esc was pressed...
-
- if( !DrgDrag( hwndFrame, pDragInfo, pDragImage, cRecs, VK_ENDDRAG,
- NULL ) )
- {
- if( !DrgDeleteDraginfoStrHandles( pDragInfo ) )
- Msg( "dragInit DrgDeleteDraginfoStrHandles RC(%X)",
- HWNDERR( hwndFrame ) );
-
- if( !DrgFreeDraginfo( pDragInfo ) )
- Msg( "dragInit DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
-
- pi->pSavedDragInfo = NULL;
- }
-
- // Take off source emphasis from the records that were dragged
-
- RemoveSourceEmphasis( hwndFrame );
- }
-
- if( pDragImage )
- free( pDragImage );
- }
-
- /**********************************************************************/
- /*----------------------------- dragOver -----------------------------*/
- /* */
- /* PROCESS CN_DRAGOVER NOTIFY MESSAGE. */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to the CNRDRAGINFO structure */
- /* */
- /* NOTES: The container sends the CN_DRAGOVER message to its owner */
- /* when it gets a DM_DRAGOVER message. The container takes */
- /* the info it gets on the DM_DRAGOVER message and combines */
- /* it with other container-specific dragover info into a */
- /* CNRDRAGINFO structure, then passes a pointer to that */
- /* structure to its owner in the CN_DRAGOVER message. */
- /* */
- /* In this program, all we care about is that the other */
- /* window can handle the DRM_FISHMAN protocol and that the */
- /* window is not trying to drop on itself. Strangely enough, */
- /* the DRM_FISHMAN protocol is not in widespread use <g>. */
- /* */
- /* RETURNS: return value from CN_DRAGOVER processing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- MRESULT dragOver( HWND hwndFrame, PCNRDRAGINFO pcdi )
- {
- USHORT usDrop, usDefaultOp;
- PDRAGINFO pDragInfo = pcdi->pDragInfo;
- PDRAGITEM pDragItem;
-
- if( !DrgAccessDraginfo( pDragInfo ) )
- {
- Msg( "dragOver DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
- return MRFROM2SHORT( DOR_NEVERDROP, 0 );
- }
-
- // Don't allow a window to drop on itself
-
- if( pDragInfo->hwndSource == hwndFrame )
- return MRFROM2SHORT( DOR_NEVERDROP, 0 );
-
- // We're only concerned with the first item being dragged. We "assume" that
- // if the first item is using the DRM_FISHMAN protocol then all others are.
- // In a real-world program you would want to check all dragitems.
-
- pDragItem = DrgQueryDragitemPtr( pDragInfo, 0 );
-
- if( pDragItem )
- {
- // We will only allow DRM_FISHMAN items to be dropped on us
-
- if( DrgVerifyRMF( pDragItem, "DRM_FISHMAN", NULL ) )
- {
- usDrop = DOR_DROP;
-
- // We only allow a logical 'copy' operation to take place, so this
- // will change the pointer to be a 'copy' (halftoned) pointer
- // during the drag when the pointer is over our window.
-
- usDefaultOp = DO_COPY;
- }
- else
- {
- usDrop = DOR_NEVERDROP;
- usDefaultOp = 0;
- }
- }
- else
- Msg( "dragOver DrgQueryDragitemPtr RC(%X)", HWNDERR( hwndFrame ) );
-
- // Free our handle to the shared memory if the source window is not in our
- // process.
-
- if( !DrgFreeDraginfo( pDragInfo ) &&
- PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
- Msg( "dragOver DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
-
- return MRFROM2SHORT( usDrop, usDefaultOp );
- }
-
- /**********************************************************************/
- /*---------------------------- dragDrop ------------------------------*/
- /* */
- /* PROCESS CN_DROP NOTIFY MESSAGE. */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to the CNRDRAGINFO structure */
- /* */
- /* NOTES: The container sends the CN_DROP message to its owner when */
- /* it gets a DM_DROP message. The container takes the info it */
- /* gets on the DM_DROP message and combines it with other */
- /* container-specific dragover info into a CNRDRAGINFO */
- /* structure, then passes a pointer to that structure to its */
- /* owner in the CN_DROP message. */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void dragDrop( HWND hwndFrame, PCNRDRAGINFO pcdi )
- {
- PDRAGINFO pDragInfo = pcdi->pDragInfo;
- PINSTANCE pi = INSTDATA( hwndFrame );
- PDRAGITEM pDragItem;
- PDRAGTRANSFER pDragXfer;
- int i, cItemsToRender, cItemsRendered;
-
- if( !pi )
- {
- Msg( "dragDrop cant get Inst data RC(%X)", HWNDERR( hwndFrame ) );
- return;
- }
-
- // Save this info so it can be used on the last DM_RENDERCOMPLETE message.
-
- pi->pSavedDragInfo = pDragInfo;
- pi->cDragItems = pDragInfo->cditem;
-
- if( !DrgAccessDraginfo( pDragInfo ) )
- {
- Msg( "dragDrop DrgAccessDraginfo RC(%X)", HWNDERR( hwndFrame ) );
- return;
- }
-
- cItemsToRender = cItemsRendered = pDragInfo->cditem;
-
- // We allocate an array of DRAGTRANSFER structures. One by one each will
- // be passed on a DM_RENDER message. On DM_RENDERCOMPLETE messages we will
- // free each one. PM takes care of freeing the whole array after it gets
- // back as many DrgFreeDragTransfer's as were allocated here.
-
- pDragXfer = DrgAllocDragtransfer( pDragInfo->cditem );
- if( !pDragXfer )
- {
- Msg( "dragDrop DrgAllocDragtransfer RC(%X)", HWNDERR( hwndFrame ) );
- return;
- }
-
- // Process each DragItem. First get a pointer to it, then call a function
- // that starts the rendering happening.
-
- for( i = 0; i < pDragInfo->cditem; i++ )
- {
- pDragItem = DrgQueryDragitemPtr( pDragInfo, i );
-
- if( pDragItem )
- ProcessDroppedItem( hwndFrame, pDragInfo, pDragItem,pDragXfer + i );
- else
- {
- Msg( "dragDrop DrgQueryDragitemPtr RC(%X)", HWNDERR( hwndFrame ) );
- --cItemsRendered;
- }
- }
-
- if( !cItemsRendered )
- {
- // Clean up after ourselves if we weren't able to do
- // any rendering. Normally this cleanup would be done
- // under the last DM_RENDERCOMPLETE message but we don't
- // get those messages if we aren't rendering.
-
- TargetCleanup( hwndFrame );
- }
- else if( cItemsToRender != cItemsRendered )
- {
- // Only *some* items weren't rendered. If the rendering for all items
- // that got sent DM_RENDER messages is complete, the target resources
- // wouldn't have been freed because the counter wouldn't have been zero,
- // so we need to free them in this case.
-
- if( pi->cDragItems )
- pi->cDragItems -= (cItemsToRender - cItemsRendered);
- else
- TargetCleanup( hwndFrame );
- }
- }
-
- /**********************************************************************/
- /*------------------------ CountSelectedRecs -------------------------*/
- /* */
- /* COUNT THE NUMBER OF RECORDS THAT ARE CURRENTLY SELECTED. */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to the record that was under the pointer, */
- /* address of BOOL - should we process selected records? */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: number of records to process */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- int CountSelectedRecs( HWND hwndFrame, PCNRREC pCnrRecUnderMouse,
- PBOOL pfUseSelectedRecs )
- {
- int cRecs = 0;
-
- *pfUseSelectedRecs = FALSE;
-
- // If the record under the mouse is NULL, we must be over whitespace, in
- // which case we don't want to drag any records.
-
- if( pCnrRecUnderMouse )
- {
- PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
-
- // Count the records with 'selection' emphasis. These are the records
- // we want to drag, unless the container record under the mouse does
- // not have selection emphasis. If that is the case, we only want to
- // process that one.
-
- while( pCnrRec )
- {
- pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
- CM_QUERYRECORDEMPHASIS,
- MPFROMP( pCnrRec ),
- MPFROMSHORT( CRA_SELECTED ));
-
- if( pCnrRec == (PCNRREC) -1 )
- Msg( "CountSelectedRecs..CM_QUERYRECORDEMPHASIS RC(%X)",
- HWNDERR( hwndFrame ) );
- else if( pCnrRec )
- {
- if( pCnrRec == pCnrRecUnderMouse )
- *pfUseSelectedRecs = TRUE;
-
- cRecs++;
- }
- }
-
- if( !(*pfUseSelectedRecs) )
- cRecs = 1;
- }
-
- return cRecs;
- }
-
- /**********************************************************************/
- /*----------------------- SetSelectedDragItems -----------------------*/
- /* */
- /* FILL THE DRAGINFO STRUCT WITH DRAGITEM STRUCTS FOR SELECTED RECS. */
- /* */
- /* PARMS: frame window handle, */
- /* count of selected records, */
- /* pointer to allocated DRAGINFO struct, */
- /* pointer to allocated DRAGIMAGE array */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void SetSelectedDragItems( HWND hwndFrame, int cRecs, PDRAGINFO pDragInfo,
- PDRAGIMAGE pDragImage )
- {
- PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
- int i;
-
- for( i = 0; i < cRecs; i++, pDragImage++ )
- {
- pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
- CM_QUERYRECORDEMPHASIS,
- MPFROMP( pCnrRec ),
- MPFROMSHORT( CRA_SELECTED ) );
-
- if( pCnrRec == (PCNRREC) -1 )
- Msg( "SetSelectedDragItems..CM_QUERYRECORDEMPHASIS RC(%X)",
- HWNDERR( hwndFrame ) );
- else
- SetOneDragItem( hwndFrame, pCnrRec, pDragInfo, pDragImage, i );
- }
- }
-
- /**********************************************************************/
- /*-------------------------- SetOneDragItem --------------------------*/
- /* */
- /* SET ONE DRAGITEM STRUCT INTO A DRAGINFO STRUCT. */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to CNRREC that contains current container record, */
- /* pointer to allocated DRAGINFO struct, */
- /* pointer to allocated DRAGIMAGE array, */
- /* record offset into DRAGINFO struct to place DRAGITEM */
- /* */
- /* NOTES: Fill in a DRAGITEM struct and 'set' it into the DRAGINFO */
- /* shared memory. Also fill in a DRAGIMAGE structure so PM */
- /* knows what image to use in representing this item. */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void SetOneDragItem( HWND hwndFrame, PCNRREC pCnrRec, PDRAGINFO pDragInfo,
- PDRAGIMAGE pDragImage, int iOffset )
- {
- DRAGITEM DragItem;
- PCH pchColon = NULL;
-
- memset( &DragItem, 0, sizeof DragItem );
-
- // hwndDragItem is the window that will get the DM_RENDER and
- // DM_RENDERCOMPLETE messages.
-
- DragItem.hwndItem = hwndFrame;
-
- // ulItemID is used to store information that can be used at drop time. Here
- // we store the container record pointer.
-
- DragItem.ulItemID = (ULONG) pCnrRec;
-
- // hstrType identifies 'types' when it is necessary to differentiate. A
- // good example is if you are dragging file names (DRM_OS2FILE) and need to
- // pass the file type to the target (i.e. DRT_BITMAP would mean the file
- // contained a bitmap, DRT_TEXT is an ascii file, etc. )
-
- DragItem.hstrType = DrgAddStrHandle( DRT_UNKNOWN );
-
- // This is the rendering mechanism/format. This establishes the protocol
- // that we will be using during the Drag/Drop operation. In this program we
- // only use DRM_FISHMAN which means rendering will take place after the
- // drop using a predefined and agreed-upon mechanism. Any target objects
- // that OK this type of protocol must know how to handle themselves after
- // the drop.
-
- DragItem.hstrRMF = DrgAddStrHandle( DRAG_RMF );
-
- // This will contain our 'database file' name. We have multiple 'database'
- // files, each with their own set of 'tables'. This field identifies the
- // 'database' name. The text for each container record has been set (in the
- // InsertRecords function in drgrendr.c) to "database:table". So we
- // temporarily set the colon to a null-terminator for the database name so
- // we can create a stringhandle for the database name.
-
- pchColon = strchr( pCnrRec->szTableName, ':' );
- if( pchColon )
- *pchColon = 0;
- else // This should never happen! Play it safe though.
- pchColon = pCnrRec->szTableName;
-
- DragItem.hstrContainerName = DrgAddStrHandle( pCnrRec->szTableName );
-
- // This will contain the table name (minus the database name)
-
- DragItem.hstrSourceName = DrgAddStrHandle( pchColon + 1 );
-
- // Replace the colon that we overwrote with a 0 earlier
-
- if( pchColon != pCnrRec->szTableName )
- *pchColon = ':';
-
- // Suggested target name is the same as the source name. We *could* ask the
- // target to call it something else but we don't need that functionality
- // in this program.
-
- DragItem.hstrTargetName = DragItem.hstrSourceName;
-
- // Allow the user to only 'copy' this item. 'Move doesn't make sense since
- // the records will always stay in the source container.
-
- DragItem.fsSupportedOps = DO_COPYABLE;
-
- // Set the DRAGITEM struct into the memory allocated by
- // DrgAllocDraginfo()
-
- DrgSetDragitem( pDragInfo, &DragItem, sizeof DragItem, iOffset );
-
- // Fill in the DRAGIMAGE structure
-
- pDragImage->cb = sizeof( DRAGIMAGE );
- pDragImage->hImage = pCnrRec->mrc.hptrIcon; // DragImage under mouse
- pDragImage->fl = DRG_ICON; // hImage is an HPOINTER
- pDragImage->cxOffset = 5 * iOffset; // Image offset from mouse ptr
- pDragImage->cyOffset = 5 * iOffset; // Image offset from mouse ptr
-
- // Set source emphasis for this container record
-
- if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETRECORDEMPHASIS,
- MPFROMP( pCnrRec ), MPFROM2SHORT( TRUE, CRA_SOURCE ) ) )
- Msg( "SetOneDragItem..CM_SETRECORDEMPHASIS RC(%X)",
- HWNDERR( hwndFrame ) );
- }
-
- /**********************************************************************/
- /*------------------------ ProcessDroppedItem ------------------------*/
- /* */
- /* PROCESS A DRAGITEM THAT HAS BEEN DROPPED ON US */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to the DRAGINFO structure, */
- /* pointer to DRAGITEM structure, */
- /* pointer to DRAGTRANSFER structure to use on DM_RENDER msg */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void ProcessDroppedItem( HWND hwndFrame, PDRAGINFO pDragInfo,
- PDRAGITEM pDragItem, PDRAGTRANSFER pDragXfer )
- {
- PSZ pszString, pszLoc;
- ULONG cbString;
- MRESULT mr;
- char szTempFileName[ CCHMAXPATH ];
-
- // We will ask the source to 'render' into a temporary file. This next
- // function gets a temporary file name to use.
-
- FindTempFile( szTempFileName );
-
- // Form a 'database:table' string by combining the database found in
- // hstrContainerName with the table found in hstrSourceName.
-
- cbString = DrgQueryStrNameLen( pDragItem->hstrContainerName ) +
- DrgQueryStrNameLen( pDragItem->hstrSourceName ) +
- 2; // Null terminator plus colon
-
- pszString = pszLoc = _alloca( cbString );
-
- DrgQueryStrName( pDragItem->hstrContainerName, cbString, pszLoc );
- strcat( pszString, ":" );
- pszLoc += strlen( pszString );
- cbString -= strlen( pszString );
- DrgQueryStrName( pDragItem->hstrSourceName, cbString, pszLoc );
-
- // Fill in the DRAGTRANSFER structure. This structure is used throughout
- // the rendering process and is exchanged between the source and the
- // target.
-
- memset( pDragXfer, 0, sizeof( DRAGTRANSFER ) );
- pDragXfer->cb = sizeof( DRAGTRANSFER );
-
- // hwndClient identifies the target window
-
- pDragXfer->hwndClient = hwndFrame;
- pDragXfer->pditem = pDragItem;
-
- // hstrSelectedRMF is the Rendering Mechanism/Format used during the
- // rendering. Remember that the hstrRMF field of the DRAGITEM structure
- // can contain multiple mechanisms and formats. When we get down to the
- // rendering stage we can use only one. In this program we only ever
- // offered one so we use the same one that was placed in DRAGITEM.hstrRMF.
- // In the real world we would first put the most native mechanism/format
- // combination into hstrSelectedRMF and send the source a DM_RENDER. If the
- // source responded to the DM_RENDER by returning DMFL_RENDERRETRY, we would
- // then use the 'next best' RMF and try again by sending another DM_RENDER
- // with the new hstrSelectedRMF. We'd do this until one was agreed upon.
-
- pDragXfer->hstrSelectedRMF = DrgAddStrHandle( DRAG_RMF );
-
- // hstrRenderToName is the file name that we are asking the source to
- // render into. In this program the source will copy the rows from the
- // requested database:table into this file.
-
- pDragXfer->hstrRenderToName = DrgAddStrHandle( szTempFileName );
-
- // usOperation is where we'd indicate 'copy' or 'move'. In this program we
- // will only do a logical copy operation so this field isn't even looked at.
- // Typically this will stay the same as the usOperation field in the
- // DRAGINFO field because that contains the last operation selected by the
- // user.
-
- pDragXfer->usOperation = pDragInfo->usOperation;
-
- // ulTargetInfo is a convenient place to store something between render
- // messages.
-
- pDragXfer->ulTargetInfo = 0;
-
- // Initialize this to 0. The source will place something in here if it
- // returns FALSE from DM_RENDER.
-
- pDragXfer->fsReply = 0;
-
- // If the source wanted to be notified before a render is to be sent,
- // do it. This program doesn't use this mechanism but the multi-threaded
- // version of this program does.
-
- if( pDragItem->fsControl & DC_PREPARE )
- DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDERPREPARE,
- pDragXfer, NULL );
-
- // Tell the source to render
-
- mr = DrgSendTransferMsg( pDragItem->hwndItem, DM_RENDER, pDragXfer, NULL );
-
- // MRESULT will be NULL if the source could not render
-
- if( !mr )
- {
- // If the source wants us to retry with another mechanism, tell it
- // 'no' because all we can handle is DRM_FISHMAN.
-
- if( pDragXfer->fsReply & DMFL_RENDERRETRY )
- DrgPostTransferMsg( pDragItem->hwndItem, DM_RENDERCOMPLETE,
- pDragXfer, DMFL_RENDERFAIL, 0, FALSE );
-
- // If the source wants us to render, tell it 'no way'. It is the one
- // that requested rendering in the first place.
-
- if( pDragXfer->fsReply & DMFL_NATIVERENDER )
- DrgSendTransferMsg( pDragItem->hwndItem, DM_ENDCONVERSATION,
- MPFROMLONG( pDragItem->ulItemID ),
- MPFROMLONG( DMFL_TARGETFAIL ) );
- }
- }
-
- /**********************************************************************/
- /*-------------------------- FindTempFile ----------------------------*/
- /* */
- /* FIND AN AVAILABLE TEMPORARY FILE NAME. */
- /* */
- /* PARMS: pointer to buffer to hold filename */
- /* */
- /* NOTES: This is a rudimentary method for getting a temporary file */
- /* name. Usually you'd want to check the TEMP or TMP */
- /* environment variables first and use that as the directory */
- /* in which to place the temporary files. For a sample */
- /* program, this will do fine. Basically we just get use */
- /* the current path and a base filename and figure out an */
- /* extension by finding the first available one. */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void FindTempFile( PSZ pszTempFileName )
- {
- PSZ pszFileExt;
- FILESTATUS3 fs;
- int i;
- APIRET rc;
- FILE *fhTemp;
-
- strcpy( pszTempFileName, szCurrentPath );
- strcat( pszTempFileName, BASE_TEMPFILE_NAME );
- strcat( pszTempFileName, "." );
-
- pszFileExt = pszTempFileName + strlen( pszTempFileName );
-
- for( i = 0; i < 1000; i++ )
- {
- _itoa( i, pszFileExt, 10 );
-
- rc = DosQueryPathInfo( pszTempFileName, FIL_STANDARD, &fs, sizeof fs );
- if( rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND )
- {
- // Create the file so it exists and we won't try and use it for the
- // next temporary file.
-
- fhTemp = fopen( pszTempFileName, "w" );
- fclose( fhTemp );
- break;
- }
- }
-
- if( i >= 1000 )
- Msg( "Can't get a temporary file name!!!" );
- }
-
- /**********************************************************************/
- /*----------------------------- Render -------------------------------*/
- /* */
- /* PROCESS A DM_RENDER MESSAGE */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to a DRAGTRANSFER structure */
- /* */
- /* NOTES: This is a SOURCE window message */
- /* */
- /* RETURNS: MRESULT explaining the rendering availability */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- MRESULT Render( HWND hwndFrame, PDRAGTRANSFER pDragXfer )
- {
- hwndFrame=hwndFrame; // Keep the compiler happy
- pDragXfer=pDragXfer;
-
- // Normally here we would check some things and return TRUE if everything
- // looked OK or we would return FALSE and set pDragXfer->fsReply to the
- // reason for the FALSE. A typical reason to return FALSE would be if
- // pDragXfer->hstrSelectedRMF was something we couldn't support or
- // pDragXfer->usOperation was something we didn't want to do. In that case
- // we'd return FALSE and set fsReply to DMFL_RENDERRETRY. It would then be
- // up to the target to change its parameters and send us another DM_RENDER.
-
- return (MRESULT) TRUE;
- }
-
- /**********************************************************************/
- /*------------------------- DoTheRendering ---------------------------*/
- /* */
- /* DO THE RENDERING. */
- /* */
- /* PARMS: pointer to a DRAGTRANSFER structure */
- /* */
- /* NOTES: This is a SOURCE window message */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void DoTheRendering( PDRAGTRANSFER pDragXfer )
- {
- PSZ pszTableName, pszFileName, pszLoc;
- ULONG cbString, flStatus = DMFL_RENDEROK;
-
- // Form the 'database:table' string by combining the database name which
- // is stored in hstrContainerName with the table name which is stored in
- // hstrSourceName.
-
- cbString = DrgQueryStrNameLen( pDragXfer->pditem->hstrContainerName ) +
- DrgQueryStrNameLen( pDragXfer->pditem->hstrSourceName ) +
- 2; // Null terminator plus colon
-
- pszTableName = pszLoc = _alloca( cbString );
-
- DrgQueryStrName( pDragXfer->pditem->hstrContainerName, cbString, pszLoc );
- strcat( pszTableName, ":" );
- pszLoc += strlen( pszTableName );
- cbString -= strlen( pszTableName );
- DrgQueryStrName( pDragXfer->pditem->hstrSourceName, cbString, pszLoc );
-
- // Get the file name that we (the source) should be rendering to. This
- // name was decided by the target before it sent us the DM_RENDER message.
-
- cbString = DrgQueryStrNameLen( pDragXfer->hstrRenderToName ) + 1;
- pszFileName = _alloca( cbString );
- DrgQueryStrName( pDragXfer->hstrRenderToName, cbString, pszFileName );
-
- // Call this function which will copy the database data into the file.
-
- if( !dbRenderToFile( pszTableName, pszFileName ) )
- flStatus = DMFL_RENDERFAIL;
-
- // Tell the target that we're done.
-
- DrgPostTransferMsg( pDragXfer->hwndClient, DM_RENDERCOMPLETE, pDragXfer,
- flStatus, 0, FALSE );
-
- // Bot the target and the source must free this. Since we're done at the
- // source, it is time to free it.
-
- DrgFreeDragtransfer( pDragXfer );
- }
-
- /**********************************************************************/
- /*------------------------- RenderComplete ---------------------------*/
- /* */
- /* PROCESS A DM_RENDERCOMPLETE MESSAGE */
- /* */
- /* PARMS: frame window handle, */
- /* pointer to a DRAGTRANSFER structure, */
- /* flags describing the render operation */
- /* */
- /* NOTES: This is a TARGET window message sent by the source when it */
- /* has completed the rendering. */
- /* */
- /* RETURNS: zero */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- MRESULT RenderComplete( HWND hwndFrame, PDRAGTRANSFER pDragXfer,
- USHORT fsRender )
- {
- BOOL fSuccess = TRUE;
- ULONG flStatus = DMFL_TARGETSUCCESSFUL;
- PINSTANCE pi = INSTDATA( hwndFrame );
-
- // If the source responded with RENDEROK, that means we can count on the
- // hstrRenderToFile file containing the data from the table in the database.
- // In that case we insert a record into the 'drop' container that will
- // represent that rendered file. The user can double-click on that icon and
- // bring up a listbox with the file dumped into it.
-
- if( fsRender & DMFL_RENDEROK )
- {
- PSZ pszLoc;
- RECORDINSERT ri;
- PCNRREC pCnrRec;
-
- memset( &ri, 0, sizeof( RECORDINSERT ) );
- ri.cb = sizeof( RECORDINSERT );
- ri.pRecordOrder = (PRECORDCORE) CMA_END;
- ri.pRecordParent = (PRECORDCORE) NULL;
- ri.zOrder = (USHORT) CMA_TOP;
- ri.cRecordsInsert = 1;
- ri.fInvalidateRecord = TRUE;
-
- pCnrRec = WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_ALLOCRECORD,
- MPFROMLONG( EXTRA_BYTES ),
- MPFROMLONG( 1 ) );
- if( pCnrRec )
- {
- DrgQueryStrName( pDragXfer->pditem->hstrContainerName,
- sizeof( pCnrRec->szTableName ), pCnrRec->szTableName );
- strcat( pCnrRec->szTableName, ":" );
- pszLoc = pCnrRec->szTableName + strlen( pCnrRec->szTableName );
- DrgQueryStrName( pDragXfer->pditem->hstrSourceName,
- sizeof( pCnrRec->szTableName ) -
- (pszLoc - pCnrRec->szTableName), pszLoc );
-
- DrgQueryStrName( pDragXfer->hstrRenderToName,
- sizeof( pCnrRec->szRenderedFileName ),
- pCnrRec->szRenderedFileName );
-
- pCnrRec->flAttr = RECATTR_OPENABLE;
- pCnrRec->mrc.pszIcon = (PSZ) &pCnrRec->szTableName;
- pCnrRec->mrc.hptrIcon = hptrOpenMe;
-
- if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_INSERTRECORD,
- MPFROMP( pCnrRec ), MPFROMP( &ri ) ) )
- {
- fSuccess = FALSE;
- Msg( "RenderComplete CM_INSERTRECORD RC(%X)",
- HWNDERR( hwndFrame ) );
- }
- }
- else
- {
- fSuccess = FALSE;
- Msg( "RenderComplete CM_ALLOCRECORD RC(%X)", HWNDERR( hwndFrame ) );
- }
- }
- else
- fSuccess = FALSE;
-
- if( fSuccess )
- {
- CNRINFO cnri;
-
- cnri.cb = sizeof( CNRINFO );
- cnri.pszCnrTitle = szDroppedOnCnrTitle;
- WinSendDlgItemMsg( hwndFrame, FID_CLIENT, CM_SETCNRINFO,
- MPFROMP( &cnri ), MPFROMLONG( CMA_CNRTITLE ) );
- }
- else
- {
- // Delete the temporary file if the render failed.
-
- char szRenderToName[ CCHMAXPATH ];
-
- DrgQueryStrName( pDragXfer->hstrRenderToName, sizeof szRenderToName,
- szRenderToName );
- DosDelete( szRenderToName );
- flStatus = DMFL_TARGETFAIL;
- }
-
- // Tell the source that we're all done here. At this point the Drag/Drop
- // is finally done.
-
- DrgSendTransferMsg( pDragXfer->pditem->hwndItem, DM_ENDCONVERSATION,
- MPFROMLONG( pDragXfer->pditem->ulItemID ),
- MPFROMLONG( flStatus ) );
-
- // It is the target's responsibility to delete the string handles.
-
- DrgDeleteStrHandle( pDragXfer->hstrSelectedRMF );
- DrgDeleteStrHandle( pDragXfer->hstrRenderToName );
-
- // Both the source and target must free the DRAGTRANSFER structure. The
- // source will have done this before it sent us the DM_RENDERCOMPLETE
- // message.
-
- DrgFreeDragtransfer( pDragXfer );
-
- // We need to keep a running total to know when all items in the drop have
- // been processed. When that happens, it is time to free the resources that
- // were allocated to the drop as a whole rather than to an indidvidual item.
-
- if( --pi->cDragItems == 0 )
- TargetCleanup( hwndFrame );
-
- return 0;
- }
-
- /**********************************************************************/
- /*-------------------------- EndConversation -------------------------*/
- /* */
- /* FREE THE RESOURCES USED BY DRAG/DROP PROCESSING. ONLY DO THIS IF */
- /* THIS IS THE LAST ITEM (there is one end-conversation message sent */
- /* to us for each item dropped). */
- /* */
- /* PARMS: frame window handle */
- /* */
- /* NOTES: This is a SOURCE window message that the target sends after*/
- /* it is done processing the DM_RENDERCOMPLETE message that */
- /* the source sent it. */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- MRESULT EndConversation( HWND hwndFrame )
- {
- PINSTANCE pi = INSTDATA( hwndFrame );
-
- if( !pi )
- {
- Msg( "EndConversation cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
- return 0;
- }
-
- // We need to keep a running total to know when all items in the drop have
- // been processed. When that happens, it is time to free the resources that
- // were allocated to the drag as a whole rather than to an indidvidual item.
-
- if( --pi->cDragItems == 0 )
- SourceCleanup( hwndFrame );
-
- return 0;
- }
-
- /**********************************************************************/
- /*----------------------- RemoveSourceEmphasis -----------------------*/
- /* */
- /* REMOVE SOURCE EMPHASIS FROM THE DRAGGED RECORDS. */
- /* */
- /* PARMS: frame window handle */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void RemoveSourceEmphasis( HWND hwndFrame )
- {
- PCNRREC pCnrRec = (PCNRREC) CMA_FIRST;
-
- // For every record with source emphasis, remove it.
-
- while( pCnrRec )
- {
- pCnrRec = (PCNRREC) WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
- CM_QUERYRECORDEMPHASIS,
- MPFROMP( pCnrRec ),
- MPFROMSHORT( CRA_SOURCE ) );
-
- if( pCnrRec == (PCNRREC) -1 )
- Msg( "RemoveSourceEmphasis..CM_QUERYRECORDEMPHASIS RC(%X)",
- HWNDERR( hwndFrame ) );
- else if( pCnrRec )
- if( !WinSendDlgItemMsg( hwndFrame, FID_CLIENT,
- CM_SETRECORDEMPHASIS, MPFROMP( pCnrRec ),
- MPFROM2SHORT( FALSE, CRA_SOURCE ) ) )
- Msg( "RemoveSourceEmphasis..CM_SETRECORDEMPHASIS RC(%X)",
- HWNDERR( hwndFrame ) );
- }
- }
-
- /**********************************************************************/
- /*--------------------------- TargetCleanup --------------------------*/
- /* */
- /* FREE THE RESOURCES USED BY DRAG/DROP PROCESSING FOR THE TARGET */
- /* */
- /* PARMS: frame window handle */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void TargetCleanup( HWND hwndFrame )
- {
- PINSTANCE pi = INSTDATA( hwndFrame );
-
- if( !pi )
- {
- Msg( "TargetCleanup cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
- return;
- }
-
- // It is the target's responsibility to delete the string resources. This
- // one API frees all the strings in all DRAGITEM structures.
-
- if( !DrgDeleteDraginfoStrHandles( pi->pSavedDragInfo ) )
- Msg( "TargetCleanup DrgDeleteDraginfoStrHandles RC(%X)",
- HWNDERR( hwndFrame ) );
-
- // Both the source and target must free the DRAGINFO structure.
-
- if( !DrgFreeDraginfo( pi->pSavedDragInfo ) &&
- PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
- Msg( "TargetCleanup DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
-
- pi->pSavedDragInfo = NULL;
- pi->cDragItems = 0;
- }
-
- /**********************************************************************/
- /*--------------------------- SourceCleanup --------------------------*/
- /* */
- /* FREE THE RESOURCES USED BY DRAG/DROP PROCESSING FOR THE SOURCE */
- /* */
- /* PARMS: frame window handle */
- /* */
- /* NOTES: */
- /* */
- /* RETURNS: nothing */
- /* */
- /*--------------------------------------------------------------------*/
- /**********************************************************************/
- void SourceCleanup( HWND hwndFrame )
- {
- PINSTANCE pi = INSTDATA( hwndFrame );
-
- if( !pi )
- {
- Msg( "SourceCleanup cant get Inst data RC(%X)", HWNDERR(hwndFrame) );
- return;
- }
-
- // Free the shared memory we got access to using DrgAccessDragInfo. If
- // the source process is the same as the target process, we get the
- // PMERR_SOURCE_SAME_AS_TARGET message. It's ok to get that - it just
- // means that we don't need to free the structure because the target
- // process already freed it.
-
- if( !DrgFreeDraginfo( pi->pSavedDragInfo ) &&
- PMERR_SOURCE_SAME_AS_TARGET != HWNDERR( hwndFrame ) )
- Msg( "SourceCleanup DrgFreeDraginfo RC(%X)", HWNDERR( hwndFrame ) );
-
- // This is important because the NULL-ness of pSavedDragInfo lets the
- // dragInit function know that another drag is now possible.
-
- pi->pSavedDragInfo = NULL;
- pi->cDragItems = 0;
- }
-
- /*************************************************************************
- * E N D O F S O U R C E *
- *************************************************************************/
-