/****************************************************************************/ /* */ /* WFDIR.C - */ /* */ /* Windows File System Directory Window Proc Routines */ /* */ /****************************************************************************/ #include "winfile.h" #include "winnet.h" #include "lfn.h" #include "wfcopy.h" #define MAXDIGITSINSIZE 8 #define DATEMASK 0x001F #define MONTHMASK 0x01E0 #define MINUTEMASK 0x07E0 #define SECONDSMASK 0x001F #define DATESEPERATOR '-' #define TIMESEPERATOR ':' CHAR szAttr[] = "RHSA"; INT iLastSel = -1; INT_PTR APIENTRY DirWndProc(register HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam); LPSTR DirGetSelection(HWND hwndDir, HWND hwndLB, INT iSelType, BOOL *pfDir); VOID DirGetAnchorFocus(register HWND hwndLB, HANDLE hDTA, LPSTR szAnchor, LPSTR szCaret, LPSTR szTopIndex); VOID FillDirList(HWND hWnd, HANDLE hDirEntries); VOID DrawItemFast(HWND hWnd, LPDRAWITEMSTRUCT lpLBItem, LPMYDTA lpmydta, BOOL bHasFocus); INT GetPict(CHAR ch, LPSTR szStr); INT DirFindIndex(HWND hwndLB, HANDLE hDTA, LPSTR szFile); INT CompareDTA(register LPMYDTA item1, LPMYDTA item2, WORD wSort); VOID CreateLBLine(register WORD wLineFormat, LPMYDTA lpmydta, LPSTR szBuffer); HANDLE CreateDTABlock(HWND hWnd, LPSTR pPath, DWORD dwAttribs, BOOL bAllowAbort, BOOL bDontSteal); BOOL SetSelection(HWND hwndLB, HANDLE hDTA, LPSTR pSel); INT CreateDate(WORD *wValArray, LPSTR szOutStr); INT CreateTime(WORD * wValArray, LPSTR szOutStr); VOID GetDirStatus(HWND hWnd, LPSTR szMsg1, LPSTR szMsg2); INT GetMaxExtent(HWND hwndLB, HANDLE hDTA); BOOL CheckEarlyAbort(VOID); BOOL SetDirFocus(HWND hwndDir); VOID APIENTRY CheckEscapes(LPSTR); VOID SortDirList(HWND, LPMYDTA, WORD ,LPMYDTA *); /*--------------------------------------------------------------------------*/ /* */ /* DrawItemFast() - */ /* */ /*--------------------------------------------------------------------------*/ VOID DrawItemFast( HWND hWnd, LPDRAWITEMSTRUCT lpLBItem, LPMYDTA lpmydta, BOOL bHasFocus ) { INT x, y, i; HDC hDC; BOOL bDrawSelected; HWND hwndLB; RECT rc; DWORD rgbText, rgbBackground; CHAR szBuf[MAXFILENAMELEN+2]; hWnd; ENTER("DrawItemFast"); hDC = lpLBItem->hDC; hwndLB = lpLBItem->hwndItem; bDrawSelected = (lpLBItem->itemState & ODS_SELECTED); if (bHasFocus && bDrawSelected) { rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); rgbBackground = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); } if (lpLBItem->itemAction == ODA_FOCUS) goto FocusOnly; /* Draw the black/white background. */ x = lpLBItem->rcItem.left + 1; y = lpLBItem->rcItem.top + (dyFileName/2); lstrcpy(szBuf, lpmydta->my_cFileName); if ((wTextAttribs & TA_LOWERCASE) && !(lpmydta->my_dwAttrs & ATTR_LFN)) AnsiLower(szBuf); ExtTextOut(hDC, x + dxFolder + dyBorderx2 + dyBorder, y-(dyText/2), ETO_OPAQUE, &lpLBItem->rcItem, szBuf, lstrlen(szBuf), NULL); if (fShowSourceBitmaps || (hwndDragging != hwndLB) || !bDrawSelected) { LONG ySrc; i = lpmydta->iBitmap; if (i & 0x40) { // It's an object type bitmap ySrc = (dyFolder * 2) + dyDriveBitmap; i = i & (~0x40); while (i >= 16) { i -= 16; ySrc += (dyFolder * 2); } } else { ySrc = 0; } ySrc += (bHasFocus && bDrawSelected) ? dyFolder : 0; BitBlt(hDC, x + dyBorderx2, y-(dyFolder/2), dxFolder, dyFolder, hdcMem, i * dxFolder, ySrc, SRCCOPY); } if (lpLBItem->itemState & ODS_FOCUS) FocusOnly: DrawFocusRect(hDC, &lpLBItem->rcItem); // toggles focus (XOR) /* Restore the normal drawing colors. */ if (bDrawSelected) { if (bHasFocus) { SetTextColor(hDC, rgbText); SetBkColor(hDC, rgbBackground); } else { HBRUSH hbr; if (hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))) { rc = lpLBItem->rcItem; rc.left += dyBorder; rc.right -= dyBorder; if (lpLBItem->itemID > 0 && (BOOL)SendMessage(hwndLB, LB_GETSEL, lpLBItem->itemID - 1, 0L)) rc.top -= dyBorder; FrameRect(hDC, &rc, hbr); DeleteObject(hbr); } } } LEAVE("DrawItemFast"); } /*--------------------------------------------------------------------------*/ /* */ /* FillDirList() - */ /* */ /* HANDLE hDirEntries; Array of directory entries */ /*--------------------------------------------------------------------------*/ VOID FillDirList( HWND hWnd, HANDLE hDTA ) { register WORD count; LPMYDTA lpmydta; LPMYDTA *alpmydtaSorted; WORD i; lpmydta = (LPMYDTA)LocalLock(hDTA); count = (WORD)lpmydta->my_nFileSizeLow; if (count == 0) { SendMessage(hWnd, LB_ADDSTRING, 0, 0L); // tolken for no items } else { alpmydtaSorted = (LPMYDTA *)LocalAlloc(LMEM_FIXED, sizeof(LPMYDTA) * count); if (alpmydtaSorted != NULL) { SortDirList(hWnd, lpmydta, count, alpmydtaSorted); for (i = 0; i < count; i++) { alpmydtaSorted[i]->nIndex = i; SendMessage(hWnd, LB_INSERTSTRING,(WPARAM)-1, (LPARAM)alpmydtaSorted[i]); } LocalFree((HANDLE)alpmydtaSorted); } } LocalUnlock(hDTA); } BOOL CheckEarlyAbort() { MSG msg; if (PeekMessage(&msg, NULL, WM_KEYDOWN, WM_KEYDOWN, PM_NOREMOVE | PM_NOYIELD)) { if (msg.wParam == VK_UP || msg.wParam == VK_DOWN) { return TRUE; } } return FALSE; } HANDLE CopyDTABlock( HANDLE hDTASrc ) { LPMYDTA lpmydtaSrc, lpmydtaDst; HANDLE hDTADst; SIZE_T dwSize; lpmydtaSrc = (LPMYDTA)LocalLock(hDTASrc); dwSize = LocalSize(hDTASrc); if (hDTADst = LocalAlloc(LPTR, dwSize)) { lpmydtaDst = (LPMYDTA)LocalLock(hDTADst); memcpy(lpmydtaDst, lpmydtaSrc, (size_t)dwSize); LocalUnlock(hDTASrc); LocalUnlock(hDTADst); return hDTADst; } else { LocalUnlock(hDTASrc); return NULL; } } HANDLE StealDTABlock( HWND hWnd, LPSTR pPath, DWORD dwAttribs ) { HWND hwnd; HWND hwndDir; HANDLE hDTA; CHAR szPath[MAXPATHLEN]; ENTER("StealDTABlock"); for (hwnd = GetWindow(hwndMDIClient, GW_CHILD); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT)) { if ((hwndDir = HasDirWindow(hwnd)) && (hwndDir != hWnd)) { GetMDIWindowText(hwnd, szPath, sizeof(szPath)); if ((dwAttribs == (DWORD)GetWindowLong(hwnd, GWL_ATTRIBS)) && !lstrcmpi(pPath, szPath) && (hDTA = (HANDLE)GetWindowLongPtr(hwndDir, GWLP_HDTA))) { LEAVE("StealDTABlock"); return CopyDTABlock(hDTA); } } } LEAVE("StealDTABlock"); return NULL; } /*--------------------------------------------------------------------------*/ /* */ /* CreateDTABlock() - */ /* */ /*--------------------------------------------------------------------------*/ /* Builds a global memory block full of DTAs for the path 'pPath'. */ /* Returns: * An unlocked global memory handle to DTA block with first DTA * my_nFileSizeLow field indicating the number of DTA blocks that follow * * This builds a global memory block that has DTA entries for all * of the files with dwAttributes in pPath. The first DTA entry's * my_nFileSizeLow field indicates the number of actual DTA areas found */ HANDLE CreateDTABlock( HWND hWnd, LPSTR pPath, DWORD dwAttribs, BOOL bAllowAbort, BOOL bDontSteal ) { register LPSTR pName; WORD wPathLen; BOOL bDoc, bProgram; DWORD dwCurrentSize, dwBlockSize; WORD wSize, wLastSize; LFNDTA lfndta; HANDLE hMem; LPMYDTA lpmydta, lpStart; CHAR szPathOEM[MAXPATHLEN]; DWORD iBitmap; WORD wDrive; ENTER("CreateDTABlock"); PRINT(BF_PARMTRACE, "IN: pPath=%s", pPath); PRINT(BF_PARMTRACE, "IN: dwAttribs=0x%lx", UlongToPtr(dwAttribs)); PRINT(BF_PARMTRACE, "IN: bDontSteal=%d", IntToPtr(bDontSteal)); #define BLOCK_SIZE_GRANULARITY 512 // must be larger than MYDTA // get the drive index assuming path is // fully qualified... wDrive = (WORD)((*pPath - 'A') & 31); if (bAllowAbort && CheckEarlyAbort()) { PRINT(BF_PARMTRACE, "OUT: hDTA=-1", 0); LEAVE("CreateDTABlock"); return (HANDLE)-1; } if (!bDontSteal && (hMem = StealDTABlock(hWnd, pPath, dwAttribs))) { PRINT(BF_PARMTRACE, "OUT: hDTA=0x%lx", hMem); LEAVE("CreateDTABlock"); return hMem; } dwBlockSize = BLOCK_SIZE_GRANULARITY; hMem = LocalAlloc(LPTR, (DWORD)dwBlockSize); if (!hMem) { PRINT(BF_PARMTRACE, "OUT: hDTA=NULL", 0); LEAVE("CreateDTABlock"); return NULL; } lpmydta = lpStart = (LPMYDTA)LocalLock(hMem); lpStart->my_nFileSizeLow = 0; wLastSize = sizeof(MYDTA); wLastSize = (WORD)DwordAlign(wLastSize); lpStart->wSize = wLastSize; dwCurrentSize = (DWORD)wLastSize; lstrcpy(szPathOEM, pPath); FixAnsiPathForDos(szPathOEM); wPathLen = (WORD)(lstrlen(szPathOEM)-3); /* Ignore '*.*' */ if (!WFFindFirst(&lfndta, szPathOEM, (dwAttribs | ATTR_DIR) & ATTR_ALL)) { // Try again if the disk is available if (!IsTheDiskReallyThere(hWnd, pPath, FUNC_EXPAND) || !WFFindFirst(&lfndta, szPathOEM, (dwAttribs | ATTR_DIR) & ATTR_ALL)) goto CDBDone; } while (TRUE) { pName = lfndta.fd.cFileName; OemToCharBuff(pName, pName, sizeof(lfndta.fd.cFileName)/sizeof(lfndta.fd.cFileName[0])); // be safe, zero unused DOS dta bits lfndta.fd.dwFileAttributes &= ATTR_USED; // filter unwanted stuff here based on current view settings if (!(lfndta.fd.dwFileAttributes & ATTR_DIR)) { bProgram = IsProgramFile(pName); bDoc = IsDocument(pName); } // figure out the bitmap type here if (lfndta.fd.dwFileAttributes & ATTR_DIR) { // ignore the "." directory if (pName[0] == '.' && pName[1] != '.') goto CDBCont; // parent ".." dir if (pName[0] == '.') { pName = szNULL; iBitmap = BM_IND_DIRUP; lfndta.fd.dwFileAttributes |= ATTR_PARENT; // mark this! } else { // We always include DIRs so that the .. is // included. Now we filter other dirs off. if (!(dwAttribs & ATTR_DIR)) goto CDBCont; iBitmap = BM_IND_CLOSE; } } else if (lfndta.fd.dwFileAttributes & ATTR_TYPES) { iBitmap = ((lfndta.fd.dwFileAttributes & ATTR_TYPES) >> 16) | 0x40; } else { iBitmap = BM_IND_DOC; } // // calc the size of this portion // // pName is assumed to be ANSI re: OemToAnsi() call, // so lstrlen() should be size in bytes. We just need to add one // for the terminating NULL wSize = (WORD)(sizeof(MYDTA) + lstrlen(pName) + sizeof('\0')); wSize = (WORD)DwordAlign(wSize); if ((wSize + dwCurrentSize) > dwBlockSize) { DWORD dwDelta; // grow the block dwBlockSize += BLOCK_SIZE_GRANULARITY; LocalUnlock(hMem); dwDelta = (DWORD)((LPBYTE)lpmydta - (LPBYTE)lpStart); { void *pv = LocalReAlloc(hMem, dwBlockSize, LMEM_MOVEABLE); if (!pv) goto CDBMemoryErr; else hMem = pv; } lpStart = (LPMYDTA)LocalLock(hMem); lpmydta = (LPMYDTA)((LPBYTE)lpStart + dwDelta); } lpStart->my_nFileSizeLow++; dwCurrentSize += wSize; // now it is safe to advance the pointer lpmydta = GETDTAPTR(lpmydta, wLastSize); wLastSize = lpmydta->wSize = wSize; lpmydta->my_dwAttrs = lfndta.fd.dwFileAttributes; lpmydta->my_ftLastWriteTime = lfndta.fd.ftLastWriteTime; lpmydta->my_nFileSizeLow = lfndta.fd.nFileSizeLow; lpmydta->my_nFileSizeHigh = lfndta.fd.nFileSizeHigh; lpmydta->iBitmap = (SHORT)iBitmap; if (IsLFN(pName)) { lpmydta->my_dwAttrs |= ATTR_LFN; } lstrcpy(lpmydta->my_cFileName, pName); CDBCont: if (bAllowAbort && CheckEarlyAbort()) { LocalUnlock(hMem); LocalFree(hMem); WFFindClose(&lfndta); PRINT(BF_PARMTRACE, "OUT: hDTA=-1", 0); LEAVE("CreateDTABlock"); return (HANDLE)-1; } if (!WFFindNext(&lfndta)) { break; } } CDBDone: LocalUnlock(hMem); WFFindClose(&lfndta); PRINT(BF_PARMTRACE, "OUT: hDTA=0x%lx", hMem); LEAVE("CreateDTABlock"); return hMem; CDBMemoryErr: WFFindClose(&lfndta); MyMessageBox(hwndFrame, IDS_OOMTITLE, IDS_OOMREADINGDIRMSG, MB_OK | MB_ICONEXCLAMATION); PRINT(BF_PARMTRACE, "OUT: hDTA=0x%lx", hMem); LEAVE("CreateDTABlock"); return hMem; } /*--------------------------------------------------------------------------*/ /* */ /* DirGetSelection() - */ /* */ /*--------------------------------------------------------------------------*/ /* Takes a Listbox and returns a string containing the names of the selected * files seperated by spaces. * * bSingle == 1 return only the first file * bSingle == 2 test for LFN files in the selection, doesn't return string * bSingle == 3 return fully qualified names * * returns: * if (bSingle == 1) * TRUE/FALSE if LFN is in the selection * else * pointer to the list of names (ANSI strings) * (must be freed by caller!) * *pfDir -> bool indicating directories are * contained in the selection (or that LFN names are present) * * NOTE: The caller must free the returned pointer! */ LPSTR DirGetSelection( HWND hwndDir, HWND hwndLB, INT iSelType, BOOL *pfDir ) { LPSTR p, pT; WORD i; WORD cch; WORD iMac; LPMYDTA lpmydta; CHAR szFile[MAXPATHLEN]; CHAR szPath[MAXPATHLEN]; BOOL bDir, bPropertyDialog; LPINT lpSelItems; BOOL bLFNTest; if (bLFNTest = (iSelType == 2)) { // determine if the directory it self is long... iSelType = FALSE; SendMessage(hwndDir, FS_GETDIRECTORY, sizeof(szPath), (LPARAM)szPath); StripBackslash(szPath); if (IsLFN(szPath)) if (pfDir) { *pfDir = TRUE; } return NULL; } if (bPropertyDialog = (iSelType == 3)) { iSelType = FALSE; } bDir = FALSE; if (!bLFNTest) { cch = 1; p = (LPSTR)LocalAlloc(LPTR, cch); if (!p) return NULL; *p = '\0'; } #ifdef DEBUG else p = (LPSTR)0xFFFF; // force a GP fault with bogus p use below #endif iLastSel = -1; iMac = (WORD)SendMessage(hwndLB, LB_GETSELCOUNT, 0, 0L); lpSelItems = LocalAlloc(LMEM_FIXED, sizeof(INT) * iMac); if (lpSelItems == NULL) return NULL; iMac = (WORD)SendMessage(hwndLB, LB_GETSELITEMS, (WPARAM)iMac, (LPARAM)lpSelItems); for (i=0; i < iMac; i++) { if (iLastSel == -1) // remember the first selection iLastSel = lpSelItems[i]; SendMessage(hwndLB, LB_GETTEXT, lpSelItems[i], (LPARAM)&lpmydta); if (!lpmydta) break; lstrcpy(szFile, (LPSTR)lpmydta->my_cFileName); if (lpmydta->my_dwAttrs & ATTR_DIR) { // is this a dir SendMessage(hwndDir, FS_GETDIRECTORY, sizeof(szPath), (LPARAM)szPath); if (lpmydta->my_dwAttrs & ATTR_PARENT) { // parent dir? // if we are getting a full selection don't // return the parent ".." entry (avoid deleting // and other nasty operations on the parent) if (!iSelType) continue; StripBackslash(szPath); // trim it down StripFilespec(szPath); } else { lstrcat(szPath, szFile); // fully qualified } lstrcpy(szFile, szPath); bDir = TRUE; } if (bPropertyDialog) QualifyPath(szFile); if (bLFNTest && lpmydta->my_dwAttrs & ATTR_LFN) { return (LPSTR)TRUE; } CheckEscapes(szFile); if (!bLFNTest) { cch += lstrlen(szFile) + 1; pT = (LPSTR)LocalReAlloc((HANDLE)p, cch, LMEM_MOVEABLE | LMEM_ZEROINIT); if (!pT) goto GDSExit; p = pT; lstrcat(p, szFile); } if (iSelType) goto GDSExit; if (!bLFNTest) lstrcat(p, szBlank); } GDSExit: LocalFree(lpSelItems); if (bLFNTest) { if (pfDir) { *pfDir = FALSE; } return NULL; } if (pfDir) { *pfDir = bDir; } return p; } // compute the max extent of all the files in this DTA block // and update the case to match (wTextAttribs & TA_LOWERCASE) INT GetMaxExtent( HWND hwndLB, HANDLE hDTA ) { LPMYDTA lpmydta; HDC hdc; INT nItems; INT maxWidth = 0; INT wWidth; HFONT hOld; CHAR szPath[MAXPATHLEN]; lpmydta = (LPMYDTA)LocalLock(hDTA); nItems = (INT)lpmydta->my_nFileSizeLow; hdc = GetDC(hwndLB); hOld = SelectObject(hdc, hFont); while (nItems-- > 0) { lpmydta = GETDTAPTR(lpmydta, lpmydta->wSize); lstrcpy(szPath, lpmydta->my_cFileName); // set the case of the file names here! if (!(lpmydta->my_dwAttrs & ATTR_LFN)) { if (wTextAttribs & TA_LOWERCASE) AnsiLower(szPath); else AnsiUpper(szPath); } MGetTextExtent(hdc, szPath, lstrlen(szPath), &wWidth, NULL); maxWidth = max(wWidth, maxWidth); } if (hOld) SelectObject(hdc, hOld); ReleaseDC(hwndLB, hdc); LocalUnlock(hDTA); return maxWidth + 3; // pad it out } /*--------------------------------------------------------------------------*/ /* */ /* DirFindIndex() - */ /* */ /*--------------------------------------------------------------------------*/ INT DirFindIndex( HWND hwndLB, HANDLE hDTA, LPSTR szFile ) { register INT i; INT nSel; LPMYDTA lpmydta; lpmydta = (LPMYDTA)LocalLock(hDTA); nSel = (INT)lpmydta->my_nFileSizeLow; for (i = 0; i < nSel; i++) { SendMessage(hwndLB, LB_GETTEXT, (WORD)i, (LPARAM)&lpmydta); if (!lstrcmpi(szFile, (LPSTR)lpmydta->my_cFileName)) goto DFIExit; } i = -1; // not found, return this DFIExit: LocalUnlock(hDTA); return i; } /*--------------------------------------------------------------------------*/ /* */ /* DirGetAnchorFocus() - */ /* */ /*--------------------------------------------------------------------------*/ VOID DirGetAnchorFocus( register HWND hwndLB, HANDLE hDTA, LPSTR szAnchor, LPSTR szCaret, LPSTR szTopIndex ) { register INT iSel, iCount; LPMYDTA lpmydta; hDTA; // fix compiler warning iSel = (INT)SendMessage(hwndLB, LB_GETANCHORINDEX, 0, 0L); iCount = (INT)SendMessage(hwndLB, LB_GETCOUNT, 0, 0L); if (iCount == 1) { SendMessage(hwndLB, LB_GETTEXT, (WORD)iSel, (LPARAM)&lpmydta); if (!lpmydta) { *szAnchor = 0L; *szCaret = 0L; *szTopIndex = 0L; return; } } if (iSel >= 0 && iSel < iCount) { SendMessage(hwndLB, LB_GETTEXT, (WORD)iSel, (LPARAM)&lpmydta); lstrcpy(szAnchor, (LPSTR)lpmydta->my_cFileName); } else *szAnchor = 0L; iSel = (INT)SendMessage(hwndLB, LB_GETCARETINDEX, 0, 0L); if (iSel >= 0 && iSel < iCount) { SendMessage(hwndLB, LB_GETTEXT, (WORD)iSel, (LPARAM)&lpmydta); lstrcpy(szCaret, (LPSTR)lpmydta->my_cFileName); } else *szCaret = 0L; iSel = (WORD)SendMessage(hwndLB, LB_GETTOPINDEX, 0, 0L); if (iSel >= 0 && iSel < iCount) { SendMessage(hwndLB, LB_GETTEXT, (WORD)iSel, (LPARAM)&lpmydta); lstrcpy(szTopIndex, (LPSTR)lpmydta->my_cFileName); } else *szTopIndex = 0L; } /*--------------------------------------------------------------------------*/ /* */ /* SetSelection() - */ /* */ /*--------------------------------------------------------------------------*/ BOOL SetSelection( HWND hwndLB, HANDLE hDTA, LPSTR pSel ) { INT i; CHAR szFile[MAXPATHLEN]; BOOL bDidSomething = FALSE; while (pSel = GetNextFile(pSel, szFile, sizeof(szFile))) { i = DirFindIndex(hwndLB, hDTA, (LPSTR)szFile); if (i != -1) { SendMessage(hwndLB, LB_SETSEL, TRUE, (DWORD)i); bDidSomething = TRUE; } } return bDidSomething; } /*** FIX30: Why do we use LONG buffer ptrs here? ***/ /*--------------------------------------------------------------------------*/ /* */ /* GetPict() - */ /* */ /*--------------------------------------------------------------------------*/ /* This gets the number of consecutive chrs of the same kind. This is used * to parse the time picture. Returns 0 on error. */ INT GetPict( CHAR ch, LPSTR szStr ) { register INT count; count = 0; while (ch == *szStr++) count++; return(count); } /*--------------------------------------------------------------------------*/ /* */ /* CreateDate() - */ /* */ /*--------------------------------------------------------------------------*/ /* This picks up the values in wValArray, converts them * in a string containing the formatted date. * wValArray should contain Month-Day-Year (in that order). */ INT CreateDate( WORD *wValArray, LPSTR szOutStr ) { INT i; INT cchPictPart; WORD wDigit; WORD wIndex; WORD wTempVal; register LPSTR pszPict; register LPSTR pszInStr; pszPict = szShortDate; pszInStr = szOutStr; for (i=0; i < 3; i++) { cchPictPart = GetPict(*pszPict, pszPict); switch (*pszPict) { case 'M': wIndex = 0; goto CDDoIt; case 'D': wIndex = 1; goto CDDoIt; case 'Y': wIndex = 2; if (cchPictPart == 4) { *pszInStr++ = '1'; *pszInStr++ = '9'; } CDDoIt: /* This assumes that the values are of two digits only. */ wTempVal = wValArray[wIndex]; wDigit = wTempVal / (WORD)10; if (wDigit) *pszInStr++ = (CHAR)(wDigit + '0'); else if (cchPictPart > 1) *pszInStr++ = '0'; #if 0 else { *pszInStr++ = ' '; *pszInStr++ = ' '; } #endif *pszInStr++ = (CHAR)((wTempVal % 10) + '0'); pszPict += cchPictPart; /* Add the separator. */ if (*pszPict) *pszInStr++ = *pszPict; break; } pszPict++; } *pszInStr = 0L; return(lstrlen(szOutStr)); } /*--------------------------------------------------------------------------*/ /* */ /* CreateTime() - */ /* */ /*--------------------------------------------------------------------------*/ /* This picks up the values in wValArray, converts them * in a string containing the formatted time. * wValArray should contain Hour-Min-Sec (in that order). */ INT CreateTime( WORD * wValArray, LPSTR szOutStr ) { INT i; BOOL bAM; WORD wHourMinSec; register WORD wDigit; register LPSTR pszInStr; pszInStr = szOutStr; wDigit = wValArray[0]; bAM = (wDigit < 12); if (!iTime) { if (wDigit >= 12) wDigit -= 12; if (!wDigit) wDigit = 12; } wValArray[0] = wDigit; for (i=0; i < 3; i++) { wHourMinSec = wValArray[i]; /* This assumes that the values are of two digits only. */ wDigit = wHourMinSec / (WORD)10; if (i > 0) *pszInStr++ = (CHAR)(wDigit + '0'); else if (wDigit || iTLZero) *pszInStr++ = (CHAR)(wDigit + '0'); #if 0 else { /* NOTE: 2 blanks is the same width as one digit. */ // wrong! *pszInStr++ = ' '; *pszInStr++ = ' '; } #endif *pszInStr++ = (CHAR)((wHourMinSec % 10) + '0'); if (i < 2) *pszInStr++ = *szTime; /* Assumes time sep. is 1 char long */ } // *pszInStr++ = ' '; if (bAM) lstrcpy(pszInStr, sz1159); else lstrcpy(pszInStr, sz2359); return lstrlen(szOutStr); } /*--------------------------------------------------------------------------*/ /* */ /* PutSize() - */ /* */ /*--------------------------------------------------------------------------*/ INT APIENTRY PutSize( DWORD dwSize, LPSTR szOutStr ) { // LPSTR szStr; // int cBlanks; // char szTemp[30]; // Convert it into string return wsprintf(szOutStr, "%lu", dwSize); } /*--------------------------------------------------------------------------*/ /* */ /* PutDate() - */ /* */ /*--------------------------------------------------------------------------*/ INT APIENTRY PutDate( LPFILETIME lpftDate, LPSTR szStr ) { WORD wValArray[3]; WORD wDate, wTime; if (FileTimeToDosDateTime(lpftDate, &wDate, &wTime)) { wValArray[0] = (WORD)((wDate & MONTHMASK) >> 5); /* Month */ wValArray[1] = (WORD)((wDate & DATEMASK)); /* Date */ wValArray[2] = (WORD)((wDate >> 9) + 80); /* Year */ return(CreateDate((WORD *)wValArray, szStr)); } else { return 0; } } /*--------------------------------------------------------------------------*/ /* */ /* PutTime() - */ /* */ /*--------------------------------------------------------------------------*/ INT APIENTRY PutTime( LPFILETIME lpftTime, LPSTR szStr ) { WORD wValArray[3]; WORD wDate, wTime; if (FileTimeToDosDateTime(lpftTime, &wDate, &wTime)) { wValArray[0] = (wTime >> 0x0B); wValArray[1] = (WORD)((wTime & MINUTEMASK) >> 5); wValArray[2] = (WORD)((wTime & SECONDSMASK) << 1); return(CreateTime((WORD *)wValArray, szStr)); } else { return 0; } } /*--------------------------------------------------------------------------*/ /* */ /* PutAttributes() - */ /* */ /*--------------------------------------------------------------------------*/ INT APIENTRY PutAttributes( register DWORD dwAttribute, register LPSTR pszStr ) { WORD i; INT cch = 0; for (i=0; i < 4; i++) { if (dwAttribute & 1) { // BUG hardcoded. *pszStr++ = szAttr[i]; cch++; } else { #if 0 *pszStr++ = '-'; *pszStr++ = '-'; cch += 2; #endif } if (i == 2) dwAttribute >>= 3; /* Skip next two bits */ else dwAttribute >>= 1; /* Goto next bit */ } *pszStr = 0; return(cch); } /*--------------------------------------------------------------------------*/ /* */ /* CreateLBLine() - */ /* */ /*--------------------------------------------------------------------------*/ /* This creates a character string that contains all the required * details of a file; (Name, Size, Date, Time, Attr) */ VOID CreateLBLine( register WORD wLineFormat, LPMYDTA lpmydta, LPSTR szBuffer ) { register LPSTR pch; DWORD dwAttr; pch = szBuffer; dwAttr = lpmydta->my_dwAttrs; /* Copy the file name. */ lstrcpy(pch, lpmydta->my_cFileName); pch += lstrlen(pch); *pch = 0L; /* Should we show the size? */ if (wLineFormat & VIEW_SIZE) { *pch++ = TABCHAR; if (!(dwAttr & ATTR_DIR)) pch += PutSize(lpmydta->my_nFileSizeLow, pch); else *pch = 0; } /* Should we show the date? */ if (wLineFormat & VIEW_DATE) { *pch++ = TABCHAR; pch += PutDate(&lpmydta->my_ftLastWriteTime, pch); } /* Should we show the time? */ if (wLineFormat & VIEW_TIME) { *pch++ = TABCHAR; pch += PutTime(&lpmydta->my_ftLastWriteTime, pch); } /* Should we show the attributes? */ if (wLineFormat & VIEW_FLAGS) { *pch++ = TABCHAR; pch += PutAttributes(dwAttr, pch); } // *pch = 0L; } /*--------------------------------------------------------------------------*/ /* */ /* CompareDTA() - */ /* */ /*--------------------------------------------------------------------------*/ INT CompareDTA( register LPMYDTA lpItem1, LPMYDTA lpItem2, WORD wSort ) { register INT ret; if (lpItem1->my_dwAttrs & ATTR_PARENT) { ret = -1; goto CDDone; } if (lpItem2->my_dwAttrs & ATTR_PARENT) { ret = 1; goto CDDone; } if ((lpItem1->my_dwAttrs & ATTR_DIR) > (lpItem2->my_dwAttrs & ATTR_DIR)) { ret = -1; goto CDDone; } else if ((lpItem1->my_dwAttrs & ATTR_DIR) < (lpItem2->my_dwAttrs & ATTR_DIR)) { ret = 1; goto CDDone; } switch (wSort) { case IDD_TYPE: { LPSTR ptr1; LPSTR ptr2; // BUG: should use strrchr for long file names. for (ptr1 = lpItem1->my_cFileName; *ptr1 && *ptr1 != '.'; ptr1++) ; for (ptr2 = lpItem2->my_cFileName; *ptr2 && *ptr2 != '.'; ptr2++) ; ret = lstrcmpi(ptr1, ptr2); if (ret == 0) goto CompareNames; break; } case IDD_SIZE: if (lpItem1->my_nFileSizeLow > lpItem2->my_nFileSizeLow) ret = -1; else if (lpItem1->my_nFileSizeLow < lpItem2->my_nFileSizeLow) ret = 1; else goto CompareNames; break; case IDD_DATE: { DWORD d1High, d1Low; DWORD d2High, d2Low; d1High = lpItem1->my_ftLastWriteTime.dwHighDateTime; d2High = lpItem2->my_ftLastWriteTime.dwHighDateTime; if (d1High > d2High) { ret = -1; } else if (d1High < d2High) { ret = 1; } else { d1Low = lpItem1->my_ftLastWriteTime.dwLowDateTime; d2Low = lpItem2->my_ftLastWriteTime.dwLowDateTime; if (d1Low > d2Low) ret = -1; else if (d1Low < d2Low) ret = 1; else goto CompareNames; } break; } case IDD_NAME: CompareNames: ret = lstrcmpi(lpItem1->my_cFileName, lpItem2->my_cFileName); break; } CDDone: return ret; } // load the status buffers with the appropriate stuff and invalidates // the status area causing it to repaint. VOID APIENTRY UpdateStatus( HWND hWnd ) { CHAR szTemp[128]; WCHAR szNumBuf1[40]; WCHAR szNumBuf2[40]; WORD wDrive; HWND hwndDir; RECT rc; if (!bStatusBar) return; if (hWnd != (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0L)) return; hwndDir = HasDirWindow(hWnd); szStatusTree[0] = 0L; if (hwndDir) GetDirStatus(hwndDir, szStatusTree, szStatusDir); else szStatusDir[0] = 0L; // force the status area to update GetClientRect(hwndFrame, &rc); rc.top = rc.bottom - dyStatus; InvalidateRect(hwndFrame, &rc, FALSE); } HWND GetDirSelData( HWND hWnd, DWORD *pdwSelSize, INT *piSelCount, DWORD *pdwTotalSize, INT *piTotalCount ) { INT i; LPMYDTA lpmydta; HWND hwndLB; INT countSel, countTotal; LPINT lpSelItems, lpSelItemsT; HANDLE hDTA; if (!(hwndLB = GetDlgItem(hWnd, IDCW_LISTBOX))) { // fast scroll return NULL; } *pdwSelSize = *pdwTotalSize = 0L; *piSelCount = *piTotalCount = 0; countSel = (INT)SendMessage(hwndLB, LB_GETSELCOUNT, 0, 0L); lpSelItems = LocalAlloc(LMEM_FIXED, sizeof(INT) * countSel); if (lpSelItems == NULL) return NULL; countSel = (INT)SendMessage(hwndLB, LB_GETSELITEMS, (WPARAM)countSel, (LPARAM)lpSelItems); hDTA = (HANDLE)GetWindowLongPtr(hWnd, GWLP_HDTA); if (hDTA == NULL) return NULL; lpmydta = (LPMYDTA)LocalLock(hDTA); countTotal = (INT)lpmydta->my_nFileSizeLow; lpSelItemsT = lpSelItems; for (i = 0; i < countTotal; i++) { lpmydta = GETDTAPTR(lpmydta, lpmydta->wSize); if (lpmydta->my_dwAttrs & ATTR_PARENT) continue; if (countSel && *lpSelItems == lpmydta->nIndex) { (*piSelCount)++; *pdwSelSize += lpmydta->my_nFileSizeLow; countSel--; lpSelItems++; } (*piTotalCount)++; *pdwTotalSize += lpmydta->my_nFileSizeLow; } LocalUnlock(hDTA); LocalFree(lpSelItemsT); return hwndLB; } VOID GetDirStatus( HWND hWnd, LPSTR szMessage1, LPSTR szMessage2 ) { INT iSelCount, iCount; DWORD dwSelSize, dwSize; CHAR szNumBuf[40]; HWND hwndLB; szMessage2[0] = 0; hwndLB = GetDirSelData(hWnd, &dwSelSize, &iSelCount, &dwSize, &iCount); if (LoadString(hAppInstance, IDS_STATUSMSG, szMessage, sizeof(szMessage))) wsprintf(szMessage2, szMessage, iCount); if ((HWND)GetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS) == hwndLB) { if (LoadString(hAppInstance, IDS_STATUSMSG2, szMessage, sizeof(szMessage))) wsprintf(szMessage1, szMessage, iSelCount); } } // given a descendant of an MDI child (or an MDI child) return // the MDI child in the descendant chain. returns NULL if not // found. HWND APIENTRY GetMDIChildFromDecendant( HWND hwnd ) { HWND hwndT; while (hwnd && ((hwndT = GetParent(hwnd)) != hwndMDIClient)) hwnd = hwndT; return hwnd; } // setup the defTabStops[] array for subsequent TabbedTextOut() calls. // // in: // iMaxWidthFileName the largest dx width of files to be // displayed // // returns: // total extent of the "File Details" view. used to // set scroll extents INT APIENTRY FixTabsAndThings( HWND hwndLB, WORD *pwTabs, INT iMaxWidthFileName, WORD wViewOpts ) { INT i; HDC hdc; HFONT hOld; CHAR szBuf[30]; INT ixExtent = 0; i = iMaxWidthFileName; // the widest filename if (pwTabs == NULL) return i; hdc = GetDC(NULL); hOld = SelectObject(hdc, hFont); // max size digits field if (wViewOpts & VIEW_SIZE) { MGetTextExtent(hdc, "99999999", 8, &ixExtent, NULL); i += ixExtent + dxText; *pwTabs++ = (WORD)i; // Size } if (wViewOpts & VIEW_DATE) { FILETIME filetime; DosDateTimeToFileTime((WORD)((19 << 9) | (12 << 5) | 30), (WORD)0xFFFF, &filetime); PutDate(&filetime, szBuf); // max date digits MGetTextExtent(hdc, szBuf, lstrlen(szBuf), &ixExtent, NULL); i += ixExtent + dxText; *pwTabs++ = (WORD)i; // Date } // max time digits if (wViewOpts & VIEW_TIME) { FILETIME filetime; DosDateTimeToFileTime((WORD)((19 << 9) | (12 << 5) | 30), (WORD)0xFFFF, &filetime); PutTime(&filetime, szBuf); MGetTextExtent(hdc, szBuf, lstrlen(szBuf), &ixExtent, NULL); i += ixExtent + dxText; *pwTabs++ = (WORD)i; // Time } // max attris digits if (wViewOpts & VIEW_FLAGS) { PutAttributes(ATTR_ALL, szBuf); MGetTextExtent(hdc, szBuf, lstrlen(szBuf), &ixExtent, NULL); i += ixExtent + dxText; *pwTabs++ = (WORD)i; // Attributes } if (hOld) SelectObject(hdc, hOld); ReleaseDC(NULL, hdc); SendMessage(hwndLB, LB_SETHORIZONTALEXTENT, i + dxFolder + 4 * dyBorderx2, 0L); return i; // total extent } // sets the font and adjusts the dimension parameters for the // new font // // in: // hWnd hwnd of a dir window // hwndLB and it's listbox // hFont the font to set // // uses: // dyFileName GLOBAL; set based on new font height // GWL_VIEW window word of hWnd for either full or name view // GWL_HDTA to compute the max extent given the new font // // sets: // Listbox tabs array // LB_SETCOLUMNWIDTH // or // LB_SETHORIZONTALEXTENT VOID APIENTRY SetLBFont( HWND hWnd, HWND hwndLB, HANDLE hNewFont ) { INT dxMaxExtent; HANDLE hDTA; WORD wViewFlags = (WORD)GetWindowLong(GetParent(hWnd), GWL_VIEW); SendMessage(hwndLB, WM_SETFONT, (WPARAM)hNewFont, 0L); // this is needed when changing the font. when creating // the return from WM_MEASUREITEM will set the cell height SendMessage(hwndLB, LB_SETITEMHEIGHT, 0, (LONG)dyFileName); hDTA = (HANDLE)GetWindowLongPtr(hWnd, GWLP_HDTA); dxMaxExtent = (INT)GetMaxExtent(hwndLB, hDTA); // if we are in name only view we change the width if ((VIEW_EVERYTHING & wViewFlags) == VIEW_NAMEONLY) { SendMessage(hwndLB, LB_SETCOLUMNWIDTH, dxMaxExtent + dxFolder + dyBorderx2, 0L); } else { FixTabsAndThings(hwndLB,(WORD *)GetWindowLongPtr(hWnd, GWLP_TABARRAY), dxMaxExtent, wViewFlags); } } VOID APIENTRY UpdateSelection( HWND hwndLB ) { INT count, i; RECT rc; count = (WORD)SendMessage(hwndLB, LB_GETCOUNT, 0, 0L); for (i=0; i < count; i++) { if ((BOOL)SendMessage(hwndLB, LB_GETSEL, i, 0L)) { SendMessage(hwndLB, LB_GETITEMRECT, i, (LPARAM)&rc); InvalidateRect(hwndLB, &rc, TRUE); } } } LONG CreateFSCChangeDisplayMess( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) { CHAR szCaret[MAXFILENAMELEN+1]; CHAR szAnchor[MAXFILENAMELEN+1]; CHAR szTopIndex[MAXFILENAMELEN+1]; CHAR szPath[256]; HCURSOR hCursor; HWND hwndLB, hwndT; HANDLE hDTA; LPMYDTA lpmydta; DWORD ws; LPSTR pSel; INT iSel, iTop=0; RECT rc; BOOL bResetFocus; WORD *pwTabs; hwndLB = GetDlgItem(hWnd, IDCW_LISTBOX); switch (wMsg) { case WM_FILESYSCHANGE: if (cDisableFSC) { // I need to be updated SetWindowLong(GetParent(hWnd), GWL_FSCFLAG, TRUE); break; } wParam = CD_PATH; lParam = 0L; /*** FALL THRU ***/ case FS_CHANGEDISPLAY: // We dont want to reset the flag, if the operation is not CD_PATH. // This is because, only the operation CD_PATH implies a true // refresh. The operations CD_VEIW and CD_SORT are not refresh // operations. They merely reformat the existing contents of a dir // window. The flag is now reset in 'case CD_PATH:'. //SetWindowLong(GetParent(hWnd), GWL_FSCFLAG, FALSE); hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); pSel = NULL; // init this bResetFocus = (GetFocus() == hwndLB); hDTA = (HANDLE)GetWindowLongPtr(hWnd, GWLP_HDTA); switch (wParam) { case CD_SORT: // change the sort order of the listbox // we want to save the current selection and things here // and restore them once the listbox has been rebuilt // But first, save a list of the selected items FIX31 pSel = (LPSTR)DirGetSelection(hWnd, hwndLB, 0, NULL); DirGetAnchorFocus(hwndLB, hDTA, szAnchor, szCaret, szTopIndex); iTop = (INT)SendMessage(hwndLB, LB_GETTOPINDEX, 0, 0L); SetWindowLong(GetParent(hWnd), GWL_SORT, LOWORD(lParam)); SendMessage(hwndLB, LB_RESETCONTENT, 0, 0L); SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0L); FillDirList(hwndLB, hDTA); goto ResetSelection; case CD_VIEW: { WORD wCurView; // change the view type (name only, vs full details) // Warning! Convoluted Code! We want to destroy the // listbox only if we are going between Name Only view // and Details view. wNewView = LOWORD(lParam); wCurView = (WORD)GetWindowLong(GetParent(hWnd), GWL_VIEW); if (wNewView == wCurView) break; // NOP // special case the long and partial view change // this doesn't require us to recreate the listbox if ((VIEW_EVERYTHING & wNewView) && (VIEW_EVERYTHING & wCurView)) { SetWindowLong(GetParent(hWnd), GWL_VIEW, wNewView); FixTabsAndThings(hwndLB,(WORD *)GetWindowLongPtr(hWnd, GWLP_TABARRAY), GetMaxExtent(hwndLB, hDTA), wNewView); InvalidateRect(hwndLB, NULL, TRUE); break; } /* Things are a changing radically. Destroy the listbox. */ // But first, save a list of the selected items pSel = (LPSTR)DirGetSelection(hWnd, hwndLB, 0, NULL); DirGetAnchorFocus(hwndLB, hDTA, szAnchor, szCaret, szTopIndex); iTop = (INT)SendMessage(hwndLB, LB_GETTOPINDEX, 0, 0L); lstrcpy(szTopIndex, szCaret); if ((HWND)GetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS) == hwndLB) SetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS, 0L); DestroyWindow(hwndLB); /* Create a new one (preserving the Sort setting). */ wNewSort = (WORD)GetWindowLong(GetParent(hWnd), GWL_SORT); dwNewAttribs = (DWORD)GetWindowLong(GetParent(hWnd), GWL_ATTRIBS); goto CreateLB; } case CD_PATH | CD_ALLOWABORT: case CD_PATH: case CD_PATH_FORCE: // bad things happens if we change the path // while we are reading the tree. bounch this // in that case. this causes the steal data // code in the tree to barf because we would // free the hDTA while it is being traversed // (very bad thing) // we set the GWL_FSCFLAG to true, if we could not refresh. // else we set it to FALSE. However if the flag was previously // TRUE we set lParam to NULL. lParam = NULL implies 'forced' // refresh. hwndT = HasTreeWindow(GetParent(hWnd)); if (hwndT && GetWindowLong(hwndT, GWL_READLEVEL)) { SetWindowLong(GetParent(hWnd), GWL_FSCFLAG, TRUE); break; } else { if (SetWindowLong(GetParent(hWnd), GWL_FSCFLAG, FALSE)) lParam = 0L; } // change the path of the current directory window (basically // recreate the whole thing) // if lParam == NULL this is a refresh, otherwise // check for short circut case to avoid rereading // the directory GetMDIWindowText(GetParent(hWnd), szPath, sizeof(szPath)); if (lParam) { // get out early if this is a NOP if ((wParam != CD_PATH_FORCE) && !lstrcmpi(szPath, (LPSTR)lParam)) break; lstrcpy(szPath, (LPSTR)lParam); iLastSel = -1; // invalidate the last selection } // if this is a refresh save the current selection, anchor stuff, etc if (!lParam) { pSel = (LPSTR)DirGetSelection(hWnd, hwndLB, 0, NULL); iTop = (INT)SendMessage(hwndLB, LB_GETTOPINDEX, 0, 0L); DirGetAnchorFocus(hwndLB, hDTA, szAnchor, szCaret, szTopIndex); } // Create a new one (preserving the Sort setting) wNewSort = (WORD)GetWindowLong(GetParent(hWnd), GWL_SORT); wNewView = (WORD)GetWindowLong(GetParent(hWnd), GWL_VIEW); dwNewAttribs = GetWindowLong(GetParent(hWnd), GWL_ATTRIBS); if (hDTA) { // fast scroll case LocalFree(hDTA); hDTA = NULL; SendMessage(hwndLB, LB_RESETCONTENT, 0, 0L); } goto CreateNewPath; } SetCursor(hCursor); ShowCursor(FALSE); break; case WM_CREATE: TRACE(BF_WM_CREATE, "CreateFSCChangeDisplayMess - WM_CREATE"); // wNewView, wNewSort and dwNewAddribs define the viewing // parameters of the new window (GLOBALS) // the window text of the parent window defines the // filespec and the directory to open up hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); wParam = 0; // don't allow abort in CreateDTABlock() lParam = 1L; // allow DTA steal optimization pSel = NULL; // no selection to restore bResetFocus = FALSE; // no focus to restore // get the dir to open from our parent window text GetMDIWindowText(GetParent(hWnd), szPath, sizeof(szPath)); if ((pwTabs = (WORD *)LocalAlloc(LPTR,sizeof(WORD) * 4)) == NULL) return -1L; SetWindowLongPtr(hWnd, GWLP_TABARRAY, (ULONG_PTR)pwTabs); CreateNewPath: // at this point szPath has the directory to read. this // either came from the WM_CREATE case or the // FS_CHANGEDISPLAY (CD_PATH) directory reset #ifdef DEBUG { char buf[80]; wsprintf(buf, "attribs %4.4X\r\n", dwNewAttribs); OutputDebugString(buf); } #endif if (!dwNewAttribs) dwNewAttribs = ATTR_DEFAULT; hDTA = CreateDTABlock(hWnd, szPath, dwNewAttribs, wParam & CD_ALLOWABORT ? TRUE : FALSE, lParam == 0L); // check for user abort (fast scroll case) if (hDTA == (HANDLE)-1) { SetWindowLongPtr(hWnd, GWLP_HDTA, 0L); goto FastScrollExit; } // for the FS_CHANGEDISPLAY case we set this now, to avoid // multiple title repaints when the user is fast scrolling if (wMsg != WM_CREATE) SetMDIWindowText(GetParent(hWnd), szPath); SetWindowLongPtr(hWnd, GWLP_HDTA, (LONG_PTR)hDTA); if (!hDTA) goto CDAbort; if (wMsg != WM_CREATE) goto SkipWindowCreate; CreateLB: if ((wNewView & VIEW_EVERYTHING) == VIEW_NAMEONLY) ws = WS_DIRSTYLE | LBS_MULTICOLUMN | WS_HSCROLL | WS_VISIBLE | WS_BORDER | LBS_DISABLENOSCROLL; else ws = WS_DIRSTYLE | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | WS_BORDER | LBS_DISABLENOSCROLL; GetClientRect(hWnd, &rc); // the border stuff is for the non initial create case // I don't know why hwndLB = CreateWindowEx(0L, szListbox, NULL, ws, dyBorder, dyBorder, rc.right - 2*dyBorder, rc.bottom - 2*dyBorder, hWnd, (HMENU)IDCW_LISTBOX, hAppInstance, NULL); if (!hwndLB) { if (hDTA) LocalFree(hDTA); if (wMsg != WM_CREATE) SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L); CDAbort: ShowCursor(FALSE); SetCursor(hCursor); return -1L; } // set all the view/sort/include parameters here SetWindowLong(GetParent(hWnd), GWL_VIEW, wNewView); SetWindowLong(GetParent(hWnd), GWL_SORT, wNewSort); SetWindowLong(GetParent(hWnd), GWL_ATTRIBS, dwNewAttribs); // restore the last focus stuff if we are recreating here if (!GetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS)) SetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS, (LONG_PTR)hwndLB); // set the font and dimensions here SkipWindowCreate: SetLBFont(hWnd, hwndLB, hFont); SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0L); FillDirList(hwndLB, hDTA); if (pSel) { BOOL bDidSomething; ResetSelection: /* Give the selected item the focus rect and anchor pt. */ bDidSomething = SetSelection(hwndLB, hDTA, pSel); LocalFree((HANDLE)pSel); if (!bDidSomething) goto SelectFirst; iSel = DirFindIndex(hwndLB, hDTA, szTopIndex); if (iSel == -1) iSel = 0; SendMessage(hwndLB, LB_SETTOPINDEX, iSel, 0L); iSel = DirFindIndex(hwndLB, hDTA, szAnchor); if (iSel == -1) iSel = 0; SendMessage(hwndLB, LB_SETANCHORINDEX, iSel, 0L); iSel = DirFindIndex(hwndLB, hDTA, szCaret); if (iSel == -1) iSel = 0; /* SETCARETINDEX will scroll item into view */ SendMessage(hwndLB, LB_SETCARETINDEX, iSel, 0L); } else { INT iLBCount; SelectFirst: iLBCount = (INT)SendMessage(hwndLB, LB_GETCOUNT, 0, 0L); if (iLastSel != -1 && (iLastSel <= iLBCount)) { iSel = iLastSel; // check the case of the last item being deleted if (iSel == iLBCount) iSel--; SendMessage(hwndLB, LB_SETSEL, TRUE, (DWORD)iSel); } else { // Select the first non-directory item iSel = 0; while (iSel < iLBCount) { SendMessage(hwndLB, LB_GETTEXT, iSel, (LPARAM)&lpmydta); if (!lpmydta) break; if (!(lpmydta->my_dwAttrs & ATTR_PARENT)) { iTop = iSel; break; } iSel++; } LocalUnlock(hDTA); if (iSel == iLBCount) iSel = 0; } SendMessage(hwndLB, LB_SETTOPINDEX, iTop, 0L); // and select this item if no tree window if (!HasTreeWindow(GetParent(hWnd))) SendMessage(hwndLB, LB_SETSEL, TRUE, (DWORD)iSel); SendMessage(hwndLB, LB_SETANCHORINDEX, iSel, 0L); /* SETCARETINDEX will scroll item into view */ SendMessage(hwndLB, LB_SETCARETINDEX, iSel, 0L); } if (bResetFocus) if (SetDirFocus(hWnd)) SetFocus(hWnd); SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hwndLB, NULL, TRUE); lFreeSpace = -1; // force status update UpdateStatus(GetParent(hWnd)); FastScrollExit: ShowCursor(FALSE); SetCursor(hCursor); break; } return 0L; } INT_PTR APIENTRY DirWndProc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) { INT iSel, i; LPSTR pSel; HWND hwndLB; HANDLE hDTA; LPMYDTA lpmydta; CHAR szTemp[MAXPATHLEN] = {0}; CHAR szSourceFile[MAXPATHLEN]; static HWND hwndOwnerDraw = NULL; STKCHK(); /* Here we generate OWNERDRAWBEGIN and OWNERDRAWEND messages * to speed up the painting operations. We do the expensive stuff * at the beginning instead of on every DRAWITEM message. */ if (hwndOwnerDraw == hWnd && wMsg != WM_DRAWITEM) { hwndOwnerDraw = NULL; SendMessage(hWnd, WM_OWNERDRAWEND, 0, 0L); } else if (wMsg == WM_DRAWITEM && hwndOwnerDraw != hWnd) { SendMessage(hWnd, WM_OWNERDRAWBEGIN, wParam, lParam); hwndOwnerDraw = hWnd; } hwndLB = GetDlgItem(hWnd, IDCW_LISTBOX); switch (wMsg) { // returns in lParam upper case ANSI directory string with // a trailing backslash. if you want to do a SetCurrentDirecotor() // you must first StripBackslash() the thing! case FS_GETDIRECTORY: MSG("DirWndProc", "FS_GETDIRECTORY"); GetMDIWindowText(GetParent(hWnd), (LPSTR)lParam, (INT)wParam); // get the string StripFilespec((LPSTR)lParam); // Remove the trailing extention AddBackslash((LPSTR)lParam); // terminate with a backslash //AnsiUpper((LPSTR)lParam); // and upper case break; case FS_GETDRIVE: MSG("DirWndProc", "FS_GETDRIVE"); // Returns the letter of the corresponding directory GetWindowText(GetParent(hWnd), szTemp, sizeof(szTemp)); AnsiUpper(szTemp); return szTemp[0]; // first character case FS_GETFILESPEC: MSG("DirWndProc", "FS_GETFILESPEC"); // returns the current filespec (from View.Include...). this is // an uppercase ANSI string GetMDIWindowText(GetParent(hWnd), (LPSTR)lParam, (INT)wParam); StripPath((LPSTR)lParam); //AnsiUpper((LPSTR)lParam); // and upper case break; case FS_SETSELECTION: MSG("DirWndProc", "FS_SETSELECTION"); // wParam is the select(TRUE)/unselect(FALSE) param // lParam is the filespec to match against SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0L); DSSetSelection(hwndLB, wParam ? TRUE : FALSE, (LPSTR)lParam, FALSE); SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hwndLB, NULL, TRUE); break; case FS_GETSELECTION: // return = pszDir #define pfDir (BOOL *)lParam #define fSingleSel (BOOL)wParam MSG("DirWndProc", "FS_GETSELECTION"); return (INT_PTR)DirGetSelection(hWnd, hwndLB, fSingleSel, pfDir); #undef pfDir #undef fSingleSel case WM_CREATE: case WM_FILESYSCHANGE: case FS_CHANGEDISPLAY: TRACE(BF_WM_CREATE, "DirWndProc - WM_CREATE"); return CreateFSCChangeDisplayMess(hWnd, wMsg, wParam, lParam); case WM_DESTROY: MSG("DirWndProc", "WM_DESTROY"); { HANDLE hMem; HWND hwnd; if (hwndLB == GetFocus()) if (hwnd = HasTreeWindow(GetParent(hWnd))) SetFocus(hwnd); if (hMem = (HANDLE)GetWindowLongPtr(hWnd, GWLP_TABARRAY)) LocalFree(hMem); } break; case WM_CHARTOITEM: MSG("DirWndProc", "WM_CHARTOITEM"); { WORD j; WORD cItems; CHAR ch[2]; if ((ch[0] = GET_WM_CHARTOITEM_CHAR(wParam, lParam)) <= ' ') return(-1L); i = GET_WM_CHARTOITEM_POS(wParam, lParam); cItems = (WORD)SendMessage(hwndLB, LB_GETCOUNT, 0, 0L); szTemp[1] = 0L; ch[0] &= 255; ch[1] = '\0'; for (j=1; j <= cItems; j++) { SendMessage(hwndLB, LB_GETTEXT, (i + j) % cItems, (LPARAM)&lpmydta); szTemp[0] = lpmydta->my_cFileName[0]; /* Do it this way to be case insensitive. */ if (!lstrcmpi((LPSTR)ch, szTemp)) break; } if (j > cItems) return -2L; return(MAKELONG((i + j) % cItems, 0)); } case WM_COMPAREITEM: MSG("DirWndProc", "WM_COMPAREITEM"); { #define lpci ((LPCOMPAREITEMSTRUCT)lParam) return (LONG)CompareDTA((LPMYDTA)lpci->itemData1, (LPMYDTA)lpci->itemData2, (WORD)GetWindowLong(GetParent(hWnd), GWL_SORT)); } case WM_NCDESTROY: MSG("DirWndProc", "WM_NCDESTROY"); if (hDTA = (HANDLE)GetWindowLongPtr(hWnd, GWLP_HDTA)) { LocalFree(hDTA); } break; case WM_DRAGLOOP: MSG("DirWndProc", "WM_DRAGDROP"); /* WM_DRAGLOOP is sent to the source window as the object is moved. * * wParam: TRUE if the object is currently over a droppable sink * lParam: LPDROPSTRUCT */ /* DRAGLOOP is used to turn the source bitmaps on/off as we drag. */ DSDragLoop(hwndLB, wParam, (LPDROPSTRUCT)lParam, FALSE); break; case WM_DRAGSELECT: MSG("DirWndProc", "WM_DRAGSELECT"); /* WM_DRAGSELECT is sent to a sink whenever an new object is dragged * inside of it. * * wParam: TRUE if the sink is being entered, FALSE if it's being * exited. * lParam: LPDROPSTRUCT */ /* DRAGSELECT is used to turn our selection rectangle on or off. */ #define lpds ((LPDROPSTRUCT)lParam) iSelHilite = LOWORD(lpds->dwControlData); DSRectItem(hwndLB, iSelHilite, (BOOL)wParam, FALSE); break; case WM_DRAGMOVE: MSG("DirWndProc", "WM_DRAGMOVE"); /* WM_DRAGMOVE is sent to a sink as the object is being dragged * within it. * * wParam: Unused * lParam: LPDROPSTRUCT */ /* DRAGMOVE is used to move our selection rectangle among sub-items. */ #define lpds ((LPDROPSTRUCT)lParam) /* Get the subitem we are over. */ iSel = LOWORD(lpds->dwControlData); /* Is it a new one? */ if (iSel == iSelHilite) break; /* Yup, un-select the old item. */ DSRectItem(hwndLB, iSelHilite, FALSE, FALSE); /* Select the new one. */ iSelHilite = iSel; DSRectItem(hwndLB, iSel, TRUE, FALSE); break; case WM_OWNERDRAWBEGIN: #define lpLBItem ((LPDRAWITEMSTRUCT)lParam) MSG("DirWndProc", "WM_OWNERDRAWBEGIN"); /* Set the default bk and text colors. */ SetTextColor(lpLBItem->hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(lpLBItem->hDC, GetSysColor(COLOR_WINDOW)); #undef lpLBItem break; case WM_OWNERDRAWEND: MSG("DirWndProc", "WM_OWNERDRAWEND"); break; case WM_DRAWITEM: #define lpLBItem ((LPDRAWITEMSTRUCT)lParam) MSG("DirWndProc", "WM_DRAWITEM"); { WORD wViewFlags; LPMYDTA lpmydta; /* Don't do anything to empty listboxes. */ if (lpLBItem->itemID == -1) break; if (lpLBItem->itemData == (DWORD)0) { LoadString(hAppInstance, IDS_NOFILES, szTemp, sizeof(szTemp)); TextOut(lpLBItem->hDC, lpLBItem->rcItem.left, lpLBItem->rcItem.top, szTemp, lstrlen(szTemp)); } else { lpmydta = (LPMYDTA)lpLBItem->itemData; wViewFlags = (WORD)GetWindowLong(GetParent(hWnd), GWL_VIEW); if (wViewFlags & VIEW_EVERYTHING) { // if any of the wViewFlags bits set, we are in slow mode CreateLBLine(wViewFlags, lpmydta, szTemp); DrawItem(lpLBItem, szTemp, lpmydta->my_dwAttrs, (HWND)GetFocus()==lpLBItem->hwndItem, (WORD *)GetWindowLongPtr(hWnd, GWLP_TABARRAY)); } else DrawItemFast(hWnd, lpLBItem, lpmydta, (HWND)GetFocus()==lpLBItem->hwndItem); } } #undef lpLBItem break; case WM_DROPOBJECT: MSG("DirWndProc", "WM_DROPOBJECT"); { WORD ret; LPSTR pFrom; DWORD dwAttrib = 0; // init this to not a dir WORD iSelSink; #define lpds ((LPDROPSTRUCT)lParam) // Do nothing - but remove selection rectangle DSRectItem(hwndLB, iSelHilite, FALSE, FALSE); return(TRUE); /* WM_DROPOBJECT is sent to a sink when the user releases an * acceptable object over it * * wParam: TRUE if over the non-client area, FALSE if over the * client area. * lParam: LPDROPSTRUCT */ // this is the listbox index of the destination iSelSink = LOWORD(lpds->dwControlData); /* Are we dropping onto ourselves? (i.e. a selected item in the * source listbox OR an unused area of the source listbox) If * so, don't do anything. */ if (hWnd == lpds->hwndSource) { if ((iSelSink == 0xFFFF) || SendMessage(hwndLB, LB_GETSEL, iSelSink, 0L)) return TRUE; } // set the destination, assume move/copy case below (c:\foo\) SendMessage(hWnd, FS_GETDIRECTORY, sizeof(szTemp), (LPARAM)szTemp); // Are we dropping on a unused portion of some listbox? if (iSelSink == 0xFFFF) goto NormalMoveCopy; // check for drop on a directory SendMessage(hwndLB, LB_GETTEXT, iSelSink, (LPARAM)&lpmydta); lstrcpy(szSourceFile, lpmydta->my_cFileName); dwAttrib = lpmydta->my_dwAttrs; if (dwAttrib & ATTR_DIR) { if (dwAttrib & ATTR_PARENT) { // special case the parent StripBackslash(szTemp); StripFilespec(szTemp); } else { lstrcat(szTemp, szSourceFile); } goto DirMoveCopy; } // dropping on a program? if (!IsProgramFile(szSourceFile)) goto NormalMoveCopy; // no, normal stuff // directory drop on a file? this is a NOP if (lpds->wFmt == DOF_DIRECTORY) { DSRectItem(hwndLB, iSelHilite, FALSE, FALSE); break; } // We're dropping a file onto a program. // Exec the program using the source file as the parameter. // set the directory to that of the program to exec SendMessage(hWnd, FS_GETDIRECTORY, sizeof(szTemp), (LPARAM)szTemp); StripBackslash(szTemp); FixAnsiPathForDos(szTemp); SheChangeDir(szTemp); // get the selected file pSel = (LPSTR)SendMessage(lpds->hwndSource, FS_GETSELECTION, TRUE, 0L); if (lstrlen(pSel) > MAXPATHLEN) // don't blow up below! goto DODone; if (bConfirmMouse) { LoadString(hAppInstance, IDS_MOUSECONFIRM, szTitle, sizeof(szTitle)); LoadString(hAppInstance, IDS_EXECMOUSECONFIRM, szTemp, sizeof(szTemp)); wsprintf(szMessage, szTemp, (LPSTR)szSourceFile, (LPSTR)pSel); if (MessageBox(hwndFrame, szMessage, szTitle, MB_YESNO | MB_ICONEXCLAMATION) != IDYES) goto DODone; } // create an absolute path to the argument (search window alaready // is absolute) if (lpds->hwndSource == hwndSearch) { szTemp[0] = 0L; } else { SendMessage(lpds->hwndSource, FS_GETDIRECTORY, sizeof(szTemp), (LPARAM)szTemp); } lstrcat(szTemp, pSel); // this is the parameter to the exec // put a "." extension on if none found if (*GetExtension(szTemp) == 0) lstrcat(szTemp, "."); FixAnsiPathForDos(szSourceFile); FixAnsiPathForDos(szTemp); ret = ExecProgram(szSourceFile, szTemp, NULL, FALSE); if (ret) MyMessageBox(hwndFrame, IDS_EXECERRTITLE, ret, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); DODone: DSRectItem(hwndLB, iSelHilite, FALSE, FALSE); LocalFree((HANDLE)pSel); return TRUE; NormalMoveCopy: /* Make sure that we don't move into same dir. */ if (GetParent(hWnd) == (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0L)) return TRUE; DirMoveCopy: // the source filename is in the loword pFrom = (LPSTR)(((LPDRAGOBJECTDATA)(lpds->dwData))->pch); // SetSourceDir(lpds); AddBackslash(szTemp); lstrcat(szTemp, szStarDotStar); // put files in this dir CheckEscapes(szTemp); ret = DMMoveCopyHelper(pFrom, szTemp, fShowSourceBitmaps); DSRectItem(hwndLB, iSelHilite, FALSE, FALSE); if (ret) return TRUE; if (!fShowSourceBitmaps) SendMessage(lpds->hwndSource, WM_FILESYSCHANGE, FSC_REFRESH, 0L); // we got dropped on, but if this is a dir we don't need to refresh if (!(dwAttrib & ATTR_DIR)) SendMessage(hWnd, WM_FILESYSCHANGE, FSC_REFRESH, 0L); return TRUE; } #if 0 case WM_GETTEXT: MSG("DirWndProc", "WM_GETTEXT"); { HDC hDC; RECT rc; /* This is where we make sure that the Directory's caption fits * inside the caption bar. */ /* Get the full path name. */ DefWindowProc(hWnd, wMsg, wParam, lParam); GetClientRect(hWnd, (LPRECT)&rc); hDC = GetDC(hWnd); CompactPath(hDC, (LPSTR)lParam, rc.right-rc.left-(dxText * 6)); ReleaseDC(hWnd, hDC); return((LONG)lstrlen((LPSTR)lParam)); /* Don't call DefWindowProc()! */ } #endif case WM_LBTRACKPOINT: MSG("DirWndProc", "WM_LBTRACKPOINT"); return DSTrackPoint(hWnd, hwndLB, wParam, lParam, FALSE); case WM_MEASUREITEM: MSG("DirWndProc", "WM_MEASUREITEM"); #define pLBMItem ((LPMEASUREITEMSTRUCT)lParam) pLBMItem->itemHeight = dyFileName; // the same as in SetLBFont() break; case WM_QUERYDROPOBJECT: MSG("DirWndProc", "WM_QUERYDROPOBJECT"); // lParam LPDROPSTRUCT // // return values: // 0 don't accept (use ghost buster) // 1 accept, use cursor from DragObject() // hCursor accept, change to this cursor // /* Ensure that we are dropping on the client area of the listbox. */ #define lpds ((LPDROPSTRUCT)lParam) /* Ensure that we can accept the format. */ switch (lpds->wFmt) { case DOF_EXECUTABLE: case DOF_DIRECTORY: case DOF_DOCUMENT: case DOF_MULTIPLE: if (lpds->hwndSink == hWnd) lpds->dwControlData = (DWORD)-1L; return (INT_PTR)GetMoveCopyCursor(); } return FALSE; case WM_SETFOCUS: // Fall through case WM_LBUTTONDOWN: MSG("DirWndProc", "WM_SETFOCUS/WM_LBUTTONDOWN"); SetFocus(hwndLB); break; case WM_COMMAND: switch (GET_WM_COMMAND_CMD(wParam, lParam)) { case LBN_DBLCLK: MSG("DirWndProc", "LBN_DBLCLK"); /* Double-click... Open the blasted thing. */ SendMessage(hwndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_OPEN, 0, 0)); break; case LBN_SELCHANGE: MSG("DirWndProc", "LBN_SELCHANGE"); for (i = 0; i < iNumExtensions; i++) { (extensions[i].ExtProc)(hwndFrame, FMEVENT_SELCHANGE, 0L); } UpdateStatus(GetParent(hWnd)); break; case LBN_SETFOCUS: MSG("DirWndProc", "LBN_SETFOCUS"); // Make sure there are files in this window. If not, set // the focus to the tree or drives window. Note: This // message was caused by a mouse click and not an // accelerator, because these were handled in the window // routine that was losing the focus. if (SetDirFocus(hWnd)) { SetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS, (LPARAM)GET_WM_COMMAND_HWND(wParam, lParam)); UpdateSelection(GET_WM_COMMAND_HWND(wParam, lParam)); } break; case LBN_KILLFOCUS: MSG("DirWndProc", "LBN_KILLFOCUS"); SetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS, 0L); UpdateSelection(GET_WM_COMMAND_HWND(wParam, lParam)); SetWindowLongPtr(GetParent(hWnd), GWLP_LASTFOCUS, (LPARAM)GET_WM_COMMAND_HWND(wParam, lParam)); break; } break; case WM_VKEYTOITEM: MSG("DirWndProc", "WM_VKEYTOITEM"); switch (GET_WM_VKEYTOITEM_ITEM(wParam, lParam)) { case VK_ESCAPE: bCancelTree = TRUE; return -2L; case 0xBF: /* Ctrl-/ */ SendMessage(hwndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_SELALL, 0, 0)); return -2; case 0xDC: /* Ctrl-\ */ SendMessage(hwndFrame, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_DESELALL, 0, 0)); return -2; case VK_F6: // like excel case VK_TAB: { HWND hwndTree, hwndDrives; GetTreeWindows(GetParent(hWnd), &hwndTree, NULL, &hwndDrives); if (GetKeyState(VK_SHIFT) < 0) SetFocus(hwndTree ? hwndTree : hwndDrives); else SetFocus(hwndDrives); break; } case VK_BACK: SendMessage(hWnd, FS_GETDIRECTORY, sizeof(szTemp), (LPARAM)szTemp); // are we already at the root? if (lstrlen(szTemp) <= 3) return -1; StripBackslash(szTemp); StripFilespec(szTemp); CreateDirWindow(szTemp, TRUE, GetParent(hWnd)); return -2; default: { HWND hwndDrives; // check for Ctrl-[DRIVE LETTER] and pass on to drives // window if ((GetKeyState(VK_CONTROL) < 0) && (hwndDrives = HasDrivesWindow(GetParent(hWnd)))) { return SendMessage(hwndDrives, wMsg, wParam, lParam); } break; } } return -1; case WM_SIZE: MSG("DirWndProc", "WM_SIZE"); if (!IsIconic(GetParent(hWnd))) { INT iMax; MoveWindow(hwndLB, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); iMax = (INT)SendMessage(hwndLB, LB_GETCARETINDEX, 0, 0L); if (iMax >= 0) // scroll item into view /* SETCARETINDEX will scroll item into view */ SendMessage(hwndLB, LB_SETCARETINDEX, iMax, 0L); //MakeItemVisible(iMax, hwndLB); } break; default: DEFMSG("DirWndProc", (WORD)wMsg); return DefWindowProc(hWnd, wMsg, wParam, lParam); } return 0L; } VOID SortDirList( HWND hWnd, LPMYDTA lpmydta, WORD count, LPMYDTA *lplpmydta ) { INT i, j; WORD wSort; INT iMax, iMin, iMid; wSort = (WORD)GetWindowLong(GetParent(GetParent(hWnd)), GWL_SORT); for (i = 0; i < (INT)count; i++) { // advance to next lpmydta = GETDTAPTR(lpmydta, lpmydta->wSize); if (i == 0) { lplpmydta[i] = lpmydta; } else { // do a binary insert iMin = 0; iMax = i-1; // last index do { iMid = (iMax + iMin) / 2; if (CompareDTA(lpmydta, lplpmydta[iMid], wSort) > 0) iMin = iMid + 1; else iMax = iMid - 1; } while (iMax > iMin); if (iMax < 0) iMax = 0; if (CompareDTA(lpmydta, lplpmydta[iMax], wSort) > 0) iMax++; // insert after this one if (i != iMax) { for (j = i; j > iMax; j--) lplpmydta[j] = lplpmydta[j-1]; } lplpmydta[iMax] = lpmydta; } } } BOOL SetDirFocus( HWND hwndDir ) /* Set the focus to whoever deserves it if not the directory window. Return whether focus needs to be set to directory window. */ { DWORD dwTemp; HWND hwndLB = GetDlgItem(hwndDir, IDCW_LISTBOX); SendMessage (hwndLB,LB_GETTEXT,0,(LPARAM) &dwTemp); if (!dwTemp) { HWND hwndFocus,hwndTree,hwndDrives,hwndParent = GetParent(hwndDir); GetTreeWindows(hwndParent,&hwndTree,NULL,&hwndDrives); if ((hwndFocus = GetTreeFocus(hwndParent)) == hwndDir) SetFocus(hwndTree ? hwndTree : hwndDrives); else SetFocus(hwndFocus); return FALSE; } else return TRUE; }