home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
VSCPPv8.zip
/
VACPP
/
IBMCPP
/
samples
/
TOOLKIT
/
PM
/
DRAGDROP
/
DRAGDRAG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-17
|
40KB
|
1,177 lines
/**************************************************************************
* File name : dragdrag.c
*
* Description: This source file contains the direct manipulation routines
* of the Drag/drop sample.
*
* This source file contains the following functions:
*
* FreeSourceResources (hab, pDraginfo)
* PreventClose (hwndClient, cDrag)
* RemoveFinalBackslash (p)
* InitDrag(hwndClient, hList, hptrFile, hptrFolder, hptrMulti,
* pContainerName)
* EndConversation (hwndClient, mp1)
* DragLeave (void)
* DropHelp (hwndClient, pDraginfo)
* DragOver (pDraginfo, pCurrentDir)
* Drop (hab, hwndClient, pDraginfo, pCurrentDir)
* EndTarget (hwnd, pParm)
* CheckBusy (void)
* CheckClose (hwnd)
* TargetThread (void)
*
* Concepts : direct manipulation
*
* API's : DrgAccessDraginfo
* DrgDeleteDraginfoStrHandles
* DrgQueryDragitemCount
* DrgQueryDragitemPtr
* DrgFreeDraginfo
* WinWindowFromID
* WinSendMsg
* DrgAllocDraginfo
* DrgAddStrHandle
* WinQueryLboxItemText
* DrgSetDragitem
* DrgDrag
* WinDeleteLboxItem
* DrgQueryStrName
* DrgVerifyRMF
* DrgAllocDragtransfer
* DrgSendTransferMsg
* WinStartTimer
* WinGetMsg
* WinStopTimer
* WinDispatchMsg
* DrgFreeDragtransfer
* DosGetNamedSharedMem
* DosSubAllocMem
* DosCreateThread
* DrgQueryDragitem
* WinPostMsg
* DosCopy
* DosDelete
* DosEnterCritSec
* WinGetLastError
*
* Required
* Files : OS2.H, STRING.H, DRAGDROP.H
*
* Copyright (C) 1991 IBM Corporation
*
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is
* sample code created by IBM Corporation. This sample code is not
* part of any standard or IBM product and is provided to you solely
* for the purpose of assisting you in the development of your
* applications. The code is provided "AS IS", without
* warranty of any kind. IBM shall not be liable for any damages
* arising out of your use of the sample code, even if they have been
* advised of the possibility of such damages. *
*************************************************************************/
/*
* Include the required sections from the PM header file.
*/
#define INCL_DOSFILEMGR
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_SHLERRORS
#define INCL_WIN
#define INCL_WINSTDDRAG
/*
* Include the PM header file.
*/
#include <os2.h>
#include <os2def.h>
/*
* Include the C library header files.
*/
#include <string.h>
/*
* Include the application header files.
*/
#include "dragdrop.h"
static PDRAGTARGETTHREAD vpThreadParms = NULL;
/*
* Variables global to this file
*/
static char szRendMechFmtFILE [] = "<DRM_OS2FILE,DRF_UNKNOWN>";
/*
* Because the following items used by the target, are used only
* during the drag operation, and drag is a system modal operation,
* a target can always accept a drop.
*
* In any case, the target cannot allow the application to
* close when a drag is in progress, either as a target or a source.
* This is because the thread performing the operation would also be
* ended. A target could allow a close, but only if it prompted
* the user to request permission.
*/
static USHORT usOperation;
/* usOperation is used to remember the user selected
* (or application selected default * operation) between
* a DM_DRAGOVER
* and a DM_DROP message, to avoid re-figuring the operation.
* Because this is used during drag, which is a system modal
* operation, a target can always be dropped on.
* Used by target only.
*/
/*
* The following is used by both the source and target to keep the total
* number of drag operations that the application is currently involved
* in. If the count is non-zero, the application will not allow the user
* to close it.
*/
static ULONG ulDragCount = 0L;
/**************************************************************************
*
* Name : FreeSourceResources (hab, pDraginfo)
*
* Description: Frees the resources allocated by the source for a drag
* operation
*
* Concepts : accesses and deletes an instance of drag information
*
* API's : DrgAccessDraginfo
* DrgDeleteDraginfoStrHandles
* DrgQueryDragitemCount
* DrgQueryDragitemPtr
* DrgFreeDraginfo
*
* Parameters : pDraginfo = pointer to the drag information structure
*
* Return : TRUE = if resources freed successfully
* FALSE = unable to free all resources
*
*************************************************************************/
BOOL FreeSourceResources (HAB hab, PDRAGINFO pDraginfo)
{
PDRAGITEM pDragitem;
ULONG ulItemsDragged, i;
ERRORID errorid;
if(DrgAccessDraginfo(pDraginfo) && DrgDeleteDraginfoStrHandles(pDraginfo))
; /* drag access OK */
else
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
return FALSE;
}
ulItemsDragged = DrgQueryDragitemCount(pDraginfo);
for (i = 0L; i < ulItemsDragged; ++i)
{
pDragitem = DrgQueryDragitemPtr(pDraginfo, i);
if(!FreeAppDragitem((PAPPDRAGITEM)pDragitem->ulItemID))
{
MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR, TRUE);
return FALSE;
}
}
if(!FreeAppDraginfo(FindAppDraginfo(pDraginfo)))
{
MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR, TRUE);
return FALSE;
}
if(DrgFreeDraginfo(pDraginfo)
|| PMERR_SOURCE_SAME_AS_TARGET ==
ERRORIDERROR(WinGetLastError(hab)))
return TRUE;
else
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
return FALSE;
}
} /* End of FreeSourceResources */
/**************************************************************************
*
* Name : PreventClose (hwndClient, cDrag)
*
* Description: Disables the close option on the system menu when
* a drag is in progress, or enables it when all drag
* operations have completed.
*
* Concepts : system menu, enablement
*
* API's : WinWindowFromID
* WinSendMsg
*
* Parameters : hwndClient = client window handlenformation structure
* cDrag = the enabled state of the close menu item
*
* Return : TRUE = if the close menu item is disabled
* FALSE = if the close menu item has been enabled
*
*************************************************************************/
VOID PreventClose(HWND hwndClient, ULONG cDrag)
{
HWND hwndSysMenu = WinWindowFromID(ParentOf(hwndClient), FID_SYSMENU);
WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, (SHORT)TRUE),
MPFROM2SHORT(MIA_DISABLED, (SHORT)(cDrag ? MIA_DISABLED : FALSE)));
return;
} /* End of PreventClose */
/**************************************************************************
*
* Name : RemoveFinalBackslash (p)
*
* Description: Checks the final character in a string and,
* if it is a backslash, removes it.
*
* Concepts : pathnames
*
* API's : [none]
*
* Parameters : p = a pointer to the string
*
* Return : [none]
*
*************************************************************************/
VOID RemoveFinalBackslash (PSZ p)
{
for (; *p; ++p)
; /* go to the end of the string */
if (*--p == '\\')
{
*p = '\0';
}
} /* End of RemoveFinalBackslash */
/**************************************************************************
*
* Name : InitDrag(hwndClient, hList, hptrFile, hptrFolder,
* hptrMulti, pContainerName)
*
* Description: Builds a DRAGINFO structure for the selected items,
* then calls DrgDrag to perform the drag operation.
*
* Concepts : direct manipulation
*
* API's : DrgAllocDraginfo
* DrgAddStrHandle
* WinQueryLboxItemText
* DrgSetDragitem
*
* Parameters : hwndClient = client window handle
* hList = handle of the list of file names
* hptrFile = file handle
* hptrFolder = folder handle
* hptrMulti = multiple list handle
* pContainerName - pointer to name of container
*
* Return : TRUE = the drag operation was performed
* FALSE = unable to perform the drag operation
*
*************************************************************************/
BOOL InitDrag (HAB hab, HWND hwndClient, HWND hList, HPOINTER hptrFile,
HPOINTER hptrFolder, HPOINTER hptrMulti, PSZ pContainerName)
{
CHAR chDrive;
SHORT item;
ULONG i, ulItemsDragged;
HWND hwndTarget;
LHANDLE hImage;
DRAGITEM Dragitem;
HSTR hstrType, hstrRMF, hstrContainerName;
USHORT fsControl;
USHORT fsSupportedOps;
PPUBFILEFINDBUF pFile;
CHAR szItemName [64];
CHAR szFullContainerName [CCHMAXPATH];
PAPPDRAGINFO pAppDraginfo;
PDRAGINFO pSourceDraginfo;
DRAGIMAGE dimg;
/*
* Determine number of items selected prior to allocating the
* DRAGINFO structure. Note that this sample program requires at
* least one item to be selected in order to do a drag operation.
*/
ulItemsDragged = 0L;
item = WinQueryLboxSelItemFirst (hList);
while (item != LIT_NONE)
{
++ulItemsDragged;
item = WinQueryLboxSelItemNext (hList, item);
}
if (ulItemsDragged == 0L)
{
MessageBox(HWND_DESKTOP, IDMSG_ATLEASTONE, MB_OK | MB_ERROR, TRUE);
return FALSE;
}
/*
* Allocate the DRAGINFO structure and the APPDRAGINFO structure.
*/
pSourceDraginfo = DrgAllocDraginfo(ulItemsDragged);
pAppDraginfo = AllocAppDraginfo (hwndClient, pSourceDraginfo);
/*
* Initialize variable used to initialize the internal DRAGITEM
* structure.
*/
hstrType = DrgAddStrHandle (DRT_UNKNOWN); /* file type is unknown */
hstrRMF = DrgAddStrHandle (szRendMechFmtFILE); /* os2file, unknown */
strcpy (szFullContainerName, pContainerName); /* container name */
RemoveFinalBackslash (szFullContainerName);
strcat (szFullContainerName, "\\");
hstrContainerName = DrgAddStrHandle(szFullContainerName);
fsControl = 0;
chDrive = (CHAR) pContainerName[0];
if((chDrive=='A') || (chDrive=='B') || (chDrive=='a') || (chDrive=='b'))
{ /* is source container removable media? */
fsControl = fsControl | (SHORT)DC_REMOVEABLEMEDIA;
}
fsSupportedOps = DO_COPYABLE | DO_MOVEABLE; /* can only move or copy */
/*
* Initialize common portions of the internal Dragitem buffer.
*/
Dragitem.hwndItem = hwndClient;
Dragitem.hstrType = hstrType;
Dragitem.hstrRMF = hstrRMF;
Dragitem.hstrContainerName = hstrContainerName;
Dragitem.fsControl = fsControl;
Dragitem.fsSupportedOps = fsSupportedOps;
/*
* Initialize unique portions of the internal Dragitem buffer for each
* item that was selected.
*/
item = LIT_FIRST;
for (i = 0L; i < ulItemsDragged; ++i)
{
item = WinQueryLboxSelItemNext (hList, item);
WinQueryLboxItemText (hList, item, szItemName, sizeof(szItemName));
pFile = FindFileName (szItemName);
if (pFile == NULL)
{
MessageBox(HWND_DESKTOP, IDMSG_CANTLOCATE, MB_OK | MB_ERROR, TRUE);
}
else
{
Dragitem.hstrSourceName = DrgAddStrHandle (pFile->achName);
Dragitem.hstrTargetName = Dragitem.hstrSourceName;
Dragitem.ulItemID = (ULONG)AllocAppDragitem(pSourceDraginfo, pFile);
if(Dragitem.ulItemID == 0L)
return FALSE;
if (pFile->attrFile & FILE_DIRECTORY)
Dragitem.fsControl = Dragitem.fsControl | (SHORT)DC_CONTAINER;
if(!DrgSetDragitem(pSourceDraginfo, &Dragitem, sizeof(DRAGITEM), i))
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGSETITEMERROR,
MB_OK | MB_ERROR, TRUE);
return FALSE;
}
}
}
/*
* Drag the items.
*/
if (ulItemsDragged == 1L)
hImage = (Dragitem.fsControl & DC_CONTAINER) ? hptrFolder : hptrFile;
else
hImage = hptrMulti;
++ulDragCount; /* remember drag is in progress */
PreventClose(hwndClient, ulDragCount);
dimg.cb = sizeof (DRAGIMAGE);
dimg.hImage = hImage;
dimg.fl = DRG_ICON | DRG_TRANSPARENT;
dimg.cxOffset = 0;
dimg.cyOffset = 0;
pSourceDraginfo->hwndSource = hwndClient;
hwndTarget=DrgDrag(hwndClient, pSourceDraginfo, &dimg, 1L, VK_BUTTON2, NULL);
if (hwndTarget == NULLHANDLE)
{
/*
* User cancelled the drag or asked for help, so we can release
* the resources allocated to the drag operation.
*/
FreeSourceResources (hab, pSourceDraginfo);
--ulDragCount;
PreventClose (hwndClient, ulDragCount);
}
return TRUE;
} /* End of InitDrag */
/**************************************************************************
*
* Name : EndConversation(hwndClient, mp1)
*
* Description: Decrements ulItemsDragged by one for each
* DM_ENDCONVERSATION received. When ulItemsDragged
* becomes 0, the DRAGINFO structure is freed.
*
* Concepts : direct manipulation
*
* API's : WinWindowFromID
* WinDeleteLboxItem
* DrgFreeDraginfo
* WinGetLastError
*
* Parameters : hwndClient = client window handle
* mp1 = drag item ID
* mp2 = render success flag
*
* Return : NULL = successful end to the conversation
*
*************************************************************************/
MRESULT EndConversation(HAB hab, HWND hwndClient, MPARAM mp1, MPARAM mp2)
{
PAPPDRAGITEM pAppDragitem = (PAPPDRAGITEM)mp1;
PAPPDRAGINFO pAppDraginfo;
USHORT i;
HWND hwndLbox = WinWindowFromID (hwndClient, LIST_ID);
/*
* Did the target properly render the item?
*/
if(mp2 == (MPARAM)DMFL_TARGETFAIL)
MessageBox(HWND_DESKTOP, IDMSG_TARGETRENDER, MB_OK | MB_ERROR, TRUE);
/*
* delete the item from the listbox if the operation was a move
*/
if (pAppDragitem->pDraginfo->usOperation == (USHORT)DO_MOVE)
{
i = WinFindLboxItem (hwndLbox, pAppDragitem->pFile->achName);
WinDeleteLboxItem (hwndLbox, i);
}
pAppDraginfo = FindAppDraginfo(FindDraginfo(pAppDragitem));
if(!pAppDraginfo)
MessageBox(HWND_DESKTOP, IDMSG_FINDAPPDRAGINFO, MB_OK | MB_ERROR, TRUE);
FreeAppDragitem(pAppDragitem);
if (--pAppDraginfo->usItemsDragged == 0)
{
if(DrgFreeDraginfo(pAppDraginfo->pDraginfo)
|| PMERR_SOURCE_SAME_AS_TARGET ==
ERRORIDERROR(WinGetLastError(hab)))
{
if(!FreeAppDraginfo(pAppDraginfo))
MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR,TRUE);
else
{
--ulDragCount; /* indicate drag completed */
PreventClose(hwndClient, ulDragCount);
}
}
else
MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
}
return (MRESULT)NULL;
} /* End of EndConversation */
/**************************************************************************
*
* Name : DragLeave()
*
* Description: Called when a LN_DRAGLEAVE message is received.
* As this application does not do target emphasis,
* this function simply returns NULL.
*
* Concepts : target emphasis
*
* API's : [none]
*
* Parameters : [none]
*
* Return : NULL = successful end
*
*************************************************************************/
MRESULT DragLeave (void)
{
return (MRESULT)NULL;
} /* End of DragLeave */
/**************************************************************************
*
* Name : DropHelp(hwndClient, pDraginfo)
*
* Description: Issues a message to notify the user what would happen
* if mouse button 2 were released, based on the current
* operation.
*
* Concepts : direct manipulation
*
* API's : DrgAccessDraginfo
* DrgDeleteDraginfoStrHandles
* DrgFreeDraginfo
*
* Parameters : hwndClient = client window handle
* pDraginfo = pointer to drag information structure
*
* Return : NULL = successful
*
*************************************************************************/
MRESULT DropHelp (HWND hwndClient, PDRAGINFO pDraginfo)
{
char message[81];
if(!DrgAccessDraginfo (pDraginfo))
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
}
strcpy (message, "Dropping here would perform ");
switch (pDraginfo->usOperation)
{
case DO_DEFAULT:
strcat (message, "the default ");
break;
case DO_COPY:
strcat (message, "a copy ");
break;
case DO_MOVE:
strcat (message, "a move ");
break;
case DO_UNKNOWN:
strcat (message, "an unknown (private) ");
break;
}
strcat (message, "operation.");
Message (message);
if(DrgDeleteDraginfoStrHandles(pDraginfo) && DrgFreeDraginfo(pDraginfo))
; /* free OK */
else
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGERROR, MB_OK | MB_ERROR, TRUE);
}
return (MRESULT)NULL;
hwndClient; /* unreferenced formal parameter */
} /* End of DropHelp */
/**************************************************************************
*
* Name : DragOver(pDraginfo, pCurrentDir)
*
* Description: Provides visual feedback to the user as to whether it
* can support the drag operation
*
* Concepts : direct manipulation
*
* API's : DrgAccessDraginfo
* DrgFreeDraginfo
* DrgQueryDragitemPtr
* DrgQueryStrName
* DrgQueryDragitemCount
* DrgVerifyRMF
* WinGetLastError
*
* Parameters : pDraginfo = pointer to drag information structure
* pCurrentDir= the name of the current directory
*
* Return : DOR_DROP, DO_MOVE for a default operation
*
*************************************************************************/
MRESULT DragOver(HAB hab, PDRAGINFO pDraginfo, PSZ pCurrentDir)
{
USHORT usIndicator, cItems, i;
ULONG ulBytesWritten;
PDRAGITEM pditem;
CHAR SourceDir [CCHMAXPATH], chDrive;
/*
* Get access to the DRAGINFO structure.
*/
if(!DrgAccessDraginfo(pDraginfo))
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
return (MRFROM2SHORT (DOR_NODROPOP, 0));
}
usOperation = (USHORT)DO_MOVE; /* the default operation is move */
/*
* Determine if a drop can be accepted.
*/
switch (pDraginfo->usOperation)
{
/*
* return DOR_NODROPOP if current operation is link or unknown.
*/
case DO_UNKNOWN:
if(!DrgFreeDraginfo (pDraginfo))
MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
return (MRFROM2SHORT (DOR_NODROPOP, 0));
/*
* Determine default operation if current operation is default.
* The default is move unless either the source or the target is
* on different removable media.
*/
case DO_DEFAULT:
pditem = DrgQueryDragitemPtr (pDraginfo, 0);
ulBytesWritten = DrgQueryStrName(pditem->hstrContainerName,
sizeof(SourceDir),
SourceDir);
if(ulBytesWritten == 0L)
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
MB_OK | MB_ERROR, TRUE);
return (MRFROM2SHORT (DOR_NODROPOP, 0));
}
/*
* if the source and target are on the
* same drive, the operation is a move
*/
if (*pCurrentDir == SourceDir[0])
usOperation = (USHORT)DO_MOVE;
/*
* otherwise, different drives
*/
else
{
chDrive = (CHAR)pCurrentDir[0];
/*
* if the target is A: or B:, or the source
* is removeable media, the operation is a copy
*/
if((chDrive == 'A') || (chDrive == 'B') || (chDrive == 'a') ||
(chDrive=='b') || pditem->fsControl & DC_REMOVEABLEMEDIA)
{
usOperation = (USHORT)DO_COPY;
}
/*
* otherwise, the default operation is a move
*/
else
{
usOperation = (USHORT)DO_MOVE;
}
}
break;
case DO_MOVE:
case DO_COPY:
usOperation = pDraginfo->usOperation;
break;
}
/*
* In order to support the operation, the source must support the
* operation this target has decided upon. The source must also
* support a rendering mechanism of <DRM_OS2FILE,DRF_UNKNOWN>.
* This target doesn't care about the file type.
*/
usIndicator = DOR_DROP;
cItems = DrgQueryDragitemCount (pDraginfo);
/*
* inspect each item to see if it is acceptable
*/
for (i = 0; i < cItems; ++i)
{
pditem = DrgQueryDragitemPtr (pDraginfo, i);
/*
* the item is acceptable only if it is copyable and the
* operation is a copy, or it is moveable and the operation
* is a move, and it can render <DRM_OS2FILE,DRF_UNKNOWN>
*/
if (((pditem->fsSupportedOps & DO_COPYABLE) &&
(usOperation == (USHORT)DO_COPY)) ||
((pditem->fsSupportedOps & DO_MOVEABLE) &&
(usOperation == (USHORT)DO_MOVE)))
{
if (DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_UNKNOWN"))
{
usIndicator = DOR_DROP;
}
else
{
usIndicator = DOR_NEVERDROP;
break;
} /* endif DrgVerifyRendMechFmt */
}
else
{
usIndicator = DOR_NODROPOP;
break;
} /* endif supported ops */
} /* end for all items dragged */
if(!DrgFreeDraginfo(pDraginfo))
if(PMERR_SOURCE_SAME_AS_TARGET != ERRORIDERROR(WinGetLastError(hab)))
{
MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
return (MRFROM2SHORT (DOR_NODROPOP, 0));
}
return (MRFROM2SHORT(usIndicator, usOperation));
} /* End of DragOver */
/**************************************************************************
*
* Name : Drop (hwndClient, pDraginfo, pCurrentDir)
*
* Description: This function handles the drop operation
*
* Since we would not receive a DM_DROP message unless a
* DOR_DROP reply had been given for a DM_DRAGOVER, we
* can assume we have successfully validated that we can
* accept the drop. Note that drag would havesent another
* DM_DRAGOVER if the operation had changed.
*
* Therefore we don't have to re-validate the operation.
* We can go ahead and perform the operation. We will
* perform each copy in sequence, but will not capture
* the mouse. This should allow the user to perform
* other operations, but not require this application
* to start another thread and coordinate the ending of
* the conversation and freeing up of resources. The user
* will not be able to perform any other operations with
* this application while the operations are in progress.
*
* Concepts : direct manipulation
*
* API's : DrgAccessDraginfo
* DrgQueryDragitemPtr
* DrgQueryStrName
* DrgAddStrHandle
* DrgSendTransferMsg
* WinStartTimer
* WinGetMsg
* WinStopTimer
* WinDispatchMsg
* DrgFreeDragtransfer
* DosGetNamedSharedMem
* DrgDeleteDraginfoStrHandles
* DrgFreeDraginfo
* DosSubAllocMem
* DosCreateThread
*
* Parameters : hwndClient = client window handle
* pDraginfo = ointer to a drag information structure
* pCurrentDir= the name of the current directory
*
* Return : NULL = successful
*
*************************************************************************/
MRESULT Drop(HAB hab, HWND hwndClient, PDRAGINFO pDraginfo, PSZ pCurrentDir)
{
PDRAGTARGETTHREAD pParm;
PBYTE aStack;
TID tid;
USHORT i;
PDRAGTRANSFER pdxfer;
PDRAGITEM pditem;
HSTR hstrRMF;
char szFullTargetName [CCHMAXPATH];
char szTargetFile [CCHMAXPATHCOMP];
QMSG qmsg;
USHORT cRetry, idTimer;
ULONG mr, ulBytesWritten;
/*
* Get access to the Draginfo structure.
*/
if(!DrgAccessDraginfo (pDraginfo))
MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
if (pDraginfo->hwndSource == hwndClient)
{
/*
* Source window and target window are the same, so don't do the
* operation... just release the resources allocated for the drag.
*/
FreeSourceResources (hab, pDraginfo);
--ulDragCount;
PreventClose (hwndClient, ulDragCount);
return (MRESULT)NULL;
}
pditem = DrgQueryDragitemPtr (pDraginfo, 0);
/*
* if the source name wasn't provided, let the source render
*/
if (!pditem->hstrSourceName)
{
pdxfer = DrgAllocDragtransfer (pDraginfo->cditem);
hstrRMF = DrgAddStrHandle ("<DRM_OS2FILE, DRF_UNKNOWN>");
for (i=0; i<pDraginfo->cditem; i++)
{
pditem = DrgQueryDragitemPtr (pDraginfo, i);
/*
* Build the fully qualified target file name.
*/
strcpy (szFullTargetName, pCurrentDir);
RemoveFinalBackslash (szFullTargetName);
ulBytesWritten =DrgQueryStrName(pditem->hstrTargetName,
sizeof(szTargetFile),
szTargetFile);
if(ulBytesWritten == 0L)
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
MB_OK | MB_ERROR, TRUE);
if (szTargetFile[0] != '\\')
strcat(szFullTargetName, "\\");
strcat(szFullTargetName, szTargetFile);
/*
* initialize the DRAGTRANSFER
*/
pdxfer[i].cb = sizeof (DRAGTRANSFER);
pdxfer[i].hwndClient = hwndClient;
pdxfer[i].pditem = pditem;
pdxfer[i].hstrSelectedRMF = hstrRMF;
pdxfer[i].hstrRenderToName = DrgAddStrHandle (szFullTargetName);
pdxfer[i].ulTargetInfo = 0L;
pdxfer[i].usOperation = pDraginfo->usOperation;
pdxfer[i].fsReply = 0;
/*
* send the DM_RENDER to the source, retrying as necessary
*/
for (cRetry=0, mr=0; cRetry<MAX_RETRIES && !mr; cRetry++)
{
mr = (ULONG)DrgSendTransferMsg(pDraginfo->hwndSource,
DM_RENDER,
(MPARAM)(pdxfer + i),
(MPARAM)NULL);
/*
* if the source didn't render, retry if we can
*/
if (!mr)
{
if (pdxfer[i].fsReply & DMFL_RENDERRETRY)
{
idTimer = WinStartTimer (0L, 0L, 0L, 1000L);
/*
* start a timer to wait, but process
* messages so we don't hang the queue
*/
while (WinGetMsg (0L, &qmsg, 0L, 0, 0))
{
if ((qmsg.msg == WM_TIMER) &&
((USHORT) qmsg.mp1 == idTimer))
{
WinStopTimer (0L, 0L, idTimer);
break;
}
else
WinDispatchMsg (0L, &qmsg);
}
}
else
DrgFreeDragtransfer(pdxfer + i);
}
}
}
}
/*
* Allocate the stack segment for the target thread.
*/
else if (DosGetNamedSharedMem((PPVOID)&aStack, (PSZ)"\\sharemem\\dragmem",
PAG_READ | PAG_WRITE) != 0LU)
{
MessageBox(HWND_DESKTOP, IDMSG_CANTCREATESTACK, MB_OK | MB_ERROR, TRUE);
DrgDeleteDraginfoStrHandles(pDraginfo);
DrgFreeDraginfo(pDraginfo);
}
else
{
/*
* Build the parameter list structure for the target thread.
*/
DosSubAllocMem(aStack, (PPVOID)&pParm, sizeof(DRAGTARGETTHREAD));
pParm->pDraginfo = pDraginfo;
pParm->hwndClient = hwndClient;
pParm->usOperation = usOperation;
strcpy(pParm->szTargetDir, pCurrentDir);
/*
* Remember that a drag is in progress and start the target thread.
*/
++ulDragCount;
PreventClose (hwndClient, ulDragCount);
vpThreadParms = pParm;
DosCreateThread(&tid, (PFNTHREAD)TargetThread,
(ULONG)vpThreadParms, 0U, STACKSIZE);
}
return (MRESULT)NULL;
} /* End of Drop */
/**************************************************************************
*
* Name : EndTarget(hwnd, pParm)
*
* Description: This function is called whenever a WM_TARGETCOMPLETE
* message is received. It releases all resources used
* during the drag operation and remembers that the drag
* operation has completed.
*
* Concepts : direct manipulation
*
* API's : DrgQueryDragitemCount
* DrgQueryDragitem
* DrgSendTransferMsg
* DrgDeleteDraginfoStrHandles
* DrgFreeDraginfo
* WinPostMsg
*
* Parameters : hwnd = window handle
* pParm = points to drag information
*
* Return : NULL = successful
*
*************************************************************************/
MRESULT EndTarget (HWND hwnd, PDRAGTARGETTHREAD pParm)
{
USHORT cItems, i;
DRAGITEM Dragitem;
/*
* Decrement the count of drag operations in progress and prepare to
* release the resources allocated for the drag operation.
*/
--ulDragCount;
PreventClose (hwnd, ulDragCount);
cItems = DrgQueryDragitemCount (pParm->pDraginfo);
/*
* End the conversation for each item in the DRAGINFO structure and
* let source know we have completed the drag operation for each item.
*/
for (i = 0; i < cItems; ++i)
{
if(!DrgQueryDragitem (pParm->pDraginfo, sizeof(Dragitem), &Dragitem, i))
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYITEMERROR,
MB_OK | MB_ERROR, TRUE);
DrgSendTransferMsg(Dragitem.hwndItem, DM_ENDCONVERSATION,
MPFROMLONG(Dragitem.ulItemID),
MPFROMLONG(DMFL_TARGETSUCCESSFUL));
}
/*
* Free the draginfo structure.
*/
if(DrgDeleteDraginfoStrHandles(pParm->pDraginfo)
&& DrgFreeDraginfo(pParm->pDraginfo))
;
else
MessageBox(HWND_DESKTOP, IDMSG_DRAGERROR, MB_OK | MB_ERROR, TRUE);
WinPostMsg(hwnd, WM_REFRESH, NULL, NULL);
return (MRESULT)NULL;
} /* End of EndTarget */
/**************************************************************************
*
* Name : CheckBusy()
*
* Description: This call determines if a drag is in progress.
*
* Concepts : direct manipulation
*
* API's : [none]
*
* Parameters : [none]
*
* Return : TRUE = a drag is in progress
* FALSE = no drag in progress
*
*************************************************************************/
BOOL CheckBusy (void)
{
return ((BOOL) ulDragCount);
} /* End of CheckBusy */
/**************************************************************************
*
* Name : CheckClose(hwnd)
*
* Description: This call determines if a drag is in progress by
* checking ulDragCount. If a drag is in progress,
* close is not allowed.
*
* Concepts : direct manipulation
*
* API's : WinPostMsg
*
* Parameters : hwnd = window handle
*
* Return : TRUE = a drag is in progress
* FALSE = no drag in progress
*
*************************************************************************/
MRESULT CheckClose (HWND hwnd)
{
if (!ulDragCount)
WinPostMsg (hwnd, WM_QUIT, (MPARAM)0L, (MPARAM)0L);
return ((MPARAM)NULL);
} /* End of CheckClose */
/**************************************************************************
*
* Name : TargetThread()
*
* Description: This is the main function of this thread.
*
* Concepts : direct manipulation
*
* API's : DrgQueryDragitemCount
* DrgQueryDragitem
* DrgQueryStrName
* DosCopy
* DosDelete
* DosEnterCritSec
*
* Parameters : [none]
*
* Return : [none]
*
*************************************************************************/
VOID FAR TargetThread (void)
{
PDRAGTARGETTHREAD pParm;
USHORT cItems, i;
ULONG ulBytesWritten;
DRAGITEM Dragitem;
char szFullSourceName [CCHMAXPATH];
char szFullTargetName [CCHMAXPATH];
char szSourceFile [CCHMAXPATHCOMP];
char szTargetFile [CCHMAXPATHCOMP];
pParm = vpThreadParms;
/*
* Get the number of items being dragged.
*/
cItems = DrgQueryDragitemCount (pParm->pDraginfo);
/*
* If the source has provided the file name in the DRAGITEM
* structures, we can go ahead and do a target copy without getting
* the source involved in the operation. We will always copy the file
* using the suggested target name. In this application the names
* are always the same.
*/
for (i = 0; i < cItems; ++i)
{
if(!DrgQueryDragitem (pParm->pDraginfo, sizeof(Dragitem), &Dragitem, i))
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYITEMERROR,
MB_OK | MB_ERROR, TRUE);
if(Dragitem.hstrSourceName != 0L &&
Dragitem.hstrTargetName != 0L &&
Dragitem.hstrContainerName != 0L)
{
/*
* Build the fully qualified source file name.
*/
ulBytesWritten = DrgQueryStrName(Dragitem.hstrContainerName,
sizeof(szFullSourceName),
szFullSourceName);
if(ulBytesWritten == 0)
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
MB_OK | MB_ERROR, TRUE);
ulBytesWritten = DrgQueryStrName(Dragitem.hstrSourceName,
sizeof(szSourceFile),
szSourceFile);
if(ulBytesWritten == 0)
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
MB_OK | MB_ERROR, TRUE);
if (szSourceFile[0] == '\\')
strcpy (szSourceFile, szSourceFile+1);
strcat (szFullSourceName, szSourceFile);
/*
* Build the fully qualified target file name.
*/
strcpy (szFullTargetName, pParm->szTargetDir);
RemoveFinalBackslash (szFullTargetName);
ulBytesWritten = DrgQueryStrName(Dragitem.hstrTargetName,
sizeof(szTargetFile),
szTargetFile);
if(ulBytesWritten == 0)
MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
MB_OK | MB_ERROR, TRUE);
if (szTargetFile[0] != '\\')
strcat (szFullTargetName, "\\");
strcat (szFullTargetName, szTargetFile);
/*
* Do the operation. DosCopy works with different drives;
* DosMove does not, so we will use DosCopy and DosDelete.
*/
switch (pParm->usOperation)
{
case DO_MOVE: /* Mimic DosMove with DosCopy and DosDelete. */
if(DosCopy(szFullSourceName, szFullTargetName, DCPY_EXISTING)
== NO_ERROR)
DosDelete(szFullSourceName);
break;
case DO_COPY:
DosCopy (szFullSourceName, szFullTargetName, DCPY_EXISTING);
break;
} /* end switch usOperation */
} /* end of target copy */
} /* end of dragitem loop */
/*
* Post ourselves a target complete message so the client window
* knows we are done and can free the stack segment and the draginfo
* structure.
*/
DosEnterCritSec(); /* make sure we finish before the */
/* main thread frees our stack */
WinPostMsg (pParm->hwndClient, WM_TARGETCOMPLETE, pParm, NULL);
} /* End of TargetThread */
/*************************** End of dragdrag.c *************************/