home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / devtools / os2tk21j / c / samples / dragdrop / dragdrag.c__ / dragdrag.c
Encoding:
C/C++ Source or Header  |  1993-03-12  |  38.9 KB  |  1,175 lines

  1. /**************************************************************************
  2.  *  File name  :  dragdrag.c
  3.  *
  4.  *  Description:  This source file contains the direct manipulation routines
  5.  *                of the Drag/drop sample.
  6.  *
  7.  *                This source file contains the following functions:
  8.  *
  9.  *                FreeSourceResources (hab, pDraginfo)
  10.  *                PreventClose (hwndClient, cDrag)
  11.  *                RemoveFinalBackslash (p)
  12.  *                InitDrag(hwndClient, hList, hptrFile, hptrFolder, hptrMulti,
  13.  *                         pContainerName)
  14.  *                EndConversation (hwndClient, mp1)
  15.  *                DragLeave (void)
  16.  *                DropHelp (hwndClient, pDraginfo)
  17.  *                DragOver (pDraginfo, pCurrentDir)
  18.  *                Drop (hab, hwndClient, pDraginfo, pCurrentDir)
  19.  *                EndTarget (hwnd, pParm)
  20.  *                CheckBusy (void)
  21.  *                CheckClose (hwnd)
  22.  *                TargetThread (void)
  23.  *
  24.  *  Concepts   :  direct manipulation
  25.  *
  26.  *  API's      :  DrgAccessDraginfo
  27.  *                DrgDeleteDraginfoStrHandles
  28.  *                DrgQueryDragitemCount
  29.  *                DrgQueryDragitemPtr
  30.  *                DrgFreeDraginfo
  31.  *                WinWindowFromID
  32.  *                WinSendMsg
  33.  *                DrgAllocDraginfo
  34.  *                DrgAddStrHandle
  35.  *                WinQueryLboxItemText
  36.  *                DrgSetDragitem
  37.  *                DrgDrag
  38.  *                WinDeleteLboxItem
  39.  *                DrgQueryStrName
  40.  *                DrgVerifyRMF
  41.  *                DrgAllocDragtransfer
  42.  *                DrgSendTransferMsg
  43.  *                WinStartTimer
  44.  *                WinGetMsg
  45.  *                WinStopTimer
  46.  *                WinDispatchMsg
  47.  *                DrgFreeDragtransfer
  48.  *                DosGetNamedSharedMem
  49.  *                DosSubAllocMem
  50.  *                DosCreateThread
  51.  *                DrgQueryDragitem
  52.  *                WinPostMsg
  53.  *                DosCopy
  54.  *                DosDelete
  55.  *                DosEnterCritSec
  56.  *                WinGetLastError
  57.  *
  58.  *  Required
  59.  *    Files    :  OS2.H, STRING.H, DRAGDROP.H
  60.  *
  61.  *  Copyright (C) 1991 IBM Corporation
  62.  *
  63.  *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
  64.  *      sample code created by IBM Corporation. This sample code is not
  65.  *      part of any standard or IBM product and is provided to you solely
  66.  *      for  the purpose of assisting you in the development of your
  67.  *      applications.  The code is provided "AS IS", without
  68.  *      warranty of any kind.  IBM shall not be liable for any damages
  69.  *      arising out of your use of the sample code, even if they have been
  70.  *      advised of the possibility of such damages.                                                    *
  71.  *************************************************************************/
  72. /*
  73.  *        Include the required sections from the PM header file.
  74.  */
  75. #define INCL_DOSFILEMGR
  76. #define INCL_DOSPROCESS
  77. #define INCL_DOSERRORS
  78. #define INCL_SHLERRORS
  79. #define INCL_WIN
  80. #define INCL_WINSTDDRAG
  81.  
  82. /*
  83.  *                     Include the PM header file.
  84.  */
  85. #include <os2.h>
  86.  
  87. /*
  88.  *                  Include the C library header files.
  89.  */
  90. #include <string.h>
  91.  
  92. /*
  93.  *                 Include the application header files.
  94.  */
  95. #include "dragdrop.h"
  96.  
  97. static PDRAGTARGETTHREAD vpThreadParms = NULL;
  98.  
  99. /*
  100.  * Variables global to this file
  101.  */
  102. static char   szRendMechFmtFILE []  = "<DRM_OS2FILE,DRF_UNKNOWN>";
  103.  
  104. /*
  105.  * Because the following items used by the target, are used only
  106.  * during the drag operation, and drag is a system modal operation,
  107.  * a target can always accept a drop.
  108.  *
  109.  * In any case, the target cannot allow the application to
  110.  * close when a drag is in progress, either as a target or a source.
  111.  * This is because the thread performing the operation would also be
  112.  * ended.  A target could allow a close, but only if it prompted
  113.  * the user to request permission.
  114.  */
  115.  
  116. static USHORT    usOperation;
  117.       /* usOperation is used to remember the user selected
  118.        * (or application selected default * operation) between
  119.        * a DM_DRAGOVER
  120.        * and a DM_DROP message, to avoid re-figuring the operation.
  121.        * Because this is used during drag, which is a system modal
  122.        * operation, a target can always be dropped on.
  123.        * Used by target only.
  124.        */
  125.  
  126. /*
  127.  * The following is used by both the source and target to keep the total
  128.  * number of drag operations that the application is currently involved
  129.  * in. If the count is non-zero, the application will not allow the user
  130.  * to close it.
  131.  */
  132. static ULONG    ulDragCount = 0L;
  133.  
  134. /**************************************************************************
  135.  *
  136.  *  Name       : FreeSourceResources (hab, pDraginfo)
  137.  *
  138.  *  Description: Frees the resources allocated by the source for a drag
  139.  *               operation
  140.  *
  141.  *  Concepts   :  accesses and deletes an instance of drag information
  142.  *
  143.  *  API's      :  DrgAccessDraginfo
  144.  *                DrgDeleteDraginfoStrHandles
  145.  *                DrgQueryDragitemCount
  146.  *                DrgQueryDragitemPtr
  147.  *                DrgFreeDraginfo
  148.  *
  149.  *  Parameters :  pDraginfo = pointer to the drag information structure
  150.  *
  151.  *  Return     :  TRUE  = if resources freed successfully
  152.  *                FALSE = unable to free all resources
  153.  *
  154.  *************************************************************************/
  155. BOOL FreeSourceResources (HAB hab, PDRAGINFO pDraginfo)
  156. {
  157.    PDRAGITEM       pDragitem;
  158.    ULONG           ulItemsDragged, i;
  159.    ERRORID         errorid;
  160.  
  161.    if(DrgAccessDraginfo(pDraginfo) && DrgDeleteDraginfoStrHandles(pDraginfo))
  162.       ;           /* drag access OK */
  163.    else
  164.    {
  165.       MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
  166.       return FALSE;
  167.    }
  168.  
  169.    ulItemsDragged = DrgQueryDragitemCount(pDraginfo);
  170.  
  171.    for (i = 0L; i < ulItemsDragged; ++i)
  172.    {
  173.       pDragitem = DrgQueryDragitemPtr(pDraginfo, i);
  174.       if(!FreeAppDragitem((PAPPDRAGITEM)pDragitem->ulItemID))
  175.       {
  176.          MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR, TRUE);
  177.          return FALSE;
  178.       }
  179.    }
  180.  
  181.    if(!FreeAppDraginfo(FindAppDraginfo(pDraginfo)))
  182.    {
  183.       MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR, TRUE);
  184.       return FALSE;
  185.    }
  186.    if(DrgFreeDraginfo(pDraginfo)
  187.                || PMERR_SOURCE_SAME_AS_TARGET == WinGetLastError(hab))
  188.       return TRUE;
  189.    else
  190.    {
  191.       MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
  192.       return FALSE;
  193.    }
  194. }  /* End of FreeSourceResources  */
  195.  
  196.  
  197. /**************************************************************************
  198.  *
  199.  *  Name       : PreventClose (hwndClient, cDrag)
  200.  *
  201.  *  Description: Disables the close option on the system menu when
  202.  *               a drag is in progress, or enables it when all drag
  203.  *               operations have completed.
  204.  *
  205.  *  Concepts   :  system menu, enablement
  206.  *
  207.  *  API's      :  WinWindowFromID
  208.  *                WinSendMsg
  209.  *
  210.  *  Parameters :  hwndClient = client window handlenformation structure
  211.  *                cDrag      = the enabled state of the close menu item
  212.  *
  213.  *  Return     :  TRUE  = if the close menu item is disabled
  214.  *                FALSE = if the close menu item has been enabled
  215.  *
  216.  *************************************************************************/
  217. VOID PreventClose(HWND hwndClient, ULONG cDrag)
  218. {
  219.    HWND hwndSysMenu = WinWindowFromID(ParentOf(hwndClient), FID_SYSMENU);
  220.  
  221.    WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, (SHORT)TRUE),
  222.              MPFROM2SHORT(MIA_DISABLED, (SHORT)(cDrag ? MIA_DISABLED : FALSE)));
  223.  
  224.    return;
  225. }  /*  End of PreventClose  */
  226.  
  227.  
  228. /**************************************************************************
  229.  *
  230.  *  Name       : RemoveFinalBackslash (p)
  231.  *
  232.  *  Description: Checks the final character in a string and,
  233.  *               if it is a backslash, removes it.
  234.  *
  235.  *  Concepts   :  pathnames
  236.  *
  237.  *  API's      :  [none]
  238.  *
  239.  *  Parameters :  p = a pointer to the string
  240.  *
  241.  *  Return     :  [none]
  242.  *
  243.  *************************************************************************/
  244. VOID RemoveFinalBackslash (PSZ p)
  245. {
  246.    for (; *p; ++p)
  247.       ;                  /*  go to the end of the string  */
  248.  
  249.    if (*--p == '\\')
  250.    {
  251.       *p = '\0';
  252.    }
  253. }  /*  End of RemoveFinalBackslash  */
  254.  
  255.  
  256. /**************************************************************************
  257.  *
  258.  *  Name       : InitDrag(hwndClient, hList, hptrFile, hptrFolder,
  259.  *                        hptrMulti, pContainerName)
  260.  *
  261.  *  Description: Builds a DRAGINFO structure for the selected items,
  262.  *               then calls DrgDrag to perform the drag operation.
  263.  *
  264.  *  Concepts   :  direct manipulation
  265.  *
  266.  *  API's      :  DrgAllocDraginfo
  267.  *                DrgAddStrHandle
  268.  *                WinQueryLboxItemText
  269.  *                DrgSetDragitem
  270.  *
  271.  *  Parameters :  hwndClient = client window handle
  272.  *                hList      = handle of the list of file names
  273.  *                hptrFile   = file handle
  274.  *                hptrFolder = folder handle
  275.  *                hptrMulti  = multiple list handle
  276.  *                pContainerName - pointer to name of container
  277.  *
  278.  *  Return     :  TRUE  = the drag operation was performed
  279.  *                FALSE = unable to perform the drag operation
  280.  *
  281.  *************************************************************************/
  282. BOOL InitDrag (HAB hab, HWND hwndClient, HWND hList, HPOINTER hptrFile,
  283.                HPOINTER hptrFolder, HPOINTER hptrMulti, PSZ pContainerName)
  284. {
  285.    CHAR             chDrive;
  286.    SHORT            item;
  287.    ULONG            i, ulItemsDragged;
  288.    HWND             hwndTarget;
  289.    LHANDLE          hImage;
  290.    DRAGITEM         Dragitem;
  291.    HSTR             hstrType, hstrRMF, hstrContainerName;
  292.    USHORT           fsControl;
  293.    USHORT           fsSupportedOps;
  294.    PPUBFILEFINDBUF  pFile;
  295.    CHAR             szItemName [64];
  296.    CHAR             szFullContainerName [CCHMAXPATH];
  297.    PAPPDRAGINFO     pAppDraginfo;
  298.    PDRAGINFO        pSourceDraginfo;
  299.    DRAGIMAGE        dimg;
  300.  
  301.    /*
  302.     * Determine number of items selected prior to allocating the
  303.     * DRAGINFO structure. Note that this sample program requires at
  304.     * least one item to be selected in order to do a drag operation.
  305.     */
  306.  
  307.    ulItemsDragged = 0L;
  308.    item = WinQueryLboxSelItemFirst (hList);
  309.  
  310.    while (item != LIT_NONE)
  311.    {
  312.       ++ulItemsDragged;
  313.       item = WinQueryLboxSelItemNext (hList, item);
  314.    }
  315.  
  316.    if (ulItemsDragged == 0L)
  317.    {
  318.       MessageBox(HWND_DESKTOP, IDMSG_ATLEASTONE, MB_OK | MB_ERROR, TRUE);
  319.       return FALSE;
  320.    }
  321.  
  322.    /*
  323.     * Allocate the DRAGINFO structure and the APPDRAGINFO structure.
  324.     */
  325.    pSourceDraginfo = DrgAllocDraginfo(ulItemsDragged);
  326.    pAppDraginfo = AllocAppDraginfo (hwndClient, pSourceDraginfo);
  327.  
  328.    /*
  329.     * Initialize variable used to initialize the internal DRAGITEM
  330.     * structure.
  331.     */
  332.    hstrType  = DrgAddStrHandle (DRT_UNKNOWN);       /* file type is unknown  */
  333.    hstrRMF   = DrgAddStrHandle (szRendMechFmtFILE); /* os2file, unknown      */
  334.    strcpy (szFullContainerName, pContainerName);    /* container name        */
  335.  
  336.    RemoveFinalBackslash (szFullContainerName);
  337.    strcat (szFullContainerName, "\\");
  338.    hstrContainerName = DrgAddStrHandle(szFullContainerName);
  339.  
  340.    fsControl = 0;
  341.    chDrive = (CHAR) pContainerName[0];
  342.  
  343.    if((chDrive=='A') || (chDrive=='B') || (chDrive=='a') || (chDrive=='b'))
  344.    {       /* is source container removable media?   */
  345.       fsControl = fsControl | (SHORT)DC_REMOVEABLEMEDIA;
  346.    }
  347.  
  348.    fsSupportedOps = DO_COPYABLE | DO_MOVEABLE;    /* can only move or copy */
  349.  
  350.    /*
  351.     * Initialize common portions of the internal Dragitem buffer.
  352.     */
  353.    Dragitem.hwndItem          = hwndClient;
  354.    Dragitem.hstrType          = hstrType;
  355.    Dragitem.hstrRMF           = hstrRMF;
  356.    Dragitem.hstrContainerName = hstrContainerName;
  357.    Dragitem.fsControl         = fsControl;
  358.    Dragitem.fsSupportedOps    = fsSupportedOps;
  359.  
  360.    /*
  361.     * Initialize unique portions of the internal Dragitem buffer for each
  362.     * item that was selected.
  363.     */
  364.    item = LIT_FIRST;
  365.  
  366.    for (i = 0L; i < ulItemsDragged; ++i)
  367.    {
  368.       item = WinQueryLboxSelItemNext (hList, item);
  369.       WinQueryLboxItemText (hList, item, szItemName, sizeof(szItemName));
  370.       pFile = FindFileName (szItemName);
  371.  
  372.       if (pFile == NULL)
  373.       {
  374.          MessageBox(HWND_DESKTOP, IDMSG_CANTLOCATE, MB_OK | MB_ERROR, TRUE);
  375.       }
  376.       else
  377.       {
  378.          Dragitem.hstrSourceName = DrgAddStrHandle (pFile->achName);
  379.          Dragitem.hstrTargetName = Dragitem.hstrSourceName;
  380.          Dragitem.ulItemID = (ULONG)AllocAppDragitem(pSourceDraginfo, pFile);
  381.          if(Dragitem.ulItemID == 0L)
  382.             return FALSE;
  383.          if (pFile->attrFile & FILE_DIRECTORY)
  384.             Dragitem.fsControl = Dragitem.fsControl | (SHORT)DC_CONTAINER;
  385.  
  386.          if(!DrgSetDragitem(pSourceDraginfo, &Dragitem, sizeof(DRAGITEM), i))
  387.          {
  388.             MessageBox(HWND_DESKTOP, IDMSG_DRAGSETITEMERROR,
  389.                        MB_OK | MB_ERROR, TRUE);
  390.             return FALSE;
  391.          }
  392.       }
  393.    }
  394.    /*
  395.     *  Drag the items.
  396.     */
  397.    if (ulItemsDragged == 1L)
  398.       hImage = (Dragitem.fsControl & DC_CONTAINER) ? hptrFolder : hptrFile;
  399.    else
  400.       hImage = hptrMulti;
  401.  
  402.    ++ulDragCount;                     /* remember drag is in progress     */
  403.    PreventClose(hwndClient, ulDragCount);
  404.  
  405.    dimg.cb       = sizeof (DRAGIMAGE);
  406.    dimg.hImage   = hImage;
  407.    dimg.fl       = DRG_ICON | DRG_TRANSPARENT;
  408.    dimg.cxOffset = 0;
  409.    dimg.cyOffset = 0;
  410.  
  411.    pSourceDraginfo->hwndSource = hwndClient;
  412.    hwndTarget=DrgDrag(hwndClient, pSourceDraginfo, &dimg, 1L, VK_BUTTON2, NULL);
  413.  
  414.    if (hwndTarget == NULLHANDLE)
  415.    {
  416.      /*
  417.       * User cancelled the drag or asked for help, so we can release
  418.       * the resources allocated to the drag operation.
  419.       */
  420.       FreeSourceResources (hab, pSourceDraginfo);
  421.       --ulDragCount;
  422.       PreventClose (hwndClient, ulDragCount);
  423.    }
  424.    return TRUE;
  425. }     /*  End of InitDrag  */
  426.  
  427.  
  428. /**************************************************************************
  429.  *
  430.  *  Name       : EndConversation(hwndClient, mp1)
  431.  *
  432.  *  Description: Decrements ulItemsDragged by one for each
  433.  *               DM_ENDCONVERSATION received.  When ulItemsDragged
  434.  *               becomes 0, the DRAGINFO structure is freed.
  435.  *
  436.  *  Concepts   :  direct manipulation
  437.  *
  438.  *  API's      :  WinWindowFromID
  439.  *                WinDeleteLboxItem
  440.  *                DrgFreeDraginfo
  441.  *                WinGetLastError
  442.  *
  443.  *  Parameters :  hwndClient = client window handle
  444.  *                mp1        = drag item ID
  445.  *                mp2        = render success flag
  446.  *
  447.  *  Return     :  NULL = successful end to the conversation
  448.  *
  449.  *************************************************************************/
  450. MRESULT EndConversation(HAB hab, HWND hwndClient, MPARAM mp1, MPARAM mp2)
  451. {
  452.    PAPPDRAGITEM pAppDragitem = (PAPPDRAGITEM)mp1;
  453.    PAPPDRAGINFO pAppDraginfo;
  454.    USHORT       i;
  455.    HWND         hwndLbox = WinWindowFromID (hwndClient, LIST_ID);
  456.  
  457.   /*
  458.    *   Did the target properly render the item?
  459.    */
  460.    if(mp2 == (MPARAM)DMFL_TARGETFAIL)
  461.       MessageBox(HWND_DESKTOP, IDMSG_TARGETRENDER, MB_OK | MB_ERROR, TRUE);
  462.   /*
  463.    * delete the item from the listbox if the operation was a move
  464.    */
  465.    if (pAppDragitem->pDraginfo->usOperation == (USHORT)DO_MOVE)
  466.    {
  467.       i = WinFindLboxItem (hwndLbox, pAppDragitem->pFile->achName);
  468.       WinDeleteLboxItem (hwndLbox, i);
  469.    }
  470.  
  471.    pAppDraginfo = FindAppDraginfo(FindDraginfo(pAppDragitem));
  472.    if(!pAppDraginfo)
  473.       MessageBox(HWND_DESKTOP, IDMSG_FINDAPPDRAGINFO, MB_OK | MB_ERROR, TRUE);
  474.    FreeAppDragitem(pAppDragitem);
  475.  
  476.    if (--pAppDraginfo->usItemsDragged == 0)
  477.    {
  478.       if(DrgFreeDraginfo(pAppDraginfo->pDraginfo)
  479.                || PMERR_SOURCE_SAME_AS_TARGET == WinGetLastError(hab))
  480.       {
  481.          if(!FreeAppDraginfo(pAppDraginfo))
  482.             MessageBox(HWND_DESKTOP, IDMSG_MEMFREEERROR, MB_OK | MB_ERROR,TRUE);
  483.          else
  484.          {
  485.             --ulDragCount;                   /* indicate drag completed */
  486.             PreventClose(hwndClient, ulDragCount);
  487.          }
  488.       }
  489.       else
  490.          MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
  491.    }
  492.    return (MRESULT)NULL;
  493. }  /*  End of EndConversation  */
  494.  
  495.  
  496. /**************************************************************************
  497.  *
  498.  *  Name       : DragLeave()
  499.  *
  500.  *  Description: Called when a LN_DRAGLEAVE message is received.
  501.  *               As this application does not do target emphasis,
  502.  *               this function simply returns NULL.
  503.  *
  504.  *  Concepts   :  target emphasis
  505.  *
  506.  *  API's      :  [none]
  507.  *
  508.  *  Parameters :  [none]
  509.  *
  510.  *  Return     :  NULL = successful end
  511.  *
  512.  *************************************************************************/
  513. MRESULT DragLeave (void)
  514. {
  515.    return (MRESULT)NULL;
  516. }  /*  End of DragLeave  */
  517.  
  518. /**************************************************************************
  519.  *
  520.  *  Name       : DropHelp(hwndClient, pDraginfo)
  521.  *
  522.  *  Description: Issues a message to notify the user what would happen
  523.  *               if mouse button 2 were released, based on the current
  524.  *               operation.
  525.  *
  526.  *  Concepts   :  direct manipulation
  527.  *
  528.  *  API's      :  DrgAccessDraginfo
  529.  *                DrgDeleteDraginfoStrHandles
  530.  *                DrgFreeDraginfo
  531.  *
  532.  *  Parameters :  hwndClient = client window handle
  533.  *                pDraginfo  = pointer to drag information structure
  534.  *
  535.  *  Return     :  NULL = successful
  536.  *
  537.  *************************************************************************/
  538. MRESULT DropHelp (HWND hwndClient, PDRAGINFO pDraginfo)
  539. {
  540.    char message[81];
  541.  
  542.    if(!DrgAccessDraginfo (pDraginfo))
  543.    {
  544.       MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
  545.    }
  546.    strcpy (message, "Dropping here would perform ");
  547.  
  548.    switch (pDraginfo->usOperation)
  549.    {
  550.    case DO_DEFAULT:
  551.       strcat (message, "the default ");
  552.       break;
  553.    case DO_COPY:
  554.       strcat (message, "a copy ");
  555.       break;
  556.    case DO_MOVE:
  557.       strcat (message, "a move ");
  558.       break;
  559.    case DO_UNKNOWN:
  560.       strcat (message, "an unknown (private) ");
  561.       break;
  562.    }
  563.  
  564.    strcat (message, "operation.");
  565.    Message (message);
  566.  
  567.    if(DrgDeleteDraginfoStrHandles(pDraginfo) && DrgFreeDraginfo(pDraginfo))
  568.       ;        /*  free OK  */
  569.    else
  570.    {
  571.       MessageBox(HWND_DESKTOP, IDMSG_DRAGERROR, MB_OK | MB_ERROR, TRUE);
  572.    }
  573.    return (MRESULT)NULL;
  574.    hwndClient;                     /* unreferenced formal parameter */
  575. }  /*  End of DropHelp  */
  576.  
  577.  
  578. /**************************************************************************
  579.  *
  580.  *  Name       : DragOver(pDraginfo, pCurrentDir)
  581.  *
  582.  *  Description: Provides visual feedback to the user as to whether it
  583.  *               can support the drag operation
  584.  *
  585.  *  Concepts   :  direct manipulation
  586.  *
  587.  *  API's      :  DrgAccessDraginfo
  588.  *                DrgFreeDraginfo
  589.  *                DrgQueryDragitemPtr
  590.  *                DrgQueryStrName
  591.  *                DrgQueryDragitemCount
  592.  *                DrgVerifyRMF
  593.  *                WinGetLastError
  594.  *
  595.  *  Parameters :  pDraginfo  = pointer to drag information structure
  596.  *                pCurrentDir= the name of the current directory
  597.  *
  598.  *  Return     :  DOR_DROP, DO_MOVE for a default operation
  599.  *
  600.  *************************************************************************/
  601. MRESULT DragOver(HAB hab, PDRAGINFO pDraginfo, PSZ pCurrentDir)
  602. {
  603.    USHORT        usIndicator, cItems, i;
  604.    ULONG         ulBytesWritten;
  605.    PDRAGITEM     pditem;
  606.    CHAR          SourceDir [CCHMAXPATH], chDrive;
  607.  
  608.   /*
  609.    * Get access to the DRAGINFO structure.
  610.    */
  611.    if(!DrgAccessDraginfo(pDraginfo))
  612.    {
  613.       MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
  614.       return (MRFROM2SHORT (DOR_NODROPOP, 0));
  615.    }
  616.    usOperation = (USHORT)DO_MOVE;          /* the default operation is move */
  617.  
  618.   /*
  619.    * Determine if a drop can be accepted.
  620.    */
  621.    switch (pDraginfo->usOperation)
  622.    {
  623.     /*
  624.      * return DOR_NODROPOP if current operation is link or unknown.
  625.      */
  626.    case DO_UNKNOWN:
  627.       if(!DrgFreeDraginfo (pDraginfo))
  628.          MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
  629.       return (MRFROM2SHORT (DOR_NODROPOP, 0));
  630.  
  631.     /*
  632.      * Determine default operation if current operation is default.
  633.      * The default is move unless either the source or the target is
  634.      * on different removable media.
  635.      */
  636.    case DO_DEFAULT:
  637.       pditem = DrgQueryDragitemPtr (pDraginfo, 0);
  638.       ulBytesWritten = DrgQueryStrName(pditem->hstrContainerName,
  639.                                        sizeof(SourceDir),
  640.                                        SourceDir);
  641.       if(ulBytesWritten == 0L)
  642.       {
  643.          MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
  644.                           MB_OK | MB_ERROR, TRUE);
  645.          return (MRFROM2SHORT (DOR_NODROPOP, 0));
  646.       }
  647.  
  648.          /*
  649.           * if the source and target are on the
  650.           * same drive, the operation is a move
  651.           */
  652.       if (*pCurrentDir == SourceDir[0])
  653.          usOperation = (USHORT)DO_MOVE;
  654.          /*
  655.           * otherwise, different drives
  656.           */
  657.       else
  658.       {
  659.          chDrive = (CHAR)pCurrentDir[0];
  660.            /*
  661.             * if the target is A: or B:, or the source
  662.             * is removeable media, the operation is a copy
  663.             */
  664.          if((chDrive == 'A') || (chDrive == 'B') || (chDrive == 'a') ||
  665.             (chDrive=='b') || pditem->fsControl & DC_REMOVEABLEMEDIA)
  666.          {
  667.             usOperation = (USHORT)DO_COPY;
  668.          }
  669.            /*
  670.             * otherwise, the default operation is a move
  671.             */
  672.          else
  673.          {
  674.             usOperation = (USHORT)DO_MOVE;
  675.          }
  676.       }
  677.       break;
  678.  
  679.    case DO_MOVE:
  680.    case DO_COPY:
  681.       usOperation = pDraginfo->usOperation;
  682.       break;
  683.    }
  684.  
  685.   /*
  686.    * In order to support the operation, the source must support the
  687.    * operation this target has decided upon.  The source must also
  688.    * support a rendering mechanism of <DRM_OS2FILE,DRF_UNKNOWN>.
  689.    * This target doesn't care about the file type.
  690.    */
  691.  
  692.    usIndicator = DOR_DROP;
  693.    cItems = DrgQueryDragitemCount (pDraginfo);
  694.  
  695.    /*
  696.     * inspect each item to see if it is acceptable
  697.     */
  698.    for (i = 0; i < cItems; ++i)
  699.    {
  700.       pditem = DrgQueryDragitemPtr (pDraginfo, i);
  701.  
  702.      /*
  703.       * the item is acceptable only if it is copyable and the
  704.       * operation is a copy, or it is moveable and the operation
  705.       * is a move, and it can render <DRM_OS2FILE,DRF_UNKNOWN>
  706.       */
  707.       if (((pditem->fsSupportedOps & DO_COPYABLE) &&
  708.                         (usOperation == (USHORT)DO_COPY)) ||
  709.           ((pditem->fsSupportedOps & DO_MOVEABLE) &&
  710.                           (usOperation == (USHORT)DO_MOVE)))
  711.       {
  712.          if (DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_UNKNOWN"))
  713.          {
  714.             usIndicator = DOR_DROP;
  715.          }
  716.          else
  717.          {
  718.             usIndicator = DOR_NEVERDROP;
  719.             break;
  720.          }                            /* endif DrgVerifyRendMechFmt */
  721.       }
  722.       else
  723.       {
  724.          usIndicator = DOR_NODROPOP;
  725.          break;
  726.       }                                     /* endif supported ops        */
  727.    }                                       /* end for all items dragged  */
  728.  
  729.    if(!DrgFreeDraginfo(pDraginfo))
  730.       if(PMERR_SOURCE_SAME_AS_TARGET != WinGetLastError(hab))
  731.       {
  732.          MessageBox(HWND_DESKTOP, IDMSG_DRAGFREEERROR, MB_OK | MB_ERROR, TRUE);
  733.          return (MRFROM2SHORT (DOR_NODROPOP, 0));
  734.       }
  735.    return (MRFROM2SHORT(usIndicator, usOperation));
  736. }  /*  End of DragOver  */
  737.  
  738.  
  739. /**************************************************************************
  740.  *
  741.  *  Name       :  Drop (hwndClient, pDraginfo, pCurrentDir)
  742.  *
  743.  *  Description:  This function handles the drop operation
  744.  *
  745.  *                Since we would not receive a DM_DROP message unless a
  746.  *                DOR_DROP reply had been given for a DM_DRAGOVER, we
  747.  *                can assume we have successfully validated that we can
  748.  *                accept the drop. Note that drag would havesent another
  749.  *                DM_DRAGOVER if the operation had changed.
  750.  *
  751.  *                Therefore we don't have to re-validate the operation.
  752.  *                We can go ahead and perform the operation. We will
  753.  *                perform each copy in sequence, but will not capture
  754.  *                the mouse. This should allow the user to perform
  755.  *                other operations, but not require this application
  756.  *                to start another thread and coordinate the ending of
  757.  *                the conversation and freeing up of resources. The user
  758.  *                will not be able to perform any other operations with
  759.  *                this application while the operations are in progress.
  760.  *
  761.  *  Concepts   :  direct manipulation
  762.  *
  763.  *  API's      :  DrgAccessDraginfo
  764.  *                DrgQueryDragitemPtr
  765.  *                DrgQueryStrName
  766.  *                DrgAddStrHandle
  767.  *                DrgSendTransferMsg
  768.  *                WinStartTimer
  769.  *                WinGetMsg
  770.  *                WinStopTimer
  771.  *                WinDispatchMsg
  772.  *                DrgFreeDragtransfer
  773.  *                DosGetNamedSharedMem
  774.  *                DrgDeleteDraginfoStrHandles
  775.  *                DrgFreeDraginfo
  776.  *                DosSubAllocMem
  777.  *                DosCreateThread
  778.  *
  779.  *  Parameters :  hwndClient = client window handle
  780.  *                pDraginfo  = ointer to a drag information structure
  781.  *                pCurrentDir= the name of the current directory
  782.  *
  783.  *  Return     :  NULL = successful
  784.  *
  785.  *************************************************************************/
  786. MRESULT Drop(HAB hab, HWND hwndClient, PDRAGINFO pDraginfo, PSZ pCurrentDir)
  787. {
  788.    PDRAGTARGETTHREAD     pParm;
  789.    PBYTE          aStack;
  790.    TID           tid;
  791.    USHORT        i;
  792.    PDRAGTRANSFER pdxfer;
  793.    PDRAGITEM     pditem;
  794.    HSTR          hstrRMF;
  795.    char          szFullTargetName  [CCHMAXPATH];
  796.    char          szTargetFile [CCHMAXPATHCOMP];
  797.    QMSG          qmsg;
  798.    USHORT        cRetry, idTimer;
  799.    ULONG         mr, ulBytesWritten;
  800.  
  801.    /*
  802.     * Get access to the Draginfo structure.
  803.     */
  804.    if(!DrgAccessDraginfo (pDraginfo))
  805.       MessageBox(HWND_DESKTOP, IDMSG_DRAGACCESSERROR, MB_OK | MB_ERROR, TRUE);
  806.    if (pDraginfo->hwndSource == hwndClient)
  807.    {
  808.      /*
  809.       * Source window and target window are the same, so don't do the
  810.       * operation... just release the resources allocated for the drag.
  811.       */
  812.       FreeSourceResources (hab, pDraginfo);
  813.       --ulDragCount;
  814.       PreventClose (hwndClient, ulDragCount);
  815.       return (MRESULT)NULL;
  816.    }
  817.  
  818.    pditem = DrgQueryDragitemPtr (pDraginfo, 0);
  819.  
  820.    /*
  821.     * if the source name wasn't provided, let the source render
  822.     */
  823.    if (!pditem->hstrSourceName)
  824.    {
  825.       pdxfer   = DrgAllocDragtransfer (pDraginfo->cditem);
  826.       hstrRMF  = DrgAddStrHandle ("<DRM_OS2FILE, DRF_UNKNOWN>");
  827.  
  828.       for (i=0; i<pDraginfo->cditem; i++)
  829.       {
  830.          pditem = DrgQueryDragitemPtr (pDraginfo, i);
  831.  
  832.        /*
  833.         * Build the fully qualified target file name.
  834.         */
  835.          strcpy (szFullTargetName, pCurrentDir);
  836.          RemoveFinalBackslash (szFullTargetName);
  837.          ulBytesWritten =DrgQueryStrName(pditem->hstrTargetName,
  838.                                          sizeof(szTargetFile),
  839.                                          szTargetFile);
  840.          if(ulBytesWritten == 0L)
  841.             MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
  842.                            MB_OK | MB_ERROR, TRUE);
  843.  
  844.          if (szTargetFile[0] != '\\')
  845.             strcat(szFullTargetName, "\\");
  846.          strcat(szFullTargetName, szTargetFile);
  847.  
  848.        /*
  849.         * initialize the DRAGTRANSFER
  850.         */
  851.          pdxfer[i].cb               = sizeof (DRAGTRANSFER);
  852.          pdxfer[i].hwndClient       = hwndClient;
  853.          pdxfer[i].pditem           = pditem;
  854.          pdxfer[i].hstrSelectedRMF  = hstrRMF;
  855.          pdxfer[i].hstrRenderToName = DrgAddStrHandle (szFullTargetName);
  856.          pdxfer[i].ulTargetInfo     = 0L;
  857.          pdxfer[i].usOperation      = pDraginfo->usOperation;
  858.          pdxfer[i].fsReply          = 0;
  859.  
  860.          /*
  861.           * send the DM_RENDER to the source, retrying as necessary
  862.           */
  863.          for (cRetry=0, mr=0; cRetry<MAX_RETRIES && !mr; cRetry++)
  864.          {
  865.             mr = (ULONG)DrgSendTransferMsg(pDraginfo->hwndSource,
  866.                                            DM_RENDER,
  867.                                            (MPARAM)(pdxfer + i),
  868.                                            (MPARAM)NULL);
  869.  
  870.            /*
  871.             * if the source didn't render, retry if we can
  872.             */
  873.             if (!mr)
  874.             {
  875.                if (pdxfer[i].fsReply & DMFL_RENDERRETRY)
  876.                {
  877.                   idTimer = WinStartTimer (0L, 0L, 0L, 1000L);
  878.  
  879.                /*
  880.                 * start a timer to wait, but process
  881.                 * messages so we don't hang the queue
  882.                 */
  883.                   while (WinGetMsg (0L, &qmsg, 0L, 0, 0))
  884.                   {
  885.                      if ((qmsg.msg == WM_TIMER) &&
  886.                                ((USHORT) qmsg.mp1 == idTimer))
  887.                      {
  888.                         WinStopTimer (0L, 0L, idTimer);
  889.                         break;
  890.                      }
  891.                      else
  892.                         WinDispatchMsg (0L, &qmsg);
  893.                   }
  894.                }
  895.                else
  896.                   DrgFreeDragtransfer(pdxfer + i);
  897.             }
  898.          }
  899.       }
  900.    }
  901.  
  902.    /*
  903.     * Allocate the stack segment for the target thread.
  904.     */
  905.    else if (DosGetNamedSharedMem((PPVOID)&aStack, (PSZ)"\\sharemem\\dragmem",
  906.                                  PAG_READ | PAG_WRITE) != 0LU)
  907.    {
  908.       MessageBox(HWND_DESKTOP, IDMSG_CANTCREATESTACK, MB_OK | MB_ERROR, TRUE);
  909.       DrgDeleteDraginfoStrHandles(pDraginfo);
  910.       DrgFreeDraginfo(pDraginfo);
  911.    }
  912.    else
  913.    {
  914.      /*
  915.       * Build the parameter list structure for the target thread.
  916.       */
  917.       DosSubAllocMem(aStack, (PPVOID)&pParm, sizeof(DRAGTARGETTHREAD));
  918.  
  919.       pParm->pDraginfo   = pDraginfo;
  920.       pParm->hwndClient  = hwndClient;
  921.       pParm->usOperation = usOperation;
  922.       strcpy(pParm->szTargetDir, pCurrentDir);
  923.  
  924.      /*
  925.       * Remember that a drag is in progress and start the target thread.
  926.       */
  927.       ++ulDragCount;
  928.       PreventClose (hwndClient, ulDragCount);
  929.  
  930.       vpThreadParms = pParm;
  931.  
  932.       DosCreateThread(&tid, (PFNTHREAD)TargetThread,
  933.                       (ULONG)vpThreadParms, 0U, STACKSIZE);
  934.    }
  935.  
  936.    return (MRESULT)NULL;
  937. }    /*  End of Drop  */
  938.  
  939.  
  940. /**************************************************************************
  941.  *
  942.  *  Name       :  EndTarget(hwnd, pParm)
  943.  *
  944.  *  Description: This function is called whenever a WM_TARGETCOMPLETE
  945.  *               message is received. It releases all resources used
  946.  *               during the drag operation and remembers that the drag
  947.  *               operation has completed.
  948.  *
  949.  *  Concepts   :  direct manipulation
  950.  *
  951.  *  API's      :  DrgQueryDragitemCount
  952.  *                DrgQueryDragitem
  953.  *                DrgSendTransferMsg
  954.  *                DrgDeleteDraginfoStrHandles
  955.  *                DrgFreeDraginfo
  956.  *                WinPostMsg
  957.  *
  958.  *  Parameters :  hwnd       = window handle
  959.  *                pParm      = points to drag information
  960.  *
  961.  *  Return     :  NULL = successful
  962.  *
  963.  *************************************************************************/
  964. MRESULT EndTarget (HWND hwnd, PDRAGTARGETTHREAD pParm)
  965. {
  966.    USHORT                cItems, i;
  967.    DRAGITEM              Dragitem;
  968.  
  969.   /*
  970.    * Decrement the count of drag operations in progress and prepare to
  971.    * release the resources allocated for the drag operation.
  972.    */
  973.    --ulDragCount;
  974.    PreventClose (hwnd, ulDragCount);
  975.    cItems = DrgQueryDragitemCount (pParm->pDraginfo);
  976.  
  977.   /*
  978.    * End the conversation for each item in the DRAGINFO structure and
  979.    * let source know we have completed the drag operation for each item.
  980.    */
  981.    for (i = 0; i < cItems; ++i)
  982.    {
  983.       if(!DrgQueryDragitem (pParm->pDraginfo, sizeof(Dragitem), &Dragitem, i))
  984.          MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYITEMERROR,
  985.                     MB_OK | MB_ERROR, TRUE);
  986.       DrgSendTransferMsg(Dragitem.hwndItem, DM_ENDCONVERSATION,
  987.                          MPFROMLONG(Dragitem.ulItemID),
  988.                          MPFROMLONG(DMFL_TARGETSUCCESSFUL));
  989.    }
  990.   /*
  991.    * Free the draginfo structure.
  992.    */
  993.    if(DrgDeleteDraginfoStrHandles(pParm->pDraginfo)
  994.                  && DrgFreeDraginfo(pParm->pDraginfo))
  995.       ;
  996.    else
  997.       MessageBox(HWND_DESKTOP, IDMSG_DRAGERROR, MB_OK | MB_ERROR, TRUE);
  998.    WinPostMsg(hwnd, WM_REFRESH, NULL, NULL);
  999.    return (MRESULT)NULL;
  1000. }  /*  End of EndTarget  */
  1001.  
  1002.  
  1003. /**************************************************************************
  1004.  *
  1005.  *  Name       :  CheckBusy()
  1006.  *
  1007.  *  Description:  This call determines if a drag is in progress.
  1008.  *
  1009.  *  Concepts   :  direct manipulation
  1010.  *
  1011.  *  API's      :  [none]
  1012.  *
  1013.  *  Parameters :  [none]
  1014.  *
  1015.  *  Return     :  TRUE = a drag is in progress
  1016.  *                FALSE = no drag in progress
  1017.  *
  1018.  *************************************************************************/
  1019. BOOL CheckBusy (void)
  1020. {
  1021.    return ((BOOL) ulDragCount);
  1022. }  /*  End of CheckBusy  */
  1023.  
  1024.  
  1025. /**************************************************************************
  1026.  *
  1027.  *  Name       :  CheckClose(hwnd)
  1028.  *
  1029.  *  Description:  This call determines if a drag is in progress by
  1030.  *                checking ulDragCount.  If a drag is in progress,
  1031.  *                close is not allowed.
  1032.  *
  1033.  *  Concepts   :  direct manipulation
  1034.  *
  1035.  *  API's      :  WinPostMsg
  1036.  *
  1037.  *  Parameters :  hwnd = window handle
  1038.  *
  1039.  *  Return     :  TRUE = a drag is in progress
  1040.  *                FALSE = no drag in progress
  1041.  *
  1042.  *************************************************************************/
  1043. MRESULT CheckClose (HWND hwnd)
  1044. {
  1045.    if (!ulDragCount)
  1046.       WinPostMsg (hwnd, WM_QUIT, (MPARAM)0L, (MPARAM)0L);
  1047.  
  1048.    return ((MPARAM)NULL);
  1049. }  /*  End of CheckClose  */
  1050.  
  1051. /**************************************************************************
  1052.  *
  1053.  *  Name       :  TargetThread()
  1054.  *
  1055.  *  Description:  This is the main function of this thread.
  1056.  *
  1057.  *  Concepts   :  direct manipulation
  1058.  *
  1059.  *  API's      :  DrgQueryDragitemCount
  1060.  *                DrgQueryDragitem
  1061.  *                DrgQueryStrName
  1062.  *                DosCopy
  1063.  *                DosDelete
  1064.  *                DosEnterCritSec
  1065.  *
  1066.  *  Parameters :  [none]
  1067.  *
  1068.  *  Return     :  [none]
  1069.  *
  1070.  *************************************************************************/
  1071. VOID FAR TargetThread (void)
  1072. {
  1073.    PDRAGTARGETTHREAD pParm;
  1074.    USHORT        cItems, i;
  1075.    ULONG         ulBytesWritten;
  1076.    DRAGITEM      Dragitem;
  1077.    char          szFullSourceName  [CCHMAXPATH];
  1078.    char          szFullTargetName  [CCHMAXPATH];
  1079.    char          szSourceFile [CCHMAXPATHCOMP];
  1080.    char          szTargetFile [CCHMAXPATHCOMP];
  1081.  
  1082.    pParm = vpThreadParms;
  1083.  
  1084.   /*
  1085.    * Get the number of items being dragged.
  1086.    */
  1087.  
  1088.    cItems = DrgQueryDragitemCount (pParm->pDraginfo);
  1089.  
  1090.   /*
  1091.    * If the source has provided the file name in the DRAGITEM
  1092.    * structures, we can go ahead and do a target copy without getting
  1093.    * the source involved in the operation.  We will always copy the file
  1094.    * using the suggested target name.  In this application the names
  1095.    * are always the same.
  1096.    */
  1097.  
  1098.    for (i = 0; i < cItems; ++i)
  1099.    {
  1100.       if(!DrgQueryDragitem (pParm->pDraginfo, sizeof(Dragitem), &Dragitem, i))
  1101.          MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYITEMERROR,
  1102.                       MB_OK | MB_ERROR, TRUE);
  1103.       if(Dragitem.hstrSourceName    != 0L &&
  1104.          Dragitem.hstrTargetName    != 0L &&
  1105.          Dragitem.hstrContainerName != 0L)
  1106.       {
  1107.       /*
  1108.        * Build the fully qualified source file name.
  1109.        */
  1110.          ulBytesWritten = DrgQueryStrName(Dragitem.hstrContainerName,
  1111.                                           sizeof(szFullSourceName),
  1112.                                           szFullSourceName);
  1113.          if(ulBytesWritten == 0)
  1114.             MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
  1115.                        MB_OK | MB_ERROR, TRUE);
  1116.          ulBytesWritten = DrgQueryStrName(Dragitem.hstrSourceName,
  1117.                                           sizeof(szSourceFile),
  1118.                                           szSourceFile);
  1119.          if(ulBytesWritten == 0)
  1120.             MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
  1121.                         MB_OK | MB_ERROR, TRUE);
  1122.  
  1123.          if (szSourceFile[0] == '\\')
  1124.             strcpy (szSourceFile, szSourceFile+1);
  1125.  
  1126.          strcat (szFullSourceName, szSourceFile);
  1127.  
  1128.       /*
  1129.        * Build the fully qualified target file name.
  1130.        */
  1131.          strcpy (szFullTargetName, pParm->szTargetDir);
  1132.          RemoveFinalBackslash (szFullTargetName);
  1133.          ulBytesWritten = DrgQueryStrName(Dragitem.hstrTargetName,
  1134.                                           sizeof(szTargetFile),
  1135.                                           szTargetFile);
  1136.          if(ulBytesWritten == 0)
  1137.             MessageBox(HWND_DESKTOP, IDMSG_DRAGQUERYSTRINGERROR,
  1138.                            MB_OK | MB_ERROR, TRUE);
  1139.  
  1140.          if (szTargetFile[0] != '\\')
  1141.             strcat (szFullTargetName, "\\");
  1142.  
  1143.          strcat (szFullTargetName, szTargetFile);
  1144.  
  1145.       /*
  1146.        * Do the operation.  DosCopy works with different drives;
  1147.        * DosMove does not, so we will use DosCopy and DosDelete.
  1148.        */
  1149.          switch (pParm->usOperation)
  1150.          {
  1151.          case DO_MOVE:     /*  Mimic DosMove with DosCopy and DosDelete.  */
  1152.              if(DosCopy(szFullSourceName, szFullTargetName, DCPY_EXISTING)
  1153.                           == NO_ERROR)
  1154.                 DosDelete(szFullSourceName);
  1155.              break;
  1156.          case DO_COPY:
  1157.              DosCopy (szFullSourceName, szFullTargetName, DCPY_EXISTING);
  1158.              break;
  1159.          }                            /* end switch usOperation */
  1160.       }                               /* end of target copy     */
  1161.    }                                  /* end of dragitem loop   */
  1162.  
  1163.   /*
  1164.    * Post ourselves a target complete message so the client window
  1165.    * knows we are done and can free the stack segment and the draginfo
  1166.    * structure.
  1167.    */
  1168.    DosEnterCritSec();                   /* make sure we finish before the   */
  1169.                                         /* main thread frees our stack      */
  1170.  
  1171.    WinPostMsg (pParm->hwndClient, WM_TARGETCOMPLETE, pParm, NULL);
  1172. }  /*  End of TargetThread  */
  1173. /***************************  End of dragdrag.c  *************************/
  1174.  
  1175.