home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / SOUR / CGAZ5N2.ZIP / FF.C < prev    next >
C/C++ Source or Header  |  1990-12-10  |  27KB  |  756 lines

  1. /************ Listing 1 ******************  FF.C  ********************
  2. ** Author:      John Rex
  3. ** Date:        November, 1990
  4. ** Compiler:    MSC 6.0
  5. ** Environment: Windows 3.0
  6. ** Switches:    DEBUG - if defined, status messages are sent to a file
  7. ** Compile commands:
  8. **     rc -r ff.rc
  9. **     cl -qc -c -W2 -AS -Gsw -Oils -Zpe ff.c
  10. **     link /NOD ff.obj,, nul.map, libw.lib slibcew.lib, ff.def
  11. **     rc ff.res
  12. **
  13. ** Object code may be used freely.
  14. ** Source code may be used freely if author/publication are acknowledged
  15. *********************************************************************/
  16.  
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include <dos.h>
  23. #include "ffdlg.h"
  24.  
  25. #if defined(DEBUG)
  26.  
  27. FILE *debugfile;
  28. #define SHOW(x) x
  29. #define SHOWF0(f)          {fprintf(debugfile,f);          flushall();}
  30. #define SHOWF1(f,a1)       {fprintf(debugfile,f,a1);       flushall();}
  31. #define SHOWF2(f,a1,a2)    {fprintf(debugfile,f,a1,a2);    flushall();}
  32. #define SHOWF3(f,a1,a2,a3) {fprintf(debugfile,f,a1,a2,a3); flushall();}
  33.  
  34. #else
  35. #define SHOW(x)
  36. #define SHOWF0(f)
  37. #define SHOWF1(f,a1)
  38. #define SHOWF2(f,a1,a2)
  39. #define SHOWF3(f,a1,a2,a3)
  40. #endif
  41.  
  42. /***   common data   ***/
  43. #define FILEMAX 12
  44. #define PATHMAX 80
  45.  
  46. /* some handles */
  47. FARPROC fpFileListProc;
  48. HANDLE hAppInstance;
  49. HWND CurrentDialogBox;
  50.  
  51. HCURSOR hHourGlass; /* hour glass cursor */
  52. int dotcount;       /* for dancing dot display while searching */
  53. int filecount;      /* total number of files found */
  54.  
  55. /* access to the icon for the main window */
  56. HICON HIcon;
  57.  
  58. /* The WinList structure is used to keep a linked list of all the dialog
  59.  * boxes. The handle of the main dialog box (SearchDialogProc) is kept in
  60.  * WinListHead.hWin, while the handles to all the secondary search result
  61.  * boxes (FileListProc) are kept in the body of the linked list. */
  62.  
  63. struct WinList {
  64.     HWND hWin;
  65.     struct WinList *next;
  66. } WinListHead;
  67.  
  68. /* state variable used during file searching */
  69. enum tagSearchState { Idle, Searching, Stop } SearchState;
  70.  
  71. /*** end common data ***/
  72.  
  73. #pragma page()
  74. #pragma subtitle("Memory Routines")
  75. /* out of memory error box */
  76. void NoMemory(HWND hDlg)
  77. {
  78.     MessageBox(hDlg, (LPSTR) "Out of memory!", 
  79.         (LPSTR) "FileFind", MB_SYSTEMMODAL | MB_OK | MB_ICONEXCLAMATION);
  80. }
  81.  
  82. void *mymalloc(HWND hDlg, size_t size)
  83. {
  84.     void *p;
  85.     p = malloc(size);
  86.     if (p == NULL) {
  87.         NoMemory(hDlg);
  88.         SHOWF0("Mymalloc: out of memory\n");
  89.     }
  90.     return (p);
  91. }
  92.  
  93. /* ffwalk:  looks in directory specified by ppath for files matching
  94.  *          spec.  Recursively descends tree as it finds new
  95.  *          subdirectories. */
  96. int ffwalk(char *ppath, char *spec, HWND hDlg)
  97. {
  98.     static struct find_t fileinfo;
  99.     char buffer[PATHMAX], *end_at;
  100.     unsigned found_one, errorcode;
  101.     int hour, am_pm, retval, index;
  102.     struct dirlist {
  103.         char *dirname;
  104.         struct dirlist *next;
  105.     } header, *temp, *last;
  106.     MSG Msg;
  107.  
  108.     /* First, check for messages directed to our dialog box. The return
  109.      * value from IsDialogMessage is ignored because we know that the
  110.      * message must belong to our dialog box. */
  111.  
  112.     while (PeekMessage((LPMSG) &Msg, hDlg, 0, 0, PM_REMOVE))
  113.         IsDialogMessage(hDlg, (LPMSG) &Msg);
  114.  
  115.     if (SearchState == Stop)  /* user wants out! */
  116.     {
  117.         if (SendDlgItemMessage(hDlg, IDC_FILELIST, LB_INSERTSTRING, 
  118.             -1, (LONG) (LPSTR) "  --Search Stopped--") < LB_OKAY)
  119.             NoMemory(hDlg);
  120.         return 1;
  121.     }
  122.  
  123.     /* create a rotating dot display as we cycle through directories */
  124.     strcpy(buffer, "    ");
  125.     buffer[dotcount++] = '*';
  126.     if (dotcount > 3) 
  127.         dotcount = 0;
  128.     SendDlgItemMessage(hDlg, IDC_DOTS, WM_SETTEXT, 0, (LONG) (LPSTR) buffer);
  129.  
  130.     /* save end of ppath so we can clip when needed */
  131.     end_at = ppath + strlen(ppath);
  132.  
  133.     /* start by searching for matching files */
  134.     found_one = 0;
  135.     strcat(ppath, spec);
  136.     SHOWF1("ffwalk: searching for %s\n", ppath);
  137.     if ((errorcode = _dos_findfirst 
  138.             (ppath, _A_NORMAL | _A_RDONLY | _A_ARCH, &fileinfo)) == 0) 
  139.     {
  140.         *end_at = '\0';
  141.         do 
  142.         {
  143.             filecount++;
  144.             /* output subdirectory name, if needed */
  145.             if (found_one++ == 0) 
  146.             {
  147.                 if (filecount > 1) 
  148.                 {                /* output a blank line first */
  149.                     if ( SendDlgItemMessage(hDlg, 
  150.                          IDC_FILELIST, LB_INSERTSTRING, -1, 
  151.                          (LONG) (LPSTR) "") < LB_OKAY) 
  152.                     {
  153.                         NoMemory(hDlg);
  154.                         return 1;
  155.                     }
  156.                 }
  157.                 if (SendDlgItemMessage(hDlg, IDC_FILELIST, 
  158.                     LB_INSERTSTRING, -1, (LONG) (LPSTR) ppath) < LB_OKAY) 
  159.                 {
  160.                     NoMemory(hDlg);
  161.                     return 1;
  162.                 }
  163.             }
  164.  
  165.             /* and now, output filename with size, date, time attached */
  166.  
  167.             hour = (fileinfo.wr_time&0xF800) >> 11;
  168.             am_pm = 'a';
  169.             if (hour > 12) 
  170.             {
  171.                 hour -= 12;
  172.                 am_pm = 'p';
  173.             }
  174.             sprintf(buffer, "  %s\t%7ld\t%2u/%02u/%02u\t%2u:%02u%c",
  175.                 fileinfo.name, fileinfo.size,          /* name and size */
  176.                 (fileinfo.wr_date & 0x01E0) >> 5,      /* month */
  177.                 fileinfo.wr_date & 0x001F,             /* date */
  178.                 ((fileinfo.wr_date & 0xFE00) >> 9)+80, /* year */
  179.                 hour,                                  /* hour */
  180.                 (fileinfo.wr_time&0x07E0) >> 5,        /* minutes */
  181.                 am_pm);                                /* am/pm */
  182.             strlwr(buffer);
  183.             if ((index = SendDlgItemMessage(hDlg, IDC_FILELIST, 
  184.                 LB_INSERTSTRING, -1, (LONG) (LPSTR) buffer)) < LB_OKAY) 
  185.             {
  186.                 NoMemory(hDlg);
  187.                 return 1;
  188.             }
  189.             /* Check to see if we should force an update of the window.
  190.              * The list of names will update itself, but the scroll bars
  191.              * that get added will not be completed unless we force it.
  192.              * There are 13 rows in the box (0-12), so we force updates
  193.              * when index is in the range 13 thru 16 */
  194.  
  195.             if (index >= 13 && index <= 16)
  196.                 UpdateWindow(hDlg);
  197.         } while (_dos_findnext(&fileinfo) == 0);
  198.     }
  199.     if (errorcode) 
  200.     {
  201.         SHOWF1("Error code was %#x\n", errorcode);
  202.         if (errorcode != 0x12) /* exit if anything but "No more files" */
  203.             return 1;
  204.     }
  205.  
  206.     /* Look for subdirectories to search. */
  207.     *end_at = '\0';
  208.     strcat(ppath, "*.*");
  209.     header.dirname = NULL;
  210.     header.next = NULL;
  211.     retval = 0;
  212.  
  213.     /* first, find all the names */
  214.     if (_dos_findfirst(ppath, _A_SUBDIR, &fileinfo) == 0) 
  215.     {
  216.         *end_at = '\0';
  217.         do 
  218.         {
  219.             if (fileinfo.attrib & _A_SUBDIR) 
  220.             {
  221.                 if (*fileinfo.name != '.')   /* don't acccept . or .. */
  222.                 {
  223.                     strcpy(buffer, ppath);
  224.                     strcat(buffer, fileinfo.name);
  225.                     strcat(buffer, "\\");
  226.                     if ((temp = mymalloc(hDlg, sizeof(struct dirlist))) 
  227.                                                 == NULL) 
  228.                     {
  229.                         retval = 1;
  230.                         break;
  231.                     }
  232.                     if ((temp -> dirname = mymalloc(hDlg, 
  233.                             strlen(buffer)+1+FILEMAX)) == NULL) 
  234.                     {
  235.                         retval = 1;
  236.                         break;
  237.                     }
  238.                     strcpy(temp->dirname, buffer);
  239.                     temp->next = header.next;
  240.                     header.next = temp;
  241.                 }
  242.             }
  243.             *end_at = '\0';
  244.         } while (_dos_findnext(&fileinfo) == 0);
  245.     }
  246.  
  247.     /* Search subdirectories.  Clean up linked list as we go. */
  248.     for (temp = header.next; temp; ) 
  249.     {
  250.         if (!retval) /* if we've had a problem, stop searching but do
  251.                        finish cleaning up linked list */
  252.             retval = ffwalk(temp->dirname, spec, hDlg);
  253.         last = temp;
  254.         temp = temp->next;
  255.         free (last->dirname);
  256.         free (last);
  257.     }
  258.  
  259.     return (retval);
  260. }
  261.  
  262. /* Draw icon for minimized windows */
  263. BOOL ShowOurIcon(HWND hDlg)
  264. {
  265.     HDC HDevContext;
  266.     PAINTSTRUCT ps;
  267.     RECT rcWindow;
  268.     HBRUSH hBrush;
  269.  
  270.     if (IsIconic(hDlg)) 
  271.     {
  272.         /* get device context and size of display area */
  273.         HDevContext = BeginPaint(hDlg, &ps);
  274.         GetClientRect(hDlg, &rcWindow);
  275.  
  276.         /* make background = desktop */
  277.         hBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
  278.         FillRect(HDevContext, &rcWindow, hBrush);
  279.         DeleteObject(hBrush);
  280.  
  281.         /* center icon in client window area. rcWindow.top and .left
  282.          * will always be zero, so we leave them out of the
  283.          * calculation. */
  284.  
  285.         DrawIcon (HDevContext,
  286.                   (rcWindow.right  - GetSystemMetrics(SM_CXICON))/2,
  287.                   (rcWindow.bottom - GetSystemMetrics(SM_CYICON))/2,
  288.                   HIcon);
  289.         EndPaint(hDlg, &ps);
  290.         return (TRUE);
  291.     }
  292.     return (FALSE);
  293. }
  294.  
  295. /* "About" dialog box procedure */
  296. BOOL FAR PASCAL
  297.     AboutDlgProc (HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  298. {
  299.     switch (message) 
  300.     {
  301.       case WM_ACTIVATE:
  302.         if (wParam)
  303.             CurrentDialogBox = NULL;
  304.         return (FALSE); /* continue with default processing */
  305.  
  306.     case WM_INITDIALOG:
  307.         return (TRUE);
  308.  
  309.     case WM_COMMAND:
  310.         if (wParam == IDOK || wParam == IDCANCEL) 
  311.         {
  312.             EndDialog(hDlg, TRUE);
  313.             return (TRUE);
  314.         }
  315.         break;
  316.     }
  317.     return (FALSE);
  318. }
  319.  
  320. /* File List dialog box procedure */
  321. BOOL FAR PASCAL
  322.     FileListProc (HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  323. {
  324.     switch (message) 
  325.     {
  326.       case WM_ACTIVATE:
  327.         if (wParam)
  328.             CurrentDialogBox = hDlg;
  329.         return (FALSE); /* continue with default processing */
  330.  
  331.       case WM_PAINT:
  332.         return (ShowOurIcon(hDlg));
  333.  
  334.       case WM_INITDIALOG:
  335.         {
  336.             int xSysDim, ySysDim, xDim, yDim, yHigh, yCaption;
  337.             RECT wRect;
  338.             struct WinList *t;
  339.  
  340.             /* place new window */
  341.             yCaption = GetSystemMetrics(SM_CYCAPTION);
  342.             xSysDim = GetSystemMetrics(SM_CXSCREEN);
  343.             ySysDim = GetSystemMetrics(SM_CYSCREEN);
  344.             GetWindowRect(hDlg, (LPRECT) &wRect);
  345.             xDim = wRect.right - wRect.left;
  346.             yDim = wRect.bottom - wRect.top;
  347.  
  348.             /* now, look at other active search windows and try to
  349.                put ourselves lower than they are. Set the starting point
  350.                so that the first window ends up at ySysDim*2/5 */
  351.  
  352.             yHigh = (ySysDim*2)/5 - yCaption;
  353.             for (t=WinListHead.next; t; t=t->next) 
  354.             {
  355.                 if (t->hWin != hDlg && !IsIconic(t->hWin)) 
  356.                 {
  357.                     GetWindowRect(t->hWin, (LPRECT) &wRect);
  358.                     yHigh = max(yHigh, wRect.top);
  359.                 }
  360.             }
  361.             yHigh += yCaption;          /* shift down by height of caption */
  362.             if (yHigh + yDim > ySysDim) /* make sure we're not off screen */
  363.                 yHigh = ySysDim - yDim;
  364.  
  365.             MoveWindow(hDlg,         /* window to move */
  366.                 (xSysDim - xDim)/2,  /* new upper left x */
  367.                 yHigh,               /* new upper left y */
  368.                 xDim,                /* window height (unchanged) */
  369.                 yDim,                /* window width (unchanged) */
  370.                 TRUE);               /* please repaint */
  371.         }
  372.         return (TRUE);
  373.  
  374.       case WM_LBUTTONDOWN:
  375.         /* Did user clicks mouse over "Stop" button during a search? */
  376.         if (SearchState == Searching) 
  377.         {
  378.             POINT pMouse;
  379.             SHOWF3
  380.             ("FileListProc: window %#x got left mouse button at (%u, %u)\n", 
  381.                                 hDlg, LOWORD(lParam), HIWORD(lParam));
  382.  
  383.             /* The mouse message returns coordinates relative to hDlg--what
  384.              * we need to know is whether these coordinates correspond to 
  385.              * the location of the "Stop/Close" button/window... */
  386.  
  387.             pMouse.x = LOWORD(lParam);
  388.             pMouse.y = HIWORD(lParam);
  389.             if ( ChildWindowFromPoint(hDlg, pMouse) == GetDlgItem(hDlg, 2)) 
  390.             {
  391.                 SearchState = Stop;
  392.                 return (TRUE);
  393.             }
  394.         }
  395.         /* otherwise, let Windows handle this */
  396.         return (FALSE);
  397.  
  398.       case WM_COMMAND:
  399.         switch (wParam) 
  400.         {
  401.  
  402.           case IDOK:
  403.           case IDCANCEL:
  404.             if (SearchState == Searching) /* Stop ongoing search! */
  405.                 SearchState = Stop;
  406.             else  /* otherwise, close the dialog box */
  407.             {
  408.                 struct WinList *t1, *t2;
  409.  
  410.                 DestroyWindow(hDlg);    /* Remove dialog box. */
  411.  
  412.                 t1 = &WinListHead;  /* and remove handle from list */
  413.                 t2 = WinListHead.next;
  414.                 for (; t2; t1=t2, t2=t2->next) 
  415.                 {
  416.                    if (t2->hWin == hDlg) 
  417.                    {
  418.                     SHOWF2
  419.                     ("FileListProc: Deleting handle %#x in structure at %p\n", 
  420.                                         t2->hWin, t2);
  421.                         t1->next = t2->next;
  422.                         free (t2);
  423.                         break;
  424.                     }
  425.                 }
  426.             }
  427.             return (TRUE);
  428.  
  429.           default:
  430.             return (FALSE); /* Dialog message NOT processed. */
  431.         }
  432.  
  433.       default:
  434.         return (FALSE);
  435.     }
  436. }
  437.  
  438. /* Search control dialog box procedure */
  439. BOOL FAR PASCAL
  440.     SearchDlgProc (HWND hDlg, unsigned message, WORD wParam, LONG lParam)
  441. {
  442.     switch (message) 
  443.     {
  444.       case WM_ACTIVATE:
  445.         if (wParam)
  446.             CurrentDialogBox = hDlg;
  447.         return (FALSE); /* continue with default processing */
  448.  
  449.       case WM_PAINT:
  450.         return (ShowOurIcon(hDlg));
  451.  
  452.       case WM_INITDIALOG:
  453.         {
  454.             int xSysDim, ySysDim, xDim, yDim;
  455.             int DriveCount, i, drive;
  456.             RECT wRect;
  457.             HWND hDirList;
  458.             char buffer[10];
  459.  
  460.             /* move main window to upper, mid screen */
  461.             xSysDim = GetSystemMetrics(SM_CXSCREEN);
  462.             ySysDim = GetSystemMetrics(SM_CYSCREEN);
  463.             GetWindowRect(hDlg, (LPRECT) &wRect);
  464.             xDim = wRect.right - wRect.left;
  465.             yDim = wRect.bottom - wRect.top;
  466.             MoveWindow(hDlg,         /* window to move */
  467.                 (xSysDim - xDim)/2,  /* new upper left x */
  468.                 (ySysDim - yDim)/3,  /* new upper left y */
  469.                 xDim,                /* window height (unchanged) */
  470.                 yDim,                /* window width (unchanged) */
  471.                 TRUE);               /* please repaint */
  472.  
  473.  
  474.             /* fill the drives box with available drives */
  475.             /* the 0x4000 | 0x8000 flag asks for drives ONLY */
  476.             DlgDirList(hDlg, "*.*", IDC_DIRLIST, 0, 0x4000 | 0x8000);
  477.  
  478.             /* Select all fixed drives. Go through the listbox backwards
  479.                so that the selection box ends up on the first selected
  480.                drive rather than the last one. */
  481.  
  482.             hDirList = GetDlgItem(hDlg, IDC_DIRLIST);
  483.             DriveCount = SendMessage(hDirList, LB_GETCOUNT, 0, (LONG) 0);
  484.             for (i=DriveCount-1; i>=0 ; i--) 
  485.             {
  486.                 SendMessage(hDirList, LB_GETTEXT, i, (LONG) (LPSTR) buffer);
  487.                 drive = tolower(buffer[2]) - 'a';
  488.                 if (GetDriveType(drive) == DRIVE_FIXED)
  489.                     SendMessage(hDirList, LB_SETSEL, TRUE, (LONG) i);
  490.             }
  491.  
  492.             /* set default file spec to "", limit it to FILEMAX
  493.                characters, and give it the focus */
  494.             SetDlgItemText(hDlg, IDC_FILESPEC, (LPSTR) "");
  495.             SendDlgItemMessage(hDlg, IDC_FILESPEC, EM_LIMITTEXT, 
  496.                                      FILEMAX, NULL);
  497.             PostMessage(hDlg, WM_NEXTDLGCTL, IDC_FILESPEC, (LONG) 1);
  498.  
  499.             /* and lastly, disable the "search" box */
  500.             EnableWindow(GetDlgItem(hDlg, 1), FALSE);
  501.         }
  502.         return (TRUE);
  503.  
  504.       case WM_COMMAND:
  505.         switch (wParam) 
  506.         {
  507.  
  508.           case IDOK: /* Search! */
  509.             {
  510.                 char buffer[11+FILEMAX]; /* for "FileFind: aabbccddee.xxx"*/
  511.                 char buffer2[4+FILEMAX]; /* for "a:\aabbccddee.xxx" */
  512.                 struct WinList *t;
  513.                 static long TabStops[3] = {4*20, 4*30, 4*40};
  514.                 int DriveCount, i;
  515.                 HWND hDirList, hFileListBox, hFL;
  516.                 HCURSOR hSaveCursor;
  517.  
  518.                 SearchState = Searching;
  519.                 hFL = 0;
  520.                 hFL = CreateDialog(hAppInstance, "FileListBox", NULL, 
  521.                                         fpFileListProc);
  522.                 if (!hFL)  /* Oops! Couldn't create dialog box! */
  523.                 {
  524.                     MessageBox(hDlg, (LPSTR) "Can't open new window!", 
  525.                                 (LPSTR) "FileFind", MB_SYSTEMMODAL 
  526.                                  | MB_OK | MB_ICONEXCLAMATION);
  527.                     SearchState = Idle;
  528.                     return (TRUE);
  529.                 }
  530.                 strcpy(buffer, "FileFind: ");
  531.                 SendDlgItemMessage(hDlg, IDC_FILESPEC, WM_GETTEXT, 
  532.                             FILEMAX+1, (LONG) (LPSTR) buffer + 10);
  533.                 SetWindowText(hFL, (LPSTR) buffer);
  534.                 SendDlgItemMessage(hFL, IDC_FILELIST, LB_SETTABSTOPS, 
  535.                                     3, (LONG) (LPSTR) &TabStops);
  536.  
  537.                 /* put in our list of window handles */
  538.                 if ((t = mymalloc(hDlg, sizeof(struct WinList))) == NULL) 
  539.                 {
  540.                     DestroyWindow(hFL);
  541.                     SearchState = Idle;
  542.                     return (TRUE);
  543.                 }
  544.                 t->hWin = hFL;
  545.                 t->next = WinListHead.next;
  546.                 WinListHead.next = t;
  547.                 SHOWF2
  548.                 ("SearchDlgProc: Adding handle %#x in structure at %p\n", 
  549.                          hFL, t);
  550.  
  551.                 /* Now, fill it up.  Start by changing the cursor
  552.                  * and letting the search results window capture the mouse.*/
  553.  
  554.                 hSaveCursor = SetCursor(hHourGlass);
  555.                 SetCapture(hFL);
  556.  
  557.                 /* move basic pattern to beginning of buffer */
  558.                 strcpy(buffer, buffer+10);
  559.  
  560.                 hDirList = GetDlgItem(hDlg, IDC_DIRLIST);
  561.                 hFileListBox = GetDlgItem(hFL, IDC_FILELIST);
  562.                 DriveCount = SendMessage(hDirList, LB_GETCOUNT, 0, (LONG) 0);
  563.                 filecount = 0;
  564.                 for (i=0; i < DriveCount; i++)
  565.                     /* ask each entry if it is selected */
  566.                     if (SendMessage(hDirList, LB_GETSEL, i, NULL)) 
  567.                     {
  568.                         /* If so, get the name of the drive ... */
  569.                         SendMessage(hDirList, LB_GETTEXT, i, 
  570.                                     (LONG) (LPSTR) buffer2);
  571.                         buffer2[0] = toupper(buffer2[2]);
  572.                         strcpy(buffer2+1, ":\\");
  573.                         /* ... update our status messages ... */
  574.                         SendDlgItemMessage(hFL, IDC_DRIVE, WM_SETTEXT, 0, 
  575.                                             (LONG) (LPSTR) buffer2);
  576.                         SendDlgItemMessage(hFL, IDC_DOTS, WM_SETTEXT, 0, 
  577.                                             (LONG) (LPSTR) "    ");
  578.                         /* ... and search the drive. */
  579.                         if (ffwalk(buffer2, buffer, hFL))
  580.                             break; /* exit loop if error occurs */
  581.                     }
  582.  
  583.                 /* Restore the cursor and mouse */
  584.                 SetCursor(hSaveCursor);
  585.                 ReleaseCapture();
  586.  
  587.                 /* display file count */
  588.                 sprintf(buffer, "%d", filecount);
  589.                 strcpy(buffer2, "Files");
  590.                 if (filecount == 1)
  591.                     buffer2[4] = '\0';
  592.                 SendDlgItemMessage(hFL, IDC_DRIVE, 
  593.                                    WM_SETTEXT, 0, (LONG) (LPSTR) buffer);
  594.                 SendDlgItemMessage(hFL, IDC_DOTS, WM_SETTEXT, 0, 
  595.                                    (LONG) (LPSTR) buffer2);
  596.  
  597.                 if (SendMessage(hFileListBox, LB_GETCOUNT, 0, 0L) == 0)
  598.                     SendMessage(hFileListBox, LB_ADDSTRING, 0, 
  599.                                         (LONG) (LPSTR) "-none-");
  600.  
  601.                 /* select first item in box */
  602.                 SendDlgItemMessage(hDlg, IDC_FILELIST, 
  603.                                          LB_SETCURSEL, 0, NULL);
  604.  
  605.                 /* and finally, change the Stop button to say Close */
  606.                 SendDlgItemMessage(hFL, 2, WM_SETTEXT, 0, 
  607.                                         (LONG) (LPSTR) "&Close");
  608.             }
  609.             SearchState = Idle;
  610.             return (TRUE);
  611.  
  612.           case IDCANCEL:
  613.             {
  614.                 struct WinList *t;
  615.  
  616.                 /* Destroy remaining filespec dialog boxes. */
  617.                 for (t = WinListHead.next; t; t = t->next) 
  618.                 {
  619.                     SHOWF1
  620.                     ("SearchDlgProc: Destroying window handle %#x\n", 
  621.                                 t->hWin);
  622.                     DestroyWindow(t->hWin);
  623.                 }
  624.                 DestroyWindow(hDlg);    /* Remove main dialog box. */
  625.                 PostQuitMessage(0);
  626.             }
  627.             return (TRUE);
  628.  
  629.           case IDC_ABOUT: /* show AboutBox */
  630.             {
  631.                 FARPROC lpAboutDlgProc;
  632.  
  633.                 lpAboutDlgProc = 
  634.                     MakeProcInstance(AboutDlgProc, hAppInstance);
  635.                 DialogBox(hAppInstance, "AboutBox", hDlg, lpAboutDlgProc);
  636.                 FreeProcInstance(lpAboutDlgProc);
  637.             }
  638.             return (TRUE);
  639.  
  640.           case IDC_FILESPEC:
  641.             /* enable the "Search" button only when there is a FILESPEC */
  642.             if (HIWORD(lParam) == EN_CHANGE) 
  643.             {
  644.                 if (SendDlgItemMessage(hDlg, IDC_FILESPEC, WM_GETTEXTLENGTH, 
  645.                                             0, 0L))
  646.                     EnableWindow(GetDlgItem(hDlg, 1), TRUE);
  647.                 else
  648.                     EnableWindow(GetDlgItem(hDlg, 1), FALSE);
  649.                 return (TRUE);
  650.             }
  651.             else return (FALSE);
  652.  
  653.           default:
  654.             return (FALSE);
  655.         }
  656.       default:
  657.         return (FALSE);
  658.     }
  659. }
  660.  
  661. /* "WinMain - program entry point */
  662. /* program entry: WinMain
  663. **
  664. ** The unusual feature of this program is that it does not create
  665. ** a main window.  Instead, it creates a dialog box that completely
  666. ** controls the program. The only part of the control logic that is at
  667. ** the "main" level is a check for the F6 key which is used to switch
  668. ** between dialog boxes.
  669. */
  670. int PASCAL
  671.  WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, 
  672.         int nCmdShow)
  673. {
  674.     FARPROC lpSearchDlgProc;
  675.     HWND hParent, hLast;
  676.     MSG Msg;
  677.     struct WinList *t;
  678.  
  679. #if defined(DEBUG)
  680.     if ((debugfile = fopen("debug.log", "w")) == NULL)
  681.         return (FALSE);
  682.     fprintf(debugfile, "FF: loaded\n");
  683. #endif
  684.  
  685.     /* initialization */
  686.     hAppInstance = hInstance;
  687.     WinListHead.next = NULL;
  688.     hHourGlass = LoadCursor(NULL, IDC_WAIT);
  689.     CurrentDialogBox = NULL;
  690.     HIcon = LoadIcon (hAppInstance,"ffIcon");
  691.  
  692.     fpFileListProc = MakeProcInstance(FileListProc, hInstance);
  693.     lpSearchDlgProc = MakeProcInstance(SearchDlgProc, hInstance);
  694.     WinListHead.hWin =
  695.         CreateDialog(hInstance, "SearchDlg", NULL, lpSearchDlgProc);
  696.     SHOWF1
  697.     ("WinMain: Handle to master dialog box is %#x\n", WinListHead.hWin);
  698.  
  699.     while (GetMessage((LPMSG) &Msg, NULL, NULL, NULL)) 
  700.     {
  701.         /* watch for F6, the key that cycles between windows */
  702.         if (Msg.message == WM_KEYDOWN && Msg.wParam == VK_F6) 
  703.         {
  704.             /* find top level window */
  705.             hLast = Msg.hwnd;
  706.             while (IsWindow(hParent = GetParent(hLast)))
  707.                  hLast = hParent;
  708.  
  709.             /* now, find that window in our window list */
  710.             for (t=&WinListHead; t; t=t->next) 
  711.             {
  712.                 if (t->hWin == hLast)  /* found self in list */
  713.                 {
  714.                     /* now, find next window that isn't iconic */
  715.                     for (t = t->next; t->hWin != hLast; t = t->next) 
  716.                     {
  717.                         if (!t)
  718.                             t = &WinListHead;
  719.  
  720.                         if (!IsIconic(t->hWin))
  721.                             break;
  722.                     }
  723.  
  724.                     SHOWF1("Setting focus to window %#x\n", t->hWin);
  725.                     if (t->hWin != hLast)
  726.                         SetFocus(t->hWin);
  727.                     break;
  728.                 }
  729.             }
  730.         }
  731.  
  732.         /* see if the message belongs to a dialog box */
  733.         if (CurrentDialogBox != NULL &&
  734.             IsWindow(CurrentDialogBox) &&
  735.             IsDialogMessage(CurrentDialogBox, (LPMSG) &Msg))
  736.             ;
  737.         /* if it didn't, give it standard processing */
  738.         else 
  739.         {
  740.             TranslateMessage ((LPMSG) &Msg);
  741.             DispatchMessage ((LPMSG) &Msg);
  742.         }
  743.     }
  744.  
  745.     /* when we get to here, all is done - cleanup & exit! */
  746. #if defined(DEBUG)
  747.     fprintf(debugfile, "Dump of WinList:\n");
  748.     for (t = WinListHead.next; t; t=t->next)
  749.         fprintf(debugfile, "WinList structure at %p contains handle %#x\n", 
  750.                 t, t->hWin);
  751.     fclose(debugfile);
  752. #endif
  753.     FreeProcInstance(lpSearchDlgProc);
  754.     FreeProcInstance(fpFileListProc);
  755.     return(FALSE);
  756. }