home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / FILEDLG6.ZIP / SOURCE.ZIP / FINDDLG.C < prev    next >
Text File  |  1990-11-12  |  40KB  |  914 lines

  1. /****************************************************************************
  2.  * FINDDLG.C - Find file dialog box routines.                               *
  3.  *                                                                          *
  4.  *  Modifications -                                                         *
  5.  *      21-Sep-1989 : Moved find file functions into separate file.         *
  6.  *                    Made default button context sensitive.                *
  7.  *                    Prevented buttons from retaining focus after being    *
  8.  *                      clicked.                                            *
  9.  *                    Fixed bug that caused duplicate error messages to     *
  10.  *                      be displayed when enter key used to select list     *
  11.  *                      box items.                                          *
  12.  *      11-Oct-1989 : Changed to DLL version of ErrMessageBox function.     *
  13.  *      11-Oct-1990 : Added long filename support.                          *
  14.  *                    Eliminated ResetDefaultButtons function.              *
  15.  *                    Fixed bug that caused contents of open file dialog    *
  16.  *                    to be invalid if an unsuccessful attempt was made     *
  17.  *                    to open a file located in a directory other than      *
  18.  *                    the current directory.                                *
  19.  *      15-Oct-1990 : Moved search function into a background thread.       *
  20.  *      16-Oct-1990 : Added ability to search for files that match one      *
  21.  *                    of a list of search patterns.                         *
  22.  *      06-Nov-1990 : Increased speed of search function by causing         *
  23.  *                    DosFindFirst/DosFindNext to return the list of        *
  24.  *                    found files in blocks of 10.                          *
  25.  *      12-Nov-1990 : Added help support.                                   *
  26.  *                                                                          *
  27.  * (c)Copyright 1990 Rick Yoder                                             *
  28.  ****************************************************************************/
  29.  
  30.     #define INCL_WIN
  31.     #define INCL_DOS
  32.     #define INCL_DOSERRORS
  33.     #include <os2.h>
  34.  
  35.     #include <string.h>
  36.     #include <process.h>
  37.     #include <errmsg.h>
  38.  
  39.     #include "filedlg.h"
  40.     #include "dialog.h"
  41.     #include "tools.h"
  42.     #include "static.h"
  43.     #include "opendata.h"   // definition of structure holding dialog box
  44.                             //  static data (DATA & PDATA types).
  45.  
  46. /****************************************************************************
  47.  *  Procedure declarations                                                  *
  48.  ****************************************************************************/
  49.     static MRESULT NEAR FindInit( HWND hwnd,MPARAM mp2 );
  50.     static MRESULT NEAR PatternEditCtrl( HWND hwnd,USHORT msg,
  51.                                          MPARAM mp1,MPARAM mp2 );
  52.     static MRESULT NEAR FindListbox( HWND hwnd,USHORT msg,
  53.                                      MPARAM mp1,MPARAM mp2 );
  54.     static MRESULT NEAR SearchButton( HWND hwnd );
  55.     static MRESULT NEAR OpenButton( HWND hwnd );
  56.     static BOOL NEAR Directory( PSZ pszFileSpec,PDATA pData );
  57.     static USHORT NEAR OpenFile( HWND hDlg,PDATA pData );
  58.     static VOID FAR SearchThread( PDATA pData );
  59. /****************************************************************************/
  60.  
  61.  
  62. /****************************************************************************
  63.  *  Definitions of messages sent from search thread to dialog box.          *
  64.  ****************************************************************************/
  65.     #define SEARCH_DONE         (WM_USER)
  66.     /* if mp1 == 0 then mp2 contains OS/2 error code.
  67.      */
  68.  
  69.     #define SEARCH_ADDDIR       (WM_USER+1)
  70.     /* mp1 contains a pointer to the directory name to be added
  71.      * to the list box.
  72.      */
  73.  
  74.     #define SEARCH_ADDFILES     (WM_USER+2)
  75.     /* mp1 contains a pointer to an array of FILEFINDBUF structures.
  76.      * mp2 contains the size of the array.
  77.      */
  78. /****************************************************************************/
  79.  
  80.  
  81. /****************************************************************************
  82.  * _FindDlgProc()                                                           *
  83.  ****************************************************************************/
  84.     MRESULT EXPENTRY _FindDlgProc( HWND hwnd,USHORT msg,MPARAM mp1,MPARAM mp2 )
  85.     {
  86.         PDATA   pData;
  87.  
  88.         switch ( msg ) {
  89.             case WM_INITDLG:
  90.                 return FindInit( hwnd,mp2 );
  91.  
  92.             case WM_CONTROL:
  93.                 switch ( SHORT1FROMMP(mp1) ) {
  94.                     case FIND_PATTERN:
  95.                         return PatternEditCtrl( hwnd,msg,mp1,mp2 );
  96.  
  97.                     case FIND_FLIST:
  98.                         return FindListbox( hwnd,msg,mp1,mp2 );
  99.  
  100.                     case FIND_DRIVES:
  101.                         if ( SHORT2FROMMP(mp1) == LN_SETFOCUS )
  102.                             {
  103.                             WinSendDlgItemMsg( hwnd,FIND_SEARCH,BM_SETDEFAULT,
  104.                                                MPFROMSHORT(TRUE),0L );
  105.                             WinSendDlgItemMsg( hwnd,FIND_OPEN,BM_SETDEFAULT,
  106.                                                MPFROMSHORT(FALSE),0L );
  107.                             WinSendDlgItemMsg( hwnd,FIND_CANCEL,BM_SETDEFAULT,
  108.                                                MPFROMSHORT(FALSE),0L );
  109.                             return 0L;
  110.                             }
  111.                         break;
  112.                     }
  113.                 break;
  114.  
  115.             case WM_COMMAND:
  116.                 switch (COMMANDMSG(&msg)->cmd) {
  117.                     case FIND_SEARCH:
  118.                         return SearchButton( hwnd );
  119.  
  120.                     case FIND_OPEN:
  121.                         return OpenButton( hwnd );
  122.  
  123.                     case DID_CANCEL:
  124.                     case FIND_CANCEL:
  125.                         pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  126.                         DosEnterCritSec();
  127.                         switch ( pData->fControl ) {
  128.                             case CANCEL:
  129.                                 pData->fControl = TERMINATE;
  130.                                 DosSemClear( &pData->semTrigger );
  131.                                 DosExitCritSec();
  132.                                 DosSemWait( &pData->semTerminate,SEM_INDEFINITE_WAIT );
  133.                                 DosFreeSeg( pData->selStack );
  134.                                 DosFreeSeg( SELECTOROF(pData->pszPattern) );
  135.                                 DosFreeSeg( SELECTOROF(pData->pszScratch2) );
  136.                                 WinDismissDlg( hwnd,FDLG_CANCEL );
  137.                                 break;
  138.  
  139.                             case CONTINUE:
  140.                                 DosSemClear( &pData->semAdd );
  141.                                 pData->fControl = CANCEL;
  142.                                 DosExitCritSec();
  143.                                 break;
  144.  
  145.                             default:
  146.                                 DosExitCritSec();
  147.                                 break;
  148.                             }
  149.                         return 0L;
  150.                     }
  151.                 break;
  152.  
  153.             case SEARCH_DONE:
  154.                 {
  155.                 SHORT sCount;
  156.  
  157.                 pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  158.                 WinSetWindowText( hwnd,szSearchTitle );
  159.                 WinEnableWindow( WinWindowFromID(hwnd,FIND_SEARCH),TRUE );
  160.                 sCount = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_FLIST,
  161.                                                          LM_QUERYITEMCOUNT,
  162.                                                          0L,0L)
  163.                                      );
  164.                 if ( SHORT1FROMMP(mp1) != 0 )
  165.                     ErrMessageBox( hwnd,szSearchTitle,SHORT1FROMMP(mp1),
  166.                                    appMsgList,appMsgCount,pData->usFindCount );
  167.                 else
  168.                     ErrMessageBox( hwnd,szSearchTitle,SHORT1FROMMP(mp2),
  169.                                    NULL,0 );
  170.                 return 0L;
  171.                 }
  172.  
  173.             case SEARCH_ADDDIR:
  174.                 {
  175.                 USHORT  rc;
  176.  
  177.                 pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  178.                 if ( pData->fControl == CONTINUE )
  179.                     {
  180.                     rc = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_FLIST,
  181.                                                          LM_INSERTITEM,
  182.                                                          MPFROMSHORT(LIT_END),
  183.                                                          mp1)
  184.                                      );
  185.                     if ( rc == LIT_MEMERROR || rc == LIT_ERROR )
  186.                         {
  187.                         pData->fControl = ERROR;
  188.                         WinPostMsg( hwnd,SEARCH_DONE,MPFROMSHORT(LISTBOX_FULL),0L );
  189.                         }
  190.                     }
  191.                 DosSemClear( &pData->semAdd );
  192.                 return 0L;
  193.                 }
  194.  
  195.             case SEARCH_ADDFILES:
  196.                 {
  197.                 USHORT       rc;
  198.                 USHORT       n;
  199.                 PFILEFINDBUF pFindbuf;
  200.  
  201.                 pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  202.                 if ( pData->fControl == CONTINUE )
  203.                     {
  204.                     pData->pszScratch2[0] = ' ';
  205.                     pData->pszScratch2[1] = ' ';
  206.                     pData->pszScratch2[2] = ' ';
  207.                     pFindbuf = PVOIDFROMMP( mp1 );
  208.                     for ( n = 0; n < SHORT1FROMMP(mp2); n++ )
  209.                         {
  210.                         strcpy( pData->pszScratch2+3,pFindbuf->achName );
  211.                         rc = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_FLIST,
  212.                                                              LM_INSERTITEM,
  213.                                                              MPFROMSHORT(LIT_END),
  214.                                                              pData->pszScratch2)
  215.                                          );
  216.                         if ( rc == LIT_MEMERROR || rc == LIT_ERROR )
  217.                             {
  218.                             pData->fControl = ERROR;
  219.                             WinPostMsg( hwnd,SEARCH_DONE,MPFROMSHORT(LISTBOX_FULL),0L );
  220.                             break;
  221.                             }
  222.                         pFindbuf = (PFILEFINDBUF)( pFindbuf->achName + pFindbuf->cchName + 1 );
  223.                         }
  224.                     }
  225.                 DosSemClear( &pData->semAdd );
  226.                 return 0L;
  227.                 }
  228.  
  229.             case WM_HELP:
  230.                 pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  231.                 if ( pData->pfnHelpProc != NULL )
  232.                     {
  233.                     (*pData->pfnHelpProc)( hwnd );
  234.                     return 0L;
  235.                     }
  236.                 break;
  237.             }
  238.  
  239.         return WinDefDlgProc( hwnd,msg,mp1,mp2 );
  240.     }
  241. /****************************************************************************/
  242.  
  243.  
  244. /****************************************************************************
  245.  * FindInit() -- Process WM_INITDLG message sent to find file dialog box.   *
  246.  ****************************************************************************/
  247.     static MRESULT NEAR FindInit( HWND hwnd,MPARAM mp2 )
  248.     {
  249.         #define STACK_SIZE  (8*1024)
  250.  
  251.         PDATA   pData;
  252.         USHORT  usResult,usCount,usIndex,usDriveNum;
  253.         ULONG   ulMap;
  254.         SEL     sel;
  255.  
  256.         pData = PVOIDFROMMP( mp2 );
  257.  
  258.         if ( pData->pfnHelpProc == NULL )
  259.             WinDestroyWindow( WinWindowFromID(hwnd,FIND_HELP) );
  260.  
  261.         if ( !WinSendDlgItemMsg(hwnd,FIND_PATTERN,EM_SETTEXTLIMIT,
  262.                                 MPFROMSHORT(pData->usMaxPathLen),0L) )
  263.             {
  264.             ErrMessageBox( hwnd,szSearchTitle,ERROR_NOT_ENOUGH_MEMORY,NULL,0 );
  265.             WinDismissDlg( hwnd,FDLG_CANCEL );
  266.             return 0L;
  267.             }
  268.  
  269.         if ( usResult = DosAllocSeg(STACK_SIZE,&pData->selStack,SEG_NONSHARED) )
  270.             {
  271.             ErrMessageBox( hwnd,szSearchTitle,usResult,NULL,0 );
  272.             WinDismissDlg( hwnd,FDLG_CANCEL );
  273.             return 0L;
  274.             }
  275.         if ( usResult = DosAllocSeg(pData->usMaxPathLen,&sel,SEG_NONSHARED) )
  276.             {
  277.             ErrMessageBox( hwnd,szSearchTitle,usResult,NULL,0 );
  278.             DosFreeSeg( pData->selStack );
  279.             WinDismissDlg( hwnd,FDLG_CANCEL );
  280.             return 0L;
  281.             }
  282.         pData->pszPattern = MAKEP(sel,0);
  283.         if ( usResult = DosAllocSeg(pData->usMaxPathLen,&sel,SEG_NONSHARED) )
  284.             {
  285.             ErrMessageBox( hwnd,szSearchTitle,usResult,NULL,0 );
  286.             DosFreeSeg( pData->selStack );
  287.             DosFreeSeg( SELECTOROF(pData->pszPattern) );
  288.             WinDismissDlg( hwnd,FDLG_CANCEL );
  289.             return 0L;
  290.             }
  291.         pData->pszScratch2 = MAKEP(sel,0);
  292.  
  293.         pData->semTrigger   = 0L;
  294.         pData->semTerminate = 0L;
  295.         pData->semAdd       = 0L;
  296.         pData->hDlg         = hwnd;
  297.         pData->fControl     = CANCEL;
  298.  
  299.         DosSemSet( &pData->semTrigger );
  300.         DosSemSet( &pData->semTerminate );
  301.         pData->tid = _beginthread( SearchThread,MAKEP(pData->selStack,0),STACK_SIZE,pData );
  302.         if ( -1 == pData->tid )
  303.             {
  304.             ErrMessageBox( hwnd,szSearchTitle,SEARCH_THREAD_ERROR,
  305.                            appMsgList,appMsgCount );
  306.             DosFreeSeg( pData->selStack );
  307.             DosFreeSeg( SELECTOROF(pData->pszPattern) );
  308.             DosFreeSeg( SELECTOROF(pData->pszScratch2) );
  309.             WinDismissDlg( hwnd,FDLG_CANCEL );
  310.             return 0L;
  311.             }
  312.  
  313.         WinSetWindowULong( hwnd,QWL_USER,(ULONG)pData );
  314.         WinSendDlgItemMsg( hwnd,FIND_FLIST,LM_DELETEALL,NULL,NULL );
  315.         WinSendDlgItemMsg( hwnd,FIND_DRIVES,LM_DELETEALL,NULL,NULL );
  316.         WinSetDlgItemText( hwnd,FIND_PATTERN,pData->pszShowSpec );
  317.         WinEnableWindow( WinWindowFromID(hwnd,FIND_OPEN),FALSE );
  318.         pData->usSelectFind = 0;
  319.  
  320.         /* Fill in disk drive list box */
  321.         if ( usResult = DosQCurDisk(&usDriveNum,&ulMap) )
  322.             {
  323.             ErrMessageBox( hwnd,szSearchTitle,usResult,NULL,0 );
  324.             WinDismissDlg( hwnd,FDLG_CANCEL );
  325.             return 0L;
  326.             }
  327.         pData->pszScratch[1] = ':';
  328.         pData->pszScratch[2] = '\0';
  329.         for ( usCount = 0; usCount < 26; usCount++ )
  330.             if ( ulMap & 1L << usCount )
  331.                 {
  332.                 pData->pszScratch[0] = (CHAR)( usCount + 'A' );
  333.  
  334.                 usIndex = SHORT1FROMMR(
  335.                             WinSendDlgItemMsg( hwnd,FIND_DRIVES,
  336.                                                LM_INSERTITEM,
  337.                                                MPFROMSHORT(LIT_END),
  338.                                                MPFROMP(pData->pszScratch) )
  339.                                       );
  340.  
  341.                 if ( usCount == usDriveNum-1 )
  342.                     {
  343.                     WinSendDlgItemMsg( hwnd,FIND_DRIVES,
  344.                                        LM_SELECTITEM,
  345.                                        MPFROMSHORT(usIndex),
  346.                                        MPFROMSHORT(TRUE) );
  347.                     }
  348.                 }
  349.  
  350.         return 0L;
  351.     }
  352. /****************************************************************************/
  353.  
  354.  
  355. /****************************************************************************
  356.  * PatternEditCtrl() -- Handles messages sent by FIND_PATTERN edit control  *
  357.  *                      to find file dialog box.                            *
  358.  ****************************************************************************/
  359.     static MRESULT NEAR PatternEditCtrl( HWND hwnd,USHORT msg,
  360.                                          MPARAM mp1,MPARAM mp2 )
  361.     {
  362.         PDATA   pData;
  363.         USHORT  usLen;
  364.  
  365.         pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  366.         switch ( SHORT2FROMMP(mp1) ) {
  367.             case EN_CHANGE:
  368.                 WinEnableWindow( WinWindowFromID(hwnd,FIND_PATTERN),
  369.                                  WinQueryDlgItemTextLength(hwnd,FIND_PATTERN)
  370.                                );
  371.                 break;
  372.  
  373.             case EN_SETFOCUS:
  374.                 usLen = WinQueryDlgItemTextLength( hwnd,FIND_PATTERN );
  375.                 WinSendDlgItemMsg( hwnd,FIND_PATTERN,EM_SETSEL,
  376.                                    MPFROM2SHORT(0,usLen),0L );
  377.                 WinSendDlgItemMsg( hwnd,FIND_SEARCH,BM_SETDEFAULT,
  378.                                    MPFROMSHORT(TRUE),0L );
  379.                 WinSendDlgItemMsg( hwnd,FIND_OPEN,BM_SETDEFAULT,
  380.                                    MPFROMSHORT(FALSE),0L );
  381.                 WinSendDlgItemMsg( hwnd,FIND_CANCEL,BM_SETDEFAULT,
  382.                                    MPFROMSHORT(FALSE),0L );
  383.                 break;
  384.             }
  385.  
  386.         return WinDefDlgProc( hwnd,msg,mp1,mp2 );
  387.     }
  388. /****************************************************************************/
  389.  
  390.  
  391. /****************************************************************************
  392.  * FindListbox() -- Handle messages sent by FIND_FLIST list box to the      *
  393.  *                  find file dialog box.                                   *
  394.  ****************************************************************************/
  395.     static MRESULT NEAR FindListbox( HWND hwnd,USHORT msg,
  396.                                      MPARAM mp1,MPARAM mp2 )
  397.     {
  398.         PDATA   pData;
  399.         USHORT  usResult;
  400.  
  401.         pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  402.         switch ( SHORT2FROMMP(mp1) ) {
  403.             case LN_SELECT:
  404.                 usResult = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_FLIST,
  405.                                                            LM_QUERYSELECTION,
  406.                                                            0L,0L)
  407.                                        );
  408.                 if ( usResult != LIT_NONE )
  409.                     pData->usSelectFind = usResult;
  410.                 WinSendDlgItemMsg( hwnd,FIND_FLIST,
  411.                                    LM_QUERYITEMTEXT,
  412.                                    MPFROM2SHORT(pData->usSelectFind,pData->usMaxPathLen+2),
  413.                                    MPFROMP(pData->pszScratch) );
  414.                 WinEnableWindow( WinWindowFromID(hwnd,FIND_OPEN),
  415.                                  (*pData->pszScratch == ' ') );
  416.                 return 0L;
  417.  
  418.             case LN_ENTER:  /* equivalent to open button clicked */
  419.                 WinSendDlgItemMsg( hwnd,FIND_OPEN,BM_CLICK,0L,0L );
  420.                 return 0L;
  421.  
  422.             case LN_SETFOCUS:
  423.                 usResult = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_FLIST,
  424.                                                            LM_QUERYTOPINDEX,
  425.                                                            0L,0L)
  426.                                        );
  427.                 if ( usResult != LIT_NONE )
  428.                     {
  429.                     if ( pData->usSelectFind < usResult )
  430.                         pData->usSelectFind = usResult;
  431.                     else if (pData->usSelectFind > usResult+10)
  432.                         pData->usSelectFind = usResult+10;
  433.  
  434.                     WinSendDlgItemMsg( hwnd,FIND_FLIST,
  435.                                        LM_SELECTITEM,
  436.                                        MPFROMSHORT(pData->usSelectFind),
  437.                                        MPFROMSHORT(TRUE) );
  438.                     }
  439.  
  440.                 /* Make OPEN button the current default button */
  441.                 WinSendDlgItemMsg( hwnd,FIND_SEARCH,BM_SETDEFAULT,
  442.                                    MPFROMSHORT(FALSE),0L );
  443.                 WinSendDlgItemMsg( hwnd,FIND_OPEN,BM_SETDEFAULT,
  444.                                    MPFROMSHORT(TRUE),0L );
  445.                 WinSendDlgItemMsg( hwnd,FIND_CANCEL,BM_SETDEFAULT,
  446.                                    MPFROMSHORT(FALSE),0L );
  447.                 return 0L;
  448.             }
  449.  
  450.         return WinDefDlgProc( hwnd,msg,mp1,mp2 );
  451.     }
  452. /****************************************************************************/
  453.  
  454.  
  455. /****************************************************************************
  456.  * OpenButton() -- Executed whenever OPEN button in find file dialog        *
  457.  *                 box is clicked.                                          *
  458.  ****************************************************************************/
  459.     static MRESULT NEAR OpenButton( HWND hwnd )
  460.     {
  461.         PDATA   pData;
  462.         SHORT   iItem;
  463.         HWND    hwndButton;
  464.  
  465.     /* Skip procedure when button does not have the focus.      *
  466.      * This prevents the duplicate error message problem that   *
  467.      * occurs when the enter key is used to select a list box   *
  468.      * item.                                                    */
  469.         hwndButton = WinWindowFromID( hwnd,FIND_OPEN );
  470.         if ( hwndButton != WinQueryFocus(HWND_DESKTOP,FALSE) ) return 0L;
  471.  
  472.         pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  473.         iItem = pData->usSelectFind;
  474.  
  475.         if ( WinSendDlgItemMsg( hwnd,FIND_FLIST,
  476.                                 LM_QUERYITEMTEXT,
  477.                                 MPFROM2SHORT(iItem,pData->usMaxPathLen),
  478.                                 MPFROMP(pData->pszFile) )
  479.            )
  480.             {
  481.             /* Get path name */
  482.             do  {
  483.                 WinSendDlgItemMsg( hwnd,FIND_FLIST,
  484.                                    LM_QUERYITEMTEXT,
  485.                                    MPFROM2SHORT(--iItem,pData->usMaxPathLen),
  486.                                    MPFROMP(pData->pszScratch) );
  487.                 } while ( *pData->pszScratch == ' ' );
  488.             strcat( pData->pszScratch,szSlash );
  489.             strcat( pData->pszScratch,pData->pszFile+3 );
  490.  
  491.             if ( !OpenFile(hwnd,pData) )
  492.                 {
  493.                 DosEnterCritSec();
  494.                 pData->fControl = TERMINATE;
  495.                 DosSemClear( &pData->semTrigger );
  496.                 DosSemClear( &pData->semAdd );
  497.                 DosExitCritSec();
  498.                 DosSemWait( &pData->semTerminate,SEM_INDEFINITE_WAIT );
  499.                 DosFreeSeg( pData->selStack );
  500.                 DosFreeSeg( SELECTOROF(pData->pszPattern) );
  501.                 DosFreeSeg( SELECTOROF(pData->pszScratch2) );
  502.                 WinDismissDlg( hwnd,FDLG_OK );
  503.                 }
  504.             else
  505.                 {
  506.                 /* Resynch current drive/directory with open dialog box */
  507.                 ParseFileName( pData->pszCurDir,pData->pszScratch,pData->pszShowSpec );
  508.                 WinSetFocus( HWND_DESKTOP,WinWindowFromID(hwnd,FIND_FLIST) );
  509.                 }
  510.             }
  511.  
  512.         return 0L;
  513.     }
  514. /****************************************************************************/
  515.  
  516.  
  517. /****************************************************************************
  518.  * OpenFile() - This function attempts to open the file specified           *
  519.  *              in the scratch data area.                                   *
  520.  *                                                                          *
  521.  *              This function returns a non-zero value if an error occured  *
  522.  *              or the input string was a search specification.             *
  523.  ****************************************************************************/
  524.     static USHORT NEAR OpenFile( HWND hDlg,PDATA pData )
  525.     {
  526.         USHORT  usResult;
  527.  
  528.         usResult = ParseFileName( pData->pszScratch,
  529.                                   pData->pszFile,
  530.                                   pData->pszShowSpec );
  531.         if ( usResult )
  532.             {
  533.             ErrMessageBox( hDlg,pData->pszTitle,usResult,NULL,0 );
  534.             return 1;
  535.             }
  536.  
  537.         if ( NULL != strpbrk(pData->pszFile,szWildCardChars) )
  538.             return 1;
  539.         else
  540.             {
  541.             usResult = DosOpen( pData->pszFile,
  542.                                 pData->phf,
  543.                                 pData->pusAction,
  544.                                 pData->ulFileSize,
  545.                                 pData->usAttribute,
  546.                                 pData->fsOpenFlags,
  547.                                 pData->fsOpenMode,
  548.                                 pData->ulReserved );
  549.             if ( usResult )
  550.                 {
  551.                 ErrMessageBox( hDlg,pData->pszTitle,usResult,NULL,0 );
  552.                 return 1;
  553.                 }
  554.             else
  555.                 return 0;
  556.             }
  557.     }
  558. /****************************************************************************/
  559.  
  560.  
  561. /****************************************************************************
  562.  * SearchButton() -- Executed whenever SEARCH button in find file dialog    *
  563.  *                   box is clicked.                                        *
  564.  ****************************************************************************/
  565.     static MRESULT NEAR SearchButton( HWND hwnd )
  566.     {
  567.         PDATA       pData;
  568.         SHORT       iItem;
  569.  
  570.         pData = (PDATA)WinQueryWindowULong( hwnd,QWL_USER );
  571.  
  572.     /* Retrieve current search pattern */
  573.         WinQueryDlgItemText( hwnd,FIND_PATTERN,
  574.                              pData->usMaxPathLen,
  575.                              pData->pszPattern );
  576.         if (   NULL != strchr(pData->pszPattern,':')
  577.             || NULL != strchr(pData->pszPattern,'\\') )
  578.             {
  579.             ErrMessageBox( hwnd,szSearchTitle,BAD_SEARCH,
  580.                            appMsgList,appMsgCount );
  581.             WinSetFocus( HWND_DESKTOP,WinWindowFromID(hwnd,FIND_PATTERN) );
  582.             return 0L;
  583.             }
  584.  
  585.     /* Disable open and search buttons */
  586.         WinEnableWindow( WinWindowFromID(hwnd,FIND_OPEN),FALSE );
  587.         WinEnableWindow( WinWindowFromID(hwnd,FIND_SEARCH),FALSE );
  588.  
  589.     /* Set dialog box title to "Searching ..." */
  590.         WinSetWindowText( hwnd,szSearching );
  591.  
  592.     /* Erase current file list */
  593.         WinSendDlgItemMsg( hwnd,FIND_FLIST,LM_DELETEALL,0L,0L );
  594.         pData->usSelectFind = 0;
  595.  
  596.     /* Generate list of drives to be searched */
  597.         pData->ulDriveList = 0L;
  598.         iItem = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_DRIVES,
  599.                                                 LM_QUERYSELECTION,
  600.                                                 MPFROMSHORT(LIT_FIRST),0L)
  601.                             );
  602.         while ( iItem != LIT_NONE )
  603.             {
  604.             pData->ulDriveList |= (1L << iItem);
  605.             iItem = SHORT1FROMMR( WinSendDlgItemMsg(hwnd,FIND_DRIVES,
  606.                                                     LM_QUERYSELECTION,
  607.                                                     MPFROMSHORT(iItem),0L)
  608.                                 );
  609.             }
  610.  
  611.     /* Start search thread */
  612.         pData->fControl = CONTINUE;
  613.         DosSemClear( &pData->semTrigger );
  614.  
  615.     /* Set focus to list of files found */
  616.         WinSetFocus( HWND_DESKTOP,WinWindowFromID(hwnd,FIND_FLIST) );
  617.         return 0L;
  618.     }
  619. /****************************************************************************/
  620.  
  621.  
  622. /****************************************************************************
  623.  * SearchThread() - This function searches for the specified files in       *
  624.  *                  a background thread.                                    *
  625.  ****************************************************************************/
  626.     static VOID FAR SearchThread( PDATA pData )
  627.     {
  628.         USHORT  usCount;
  629.         PSZ     pszCurrent;
  630.         PSZ     pszFileSpec;
  631.         SEL     sel;
  632.         USHORT  rc;
  633.  
  634.         while (TRUE)
  635.             {
  636.             DosSemWait( &pData->semTrigger,SEM_INDEFINITE_WAIT );
  637.             DosSemSet( &pData->semTrigger );
  638.  
  639.             if ( pData->fControl == TERMINATE )
  640.                 {
  641.                 DosEnterCritSec();
  642.                 DosSemClear( &pData->semTerminate );
  643.                 _endthread();
  644.                 }
  645.  
  646.             if ( rc = DosAllocSeg(pData->usMaxPathLen,&sel,SEG_NONSHARED) )
  647.                 {
  648.                 DosEnterCritSec();
  649.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(rc) );
  650.                 goto RESTART_LOOP;
  651.                 }
  652.             pszFileSpec = MAKEP(sel,0);
  653.  
  654.             pData->usFindCount = 0;
  655.             pszCurrent = strtok( pData->pszPattern,szDelimiters );
  656.             while ( pszCurrent != NULL )
  657.                 {
  658.                 strcpy( pszFileSpec+3,pszCurrent );
  659.                 for ( usCount = 0; usCount < 26; usCount++ )
  660.                     {
  661.                     if ( pData->ulDriveList & (1L << usCount) )
  662.                         {
  663.                         pszFileSpec[0] = (CHAR)( usCount + 'A' );
  664.                         pszFileSpec[1] = ':';
  665.                         pszFileSpec[2] = '\\';
  666.                         if ( !Directory(pszFileSpec,pData) ) switch (pData->fControl) {
  667.                             case CANCEL:
  668.                                 WinPostMsg( pData->hDlg,SEARCH_DONE,
  669.                                             MPFROMSHORT(SEARCH_CANCELLED),0L );
  670.                                 goto RESTART_LOOP;
  671.  
  672.                             case TERMINATE:
  673.                                 DosFreeSeg( SELECTOROF(pszFileSpec) );
  674.                                 DosSemClear( &pData->semTerminate );
  675.                                 _endthread();
  676.  
  677.                             case ERROR:
  678.                                 goto RESTART_LOOP;
  679.                             }
  680.                         }
  681.                     DosEnterCritSec();
  682.                     switch ( pData->fControl ) {
  683.                         case CANCEL:
  684.                             WinPostMsg( pData->hDlg,SEARCH_DONE,
  685.                                         MPFROMSHORT(SEARCH_CANCELLED),0L );
  686.                             goto RESTART_LOOP;
  687.  
  688.                         case TERMINATE:
  689.                             DosFreeSeg( SELECTOROF(pszFileSpec) );
  690.                             DosSemClear( &pData->semTerminate );
  691.                             _endthread();
  692.  
  693.                         case CONTINUE:
  694.                             DosExitCritSec();
  695.                             break;
  696.                         }
  697.  
  698.                     } /* search next drive */
  699.  
  700.                 pszCurrent = strtok( NULL,szDelimiters );
  701.                 } /* look for next search pattern */
  702.  
  703.             DosEnterCritSec();
  704.             WinPostMsg( pData->hDlg,SEARCH_DONE,MPFROMSHORT(FILES_FOUND),0L );
  705.  
  706. RESTART_LOOP:
  707.             DosFreeSeg( SELECTOROF(pszFileSpec) );
  708.             pData->fControl = CANCEL;
  709.             DosExitCritSec();
  710.             } /* end while */
  711.     }
  712. /****************************************************************************/
  713.  
  714.  
  715. /****************************************************************************
  716.  * Directory() - This function is called recursively, successively          *
  717.  *               searching each subdirectory for files that match           *
  718.  *               the search criteria until the entire drive has been        *
  719.  *               traversed.                                                 *
  720.  *                                                                          *
  721.  *               This function returns a value of FALSE if an error         *
  722.  *               occurs, otherwise it returns a value of TRUE.              *
  723.  ****************************************************************************/
  724.     static BOOL NEAR Directory( PSZ pszFileSpec,PDATA pData )
  725.     {
  726.         #define FINDCOUNT       10
  727.         #define FILEFINDSIZE    (FINDCOUNT*sizeof(FILEFINDBUF))
  728.         #define ABORT_CHK()     if ( pData->fControl != CONTINUE ) goto ABORT_EXIT
  729.  
  730.         SEL          sel;
  731.         PSZ          pszSpec;
  732.         PSZ          pszSub;
  733.         PFILEFINDBUF pFindbuf,pFindbuf2;
  734.         PFILEFINDBUF pCurrent;
  735.         HDIR         hdir = HDIR_CREATE;
  736.         USHORT       usSearchCount;
  737.         USHORT       n;
  738.         USHORT       usResult,rc;
  739.  
  740.         /*********************************************************
  741.          * Allocate memory for file find buffers                 *
  742.          *   DosAllocSeg is used to keep from overflowing the    *
  743.          *   stack when a disk with a large directory tree is    *
  744.          *   searched.                                           *
  745.          *********************************************************/
  746.         if ( rc = DosAllocSeg(FILEFINDSIZE,&sel,SEG_NONSHARED) )
  747.             {
  748.             DosEnterCritSec();
  749.             if ( pData->fControl == CONTINUE )
  750.                 {
  751.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(rc) );
  752.                 pData->fControl = ERROR;
  753.                 }
  754.             return FALSE;
  755.             }
  756.         pFindbuf = MAKEP( sel,0 );
  757.         if ( rc = DosAllocSeg(FILEFINDSIZE,&sel,SEG_NONSHARED) )
  758.             {
  759.             DosEnterCritSec();
  760.             if ( pData->fControl == CONTINUE )
  761.                 {
  762.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(rc) );
  763.                 pData->fControl = ERROR;
  764.                 }
  765.             DosFreeSeg( SELECTOROF(pFindbuf) );
  766.             return FALSE;
  767.             }
  768.         pFindbuf2 = MAKEP( sel,0 );
  769.  
  770.         /* Split input file spec into directory name and file name */
  771.         strcpy( pData->pszScratch2,pszFileSpec );
  772.         pszSpec = strrchr( pszFileSpec,'\\' );
  773.         *pszSpec++ = '\0';
  774.  
  775.         /* Find first file that matches criteria */
  776.         usSearchCount = FINDCOUNT;
  777.         usResult = DosFindFirst( pData->pszScratch2,&hdir,pData->usShowAttr,
  778.                                  pFindbuf2,FILEFINDSIZE,
  779.                                  &usSearchCount,0L );
  780.  
  781.         /* Add directory name to list box if a file was found */
  782.         if ( !usResult )
  783.             {
  784.             ABORT_CHK();
  785.             DosSemSet( &pData->semAdd );
  786.             while ( !WinPostMsg(pData->hDlg,SEARCH_ADDDIR,MPFROMP(pszFileSpec),0L) )
  787.                 ABORT_CHK();
  788.             DosSemWait( &pData->semAdd,SEM_INDEFINITE_WAIT );
  789.             }
  790.  
  791.         /* Add names of found files to list box */
  792.         while ( !usResult )
  793.             {
  794.             ABORT_CHK();
  795.             memcpy( pFindbuf,pFindbuf2,FILEFINDSIZE );
  796.             pData->usFindCount += usSearchCount;
  797.             DosSemSet( &pData->semAdd );
  798.             while ( !WinPostMsg(pData->hDlg,SEARCH_ADDFILES,
  799.                                 MPFROMP(pFindbuf),
  800.                                 MPFROMSHORT(usSearchCount)) ) ABORT_CHK();
  801.  
  802.             /* Get next set of matching files while list is being updated */
  803.             usSearchCount = FINDCOUNT;
  804.             usResult = DosFindNext( hdir,pFindbuf2,FILEFINDSIZE,&usSearchCount );
  805.  
  806.             /* Wait until listbox is finished being updated */
  807.             DosSemWait( &pData->semAdd,SEM_INDEFINITE_WAIT );
  808.             }
  809.         DosFreeSeg( SELECTOROF(pFindbuf2) );
  810.         if ( usResult != ERROR_NO_MORE_SEARCH_HANDLES ) DosFindClose(hdir);
  811.         if (   (usResult && usResult != ERROR_NO_MORE_FILES)
  812.             || pData->fControl != CONTINUE )
  813.             {
  814.             DosEnterCritSec();
  815.             if ( pData->fControl == CONTINUE )
  816.                 {
  817.                 pData->fControl = ERROR;
  818.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(usResult) );
  819.                 }
  820.             DosFreeSeg( SELECTOROF(pFindbuf) );
  821.             return FALSE;
  822.             }
  823.  
  824.         /* Allocate memory for subdirectory search spec. */
  825.         if ( rc = DosAllocSeg(pData->usMaxPathLen,&sel,SEG_NONSHARED) )
  826.             {
  827.             DosEnterCritSec();
  828.             if ( pData->fControl == CONTINUE )
  829.                 {
  830.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(rc) );
  831.                 pData->fControl = ERROR;
  832.                 }
  833.             DosFreeSeg( SELECTOROF(pFindbuf) );
  834.             return FALSE;
  835.             }
  836.         pszSub = MAKEP( sel,0 );
  837.  
  838.         /* Search subdirectories for matching files */
  839.         hdir            = HDIR_CREATE;
  840.         usSearchCount   = FINDCOUNT;
  841.         strcpy( pData->pszScratch2,pszFileSpec );
  842.         strcat( pData->pszScratch2,szSlash );
  843.         strcat( pData->pszScratch2,szStarDotStar );
  844.         usResult = DosFindFirst( pData->pszScratch2,&hdir,FILE_DIRECTORY,
  845.                                  pFindbuf,FILEFINDSIZE,
  846.                                  &usSearchCount,0L );
  847.         while ( !usResult )
  848.             {
  849.             for ( pCurrent = pFindbuf,n = 0; n < usSearchCount; n++ )
  850.                 {
  851.                 if ( pData->fControl != CONTINUE )
  852.                     {
  853.                     DosEnterCritSec();
  854.                     DosFindClose( hdir );
  855.                     DosFreeSeg( SELECTOROF(pFindbuf) );
  856.                     DosFreeSeg( SELECTOROF(pszSub) );
  857.                     return FALSE;
  858.                     }
  859.  
  860.                 if (   (pCurrent->attrFile & FILE_DIRECTORY)
  861.                     && (pCurrent->achName[0] != '.') )
  862.                     {
  863.                     strcpy( pszSub,pszFileSpec );
  864.                     strcat( pszSub,szSlash );
  865.                     strcat( pszSub,pCurrent->achName );
  866.                     strcat( pszSub,szSlash );
  867.                     strcat( pszSub,pszSpec );
  868.                     if ( !Directory(pszSub,pData) )
  869.                         {
  870.                         DosFindClose( hdir );
  871.                         DosFreeSeg( SELECTOROF(pFindbuf) );
  872.                         DosFreeSeg( SELECTOROF(pszSub) );
  873.                         return FALSE;
  874.                         }
  875.                     }
  876.                 pCurrent = (PFILEFINDBUF)( pCurrent->achName + pCurrent->cchName + 1 );
  877.                 }
  878.             usSearchCount = FINDCOUNT;
  879.             usResult = DosFindNext( hdir,pFindbuf,FILEFINDSIZE,&usSearchCount );
  880.             }
  881.         if ( usResult != ERROR_NO_MORE_SEARCH_HANDLES ) DosFindClose(hdir);
  882.         if (   (usResult && usResult != ERROR_NO_MORE_FILES)
  883.             || pData->fControl != CONTINUE )
  884.             {
  885.             DosEnterCritSec();
  886.             if ( pData->fControl == CONTINUE )
  887.                 {
  888.                 pData->fControl = ERROR;
  889.                 WinPostMsg( pData->hDlg,SEARCH_DONE,0L,MPFROMSHORT(usResult) );
  890.                 }
  891.             DosFreeSeg( SELECTOROF(pFindbuf) );
  892.             DosFreeSeg( SELECTOROF(pszSub) );
  893.             return FALSE;
  894.             }
  895.  
  896.         /* Done. Return to caller */
  897.         DosFreeSeg( SELECTOROF(pFindbuf) );
  898.         DosFreeSeg( SELECTOROF(pszSub) );
  899.         return TRUE;
  900.  
  901.         /* Executed by ABORT_CHK() macro if search is aborted */
  902. ABORT_EXIT:
  903.         DosEnterCritSec();
  904.         DosFindClose( hdir );
  905.         DosFreeSeg( SELECTOROF(pFindbuf) );
  906.         DosFreeSeg( SELECTOROF(pFindbuf2) );
  907.         return FALSE;
  908.  
  909.         #undef FINDCOUNT
  910.         #undef FILEFINDSIZE
  911.         #undef ABORT_CHK
  912.     }
  913. /****************************************************************************/
  914.