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