/****************************************************************************/
/*                                                                          */
/*  WFDIRSRC.C -                                                            */
/*                                                                          */
/*      Routines Common to the Directory and Search Windows                 */
/*                                                                          */
/****************************************************************************/

#include "winfile.h"

#define DO_DROPFILE 0x454C4946L
#define DO_PRINTFILE 0x544E5250L
#define DO_DROPONDESKTOP 0x504D42L

HWND hwndGlobalSink = NULL;

VOID SelectItem(HWND hwndLB, WPARAM wParam, BOOL bSel);
VOID ShowItemBitmaps(HWND hwndLB, BOOL bShow);
DWORD GetSearchAttribs(HWND hwndLB, WORD wIndex);

HCURSOR
APIENTRY
GetMoveCopyCursor()
{
    if (fShowSourceBitmaps)
        // copy
        return LoadCursor(hAppInstance, MAKEINTRESOURCE(iCurDrag | 1));
    else
        // move
        return LoadCursor(hAppInstance, MAKEINTRESOURCE(iCurDrag & 0xFFFE));
}


DWORD
GetSearchAttribs(
                HWND hwndLB,
                WORD wIndex
                )
{
    DWORD dwAttribs;
    HANDLE hDTA;
    LPDTASEARCH lpschdta;

    hDTA = (HANDLE)GetWindowLongPtr(GetParent(hwndLB), GWLP_HDTASEARCH);
    lpschdta = (LPDTASEARCH)LocalLock(hDTA);
    dwAttribs = lpschdta[(INT)SendMessage(hwndLB, LB_GETITEMDATA, wIndex, 0L)].sch_dwAttrs;
    LocalUnlock(hDTA);

    return dwAttribs;
}


// match a DOS wild card spec against a dos file name
// both strings are ANSI and Upper case

BOOL
MatchFile(
         LPSTR szFile,
         LPSTR szSpec
         )
{
    ENTER("MatchFile");
    PRINT(BF_PARMTRACE, "IN:szFile=%s", szFile);
    PRINT(BF_PARMTRACE, "IN:szSpec=%s", szSpec);

#define IS_DOTEND(ch)   ((ch) == '.' || (ch) == 0)

    if (!lstrcmp(szSpec, "*") ||            // "*" matches everything
        !lstrcmp(szSpec, szStarDotStar))    // so does "*.*"
        return TRUE;

    while (*szFile && *szSpec) {

        switch (*szSpec) {
            case '?':
                szFile++;
                szSpec++;
                break;

            case '*':

                while (!IS_DOTEND(*szSpec))     // got till a terminator
                    szSpec = AnsiNext(szSpec);

                if (*szSpec == '.')
                    szSpec++;

                while (!IS_DOTEND(*szFile))     // got till a terminator
                    szFile = AnsiNext(szFile);

                if (*szFile == '.')
                    szFile++;

                break;

            default:
                if (*szSpec == *szFile) {
                    if (IsDBCSLeadByte(*szSpec)) {
                        szFile++;
                        szSpec++;
                        if (*szFile != *szSpec)
                            return FALSE;
                    }
                    szFile++;
                    szSpec++;
                } else
                    return FALSE;
        }
    }
    return !*szFile && !*szSpec;
}


VOID
APIENTRY
DSSetSelection(
              HWND hwndLB,
              BOOL bSelect,
              LPSTR szSpec,
              BOOL bSearch
              )
{
    WORD            i;
    WORD            iMac;
    HANDLE          hMem;
    LPMYDTA         lpmydta;
    CHAR            szTemp[MAXPATHLEN];

    AnsiUpper(szSpec);

    iMac = (WORD)SendMessage(hwndLB, LB_GETCOUNT, 0, 0L);

    if (bSearch)
        hMem = (HANDLE)GetWindowLongPtr(GetParent(hwndLB), GWLP_HDTASEARCH);
    else
        hMem = (HANDLE)GetWindowLongPtr(GetParent(hwndLB), GWLP_HDTA);

    LocalLock(hMem);

    for (i = 0; i < iMac; i++) {

        if (bSearch) {
            SendMessage(hwndLB, LB_GETTEXT, i, (LPARAM)szTemp);
            StripPath(szTemp);
        } else {

            SendMessage(hwndLB, LB_GETTEXT, i, (LPARAM)&lpmydta);

            if (lpmydta->my_dwAttrs & ATTR_PARENT)
                continue;

            lstrcpy(szTemp, lpmydta->my_cFileName);
        }

        AnsiUpper(szTemp);

        if (MatchFile(szTemp, szSpec))
            SendMessage(hwndLB, LB_SETSEL, bSelect, MAKELONG(i, 0));
    }

    LocalUnlock(hMem);
}


/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  ShowItemBitmaps() -                                                     */
/*                                                                          */
/*--------------------------------------------------------------------------*/

VOID
ShowItemBitmaps(
               HWND hwndLB,
               BOOL bShow
               )
{
    INT       iSel;
    RECT      rc;

    if (bShow == fShowSourceBitmaps)
        return;

    fShowSourceBitmaps = bShow;

    /* Invalidate the bitmap parts of all visible, selected items. */
    iSel = (WORD)SendMessage(hwndLB, LB_GETTOPINDEX, 0, 0L);

    while (SendMessage(hwndLB, LB_GETITEMRECT, iSel, (LPARAM)&rc) != LB_ERR) {
        /* Is this item selected? */
        if ((BOOL)SendMessage(hwndLB, LB_GETSEL, iSel, 0L)) {
            /* Invalidate the bitmap area. */
            rc.right = rc.left + dxFolder + dyBorderx2 + dyBorder;
            InvalidateRect(hwndLB, &rc, FALSE);
        }
        iSel++;
    }
    UpdateWindow(hwndLB);
}


INT
CharCountToTab(
              LPSTR pStr
              )
{
    LPSTR pTmp = pStr;

    while (*pStr && *pStr != '\t') {
        pStr = AnsiNext(pStr);
    }

    return (INT)(pStr-pTmp);
}


// this only deals with opaque text for now

VOID
RightTabbedTextOut(
                  HDC hdc,
                  INT x,
                  INT y,
                  LPSTR pLine,
                  WORD *pTabStops,
                  INT x_offset
                  )
{
    INT len, cch;
    INT x_ext;
    INT x_initial;
    RECT rc;

    len = lstrlen(pLine);

    // setup opaquing rect (we adjust the right border as we
    // output the string)

    rc.left = x;
    rc.top  = y;
    rc.bottom = y + dyText; // global max char height

    x_initial = x;

    cch = CharCountToTab(pLine);
    MGetTextExtent(hdc, pLine, cch, &x_ext, NULL);

    // first position is left alligned so bias initial x value
    x += x_ext;

    while (len) {

        len -= cch + 1;

        rc.right = x;
        ExtTextOut(hdc, x - x_ext, y, ETO_OPAQUE, &rc, pLine, cch, NULL);

        if (len <= 0)
            return;

        rc.left = rc.right;
        pLine += cch + 1;

        cch = CharCountToTab(pLine);
        MGetTextExtent(hdc, pLine, cch, &x_ext, NULL);

        x = *pTabStops + x_offset;
        pTabStops++;
    }
}



/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  DrawItem() -                                                            */
/*                                                                          */
/*--------------------------------------------------------------------------*/


VOID
APIENTRY
DrawItem(
        LPDRAWITEMSTRUCT lpLBItem,
        LPSTR szLine,
        DWORD dwAttrib,
        BOOL bHasFocus,
        WORD *pTabs
        )
{
    INT x, y;
    CHAR ch;
    LPSTR psz;
    HDC hDC;
    BOOL bDrawSelected;
    HWND hwndLB;
    INT iBitmap;

    hwndLB = lpLBItem->hwndItem;

    bDrawSelected = (lpLBItem->itemState & ODS_SELECTED);

    hDC = lpLBItem->hDC;

    if (bHasFocus && bDrawSelected) {
        SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
        SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
    }

    if (lpLBItem->itemAction == ODA_FOCUS)
        goto FocusOnly;

    /* Draw the black/white background. */
    ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &lpLBItem->rcItem, NULL, 0, NULL);

    x = lpLBItem->rcItem.left + 1;
    y = lpLBItem->rcItem.top + (dyFileName/2);

    if (fShowSourceBitmaps || (hwndDragging != hwndLB) || !bDrawSelected) {

        if (dwAttrib & ATTR_DIR) {
            if (dwAttrib & ATTR_PARENT) {
                iBitmap = BM_IND_DIRUP;
                szLine = szNULL;  // no date/size stuff!
            } else
                iBitmap = BM_IND_CLOSE;
        } else {

            // isolate the name so we can see what type of file this is

            psz = szLine + CharCountToTab(szLine);
            ch = *psz;
            *psz = 0;

            if (dwAttrib & (ATTR_HIDDEN | ATTR_SYSTEM))
                iBitmap = BM_IND_RO;
            else if (IsProgramFile(szLine))
                iBitmap = BM_IND_APP;
            else if (IsDocument(szLine))
                iBitmap = BM_IND_DOC;
            else
                iBitmap = BM_IND_FIL;

            *psz = ch;                           // resore the old character
        }

        BitBlt(hDC, x + dyBorder, y-(dyFolder/2), dxFolder, dyFolder, hdcMem,
               iBitmap * dxFolder, (bHasFocus && bDrawSelected) ? dyFolder : 0, SRCCOPY);
    }

    x += dxFolder + dyBorderx2;

    if ((wTextAttribs & TA_LOWERCASE) && !(dwAttrib & ATTR_LFN))
        AnsiLower(szLine);

    RightTabbedTextOut(hDC, x, y-(dyText/2), szLine, (WORD *)pTabs, x);

    if (lpLBItem->itemState & ODS_FOCUS)
        FocusOnly:
        DrawFocusRect(hDC, &lpLBItem->rcItem);    // toggles focus (XOR)


    if (bDrawSelected) {
        if (bHasFocus) {
            SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
            SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
        } else {
            HBRUSH hbr;
            RECT rc;

            if (hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))) {
                rc = lpLBItem->rcItem;
                rc.right = rc.left + (INT)SendMessage(hwndLB, LB_GETHORIZONTALEXTENT, 0, 0L);

                if (lpLBItem->itemID > 0 &&
                    (BOOL)SendMessage(hwndLB, LB_GETSEL, lpLBItem->itemID - 1, 0L))
                    rc.top -= dyBorder;

                FrameRect(hDC, &rc, hbr);
                DeleteObject(hbr);
            }
        }
    }
}


/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  SelectItem() -                                                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

VOID
SelectItem(
          HWND hwndLB,
          WPARAM wParam,
          BOOL bSel
          )
{
    /* Add the current item to the selection. */
    SendMessage(hwndLB, LB_SETSEL, bSel, (DWORD)wParam);

    /* Give the selected item the focus rect and anchor pt. */
    SendMessage(hwndLB, LB_SETCARETINDEX, wParam, 0L);
    SendMessage(hwndLB, LB_SETANCHORINDEX, wParam, 0L);
}


//
// void  APIENTRY DSDragLoop(register HWND hwndLB, WPARAM wParam, LPDROPSTRUCT lpds, BOOL bSearch)
//
// called by for the directory and search drag loops. this must handle
// detecting all kinds of different destinations.
//
// in:
//      hwndLB  source listbox (either the dir or the sort)
//      wParam  same as sent for WM_DRAGLOOP (TRUE if we are on a dropable sink)
//      lpds    drop struct sent with the message
//      bSearch TRUE if we are in the search listbox
//

VOID
APIENTRY
DSDragLoop(
          HWND hwndLB,
          WPARAM wParam,
          LPDROPSTRUCT lpds,
          BOOL bSearch
          )
{
    BOOL          bTemp;
    BOOL          bShowBitmap;
    LPMYDTA       lpmydta;
    HWND          hwndMDIChildSink, hwndDir;


    // bShowBitmap is used to turn the source bitmaps on or off to distinguish
    // between a move and a copy or to indicate that a drop can
    // occur (exec and app)

    // hack: keep around for drop files!
    hwndGlobalSink = lpds->hwndSink;

    bShowBitmap = TRUE;   // default to copy

    if (!wParam)
        goto DragLoopCont;        // can't drop here

    // Is the user holding down the CTRL key (which forces a copy)?
    if (GetKeyState(VK_CONTROL) < 0) {
        bShowBitmap = TRUE;
        goto DragLoopCont;
    }

    // Is the user holding down the ALT or SHIFT key (which forces a move)?
    if (GetKeyState(VK_MENU)<0 || GetKeyState(VK_SHIFT)<0) {
        bShowBitmap = FALSE;
        goto DragLoopCont;
    }

    hwndMDIChildSink = GetMDIChildFromDecendant(lpds->hwndSink);

    // Are we over the source listbox? (sink and source the same)

    if (lpds->hwndSink == hwndLB) {

        // Are we over a valid listbox entry?
        if (LOWORD(lpds->dwControlData) == 0xFFFF) {
            goto DragLoopCont;
        } else {
            /* Yup, are we over a directory entry? */
            if (bSearch) {

                bTemp = (GetSearchAttribs(hwndLB, (WORD)(lpds->dwControlData)) & ATTR_DIR) != 0L;

            } else {

                SendMessage(hwndLB, LB_GETTEXT, (WORD)(lpds->dwControlData), (LPARAM)&lpmydta);

                bTemp = lpmydta->my_dwAttrs & ATTR_DIR;

            }
            if (!bTemp)
                goto DragLoopCont;
        }
    }

    /* Now we need to see if we are over an Executable file.  If so, we
     * need to force the Bitmaps to draw.
     */

    /* Are we over a directory window? */

    if (hwndMDIChildSink)
        hwndDir = HasDirWindow(hwndMDIChildSink);
    else
        hwndDir = NULL;

    if (hwndDir && (hwndDir == GetParent(lpds->hwndSink))) {

        // Are we over an occupided part of the list box?

        if (LOWORD(lpds->dwControlData) != 0xFFFF) {

            // Are we over an Executable?

            SendMessage(lpds->hwndSink, LB_GETTEXT, (WORD)(lpds->dwControlData), (LPARAM)&lpmydta);

            bTemp = IsProgramFile(lpmydta->my_cFileName);

            if (bTemp)
                goto DragLoopCont;
        }
    }

    // Are we dropping into the same drive (check the source and dest drives)

    bShowBitmap = ((INT)SendMessage(GetParent(hwndLB), FS_GETDRIVE, 0, 0L) !=
                   GetDrive(lpds->hwndSink, lpds->ptDrop));

    DragLoopCont:

    ShowItemBitmaps(hwndLB, bShowBitmap);

    // hack, set the cursor to match the move/copy state
    if (wParam)
        SetCursor(GetMoveCopyCursor());
}


/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  DSRectItem() -                                                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

VOID
APIENTRY
DSRectItem(
          HWND hwndLB,
          INT iItem,
          BOOL bFocusOn,
          BOOL bSearch
          )
{
    RECT      rc;
    RECT      rcT;
    HDC       hDC;
    BOOL      bSel;
    WORD      wColor;
    HBRUSH    hBrush;
    LPMYDTA   lpmydta;
    CHAR      szTemp[MAXPATHLEN];

    /* Are we over an unused part of the listbox? */
    if (iItem == 0xFFFF)
        return;

    /* Are we over ourselves? (i.e. a selected item in the source listbox) */
    bSel = (BOOL)SendMessage(hwndLB, LB_GETSEL, iItem, 0L);
    if (bSel && (hwndDragging == hwndLB))
        return;

    /* We only put rectangles around directories and program items. */
    if (bSearch) {
        SendMessage(hwndLB, LB_GETTEXT, iItem, (LPARAM)szTemp);

        // this is bused, we must test this as attributes

        if (!(BOOL)(GetSearchAttribs(hwndLB, (WORD)iItem) & ATTR_DIR) && !IsProgramFile((LPSTR)szTemp))
            return;
    } else {
        SendMessage(hwndLB, LB_GETTEXT, iItem, (LPARAM)&lpmydta);

        if (!(lpmydta->my_dwAttrs & ATTR_DIR) &&
            !IsProgramFile(lpmydta->my_cFileName)) {
            return;
        }
    }

    /* Turn the item's rectangle on or off. */

    SendMessage(hwndLB, LB_GETITEMRECT, iItem, (LPARAM)&rc);
    GetClientRect(hwndLB,&rcT);
    IntersectRect(&rc,&rc,&rcT);

    if (bFocusOn) {
        hDC = GetDC(hwndLB);
        if (bSel) {
            wColor = COLOR_WINDOW;
            InflateRect(&rc, -1, -1);
        } else
            wColor = COLOR_WINDOWFRAME;

        if (hBrush = CreateSolidBrush(GetSysColor(wColor))) {
            FrameRect(hDC, &rc, hBrush);
            DeleteObject(hBrush);
        }
        ReleaseDC(hwndLB, hDC);
    } else {
        InvalidateRect(hwndLB, &rc, FALSE);
        UpdateWindow(hwndLB);
    }
}


/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  DropFilesOnApplication() -                                              */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* this function will determine whether the application we are currently
 * over is a valid drop point and drop the files
 */

WORD
DropFilesOnApplication(
                      LPSTR pszFiles
                      )
{
    POINT pt;
    HWND hwnd;
    RECT rc;
    HANDLE hDrop,hT;
    LPSTR lpList;
    WORD cbList = 2;
    OFSTRUCT ofT;
    WORD cbT;
    LPDROPFILESTRUCT lpdfs;
    CHAR szFile[MAXPATHLEN];

    if (!(hwnd = hwndGlobalSink))
        return 0;

    hwndGlobalSink = NULL;

    GetCursorPos(&pt);

    cbList = 2 + sizeof (DROPFILESTRUCT);
    hDrop = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,cbList);
    if (!hDrop)
        return 0;

    lpdfs = (LPDROPFILESTRUCT)GlobalLock(hDrop);

    GetClientRect(hwnd,&rc);
    ScreenToClient(hwnd,&pt);
    lpdfs->pt = pt;
    lpdfs->fNC = !PtInRect(&rc,pt);
    lpdfs->pFiles = sizeof(DROPFILESTRUCT);

    GlobalUnlock(hDrop);

    while (pszFiles = GetNextFile(pszFiles, szFile, sizeof(szFile))) {

        MOpenFile(szFile, &ofT, OF_PARSE);

        cbT = (WORD)(lstrlen(ofT.szPathName)+1);
        hT = GlobalReAlloc(hDrop,cbList+cbT,GMEM_MOVEABLE|GMEM_ZEROINIT);
        if (!hT)
            break;
        hDrop = hT;
        lpList = GlobalLock(hDrop);
        OemToAnsi(ofT.szPathName, lpList+cbList-2);
        GlobalUnlock(hDrop);
        cbList += cbT;
    }

    PostMessage(hwnd, WM_DROPFILES, (WPARAM)hDrop, 0L);

    return 1;
}


/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  DSTrackPoint() -                                                        */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/* Return 0 for normal mouse tracking, 1 for no mouse single-click processing,
 * and 2 for no mouse single- or double-click tracking.
 */

INT
APIENTRY
DSTrackPoint(
            HWND hWnd,
            HWND hwndLB,
            WPARAM wParam,
            LPARAM lParam,
            BOOL bSearch
            )
{
    UINT       iSel;
    MSG       msg;
    RECT      rc;
    WORD      wAnchor;
    DWORD     dwTemp;
    LPSTR      pch;
    BOOL      bDir;
    BOOL      bSelected;
    BOOL      bSelectOneItem;
    BOOL      bUnselectIfNoDrag;
    CHAR      szFileName[MAXPATHLEN+1];
    INT iNoYieldCount;
    WORD wYieldFlags;
    POINT     pt;
    HANDLE hHackForHDC = NULL;    // hDC Express editor relies on this
    DRAGOBJECTDATA dodata;

    bSelectOneItem = FALSE;
    bUnselectIfNoDrag = FALSE;

    bSelected = (BOOL)SendMessage(hwndLB, LB_GETSEL, wParam, 0L);

    if (GetKeyState(VK_SHIFT) < 0) {
        /* What is the state of the Anchor point? */
        wAnchor = (WORD)SendMessage(hwndLB, LB_GETANCHORINDEX, 0, 0L);
        bSelected = (BOOL)SendMessage(hwndLB, LB_GETSEL, wAnchor, 0L);

        /* If Control is up, turn everything off. */
        if (!(GetKeyState(VK_CONTROL) < 0))
            SendMessage(hwndLB, LB_SETSEL, FALSE, -1L);

        /* Select everything between the Anchor point and the item. */
        SendMessage(hwndLB, LB_SELITEMRANGE, bSelected, MAKELONG(wParam, wAnchor));

        /* Give the selected item the focus rect. */
        SendMessage(hwndLB, LB_SETCARETINDEX, wParam, 0L);
    } else if (GetKeyState(VK_CONTROL) < 0) {
        if (bSelected)
            bUnselectIfNoDrag = TRUE;
        else
            SelectItem(hwndLB, wParam, TRUE);
    } else {
        if (bSelected)
            bSelectOneItem = TRUE;
        else {
            /* Deselect everything. */
            SendMessage(hwndLB, LB_SETSEL, FALSE, -1L);

            /* Select the current item. */
            SelectItem(hwndLB, wParam, TRUE);
        }
    }

    if (!bSearch)
        UpdateStatus(GetParent(hWnd));

    LONG2POINT(lParam, pt);
    ClientToScreen(hwndLB, (LPPOINT)&pt);
    ScreenToClient(hWnd, (LPPOINT)&pt);

    // See if the user moves a certain number of pixels in any direction

    SetRect(&rc, pt.x - dxClickRect, pt.y - dyClickRect,
            pt.x + dxClickRect, pt.y + dyClickRect);

    SetCapture(hWnd);
    wYieldFlags = PM_NOYIELD | PM_REMOVE;
    iNoYieldCount = 50;
    for (;;) {
#if 0
        {
            CHAR szBuf[80];

            wsprintf(szBuf, "Message %4.4X\r\n", msg.message);
            OutputDebugString(szBuf);
        }
#endif

        if (PeekMessage(&msg, NULL, 0, 0, wYieldFlags))
            DispatchMessage(&msg);

        if (iNoYieldCount <= 0)
            wYieldFlags = PM_REMOVE;
        else
            iNoYieldCount--;

        // WM_CANCELMODE messages will unset the capture, in that
        // case I want to exit this loop

        if (GetCapture() != hWnd) {
            msg.message = WM_LBUTTONUP;   // don't proceed below
            break;
        }

        if (msg.message == WM_LBUTTONUP)
            break;

        LONG2POINT(msg.lParam, pt);
        if ((msg.message == WM_MOUSEMOVE) && !(PtInRect(&rc, pt)))
            break;
    }
    ReleaseCapture();

    /* Did the guy NOT drag anything? */
    if (msg.message == WM_LBUTTONUP) {
        if (bSelectOneItem) {
            /* Deselect everything. */
            SendMessage(hwndLB, LB_SETSEL, FALSE, -1L);

            /* Select the current item. */
            SelectItem(hwndLB, wParam, TRUE);
        }

        if (bUnselectIfNoDrag)
            SelectItem(hwndLB, wParam, FALSE);

        // notify the appropriate people

        SendMessage(hWnd, WM_COMMAND,
                    GET_WM_COMMAND_MPS(0, hwndLB, LBN_SELCHANGE));

        return 1;
    }

    /* Enter Danger Mouse's BatCave. */
    if ((WORD)SendMessage(hwndLB, LB_GETSELCOUNT, 0, 0L) == 1) {
        /* There is only one thing selected.
         * Figure out which cursor to use.
         */
        if (bSearch) {
            SendMessage(hwndLB, LB_GETTEXT, wParam, (LPARAM)szFileName);
            bDir = (BOOL)(GetSearchAttribs(hwndLB, (WORD)wParam) & ATTR_DIR);
        } else {
            LPMYDTA lpmydta;

            SendMessage(hwndLB, LB_GETTEXT, wParam, (LPARAM)&lpmydta);

            lstrcpy(szFileName, lpmydta->my_cFileName);
            bDir = lpmydta->my_dwAttrs & ATTR_DIR;

            // avoid dragging the parrent dir

            if (lpmydta->my_dwAttrs & ATTR_PARENT) {
                return 1;
            }
        }

        if (bDir) {
            iSel = DOF_DIRECTORY;
        } else if (IsProgramFile(szFileName)) {
            iSel = DOF_EXECUTABLE;
            goto HDC_HACK_FROM_HELL;
        } else if (IsDocument(szFileName)) {
            iSel = DOF_DOCUMENT;
            HDC_HACK_FROM_HELL:
            hHackForHDC = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(OFSTRUCT));
            if (hHackForHDC) {
                LPOFSTRUCT lpof;

                lpof = (LPOFSTRUCT)GlobalLock(hHackForHDC);
                QualifyPath(szFileName);
                lstrcpy(lpof->szPathName, szFileName);
                GlobalUnlock(hHackForHDC);
            }
        } else
            iSel = DOF_DOCUMENT;

        iCurDrag = SINGLECOPYCURSOR;
    } else {
        /* Multiple files are selected. */
        iSel = DOF_MULTIPLE;
        iCurDrag = MULTCOPYCURSOR;
    }


    /* Get the list of selected things. */
    pch = (LPSTR)SendMessage(hWnd, FS_GETSELECTION, FALSE, 0L);

    /* Wiggle things around. */
    hwndDragging = hwndLB;
    dodata.pch = pch;
    dodata.hMemGlobal = hHackForHDC;
    dwTemp = DragObject(GetDesktopWindow(),hWnd,(UINT)iSel,(DWORD)(ULONG_PTR)&dodata,GetMoveCopyCursor());

    if (hHackForHDC)
        GlobalFree(hHackForHDC);

    SetWindowDirectory();

    if (dwTemp == DO_PRINTFILE) {
        // print these 
        hdlgProgress = NULL;
        WFPrint(pch);
    } else if (dwTemp == DO_DROPFILE) {
        // try and drop them on an application
        DropFilesOnApplication(pch);
    }

    LocalFree((HANDLE)pch);

    if (IsWindow(hWnd))
        ShowItemBitmaps(hwndLB, TRUE);

    hwndDragging = NULL;

    if (!bSearch && IsWindow(hWnd))
        UpdateStatus(GetParent(hWnd));

    return 2;
}