|
|
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.