EXPDIR.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:19k
源码类别:

Windows编程

开发平台:

Visual C++

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