|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /***************************************************************************\ ! 13: * ! 14: * PROGRAM: EXPDIR.C ! 15: * ! 16: * PURPOSE: Directory Listbox expansion/collapse functions ! 17: * ! 18: \***************************************************************************/ ! 19: #define STRICT ! 20: #include <windows.h> ! 21: #include <limits.h> ! 22: #include "globals.h" ! 23: #include "filer.h" ! 24: #include "drvproc.h" ! 25: #include "expdir.h" ! 26: ! 27: extern HANDLE ghModule; ! 28: ! 29: /***************************************************************************\ ! 30: * ! 31: * ExpDir() ! 32: * ! 33: * Thread Function ! 34: * Called when directory is selected (Enter or Double-click). Expands subdirs ! 35: * of selected directory if not expanded, indenting subdirs with a '|'. If ! 36: * already expaneded, deleteds all subdirs from listbox ! 37: * ! 38: * Returns: TRUE if successful, FALSE if error. ! 39: * ! 40: * History: ! 41: * 5/11/93 ! 42: * Created. ! 43: * ! 44: \***************************************************************************/ ! 45: BOOL ExpDir(LPCINFO lpCInfo) ! 46: { ! 47: HANDLE hFile = NULL; // Find file handle ! 48: WIN32_FIND_DATA FileData; // Find file info structure ! 49: ! 50: TCHAR szFileName[DIRECTORY_STRING_SIZE << 1]; // file name buffer ! 51: PTCHAR lpszHold; // Points to actual name in LB string ! 52: ! 53: BOOL fDone = FALSE; // Loop flag for finding files in dir ! 54: ! 55: DWORD dwAttrib; // Holds file attribute flags ! 56: ! 57: LONG lIndex, // Index of selected listbox member ! 58: lDirDepth; ! 59: ! 60: ! 61: if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT) ! 62: == WAIT_TIMEOUT ){ ! 63: ErrorMsg(TEXT("ExpDir: Dir LB Mutex Timeout.")); ! 64: return(0); ! 65: } ! 66: ! 67: // ! 68: // If the LB is empty, we insert the root, unexpanded ! 69: // ! 70: if( !SendMessage( lpCInfo->hDirLB, LB_GETCOUNT, 0, 0) ){ ! 71: ! 72: TCHAR szHold[DIRECTORY_STRING_SIZE << 1]; ! 73: ! 74: szHold[0] = TEXT('+'); ! 75: lstrcpy( &(szHold[1]), lpCInfo->lpDriveInfo->DriveName ); ! 76: ! 77: // ! 78: // Also copy the DriveName to the Caption Bar. ! 79: // ! 80: lstrcpy(lpCInfo->CaptionBarText, lpCInfo->lpDriveInfo->DriveName ); ! 81: ! 82: SendMessage(lpCInfo->hDirLB, LB_ADDSTRING, 0, ! 83: (LPARAM)szHold ); ! 84: ! 85: ReleaseMutex( lpCInfo->hDirMutex ); ! 86: return(1); ! 87: } ! 88: ! 89: // ! 90: // Retrieve index of selected (careted) directory. ! 91: // ! 92: lIndex = SendMessage( lpCInfo->hDirLB, LB_GETCARETINDEX, ! 93: (WPARAM)NULL, (LPARAM)NULL ); ! 94: ! 95: if( SendMessage( lpCInfo->hDirLB, LB_GETTEXT, (WPARAM)lIndex, ! 96: (LPARAM)szFileName ) < 0 ){ ! 97: ErrorMsg(TEXT("Expand Directory: Get listbox text failure")); ! 98: ExpDirExit(lpCInfo, hFile); ! 99: return(0); ! 100: } ! 101: ! 102: lDirDepth = GetDirDepth( szFileName, &lpszHold ); ! 103: ! 104: if( lDirDepth == -1 ){ ! 105: ErrorMsg(TEXT(" Expand Directory: GetDirDepth failure")); ! 106: ExpDirExit(lpCInfo, hFile); ! 107: return(0); ! 108: } ! 109: ! 110: // ! 111: // If Directory is already expanded, collapse it, and vice versa. ! 112: // First, change the symbol. ! 113: // ! 114: if( *lpszHold == TEXT('-')) ! 115: *lpszHold = TEXT('+'); ! 116: else ! 117: *lpszHold = TEXT('-'); ! 118: ! 119: // ! 120: // Clear WM_SETREDRAW flag, so changes will not be seen until entire ! 121: // expansion/collapse is complete. Reset flag at end of function ! 122: // ! 123: if( SendMessage(lpCInfo->hDirLB, WM_SETREDRAW, (WPARAM)FALSE, ! 124: (LPARAM)0 ) < 0){ ! 125: ErrorMsg(TEXT("Expand Directory: Clear redraw flag failure")); ! 126: ExpDirExit(lpCInfo, hFile); ! 127: return(0); ! 128: } ! 129: ! 130: // ! 131: // Delete old dir string, insert new, and reset the selection ! 132: // ! 133: if( SendMessage(lpCInfo->hDirLB, LB_DELETESTRING, (WPARAM)lIndex, ! 134: (LPARAM)0 ) < 0){ ! 135: ErrorMsg(TEXT("Expand Directory: Delete dir string failure")); ! 136: ExpDirExit(lpCInfo, hFile); ! 137: return(0); ! 138: } ! 139: if( SendMessage(lpCInfo->hDirLB, LB_INSERTSTRING, (WPARAM)lIndex, ! 140: (LPARAM)szFileName ) < 0){ ! 141: ErrorMsg(TEXT("Expand Directory: Insert dir string failure")); ! 142: ExpDirExit(lpCInfo, hFile); ! 143: return(0); ! 144: } ! 145: if( SendMessage(lpCInfo->hDirLB, LB_SETCURSEL, (WPARAM)lIndex, ! 146: (LPARAM)0 ) < 0){ ! 147: ErrorMsg(TEXT("Expand Directory: Insert dir string failure")); ! 148: ExpDirExit(lpCInfo, hFile); ! 149: return(0); ! 150: } ! 151: ! 152: // ! 153: // The symbol has been changed, now collapse if needed, then reset ! 154: // redraw flag, leave critical section, and exit. ! 155: // ! 156: if( *lpszHold == TEXT('+') ){ ! 157: CollapseDir( lpCInfo, lIndex, lDirDepth); ! 158: ExpDirExit(lpCInfo, hFile); ! 159: return(1); ! 160: } ! 161: ! 162: // ! 163: // If we're here, directory needs to be expanded. ! 164: // Enumerate subdirectories beneath the dir entry in the listbox. ! 165: // ! 166: // First, Get the full path of the directory (in szFileName) ! 167: // ! 168: if( !ConstructDirName(lpCInfo, lIndex, szFileName) ){ ! 169: ErrorMsg(TEXT("Expand Directory: ConstructDirName failure")); ! 170: ExpDirExit(lpCInfo, hFile); ! 171: return(0); ! 172: } ! 173: ! 174: // ! 175: // Check to see if there is a terminating backslash ! 176: // Then append a '*' as a wildcard for FindFirstFile. ! 177: // ! 178: lpszHold = TStrChr(szFileName, TEXT('\0')); ! 179: ! 180: lpszHold--; ! 181: if( *lpszHold != TEXT('\\') ){ ! 182: lpszHold++; ! 183: *lpszHold = TEXT('\\'); ! 184: } ! 185: ! 186: lpszHold++; ! 187: lstrcpy( lpszHold, TEXT("*")); ! 188: ! 189: // ! 190: // Start a search on all the files within the directory ! 191: // ! 192: hFile = FindFirstFile( szFileName, &FileData ); ! 193: if( hFile == INVALID_HANDLE_VALUE ){ ! 194: ErrorMsg(TEXT("Expand Directory: FindFirstFile failure.")); ! 195: ExpDirExit(lpCInfo, hFile); ! 196: return(0); ! 197: } ! 198: ! 199: // ! 200: // Walk all the files in the directory. ! 201: // ! 202: while( !fDone ){ ! 203: ! 204: // ! 205: // Check to see if the thread has been requested to kill itself. ! 206: // This code does not clear the suicide flag for synchronization ! 207: // reasons - it is left to the calling code. ! 208: // ! 209: if( lpCInfo->fSuicide ){ ! 210: ErrorMsg(TEXT("Expand Directory: killing thread per request.")); ! 211: ExpDirExit(lpCInfo, hFile); ! 212: ! 213: // ! 214: // Post an MM_REFRESH Message if the user has re-collapsed the ! 215: // Dir LB. ! 216: // ! 217: if( !lpCInfo->fDirExpand ) ! 218: if( !PostMessage(lpCInfo->hwnd, WM_COMMAND, MM_REFRESH, ! 219: (LPARAM)0) ) ! 220: ErrorMsg(TEXT("ExpDir: MM_REFRESH call failure.")); ! 221: ! 222: // ! 223: // We must return failure (0) here, so if FullExpand is calling, ! 224: // it will terminate. ! 225: // ! 226: return(0); ! 227: } ! 228: ! 229: // ! 230: // Append filename to path, and get attributes ! 231: // ! 232: lstrcpy(lpszHold, FileData.cFileName); ! 233: dwAttrib = GetFileAttributes( szFileName ); ! 234: ! 235: // ! 236: // Check if file is a directory. If not, or if '.' or '..', fall ! 237: // through. If so, add it to the directory listbox. ! 238: // ! 239: if( dwAttrib & FILE_ATTRIBUTE_DIRECTORY ) ! 240: if( lstrcmp( FileData.cFileName,TEXT(".") ) ) ! 241: if( lstrcmp( FileData.cFileName,TEXT("..") ) ){ ! 242: TCHAR szLBEntry[DIRECTORY_STRING_SIZE << 1]; ! 243: ! 244: ConstructLBEntry(lDirDepth, FileData.cFileName, szLBEntry); ! 245: // ! 246: // Increment index in order to add subdir after ! 247: // dirs just inserted. ! 248: // ! 249: if( SendMessage(lpCInfo->hDirLB, LB_INSERTSTRING, ! 250: (WPARAM)++lIndex, ! 251: (LPARAM)szLBEntry) < 0){ ! 252: ErrorMsg(TEXT("Expand Directory: error inserting string.")); ! 253: ExpDirExit(lpCInfo, hFile); ! 254: return(0); ! 255: } ! 256: } ! 257: ! 258: fDone = !FindNextFile( hFile, &FileData ); ! 259: } ! 260: ! 261: ExpDirExit(lpCInfo, hFile); ! 262: return(1); ! 263: } ! 264: ! 265: ! 266: /***************************************************************************\ ! 267: * ! 268: * ExpDirExit() ! 269: * ! 270: * Performs clean-up operations for ExpDir, closing handles, etc. ! 271: * ! 272: * History: ! 273: * 5/28/93 ! 274: * Created. ! 275: * ! 276: \***************************************************************************/ ! 277: void ExpDirExit(LPCINFO lpCInfo, HANDLE hFile) ! 278: { ! 279: ! 280: // ! 281: // Reset redraw flag. Post this message, to avoid synchro problems ! 282: // ! 283: if( PostMessage(lpCInfo->hDirLB, WM_SETREDRAW, (WPARAM)TRUE, ! 284: (LPARAM)0 ) < 0) ! 285: ErrorMsg(TEXT("Expand Directory: Clear redraw flag failure")); ! 286: ! 287: // ! 288: // Close FindFirstFile session ! 289: // ! 290: if( hFile != NULL ) ! 291: FindClose(hFile); ! 292: ! 293: // ! 294: // Release Dir LB Mutex ! 295: // ! 296: ReleaseMutex( lpCInfo->hDirMutex); ! 297: } ! 298: ! 299: ! 300: /***************************************************************************\ ! 301: * ! 302: * ConstructDirName() ! 303: * ! 304: * Builds the fully qualified path of the current directory, by walking back ! 305: * through the Dir LB tree. ! 306: * ! 307: * Returns: TRUE if successful, FALSE if error. ! 308: * Returns the full directory path of given directory name in ! 309: * lpszDirName. ! 310: * ! 311: * History: ! 312: * 5/11/93 ! 313: * Created. ! 314: * ! 315: \***************************************************************************/ ! 316: BOOL ConstructDirName(LPCINFO lpCInfo, LONG lIndex, LPTSTR lpszDirName) ! 317: { ! 318: LONG lDirDepth, // Depth of selected directory ! 319: lSeekDepth = LONG_MAX; ! 320: ! 321: TCHAR szFileName[DIRECTORY_STRING_SIZE << 1]; // file buffer ! 322: LPTSTR lpszInfoPtr, ! 323: lpszHold; ! 324: ! 325: // ! 326: // Clear the directory name buffer ! 327: // ! 328: *lpszDirName = TEXT('\0'); ! 329: ! 330: // ! 331: // Walk up the entries in the listbox, constructing the full path from ! 332: // the bottom up. ! 333: // ! 334: while( lIndex >= 0 ){ ! 335: ! 336: // ! 337: // Get listbox text, and compute the depth of the directory ! 338: // ! 339: if( SendMessage( lpCInfo->hDirLB, LB_GETTEXT, (WPARAM)lIndex, ! 340: (LPARAM)szFileName ) < 0 ){ ! 341: ErrorMsg(TEXT(" Expand Directory: Get listbox text failure")); ! 342: return(0); ! 343: } ! 344: ! 345: lDirDepth = GetDirDepth(szFileName, &lpszInfoPtr); ! 346: if( lDirDepth == -1){ ! 347: ErrorMsg(TEXT("ConstructDirName: GetDirDepth failed")); ! 348: return(0); ! 349: } ! 350: ! 351: // ! 352: // If we've reached the next level up, add to the directory name ! 353: // ! 354: if( lDirDepth < lSeekDepth ){ ! 355: lSeekDepth = lDirDepth; ! 356: ! 357: // check if we will exceed the size of our buffer ! 358: if( lstrlen(lpszInfoPtr) + lstrlen(lpszDirName) > ! 359: (DIRECTORY_STRING_SIZE << 1) ){ ! 360: ErrorMsg(TEXT("ConstructDirName: Exceeded Directory Size limit")); ! 361: return(0); ! 362: } ! 363: ! 364: // Find the end of the directory name ! 365: lpszHold = TStrChr(lpszInfoPtr, TEXT('\0')); ! 366: ! 367: // If we're not at the root, add a '\' ! 368: if( lIndex && (*lpszDirName != TEXT('\0')) ) ! 369: *lpszHold++ = TEXT('\\'); ! 370: ! 371: // Append the heretofore computed path to the end of the dir name ! 372: lstrcpy( lpszHold, lpszDirName); ! 373: // Copy the whole path so far back into the final buffer ! 374: lstrcpy( lpszDirName, ++lpszInfoPtr); ! 375: } ! 376: ! 377: // If the first level dir has been added, jump to the root, ! 378: // else go up to the previous entry in the listbox. ! 379: if( lDirDepth == 1 ) ! 380: lIndex = 0; ! 381: else ! 382: lIndex--; ! 383: } ! 384: ! 385: return(TRUE); ! 386: } ! 387: ! 388: ! 389: /***************************************************************************\ ! 390: * ! 391: * GetDirDepth() ! 392: * ! 393: * Returns: -1 if error ! 394: * otherwise, the depth of the directory (i.e. root is depth 0, ! 395: * c:\foo is depth 1, etc. This is computed in perhaps not the ! 396: * most efficient way, by counting the '|'s proceeding the name. ! 397: * ! 398: * This function also returns in lpszDirName a pointer to the ! 399: * end of the preceeding '|' characters within the given listbox str. ! 400: * If the function fails, this pointer value is undefined. ! 401: * ! 402: * The left shifted index is to skip the tab characters. See ConstructLBEntry(). ! 403: * ! 404: * History: ! 405: * 5/7/93 ! 406: * Created. ! 407: * ! 408: \***************************************************************************/ ! 409: LONG GetDirDepth(LPTSTR lpszLBString, LPTSTR *lpszDirName) ! 410: { ! 411: TCHAR cBar; ! 412: LONG lCount = 0; ! 413: ! 414: do{ ! 415: ! 416: cBar = lpszLBString[lCount << 1]; ! 417: ! 418: if( cBar == TEXT('|') ) ! 419: lCount++; ! 420: else ! 421: if( cBar != TEXT('+') && cBar != TEXT('-') ){ ! 422: ErrorMsg(TEXT("GetDirDepth: string parse error")); ! 423: return(-1); ! 424: } ! 425: ! 426: }while( cBar != TEXT('+') && cBar != TEXT('-') ); ! 427: ! 428: *lpszDirName = &(lpszLBString[lCount << 1]); ! 429: ! 430: return( lCount ); ! 431: } ! 432: ! 433: ! 434: /***************************************************************************\ ! 435: * ! 436: * CollapseDir() ! 437: * ! 438: * If directory is expanded, collapses it, by deleteing any subdirectory ! 439: * entries below it. ! 440: * ! 441: * Returns: TRUE if successful, FALSE if error ! 442: * ! 443: * History: ! 444: * 5/11/93 ! 445: * Created. ! 446: * ! 447: \***************************************************************************/ ! 448: BOOL CollapseDir(LPCINFO lpCInfo, LONG lIndex, LONG lDirDepth) ! 449: { ! 450: TCHAR szFileName[DIRECTORY_STRING_SIZE << 1]; // file name buffer ! 451: LPTSTR lpszNamePtr; ! 452: ! 453: LONG lDepthHold; ! 454: ! 455: ! 456: // ! 457: // Remove any following LB entries until we return to same depth ! 458: // ! 459: do{ ! 460: ! 461: if( SendMessage( lpCInfo->hDirLB, LB_GETTEXT, (WPARAM)lIndex + 1, ! 462: (LPARAM)szFileName ) < 0 ){ ! 463: ErrorMsg(TEXT(" Expand Directory: Get listbox text failure")); ! 464: return(0); ! 465: } ! 466: ! 467: lDepthHold = GetDirDepth( szFileName, &lpszNamePtr); ! 468: if( lDirDepth == -1 ){ ! 469: ErrorMsg(TEXT(" Expand Directory: GetDirDepth failure")); ! 470: return(0); ! 471: } ! 472: ! 473: if( lDirDepth < lDepthHold ) ! 474: if( SendMessage( lpCInfo->hDirLB, LB_DELETESTRING, (WPARAM)lIndex + 1, ! 475: (LPARAM)0 ) < 0 ){ ! 476: ErrorMsg(TEXT(" Expand Directory: Delete String failure")); ! 477: return(0); ! 478: } ! 479: ! 480: }while( lDirDepth < lDepthHold ); ! 481: ! 482: return(1); ! 483: } ! 484: ! 485: ! 486: /***************************************************************************\ ! 487: * ! 488: * ConstructLBEntry() ! 489: * ! 490: * Given the parent's directory depth, and the subdirectory name, inserts ! 491: * '|'s equal to the depth+1 of the parent (plus tab character), and an ! 492: * unexpanded '+' directory marker, then the name of the subdirectory. ! 493: * ! 494: * The left shifted index is to skip the tab characters. ! 495: * ! 496: * Returns: void. the completed listbox entry is returned in szLBEntry. ! 497: * ! 498: * History: ! 499: * 5/14/93 ! 500: * Created. ! 501: * ! 502: \***************************************************************************/ ! 503: void ConstructLBEntry(LONG lDirDepth, LPTSTR szFileName, LPTSTR szLBEntry) ! 504: { ! 505: int i; ! 506: ! 507: for(i = 0; i <= lDirDepth; i++){ ! 508: szLBEntry[i << 1] = TEXT('|'); ! 509: szLBEntry[(i << 1) + 1] = 9; ! 510: } ! 511: ! 512: szLBEntry[i << 1] = TEXT('+'); ! 513: szLBEntry[(i << 1) + 1] = TEXT('\0'); ! 514: ! 515: lstrcat(szLBEntry, szFileName); ! 516: } ! 517: ! 518: ! 519: /***************************************************************************\ ! 520: * ! 521: * FullExpand() ! 522: * ! 523: * From the unexpanded root, walks down directory LB, expanding each directory ! 524: * until it reaches the end of the tree. ! 525: * ! 526: * Returns: void ! 527: * ! 528: * History: ! 529: * 5/20/93 ! 530: * Created. ! 531: * ! 532: \***************************************************************************/ ! 533: BOOL FullExpand(LPCINFO lpCInfo) ! 534: { ! 535: LONG lIndex = 0; ! 536: ! 537: if( WaitForSingleObject( lpCInfo->hDirMutex, MUTEX_TIMEOUT) ! 538: == WAIT_TIMEOUT ){ ! 539: ErrorMsg(TEXT("FullExpand: Dir LB Mutex Timeout.")); ! 540: return(0); ! 541: } ! 542: ! 543: while( SendMessage(lpCInfo->hDirLB, LB_SETCURSEL, ! 544: (WPARAM)lIndex, ! 545: (LPARAM)0) != LB_ERR ){ ! 546: if( !ExpDir( lpCInfo ) ){ ! 547: ErrorMsg(TEXT("Full Expand: ExpDir failure.")); ! 548: ReleaseMutex( lpCInfo->hDirMutex ); ! 549: ! 550: // This is in case the ExpDir failed because a change drive ! 551: // command caused a kill. ! 552: if( !PostMessage(lpCInfo->hwnd, WM_COMMAND, MM_REFRESH, ! 553: (LPARAM)0) ) ! 554: ErrorMsg(TEXT("ExpDir: MM_REFRESH call failure.")); ! 555: return(0); ! 556: } ! 557: ! 558: lIndex++; ! 559: } ! 560: ! 561: // Set selection in listboxes to first item. ! 562: if( SendMessage(lpCInfo->hDirLB, LB_SETCURSEL, ! 563: (WPARAM)0, ! 564: (LPARAM)0) == LB_ERR ){ ! 565: ErrorMsg(TEXT("Full Expand: Dir LB Set Selection Error")); ! 566: ReleaseMutex( lpCInfo->hDirMutex ); ! 567: return(0); ! 568: } ! 569: ! 570: ReleaseMutex( lpCInfo->hDirMutex ); ! 571: return(1); ! 572: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.