Click here to Skip to main content
15,867,991 members
Articles / Desktop Programming / Win32

The Explorer Imperative - Two Stage Search

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
4 Sep 2019CPOL52 min read 5.9K   165   4  
Least frequent character offset exact match algorithm used in GUI keyword search

The String found by U2Charfunc, shown in it 's full context in yhe Viewer Panel

The String found by U2Charfunc, shown in its full context in the Viewer Panel

Introduction: The Explorer Imperative Two Stage Search using the Least Frequent Character Offset

What Is the Least Frequent Character Offset and Why Should I Care?

The Least Frequent Character Offset is the position of LFC in a pattern you want to find. Any character in the pattern could be used but by using the LFC, it will be found much less often. With SSE SIMD Instructions, the compare can examine sixteen bytes at a time. The first character of the pattern must occur at the correct prefixed offset to the LFC or they will both disappear when the SIMD registers are 'ANDED' together. This means the SSE intrinsics can scan a file in 16 byte increments, finding only those instances of the LFC that are at the proper offset from a character that matches the first character of the pattern being searched for. When the LFC and the 'other ' character are found, then a string compare is executed to confirm or deny that a match has been found.

This program, U2Charfunc, was written to run on a machine that had only the SSE Instructions or possibly only the headers for SSE. I am not sure at this point, and I no longer have that machine but I know that someone does and they can still use this program. SSE2 has some additional instructions that make it a little faster, notably the _mm_and_si128 which allows anding the 16 bytes as bytes whereas SSE has only the _mm_and_ps which ands them as 32 bit floating point, so you can't use it to 'and' 2 16 byte SSE registers. In other words, you have to store them in an intermediate DWORD and use a '& ' to 'and ' the intermediate results. This makes a tighter loop and a faster search possible with SSE2, but it only works if you have the SSE2 Instruction Set.

The LFC Algorithm uses a Control String and a short preprocessing routine to determine the LFC in the pattern you supply. The Control String contains the characters of the alphabet arranged in the order of their frequency, most frequent to least frequent in 'C ' and 'C++' on my computer. They were counted by U2Charfunc. It will count characters, pairs of characters and strings, tested to a length of 64 characters. The preprocessing routine tries to find the last character in the LFCARRAY Control string in the search pattern. It scans backwards until a character is found. This is the Least Frequent Character. It is the OFFSET of this character in the search pattern that is the LFC Offset used in the scanning loop. Once the LFC and its Offset are found, the file is opened and read. There are separate routines for a single character, two character and more than two character patterns. The single character routine uses one SSE register and pops the count of occurrences. The two character routine uses two registers but it also pops the count. Neither of these routines requires a compare to verify the match.

In the three or more character routine, the (MEMORY) register is aligned on a 16 byte boundary and loaded aligned from the current file position, nWts. These 16 bytes are compared to a 16 bytes containing copies of the first character (of the pattern) to match, called fCtm, using _mm_cmpeq_epi8 and the resulting mask is moved to first character of match, fCom. Now memory is loaded from nWts plus the LFC Offset. This is compared to the 16 copies of the Least Frequent Character and the mask is moved to sCom, the second character to match. Now fCom and sCom are anded, causing any 1 bits that aren't matched to disappear. If the anded results are zero, nWts is increased by 16 and the window To scan, wTs, is loaded from nWts.

When the results of the AND operation are not zero, we use _BitScanForward to find the least significant bit that is set. This is the match Index or mIdx, which is added to nWts to get the address of a possible match. Here, we use a _memicmp function to do the compare and possibly increment a count. If you only wanted to know whether a file contained a string and didn't care about the number of times it contained it, you could just return a flag to indicate that it did or at the end of the program return a flag to indicate that it didn't.

Here Is the Code for U2Charfunc as a Standalone Program. The 'main() ' Function Is Commented Out.

The u2Charfunc Function

C++
// u2charFunc.c() loads the memory segments of the  'line ' buffer in
// sixteen byte increments in a 16 byte aligned SIMD Instruction and 
// compares each byte for equality with the least frequent character, 
// then it loads 16 bytes from an offset of the aligned address that 
// matches the offset of the second least frequent character from the
// first. The results are and-ed, eliminating any occurrence of either
// character which does not have an occurrence of the other at the proper
// offset. Since it jumps ahead 16 bytes at a time, it is fast. Also, 
// since it looks for the least frequent characters of the search string,
// it should be faster when the characters chosen are, indeed, less 
// frequently the other characters. The exact effect on the speed of a 
// search depends on the use of the proper control string and the specific
// string being searched for.
//

#include <intrin.h>
#include <stdio.h>

#define  MAXLINE   1024 * 4
#define  MAXPATH   260
#pragma warning( disable: 4706)

// unaligned two character scan function
int u2Charfunc ( CHAR * chBuf, char * pattern, int patlen ) {

  // Analyze search string and scan files in Listview 
  // Frequency Rank   -----------1---------2---------3---------4---------5-
  // most to least    0123456789012345678901234567890123456789012345678901 
  // frequent char    etroniaslcdpETSCmIRuLDAhOfPNgwMUbBFyWvGxVHkzKYXjQqZJ
  char lFcArray [ ] =  "etroniaslcdpETSCmIRuLDAhOfPNgwMUbBFyWvGxVHkzKYXjQqZJ ";
  int lfclen = ( int ) strlen ( lFcArray );
  int prefixLen;
  char lFcIndex = 0;
  char secLFcIndex = 0;
  char searchChar = 0;
  char searchChar2 = 0;
  char *p, *q, *r; p = q = r = 0;
  size_t j = 0;
  for ( int i = 1; i < lfclen; i++ ) {
    p = strrchr ( pattern, lFcArray [ lfclen - i ] );
    if ( p != 0 ) {
      lFcIndex = ( char ) ( p - pattern );
      searchChar = pattern [ lFcIndex ];
      j = ( size_t ) lfclen - i - 1;
      p = strchr ( pattern, searchChar );
      secLFcIndex = ( char ) ( p - pattern );
      searchChar2 = pattern [ secLFcIndex ];
      break;
    }
  }
  if ( secLFcIndex == lFcIndex ) {

    for ( size_t i = 0; i < j; i++ ) {
      p = strrchr ( pattern, lFcArray [ j - i ] );
      if ( p != 0 ) {
        secLFcIndex = ( char ) ( p - pattern );
        searchChar2 = pattern [ secLFcIndex ];
        break;
      }
    }
  }

  char  scanChar = searchChar;
  char scanChar2 = searchChar2;
  prefixLen = lFcIndex;
  int charOffset = -prefixLen;
  int maskOffset = secLFcIndex - lFcIndex;

  HANDLE  hSearch;
  char * line = NULL;
  char searchFile [ 260 ];
  int numfound = 0;
  scanChar = pattern [ lFcIndex ];
  scanChar2 = pattern [ secLFcIndex ];
  charOffset = -lFcIndex;
  maskOffset = secLFcIndex - lFcIndex;

  int totBytes = 0;
  p = strchr ( chBuf,  '\r ' );
  if ( p ) *p =  '\0 ';
  memset ( &searchFile, 0, sizeof ( searchFile ) );
  sprintf_s ( searchFile, 260,  "%s ", chBuf );
  numfound = 0;
  BOOL bResult = FALSE;
  DWORD nbytesToRead = 1024 * 64;
  DWORD nbytesRead = 0;
  hSearch = CreateFileA ( searchFile, GENERIC_READ, FILE_SHARE_READ, NULL,
              OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
  if ( hSearch == INVALID_HANDLE_VALUE ) {
    DWORD dwErr = GetLastError ( );
    if ( dwErr != 0 && dwErr != 5 && dwErr != 32 && dwErr != 2 ) {
      MessageBoxA ( 0, searchFile,  "Can 't Create File: ", MB_OK | MB_ICONEXCLAMATION );
      return -1;
    }
  }
  else {
    unsigned long maxLen = 0;
    LARGE_INTEGER  maxLenQ;
    PLARGE_INTEGER  maxLenL = &maxLenQ;
    maxLenL->QuadPart = 0;
    GetFileSizeEx ( hSearch, maxLenL );
    if ( maxLenL == 0 )
      return 0;
    maxLen = ( LONG ) maxLenL->QuadPart;
    if ( maxLen > 1024 * 1024 - 1024 ) {
      nbytesToRead = 1024 * 1024 - 1024;
      maxLen -= 1024 * 1024 - 1024;
    }
    else
      nbytesToRead = ( DWORD ) maxLenL->QuadPart;
    line = ( char * ) calloc ( ( size_t ) 
            nbytesToRead + 1024, 1 ); // Buffer the buffer - doubled buffered
    errno_t nErr;
    _get_errno ( &nErr );
    if ( patlen != 0 ) {
      bResult = ReadFile ( hSearch, &line [ 16 ], nbytesToRead, &nbytesRead, NULL );
      while ( bResult &&  nbytesRead != 0 ) {
        int numRead = nbytesRead;
        if ( numRead != 0 ) {
          totBytes += nbytesRead;
          numRead = nbytesRead;
          if ( patlen == 1 ) {
            // Next Window to Scan
            char * nWts = line + 16;
            //Match InDeX
            //unsigned long mIdx = 0ul;
            // The Window to Scan
            __m128i       wTs;
            // First Character To Match
            __m128i       fCtm = _mm_set1_epi8 ( *pattern );
            // Comparison flags to be moved to fcom
            __m128i       tempMask;

            // First Character of Match
            unsigned  fCom = 0;;
            // Scan Matches
            // Alignment Offset
            unsigned      aO = 15 & ( UINT_PTR ) nWts;
            nWts -= aO;        // align the buffer
            // Pointer To Matches 
            wTs = _mm_load_si128 ( ( __m128i const * )nWts );
            while ( 1 ) {
              tempMask = _mm_cmpeq_epi8 ( fCtm, wTs );
              fCom = _mm_movemask_epi8 ( tempMask );
              numfound += __popcnt ( fCom );
              if ( numRead <= 0 )
                break;
              nWts += 16;
              wTs = _mm_load_si128 ( ( __m128i const * )nWts );
              numRead -= 16;
            }
          }
          else if ( patlen > 1 ) {
            if ( numRead == 4096 ) {
              SetFilePointer ( hSearch, -( patlen - 1 ),
                       NULL, FILE_CURRENT );
            }
            if ( patlen == 2 ) {
              char * nWts = line + 16;  // Next Window to Scan
              __m128i       wTs;        // The Window to Scan
              // First Character To Match
              __m128i       fCtm = _mm_set1_epi8 ( scanChar );
              // Second Character To Match
              __m128i       sCtm = _mm_set1_epi8 ( scanChar2 );

              unsigned  fCom = 0;  // First Character of Match
              unsigned  sCom = 0;  // Second Character of Match
              unsigned    sM = 0;  // Scan Matches

              // Alignment Offset
              unsigned      aO = 15 & ( uintptr_t ) nWts;
              nWts -= aO;        // align the buffer
              wTs = _mm_load_si128 ( ( __m128i const * ) nWts );
              while ( 1 ) {
                //#pragma warning( disable: 4706)
                if ( ( fCom = _mm_movemask_epi8 ( _mm_cmpeq_epi8 ( fCtm, wTs ) ) != 0 ) ) {
                  wTs = _mm_loadu_si128 ( ( __m128i const * )( nWts + maskOffset ) );
                  //#pragma warning( disable: 4706 )
                  if ( ( sCom = _mm_movemask_epi8 ( _mm_cmpeq_epi8 ( sCtm, wTs ) ) != 0 ) ) {
                    sM = fCom & sCom;
                  }
                  if ( sM ) {
                    numfound += __popcnt ( sM );
                  }
                }
                if ( numRead <= 0 )
                  break;
                nWts += 16;
                wTs = _mm_load_si128 ( ( __m128i const * ) nWts );
                numRead -= 16;
              }
            }
            else if ( patlen > 2 ) {
              // Next Window to Scan
              char * nWts = line + 16;
              //Match InDeX
              unsigned long mIdx = 0ul;
              // The Window to Scan
              __m128i       wTs;
              // First Character To Match
              __m128i       fCtm = _mm_set1_epi8 ( scanChar );
              // Second Character To Match
              __m128i       sCtm = _mm_set1_epi8 ( scanChar2 );
              // Comparison flags to be moved to fcom and scom
              __m128i       tempMask;

              // First Character of Match
              unsigned  fCom = 0;;
              // Second Character of Match
              unsigned  sCom = 0;
              // Scan Matches
              unsigned      sM = 0;
              // Alignment Offset
              unsigned      aO = 15 & ( uintptr_t ) nWts;
              nWts -= aO;        // align the buffer
              // Pointer To Matches 
              char const* pTm = NULL;
              wTs = _mm_load_si128 ( ( __m128i const * )nWts );
              while ( 1 ) {
                tempMask = _mm_cmpeq_epi8 ( fCtm, wTs );
                fCom = _mm_movemask_epi8 ( tempMask );
                wTs = _mm_loadu_si128 ( ( __m128i const * )( nWts + maskOffset ) );
                tempMask = _mm_cmpeq_epi8 ( sCtm, wTs );
                sCom = _mm_movemask_epi8 ( tempMask );
                sM = fCom & sCom;
                while ( sM ) {
                  _BitScanForward ( &mIdx, sM );
                  pTm = nWts + mIdx + charOffset; //address of a possible match
                  if ( !_memicmp ( pTm, pattern, patlen ) ) {
                    numfound++;
                  }
                  sM &= sM - 1;
                }
                nWts += 16;
                if ( numRead <= 0 )
                  break;
                numRead -= 16;
                wTs = _mm_load_si128 ( ( __m128i const * )nWts );
              }
            }
          }
          memset ( &line [ 16 ], 0, nbytesRead );
          bResult = ReadFile ( hSearch, &line [ 16 ], nbytesToRead, &nbytesRead, NULL );
        }
      }
    }
  }
  CloseHandle ( hSearch );
  free ( line );
  return numfound;
}
/* 
// To run u2charfunc as a stand-alone program, you need 
// a main function, similarto the one below but when you
// call it as a subroutine,  you must pass the pattern
// length as the third parameyer.
int main ( int argc, char *argv [ ] ) {
  char * path [ 260 ] = { 0 };
  char * pattern [ 64 ] = { 0 };
  int patlen = 0;
  // Verify correct number of args (exename filename string2search4
  if ( argc != 3 ) {
    printf_s (  "Usage: lfcMatch.exe  <path\file> <pattern>\n " );
    // Copy args 
    //strcpy ( pattern, tPattern );
    //strcpy ( path, tPath );
    return 0;
  }
  else {
    // Copy args
    patlen = sprintf_s ( path, 260,  "%s ", *++argv );
    if ( 260 < patlen ) {
      printf_s (  "Path is too long \n " );
    }
    patlen = sprintf_s ( pattern, 64,  "%s ", *++argv );
  }
  int retnum = u2Charfunc ( path, pattern, patlen );
  printf_s (  "Found %s %d times\n ", pattern, retnum );
  return retnum;
}
*/

This program, U2Charfunc, is the reason for this article. But I realize that only those developers that have a pre-existing interest in string matching techniques will find this of interest. Therefore, I have included a short windows program to demonstrate a possible use of this program.

Background

Why another find utility? Simple. I don't like the ones I have available. I have tried many different products and I can 't find the one I need. There may be times when I need one of them and their capabilities but primarily I want to find a keyword and the context in which it is used. Most of the time, I want to see how I used it in my own code or maybe how someone else used it. I need this when I read the Visual Studio Documentation, which says can't find requested topic, or sometimes when it can find requested topic. I need it to not take my focus away from what I am trying to do. I don't want to take 30 minutes to figure out how to use it. I have tried to provide these features while trying to not let the program grow to large.

But This Is a Batch Program! What's It Got to Do With Windows?

This can only be a Batch program if you uncomment the 'main()' function. Otherwise, it is a function in a Windows program. U2Charfunc is not called by 'main()' in a Windows program, instead it is called by the findStringInAllFiles() function. This function takes no arguments and returns a BOOL. The pattern to find is taken from the Environment Variable 'FSIAF', which is the acronym for 'Find string in all files '. The File Name and Path are retrieved from the currently selected item in the List View. The pattern length is determined by _snprintf_s as the number of characters copied from fsiaf to pattern. It gets the first path, which is the current item in ListView. Then gets the item count and loops through the ListView item count times, getting the next path, setting the window text for the main window and Edit Box and calling u2Charfunc(path, pattern, patlen). If the return value is greater than zero, the 'OCCURS' Column in the ListView is updated with the count. Then it gets the next Item's path and peeks at the message queue so that the user won't cause the program to become un-responsive by attempting to multi-task. Then we loop until all of the items have been searched. When the loop finishes, the current item in the ListView is the same as it was in the beginning. We send an F5 key to the ListView, causing it to search the 'Occurs' Column for the first file after the current one to contain an occurrence.

findStringInAllFiles() Function

C++
//////////////////////////////////////////////
//
// findStringInAllFiles() analyzes the Search String to find the Least Frequent
// and Second Least Frequent characters using a Control String that is specific
// to the C and C++ Language, based on the C++ files on My Computer. It then calls 
// U2CharFunc() on each file in the ListView File Set to count the occurrences
// of the Search String, if any. After each file is scanned, the message queue
// is peeked and dispatched to animate the progress bar and retain the windows 
// responsiveness.
//
////////////////////////////////////////////
BOOL findStringInAllFiles ( ) {
  # pragma region Initialize_Storage
  TCHAR searchCap [ 256 ]; // The Window Caption for Search Function
  TCHAR curntFname [ 256 ];
  TCHAR curntPath [ MAX_PATH ];
  int hits = 0;
  memset ( &curntFname, 0, sizeof ( curntFname ) );
  memset ( &curntPath, 0, sizeof ( curntPath ) );
  TCHAR curntHitCount [ 256 ];
  int result;
  CHAR chBuf [ 4096 ];
  memset ( &chBuf, 0, sizeof ( chBuf ) );
  char pattern [ MAX_PATH ];
  TCHAR fsiaf [ 256 ] = { 0 };  // Find this String In A File
  GetEnvironmentVariable ( L "FSIAF ", fsiaf, 255 );
  int patlen = _snprintf_s ( pattern, 255, 255,  "%S ", fsiaf );
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
  HWND hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );

  int startPos = -1, endPos = 0;
  SendMessage ( hEdit, EM_SETSEL, ( WPARAM ) &startPos, ( LPARAM ) &endPos );

  # pragma endregion findStringInAllFiles(...)  
  SetFocus ( hEdit );
  StringCchPrintf ( searchCap, 255, L "Searching for %s in ALL listed files. ", fsiaf );
  SetWindowText ( hMainWnd, searchCap );
  int iCount = ListView_GetItemCount ( hList );
  for ( int i = 0; i < iCount; ++i ) {
    memset ( &curntPath, 0, sizeof ( curntPath ) );
    memset ( &curntFname, 0, sizeof ( curntFname ) );
    // Get column one text string
    ListView_GetItemText ( hList, i, 0, curntFname, MAX_PATH - 1 );
    // Get column three text string
    ListView_GetItemText ( hList, i, 2, curntPath, MAX_PATH - 1 );
    memset ( &chBuf, 0, sizeof ( chBuf ) );
    // either of the following 2 lines can be used because u2Charfunc
    // changes backslash r to backslash zero
    sprintf_s ( chBuf, 4096,  "%S\\%S\r\n ", curntPath, curntFname );
    curntPath [ 259 ] = 0;
    SetWindowText ( hMainWnd, curntPath );
    SetWindowText ( hEdit, curntPath );
    int numbFound = u2Charfunc ( chBuf, pattern, patlen );

    if ( numbFound > 0 ) {
      hits++;
      StringCchPrintf ( curntHitCount, 255, L "%d occurrences of  '%s '. ", numbFound, fsiaf );
      LVITEM lvi;
      int ret = i;
      memset ( &lvi, 0, sizeof ( lvi ) );
      lvi.mask = LVIF_TEXT;
      lvi.iItem = ret;
      lvi.iSubItem = 1;
      lvi.cchTextMax = 255;
      lvi.pszText = curntHitCount;
      ListView_SetItem ( hList, &lvi );
      ListView_SetItemState ( hList, i, LVIS_SELECTED, LVIS_SELECTED );
      ListView_EnsureVisible ( hList, i, TRUE );
      MSG msg;
      while ( PeekMessage ( &msg, NULL, 0, 0, PM_REMOVE ) ) {
        DispatchMessage ( &msg );
      }
    }
  } //endfor
  result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
  if ( result == -1 )
    result = 0;
  ListView_SetItemState ( hList, result, LVIS_SELECTED, LVIS_SELECTED );
  StringCchPrintf
  ( searchCap, 255,
    L "Searched %d Files, Found %d files containing 1 or more occurrences of  '%s '. ",
    iCount, hits, fsiaf );
  SetWindowText ( hMainWnd, searchCap );
  SetWindowText ( hEdit, searchCap );
  ListView_SetItemState ( hList, -1, 0, LVIS_SELECTED );
  ListView_SetItemState ( hList, result, LVIS_SELECTED, LVIS_SELECTED );
  HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
  StringCchPrintf ( searchCap, 255, L "%d Files with matches. ", hits );
  SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) searchCap );
  sendMeMyKey ( hList, VK_F5 );
  return 1;
}

Putting the File Name in the ListView

Selecting or Entering the extensions for the File List.

Putting the File Name and Path into the ListView: recursivefileSearch() Function

Most developers have a primary language in which they code most of their work. This suggests they might want a 'default' type of file. We don't know what that is in advance, so the initial 'default ' is set to "*.cpp;*.c". This will result in the ListView being filled with files having the extensions 'cpp' and 'c', with the root folder being the %USERPROFILE% Environment Variable. Both of these 'defaults' can be changed and the new value will be stored in the registry using the setx function. The set of extensions is selected or entered using the combo box on the left. The user can click on the dropdown row he wants or the EditCtrl and type in their choice, then push ENTER or click the START Button on the left.

In the screen print above, the combo box dropdown shows a long string of extensions preceded by an asterisk and a period and separated by semicolons. The semicolon is necessary when more than one extension is used. The asterisk must be used unless you are searching for a specific title or suffix, such 'the Wind' might find 'Gone With the Wind' but not find 'The Wind blows Cold' because it looks at the ending of the argument. These three cases are handled by three different routines which are recursive. Since the cases can be differentiated by the presence of a semicolon and asterisk, we use a non recursive function to dispatch them. This makes the logic much simpler for the individual case but does require more code. Here is the code for the non recursive 'recursiveFileSearch' function.

Choosing the Right Recursive File Search

The recursivefileSearch Function

C++
// analyze search request string and dispatch recursivefileSearch functions accordingly
int recursivefileSearch ( TCHAR *name, BOOL hidden ) {
  TCHAR searchStr [ MAX_PATH ] = { 0 };
  GetEnvironmentVariable ( L "SEARCHSTR ", searchStr, 255 );
  if ( ( wcschr ( searchStr, L '* ' ) == NULL ) ) {
    recursivefileSearch1 ( name, searchStr, hidden );
    return 0;
  }
  else    if ( wcschr ( ( LPWSTR ) searchStr, L '; ' ) != NULL ) {
    recursivefileSearch2 ( name, searchStr, hidden );
    return 0;
  }
  recursivefileSearch3 ( name, searchStr, hidden );
  return 0;
}

Looking for a Matching Suffix: recursivefileSearch1

Now, the criteria has been established to build the File List for the ListView. We are just entering the function but we don't know how many times we have already been here. Since it could have been a while, we peek at the message queue to make sure we remain responsive. This is in a loop so we don't need to loop de loop. We make sure the path has a backslash on the end and add an '*' to the ending. We create a handle to a find with FindFirstFileExW. This fills a structure with information about the initial findings. If this is a file, we compare the suffix of the filename with our argument. If it matches, we put it in the ListView. If it's a dot or dot dot, we ignore it. When it's a directory, we add the directory to the end of the path and put the path in the Title of the main window and the Edit Box. Then we call recursivefileSearch1. We do this until FindNextFile returns a zero instead of new information from the handle to the hFind. Here's the code for the recursivefileSearch1 function.

The recursivefileSearch1 Function

C++
// FUNCTION: Find all files whose name contains the search argument.
// Does not search hidden directories. This results in a significant 
// increase in speed. Pattern is assumed to be a suffix. It can be any
// reasonable length, so it is not limited to extensions. It can not 
// contain wildcards. The pattern is compared to the end of the file
// name to identify files to list.
int recursivefileSearch1 ( TCHAR *name, TCHAR * searchStr, BOOL hidden ) {
  WIN32_FIND_DATA ffd;
  HANDLE hFind = INVALID_HANDLE_VALUE;
  DWORD dwError = 0, addcount = 0;
  TCHAR recursiveSearchPath [ MAX_PATH ], text [ 32 ];
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
  HWND hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
  MSG msg;
  while ( PeekMessage ( &msg, NULL, 0, 0, PM_REMOVE ) )
    DispatchMessage ( &msg );

  if ( name [ wcslen ( name ) - 1 ] != L '\\ ' ) {
    // Prepare string for use with FindFile functions.  First, copy the
    // string to a buffer, then append  "\* " to the directory name. 
    wsprintf ( recursiveSearchPath, L "%s\\* ", name );
  }
  else {
    wsprintf ( recursiveSearchPath, L "%s* ", name );
  }

  // Find the first file in the directory.
  hFind = FindFirstFileExW ( recursiveSearchPath, FindExInfoBasic, 
          &ffd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH );

  // List all the files in the directory with some info about them.
  do {
    if ( hFind == INVALID_HANDLE_VALUE )
      // Done checking this folder
      // no files were found in this recursion
      return -1;

    int fnlen = ( int ) wcslen ( ffd.cFileName );
    int extlen = ( int ) wcslen ( searchStr );
    if ( ( wcscmp ( ffd.cFileName, L ". " ) ) == 0
       || ( wcscmp ( ffd.cFileName, L ".. " ) ) == 0 ) {
      ;  //If the file is a self-reference do nothing
    }
    else  if ( ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN && !hidden ) {
      ;    // the file is hidden and hidden search is turned off
    }
    else if ( !( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
      if ( wcsncmp ( ffd.cFileName + fnlen - extlen, searchStr, extlen ) == 0 ) 
      { // it is a FILE containing the argument, put it in the list
        LVITEM item;
        memset ( &item, 0, sizeof ( item ) );
        item.mask = LVIF_TEXT;
        item.iItem = 0;
        item.iSubItem = 0;
        item.cchTextMax = 260;
        item.pszText = ffd.cFileName;
        ListView_InsertItem ( hList, &item );
        item.iSubItem = 2;
        item.pszText = name;
        ListView_SetItem ( hList, &item );
        wsprintf ( text, L "%I64u ", ( ( ULONGLONG ) 
        ( ffd.nFileSizeHigh ) * ( ( ULONGLONG ) MAXDWORD + 1 ) ) + ffd.nFileSizeLow );
        item.iSubItem = 3;
        item.pszText = text;
        ListView_SetItem ( hList, &item );
      }
    }
    else if ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { // it is a directory
      if ( name [ wcslen ( name ) - 1 ] != L '\\ ' ) {
        wsprintf ( recursiveSearchPath, L "%s\\%s ", name, ffd.cFileName );
      }
      else {
        wsprintf ( recursiveSearchPath, L "%s%s ", name, ffd.cFileName );
      }
      SetWindowText ( hEdit, recursiveSearchPath );
      addcount = ListView_GetItemCount ( hList );
      TCHAR tStr [ MAX_PATH ] = { 0 };
      StringCchPrintf ( tStr, MAX_PATH - 1, L "[%d] %s ", addcount, recursiveSearchPath );
      SetWindowText ( hMainWnd, tStr );
      recursivefileSearch1 ( recursiveSearchPath, searchStr, hidden ); // search this one too
    }
  }
  while ( FindNextFile ( hFind, &ffd ) != 0 );

  dwError = GetLastError ( );
  if ( dwError != ERROR_NO_MORE_FILES )
    if ( dwError != ERROR_ACCESS_DENIED ) {
      // set the text in IDC_EDIT2
      SetWindowText ( hEdit, L "Error in Find File Routine ! " );
    }

  FindClose ( hFind );
  return dwError;
}

Putting the File Name in the ListView

Progress Bar covering combo boxes as recursiveFileSearch fills ListView

Listing Multiple Extensions:recursivefileSearch2()

The recursivefileSearch2() function is very similar to recursivefileSearch1. But there is one major difference. recursivefileSearch1 compares the argument with the end of the file name whereas recursivefileSearch2 uses the PathMatchSpec function to determine if the filename extension is in the arguments set of extensions. If it is, it is added to the File List. Since everything else is the same, the code block is not shown here.

Splitting the Recursion:recursivefileSearch3

When there is only one extension and there is an asterisk in the argument, we can tell the FindFirstFileExW function we only want to see files with this extension and no directories, by using the FindExSearchNameMatchflag in the FINDEX_SEARCH_OPS field. Then we loop through the results, putting them all in the File List, until FindNextFile returns zero. Then we call FindFirstFileExW again, this time using FindExSearchLimitToDirectories as in the FINDEX_SEARCH_OPS parameter to recurse through the directories. Since the logic is quite different, I will present it in its entirety. And here it is...

The recursivefileSearch3 Function

C++
// FUNCTION: Find all files whose name contains the search argument.
// Does not search hidden directories. This results in a significant 
// increase in speed. The pattern may contain wildcards. The 
// FindExSearchNameMatchflag is used to identify files to list. 
// After FindExSearchNameMatchflag processing is completed then 
// the FindExSearchLimitToDirectories as is used to recursively search
// through the subdirectories.
int recursivefileSearch3 ( TCHAR *name, TCHAR * searchStr, BOOL hidden ) {
  WIN32_FIND_DATA ffd;
  HANDLE hFind = INVALID_HANDLE_VALUE;
  DWORD dwError = 0;
  TCHAR recursiveSearchPath [ MAX_PATH * 2 ], text [ 32 ];
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1);
  HWND hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
  MSG msg;
  while ( PeekMessage ( &msg, NULL, 0, 0, PM_REMOVE ) )
    DispatchMessage ( &msg );
  if ( name [ wcslen ( name ) - 1 ] != L '\\ ' ) {
    // Prepare string for use with FindFile functions.  First, copy the
    // string to a buffer, then append  "\* " to the directory name. 
    wsprintf ( recursiveSearchPath, L "%s\\*%s ", name, searchStr );
  }
  else {
    wsprintf ( recursiveSearchPath, L "%s* ", name );
  }

  // Find the first file in the directory.
  hFind = FindFirstFileExW ( recursiveSearchPath, FindExInfoBasic, &ffd,
                 FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH );

  if ( hFind != INVALID_HANDLE_VALUE ) {
    // List all the files in the directory with some info about them.
    do {
      LVITEM item;
      memset ( &item, 0, sizeof ( item ) );
      item.mask = LVIF_TEXT;
      item.iItem = 0;
      item.iSubItem = 0;
      item.cchTextMax = 260;
      item.pszText = ffd.cFileName;
      ListView_InsertItem ( hList, &item );
      item.iSubItem = 2;
      item.pszText = name;
      ListView_SetItem ( hList, &item );
      wsprintf ( text, L "%I64u ", ( ( ULONGLONG ) 
      ( ffd.nFileSizeHigh ) * ( ( ULONGLONG ) MAXDWORD + 1 ) ) + ffd.nFileSizeLow );
      item.iSubItem = 3;
      item.pszText = text;
      ListView_SetItem ( hList, &item );
    }
    while ( FindNextFile ( hFind, &ffd ) != 0 );

    dwError = GetLastError ( );
    if ( dwError != ERROR_NO_MORE_FILES )
      if ( dwError != ERROR_ACCESS_DENIED ) {
        // set the text in IDC_EDIT2
        SetWindowText ( hEdit, L "Error in Find File Routine ! " );
      }
    FindClose ( hFind );
  }

  if ( name [ wcslen ( name ) - 1 ] != L '\\ ' ) {
    // Prepare string for use with FindFile functions.  First, copy the
    // string to a buffer, then append  "\* " to the directory name. 
    wsprintf ( recursiveSearchPath, L "%s\\* ", name );
  }
  else {
    wsprintf ( recursiveSearchPath, L "%s* ", name );
  }
  // Find the first file in the directory.
  hFind = FindFirstFileExW ( recursiveSearchPath, FindExInfoBasic, &ffd,
                 FindExSearchLimitToDirectories, NULL, FIND_FIRST_EX_LARGE_FETCH );
  do {
    if ( hFind == INVALID_HANDLE_VALUE )
      // Done checking this folder
      // no files were found in this recursion
      return -1;

    if ( ( wcscmp ( ffd.cFileName, L ". " ) ) == 0
       || ( wcscmp ( ffd.cFileName, L ".. " ) ) == 0 ) {
      ;  //If the file is a self-reference do nothing
    }
    else  if ( ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN && !hidden ) {
      ;    // the file is hidden and hidden search is turned off
    }
    else if ( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { // it is a directory
      if ( name [ wcslen ( name ) - 1 ] != L '\\ ' ) {
        wsprintf ( recursiveSearchPath, L "%s\\%s ", name, ffd.cFileName );
      }
      else {
        wsprintf ( recursiveSearchPath, L "%s%s ", name, ffd.cFileName );
      }
      SetWindowText ( hMainWnd, recursiveSearchPath );
      SetWindowText ( hEdit, recursiveSearchPath );

      recursivefileSearch3 ( recursiveSearchPath, searchStr, hidden ); // search this one too
    }
  }
  while ( FindNextFile ( hFind, &ffd ) != 0 );

  dwError = GetLastError ( );
  if ( dwError != ERROR_NO_MORE_FILES ) {
    if ( dwError != ERROR_ACCESS_DENIED ) {
      // set the text in IDC_EDIT2
      SetWindowText ( hEdit, L "Error in Find File Routine ! " );
    }
  }
  FindClose ( hFind );
  return dwError;
}

Selecting or Entering a String to Search For: ComboBox2

The irratating meddagebox that you can get rid of. ...forever

When you change the Directory, Extension or string to search for, this message box is displayed.

When you see this message box, there is a checkbox on the lower left corner of the message box. If the checkbox is checked, the message box will no longer be displayed. The method to recover the message box will be discussed later. Currently, all three of these message boxes use the same GUID to control the state of the Checkbox. The message box is purely informational, since the function used (SETX) returns the same result even if it fails. There is additional error checking to inform the user if the data was not saved. The most likely time for this function to fail is the very first attempt of the day and will only matter if it is the last attempt. since only the last value set is the one retrieved.

The not irratating meddagebox that you see whem the data is not saved.

When you change the Directory, Extension or string to search for, and the data is not saved, this message box is displayed.

Selecting the combobox EditCtrl on the RIGHT and Pushing ENTER will Retrieve the Last Value SAVED. Clicking the DROPDOWN Triangle Will Show the Values Entered Today

Entering a string to search for or using the Dropdown

With the selected string in the EditCtrl, pushing ENTER has the same effect as clicking on the Start Search Button.

Both ComboBoxes are subclassed in the same comboBoxSubClassProc function. It's a very simple function. The first thing it does is get the window handles for the main window and IDC_BTN1 and IDC_BTN2. When uMsg is WM_KEYDOWN and wParam is VK_RETURN, it is known that it is coming from the child of a combobox, so it gets the parent combobox, which it uses to GetDlgCtrlID to differentiate between the two ComboBoxes and sends a BM_CLICK message to the corresponding Button. This clicks the button and initiates the requested function. It also processes WM_KEYUP and WM_CHAR for WM_KEYUP by returning zero. Everything is returned to the DefSubclassProc function.

Handling the Enter Key: comboBoxSubClassProc

The comboBoxSubClassProc Function

C++
// The Combobox was subclassed to make Buttons respond to EDITCTRL Enter Key 
// press as if Button was clicked. User can either click Button or, since they
// are typing in the EditCtrl,  they can just press Enter.
LRESULT CALLBACK comboBoxSubClassProc ( HWND hWnd, UINT uMsg, WPARAM wParam, 
  LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) {
  UNREFERENCED_PARAMETER ( uIdSubclass );
  UNREFERENCED_PARAMETER ( dwRefData );
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hBtn1 = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_BUTTON1 );
  HWND hBtn2 = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_BUTTON2 );
  
  switch ( uMsg ) {

  case WM_KEYDOWN:
    switch ( wParam ) {
    case VK_RETURN:
      HWND hComBo = GetParent ( hWnd );
      ULONG dlgId = GetDlgCtrlID ( hComBo );
      if ( dlgId == IDC_COMBO1 ) {
        SetActiveWindow ( hBtn1 );
        SendMessage ( hBtn1, BM_CLICK, 0, 0 );
        return 1;
      }
      if ( dlgId == IDC_COMBO2 ) {
        SetActiveWindow ( hBtn2 );
        SendMessage ( hBtn2, BM_CLICK, 0, 0 );
        return 1;
      }
    }
    break;

  case WM_KEYUP:
  case WM_CHAR:
    switch ( wParam ) {
    case  VK_RETURN:
      return 0;
    }
  default:
    return DefSubclassProc ( hWnd, uMsg, wParam, lParam );
  }
  return 0;
}

Handling the Input and Life-Cycle of Data: The Comboboxproc Function

The String found by U2Charfunc, shown in it 's full context in yhe Viewer Panel

The String found by U2Charfunc, shown in its full context in the Viewer Panel

The Extension in ComboBox1, the 'string to search for ' and the File It was Found in

The comboBoxProc function processes the user input for the TwoStageSearch. Before the 'message' switch, it determines if the message is not WM_INITDIALOG so it can retrieve the handles to all of the windows that WM_INITDIALOG has created. The reason this is done is a constant cannot be used twice in case statements. By using WM_INITDIALOG in an 'if' construct, it can still be used in a switch case.

The handle for ComboBox1, hCombo1 is used to prevent the initialization of some items until all items are ready for it. After the hCombo1 handle has been initialized in WndProc, everything else can be done. We get the Combobox Info and SetWindowSubclass for the proc. This is the new process for sub-classing a control. As was shown previously, we are only processing the Return Key to generate a Mouse Click of a Button. The first Combo Box will generate a mouse click for the 'Start File List Build' Button. Next, we fill the Combo Box drop down List with some possible choices for the Set of Extensions for the build and initialize the Cue Banner for the Combo Box. For ComboBox2, we do the same things except for the drop down List which we leave empty. Next, we give the controls an initial size and move them into the initial position. The Progress Bar is positioned to cover the Comboxes but is hidden.

In the WM_COMMAND message we process the wmId switch, the first case is IDC_BUTTON1. Here, we respond to the BM_CLICK message by getting the text of the Combobox EditCtrl. If it's non- blank, it is added to the drop down List, otherwise, the extension set used last time is retrieved and placed in the EditCtrl and zero is returned. In other words, if the EditCtrl is empty and the CUE is displayed, when the user clicks on the EditCtrl or clicks the button on the left, the previous value is placed in the EditCtrl. If there is a value in the EditCtrl, it is compared to the previous extension set and if they are different, the new value is saved in the Registry by calling the persist_This function. Either way, the Progress Bar is activated to cover the ComboBoxes and prevent user multi-tasking, the status bar is updated and the recursivefileSearch is called to Build the File List. When it returns, the status bar is updated, the Progress Bar is hidden and the current file is selected.

Also in the wmId switch, the next case is IDC_COMBO1. The only event we respond to is CBN_EDITUPDATE. We get the text of the EditCtrl and check the first character, if it's a question mark, we blank out the field and set the CUE Banner. The processing for IDC_COMBO0 is the same as for IDC_COMBO1. IDC_BUTTON2 handles BM_CLICK in the same way as IDC_BUTTON1 but calls the findStringInAllFiles function instead of the recursivefileSearch function.

The WM_SIE message gets the position and size for all of the controls in the hFormView container and moves them to their proper positions. The only problem child(window) was ComboBox2. If I used the size from the GetWindowRect function, it would sometimes show the combobox button, and sometimes it wouldn't show it. In full screen, it always showed it but I don't think it would be reasonable to ask a user to go full screen when they wanted to click the drop down triangle. To make sure the drop down button was always displayed, I chose to make it a static value unless it was full screen, in which case I used the GetWindowRect values.

The comboBoxProc Function

C++
// Subclass the proc to handle vk_return to simulate button click.
// Input string2search4 and file list Extension Set. Persist environment
// variables on input invoke File list Build or Find string in all files.
INT_PTR CALLBACK comboBoxProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
  UNREFERENCED_PARAMETER ( lParam );
  TCHAR searchStr [ 256 ] = { 0 };
  int wmId, wmEvent;
  static HWND hwndEdit1, hwndEdit2;
  HWND hEdit = NULL, hMainWnd = NULL, hCombo1 = NULL, hCombo2 = NULL, hProgress = NULL,
    hStrtBild = NULL, hStrtSrch = NULL, hList = NULL;
  RECT bRc1 = { 0 }, bRc2 = { 0 }, cRc1 = { 0 }, cRc2 = { 0 }, dRc = { 0 }, pRc = { 0 };
  RECT bRccl1 = { 0 }, bRccl2 = { 0 }, cRccl1 = { 0 }, 
                       cRccl2 = { 0 }, dRccl = { 0 }, pRccl = { 0 };

  if ( WM_INITDIALOG != message ) {

    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    if ( 0 == hMainWnd ) {  return 0;}
    hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
    if ( 0 == hEdit ) {    return 0;  }
    hCombo1 = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_COMBO1 );
    if ( 0 == hCombo1 ) {return 0;  }
    hCombo2 = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_COMBO2 );
    if ( 0 == hCombo2 ) {  return 0;}
    hProgress = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_PROGRESS1 );
    if ( 0 == hProgress ) {  return 0;}
  }

  switch ( message ) {

  case WM_INITDIALOG:
  {
    hCombo1 = getThisWindowHandle ( hDlg, IDC_COMBO1 );
    if ( 0 != hCombo1 )
    {
      hStrtBild = GetDlgItem ( hDlg, IDC_BUTTON1 );
      hCombo1 = GetDlgItem ( hDlg, IDC_COMBO1 );
      COMBOBOXINFO cbi = { 0 };
      cbi.cbSize = { sizeof ( COMBOBOXINFO ) };
      GetComboBoxInfo ( hCombo1, &cbi );
      hwndEdit1 = cbi.hwndItem;
      SetWindowSubclass ( hwndEdit1, comboBoxSubClassProc, ( UINT_PTR ) IDC_COMBO1, 0 );
      DWORD dwErr = GetLastError ( );
      // Add strings to combobox.
      TCHAR szComboText [ ] [ 64 ] = { L "*.cpp;*.c;*.cs;*.fs;*.fsx;*.htm;*.html;*.xaml;
      *.xml ",L "*.cs ",L "*.vb ",L "*.c ",
      L"*.fsx;*.fs",L"*.pdf",L"*.txt" };
      int nItemCount = 7;
      for ( int i = 0; i < nItemCount; i++ ) {
        SendMessage ( hCombo1, ( UINT ) CB_ADDSTRING, 
                    ( WPARAM ) 0, ( LPARAM ) szComboText [ i ] );
        dwErr = GetLastError ( );
      }
      // set the CUE Banner for the ComboBox
      SendMessage ( hCombo1, ( UINT ) CB_SETCUEBANNER, ( WPARAM ) 0,
        ( LPARAM ) L "Type any part of filename or 
        select extension from the drop down list below. " );
      dwErr = GetLastError ( );
      hStrtSrch = GetDlgItem ( hDlg, IDC_BUTTON2 );
      dwErr = GetLastError ( );

      hCombo2 = GetDlgItem ( hDlg, IDC_COMBO2 );
      GetComboBoxInfo ( hCombo2, &cbi );
      hwndEdit2 = cbi.hwndItem;
      SetWindowSubclass ( hwndEdit2, comboBoxSubClassProc, ( UINT_PTR ) IDC_COMBO2, 0 );
      dwErr = GetLastError ( );
      // set the CUE Banner for the ComboBox
      //SendMessage ( hCombo2, ( UINT ) CB_SETEXTENDEDUI, ( WPARAM ) 0, 0 );
      SendMessage ( hCombo2, ( UINT ) CB_SETCUEBANNER, ( WPARAM ) 0, 
      ( LPARAM ) L "Type a word to search for in the list of files shown below. " );
      dwErr = GetLastError ( );
      hProgress = GetDlgItem ( hDlg, IDC_PROGRESS1 );
      ShowWindow ( hProgress, SW_HIDE );
      GetWindowRect ( hDlg, &dRc );
      MoveWindow ( hDlg, 0, 10, dRc.right, 30, TRUE );
      MoveWindow ( hStrtBild, 10, 0, 104, 23, TRUE );
      MoveWindow ( hCombo1, 120, 0, 410, 23, TRUE );
      MoveWindow ( hStrtSrch, 540, 0, 104, 23, TRUE );
      MoveWindow ( hCombo2, 650, 0, dRc.right-650, 23, TRUE );
      MoveWindow ( hProgress, 0, 0, dRc.right, dRc.bottom, TRUE );
      return FALSE;
    }
  }
  break;

  case WM_COMMAND:
    wmId = LOWORD ( wParam );
    wmEvent = HIWORD ( wParam );
    switch ( wmId ) {

    case IDC_BUTTON1:
    {
      TCHAR  ListItem [ 256 ];
      TCHAR  searchCap [ 256 ];
      TCHAR  nodeCD [ 256 ];
      TCHAR * tStr;
      TCHAR cStr [ 255 ]; tStr = cStr;
      LRESULT itemIndex = SendMessage ( hCombo1, 
                   ( UINT ) CB_GETCURSEL, ( WPARAM ) 0, ( LPARAM ) 0 );
      if ( itemIndex < 0 )
        if ( ComboBox_GetText ( hCombo1, ListItem, 255 ) )
          itemIndex = SendMessage ( hCombo1, 
                   ( UINT ) CB_ADDSTRING, ( WPARAM ) 0, ( LPARAM ) ListItem );
        else {
          if (!*searchStr ) {
            GetEnvironmentVariable ( L "SEARCHSTR ", searchStr,255 );
            ComboBox_SetText ( hCombo1, searchStr );
          }
          return 0;
        }
      SendMessage ( hCombo1, ( UINT ) CB_SETCURSEL, ( WPARAM ) itemIndex, ( LPARAM ) 0 );
      SendMessage ( hCombo1, ( UINT ) CB_GETLBTEXT, 
                  ( WPARAM ) itemIndex, ( LPARAM ) ListItem );
      GetEnvironmentVariable ( L "SEARCHSTR ", searchStr,255 );

      if ( wcscmp(ListItem, searchStr)!=0 ) {
        StringCchPrintf ( searchStr, 255, L "%s ", ListItem );
        SetEnvironmentVariable ( L "SEARCHSTR ", searchStr );
        StringCchPrintf ( cStr, 255, L " /k Setx SEARCHSTR \ "%s\ " ", searchStr );
        persist_This ( tStr );
      }
      GetCurrentDirectory ( 255, nodeCD );
      StringCchPrintf ( searchCap, 255, L "Searching --- %s ", nodeCD );
      SetWindowText ( hMainWnd, searchCap );
      hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
      if ( 0 == hList ) {
        return 0;
      }
      ShowWindow ( hProgress, SW_NORMAL );
      SendMessage ( hProgress, PBM_SETMARQUEE, PBST_NORMAL, 0 );
      HWND hwndStatus = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_STATUS );
      StringCchPrintf ( tStr, MAX_PATH, L "Searching for %s in   ", searchStr );
      SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) tStr );
      SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) nodeCD );
      recursivefileSearch ( nodeCD, FALSE );
      SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) nodeCD );
      int iCount = ListView_GetItemCount ( hList );
      int result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
      StringCchPrintf ( tStr, MAX_PATH, L "Number of Files %d. ", iCount );
      SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) tStr );
      StringCchPrintf ( tStr, MAX_PATH, L "%d of %d Files. ", result + 1, iCount );
      SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) tStr );
      SetFocus ( hList );
      SendMessage ( hProgress, PBM_SETMARQUEE, PBST_PAUSED - 3, 0 );
      ShowWindow ( hProgress, SW_HIDE );
      SendMessage ( hwndStatus, SB_SETTEXT, 
                    3 | SBT_POPOUT, ( LPARAM ) L "Line: 0    Column: 0 " );
      return FALSE;
    }
    break;

    case IDC_COMBO1:
    {
      hCombo1 = ( HWND ) lParam;
      if ( wmEvent == CBN_EDITUPDATE ) {
        TCHAR  ListItem [ 256 ];
        ComboBox_GetText ( hCombo1, ListItem, 255 );
        if ( *ListItem == L '? ' ) {
          SetWindowText ( hEdit, L " " );
          // set the CUE Banner for the ComboBox
          Edit_SetCueBannerText ( hEdit,
            ( LPARAM ) L "Type last part of filename in the ComboBox or 
            select an extension from the drop down list below the ComboBox. " );
        }
      }
    }
    break;

    case IDC_BUTTON2:
    {
      TCHAR  ListItem [ 256 ];
      TCHAR  fsiaf [ 256 ] = { 0 };
      TCHAR  searchCap [ 256 ];
      TCHAR  nodeCD [ 256 ];
      TCHAR * tStr;
      TCHAR cStr [ 255 ]; tStr = cStr;
      LRESULT itemIndex = SendMessage 
                ( hCombo2, ( UINT ) CB_GETCURSEL, ( WPARAM ) 0, ( LPARAM ) 0 );
      if ( itemIndex == CB_ERR )
        if ( ComboBox_GetText ( hCombo2, ListItem, 255 ) )
          itemIndex = SendMessage 
                ( hCombo2, ( UINT ) CB_ADDSTRING, ( WPARAM ) 0, ( LPARAM ) ListItem );
        else {
          if ( !*fsiaf ) {
            GetEnvironmentVariable ( L "FSIAF ", fsiaf, 255 );
            ComboBox_SetText ( hCombo2, fsiaf );
          }
          return 0;
        }
      SendMessage ( hCombo2, ( UINT ) CB_SETCURSEL, ( WPARAM ) itemIndex, ( LPARAM ) 0 );
      SendMessage ( hCombo2, ( UINT ) CB_GETLBTEXT, ( WPARAM ) itemIndex, ( LPARAM ) ListItem );
      GetEnvironmentVariable ( L "FSIAF ", fsiaf, 255 );
      if ( wcscmp(ListItem,fsiaf)!=0 ) {
        StringCchPrintf ( fsiaf, 255, L "%s ", ListItem );
        SetEnvironmentVariable ( L "FSIAF ", fsiaf );
        StringCchPrintf ( cStr, 255, L " /k Setx FSIAF \ "%s\ " ", fsiaf );
        persist_This ( tStr );
      }

      GetCurrentDirectory ( 255, nodeCD );
      StringCchPrintf ( searchCap, 255, L "Searching --- %s ", nodeCD );
      SetWindowText ( hMainWnd, searchCap );
      hList = getThisWindowHandle ( hMainWnd, IDC_LIST1 );
      int result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
      int searchStartRow = result;
      ShowWindow ( hProgress, SW_NORMAL );
      SendMessage ( hProgress, PBM_SETMARQUEE, PBST_NORMAL, 0 );
      findStringInAllFiles ( );
      SendMessage ( hProgress, PBM_SETMARQUEE, PBST_PAUSED - 3, 0 );
      ShowWindow ( hProgress, SW_HIDE );
      HWND hRich = getThisWindowHandle ( hMainWnd, IDC_EDIT1 );
      #pragma region select_first_file_with_a_match
      if ( hRich && IsWindowVisible ( hRich ) ) {
        result = searchStartRow - 1;
        if ( searchStartRow == 0 ) {
          result++;
        }
        ListView_SetItemState 
             ( hList, -1, 0, LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
        ListView_SetItemState 
             ( hList, result, LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED,
                    LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
        ListView_EnsureVisible ( hList, result, TRUE );
        return 0; 
      }
      #pragma endregion and make sure it is visible
    }
    break;

    case IDC_COMBO2:
    {
      hCombo2 = ( HWND ) lParam;
      if ( wmEvent == CBN_EDITUPDATE ) {
        TCHAR  ListItem [ 256 ];
        ComboBox_GetText ( hCombo2, ListItem, 255 );
        if ( *ListItem == L '? ' ) {
          SetWindowText ( hEdit, L " " );
          // set the CUE Banner for the ComboBox
          Edit_SetCueBannerText ( hEdit,
            ( LPARAM ) L "Type a word to search for in the list of files 
             shown in the ListView below. " );
        }
      }
    }
    break;

    default:
      break;
    }
    break;

  case WM_SIZE:
  {
    hStrtBild = getThisWindowHandle ( hDlg, IDC_BUTTON1 );
    hStrtSrch = getThisWindowHandle ( hDlg, IDC_BUTTON2 );
    GetWindowRect ( hDlg, &dRc );
    GetClientRect ( hDlg, &dRccl );
    GetWindowRect ( hStrtBild, &bRc1 );
    GetClientRect ( hStrtBild, &bRccl1 );
    GetWindowRect ( hStrtSrch, &bRc2 );
    GetClientRect ( hStrtSrch, &bRccl2 );
    GetWindowRect ( hCombo1, &cRc1 );
    GetClientRect ( hCombo1, &cRccl1 );
    GetWindowRect ( hCombo2, &cRc2 );
    GetClientRect ( hCombo2, &cRccl2 );
    GetWindowRect ( hProgress, &pRc );
    GetClientRect ( hProgress, &pRccl );
    OffsetRect ( &bRc1, -dRc.left, -dRc.top );
    OffsetRect ( &cRc1, -dRc.left, -dRc.top );
    OffsetRect ( &bRc2, -dRc.left, -dRc.top );
    OffsetRect ( &cRc2, -dRc.left, -dRc.top );
    MoveWindow ( hStrtBild, bRc1.left, bRc1.top, bRc1.right-bRc1.left, bRc1.bottom, TRUE );
    MoveWindow ( hCombo1, cRc1.left, cRc1.top, cRc1.right-cRc1.left, cRc1.bottom, TRUE );
    MoveWindow ( hStrtSrch, bRc2.left, bRc2.top, bRc2.right-bRc2.left, bRc2.bottom, TRUE );
    HWND dtHwnd = GetDesktopWindow ( );//MoveWindow 
        // ( hCombo2, cRc2.left, cRc2.top, dRc.right - 720, cRc2.bottom, TRUE );
    RECT dtRc;  GetWindowRect ( dtHwnd, &dtRc );//
    if ( dtRc.right <= dRc.right ) {
      MoveWindow ( hCombo2, cRc2.left, cRc2.top, dRc.right - cRc2.left, cRc2.bottom, TRUE );
    }
    else
      MoveWindow ( hCombo2, cRc2.left, cRc2.top, 350, cRc2.bottom, TRUE );
    MoveWindow ( hProgress, 0, 0, pRccl.right, pRccl.bottom, TRUE );
    return 0;
  }break;
  }
  return ( INT_PTR ) FALSE;
}

Using the Viewer Panel: richEditProc

In the WM_INITDIALOG message handler, the RichEdit Control is in a window, hFormView3 which is used for sizing of the RichEdit Control. The window hFormView3 is in a window, hBottom, that is used for sizing hFormView1, hFormView2, hForView3 and hMiddle. To prevent RichEdit from being created in hBottom but not in hFormview3, we get the handles for the main window and hDlg. Because hDlg can be hBottom or hFormView3, we differentiate between them by getting the parent of hDlg. If that is the main window, we return 0. We then make sure there is no RichEdit before we load the "MSFTEDIT" DLL which contains RICHEDIT50W, which is used to create the RichEdit Control. Next, we send RichEdit an EM_SETEVENTMASK telling it we want key events, mouse events and requestresize. Then the zoom ratio is set so that the user can zoom the text font with the mouse wheel and ctrl key.

In the WM_THEMECHANGED message handler, we need to correct a very bad(for me) color combination when the theme is changed during program execution. The other controls change their colors to an acceptable combination, but RichEdit50w does not. We send it an EM_SETBKGNDCOLOR with the wParam set to one, telling it to set the color to the system color. With the wParam set to 1, it ignores the color you send it but you still have to send it a color. I don't know if this happens with other versions of RichEdit or with other controls.

In the WM_NOTIFY message handler, for the pMsgFilter member msg equal to WM_KEYUP, we get the position of the CARET or if there is a selection, the first character of the selection. This is translated into the Line Number by the EM_EXLINEFROMCHAR and EM_LINEINDEX messages and the Column by subtracting the beginning of the line from the CARET position. Then the status bar is updated with the Line number and Column.

The member msg WM_LBUTTONDOWN handler performs the same processing as WM_KEYUP, that is getting the Line Number and Column for the status bar, But with WM_LBUTTONDOWN, we also get the mouse position, convert it from Client coordinates to screen coordinates and save it in a static Point variable named 'rpt'. If the left button was clicked on a word, this Point may be used to select the word programmatically.

This is handled when pMsgFilter member msg is WM_KEYDOWN and wParam is 'f' and the control key is down. Again, we use EM_GETSEL. This time, we compare the startsel and endsel to determine if we have a selection. If they are, we don't so we send a mouse double click to the Point 'rpt'. When RichEdit receives a mouse double click, it selects the word under the mouse. Then we send an 'f' to RichEdit which causes the same block of code to be executed because the control key is still down. This time there is a selection, so the 'else' block is executed. Now an EM_GETSELTEXT message is sent to RichEdit and the text is copied to 'fsiaf' and the Environment Variable is set. The value is also put into ComboBox2. The word in RichEdit is then highlighted.

The message handler for pMsgFilter member msg equals WM_KEYDOWN and wParam is VK_F3(F3) and the static variable keyshifted is set, we set the table entry keyst[VK_SHIFT] to 0x80, Set the Keyboard State, copying keyst to the system table. This is done to prevent RichEdit from capitalizing the word we are searching for.

The message handler for pMsgFilter member msg equals WM_KEYDOWN and wParam is VK_F3(F3) and there is nothing in 'fsiaf' the user may have left double clicked and pushed F3. Here, we get the selection and copy it into 'fsiaf'. Now we determine if the SHIFT Key is down and if it is, we get the keyboard state table and put it in keyst. Setting the keyst entry for VK_SHIFT to zero, we set the keyboard state table to keyst and set the static variable keyshifted to true. Then we find the previous occurrence of the word and highlight it. If the SHIFT Key is not down, we simply find the next occurrence and highlight it. If nothing is found, then a VK_F5 is sent to the ListView requesting the next file containing a match be found. VK_F17 is sent if the SHIFT Key is down. If the find function was successful, we place the CARET in the middle of the screen. This requires we get the first character of the line containing the selection, chline, the first visible line, fvline. Scroll down a page to get the page size, scroll backup a page, divide page size by 2 and add it to fvline, subtract that from chline to find the number of lines to scroll. You also have the information to update the status bar. Piece of cake, piece of candy!

The message handler for pMsgFilter member msg equals WM_KEYDOWN and wParam is VK_F6(F6) is provided as an alternative to the shift F3 processing. It always finds previous and when it fails, it send a VK_F17 to the ListView to find the previous file containing a match. When it succeeds, the CARET is moved to the middle of the screen and the status bar is updated.

The message handler for pMsgFilter member msg equals WM_KEYDOWN and wParam is VK_F5(F5) will simply send the key to ListView.

The message handler for when pMsgFilter member msg is EN_REQUESTRESIZE, if it gives me a size request, I'll give it the room.

The richEditProc Function

C++
// The richEditProc offers the user a Viewer where the context of a code snippet
// can examined to assist in understanding the concept of it 's usage. The find
// function in the Viewer is  the built-in RichEdit find function, however, the 
// find function for the file search is U2Charfunc - an Exact Match algorithm.
// This means that it will miss some apparent matches and RichEdit will find more
// of the string than is indicated in the OCCURS Column of the ListView. For some
// languages, this could be undesirable but for  'C/C++ ' it filters out non-keywords
// in the file search but the point is to speed-up the process. RICHEDIT50W in MSFTEDIT.DLL
// has a feature that CAPITALIZES the first letter of a word 
// when the user types shift plus VK_F3.
// Common convention is to use this combination for  'find previous '. 
// To provide this functionality without the capitalization 
// it is necessary to manipulate the KEYSTATE Table to trick RichEdit.
// To extend  'find previous ' to the file search, richEditProc 
// sends VK_17( which is shift + F5) to the ListView. 
// The RichEdit Control is READ/WRITE to allow the user to type in a  'string to find '
// then select it and press Control plus  'F ' to begin a search, 
// instead of using the Combobox.
// The richEditProc adds the string to the Combobox Dropdown List and 
// saves it in the Environment
// Variables. It does not save the full list, only the last string entered. 
// The richEditProc also positions the Caret(EM_LINESCROLL)
// in the middle of the screen to reduce Eye-Strain. This Version
// of RichEdit appears to not repaint the client area when the THEME is changed by the user.
// This can result in a less than optimum color combination. 
// We send it a EM_SETBKGNDCOLOR with a wParam value
// of 1 to tell it to repaint the client area with the system(THEME) color.
INT_PTR CALLBACK richEditProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
  UNREFERENCED_PARAMETER ( lParam );
  int wmId, wmEvent;
  static POINT rpt = { 0, 0 };
  static BOOL keyshifted = FALSE;
  LONG intRc = 0;
  BYTE keyst [ 256 ] = { 0 };
  static HTHEME thme = NULL;
  HWND hMainWnd = NULL, hRich = NULL, hTree = NULL, hList = NULL, 
                  hEdit = NULL, hFormView3 = NULL;
  if ( message != WM_INITDIALOG ) {
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    hRich = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT1 );
  }

  switch ( message ) {
  case WM_INITDIALOG:
  {
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    HWND hBottom = GetAncestor ( hDlg, GA_PARENT );
    if ( hMainWnd == hBottom ) {
      return 0;
    }
    hRich = FindWindowEx ( hDlg, 0, L "RICHEDIT50W ", 0 );
    if ( hRich == 0 ) {
      RECT rc = { 0, 0, 380, 380 };
      GetClientRect ( hMainWnd, &rc );
      HINSTANCE hLib;       // for Rich Edit
      hLib = LoadLibrary ( L "Msftedit.dll " );
      hRich = CreateWindowExW ( WS_EX_CLIENTEDGE,   // extended styles
                    L "RICHEDIT50W ",               //control  'class ' name
                    L " ",                          //control caption
                    //control style
                    WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | 
                    ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | 
                    ES_NOHIDESEL | ES_WANTRETURN,
                    rc.left,                        //position: left
                    rc.top,                         //position: top
                    rc.right,                       //width
                    rc.bottom,                      //height
                    hDlg,                           //parent window handle
                    //control 's ID
                    ( HMENU ) ( IDC_EDIT1 ),
                    hInst,                          //application instance
                    0 );                            //user defined info
      SendMessage ( hRich, EM_SHOWSCROLLBAR, SB_VERT, TRUE );
      ShowWindow ( hRich, SW_SHOW );
      SendMessage ( hRich, EM_SETEVENTMASK, 0, ENM_KEYEVENTS | 
                    ENM_REQUESTRESIZE | ENM_MOUSEEVENTS );
      SendMessage ( hRich, EM_SHOWSCROLLBAR, SB_VERT, TRUE );
      SendMessage ( hRich, EM_SETZOOM, 3, 4 );
      SendMessage ( hRich, EM_SETEDITSTYLEEX, SES_EX_NOACETATESELECTION, 
                    SES_EX_NOACETATESELECTION );
      ShowWindow ( hFormView3, SW_SHOW );

      return ( INT_PTR ) TRUE;
    }
  }

  case WM_THEMECHANGED:
  {
    // RICHEDIT does not change the background color when HIGH CONTRAST 
    // is turned on . Turn it on progmattically using the new background color
    // by setting wparam to any non zero value. The hex lparam value is ignored.
    SendMessage ( hRich, EM_SETBKGNDCOLOR, 1, 0x008888ff );
    return ( HRESULT ) FALSE;
  }

  case WM_NOTIFY:
  {
    wmId = LOWORD ( wParam );
    wmEvent = HIWORD ( wParam );
    TCHAR fsiaf [ 256 ] = { 0 };  // Find this String In A File
    GetEnvironmentVariable ( L "FSIAF ", fsiaf, 255 );
    FINDTEXTEXW fndFrst;
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
    hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
    hRich = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT1 );
    hTree = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_TREE1 );
    hFormView3 = hDlg;

    switch ( wmId ) {

    case IDC_EDIT1:
    {
      hRich = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT1 );
      MSGFILTER  *pMsgFilter = ( MSGFILTER * ) lParam;

      if ( pMsgFilter->msg == WM_KEYUP ) {
        TCHAR Text [ 256 ] = { 0 };
        DWORD dwSelStart = 0, dwSelEnd = 0;
        SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
        int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, dwSelStart );
        LONG strtLine = ( LONG ) SendMessage ( hRich, EM_LINEINDEX, chLine, 0 );
        LONG colPos = dwSelStart - strtLine;
        StringCchPrintf ( Text, 255, L "Line: %d  Column: %d ", chLine, colPos );
        HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
        SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, ( LPARAM ) Text );
      }
      if ( pMsgFilter->msg == WM_LBUTTONDOWN && pMsgFilter->wParam == MK_LBUTTON ) {
        #pragma region user_clicked_somewhere_in_richedit
        DWORD lbd = ( DWORD ) pMsgFilter->lParam;// NOTE this is the lParam of the lParam
        rpt.x = GET_X_LPARAM ( lbd );
        rpt.y = GET_Y_LPARAM ( lbd );
        ClientToScreen ( hRich, &rpt );
        TCHAR Text [ 256 ] = { 0 };
        DWORD dwSelStart = 0, dwSelEnd = 0;
        SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
        int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, dwSelStart );
        LONG strtLine = ( LONG ) SendMessage ( hRich, EM_LINEINDEX, chLine, 0 );
        LONG colPos = dwSelStart - strtLine;
        StringCchPrintf ( Text, 255, L "Line: %d  Column: %d ", chLine, colPos );
        HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
        SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, ( LPARAM ) Text );
        return 0;
        #pragma endregion save mouse position for control  'f '
      }

      if ( pMsgFilter->msg == WM_KEYDOWN && pMsgFilter->wParam == 0x46 ) {
        #pragma region control-f_was_pressed_by_ user
        short nVirtKey = GetKeyState ( VK_CONTROL );
        if ( nVirtKey & 0x8000 ) {
          CHARRANGE cr;
          DWORD dwSelStart = 0, dwSelEnd = 0;
          SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
          if ( dwSelStart == dwSelEnd ) {
            SetCursorPos ( rpt.x, rpt.y );
            INPUT lbtnPr;
            lbtnPr.type = INPUT_MOUSE;
            lbtnPr.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
            lbtnPr.mi.dx = rpt.x;
            lbtnPr.mi.dy = rpt.y;
            SendInput ( 1, &lbtnPr, sizeof ( INPUT ) );
            lbtnPr.mi.dwFlags = MOUSEEVENTF_LEFTUP;
            SendInput ( 1, &lbtnPr, sizeof ( INPUT ) );
            lbtnPr.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
            SendInput ( 1, &lbtnPr, sizeof ( INPUT ) );
            lbtnPr.mi.dwFlags = MOUSEEVENTF_LEFTUP;
            SendInput ( 1, &lbtnPr, sizeof ( INPUT ) );
            INPUT keyPr;
            keyPr.type = INPUT_KEYBOARD;
            keyPr.ki.dwFlags = 0; // KEYEVENTF_KEYDOWN?;
            keyPr.ki.wScan = 0;
            keyPr.ki.time = 0;
            keyPr.ki.dwExtraInfo = 0;
            keyPr.ki.wVk = 0x46;
            SendInput ( 1, &keyPr, sizeof ( INPUT ) );
            keyPr.ki.dwFlags = KEYEVENTF_KEYUP;
            SendInput ( 1, &keyPr, sizeof ( INPUT ) );
          }
          else {
            cr.cpMin = dwSelStart;
            cr.cpMax = dwSelEnd;
            intRc = dwSelStart;
            SendMessage ( hRich, EM_GETSELTEXT, 0, ( LPARAM ) fsiaf );
            SetEnvironmentVariable ( L "FSIAF ", fsiaf );
            TCHAR  ListItem [ 256 ];
            StringCchPrintf ( ListItem, 255, L "%s ", fsiaf );
            HWND hCombo2 = getThisWindowHandle ( hMainWnd, IDC_COMBO2 );
            ComboBox_SetCurSel ( hCombo2, -1 );
            ComboBox_SetText ( hCombo2, ListItem );
            LRESULT itemIndex = SendMessage ( hCombo2, ( UINT ) CB_GETCURSEL, 
                                            ( WPARAM ) 0, ( LPARAM ) 0 );
            if ( itemIndex < 0 )
              if ( ComboBox_GetText ( hCombo2, ListItem, 255 ) )
                itemIndex = SendMessage ( hCombo2, ( UINT ) CB_ADDSTRING, 
                                        ( WPARAM ) 0, ( LPARAM ) ListItem );
              else
                itemIndex = 0;
            SendMessage ( hCombo2, ( UINT ) CB_SETCURSEL, 
                                   ( WPARAM ) itemIndex, ( LPARAM ) 0 );
            SendMessage ( hCombo2, ( UINT ) CB_GETLBTEXT, 
                        ( WPARAM ) itemIndex, ( LPARAM ) ListItem );
            CHARFORMAT cf;
            cf.cbSize = sizeof ( cf );
            cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
            cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
            SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
            DWORD dwerr = GetLastError ( );
            dwerr = GetLastError ( );
          }
        }
        return TRUE;
        #pragma endregion send double click and get text for search string
      }

      if ( pMsgFilter->msg == WM_KEYUP && pMsgFilter->wParam == VK_F3 ) {
        #pragma region vk_f3-released
        if ( keyshifted ) {
          keyst [ VK_SHIFT ] = 0x80;//keysh [ VK_SHIFT ];
          SetKeyboardState ( keyst );
        }
        #pragma endregion so release shift key
      }

      // Richedit will capitalize an uncapitalized word, capitalize the
      // the entire word if the first letter is a capital and if the 
      // entire word is all caps it will make them all lower case when
      // the key combination is  VK_F3 and VK_SHIFT. To prevent this from happening
      // the user can hold down the control key, VK_CONTROL. To prevent it 
      // in code, one way is to copy the keyboard state table and unset 
      // the VK_SHIFT entry. When Richedit processes the VK_F3 message  it
      // will be unshifted but the previous occurrence has been found
      if ( pMsgFilter->msg == WM_KEYDOWN && pMsgFilter->wParam == VK_F3 ) {
        if ( !*fsiaf ) {
          #pragma region select_marked_text
          CHARRANGE cr;
          DWORD dwSelStart = 0, dwSelEnd = 0;
          cr.cpMin = dwSelStart;  cr.cpMax = dwSelEnd;
          SendMessage ( hRich, EM_GETSELTEXT, 0, ( LPARAM ) fsiaf );
          CHARFORMAT cf;
          cf.cbSize = sizeof ( cf );
          cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
          cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
          SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
          DWORD dwerr = GetLastError ( );
          dwerr = GetLastError ( );
          #pragma endregion if search string is blank and text is high-lighted
        }
        short nVirtKeySh = GetKeyState ( VK_SHIFT );
        short nVirtKey = GetKeyState ( VK_CONTROL );
        WPARAM wp = 1;
        if ( nVirtKeySh & 0x8000 || nVirtKey & 0x8000 ) {
          #pragma region find_backwards
          if ( GetKeyboardState ( keyst ) == TRUE ) {
            #pragma region prevent_richedit_from _changing_case
            keyst [ VK_SHIFT ] = 0;
            SetKeyboardState ( keyst );
            keyshifted = TRUE;
            #pragma endregion along with find previous
            wp = 0;
            DWORD dwSelStart = 0, dwSelEnd = 0;
            SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
            fndFrst.chrg.cpMin = dwSelStart - 1;
            fndFrst.chrg.cpMax = intRc;
            fndFrst.lpstrText = fsiaf;
            intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 
                                         ( WPARAM ) wp, ( LPARAM ) &fndFrst );
            CHARFORMAT cf;
            cf.cbSize = sizeof ( cf );
            cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
            cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
            SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
            DWORD dwerr = GetLastError ( );
            dwerr = GetLastError ( );
          }
          else {
            // can 't get keyboard state table
            return FALSE;
          }
          #pragma endregion when vk_f3 is shifted
        }
        else {
          #pragma region find-forward
          keyshifted = FALSE;
          DWORD dwSelStart = 0, dwSelEnd = 0;
          SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
          fndFrst.chrg.cpMin = dwSelEnd + 1;
          fndFrst.chrg.cpMax = -1;
          fndFrst.lpstrText = fsiaf;
          intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 
                                       ( WPARAM ) wp, ( LPARAM ) &fndFrst );
          CHARFORMAT cf;
          cf.cbSize = sizeof ( cf );
          cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
          cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
          SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
          DWORD dwerr = GetLastError ( );
          dwerr = GetLastError ( );
          #pragma endregion when vk_f3 is not shifted
        }

        if ( intRc == -1 ) {
          #pragma region string_not_found
          if ( wp ) {
            return sendMeMyKey ( hList, VK_F5 );
          }
          else {
            if ( keyshifted ) {
              keyst [ VK_SHIFT ] = 0x80;//keysh [ VK_SHIFT ];
              SetKeyboardState ( keyst );
            }
            return sendMeMyKey ( hList, VK_F17 );
          }
          #pragma endregion so send request to listview
        }
        else {
          #pragma region put_caret_in_middle of screen
          SendMessage ( hRich, EM_SETSEL, fndFrst.chrgText.cpMin, fndFrst.chrgText.cpMax );
          SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );
          int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, intRc );
          int fvLine = ( int ) SendMessage ( hRich, EM_GETFIRSTVISIBLELINE, 0, 0 );
          DWORD lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEDOWN, 0 );
          WORD pgSize = LOWORD ( lvLine );
          lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEUP, 0 );
          DWORD desiredPos = pgSize / 2 + fvLine;
          int noffSet = chLine - desiredPos;
          SendMessage ( hRich, EM_LINESCROLL, 0, noffSet );
          SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );
          TCHAR Text [ 255 ] = { 0 };
          HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
          LONG strtLine = ( LONG ) SendMessage ( hRich, EM_LINEINDEX, chLine, 0 );
          LONG colPos = intRc - strtLine;
          StringCchPrintf ( Text, 255, L "Line: %d  Column: %d ", chLine, colPos );
          SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, ( LPARAM ) Text );
          intRc = fndFrst.chrgText.cpMax + 1;
          #pragma endregion to reduce visual fatigue
        }
        return -1;
      }
      if ( pMsgFilter->msg == WM_KEYDOWN && pMsgFilter->wParam == VK_F6 ) {
        #pragma region find_previous_unshifted
        #pragma region find_previous_unshifted
        WPARAM wp = 0;
        DWORD dwSelStart = 0, dwSelEnd = 0;
        SendMessage ( hRich, EM_GETSEL, ( WPARAM ) &dwSelStart, ( LPARAM ) &dwSelEnd );
        fndFrst.chrg.cpMin = dwSelStart - 1;
        fndFrst.chrg.cpMax = intRc;
        fndFrst.lpstrText = fsiaf;
        intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 
                                     ( WPARAM ) wp, ( LPARAM ) &fndFrst );
        CHARFORMAT cf;
        cf.cbSize = sizeof ( cf );
        cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
        cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
        SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
        DWORD dwerr = GetLastError ( );
        dwerr = GetLastError ( );
        #pragma endregion (just using vk_f6, no shift or control)
        if ( intRc == -1 ) {
          #pragma region when_not_found_backwards
          return sendMeMyKey ( hList, VK_F17 );
          #pragma endregion send vk_f5 to listview
        }
        else {
          #pragma region put_the_caret_in_middle of screen
          SendMessage ( hRich, EM_SETSEL, fndFrst.chrgText.cpMin, fndFrst.chrgText.cpMax );
          SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );
          int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, intRc );
          int fvLine = ( int ) SendMessage ( hRich, EM_GETFIRSTVISIBLELINE, 0, 0 );
          DWORD lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEDOWN, 0 );
          WORD pgSize = LOWORD ( lvLine );
          lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEUP, 0 );
          DWORD desiredPos = pgSize / 2 + fvLine;
          int noffSet = chLine - desiredPos;
          SendMessage ( hRich, EM_LINESCROLL, 0, noffSet );
          SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );
          intRc = fndFrst.chrgText.cpMax + 1;
          #pragma endregion to reduce visual fatigue
        }
        return 1;
        #pragma endregion (just using vk_f6, then center caret)
      }
      if ( pMsgFilter->msg == WM_KEYDOWN && pMsgFilter->wParam == VK_F5 ) {
        #pragma region send_find_next_to_listview
        return sendMeMyKey ( hList, VK_F5 );
        #pragma endregion to find string in a file
      }
      if ( pMsgFilter->msg == EN_REQUESTRESIZE ) {
        #pragma region Richedit_requested_more_space
        REQRESIZE * resrc = ( REQRESIZE * ) lParam;
        MoveWindow ( hRich, resrc->rc.left, resrc->rc.top, resrc->rc.right, 
                     resrc->rc.bottom, TRUE );
        return 0;
        #pragma endregion lParam points to REQRESIZE structure with width and height
      }
    }
    break;
    }
    return 0;
  }
  break;

  case WM_NCCALCSIZE:
    if ( wParam ) {
      return WVR_ALIGNLEFT | WVR_ALIGNTOP | WVR_REDRAW;
    }
    else
      return DefWindowProc ( hRich, message, wParam, lParam );
    break;

  case WM_SIZE:
  {
    #pragma region  Richedit_parent_window_resized
    UINT width = GET_X_LPARAM ( lParam );
    UINT height = GET_Y_LPARAM ( lParam );
    if ( wParam ) {  
      MoveWindow ( hRich, 0, 0, width, height, TRUE );
    }
    return 0;
    #pragma endregion get size from richedit and make it so
  }break;

  case WM_ACTIVATE:
  {
    if ( LOWORD ( wParam ) & WA_ACTIVE ) {
      SendMessage ( hRich, EM_SHOWSCROLLBAR, SB_VERT, TRUE );
      if ( hRich ) {
        SetFocus ( hRich );
        return 0;
      }
      return 0;
    }
    else
      return -1;
  }break;
  }
  return ( INT_PTR ) FALSE;
}

Finding the Next or Previous File with a Match: The listViewProc Function

In the message switch, the WM_INITDIALOG message is received for hBottom and hFormView2. If it's hBottom, we just get out. If it's hFormView2, a font is created for a larger text size. Then the ListView Control is created and the Column Headers are put in. Having created the ListView, a WM_SETFONT message is sent to it to set the font we created earlier. Now for a word about hFormView2. Looking in the Resource View, you can see that it has a RESIZING Border. This is used instead of Emulating a Splitter Bar. The RESIZING Border can give you a 3 by 3 grid if you want it but we want a 1 by 3 row from that grid. In order to do this, the Top and Bottom Borders of hFormView2 must be dis-abled. The Cursor is clipped to achieve this. The sizing of all of the controls in hBottom is controlled by hFormView2 and is performed in the WM_SIZING message handler. There is an issue with using the RESIZING Border instead of a splitter Bar. The issue is the size of the RECTS received by the size control messages. I know how to fix the issue properly but for now, I just use hard coded values to give them the proper sizes.

The WM_COMMAND message is used to process the WM_SETFOCUS message. When an item is selected, it is highlighted here if the ListView receives focus but nothing is selected, the first item in ListView is selected and highlighted.

In the WM_NOTIFY message handler, we get the value of fsiaf from the environment block. We also get all of the window handles we might need. In the switch for the LPNMHDR lParam member code, we handle the code for NM_CLICK by getting the path of the selected file and loading it into RichEdit and update the status bar unless it is larger than 64 megabytes, in which case we use the Open with Dialog to open the file in another application.

The code for NM_DBLCLK is handled by opening the folder or file in File Explorer with the item selected.

The code for NM_RCLICK is handled by invoking the Open With Dialog. It does not display a context menu.

The code for LVN_KEYDOWN is handled by creating a pointer to a NMLVKEYDOWN structure and calling it pnkd and initializing it to the lParam cast to a LPNMLVKEYDOWN'. The pnkd member wVKey will contain the virtual key code that was typed.

The wVKey code for VK_DOWN is handled by moving down one and loading that file into RichEdit unless it is larger 64 megabytes.

The wVKey code for VK_TAB is handled by setting the focus on the RichEdit Control, simulating a tab key.

The wVKey code for VK_UP is handled by moving up one and loading that file into RichEdit unless it is larger than 64 megabytes.

The wVKey code for VK_F5 and VK_F17*SHIFT F5) is handled by getting the text for the current item's second Column, the 'Number of Occurrences' to determine if it contains fsiaf. If it does, it calls U2Charfunc to make sure and highlights the file name in ListView, then places the highlighted line in the middle of the visible list, loads the file into RichEdit and the RichEdit find function is used to place the RichEdit CARET on the match and scroll it to the middle of the screen.

When a next or previous file cannot be found in the ListView Occurs Column (determined by counting the number of misses until it equals or exceeds the number of rows in the List View), if the number of rows is greater, it displays a message box informing that the next step could take a while. Then it calls findStringInAllFiles search the File List itself to populate the Occurs Column with the counts. Next, it finds the next file containing a match and loads it into RichEdit, positioning the highlights in the middle of the screen. Note this will only happen when the user has entered the string to search for in the RichEdit Viewer Panel.

When the number of hits exceeds the number of rows in the ListView, a message box is displayed to inform the user that NO FILES containing the Requested STRING were found, and suggesting that they check the spelling.

The wVKey code for VK_F3 and VK_F6 is handled by sending the keys to the RichEdit proc.

The wVKey code for VK_F4 is handled by displaying the Properties for the file.

NM_RETURN is a WM_NOTIFY message. We process it the same as a NM_DBLCLK with the file location being opened in File Explorer.

NM_SETFOCUS is a WM_NOTIFY message. We process it the same as a WM_SETFOCUS. If there is anything in the ListView, we make sure it's highlighted.

For the message WM_NCLBUTTONUP, we cancel the ClipCursor by setting it to NULL so that the cursor can move freely.

For the WM_SIZING message, we get the drag rectangle from the lParam. We also get all of the window handles, window rectangles and client rectangles, and offset the window rectangles to make their positions relative to the main window. Then we determine which border is being moved. If it's not the left or right, then we clip the cursor to prevent vertical movement. The same formula works for the top and bottom. The cursor is only allowed to move from the left border to the right border in either direction. For the right border, we clip to prevent the user from covering the RichEdit Viewer Panel with the ListView. Then we move hFormView3, the container for the RichEdit Control, to its new position and fill it with RichEdit. If it is the left border, we clip the cursor to prevent the ListView from covering the entire treeview and move the treeview to its new size and position. For both the left and right border, we move the ListView Control into hFormView2.

The listViewProc Function

C++
// Message handler for ListView. Processes WM_NOTIFY for the following messages: 
// NM_CLICK - select the current file and load it into RichEdit
// NM_RCLICK - select the current file and Invokes OpenWith Dialog
// NM_DBLCLK - opens selected file location in File Explorer with Mouse input
// NM_RETURN - opens selected file location in File Explorer with Keyboard input
// F3 is sent to RichEdit to find next string in the current file. 
// Shift with F3 searches backwards
// F4 Displays Properties for current file
// F5 finds next fie containing string. Shift with F5 searches backwards
// F6 is sent to RichEdit to find previous string or 
// last occurrence of string in current file
// F17 (shifted F5) is sent to ListView by Richedit when F6 reaches the begining of the file
// WM_NCLBUTTONUP will nullify the ClipCursor, thus freeing the Cursor to move freely
// WM_SIZING wil<span lang="en-us">l</span> re-size the TreeView control and RichEdit 
// when User drags Left or Right sizing grip. If User attempts to drag 
// the TOP or BOTTOM size grip the Cursor is Clipped preventing
// UP or Down movement. The Cursor is also clipped to 
// prevent the user from moving the left or 
// right side sizing grips too far, covering up the other windows and 
// causing a loss of function.
INT_PTR CALLBACK    listViewProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
  PAINTSTRUCT ps;
  HDC hdc;
  TCHAR curntFname [ 256 ];
  TCHAR numbOfOccurs [ 256 ];
  TCHAR curntPath [ MAX_PATH ];
  TCHAR Text [ 256 ] = { 0 };
  TCHAR text [ 256 ] = { 0 };
  TCHAR teXt [ 256 ] = { 0 };
  TCHAR tStr [ MAX_PATH ];
  TCHAR searchCap [ 256 ]; // The Window Caption for Search Function
  static int currentRow = 0;
  CHAR chBuf [ 4096 ];
  HWND hMainWnd = NULL, hTree = NULL, hList = NULL, hEdit = NULL,
    hRich = NULL, hListView, hFormView2;
  HWND hWndFocus = NULL;

  switch ( message ) {
  case WM_INITDIALOG:
  {
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    HWND hBottom = GetAncestor ( hDlg, GA_PARENT );
    if ( hMainWnd == hBottom ) {
      return 0;
    }
    hList = FindWindowEx ( hDlg, 0, L "SysListView32 ", 0 );
    if ( hList == 0 ) {

      HFONT hFont = CreateFont ( 32, 10, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, \
                     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \
                     DEFAULT_PITCH | FF_SWISS, L "Arial " );
      RECT sRc;
      GetClientRect ( hDlg, &sRc );
    
      hList = CreateWindowEx ( 0,
                      WC_LISTVIEW, NULL,
                      WS_CHILD | WS_VISIBLE | DS_3DLOOK | WS_BORDER |
                      WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP |
                      WS_EX_OVERLAPPEDWINDOW | WS_EX_STATICEDGE | 
                      WS_EX_COMPOSITED | WS_EX_NOINHERITLAYOUT |
                      LVS_REPORT | LVS_SHOWSELALWAYS,
                      sRc.left, sRc.top, sRc.right, sRc.bottom - 5, hDlg,
                      ( HMENU ) IDC_LIST1, hInst, 0 );
      LVCOLUMN lvCol;
      memset ( &lvCol, 0, sizeof ( lvCol ) );
      lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; // Type of mask
      lvCol.pszText = ( LPWSTR ) L "Name ";
      lvCol.cx = 0x96;          // width of first column
      ListView_InsertColumn ( hList, 0, &lvCol );
      lvCol.pszText = ( LPWSTR ) L "Number of Occurrences ";
      lvCol.cx = 0x96;        // width of second column
      ListView_InsertColumn ( hList, 1, &lvCol );
      lvCol.pszText = ( LPWSTR ) L "Path ";
      lvCol.cx = 0x64;        // width of third column
      ListView_InsertColumn ( hList, 2, &lvCol );
      lvCol.pszText = ( LPWSTR ) L "File Size ";
      lvCol.cx = 0x072;        // width of fourth column
      ListView_InsertColumn ( hList, 3, &lvCol );
      SendMessage ( hList, WM_SETFONT, WPARAM ( hFont ), TRUE );
      return 0;
    }
  }
  break;

  case WM_PAINT:

    if ( hMainWnd ) {
      hdc = BeginPaint ( hMainWnd, &ps );
      EndPaint ( hMainWnd, &ps );
    }
    return 0;
    break;

  case WM_COMMAND:
  {
    switch ( HIWORD ( wParam ) ) {
    case WM_SETFOCUS:
    {
      // if anything is in List make sure something is selected
      if ( hList && ListView_GetItemCount ( hList ) >= 1 ) {
        int selectedItem = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
        if ( selectedItem == -1 ) {
          // select first one
          ListView_SetItemState ( hList, 0, LVIS_SELECTED, LVIS_SELECTED );
          return 0;
        }
        else {
          ListView_SetItemState ( hList, selectedItem, LVIS_SELECTED, LVIS_SELECTED );
          return 0;
        }
      }
    }
    break;
    }
  }
  break;

  case WM_LBUTTONUP:
    return 0;
    break;

  case WM_LBUTTONDOWN:

    if ( hList ) {
      hWndFocus = hList;
    }
    return 0;
    break;

  case WM_NOTIFY:
  {
    LONG intRc = 0;
    TCHAR fsiaf [ 256 ] = { 0 };  // Find this String In A File
    GetEnvironmentVariable ( L "FSIAF ", fsiaf, 255 );
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    if ( 0 == hMainWnd ) {
      return 0;
    }
    hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
    hTree = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_TREE1 );
    if ( 0 == hList ) {
      return 0;
    }
    hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
    if ( 0 == hEdit ) {  return 0;}
    hRich = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT1 );
    if ( 0 == hRich ) {  return 0;}
    hListView = GetParent ( hList );
    hFormView2 = hListView;
    
    switch ( ( ( LPNMHDR ) lParam )->code ) {

    case NM_CLICK:
    {
      #pragma region mouse_left_ckick
      // Left Click
      NMLISTVIEW * pnmlv;
      LVITEM lvi;
      INT ret;
      pnmlv = ( LPNMLISTVIEW ) lParam;
      memset ( &lvi, 0, sizeof ( lvi ) );
      ret = ( pnmlv )->iItem;
      if ( ret == -1 ) {
        ret = currentRow;
        lvi.iItem = ret;
      }
      else {
        currentRow = ret;
        lvi.iItem = ( pnmlv )->iItem;
      }
      lvi.iItem = ( pnmlv )->iItem;
      lvi.mask = LVIF_TEXT;
      lvi.cchTextMax = 255;
      lvi.pszText = Text;
      ListView_GetItem ( hList, &lvi );
      lvi.pszText = text;
      lvi.iSubItem = 2;
      ListView_GetItem ( hList, &lvi );
      wsprintf ( teXt, L "\ "%s\\%s\ " ", text, Text );
      SetWindowText ( hEdit, teXt );
      ListView_SetItemState ( hList, -1, 0, LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
      ListView_SetItemState ( hList, ret, LVIS_DROPHILITED, LVIS_DROPHILITED );
      ListView_SetItemState ( hList, ret, LVIS_SELECTED, LVIS_SELECTED );
      ListView_SetItemState ( hList, ret, LVIS_FOCUSED, LVIS_FOCUSED );
      int result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
      ListView_GetItemText ( hList, result, 3, text, MAX_PATH - 1 );
      text [ 255 ] = 0;
      int fileSize = _wtoi ( text );
      ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
      ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
      StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
      SetWindowText ( hMainWnd, tStr );
      if ( fileSize > 64 * 1024 * 1024 ) {
        MessageBox ( hMainWnd, L "File Size  is too much for me! 
        Can 't LOAD ", text, MB_OK | MB_ICONEXCLAMATION );
        OPENASINFO opWith;
        opWith.pcszFile = ( LPCTSTR ) &tStr;
        opWith.pcszClass = NULL;
        SHOpenWithDialog ( NULL, &opWith );
        return 0;
      }
      FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
      HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
      int iCount = 0;
      if ( hList ) iCount = ListView_GetItemCount ( hList );
      StringCchPrintf ( Text, 255, L "%d of %d Files ", result + 1, iCount );
      SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) Text );
      SetFocus ( hList );
      #pragma endregion select item and load richedit
    }break; // case NM_CLICK

    case  NM_DBLCLK:
    {
      #pragma region user_left_double_clicked_an_item
      // Left Double Click
      NMLISTVIEW * pnmlv;
      LVITEM lvi;
      int result = 0;
      struct _stat64 buf;
      pnmlv = ( LPNMLISTVIEW ) lParam;
      memset ( &lvi, 0, sizeof ( lvi ) );
      lvi.iItem = ( pnmlv )->iItem;
      if ( lvi.iItem == -1 ) return 0;
      lvi.mask = LVIF_TEXT;
      lvi.cchTextMax = 255;
      lvi.pszText = Text;
      ListView_GetItem ( hList, &lvi );
      lvi.pszText = text;
      lvi.iSubItem = 2;
      ListView_GetItem ( hList, &lvi );
      wsprintf ( teXt, L "%s\\%s ", text, Text );
      result = _wstat64 ( teXt, &buf );
      #pragma endregion get the full path and attributes
      if ( ( buf.st_mode & _S_IFDIR ) ) {
        #pragma region for_a_directory
        wsprintf ( teXt, L "\ "%s\\%s\ " ", text, Text );
        SetWindowText ( hEdit, teXt );
        ShellExecute ( NULL, L "explore ", teXt, NULL, NULL, SW_SHOWNORMAL );
        #pragma endregion open it with file explorer
      }
      if ( result == 0 ) {
        if ( ( buf.st_mode & _S_IFREG ) ) {
          #pragma region not_a_directory_but_a_regular_file
          wsprintf ( teXt, L "/select, \ "%s\\%s\ " ", text, Text );
          SetWindowText ( hEdit, teXt );
          ShellExecute ( NULL, L "open ", L "explorer.exe ", teXt, text, SW_SHOW );
          #pragma endregion open it with current program association
        }
      }
    }break; // case NM_DBLCLK

    case NM_RCLICK:
    {
      #pragma region mouse_right_click
      // Right Click
      NMLISTVIEW * pnmlv;
      LVITEM item;
      pnmlv = ( LPNMLISTVIEW ) lParam;
      memset ( &item, 0, sizeof ( item ) );
      item.iItem = ( pnmlv )->iItem;
      int result = item.iItem;
      item.mask = LVIF_TEXT;
      item.iSubItem = 0;
      item.cchTextMax = 260;
      item.pszText = Text;
      ListView_GetItem ( hList, &item );
      ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
      ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
      StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
      SetWindowText ( hMainWnd, tStr );
      OPENASINFO opWith;
      opWith.pcszFile = ( LPCTSTR ) &tStr;
      opWith.pcszClass = NULL;
      opWith.oaifInFlags = OAIF_EXEC;
      SHOpenWithDialog ( NULL, &opWith );
      return 0;
      #pragma endregion get fullpath and call Open-With dialog
    } break; // case  NM_RCLICK

    case LVN_KEYDOWN:
    {
      NMLVKEYDOWN * pnkd;
      pnkd = ( LPNMLVKEYDOWN ) lParam;
      if ( ( pnkd )->wVKey == VK_DOWN ) {
        #pragma region select_next_item
        LVITEM lvi = { 0 };
        int result = 0;
        int itemCount = 0;
        memset ( &lvi, 0, sizeof ( lvi ) );
        itemCount = ListView_GetItemCount ( hList );
        result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
        if ( result < itemCount - 1 )
          lvi.iItem = result + 1;
        else
          return 0;
        lvi.mask = LVIF_TEXT;
        lvi.cchTextMax = 255;
        lvi.pszText = Text;
        ListView_GetItem ( hList, &lvi );
        lvi.pszText = text;
        ListView_GetItemText ( hList, result, 0, Text, MAX_PATH - 1 );
        ListView_GetItemText ( hList, result, 2, text, MAX_PATH - 1 );
        wsprintf ( teXt, L "%s\\%s ", text, Text );
        SetWindowText ( hEdit, teXt );
        SetWindowText ( hMainWnd, teXt );
        ListView_SetItemState ( hList, -1, LVIS_SELECTED | LVIS_FOCUSED | 
        LVIS_DROPHILITED, LVIS_CUT | LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
        ListView_SetItemState ( hList, result, LVIS_FOCUSED, LVIS_CUT | 
        LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
             // select this one and scroll to it 's position
        ListView_SetItemState ( hList, lvi.iItem, LVIS_SELECTED, LVIS_SELECTED );
        ListView_EnsureVisible ( hList, lvi.iItem, TRUE );
        currentRow = lvi.iItem;
        ListView_GetItemText ( hList, currentRow, 3, curntFname, MAX_PATH - 1 );
        curntFname [ 255 ] = 0;
        int fileSize = _wtoi ( curntFname );
        if ( fileSize > 64 * 1024 * 1024 ) {
          MessageBox ( hMainWnd, L "File Size  is too much for me! 
          Can 't LOAD ", curntFname, MB_OK | MB_ICONEXCLAMATION );
          return 0;
        }
        ListView_GetItemText ( hList, currentRow, 0, curntFname, MAX_PATH - 1 );
        ListView_GetItemText ( hList, currentRow, 2, curntPath, MAX_PATH - 1 );
        StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
        SetWindowText ( hMainWnd, tStr );
        SetWindowText ( hEdit, tStr );
        FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
        HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
        int iCount = 0;
        if ( hList ) iCount = ListView_GetItemCount ( hList );
        StringCchPrintf ( Text, 255, L "%d of %d Files ", currentRow + 1, iCount );
        SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) Text );
        SetFocus ( hList );
        return 1;
        #pragma endregion and load it into richedit
      }

      if ( ( pnkd )->wVKey == VK_TAB ) {
        SetFocus ( hRich );
        return 0;
      }

      if ( ( pnkd )->wVKey == VK_UP ) {
        #pragma region select_previous_item
        LVITEM lvi;
        int result = 0;
        memset ( &lvi, 0, sizeof ( lvi ) );
        result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
        if ( result < 1 ) return 0;
        lvi.iItem = result - 1;
        lvi.mask = LVIF_TEXT;
        lvi.cchTextMax = 255;
        lvi.pszText = Text;
        ListView_GetItem ( hList, &lvi );
        lvi.pszText = text;
        ListView_GetItem ( hList, &lvi );
        wsprintf ( teXt, L "%s\\%s ", text, Text );
        SetWindowText ( hEdit, teXt );
        ListView_SetItemState ( hList, -1, LVIS_SELECTED | LVIS_FOCUSED | 
        LVIS_DROPHILITED, LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED | LVIS_CUT);
        // select this one and scroll to it 's position
        ListView_SetItemState ( hList, lvi.iItem, LVIS_SELECTED, LVIS_SELECTED );
        ListView_EnsureVisible ( hList, lvi.iItem, TRUE );
        currentRow = lvi.iItem;
        ListView_GetItemText ( hList, currentRow, 3, curntFname, MAX_PATH - 1 );
        curntFname [ 255 ] = 0;
        int fileSize = _wtoi ( curntFname );
        if ( fileSize > 64 * 1024 * 1024 ) {
          MessageBox ( hMainWnd, L "File Size  is too much for me! 
          Can 't LOAD ", curntFname, MB_OK | MB_ICONEXCLAMATION );
          return 0;
        }
        ListView_GetItemText ( hList, currentRow, 0, curntFname, MAX_PATH - 1 );
        ListView_GetItemText ( hList, currentRow, 2, curntPath, MAX_PATH - 1 );
        StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
        SetWindowText ( hMainWnd, tStr );
        FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
        HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
        int iCount = 0;
        if ( hList ) iCount = ListView_GetItemCount ( hList );
        StringCchPrintf ( Text, 255, L "%d of %d Files ", currentRow + 1, iCount );
        SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) Text );
        SetFocus ( hList );
        return 0;
        #pragma endregion and load it into richedit
      }

      if ( ( pnkd )->wVKey == VK_F5 || ( pnkd )->wVKey == VK_F17 ) {
        #pragma region cycle _thru_OCCURRENCES_Column
        LVITEM lvi;
        MSG msg;
        memset ( &lvi, 0, sizeof ( lvi ) );
        int numbFound = 0;
        int iCount = 0;
        if ( hList ) iCount = ListView_GetItemCount ( hList );
        int result = currentRow;;
        int misses = 0;
        short nVirtKey = GetKeyState ( VK_CONTROL );
        short nVirtKeySh = GetKeyState ( VK_SHIFT );
        // async key states
        nVirtKey = GetAsyncKeyState ( VK_CONTROL );
        if ( wcscmp ( fsiaf, L " " ) != 0 ) {
          do {
            if ( nVirtKeySh & 0x8000|| ( pnkd )->wVKey == VK_F17) {
              #pragma region shift_key_down
              // get previous file with matches
              result = ListView_GetNextItem ( hList, result, LVNI_ABOVE );
              if ( result == -1 ) {
                result = iCount - 1;
                ListView_SetItemState ( hList, -1, 0, 
                LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                ListView_SetItemState ( hList, result, LVIS_DROPHILITED | 
                                        LVIS_SELECTED | LVIS_FOCUSED,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                ListView_EnsureVisible ( hList, result, TRUE );
                ListView_Update ( hList, result );
                #pragma endregion select previous file
              }
            }
            else {
              #pragma region shift_key_up
              // get next file with matches
              result = ListView_GetNextItem ( hList, result, LVNI_BELOW );
              if ( result == -1 )
                result = 0;
              #pragma endregion select nextt file
            }
            #pragma region does_str-to-search-for_occur_in_occurs_text
            // Get column two text string
            ListView_GetItemText ( hList, result, 1, numbOfOccurs, 255 );
            numbOfOccurs [ 255 ] = 0;
            if ( wcsstr ( (LPWSTR)numbOfOccurs, (LPWSTR)fsiaf ) != 0 ) {
              // search string is a substring of Number of Occurrences column
              // Get column one text string
              ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
              // Get column three text string
              ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
              sprintf_s ( chBuf, 4096,  "%S\\%S\r\n ", curntPath, curntFname );
              char pattern [ 260 ] = { 0 };
              int patlen = sprintf_s ( pattern, 259,  "%S ", fsiaf );
              // daa-ble chek. Call u2Charfunc just to make sure it has a match
              if ( ( numbFound = u2Charfunc ( chBuf, pattern, patlen ) ) != 0 ) {
                ListView_SetItemState ( hList, -1, 0, LVIS_DROPHILITED | 
                                        LVIS_SELECTED | LVIS_FOCUSED );
                ListView_SetItemState ( hList, result, LVIS_DROPHILITED | 
                                        LVIS_SELECTED | LVIS_FOCUSED,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                // Remove Highlight from all files that are highlighted
                result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
                ListView_SetItemState ( hList, -1, 0,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                // Highlight all files with matches
                ListView_SetItemState ( hList, result,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                ListView_EnsureVisible ( hList, result, TRUE );
                ListView_Update ( hList, result );
                currentRow = result;
                int topLine = 0, linesPer = 0;
                topLine = ListView_GetTopIndex ( hList );
                linesPer = ListView_GetCountPerPage ( hList );
                ListView_Scroll ( hList, 0, ( ( ( size_t ) currentRow - topLine ) - 
                                ( linesPer / 2 )+3 ) * 16 );
                iCount = ListView_GetItemCount ( hList );
                ListView_GetItemText ( hList, currentRow, 3, curntFname, MAX_PATH - 1 );
                curntFname [ 255 ] = 0;
                int fileSize = _wtoi ( curntFname );
                if ( fileSize > 64 * 1024 * 1024 ) {
                  MessageBox ( hMainWnd, L "File Size  is too much for me! 
                  Can 't LOAD ", curntFname, MB_OK | MB_ICONEXCLAMATION );
                  ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
                  ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
                  curntPath [ 259 ] = 0;
                  wsprintf ( teXt, L "/select, \ "%s\\%s\ " ", curntPath, curntFname );
                  SetWindowText ( hEdit, teXt );
                  ShellExecute ( NULL, L "open ", 
                                 L "explorer.exe ", teXt, curntPath, SW_SHOW );
                  return 0;
                }
                ListView_GetItemText ( hList, currentRow, 0, curntFname, MAX_PATH - 1 );
                ListView_GetItemText ( hList, currentRow, 2, curntPath, MAX_PATH - 1 );
                StringCchPrintf ( Text, 255, L "[%d of %d]%s\\%s ", 
                                  result + 1, iCount, curntPath, curntFname );
                SetWindowText ( hMainWnd, Text );
                StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
                SetWindowText ( hEdit, tStr );
                FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
                HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
                StringCchPrintf ( Text, 255, L "%d of %d Files ", result + 1, iCount );
                SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) Text );
                SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, 
                            ( LPARAM ) L "Line: 0    Column: 0 " );
                SendMessage ( hwndStatus, WM_SIZE, 0, 0 );
                if ( fsiaf ) {
                  SetFocus ( hRich );
                  FINDTEXTEX fndFrst;
                  fndFrst.lpstrText = fsiaf;
                  if ( ( pnkd )->wVKey == VK_F17 ) {
                    GETTEXTLENGTHEX lastChar = { 0 };
                    lastChar.flags = GTL_DEFAULT;
                    lastChar.codepage = 1200;
                    intRc = ( LONG ) SendMessage ( hRich, EM_GETTEXTLENGTHEX, 
                                                 (WPARAM)&lastChar, ( LPARAM ) 0 );
                    fndFrst.chrg.cpMin = intRc;
                    fndFrst.chrg.cpMax = 0;
                    intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 0, 
                                                 ( LPARAM ) &fndFrst );
                  }
                  else {
                    fndFrst.chrg.cpMin = 0;
                    fndFrst.chrg.cpMax = -1;
                    intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 1, 
                                                 ( LPARAM ) &fndFrst );
                  }

                  CHARFORMAT cf;
                  cf.cbSize = sizeof ( cf );
                  cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
                  cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
                  SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
                  DWORD dwerr = GetLastError ( );
                  dwerr = GetLastError ( );
                  if ( intRc == -1 ) {
                    #pragma region str-to-find was not found in this file 
                    if ( MessageBox ( hMainWnd, L "Could Not FIND 
                    Requested String!\rDo you want to Continue? ", fsiaf,
                        MB_YESNO | MB_ICONINFORMATION | MB_DEFBUTTON2 ) == IDOK ) {
                      StringCchPrintf ( searchCap, 255, L "Could Not 
                      FIND Requested String!\tDo you want to Continue? " );
                      SetWindowText ( hMainWnd, searchCap );
                      SetWindowText ( hEdit, searchCap );
                      SetFocus ( hRich );
                      return 1;
                    }
                    else {
                      intRc = 0;
                      SetFocus ( hRich );
                    }
                    #pragma endregion str-to-find was not found in this file 
                  }
                  else {
                    #pragma region str-to-find was found in this file 
                    hWndFocus = hRich;
                    SetFocus ( hWndFocus );
                    SendMessage ( hRich, EM_SETSEL, fndFrst.chrgText.cpMin, 
                                  fndFrst.chrgText.cpMax );
                    SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );
                    int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, intRc );
                    int fvLine = ( int ) SendMessage ( hRich, EM_GETFIRSTVISIBLELINE, 0, 0 );
                    LONG strtLine = ( LONG ) SendMessage ( hRich, EM_LINEINDEX, chLine, 0 );
                    LONG colPos = intRc - strtLine;
                    DWORD lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEDOWN, 0 );
                    int pgSize = 0;
                    pgSize = LOWORD ( lvLine );
                    lvLine = ( DWORD ) SendMessage ( hRich, EM_SCROLL, SB_PAGEUP, 0 );
                    DWORD desiredPos = pgSize / 2 + fvLine;
                    int noffSet = chLine - desiredPos;
                    SendMessage ( hRich, EM_LINESCROLL, 0, noffSet );
                    SendMessage ( hRich, EM_SCROLLCARET, 0, 0 );

                    intRc = fndFrst.chrgText.cpMax + 1;
                    StringCchPrintf ( Text, 255, L "Line: %d  Column: %d ", chLine, colPos );
                    SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, ( LPARAM ) Text );
                    #pragma endregion make sure caret is centered in the middle of the screen 
                  }
                }
                SetFocus ( hRich );
              }
              if ( !( nVirtKeySh & 0x8000 ) ) {
                // Key-repeat can cause find-in-previous-file to appear
                // to skip files that have matches. This prevents that, whilr
                // remaining responsive for find-in-next-file
                PeekMessage ( &msg, NULL, 0, 0, PM_REMOVE );
                DispatchMessage ( &msg );
              }
              nVirtKey = GetAsyncKeyState ( VK_CONTROL );
              if ( nVirtKey & -1 ) {
                nVirtKey = GetAsyncKeyState ( 0x43 );//  'c ' key
                if ( nVirtKey & -1 )
                  return 0; //user hit control-c. stop finding
              }
            }
            #pragma endregion load richedit and find string in file
            else {
              if ( misses++ == iCount ) {
                #pragma region when_entire_column_has_been_searched_and_no_match_found
                if ( iCount >= 5000 ) {
                  MessageBox ( NULL, L "NO Matches found in the presearched files!\rPress 
                  ENTER or SELECT OK to search file-list. 
                  This could take a while! ", fsiaf, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL );
                }
                int searchStartRow = currentRow;
                ListView_SetItemState ( hList, -1, 0,
                            LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                findStringInAllFiles ( );
                #pragma endregion search every file in listview
                SetFocus ( hRich );
                #pragma region select_first_file_with_a_match
                if ( hRich && IsWindowVisible ( hRich ) ) {
                  result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
                  if ( searchStartRow != 0 ) {
                    result = searchStartRow + 1;
                  }
                  ListView_SetItemState ( hList, result,
                              LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED,
                              LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
                  ListView_GetItemText ( hList, result, 3, curntFname, 255 );
                  curntFname [ 255 ] = 0;
                  int fileSize = _wtoi ( curntFname );
                  if ( fileSize > 64 * 1024 * 1024 ) {
                    MessageBox ( hMainWnd, L "File Size  is too much for me! 
                    Can 't LOAD ", curntFname, MB_OK | MB_ICONEXCLAMATION );
                    ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
                    ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
                    wsprintf ( teXt, L "/select, \ "%s\\%s\ " ", curntPath, curntFname );
                    SetWindowText ( hEdit, teXt );
                    curntPath [ 259 ] = 0;
                    ShellExecute ( NULL, L "open ", 
                                   L "explorer.exe ", teXt, curntPath, SW_SHOW );
                    return 0;
                  }
                  ListView_GetItemText ( hList, result, 0, curntFname, MAX_PATH - 1 );
                  ListView_GetItemText ( hList, result, 2, curntPath, MAX_PATH - 1 );
                  StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
                  SetWindowText ( hMainWnd, tStr );
                  SetWindowText ( hEdit, tStr );
                  FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
                  HWND hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
                  iCount = 0;
                  if ( hList ) iCount = ListView_GetItemCount ( hList );
                  StringCchPrintf ( Text, 255, L "%d of %d Files ", result + 1, iCount );
                  SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) Text );
                  ShowWindow ( hRich, SW_SHOW );
                  SetFocus ( hRich );
                  if ( fsiaf ) {
                    FINDTEXTEX fndFrst;
                    fndFrst.chrg.cpMin = 0;
                    fndFrst.chrg.cpMax = -1;
                    fndFrst.lpstrText = fsiaf;
                    intRc = ( LONG ) SendMessage 
                            ( hRich, EM_FINDTEXTEXW, 1, ( LPARAM ) &fndFrst );
                    CHARFORMAT cf;
                    cf.cbSize = sizeof ( cf );
                    cf.dwMask = CFM_BOLD | CFM_UNDERLINE;
                    cf.dwEffects = CFE_BOLD | CFE_UNDERLINE;
                    SendMessage ( hRich, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM ) &cf );
                    DWORD dwerr = GetLastError ( );
                    dwerr = GetLastError ( );
                    if ( intRc == -1 ) {
                      if (1){
                        StringCchPrintf ( searchCap, 255, 
                        L "Could Not FIND Requested String!\tDo you want to Continue? " );
                        SetWindowText ( hMainWnd, searchCap );
                        SetWindowText ( hEdit, searchCap );
                        sendMeMyKey ( hList, VK_F5 );
                        intRc = ( LONG ) SendMessage ( hRich, EM_FINDTEXTEXW, 1, 
                                                     ( LPARAM ) &fndFrst );
                        if ( intRc == -1 ) {
                          intRc = 0;
                          SetFocus ( hRich );
                        }
                      }
                    }
                    else {
                      SendMessage ( hRich, EM_SETSEL, 
                                    fndFrst.chrgText.cpMin, fndFrst.chrgText.cpMax );
                      hwndStatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
                      int chLine = ( int ) SendMessage ( hRich, EM_EXLINEFROMCHAR, 0, intRc );
                      LONG strtLine = ( LONG ) SendMessage ( hRich, EM_LINEINDEX, chLine, 0 );
                      LONG colPos = intRc - strtLine;
                      StringCchPrintf ( Text, 255, L "Line: %d  Column: %d ", chLine, colPos );
                      SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, ( LPARAM ) Text );
                      return 1;
                    }
                  }
                }
                #pragma endregion and load it into richedit to find match
              }
              else if ( misses > iCount ) {
                MessageBox ( NULL, L "NO FILES containing Requested STRING were found!\rCheck 
                the spelling of STRING. ", fsiaf, MB_OK | MB_ICONHAND );
                return 0;// searched every file in listvie and found no matchesw
              }
            }
          }
          while ( !numbFound );
          SetFocus ( hList );
          return 0;
        }
        #pragma endregion looking for string-to-search-for in text
      }
      if ( ( pnkd )->wVKey == VK_F3 ) {
        #pragma region send_vk-f3
        sendMeMyKey ( hRich, VK_F3 );
        return 0;
        #pragma endregion to richedit
      }
      if ( ( pnkd )->wVKey == VK_F6 ) {
        #pragma region send_vk-f6
        sendMeMyKey ( hRich, VK_F6 );
        return 0;
        #pragma endregion to richedit
      }

      if ( ( pnkd )->wVKey == VK_F4 ) {
        short nVirtKey = GetKeyState ( VK_MENU );
        if ( nVirtKey & -128 ) {
          if ( hMainWnd ) {
            return DefWindowProc ( hMainWnd, message, wParam, lParam );
          }
          else {
            return 0;
          }
        }
        #pragma region get_full_path_and_file_attributes
        NMLISTVIEW * pnmlv;
        LVITEM lvi;
        int result = 0;
        struct _stat64 buf;
        pnmlv = ( LPNMLISTVIEW ) lParam;
        memset ( &lvi, 0, sizeof ( lvi ) );
        result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
        if ( result == -1 ) result = 0;
        lvi.iItem = result;
        lvi.mask = LVIF_TEXT;
        lvi.cchTextMax = 255;
        lvi.pszText = Text;
        if ( hList ) ListView_GetItem ( hList, &lvi );
        lvi.pszText = text;
        lvi.iSubItem = 2;// get the path
        ListView_GetItem ( hList, &lvi );
        wsprintf ( teXt, L "%s\\%s ", text, Text );
        result = _wstat64 ( teXt, &buf );
        if ( result == 0 ) {
          if ( ( buf.st_mode & _S_IFREG ) ) {
            wsprintf ( teXt, L "\ "%s\\%s\ " ", text, Text );
            SetWindowText ( hEdit, teXt );
            SHELLEXECUTEINFO ShExecInfo = { 0 };
            ShExecInfo.cbSize = sizeof ( SHELLEXECUTEINFO );
            ShExecInfo.fMask = SEE_MASK_INVOKEIDLIST;
            ShExecInfo.hwnd = hList;
            ShExecInfo.lpVerb = L "properties ";
            ShExecInfo.lpFile = Text; //can be a file as well
            ShExecInfo.lpParameters = L " ";
            ShExecInfo.lpDirectory = text;
            ShExecInfo.nShow = SW_SHOW;
            ShExecInfo.hInstApp = NULL;
            ShellExecuteEx ( &ShExecInfo );
          }
          if ( ( buf.st_mode & _S_IFDIR ) ) {
            wsprintf ( teXt, L "\ "%s\\%s\ " ", text, Text );
            if ( hEdit ) {
              SetWindowText ( hEdit, teXt );
            }
            ShellExecute ( NULL, L "properties ", teXt, NULL, NULL, SW_SHOWNORMAL );
          }
        }
        #pragma endregion and open with current file association
      }
    }
    break;

    case NM_RETURN:
    {
      #pragma region get_full_path_and_file_attributes
      // Keyboard RETuRN Key
      NMLISTVIEW * pnmlv;
      LVITEM lvi = { 0 };
      int result = 0;
      struct _stat64 buf;
      pnmlv = ( LPNMLISTVIEW ) lParam;
      memset ( &lvi, 0, sizeof ( lvi ) );
      result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
      if ( result == -1 ) return 0;
      lvi.iItem = result;
      lvi.mask = LVIF_TEXT;
      lvi.cchTextMax = 255;
      lvi.pszText = Text;
      ListView_GetItem ( hList, &lvi );
      lvi.pszText = text;
      lvi.iSubItem = 2;// get the path
      ListView_GetItem ( hList, &lvi );
      wsprintf ( teXt, L "%s\\%s ", text, Text );
      result = _wstat64 ( teXt, &buf );
      if ( result == 0 ) {
        if ( ( buf.st_mode & _S_IFREG ) ) {
          wsprintf ( teXt, L "/select, \ "%s\\%s\ " ", text, Text );
          SetWindowText ( hEdit, teXt );
          ShellExecute ( NULL, L "open ", L "explorer.exe ", teXt, text, SW_SHOW );
        }
        if ( ( buf.st_mode & _S_IFDIR ) ) {
          wsprintf ( teXt, L "\ "%s\\%s\ " ", text, Text );
          SetWindowText ( hEdit, teXt );
          ShellExecute ( NULL, L "explore ", teXt, NULL, NULL, SW_SHOWNORMAL );
        }
      }
      #pragma endregion and open with current file association
    }break; // case NM_RETURN 

    case NM_SETFOCUS:
    {
      int rslt = 0;
      rslt = ListView_GetItemCount ( hList );
      if ( rslt >= 1 ) {
        if ( ( rslt = ListView_GetNextItem ( hList, -1, LVNI_SELECTED ) ) == -1 ) {
          ListView_SetItemState ( hList, 0, LVIS_SELECTED | LVIS_DROPHILITED | LVIS_FOCUSED,
                      LVIS_SELECTED | LVIS_DROPHILITED | LVIS_FOCUSED ); // select this one
          return 1;
        }
      }
    } //  case NM_SETFOCUS
    break;
    } // switch (((LPNMHDR)lParam)->code)
  }break; // case WM_NOTIFY

    case WM_NCLBUTTONUP:
  {
    ClipCursor ( NULL );
    return 0;
  }break;

  case WM_SIZING:
  {
    RECT* dragRc = ( RECT* ) lParam;
    RECT mrc = { 0 }, wrc = { 0 }, wrccl = { 0 }, crc = { 0 }, lrc = { 0 }, lrccl = {0 },
      trc = { 0 }, trccl = { 0 },rrc = { 0 }, rrccl = {0 }, temprc = {0 },
      drc = { 0 }, src = { 0 }, srccl = { 0 }, brc = { 0 }, 
      brccl = { 0 }, toprc = { 0 }, toprccl = { 0 }, f0rc = { 0 },
      f0rccl = { 0 }, erc = { 0 }, erccl = { 0 },  oldCliprc = { 0 }, clipRc = { 0 };
    POINT xPos = { 0 };
    GetCursorPos ( &xPos );
    HWND hWnd = FindWindow ( L "TwoStageSearch ", 0 );
    GetWindowRect ( hWnd, &wrc );
    GetClientRect ( hWnd, &wrccl );
    HWND hTopView = FindWindowEx ( hWnd, 0, L "#32770 ", 0 );
    GetWindowRect ( hTopView, &toprc );
    GetClientRect ( hTopView, &toprccl );
    HWND hFormView0 = FindWindowEx ( hTopView, 0, L "#32770 ", 0 );
    GetWindowRect ( hFormView0, &f0rc );
    GetClientRect ( hFormView0, &f0rccl );
    hEdit = FindWindowEx (hFormView0, 0, L "Edit ", 0 );
    GetWindowRect ( hEdit, &erc );
    GetClientRect ( hEdit, &erccl );
    GetWindowRect ( hDlg, &lrc );
    HWND hBottomView = GetParent ( hDlg );
    HWND hFormView1 = GetNextWindow ( hDlg, GW_HWNDNEXT );
    HWND hFormView3 = GetNextWindow ( hDlg, GW_HWNDPREV );
    HWND hStatusView = GetNextWindow ( hFormView3, GW_HWNDPREV );
    hFormView2 = hDlg;
    hList = getThisWindowHandle ( hFormView2, IDC_LIST1 );
    hTree = getThisWindowHandle ( hFormView1, IDC_TREE1 );
    hRich = getThisWindowHandle ( hFormView3, IDC_EDIT1 );
    HWND hwndStatus = getThisWindowHandle ( hStatusView, IDC_STATUS );
    GetWindowRect ( hStatusView, &src );
    GetClientRect ( hwndStatus, &srccl );
    GetClientRect ( hTree, &trccl );
    GetClientRect ( hList, &lrccl );
    GetClientRect ( hRich, &rrccl );
    GetWindowRect ( hBottomView, &brc );
    GetClientRect ( hBottomView, &brccl );
    GetClientRect ( hWnd, &crc );
    GetWindowRect ( hWnd, &wrc );
    GetWindowRect ( hDlg, &drc );
    GetWindowRect ( hFormView1, &trc );
    GetWindowRect ( hFormView2, &lrc );
    GetWindowRect ( hFormView3, &rrc );
    OffsetRect ( &toprc, -wrc.left, -wrc.top );
    OffsetRect ( &f0rc, -wrc.left, -wrc.top );
    OffsetRect ( &erc, -wrc.left, -wrc.top );
    OffsetRect ( &brc, -wrc.left, -wrc.top );
    OffsetRect ( &trc, -wrc.left, -wrc.top );
    OffsetRect ( &lrc, -wrc.left, -wrc.top );
    OffsetRect ( &rrc, -wrc.left, -wrc.top );
    OffsetRect ( &src, -wrc.left, -wrc.top );
    CopyRect ( &temprc, dragRc );
    OffsetRect ( &temprc, -wrc.left, -wrc.top );

    if ( wParam != WMSZ_RIGHT &&
       wParam != WMSZ_LEFT )
    {
      GetClipCursor ( &oldCliprc );
      clipRc.left = drc.left;
      clipRc.top = xPos.y;
      clipRc.right = drc.right;
      clipRc.bottom = xPos.y + 1;
      ClipCursor ( &clipRc );
    }
    if ( wParam == WMSZ_RIGHT ) {
      GetClipCursor ( &oldCliprc );
      clipRc.left = drc.left+100;
      clipRc.top = xPos.y;
      clipRc.right = wrc.right-wrc.left - 20;
      clipRc.bottom = xPos.y + 1;
      ClipCursor ( &clipRc );
      MoveWindow ( hFormView3, lrc.right-8, 0, wrccl.right - lrc.right+8, 
                   lrc.bottom - lrc.top, TRUE );
      MoveWindow ( hRich, 0, 0, wrccl.right - lrc.right+8, lrc.bottom - lrc.top, TRUE );
    }
    if ( wParam == WMSZ_LEFT ) {
      GetClipCursor ( &oldCliprc );
      clipRc.left = wrc.left + 50;
      clipRc.top = xPos.y;
      clipRc.right = drc.right-30;
      clipRc.bottom = xPos.y + 1;
      ClipCursor ( &clipRc );
      MoveWindow ( hFormView1, 0, 0, temprc.left-4, temprc.bottom - temprc.top+4, TRUE );
      GetWindowRect ( hFormView1, &trc );
      OffsetRect ( &trc, -wrc.left, -wrc.top );
    }
    MoveWindow ( hList, 0, 0, lrc.right - lrc.left - 16, lrc.bottom - lrc.top - 16, TRUE );
    return 0;
  }break;

  case WM_SIZE:
  {
    UINT width = GET_X_LPARAM ( lParam );
    UINT height = GET_Y_LPARAM ( lParam );
    MoveWindow ( hList, 0, 0, width, height, TRUE );
    return 0;
  }
  break;

  case WM_ACTIVATE:
  {
    if ( LOWORD ( wParam ) & WA_ACTIVE ) {
      if ( hWndFocus ) {
        SetFocus ( hWndFocus );
        return 0;
      }
      else {
        hWndFocus = hList;
        SetFocus ( hList );
        if ( ListView_GetItemCount ( hList ) >= 1 ) {
          if ( ListView_GetNextItem ( hList, -1, LVNI_SELECTED ) == -1 ) {
            // select this one
            ListView_SetItemState ( hList, 0, LVIS_SELECTED, LVIS_SELECTED );
          }
        }
        return 0;
      }
    }
    else
      return -1;
  }
  break;

  default:
    break;
  }
  return 0;
}

How to Change the ROOT Folder for the File List: The Menu and the Tree View

The Windows program that the user sees resembles the Windows File Explorer superficially. It has a TreeView on the left, used to navigate the file system and select a current directory path, a ListView in the middle and a file viewer on the right side. But it's not intended for file management. Its only purpose is to find a string in a file and display it in the context in which it is used. It finds forward with PF3 and finds backwards when PF3 is used with shift. It will also find backwards with PF6. When finding backwards, if no more occurrences can be found, it will find the first occurrence in the next containing a match or the last occurrence in a previous file with a match. You can immediately go to the next file with PF5 or the preceding file with PF5 and shift. There is other functionality in the program but it is there to support the find functions.

The TwoStageSearch Menu is very sparse, and that is intentional. In the screen shot below, you see the menu with Change Directory selected. The text in the Title Bar of the main window says 'Two Stage Search - Build ... '. In the slightly smaller screen shot on the right, we see the Title Text now says 'Use CURSOR KEYS to Navigate in the ... '. In the TreeView, the user moves the selection from 'ASUS ' To 'All Users'. The Edit Box contains 'c:\Users\All Users'. The status bar still says 'c:\Users\asus'. The last step is to push 'ENTER ' to accept the change. The user could just click on the folder of their choice, but doing this deletes the contents of the ListView and populates it with the children of the selected folder, if any. To get files from more than one Root, you must use the Menu.

The significance of the Title Text is it is used by the TreeView Proc to detect the request to change directories. When the focus is on the TreeView and the user pushes 'ENTER', the NM_RETURN handler gets the Title Text. It is compared to several different control strings. If the control string matches the Title Text, the corresponding request is executed. The Change Directory request will change the root folder and save it in the Registry. The second request, Temp_Change_CD will temporarily change it and the third request, CD_AND_Build will change it and build the file list.

Changing the Start In Directory: Click on the Menu

Click on the Menu and select Change Directory.

To Change the ROOT Folder or Start In Directory, click on the Menu and select Change_Directory

The TreeView Proc also Handles the Other Messages Sent to the TreeView Control

In the WM_INITDIALOG message handler, we make sure that we're not in hBottom itself, but are in hFormView1. Then we create a font, create the treectrl and send it the WM_SETFONT message. Then we call SetTreeviewImagelist and get the search root, startInDir from the Environment Variable to set the current Directory. We set the TreeView extended styles to double buffered in order to cut down on flickering. Then we show the main window.

The message handler for WM_NOTIFY contains the switch for the (LP)NMHDR lParam code for TVN_SELCHANGING, which gets the NODE's full path, back to the drive and ensures that it is visible.

The NMHDR lParam code for TVN_SELCHANGED checks if the action is TVC_UNKNOWN and startInDir is not blank, it populates and expands the tree nodes until startInDir is located. If the action is TVC_BYKEYBOARD, the current item is selected and highlighted. If the action is TVC_BYMOUSE and current item is a folder, the contents of the folder replaces the ListView contents. If it is not a folder, the item is added to the ListView.

The NMHDR lParam code for TVN_ITEMEXPANDING populates the child nodes with files and folders, always and only one level deeper. This creates the populate on demand behavior of the TreeView.

The NMHDR lParam code for TVN_ITEMEXPANDED will, if startInDir is not blank, populate and expand the tree nodes until startInDir is located. This will show the Root Folder for the File List Build as the selected TreeView Item.

The NMHDR lParam code for NM_CLICK populates ListView when node is already selected by keyboard and then clicked by mouse.

The NMHDR lParam code for NM_RETURN populates ListView when node is selected by keyboard and then Enter is pressed. When TreeView receives focus from Menu Selection, it gets text from Title of Main Window to determine whether to save CD temporarily, permanently or just to use it to perform file list build, also gets environment variable for extension set.

The NMHDR lParam code for TVN_KEYDOWN will handle VK_TAB and VK_F5 by setting the focus to ListView.

The WM_SIZE message handler will re-size the TreeView control when the container FormView1 is moved by the ListView control's sizing border on the LEFT side of the control, based on the current relationship of the two controls, to fill the containing window but leaving a narrow strip in between them.

The treeViewProc Function

C++
// Message handler for tree view. Processes WM_NOTIFY for the following messages: 
// TVN_SELCHANGING - Gets the NODE 's full path, back to the drive. 
// TVN_SELCHANGED - If action is TVC_UNKNOWN and startindir is not blank, 
// populates and expands tree until startin dir is located. 
// If action is TVC_BYKEYBOARD current item is selected and 
// highlighted If action is TVC_BYMOUSE and current item is a folder 
// the contents of the folder replaces the listview contents.
// If it's not a folder the item is added to the listview. 
// TVN_ITEMEXPANDING - populates the child nodes with files and folders, 
// always and only one level deeper. 
// TVN_ITEMEXPANDED - If startindir is not blank, populates and expands tree 
// until startin dir is located. 
// NM_CLICK - populates ListView when node is selected by keyboard and 
// then clicked by mouse. 
// NM_RETURN - populates ListView when node is selected by keyboard and 
// then Enter is pressed. When TreeView
// receives focus from Menu Selection it gets text from Title of MainWindow 
// to determine whether to save CD 
// temporarily, permanently or just to perform file list build, 
// also gets environment variable for extension set.
// WM_SIZE wil re-size the TreeView control when the container 
// FormView1 is moved by the ListView
// control 's sizing border on the LEFT side of the control 
// based on the current relationship of the 
// two controls, to fill the containing window but leaving a narrow strip 
// in between them. 
INT_PTR CALLBACK treeViewProc 
( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
  UNREFERENCED_PARAMETER ( wParam );
  TCHAR nodeCD [ MAX_PATH ] = { 0 };
  TCHAR startInDir [ MAX_PATH ] = { 0 };
  HWND hMainWnd = NULL, hTree = NULL, hList = NULL, hEdit = NULL;
  TV_ITEM tvi;
  DWORD sidLen = 0;

  if ( WM_INITDIALOG == message ) {
    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    HWND hBottom = GetAncestor ( hDlg, GA_PARENT );
    if ( hMainWnd == hBottom ) {
      return 0;
    }
    hTree = FindWindowEx ( hDlg, 0, L "SysTreeView32 ", 0 );
    if ( hTree == 0 ) {
      HFONT hFont = CreateFont ( 32, 10, 0, 0, FW_BOLD, FALSE, 
                     FALSE, FALSE, ANSI_CHARSET, \
                     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \
                     DEFAULT_PITCH | FF_SWISS, L "Arial " );
      RECT sRc;
      GetClientRect ( hDlg, &sRc );
      hTree = CreateWindowEx ( WS_EX_OVERLAPPEDWINDOW | WS_EX_STATICEDGE | 
                   WS_EX_COMPOSITED | WS_EX_NOINHERITLAYOUT,
                   WC_TREEVIEW, NULL,
                   WS_CHILD | WS_VISIBLE |
                   DS_3DLOOK | WS_BORDER | WS_CLIPSIBLINGS | 
                   WS_CLIPCHILDREN | WS_TABSTOP |
                   TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT,
                   sRc.left, sRc.top, sRc.right, sRc.bottom, hDlg,
                   ( HMENU ) IDC_TREE1, hInst, 0 );
      SendMessage ( hTree, WM_SETFONT, WPARAM ( hFont ), TRUE );
      GetClientRect ( hDlg, &sRc );
      SetTreeviewImagelist ( hTree );
      sidLen = GetEnvironmentVariable ( L "startInDir ", startInDir, 255 );
      SetCurrentDirectory ( startInDir );
      if ( _wcsicmp ( startInDir, nodeCD ) != 0 ) {
        StringCchPrintf ( nodeCD, 255, L "%s ", startInDir ); // define the 
                                                  // start-in-directory for XP
        SetCurrentDirectory ( nodeCD );
        GetCurrentDirectory ( 255, startInDir );
      }
      else {
        StringCchPrintf ( nodeCD, 255, L "%s ", startInDir ); // initialize 
            // in case user did not select anything before clicking  'search '
      }
      sidLen = GetEnvironmentVariable ( L "HOMEDRIVE ", startInDir, 255 );
      RECT wrc = { 0 };
      GetWindowRect ( hMainWnd, &wrc );
      TreeView_SetExtendedStyle ( hTree, TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER );
      MoveWindow ( hMainWnd, wrc.left, wrc.top, wrc.right - wrc.left, 
                   wrc.bottom - wrc.top, TRUE );
      ShowWindow ( hMainWnd, SW_NORMAL );
      return ( INT_PTR ) TRUE;
    }
  }
  else {
    if ( WM_NOTIFY == message ||
       WM_SIZE == message ) {
      if ( (  hMainWnd = FindWindow ( L "TwoStageSearch ", 0 )) == 0 ) return 0;
      if ( (  hTree = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_TREE1 )) == 0) 
         return 0;
      if ( ( hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 ) ) == 0 ) 
         return 0;
      if ( ( hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 )) == 0) 
         return 0;
    }
  }

  switch ( message ) {

  case WM_ERASEBKGND:
    return 1;

  case WM_NOTIFY:
  { // messages from child window common controls
    if ( ( hMainWnd = FindWindow ( L "TwoStageSearch ", 0 ) ) == 0 ) return 0;
    if ( ( hTree = getThisWindowHandle 
          ( hMainWnd, ( ULONG ) IDC_TREE1 ) ) == 0 ) return 0;
    if ( ( hList = getThisWindowHandle 
          ( hMainWnd, ( ULONG ) IDC_LIST1 ) ) == 0 ) return 0;
    if ( ( hEdit = getThisWindowHandle 
          ( hMainWnd, ( ULONG ) IDC_EDIT2 ) ) == 0 ) return 0;

    switch ( ( ( LPNMHDR ) lParam )->idFrom ) {
    case IDC_TREE1:
    {
      switch ( ( ( LPNMHDR ) lParam )->code ) {
      case  TVN_SELCHANGING:
      { // Gets the NODE 's full path, back to the drive. 
        NMTREEVIEW * pnmtv; // Handle to the NM TreeView STRUCTURE
        pnmtv = ( LPNMTREEVIEW ) lParam; // set the Handle to the 
                                         // NM TreeView STRUCTURE
        tvi = ( ( pnmtv )->itemNew );    // set the Handle to the tvitem 
                                     // STRUCTURE for the item that was just selected 
        getNodeFullPath ( hTree, tvi.hItem );
        TreeView_EnsureVisible ( hTree, tvi.hItem );
        return FALSE;
      }  break; // case  TVN_SELCHANGING

      case TVN_SELCHANGED:
      {
        // populates ListView when node is expanded by mouse. 
        // picks-up process to find startinDirectory when node is 
        // selected by code or by clicking  '+ ' button on node
        // updates  'HighLite ' status if node is selected by keyboard
        NMTREEVIEW * pnmtv;
        pnmtv = ( LPNMTREEVIEW ) lParam;
        HTREEITEM  nmtvi;
        sidLen = GetEnvironmentVariable ( L "STARTINDIR ", startInDir, 255 );
        nmtvi = TreeView_GetSelection ( hTree );
        TCHAR Text [ 256 ] = { 0 };
        TCHAR text [ 256 ] = { 0 };
        DWORD result = 0;
        memset ( &tvi, 0, sizeof ( tvi ) );
        tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
        tvi.pszText = Text;
        tvi.cchTextMax = 255;
        tvi.hItem = nmtvi;
        if ( ( pnmtv )->action == TVC_UNKNOWN ) {
          if ( *startInDir ) {
            // is there a start-in-directory 
            GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
            if ( _wcsnicmp ( startInDir, nodeCD, wcslen ( nodeCD ) ) == 0 ) {
              // is it in the path
              if ( TreeView_GetItem ( hTree, &tvi ) ) {
                // could you get the item 
                if ( tvi.cChildren > 0 ) {
                  // does it have children
                  if ( tvi.state & TVIS_EXPANDEDONCE ) {
                    // node has children and has been expanded. 
                    // Go on to the next higher level
                    nmtvi = TreeView_GetChild ( hTree, nmtvi );
                    while ( nmtvi ) {
                      // loop to get the child 's label text
                      memset ( &tvi, 0, sizeof ( tvi ) );
                      memset ( &Text, 0, sizeof ( Text ) );
                      tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
                      tvi.pszText = Text;
                      tvi.cchTextMax = 255;
                      tvi.hItem = nmtvi;
                      if ( TreeView_GetItem ( hTree, &tvi ) ) {
                        if ( nodeCD [ wcslen ( nodeCD ) - 1 ] != L '\\ ' ) {
                          // concat in text buffer
                          wsprintf ( text, L "%s\\%s ", nodeCD, tvi.pszText );
                        }
                        else {
                          // concat in text buffer
                          wsprintf ( text, L "%s%s ", nodeCD, tvi.pszText );
                        }
                        result = ( int ) wcslen ( text );
                        // when lengths are the same compare
                        if ( sidLen == result && ( _wcsicmp 
                          ( startInDir, text ) == 0 ) ) {
                          // when strings are same 
                          SetCurrentDirectory ( nodeCD );
                          memset ( startInDir, 0, sizeof ( startInDir ) );
                          TreeView_Select ( hTree, nmtvi, TVGN_CARET );
                          TreeView_Select ( hTree, nmtvi, TVGN_DROPHILITE );
                          // comment this out to position at bottom
                          TreeView_Select ( hTree, nmtvi, TVGN_FIRSTVISIBLE );
                          SetFocus ( hTree );
                          return 0;
                        }
                        else {
                          wsprintf ( text, L "%s\\ ", text ); // concat a back-slash
                          result = ( int ) wcslen ( text );   //take the length 
                                                              //again(it just changed)
                          if ( _wcsnicmp ( startInDir, 
                               text, result ) == 0 ) { // is folder in path
                            if ( tvi.cChildren > 0 ) {
                              if ( !( tvi.state & TVIS_EXPANDEDONCE ) ) 
                              { //node has children but has never been expanded. 
                                //TVN_EXPANDED will take over now.
                                TreeView_Expand ( hTree, tvi.hItem, 
                                     TVE_EXPAND ); // we are through here
                                return 0; //terminate the routine
                              }
                              else { // folder in path, go on to the 
                                     // next higher level
                                if ( nodeCD [ wcslen ( nodeCD ) - 1 ] != L '\\ ' ) {
                                  wsprintf ( nodeCD, L "%s\\%s ", 
                                             nodeCD, tvi.pszText );
                                }
                                else {
                                  wsprintf ( nodeCD, L "%s%s ", nodeCD, tvi.pszText );
                                }
                                nmtvi = TreeView_GetChild ( hTree, nmtvi );
                              }
                            }
                            else { // there are no children. end
                              return 0;
                            }
                          }
                          else {
                            // get the next child 's handle
                            nmtvi = TreeView_GetNextSibling ( hTree, nmtvi );
                          }
                        }
                      }
                    } // loop to get the child 's label text
                  }   // node has children and has been expanded. 
                      //Go on to the next higher level
                }     // does it have children
              }       // could you get the item 
            }         // is it in the path
            else {
              return 0; // don 't do  anything
            }
            return 0;
          } // is there a start-in-directory 
        }

        if ( ( pnmtv )->action == TVC_BYKEYBOARD ) {
          TreeView_Select ( hTree, nmtvi, TVGN_CARET );
          TreeView_Select ( hTree, nmtvi, TVGN_DROPHILITE );
          return 0;
        }

        if ( ( pnmtv )->action == TVC_BYMOUSE ) {
          TreeView_Select ( hTree, nmtvi, TVGN_DROPHILITE );
          TreeView_Select ( hTree, nmtvi, TVGN_CARET );
          tvi.hItem = nmtvi;
          if ( TreeView_GetItem ( hTree, &tvi ) ) {
            if ( tvi.iImage == 4 ) { // not a folder
              LVITEM item;
              memset ( &item, 0, sizeof ( item ) );
              GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
              item.mask = LVIF_TEXT;
              item.iItem = 0;
              item.iSubItem = 0;
              item.cchTextMax = 260;
              item.pszText = tvi.pszText;
              int ret = 0, nRet = 0;
              ret = ListView_InsertItem ( hList, &item );
              item.iItem = ret;
              item.iSubItem = 2;
              item.pszText = nodeCD;
              ListView_SetItem ( hList, &item );
              nRet = ret + 1;
              ListView_GetItemText ( hList, nRet, 0, text, 255 );
              while ( _wcsicmp ( text, tvi.pszText ) == 0 ) { //  'text ' is  
                                                              //'Name ' in listview
                ListView_GetItemText ( hList, nRet, 1, text, 255 );
                if ( _wcsicmp ( text, nodeCD ) == 0 ) { // now  'text ' is  
                                                        // 'Path ' in listview
                  ListView_DeleteItem ( hList, ret );   // it 's a duplicate. 
                                                        // Delete it. 
                  ret = nRet;
                }
                nRet = nRet + 1;
                ListView_GetItemText ( hList, nRet, 0, text, 255 ); // now it's 
                                                                    //'Name ' again 
              }
              ListView_SetItemState ( hList, -1, 0, 
                       LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
              ListView_SetItemState ( hList, ret, 
                       LVIS_DROPHILITED, LVIS_DROPHILITED );
              ListView_SetItemState ( hList, ret, LVIS_SELECTED, LVIS_SELECTED );
              ListView_SetItemState ( hList, ret, LVIS_FOCUSED, LVIS_FOCUSED );
              ListView_EnsureVisible ( hList, ret, TRUE );
              SetFocus ( hList );
            } // the item is not a folder, add it to the listview
            else if ( tvi.cChildren == 1 ) { // it is a folder, 
                 // clear listview and populate it with folder contents. 
              nmtvi = TreeView_GetChild ( hTree, nmtvi );
              memset ( &tvi, 0, sizeof ( tvi ) );
              memset ( &Text, 0, sizeof ( Text ) );
              tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
              tvi.pszText = Text;
              tvi.cchTextMax = 255;
              tvi.hItem = nmtvi;
              if ( TreeView_GetItem ( hTree, &tvi ) ) {
                ListView_DeleteAllItems ( hList );
                GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
                do {
                  LVITEM item;
                  memset ( &item, 0, sizeof ( item ) );
                  item.mask = LVIF_TEXT;
                  item.iItem = 0;
                  item.iSubItem = 0;
                  item.cchTextMax = 260;
                  item.pszText = tvi.pszText;
                  int ret = ListView_InsertItem ( hList, &item );
                  item.iItem = ret;
                  item.iSubItem = 2;
                  item.pszText = nodeCD;
                  ListView_SetItem ( hList, &item );
                  if ( ret < 1 )
                    ret *= -1;
                  nmtvi = tvi.hItem;
                  nmtvi = TreeView_GetNextSibling ( hTree, nmtvi );
                  memset ( &tvi, 0, sizeof ( tvi ) );
                  memset ( &Text, 0, sizeof ( Text ) );
                  tvi.mask = TVIF_TEXT;
                  tvi.pszText = Text;
                  tvi.cchTextMax = 255;
                  tvi.hItem = nmtvi;
                }
                while ( TreeView_GetItem ( hTree, &tvi ) );
              }
            }
          }
        }
      } break; // case TVN_SELCHANGED 

      case TVN_ITEMEXPANDING:
      { // populates the child nodes with files and folders, always one level deeper. 
        NMTREEVIEW * pnmtv;
        HTREEITEM  nmtvi = { 0 };
        sidLen = GetEnvironmentVariable ( L "STARTINDIR ", startInDir, 255 );
        pnmtv = ( LPNMTREEVIEW ) lParam;
        TCHAR Text [ 256 ] = { 0 };
        tvi = ( ( pnmtv )->itemNew );
        nmtvi = TreeView_GetSelection ( hTree );
        if ( NULL != nmtvi && tvi.hItem != nmtvi ) {
          // user clicked on node button(+), node is not selected
          TreeView_SelectItem ( hTree, tvi.hItem );
        }
        if ( ( pnmtv )->action & TVE_COLLAPSE ) { // the folder is closing, 
               // set its image indexes  to show a closed folder
          tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
          tvi.iImage = 0; // Closed 
          tvi.iSelectedImage = 1; // Closed and selected 
          TreeView_SetItem ( hTree, &tvi );
          return FALSE;
        }
        // still here? Okay, then this node is expanding but it has no grandchildren yet. 
        // Give it 's CHILDREN some Children so that it 's CHILDREN will have BUTTONS.
        tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
        tvi.iImage = 2;// FOLDEROPEN 
        tvi.iSelectedImage = 3;// opened and selected
        TreeView_SetItem ( hTree, &tvi ); // set the image indexes to show open folders.
        if ( tvi.state & TVIS_EXPANDEDONCE )
          return FALSE; // don 't duplicate children
        tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
        tvi.pszText = Text;
        tvi.cchTextMax = 255;
        if ( TreeView_GetItem ( hTree, &tvi ) ) { // you 've got the requested attributes 
          if ( tvi.pszText [ 1 ] == L ': ' ) { //the second character is a colon. It 's a DRIVE 
            wsprintf ( nodeCD, L "%s ", Text );
            SetCurrentDirectory ( nodeCD );
            nmtvi = TreeView_GetChild ( hTree, tvi.hItem );
          }
          else { //the second character is not a colon. This is not a DRIVE 
            memset ( &nodeCD, 0, sizeof ( nodeCD ) );
            nmtvi = TreeView_GetChild ( hTree, tvi.hItem );
          } // either way, you might now have the first child of the node
          while ( nmtvi ) { // if you have the child, do the loop 
            memset ( &tvi, 0, sizeof ( tvi ) );
            memset ( &Text, 0, sizeof ( Text ) );
            tvi.hItem = nmtvi;
            tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
            tvi.pszText = Text;
            tvi.cchTextMax = 255;
            if ( TreeView_GetItem ( hTree, &tvi ) ) { // just in case the handle is corrupted 
              DWORD dwLen = GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
              if ( dwLen == 0 || dwLen > MAX_PATH - 2 )
                return 0;
              if ( nodeCD [ wcslen ( nodeCD ) - 1 ] != L '\\ ' ) 
              { // does not end with a back-slash
                wsprintf ( nodeCD, L "%s\\ ", nodeCD ); // concat a back-slash to nodeCD 
              }
              wsprintf ( nodeCD, L "%s%s ", nodeCD, tvi.pszText ); // concat to nodeCD 
              getDirectories ( tvi.hItem, nodeCD );
              nmtvi = TreeView_GetNextSibling ( hTree, tvi.hItem );
            }
          }
        }
        return FALSE;
      } break; // case TVN_ITEMEXPANDING

      case TVN_ITEMEXPANDED: // This folder has just been expanded. 
      { // Is it and any of it 's children in the srart-in-directory?
        NMTREEVIEW * pnmtv;
        HTREEITEM  nmtvi;
        sidLen = GetEnvironmentVariable ( L "STARTINDIR ", startInDir, 255 );
        pnmtv = ( LPNMTREEVIEW ) lParam;
        TCHAR Text [ 256 ] = { 0 };
        TCHAR text [ 256 ] = { 0 };
        if ( ( pnmtv )->action & TVE_COLLAPSE )
          return 0; // don 't do  anything
        tvi = ( ( pnmtv )->itemNew );
        tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
        tvi.pszText = Text;
        tvi.cchTextMax = 255;
        if ( TreeView_GetItem ( hTree, &tvi ) ) { // you 've got the requested attributes 
          if ( *startInDir ) { // is there a start-in-directory
            memset ( &nodeCD, 0, sizeof ( nodeCD ) );
            nmtvi = TreeView_GetChild ( hTree, tvi.hItem );
            while ( nmtvi ) { // if you have the child, do the loop 
              tvi.hItem = nmtvi;
              DWORD dwLen = GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
              if ( dwLen == 0 || dwLen > MAX_PATH - 2 )
                return 0;
              if ( TreeView_GetItem ( hTree, &tvi ) ) { // just in case the handle is corrupted 
                if ( nodeCD [ wcslen ( nodeCD ) - 1 ] != L '\\ ' ) 
                { // if it doesn 't have a backslash on the end, add one 
                  wsprintf ( nodeCD, L "%s\\ ", nodeCD );
                }
                wsprintf ( text, L "%s%s ", nodeCD, tvi.pszText );
                if ( _wcsnicmp ( startInDir, text, wcslen ( text ) ) == 0 ) {
                  if ( ( _wcsicmp ( ( startInDir ), ( text ) ) ) == 0 ) {
                    memset ( startInDir, 0, sizeof ( startInDir ) );
                    TreeView_Select ( hTree, nmtvi, TVGN_CARET );
                    TreeView_Select ( hTree, nmtvi, TVGN_DROPHILITE );
                    SetFocus ( hTree );
                    return FALSE;
                  }
                  wsprintf ( text, L "%s\\ ", text );
                  if ( _wcsnicmp ( startInDir, text, wcslen ( text ) ) == 0 ) {
                    if ( tvi.cChildren > 0 ) {
                      if ( !( tvi.state & TVIS_EXPANDEDONCE ) ) 
                      { //node has children but has never been expanded. 
                        //TVN_EXPANDED will take over now.
                        SetCurrentDirectory ( text );
                        TreeView_Expand ( hTree, tvi.hItem, TVE_EXPAND ); // we are through here
                        return FALSE; //terminate the routine
                      }
                    }
                  }
                }
                nmtvi = TreeView_GetNextSibling ( hTree, tvi.hItem );
              } // just in case the handle is corrupted 
            } // if you have the child, do the loop 
          } // is there a start-in-directory
        } //you 've got the requested attributes 
        return FALSE;
      }
      break; // case TVN_ITEMEXPANDED

      case  NM_CLICK:
      { // populates ListView when node is selected by keyboard and then clicked by mouse. 
        HTREEITEM  nmtvi;
        NMHDR * lpnmh;
        TCHAR Text [ 256 ] = { 0 };
        TCHAR text [ 256 ] = { 0 };
        lpnmh = ( LPNMHDR ) lParam;
        HWND hwndFrom = ( lpnmh )->hwndFrom;
        TVHITTESTINFO  lpht = { 0 };
        POINT pt;
        GetCursorPos ( &pt ); // get the screen coordinates of the cursor
        ScreenToClient ( hwndFrom, &pt ); // convert them to client coordinates
        lpht.pt = pt; //put it in the hit test info structure
        TreeView_HitTest ( hwndFrom, &lpht ); // hit me!
        SetFocus ( hTree );
        HTREEITEM nmClickedtvi = lpht.hItem;
        nmtvi = TreeView_GetSelection ( hwndFrom );
        if ( nmtvi != nmClickedtvi )   // the clicked node hasn 't been 
        {
          return 0;
        }  // selected yet. don 't do anything else
        if ( lpht.flags && TVHT_ONITEM ) // TVHT_ONITEMBUTTON 
                                                 // you clicked on a selected treeview node. 
        { // The selection status is not going to change. You have to handle it. 
          memset ( &tvi, 0, sizeof ( tvi ) );
          tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
          tvi.pszText = Text;
          tvi.cchTextMax = 255;
          tvi.hItem = nmtvi;
          if ( TreeView_GetItem ( hwndFrom, &tvi ) ) { // you got the item that was clicked 
            GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
            if ( tvi.iImage == 4 ) { // the item is not a folder, add it to the listview
              LVITEM item;
              memset ( &item, 0, sizeof ( item ) );
              item.mask = LVIF_TEXT;
              item.iItem = 0;
              item.iSubItem = 0;
              item.cchTextMax = 260;
              item.pszText = tvi.pszText;
              int ret = ListView_InsertItem ( hList, &item );
              item.iItem = ret;
              item.iSubItem = 2;
              item.pszText = nodeCD;
              ListView_SetItem ( hList, &item );
              int nRet = ret + 1;
              ListView_GetItemText ( hList, nRet, 0, text, 255 );
              while ( _wcsicmp ( text, tvi.pszText ) == 0 ) {
                ListView_GetItemText ( hList, nRet, 1, text, 255 );
                if ( _wcsicmp ( text, nodeCD ) == 0 ) {
                  ListView_DeleteItem ( hList, ret ); // delete one of them
                  ret = nRet;
                }
                nRet = nRet + 1;
                ListView_GetItemText ( hList, nRet, 0, text, 255 );
              }
              ListView_SetItemState ( hList, -1, 0, LVIS_DROPHILITED | 
                                      LVIS_SELECTED | LVIS_FOCUSED );
              ListView_SetItemState ( hList, ret, LVIS_DROPHILITED, LVIS_DROPHILITED );
              ListView_SetItemState ( hList, ret, LVIS_SELECTED, LVIS_SELECTED );
              ListView_SetItemState ( hList, ret, LVIS_FOCUSED, LVIS_FOCUSED );
              ListView_EnsureVisible ( hList, ret, TRUE );
              SetFocus ( hList );
            } // the item is not a folder, addit to the listview
            else if ( tvi.cChildren == 1 ) { // the item has children, 
                                             // get the first one and set-up loop  
              nmtvi = TreeView_GetChild ( hwndFrom, nmtvi );
              memset ( &tvi, 0, sizeof ( tvi ) );
              memset ( &Text, 0, sizeof ( Text ) );
              tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
              tvi.pszText = Text;
              tvi.cchTextMax = 255;
              tvi.hItem = nmtvi;
              if ( TreeView_GetItem ( hwndFrom, &tvi ) ) 
              { // delete all the listview items and re build the list 
                ListView_DeleteAllItems ( hList );
                GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
                do { //  while (TreeView_GetItem(hwndFrom, &tvi))
                  LVITEM item;
                  memset ( &item, 0, sizeof ( item ) ); // zap the item
                  item.mask = LVIF_TEXT; // item is textual
                  item.iItem = 0; // item is sorted so start at first row
                  item.iSubItem = 0; //column number one
                  item.cchTextMax = 260;
                  item.pszText = tvi.pszText;
                  int ret = ListView_InsertItem ( hList, &item );
                  item.iItem = ret; // row number where irem was inserted
                  item.iSubItem = 2; // 3d column
                  item.pszText = nodeCD;
                  ListView_SetItem ( hList, &item ); // set the 2nd column sub item text
                  if ( ret < 1 )         ret *= -1;
                  nmtvi = tvi.hItem;
                  nmtvi = TreeView_GetNextSibling ( hwndFrom, nmtvi ); // get the 
                                                                // next child's handle
                  memset ( &tvi, 0, sizeof ( tvi ) );
                  memset ( &Text, 0, sizeof ( Text ) );
                  tvi.mask = TVIF_TEXT;
                  tvi.pszText = Text;
                  tvi.cchTextMax = 255;
                  tvi.hItem = nmtvi;
                }
                while ( TreeView_GetItem ( hwndFrom, &tvi ) ); // get the child's label or stop
              }  // delete all the listview items and re build the list 
            } // the item has children, get the first one and set-up loop  
          }  // you got the item that was clicked 
        } // you clicked on a treeview node
      }break; // case  NM_CLICK

      case TVN_KEYDOWN:
      {
        NMTVKEYDOWN * ptvkd;
        ptvkd = ( LPNMTVKEYDOWN ) lParam;
        if ( ( ptvkd )->wVKey == VK_TAB ) {
          SetFocus ( hList );
        }

        if ( ( ptvkd )->wVKey == VK_F5 ) {
          #pragma region search_current_folder_to_build_file_list
          GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
          SetFocus ( hList );
          return 0;
          #pragma endregion then send vk_f5 to listview
        }
        break;

      case NM_RETURN:
      { // populates ListView when node is selected by keyboard and 
        // then Keyboard ENTER Key is pressed.
        HTREEITEM  nmtvi = { 0 };
        TCHAR Text [ 256 ] = { 0 };
        TCHAR text [ 256 ] = { 0 };
        TCHAR tStr [ 256 ] = { 0 };
        TCHAR searchStr [ 256 ] = { 0 };
        TCHAR titleText [ 256 ] = { 0 };
        GetWindowText ( hMainWnd, titleText, 255 );
        if ( wcscmp ( titleText, L "   USE CURSOR KEYS to Navigate in the TREEVIEW, 
        select a folder path, then push ENTER to save path temporarily. " ) == 0 ) {
          if ( GetWindowTextLength ( hEdit ) ) {
            GetWindowText ( hEdit, nodeCD, 255 );
            SetEnvironmentVariable ( L "STARTINDIR ", nodeCD );
          }
          else {
            GetCurrentDirectory ( 255, nodeCD );
          }
          Edit_SetCueBannerTextFocused ( hEdit, L " ", TRUE );
          HWND hwndstatus = getThisWindowHandle ( hMainWnd, IDC_STATUS );
          SendMessage ( hwndstatus, SB_SETTEXT, 0, ( LPARAM ) nodeCD );
          return TRUE;
        }
        if ( wcscmp ( titleText, L "   USE CURSOR KEYS to Navigate in the TREEVIEW, 
        select a folder path, then push ENTER to search path. " ) == 0 ) {
          if ( GetWindowTextLength ( hEdit ) ) {
            GetWindowText ( hEdit, nodeCD, 255 );
            SetEnvironmentVariable ( L "STARTINDIR ", nodeCD );
          }
          else {
            GetCurrentDirectory ( 255, nodeCD );
          }

          Edit_SetCueBannerTextFocused ( hEdit, L " ", TRUE );
          HWND hwndStatus = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_STATUS );
          GetEnvironmentVariable ( L "SEARCHSTR ", searchStr, 255 );
          StringCchPrintf ( tStr, MAX_PATH, L "Searching for %s in   ", searchStr );
          SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) tStr );
          SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) nodeCD );
          HWND hProgress = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_PROGRESS1 );
          ShowWindow ( hProgress, SW_NORMAL );
          SendMessage ( hProgress, PBM_SETMARQUEE, PBST_NORMAL, 0 );
          recursivefileSearch ( nodeCD, FALSE );
          SendMessage ( hProgress, PBM_SETMARQUEE, PBST_PAUSED - 3, 0 );
          ShowWindow ( hProgress, SW_HIDE );
          SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) nodeCD );
          int iCount = ListView_GetItemCount ( hList );
          int result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
          StringCchPrintf ( tStr, MAX_PATH, L "Number of Files %d. ", iCount );
          SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) tStr );
          StringCchPrintf ( tStr, MAX_PATH, L "%d of %d Files. ", result + 1, iCount );
          SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) tStr );
          return TRUE;
        }
        if ( wcscmp ( titleText, L "   USE CURSOR KEYS to Navigate in the TREEVIEW 
        to select a folder path, then push ENTER. 
        The path will be saved permanently " ) == 0 ) {
          if ( GetWindowTextLength ( hEdit ) ) {
            GetWindowText ( hEdit, nodeCD, 255 );
            SetEnvironmentVariable ( L "STARTINDIR ", nodeCD );
          }
          else {
            GetCurrentDirectory ( 255, nodeCD );
          }
          StringCchPrintf ( Text, 255, L " /k Setx STARTINDIR \ "%s\ " ", nodeCD );
          SetEnvironmentVariable ( L "STARTINDIR ", nodeCD );
          persist_This ( Text );
          HWND hwndstatus = getThisWindowHandle ( hMainWnd, IDC_STATUS ); 
          SendMessage ( hwndstatus, SB_SETTEXT, 0, ( LPARAM ) nodeCD );
          return TRUE;
        }
        memset ( &tvi, 0, sizeof ( tvi ) );
        tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
        tvi.pszText = Text;
        tvi.cchTextMax = 255;
        nmtvi = TreeView_GetSelection ( hTree );
        tvi.hItem = nmtvi;
        if ( TreeView_GetItem ( hTree, &tvi ) ) {
          GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
          if ( tvi.iImage == 4 ) { // not a folder
            LVITEM item;
            memset ( &item, 0, sizeof ( item ) );
            item.mask = LVIF_TEXT;
            item.iItem = 0; // we start at zero but list is sorted, 
                            // so it will find a place for it
            item.iSubItem = 0; // sub-item zero is first column
            item.cchTextMax = 260;
            item.pszText = tvi.pszText; //the file name
            int ret = 0;
            ret = ListView_InsertItem ( hList, &item ); // insert in sorted order
            item.iItem = ret; // ret is the index of the one we inserted
            item.iSubItem = 2; // sub-item two is third column
            item.pszText = nodeCD; // the  'PATH ' part of filename
            ListView_SetItem ( hList, &item ); // second column text
            int nRet = ret + 1;
            ListView_GetItemText ( hList, nRet, 0, text, 255 );
            while ( _wcsicmp ( text, tvi.pszText ) == 0 ) {
              ListView_GetItemText ( hList, nRet, 1, text, 255 );
              if ( _wcsicmp ( text, nodeCD ) == 0 ) {
                ListView_DeleteItem ( hList, ret ); // delete one of them
                ret = nRet;
              }
              nRet = nRet + 1;
              ListView_GetItemText ( hList, nRet, 0, text, 255 );
            }
            ListView_SetItemState ( hList, -1, 0, LVIS_DROPHILITED | 
                                    LVIS_SELECTED | LVIS_FOCUSED );
            ListView_SetItemState ( hList, ret, LVIS_DROPHILITED, LVIS_DROPHILITED );
            ListView_SetItemState ( hList, ret, LVIS_SELECTED, LVIS_SELECTED );
            ListView_SetItemState ( hList, ret, LVIS_FOCUSED, LVIS_FOCUSED );
            ListView_EnsureVisible ( hList, ret, TRUE );
            SetFocus ( hList );
          }
          else if ( tvi.cChildren == 1 ) {
            nmtvi = TreeView_GetChild ( hTree, nmtvi );
            memset ( &tvi, 0, sizeof ( tvi ) );
            memset ( &Text, 0, sizeof ( Text ) );
            tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE;
            tvi.pszText = Text;
            tvi.cchTextMax = 255;
            tvi.hItem = nmtvi;
            if ( TreeView_GetItem ( hTree, &tvi ) ) {
              ListView_DeleteAllItems ( hList );
              GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
              do {
                LVITEM item;
                memset ( &item, 0, sizeof ( item ) );
                item.mask = LVIF_TEXT;
                item.iItem = 0;
                item.iSubItem = 0;
                item.cchTextMax = 260;
                item.pszText = tvi.pszText;
                int ret = 0;
                ret = ListView_InsertItem ( hList, &item );
                item.iItem = ret;
                item.iSubItem = 2;
                item.pszText = nodeCD;
                ListView_SetItem ( hList, &item );
                if ( ret < 1 )         ret *= -1;
                nmtvi = tvi.hItem;
                nmtvi = TreeView_GetNextSibling ( hTree, nmtvi );
                memset ( &tvi, 0, sizeof ( tvi ) );
                memset ( &Text, 0, sizeof ( Text ) );
                tvi.mask = TVIF_TEXT;
                tvi.pszText = Text;
                tvi.cchTextMax = 255;
                tvi.hItem = nmtvi;
              }
              while ( TreeView_GetItem ( hTree, &tvi ) );
            }
          }
        } // if(TreeView_GetItem(hTree, &tvi))
      } break; // case NM_RETURN - Keyboard ENTER Key
      } // TVN_KEYDOWN
      } // switch (((LPNMHDR)lParam)->code)
    } break;// case IDC_TREE1
    } // switch (((LPNMHDR)lParam)->idFrom)
  }  break; //  case WM_NOTIFY:

  case WM_SIZE:
  {
    UINT width = GET_X_LPARAM ( lParam );
    UINT height = GET_Y_LPARAM ( lParam );
    MoveWindow ( hTree, 0, 0, width, height, TRUE );
    return 0;
  }break;
  }
  return ( INT_PTR ) FALSE;
}

SetTreeviewImagelist Function: For the Tree

These images are just for the TreeView because it is assumed that most of the files in the ListView will be of the same type and thus of a lower value in most cases. This certainly would not be true if the user selected a set of extensions with 5 or 6 members but the icon for the extension would add nothing to the search process.

C++
// FUNCTION: Creates a 32 by 32 imagelist containing 6 bitmaps of folder icons. 
// The images are; closed-folder, selected-closed-folder, opened-folder, 
// selected-opened-folder, document(not a folder) and selected-document. 
// No attempt is made to identify nature of document. 
bool inline SetTreeviewImagelist ( const HWND hTv ) {
  HIMAGELIST hImageList = ImageList_Create ( 16, 16, ILC_COLOR32, 6, 1 );
  HBITMAP hBitMap = LoadBitmap ( hInst, MAKEINTRESOURCE ( IDB_BITMAP1 ) );
  ImageList_Add ( hImageList, hBitMap, NULL );
  DeleteObject ( hBitMap );
  TreeView_SetImageList ( hTv, hImageList, 
        TVSIL_NORMAL );  // attach image lists to tree view common control
  return true;
}

getNodeFullPath: Find the Parents Recursively

This function accepts 2 parameters, a handle to the Tree Control and the handle to the current HTREEITEH. Getting the item, it checks to see if the second character is a colon, found on in the ROOT Item. If this condition is met, it sets the current directory and returns TRUE, stopping the recursion, otherwise, it calls TreeView_GetParent, getting the item 's parent node and calling getNodeFullPath with the parent. Having completed the recursion, we concatenate the items text to the current directory with each return from the recursion. In effect, we reversed the order of the nodes as they were on the stack.

The getNodeFullPath Function

C++
// FUNCTION: recursively get the current item 's parent until you find the 
// drive then return the tvi.pszText and collect it to build the full-path 
// of the current node. Call this routine when a node is selected or when 
// a button(+ or -) is clicked. This is necessary because clicking a button 
// does not automatically select a node, it only expands it.
BOOL getNodeFullPath ( HWND hTree, HTREEITEM  nmtvi ) {
  TVITEM tvi;
  TCHAR Text [ 256 ] = {};
  tvi.hItem = nmtvi;
  tvi.mask = TVIF_TEXT;
  tvi.cchTextMax = 255;
  tvi.pszText = Text;
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
  hTree = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_TREE1 );
  TCHAR nodeCD [ 250 ] = { 0 };
  if ( TreeView_GetItem ( hTree, &tvi ) ) {
    if ( tvi.pszText [ 1 ] == L ': ' ) {
      // you found the drive, the root of the folders
      StringCchPrintf ( nodeCD, 255, L "%s ", tvi.pszText ); // concat in text buffer
      SetCurrentDirectory ( nodeCD );
      SetWindowText ( hEdit, nodeCD );         // set the text in IDC_EDIT2
      return true; // stop recursing
    }
    else {
      nmtvi = TreeView_GetParent ( hTree, tvi.hItem );
      getNodeFullPath ( hTree, nmtvi ); // loop recursively 

    // when you get here you are no longer recursing,
    // you are just collecting the returned information
    // in the reverse order of the get parent calls. This
    // has the effect of a last-in - first-out stack,
    //  resulting in a  'reversal by recursion '.  
      if ( *nodeCD == 0 ) {
        GetCurrentDirectory ( 255, nodeCD );
      }
      if ( tvi.pszText ) {
        if ( nodeCD [ wcslen ( nodeCD ) - 1 ] != L '\\ ' ) {
          StringCchPrintf 
          ( nodeCD, 255, L "%s\\%s ", nodeCD, tvi.pszText ); // concat in text buffer
        }
        else {
          StringCchPrintf 
          ( nodeCD, 255, L "%s%s ", nodeCD, tvi.pszText ); // concat in text buffer
        }
        SetCurrentDirectory ( nodeCD );
        SetWindowText ( hEdit, nodeCD );
      }
    }
  }
  return true; // return current value of tvi.pszText
}

The Main Window Procedure: WndProc

When we enter the WndProc, we allocate all of the variables we need on the stack. Then we handle WM_CREATE in an if statement. As it turned out, the else block was not needed, so it could have been in the message switch. The first dialog we create is the container hTopView, the place where the controls that I thought would not have to be moved around were placed. This container window has one control and another dialog in it. The control is an Edit control, named hEdit. The Dialog is hFormView0 which contains two buttons, two Combo Boxes and a Progress Bar. The Progress Bar will fill hFormView0 completely when shown, preventing user input.

The next dialog to be created is hBottom. It will contain hFormView1, hFormview2, hFormView3 hMiddle. hFormView1 contains the TreeView, hFormView2 is the RESIZIBG Window and contains the ListView, hFormView3 contains the RichEdit Control and finally, hMiddle contains the status bar. If all of these windows were created successfully, we create RECTs for them and establish their initial sizes and move them into position and show the main window, hWnd.

Now, we get the Environment Variable HOMEDRIVE and call the InitTreeViewItems function. Next, we get the Environment Variable STARTINDIR if it exists, otherwise we get USERPROFILE to set the current directory. We get SEARCHSTR, which is the set of file extensions last used, or set searchStr to '*.cpp;*.c' and set SEARCHSTR. The Progress Bar is turned on and displayed before we call the recursivefileSearch function. On return, the Progress Bar is hidden, the status bar is updated, the Caption is set, the first file in the ListView is selected and loaded into the RichEdit Viewer Panel, focus is set to the ListView and WndProc returns zero.

The WM_SIZE message handler gets the window rectangle for hBottom and moves it to left=0, top = 90, right=width, bottom=feight. This causes hFormView(1,2,3,and hNiddle) to be sent WM_SIZE messages. This is done so that all of the windows that are re-sized by the RESIZING Border of hFormView2 can be set properly. The top=90 is the combined height of the Menu and hTopView. The Controls in hTopView are more or less stationary and therefore don't get moved as much as the hTree, hList and hRich, so they only need to be SIZE_RESTORED and SIZE_MAXIMIZED. I also used a little trickery when wParam was SIZED_RESTORED, I sent the same message again but changed wParam to SIZE_MAXIMIZED and added a SIZE_MAXSHOW message. This was done to eliminate some blocks of code that were just copies of the SIZE_MAXIMIZED block.

In the WM_COMMAND message switch, the ID_FILE_CD command handler will set the Title Text for the main window to ' USE CURSOR KEYS to Navigate in the TREEVIEW, select a folder path, then push ENTER to search path. '. Then it will blank out hEdit and set the CUE Banner and set focus to hTree. The user can cancel the command by not pushing ENTER, but if the user does push ENTER, then the selected tree node will be searched and the files found will be added to the ListView.

The ID_FILE_TEMP command handler will set the Title Text for the main window to ' USE CURSOR KEYS to Navigate in the TREEVIEW, select a folder path, then push ENTER to save path temporarily.' Then it will blank out hEdit and set the CUE Banner, set the focus to hTree. The user can cancel the command by not pushing ENTER, but if the user does push ENTER, then the selected tree node will be saved to the Environment Block and the Current Directory will be set but the value will not be written to the Registry.

The ID_FILE_CHANGE command handler will set the Title Text for the main window to 'USE CURSOR KEYS to Navigate in the TREEVIEW to select a folder path, then push ENTER. The path will be saved permanently.' Then it will blank out hEdit, set the CUE Banner and set the focus to hTree. The user can cancel the command by not pushing ENTER, but if the user does push ENTER, then the selected tree node will be saved to the Environment Block and the Current Directory will be set and the value will be written to the Registry.

The IDM_EXIT command under the File Menu destroys the main window at program termination.

The ID_EDIT_CMD command sets the Window TEXT in hEdit to '#&cmd&sol;f:on /k set prompt=&P&_&l&D&G&L&T&G && ver && echo Path Completion is turned ON. For directory use control + D. Control + Shift + F for Files. 'Then it sends a RETURN Key to hEdit. hEdit is subclassed to get the RETURN Key and process the Window Text., resulting in a CMD Prompt being started.

The ID_VIEW_RESET and ID_VIEW_FO commands are used to start the process to reset the Checkbox in the SHMessageBoxCheck message box. The command sets the Window Text in hEdit to '#@WHOAMI /USER /FO CSV /NH | clip ' for ID_VIEW_RESET and '##WHOAMI /USER /NH |clip ' for ID_VIEW_FO. The hEdit subclass proc uses the first two characters to determine whether to reset the Check Box nicely by asking 'Are You Sure? ' for '#@ ' or just 'FOrce ' it for '## '. Next we send a RETURN Key to hEedit.

The Help Menu Item displays a dropdown with the following commands:

The About.. command handled by IDM_ABOUT. It displays the usual About Dialog.

The About Extensions command handled by ID_HELP_EXTENSIONS. It displays a Dialog explaining the file extensions and how to set them.

The About Strings command handled by IDD_HELP_STRING. It displays a Dialog explaining the string to search for and how to set them.

The About Path command handled by IDD_HELP_PATH. It displays a Dialog explaining how to set the Path.

The About CheckBox command handled by IDD_HELP_CHECKBOX. It displays a Dialog explaining how to reset the message box check box.

The About CMD.EXE command handled by IDD_HELP_CMD. It displays a Dialog explaining how to USE the cmd.exe prompt.

The WM_INITMENU message handler sets the default menu item for the Edit Menu command. This enables a double click to activate the default

The WM_SYSCOMMAND message handler removes or restores the Menu when user pushes the ALT Key.

The WM_ACTIVATE message handler sets the focus to the ListView.

The Help Menu Command is About more than 'About '

Click on the Menu and select ...

The Sub Menus explain 'about ' how to do things in TwoStageSearch

The WndProc Function

C++
//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_CREATE   - process main window creation and create all dialogs. Retrieve state and 
//                perform initial file list build, load first file into RichEdit
//  WN_SIZE     - process sizing message
//  WM_COMMAND  - process the application menu
//  WM_SYSCOMMAND process SC_MENU to show or hide menu
//  WM_ACTIVATE - set initial focus to ListView
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) {
  int wmEvent;
  int mnh = 0;//MeNu Height
  TCHAR curntFname [ 256 ];
  TCHAR curntPath [ MAX_PATH ];
  TCHAR tStr [ MAX_PATH ];
  TCHAR extensionCue [ MAX_PATH ];
  TCHAR nodeCD [ MAX_PATH - 1 ] = { 0 };
  TCHAR searchStr [ MAX_PATH ] = { 0 };
  TCHAR startInDir [ MAX_PATH ] = { 0 };
  static RECT rcClip, rcOldClip;
  HWND hWndFocus = NULL, hEdit = NULL, hTree = NULL, hList = NULL, 
                         hRich = NULL, hFormView0 = NULL,
    hFormView1 = NULL, hFormView2 = NULL, hCombo1 = NULL, 
                       hCombo2 = NULL, hProgress = NULL,
    hFormView3 = NULL, hTopView = NULL, hBottomView = NULL, 
                       hwndStatus = NULL, hStatusView = NULL;


  if ( WM_CREATE == message ) {
    RECT rc = { 0, 0, 1380, 480 };
  
    hTopView = CreateDialog ( GetModuleHandle ( NULL ),
                     MAKEINTRESOURCE ( IDD_TOP ), hWnd, editBoxProc );
    if ( hTopView != NULL ) {
      hEdit = GetDlgItem ( hTopView, IDC_EDIT2 );
      ShowWindow ( hEdit, SW_SHOW );
      ShowWindow ( hTopView, SW_SHOW );
    }
    hFormView0 = CreateDialog ( GetModuleHandle ( NULL ),
                     MAKEINTRESOURCE ( IDD_FORMVIEW0 ), hWnd, comboBoxProc );
    if ( hFormView0 != NULL ) {
      hCombo1 = GetDlgItem ( hFormView0, IDC_COMBO1 );
      hCombo2 = GetDlgItem ( hFormView0, IDC_COMBO2 );
      hProgress = GetDlgItem ( hFormView0, IDC_PROGRESS1 );
      ShowWindow ( hCombo1, SW_SHOW );
      ShowWindow ( hCombo2, SW_SHOW );
      ShowWindow ( hProgress, SW_SHOW );
      ShowWindow ( hFormView0, SW_SHOW );
    }
    else return FALSE;

    hBottomView = CreateDialog ( GetModuleHandle ( NULL ),
                      MAKEINTRESOURCE ( IDD_BTTOM ), hWnd, bottomProc );
    if ( hBottomView != NULL ) {
      hStatusView = CreateDialog ( GetModuleHandle ( NULL ),
                      MAKEINTRESOURCE ( IDD_MIDDLE ), hBottomView, statusBarProc );
      hwndStatus = GetDlgItem ( hStatusView, IDC_STATUS );
      ShowWindow ( hwndStatus, SW_SHOW );
      ShowWindow ( hStatusView, SW_SHOW );
      ShowWindow ( hBottomView, SW_SHOW );
      if ( hwndStatus ) {
        SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) L "Ready " );
        SendMessage ( hwndStatus, SB_SETTEXT, 1 | 
                      SBT_POPOUT, ( LPARAM ) L "Blah blah blah " );
        SendMessage ( hwndStatus, SB_SETTEXT, 2 | 
                      SBT_POPOUT, ( LPARAM ) L "Blah blah blah " );
        SendMessage ( hwndStatus, SB_SETTEXT, 3 | 
                      SBT_POPOUT, ( LPARAM ) L "|H:32|W:10| " );
        SendMessage ( hwndStatus, WM_SIZE, 0, 0 );
      }
      hFormView3 = CreateDialog ( GetModuleHandle ( NULL ),
                       MAKEINTRESOURCE ( IDD_FORMVIEW3 ), hBottomView, richEditProc );
      if ( hFormView3 != 0 ) {
        hRich = GetDlgItem ( hFormView3, IDC_EDIT1 );
        ShowWindow ( hRich, SW_SHOW );
        ShowWindow ( hFormView3, SW_SHOW );
      }
      hFormView2 = CreateDialog ( GetModuleHandle ( NULL ),
                       MAKEINTRESOURCE ( IDD_FORMVIEW2 ), hBottomView, listViewProc );
      if ( hFormView2 != 0 ) {
        hList = GetDlgItem ( hFormView2, IDC_LIST1 );
        ShowWindow ( hList, SW_SHOW );
        ShowWindow ( hFormView2, SW_SHOW );
      }
      hFormView1 = CreateDialog ( GetModuleHandle ( NULL ),
                       MAKEINTRESOURCE ( IDD_FORMVIEW1 ), hBottomView, treeViewProc );
      if ( hFormView1 != 0 ) {
        hTree = GetDlgItem ( hFormView1, IDC_TREE1 );
        ShowWindow ( hTree, SW_SHOW );
        ShowWindow ( hFormView1, SW_SHOW );
      }
      ShowWindow ( hBottomView, SW_SHOW );
    }

    RECT wrc = { 0 }, wrccl = { 0 }, src = { 0 }, srccl = { 0 }, crc = { 0 }, crccl = { 0 },
      brc = { 0 }, brccl = { 0 },  toprc = { 0 }, 
                   toprccl = { 0 },  rrc = { 0 }, rrccl = { 0 },
      erc = { 0 }, erccl = { 0 },  lrc = { 0 }, lrccl = { 0 },  trc = { 0 }, trccl = { 0 };
    GetWindowRect ( hWnd, &wrc );
    GetClientRect ( hWnd, &wrccl );
    GetWindowRect ( hTopView, &toprc );
    GetClientRect ( hTopView, &toprccl );
    GetWindowRect ( hBottomView, &brc );
    GetClientRect ( hBottomView, &brccl );
    GetWindowRect ( hFormView0, &erc );
    GetClientRect ( hFormView0, &erccl );
    GetWindowRect ( hFormView1, &trc );
    GetClientRect ( hFormView1, &trccl );
    GetWindowRect ( hFormView2, &lrc );
    GetClientRect ( hFormView2, &lrccl );
    GetWindowRect ( hFormView3, &rrc );
    GetClientRect ( hFormView3, &rrccl );
    GetWindowRect ( hStatusView, &src );
    GetClientRect ( hStatusView, &srccl );
    OffsetRect ( &toprc, -toprc.left, -toprc.top );
    OffsetRect ( &erc, -wrc.left, -wrc.top );
    OffsetRect ( &brc, -wrc.left, -wrc.top );
    MoveWindow ( hFormView0, 0, 0, wrc.right, 30, TRUE );
    MoveWindow ( hTopView, 0, 40, wrc.right, 50, TRUE );
    MoveWindow ( hEdit, 10, 10, wrc.right, 30, TRUE );
    MoveWindow ( hBottomView, 0, 90, brc.right-brc.left, wrc.bottom, TRUE );
    MoveWindow ( hFormView1, 0, 0, trc.right - trc.left, lrc.bottom - lrc.top+4, TRUE );
    MoveWindow ( hFormView2, trc.right - trc.left, 0, 
                 lrc.right - lrc.left, lrc.bottom - lrc.top, TRUE );
    GetWindowRect ( hFormView2, &lrc );
    OffsetRect ( &lrc, -wrc.left, -wrc.top );
    MoveWindow ( hFormView3, lrc.right-8, 0, 
                 wrccl.right - lrc.right+8, lrc.bottom - lrc.top, TRUE );
    MoveWindow ( hRich, 0, 0, rrccl.right+8, rrccl.bottom , TRUE );
    MoveWindow ( hList, 0, 0, lrc.right - lrc.left - 16, lrc.bottom - lrc.top - 16, TRUE );

    MoveWindow ( hStatusView, 0, wrccl.bottom - srccl.bottom - 85, 
                 wrccl.right, srccl.bottom, TRUE );
    MoveWindow ( hwndStatus, 0, 0, wrccl.right, srccl.bottom, FALSE );
    ShowWindow ( hWnd, SW_NORMAL );
    ShowWindow ( hwndStatus, SW_NORMAL );
    DWORD sidLen = GetEnvironmentVariable ( L "HOMEDRIVE ", startInDir, 255 );
    InitTreeViewItems ( hTree, startInDir );
    sidLen = GetEnvironmentVariable ( L "STARTINDIR ", startInDir, 255 );
    if ( 0 == sidLen ) {
      GetEnvironmentVariable ( L "USERPROFILE ", startInDir, 256 );
    }
    SetCurrentDirectory ( startInDir );
    GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
    sidLen = GetEnvironmentVariable ( L "SEARCHSTR ", searchStr, 255 );
    if ( 0 == sidLen ) {
      wsprintf ( searchStr, L "%s ", L "*.cpp;*.c " );
      SetEnvironmentVariable ( L "SEARCHSTR ", searchStr );
    }
    StringCchPrintf ( tStr, MAX_PATH, L "Searching for %s in   ", searchStr );
    SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) tStr );
    SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) startInDir );
    SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, 
                                              ( LPARAM ) L "Number of Files......... " );
    SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, 
                                              ( LPARAM ) L "Line: 0 Column: 0......... " );
      MoveWindow ( hStatusView, 0, wrccl.bottom - srccl.bottom - 85, 
                                   wrccl.right, srccl.bottom, TRUE );
    MoveWindow ( hwndStatus, 0, 0, wrccl.right, srccl.bottom, FALSE );
    SendMessage ( hwndStatus, WM_SIZE, 0, 0 );
    ShowWindow ( hProgress, SW_NORMAL );
    SendMessage ( hProgress, PBM_SETMARQUEE, PBST_NORMAL, 0 );
    recursivefileSearch ( nodeCD, FALSE );
    SetFocus ( hList );
    SendMessage ( hProgress, PBM_SETMARQUEE, PBST_PAUSED - 3, 0 );
    ShowWindow ( hProgress, SW_HIDE );
    int iCount = ListView_GetItemCount ( hList );
    int result = ListView_GetNextItem ( hList, -1, LVNI_SELECTED );
    StringCchPrintf ( tStr, MAX_PATH, L "Number of Files %d. ", iCount );
    SendMessage ( hwndStatus, SB_SETTEXT, 0, ( LPARAM ) startInDir );
    SendMessage ( hwndStatus, SB_SETTEXT, 1 | SBT_POPOUT, ( LPARAM ) tStr );
    StringCchPrintf ( tStr, MAX_PATH, L "%d of %d Files. ", result+1 , iCount );
    SendMessage ( hwndStatus, SB_SETTEXT, 2 | SBT_POPOUT, ( LPARAM ) tStr );
    SendMessage ( hwndStatus, SB_SETTEXT, 3 | SBT_POPOUT, 
                                              ( LPARAM ) L "Line: 0    Column: 0 " );
    SendMessage ( hwndStatus, WM_SIZE, 0, 0 );
    SetWindowText ( hWnd, L "Two Stage Search - Build File Set to SEARCH, 
    then SEARCH File Set for a strings! File List Initial 
    Build uses Path and Extensions used in previous invocation. " );
    SetWindowText ( hEdit, L "To SEARCH list, select a string in View panel. 
    Hold control key down and push  'F 'to begin search. 
    PF3 will find next occurrence. When last occurrence is found, 
    next file containing string is searched for. " );
    ListView_GetItemText ( hList, 0, 0, curntFname, MAX_PATH - 1 );
    ListView_GetItemText ( hList, 0, 2, curntPath, MAX_PATH - 1 );
    StringCchPrintf ( tStr, MAX_PATH, L "%s\\%s ", curntPath, curntFname );
    FillRichEditFromFile ( hRich, ( LPCTSTR ) &tStr );
    SetFocus ( hList );
    return 0;
  }
    switch (message)
    {

  case WM_SIZE:
  {
  UINT width = GET_X_LPARAM ( lParam );
  UINT height = GET_Y_LPARAM ( lParam );
    RECT erc = { 0 }, erccl = { 0 }, rrc = { 0 }, rrccl = { 0 }, 
                        lrc = { 0 }, lrccl = { 0 }, trc = { 0 }, 
      trccl = { 0 }, wrc = { 0 }, wrccl = { 0 }, brc = { 0 }, 
                        brccl = { 0 },  src = { 0 }, srccl = { 0 };
    HWND hMainWnd = FindWindow ( L"TWOSTAGESEARCH", 0 );
    hTopView = FindWindowEx ( hMainWnd, 0, L"#32770", 0 );
    hEdit = getThisWindowHandle ( hTopView, IDC_EDIT2 );
    hFormView0 = FindWindowEx ( hMainWnd, hTopView, L"#32770", 0 );
    hCombo1 = getThisWindowHandle ( hFormView0, IDC_COMBO1 );
    hCombo2 = getThisWindowHandle ( hFormView0, IDC_COMBO2 );
    hBottomView = FindWindowEx ( hMainWnd, hFormView0, L"#32770", 0 );
    hTree = getThisWindowHandle ( hBottomView, IDC_TREE1 );
    hStatusView = FindWindowEx ( hBottomView, 0, L"#32770", 0 );
    hwndStatus = FindWindowEx ( hStatusView, 0, L"MSCTLS_STATUSBAR32", 0 );
    hFormView3 = FindWindowEx ( hBottomView, hStatusView, L"#32770", 0 );
    hFormView2 = FindWindowEx ( hBottomView, hFormView3, L"#32770", 0 );
    hFormView1 = FindWindowEx ( hBottomView, hFormView2, L"#32770", 0 );
    hList = FindWindowEx ( hFormView2, 0, L"SYSLISTVIEW32", 0 );
    hTree = FindWindowEx ( hFormView1, 0, L"SYSTREEVIEW32", 0 );
    hRich = FindWindowEx ( hFormView3, 0, L"RICHEDIT50W", 0 );
    if ( 0 == hTree ) {  return 0;}
    if ( 0 == hList ) {  return 0;}
    if ( 0 == hEdit ) {  return 0;}
    if ( 0 == hRich ) {  return 0;}
    if ( 0 == hFormView0 ) {return 0;}
    if ( 0 == hFormView1 ) {return 0;}
    if ( 0 == hFormView2 ) {return 0;}
    if ( 0 == hFormView3 ) {return 0;}
    MoveWindow ( hBottomView, 0, 90, width, height, TRUE );
    GetClientRect ( hBottomView, &brccl );
    GetWindowRect ( hBottomView, &brc );
    GetClientRect ( hFormView3, &rrccl );
    GetWindowRect ( hFormView3, &rrc );
    GetClientRect ( hWnd, &wrccl );
    GetClientRect ( hWnd, &erccl );
    GetWindowRect ( hWnd, &erc );
    GetWindowRect ( hFormView0, &erc );
    GetClientRect ( hFormView1, &trccl );
    GetWindowRect ( hFormView1, &trc );
    GetWindowRect ( hFormView2, &lrc );
    GetWindowRect ( hWnd, &wrc );
    GetClientRect ( hFormView2, &lrccl );
    GetWindowRect ( hFormView3, &rrc );
    GetClientRect ( hRich, &rrccl );
    GetWindowRect ( hStatusView, &src );
    GetClientRect ( hStatusView, &srccl );
    OffsetRect ( &erc, -wrc.left, -wrc.top );
    OffsetRect ( &trc, -wrc.left, -wrc.top );
    OffsetRect ( &lrc, -wrc.left, -wrc.top );
    OffsetRect ( &rrc, -wrc.left, -wrc.top );
    OffsetRect ( &src, -wrc.left, -wrc.top );
    OffsetRect ( &brc, -wrc.left, -wrc.top );
    
    if ( wParam == SIZE_RESTORED ) {
      MoveWindow ( hTopView, 0, 40, wrc.right, 50, TRUE );
      MoveWindow ( hFormView0, 0, 0, wrc.right, 30, TRUE );
      MoveWindow ( hEdit, 10, 0, wrc.right, 30, TRUE );
      SendMessage ( hWnd, message, SIZE_MAXIMIZED, lParam );
    }
    if ( wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXSHOW ) {
      MoveWindow ( hTopView, 0, 40, wrc.right, 50, TRUE );
      MoveWindow ( hFormView0, 0, 0, wrc.right, 30, TRUE );
      MoveWindow ( hEdit, 10, 0, wrc.right, 30, TRUE );
      MoveWindow ( hList, 0, 0, lrc.right - lrc.left - 16, lrc.bottom- lrc.top-16, TRUE );
      MoveWindow ( hFormView1, 0, 0, trc.right - trc.left, height-brc.top+12, TRUE );
      MoveWindow ( hFormView2, trc.right - trc.left - 8, 0, 
                     lrc.right - lrc.left, height - brc.top+16, TRUE );
      MoveWindow ( hTree, trccl.left, trccl.top, 
                     lrc.left - trc.left, height-brc.top+12, TRUE );
      MoveWindow ( hFormView3, lrc.right-8, 0, 
                     width - lrc.right+8, height - brc.top+16, TRUE );
      MoveWindow ( hRich,       0, 0, width - lrc.right+8, height-brc.top+16, TRUE );
      MoveWindow ( hStatusView, 0, lrc.bottom - lrc.top+8, 
                    brc.right-brc.left, srccl.bottom, TRUE );
      MoveWindow ( hwndStatus, 0, 0, wrccl.right, srccl.bottom, TRUE );
      if ( wParam == SIZE_MAXIMIZED ) {
        SendMessage ( hWnd, message, SIZE_MAXSHOW, lParam );
      }
    }
    return 0;
  } // case WM_SIZE:
  break;


  case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
      wmEvent = HIWORD ( wParam );
      // For menu items lparam is zero
      // Parse the menu selections:
            switch (wmId)
            {
      case ID_FILE_CD:
      {
        hEdit = getThisWindowHandle ( hWnd, IDC_EDIT2 );
        hTree = getThisWindowHandle ( hWnd, IDC_TREE1 );
        if ( hEdit && GetWindowTextLength ( hEdit ) < 255 ) {
          SetWindowText ( hWnd, L "   USE CURSOR KEYS to Navigate in the TREEVIEW, 
          select a folder path, then push ENTER to search path. " );
          SetWindowText ( hEdit, L " " );
          StringCchCopy ( extensionCue, 259,
                  L "Navigate in the TreeView using the CURSOR Keys,  " );
          StringCchCat ( extensionCue, 259,
                   L "Left will close an open folder but Right will open a folder.  " );
          StringCchCat ( extensionCue, 259,
                   L " Push  'ENTER ' Key to begin build. " );
          Edit_SetCueBannerTextFocused ( hEdit, extensionCue, TRUE );
          SetFocus ( hTree );
          return 0;
        }
      }
      break;

      case ID_FILE_TEMP:
      {
        hEdit = getThisWindowHandle ( hWnd, IDC_EDIT2 );
        hTree = getThisWindowHandle ( hWnd, IDC_TREE1 );
        if ( hEdit && GetWindowTextLength ( hEdit ) < 255 ) {
          SetWindowText ( hWnd, L "   USE CURSOR KEYS to Navigate in the TREEVIEW, 
          select a folder path, then push ENTER to save path temporarily. " );
          SetWindowText ( hEdit, L " " );
          StringCchCopy ( extensionCue, 259,
                  L "Navigate in the TreeView using the CURSOR Keys,  " );
          StringCchCat ( extensionCue, 259,
                   L "Left will close an open folder but Right will open a folder.  " );
          StringCchCat ( extensionCue, 259,
                   L " Push  'ENTER ' Key to select folder. " );
          Edit_SetCueBannerTextFocused ( hEdit, extensionCue, TRUE );
          SetFocus ( hTree );
          return 0;
        }
      }
      break;

      case ID_FILE_CHANGE:
      {
        hEdit = getThisWindowHandle ( hWnd, IDC_EDIT2 );
        hTree = getThisWindowHandle ( hWnd, IDC_TREE1 );
        if ( hEdit && GetWindowTextLength ( hEdit ) < 255 ) {
          SetWindowText ( hWnd, L "   USE CURSOR KEYS to Navigate in the TREEVIEW 
          to select a folder path, then push ENTER. The path will be saved permanently " );
          SetWindowText ( hEdit, L " " );
          StringCchCopy ( extensionCue, 259,
                  L "Navigate in the TreeView using the CURSOR Keys,  " );
          StringCchCat ( extensionCue, 259,
                   L "Left will close an open folder but Right will open a folder.  " );
          StringCchCat ( extensionCue, 259,
                   L " Push  'ENTER ' Key to select folder. " );
          Edit_SetCueBannerTextFocused ( hEdit, extensionCue, TRUE );
          SetFocus ( hTree );
          return 0;
        }
      }
      break;

      case ID_EDIT_CMD:
      {
        hEdit = getThisWindowHandle ( hWnd, IDC_EDIT2 );
        SetWindowText ( hEdit, L "#&cmd /f:on /k set prompt=&P&_&l&D&G&L&T&G && 
        ver && echo Path Completion is turned ON. For diewctory use control + 
        D. Control + Shift + F for Files. " );
        sendMeMyKey ( hEdit, VK_RETURN );
        return 0;
      }
      break;

      case ID_VIEW_RESET:
      case ID_VIEW_FO:
      {
        hEdit = getThisWindowHandle ( hWnd, IDC_EDIT2 );
        if ( wmId == ID_VIEW_RESET ) {
          SetWindowText ( hEdit, L "#@WHOAMI /USER /FO CSV /NH |clip " );
        }
        else  {
          SetWindowText ( hEdit, L "##WHOAMI /USER /NH |clip " );
        }
        // This command  "wmic USERACCOUNT get sid|findstr  "1001 "|clip "
        // or this one   "wmic USERACCOUNT get sid|find  "1001 "|clip " " will
        // produce  a string ending with  2 spaces and 2 crlf line endings
        // This could be used by setting  L '\0 ' six bytes before end of line
        // as is done with  '#@whoami ' to cut the suffix from the string.
        sendMeMyKey ( hEdit, VK_RETURN );
        return 0;
      }
      break;

      case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;

      case ID_HELP_EXTENSIONS:
        DialogBox ( hInst, MAKEINTRESOURCE ( IDD_HELP_EXT ), hWnd, AboutExt );
        break;

      case IDD_HELP_STRING:
        DialogBox ( hInst, MAKEINTRESOURCE ( IDD_HELP_STRING ), hWnd, AboutString );
        break;

      case IDD_HELP_PATH:
        DialogBox ( hInst, MAKEINTRESOURCE ( IDD_HELP_PATH ), hWnd, AboutPath );
        break;

      case IDD_HELP_CHECKBOX:
        DialogBox ( hInst, MAKEINTRESOURCE ( IDD_HELP_CHECKBOX ), hWnd, AboutCheckBox );
        break;

      case IDD_HELP_CMD:
        DialogBox ( hInst, MAKEINTRESOURCE ( IDD_HELP_CMD ), hWnd, AboutCMD );
        break;

      case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;

  case WM_INITMENU:
  {
    HMENU hMenu = GetMenu ( hWnd ); // == the application menu
    HMENU hsubmenu = GetSubMenu ( hMenu, 1 ); // == the Edit item of the menu
    BOOL bsmdi = SetMenuDefaultItem ( hsubmenu, ID_EDIT_CMD, FALSE );
    DWORD dwerr = GetLastError ( );
    return 0;
  }
  break;


  case WM_SYSCOMMAND:
  {
    switch ( LOWORD ( wParam ) & 0xfff0 ) {
    case SC_KEYMENU:
      if ( ( !GetMenu ( hWnd ) ) ) {
        HMENU hMenu = LoadMenu ( hInst, MAKEINTRESOURCE ( IDC_TWOSTAGESEARCH ) );
        SetMenu ( hWnd, hMenu );
        mnh = GetSystemMetrics ( SM_CYMENU );//MeNu Height
        UpdateWindow ( hWnd );
        return 0;
      }
      else {
        SetMenu ( hWnd, NULL );
        mnh = 0;
        UpdateWindow ( hWnd );
        return 0;
      }
    default:
      return DefWindowProc ( hWnd, message, wParam, lParam );
    }
  }
  break;

  case WM_ACTIVATE:
  {
    if ( LOWORD ( wParam ) & WA_ACTIVE ) {
      hWndFocus = GetFocus ( );
      hList = getThisWindowHandle ( hWnd, IDC_LIST1 );
      if ( hWndFocus ) {
        SetFocus ( hWndFocus );
        return 0;
      }
      else {
        hWndFocus = hList;
        SetFocus ( hList );
        if ( hList && ListView_GetItemCount ( hList ) >= 1 ) {
          if ( ListView_GetNextItem ( hList, -1, LVNI_SELECTED ) == -1 ) {
            // select this one
            ListView_SetItemState ( hList, 0, LVIS_SELECTED, LVIS_SELECTED );
          }
        }
        return 0;
      }
    }
    else
      return -1;
  }break;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(hWnd, &ps);
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
  return DefWindowProc ( hWnd, message, wParam, lParam );
}

InitTreeViewItems: Give them a Path to Follow

This function receives 2 parameters, the handle to the Tree Control and the HOMEDRIVE. It adds the ROOT Item to the Tree Control, then gets the logical drive string and calls the AddItemToTree function adding each of the drives to the Tree and calling the getDirectories function for each drive to populate the first level, producing the populate on demand behavior of the TreeView and expanding the HOMEDRIVE. This is the one that should contain the start in directory, expanding it results in a TVN_ITEMEXPANDING message bring sent to the TreeView Control, followed by a TVN_ITEMEXPANDED message. When control returns, the HOMEDRIVE has been populated and expanded to the start in directory. Next, it selects the highlighted tree node, which should be the start in directory. The two additional functions called by this routine are also called by the TreeView repeatedly.

The InitTreeViewItems Function

C++
// FUNCTION: Populates treeview with logical drives and one level of sub-directories by calling 
// AddItemToTree and getDirectories for each drive. Begins process to find startindir
BOOL InitTreeViewItems ( HWND hwndTV, TCHAR * startPoint ) {
  // Define the ROOT of each drive 
  HTREEITEM nodeParent;
  HTREEITEM hti; // the root folder item to insert.
  TV_ITEM tvi = { 0 };
  // Defibe the temporary drive string 
  TCHAR szDTemp [ ] = TEXT (  " :\\ " ); // first position will contain drive letter.
  // Define string to hold Drive List.
  TCHAR szTemp [ 512 ];
  // add a root item to the tree 
  hti = ( HTREEITEM ) TVI_ROOT; //initialize root item
  if ( GetLogicalDriveStrings ( 512 - 1, szTemp ) ) { // szTemp contains list of drives 
    TCHAR* p = szTemp;   // point p at  'A ' in  'A:\\\0C:\\\0...\0\0 '
    TCHAR* d = szDTemp;  // point d at blank space in  ' :\\\0 '
    do {
      // loop through string of drives
      *d = *p; // copy 1 tchar from p to d 
      nodeParent = AddItemToTree 
      ( hwndTV, hti, szDTemp, 0, 1 ); // add a root item to the tree at level 2
      getDirectories ( nodeParent, szDTemp ); //  add it 's subdirectories at level 2
      if ( hti == NULL )              // you couldn 't add the item
        return FALSE;                 // go back and tell them it failed
      if ( NULL == nodeParent ) {
        return FALSE;                 // go back and tell them it failed
      }
      else if ( *d == *startPoint ) {
        TreeView_Expand ( hwndTV, nodeParent, TVE_EXPAND );
      }
      while ( *p++ ); // loop until p points at a  '\0 ', incrementing p afterwards. 
    }
    while ( *p );     // end of string when p points at second  '\0 ' of pair.
  }
  else
    return FALSE;     // go back and tell them you couldn 't get drive string.

  nodeParent = TreeView_GetSelection ( hwndTV );
  TreeView_Select ( hwndTV, nodeParent, TVGN_CARET );
  return TRUE;        // go back and tell them it 's okay.
}

AddItemToTree : Populate the Branches

There isn't too much to say about this routine, after all, it is just initializing the parameters to the TreeView_InsertItem macro. But look closely at what it is doing. One of the members of the tvins structure used by TreeView_InsertItem is hInsertAfter. This is being set to hPrev. This means hPrev must retain its state between calls, so we make it a static variable. If it weren't static, hPrev would always be TVI_FIRST. This would cause the Tree to be sorted Descending with the last item first and the first item last.

The AddItemToTree Function

C++
//
// FUNCTION: Inserts an item into the tree as a child of hDir, after the 
// previously inserted item if it is a sibling. If not a sibling, previously 
// inserted item is ignored. 
HTREEITEM __inline AddItemToTree 
( HWND hwndTV, HTREEITEM hDir, LPTSTR lpszItem, int tviiImage, int tviiSelectedImage ) {
  TVITEM tvi;
  TVINSERTSTRUCT tvins;
  static   HTREEITEM hPrev = ( HTREEITEM ) TVI_FIRST;
  tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  tvi.pszText = lpszItem; // Set the text of the item. 
  tvi.cchTextMax = 0; // set this to size of buffer when getting test label. Here it is ignored
  tvi.iImage = tviiImage;
  tvi.iSelectedImage = tviiSelectedImage;
  tvins.item = tvi;
  tvins.hInsertAfter = hPrev;
  tvins.hParent = hDir; // Set the parent item
  hPrev = TreeView_InsertItem ( hwndTV, &tvins ); // Add the item to the tree-view control. 
  return hPrev;
}

getDirectories: and hang 'm in the Tree

This function accepts 2 parameters, an HTREEITEM and an LPTSTR. It uses the FindFirstFileExW - FindNextFile sequence loop to get all of the child items of the HTREEITEM, hDir. It calls AddItemToTree for each item, setting the parameters to show the appropriate images, indicating a file or folder.

The getDirectories Function

C++
// FUNCTION: FindFirstFile in specified directory then repeatedly 
// FindNextFile until there aint no mo(aren 't any left to find).  
// Sets image index to show folder or not a folder, adds both to tree. 
void getDirectories ( HTREEITEM hDir, LPTSTR lpszItem ) {
  HANDLE hFind;
  WIN32_FIND_DATA win32fd;
  TCHAR szSearchPath [ _MAX_PATH ];
  LPTSTR szPath = lpszItem;
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hTree = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_TREE1 );

  if ( szPath [ wcslen ( szPath ) - 1 ] != L '\\ ' ) {
    wsprintf ( szSearchPath, L "%s\\* ", szPath ); // concat in text buffer
  }
  else {
    wsprintf ( szSearchPath, L "%s* ", szPath ); // concat in text buffer
  }

  if ( ( hFind = FindFirstFile ( szSearchPath, &win32fd ) ) == INVALID_HANDLE_VALUE ) return;
  do {
    if ( win32fd.cFileName [ 0 ] != L '. ' ) {
      if ( ( win32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 ) {
        AddItemToTree ( hTree, hDir, win32fd.cFileName, 0, 1 );
      }
      else {
        AddItemToTree ( hTree, hDir, win32fd.cFileName, 4, 5 );
      }
    }
  }
  while ( FindNextFile ( hFind, &win32fd ) != 0 );
  FindClose ( hFind );
}

The editBoxProc and its Alter-ego: The editBoxSubClassProc

The editBoxProc is a very simple function. THE WM_INITDIALOG message handler creates the control and sets the Window Subclass for hEdit to editBoxSubClassProc. The third parameter, IDC_EDIT2 is the control's id but here it is the uIdSubclass parameter and it could be any UINT_PTR as long as it uniquely identifies the subclass procedure to the system. The fourth parameter is the dwRefData and is passed to the procedure with each invocation. WM_INITDIALOG also establishes the position of hFormView0(hDlg) and moves hEdit into it. The WM_COMMAND message processes only the WM_SETFOCUS message to set the focus on the ListView. WM_SIZE resizes the control when necessary.

The editBoxProc Function

C++
// Subclass the proc and handle vk_f3, vk_f6 and vk_f6. handle vk_return to 
// invoke system commands.
INT_PTR CALLBACK editBoxProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
  UNREFERENCED_PARAMETER ( lParam );
  int wmId, wmEvent;
  static HWND hwndEdit2;
  HWND hEdit = NULL, hMainWnd = NULL,  hList = NULL;
  
  if ( WM_INITDIALOG != message ) {

    hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
    if ( 0 == hMainWnd ) {  return 0;}
    hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
    if ( 0 == hEdit ) {  return 0;}
  }
  
  switch ( message ) {

  case WM_INITDIALOG:
  {
    hEdit = FindWindowEx ( hDlg, 0, L "Edit ", 0 );
    if ( 0 == hEdit ) {

      RECT rc = { 0 }; // 20, 1380, 20

      GetClientRect ( hDlg, &rc );
      hEdit = CreateWindowExW ( WS_EX_CLIENTEDGE, // extended styles
                    L "EDIT ",          //control  'class ' name
                    L " ",              //control caption
                    //control style
                    WS_CHILD | WS_VISIBLE | 
                    ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_NOHIDESEL, // | ES_WANTRETURN,
                    10,                           //position: left
                    42,                           //position: top
                    rc.right,                     //width
                    25,                           //height
                    hDlg,                         //parent window handle
                    //control 's ID
                    ( HMENU ) ( IDC_EDIT2 ),
                    hInst,                        //application instance
                    0 );                          //user defined info
      //BOOL bTrue = 
      SetWindowSubclass ( hEdit, editBoxSubClassProc, ( UINT_PTR ) IDC_EDIT2, 0 );
      RECT eRc = { 0 };
      GetWindowRect ( hDlg, &eRc );
      MoveWindow ( hDlg, 0, 10, eRc.right, 30, TRUE );
      MoveWindow ( hEdit, 10, 0, eRc.right, 23, TRUE );
      return FALSE;
    }
  }

  case WM_COMMAND:
    wmId = LOWORD ( wParam );
    wmEvent = HIWORD ( wParam );

    switch ( wmId ) {
    case IDC_EDIT2:
      if ( HIWORD ( wParam ) == WM_SETFOCUS ) {
        hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
        if ( 0 == hList ) {
          return 0;
        }
        if ( ListView_GetItemCount ( hList ) >= 1 )
          if ( ListView_GetNextItem ( hList, -1, LVNI_SELECTED ) == -1 ) {
            SetFocus ( hList );
            // select first one
            ListView_SetItemState 
            ( hList, -1, 0, LVIS_DROPHILITED | LVIS_SELECTED | LVIS_FOCUSED );
            ListView_SetItemState ( hList, 0, LVIS_SELECTED, LVIS_SELECTED );
            return 0;
          }
      }
      break;
    default:
      break;
    }
    break;

  case WM_SIZE:
  {
    UINT width = GET_X_LPARAM ( lParam );
    UINT height = GET_Y_LPARAM ( lParam );
    if ( hEdit ) {
      MoveWindow ( hEdit, 0, 0, width, height, TRUE );
    }

    return 0;
  }break;
  }
  return ( INT_PTR ) FALSE;
}

The editBoxSubClassProc, on the other hand, is a bit more complicated. In the uMsg switch, the WM_GETDLGCODE handler listens for wParam equal to VK_F3, Vk_F5, VK_F6 and VK_RETURN. For all of these, it returns DLGC_WANTMESSAGE, preventing the control, hEdit, from performing the default processing for these keys. Instead, we will process them. For the function keys, we send VK_F3 and VK_F6 to Richedit, VK_F5 is sent to ListView.

For VK_RETURN, we get the window text from hEdit. Comparing the first two characters with '#!', when they are equal, they are stripped off and the _tsystem function is called with the rest of the text. What the user sees depends on the command they entered. The command 'time' they would see the console window with the current time and a prompt to enter the new time, but if the command was 'time /t', it would execute so quickly they would see nothing but the command's return code in hEdit. In such situations, the user could add && pause to the end of the command to keep the console open.

Comparing the first two characters with '#@', when they are equal, they are stripped off and the _tsystem function is called with the rest of the text. The text should have been put there by the Reset_CheckBox Menu selection. The next step is to wait for a short time for the command to complete, then paste the results into hEdit and get the window text again. This is the output of the 'WMIC /USER /FO CSV /NH |clip' command. It has the username and SID separated by a comma. We split the string at the comma. The SID is enclosed in double quotes, so to get rid of the first, we add one to the pointer. To get rid of the last, we overlay it with a character zero. We use the SID to construct the Registry Key to the CheckBox Flag and put it in the Environment Variable. Then we construct the Registry Query to find the reset flag entry and delete it. The Reg Delete asks if you are sure. The query and delete were ran by '#!' which writes the return code to the hEdit window. What the user sees is the console window with the confirmation prompt and command's return code in hEdit.

Forcing the Reset of the SHMessageBoxCheck Checkbox

Uncheck the check box in the SHMessageBoxCheck message box

Uncheck the check box in the SHMessageBoxCheck message box

Comparing the first two characters with '##', when they are equal, they are stripped off and the _tsystem function is called with the rest of the text. The text should have been put there by the Force_Reset_CheckBox selection. The next step is to wait for a short time for the command to complete, then paste the results into hEdit and get the window text again. This is the output of the 'WMIC /USER /NH |clip' command. It has the username and SID separated by a space. We split the string at the space. We use the SID to construct the Registry Key to the CheckBox Flag and put it in the Environment Variable. Then we construct the Registry Query to find the reset flag entry and delete it. The Reg Delete uses the '/;F' switch, which forces the delete and does not ask if you are sure. The query and delete were run by _tsystem to get the return code and inform the user of success or failure using the SHMessageBoxCheck message box.

The ID_EDIT_CMD Menu selection uses the prefix '#&' in the window text of hEdit to start a command console. Instead of _tsystem, it uses the ShellExecute function. The cmd.exe is started with the /f switch set on and executes the 'ver' built-in function to display the version of windows, just like a regular console. It sets the prompt and prints the message 'Path Completion is on...'. The reason this Menu Entry was included is if the user tried to start a console using '#!' Two Stage Search would become unresponsive until the console was exited. This console shows the Date and Time in the prompt. The path completion is very useful once you learn how to use it.

The editBoxSubClassProc Function

C++
// The EditBox was subclassed to intercept and relay vk_f3, vk_f5 and vk_f6 when the
// EditBox had keyboard focus. It also receives vk_return to invoke system commands.
LRESULT CALLBACK editBoxSubClassProc 
( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) {
  UNREFERENCED_PARAMETER ( uIdSubclass );
  UNREFERENCED_PARAMETER ( dwRefData );
  HWND hMainWnd = FindWindow ( L "TwoStageSearch ", 0 );
  HWND hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1 );
  HWND hEdit = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT2 );
  HWND hRich = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_EDIT1 );
  TCHAR searchStr [ MAX_PATH ] = { 0 };
  TCHAR nodeCD [ MAX_PATH - 1 ] = { 0 };
  TCHAR fsiaf [ 256 ] = { 0 };  // Find this String In A File

  switch ( uMsg ) {
  case WM_GETDLGCODE:

    if ( lParam ) {
      LPMSG lpmsg = ( LPMSG ) lParam;
      if ( lpmsg->message == WM_KEYDOWN )
        switch ( lpmsg->wParam ) {
        case VK_F3:
        case VK_F5:
        case VK_F6:
        case VK_RETURN:
          return DLGC_WANTMESSAGE;
          break;
        default:
          return DefSubclassProc ( hWnd, uMsg, wParam, lParam );
        }
      break;
    }
    break;

  case WM_KEYDOWN:
    switch ( wParam ) {
    case  VK_F3:
    {
      return sendMeMyKey ( hRich, VK_F3 );
    }
    break;

    case  VK_F5:
    {
      return sendMeMyKey (hList, VK_F5 );
    }
    break;

    case  VK_F6:
    {
      return sendMeMyKey ( hRich, VK_F6 );
    }
    break;

    case  VK_RETURN:
    {
      TCHAR titleText [ 256 ] = { 0 };
      TCHAR tStr [ 256 ] = { 0 };
      int retCode = 0;
      GetWindowText ( hEdit, titleText, 255 );
      if ( wcsncmp ( titleText, L "#! ", 2 ) == 0 ) {
        TCHAR * cmdLine = titleText; cmdLine += 2;
        TCHAR   rgky [ 256 ];
        retCode = _tsystem ( cmdLine );
        StringCchPrintf ( rgky, 255, L "Return Code was %d ", retCode );
        SetWindowText ( hEdit, rgky );
        return 0;
      }
      if ( wcsncmp ( titleText, L "#@ ", 2 ) == 0 ) {
        TCHAR * cmdLine = titleText; cmdLine += 2;
        TCHAR   rgky [ 256 ], *prgky;
        _tsystem ( cmdLine );
        Sleep ( 10 );
        SetWindowText ( hEdit, L " " );
        SendMessage ( hEdit, WM_PASTE, 0, 0 );
        GetWindowText ( hEdit, rgky, 255 );
        TCHAR * token = wcstok_s ( rgky, L ", ", &prgky );
        token = wcstok_s ( nullptr, L " ", &prgky );

        ++token; token [ wcslen ( token ) - 1 ] = L '\0 ';

        StringCchPrintf ( rgky, 255, L 
        "hku\\%s\\Software\\Microsoft\\Windows\\
                  CurrentVersion\\Explorer\\DontShowMeThisDialogAgain ", 
        token );
        SetEnvironmentVariable ( L "rgky ", rgky );
        StringCchCopy ( titleText, 255, L "#!reg query %rgky% /f 
        {51842606-D64C-4EDE-AF3F-4EE7AD3755A3} /e &&reg delete %rgky%  " );
        StringCchCat ( titleText, 255, L " 
        /v {51842606-D64C-4EDE-AF3F-4EE7AD3755A3}&&pause " );
        GetEnvironmentVariable ( L "rgky ", fsiaf, 255 );
        SetWindowText ( hEdit, titleText );
        sendMeMyKey ( hEdit, VK_RETURN );
        return 0;
      }
      if ( wcsncmp ( titleText, L "## ", 2 ) == 0 ) {
        TCHAR * cmdLine = titleText; cmdLine += 2;
        TCHAR   rgky [ 256 ], *prgky;
        _tsystem ( cmdLine );
        Sleep ( 10 );
        SetWindowText ( hEdit, L " " );
        SendMessage ( hEdit, WM_PASTE, 0, 0 );
        GetWindowText ( hEdit, rgky, 255 );
        TCHAR * token = wcstok_s ( rgky, L "  ", &prgky );
        token = wcstok_s ( nullptr, L " ", &prgky );
        StringCchPrintf ( rgky, 255, L "hku\\%s\\Software\\Microsoft\\
        Windows\\CurrentVersion\\Explorer\\DontShowMeThisDialogAgain ", token );
        SetEnvironmentVariable ( L "rgky ", rgky );
        StringCchCopy ( titleText, 255, L "reg query %rgky% /f 
        {51842606-D64C-4EDE-AF3F-4EE7AD3755A3} /e &&reg delete %rgky%  " );
        StringCchCat ( titleText, 255, L " /v {51842606-D64C-4EDE-AF3F-4EE7AD3755A3} /f " );
        retCode = _tsystem ( titleText );
        if ( retCode == 0 ) {
          SetWindowText ( hEdit, L "MessageBox CheckBox Successfully RESET " );
          SHMessageBoxCheck ( 0, L "MessageBox CheckBox 
          Successfully RESET ", L "MessageBox CheckBox Successfully RESET ",
                    MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, IDOK, 
                    L "{51842606-D64C-4EDE-AF3F-4EE7AD3755A3} " );
        }
        else {
          SetWindowText ( hEdit, L "MessageBox CheckBox FAILED To RESET " );
          SHMessageBoxCheck ( 0, L "MessageBox CheckBox 
          FAILED To RESET (It 's not set!). ", 
          L "MessageBox CheckBox FAILED To RESET ",
                    MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, 
                    IDOK, L "{51842606-D64C-4EDE-AF3F-4EE7AD3755A3} " );
        }
        return 0;
      }
      if ( wcsncmp ( titleText, L "#& ", 2 ) == 0 ) {
        TCHAR * cmdLine = titleText; cmdLine += 2;
        GetCurrentDirectory ( 255, nodeCD );
        ShellExecute ( NULL, L " ", 
        L "cmd.exe ", cmdLine, nodeCD, SW_SHOW );
        SetWindowText ( hEdit, L '\0 ' );
        return 0;
      }

      return TRUE;
    }
    break;
    }
  default:
    return DefSubclassProc ( hWnd, uMsg, wParam, lParam );
  }
  return 0;
}

Retaining State: Now WHERE Was I?

The Relationship between SET and SETX

The first time Two Stage Search is used, there is no pre-existing place in the file system to search or file extension to seek out. The ListView could be left blank and the user could choose the root path and set of file extensions to build the File List with. But arbitrary choices have been made to act as an example of what the program does. If the user makes their own choices, the values they selected should be honored the next time they want to use the Two Stage Search. There are many ways to save these values allowing them to be recalled. The method chosen here is to use the 'SETX ' function. The problem is, 'SETX' is not a Windows function, it is a built-in CMD.EXE function. It is a batch command. It requires the use of ShellExecuteEx with the SHELLEXECUTEINFO structure initialized with the required information, the cmdToExeCute must contain the SETX verb, the variable name and its value. The value must be enclosed in double quotes if it contains white space. The syntax resembles the 'SET ' verb but the comma is replaced by a space. The 'SET ' verb, or the SetEnvironmentVariable Windows function writes the information to the Environment Block being used by the program. The 'SRTX' verb writes the information to the Registry. This means the new value cannot be retrieved with 'SET' or GetEnvironmentVariable until the program is re-started. If you want to retrieve it immediately, you have to save it with GetEnvironmentVariable. Using 'SET' and 'SETX' together, we can persist the state of the program across function calls and across program invocations. ShellExecuteEx is used to get the return code from CMD.EXE because 'SETX ' always succeeds if the parameters are correct, but this doesn't mean the value was saved. We get the output from the command to show to the user but we also get the process return code to report the possible failure of the command.

The persist_This function

C++
// This function writes to the Registry using the Batch SETX
// command to save environment variables permanently, until 
// they are changed by the User. Also, the SHMessageBoxCheck
// function writes to the Registry to prevent future displays
// of the message box. Refer to Menu Command VIEW>Reset_CheckBox
// to restore display of message
DWORD WINAPI  persist_This ( TCHAR * tStr ) {
  TCHAR cmdToExeCute [ 512 ] = { 0 };
  // Below is a sample output from both a successful and
  // an unsuccessful function execution. Notice that 
  // SETX sets ERRORLEVEL to zero either way, or possibly
  // doen 't set it at all. All we can do is give the 
  // process enough time to finish before we close the 
  // handle and report any error code returned by ShellExecuteEx
  //
  // --- Successful Execution.Notice the path is enclosed in  quotes.
  //  SUCCESS: Specified value was saved.
  //  errorlevel is 0
  //  Command Line was  "C:\Windows\System32\cmd.exe "  
  //  /k Setx STARTINDIR  "C:\Users\All Users "
  //  errorlevel is %ERRORLEVEL%
  //  Command Line was %CMDCMDLINE%
  //
  // ---Un-Succeddful Execution. Notice the path is not enclosed in quotes.
  //  This is seen as a third default parameter by SETX
  //  ERROR: Invalid syntax. Default option is not allowed more than  '2 ' time(s).
  //  Type  "SETX /? " for usage.
  //  errorlevel is 0
  //  Command Line was  "C:\Windows\System32\cmd.exe "  
  //  /k Setx STARTINDIR C:\Users\All Users
  //  errorlevel is %ERRORLEVEL%
  //  Command Line was %CMDCMDLINE%
  //
  // Get a temporary path 
  TCHAR nodeCD [ MAX_PATH - 1 ] = { 0 };
  GetCurrentDirectory ( MAX_PATH - 1, nodeCD );
  TCHAR tempFname [ MAX_PATH ];
  TCHAR tempPath [ MAX_PATH ];
  TCHAR tempStr [ 1024 ] = { 0 };// buffer for setx output
  CHAR setXresults [ 1024 ] = { 0 };// buffer for setx output
  TCHAR resultFileName [ MAX_PATH ];
  DWORD dwResult = GetTempPath ( MAX_PATH, tempPath );
  UINT uiResult = 0;
  // The length of the temp path(result) must be between 0 and MAX_PATH
  if ( dwResult < MAX_PATH || dwResult != 0 )
    // Get a temp file name based on temp path and  'search '
    uiResult = GetTempFileName ( tempPath, L "persist_This ", 0, tempFname );
  if ( uiResult == 0 ) {
    // if this user can 't get temp file name, 
    GetEnvironmentVariable ( L "USERPROFILE ", tempPath, 255 );
    // and create your own temp file name
    StringCchPrintf ( resultFileName, 255, L "%s\\result1.txt ", tempPath );
  }
  else {
    StringCchPrintf ( resultFileName, 255, L "%s ", tempFname );
  }
  #pragma region Line Continuation

  StringCchCopy ( tempStr, 511, tStr );
  StringCchCat ( tempStr, 511, L " >> %s &  " );
  StringCchCat ( tempStr, 511, L "echo errorlevel is %%ERRORLEVEL%% >> %s &  " );
  StringCchCat ( tempStr, 511, L "echo Command Line was:  " );
  StringCchCat ( tempStr, 511, L "%%CMDCMDLINE%% >> %s " );
  StringCchPrintf ( cmdToExeCute, 511, tempStr, tempFname, tempFname, tempFname );
  #pragma endregion for Command to Execute String

  SHELLEXECUTEINFO ShExecInfo = { 0 };
  ShExecInfo.cbSize = sizeof ( SHELLEXECUTEINFO );
  ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC;
  ShExecInfo.hwnd = NULL;
  ShExecInfo.lpVerb = NULL;
  ShExecInfo.lpFile = L "cmd.exe ";
  ShExecInfo.lpParameters = cmdToExeCute;
  ShExecInfo.lpDirectory = nodeCD;
  ShExecInfo.nShow = SW_HIDE;
  ShExecInfo.hInstApp = NULL;
  ShellExecuteEx ( &ShExecInfo );
  DWORD dwCode = STILL_ACTIVE;
  BOOL gotReturn = FALSE;
  for ( size_t i = 0; i < 100 && dwCode == STILL_ACTIVE; ++i ) {
    if ( ShExecInfo.hProcess ) gotReturn = GetExitCodeProcess ( ShExecInfo.hProcess, &dwCode );
    MSG msg; while ( PeekMessage ( &msg, NULL, 0, 0, PM_REMOVE ) ) DispatchMessage ( &msg );
    Sleep ( 10 );
  }  //  process is still active
  // if process is still active it will eventually return 0
  if ( STILL_ACTIVE == dwCode ) dwCode = 0;
  if ( 0 != dwCode ) {
    StringCchPrintf ( cmdToExeCute, 255, L "Return Code is %d. 
    File System ERROR.\nDATA was not be saved. Try it again! ", dwCode );
    MessageBox ( 0, cmdToExeCute, L "persist_This Return Code ",
           MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL );
  }
  CloseHandle ( ShExecInfo.hProcess );
  HANDLE resultFile = NULL;
  DWORD dwRead = 0;
  resultFile = CreateFile ( tempFname, GENERIC_READ, 0, NULL,
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  BOOL bSuccess = ReadFile ( resultFile, setXresults, MAX_PATH, &dwRead, NULL );
  if ( !bSuccess || dwRead == 0 ) {
    DWORD dwErr = GetLastError ( );
    StringCchPrintf ( cmdToExeCute, 255, L "Return Code is %d.
    \nThe data was not saved!\nMaybe you should do it again. ", dwErr );
    MessageBox ( 0, cmdToExeCute, L "persist_This Results File Read Failed! ",
           MB_OK | MB_ICONEXCLAMATION );
  }
  if ( dwRead != 0 ) {
    StringCchPrintf ( cmdToExeCute, 255, L "%S ", setXresults );
    TCHAR * pCmd = cmdToExeCute;
    for ( size_t i = 0; i < 4; i++ ) {
      pCmd = wcschr ( ( LPWSTR ) pCmd, L '\r ' );
      pCmd++;
    }
    *pCmd = L '\0 ';
    SHMessageBoxCheck ( 0,   cmdToExeCute, L "SET and 
    PERSIST this ENVIRONMENT VARIABLE Return Code ",
           MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, IDOK, 
           L "{51842606-D64C-4EDE-AF3F-4EE7AD3755A3} " );
    if ( uiResult>0 ) {
      StringCchPrintf ( cmdToExeCute, 255, L "%s\\per*.tmp ", tempPath );
      DeleteFile ( cmdToExeCute );
    }

  }
  CloseHandle ( resultFile );
  return 0;
}

EnumChildWindows and EnumChildProc: Retaining the STATE of the Window Handles

The Window handles are initialized by the Create Window functions, so we can 't persist them with 'SETX'. The handles are a part of the Window, so all we have to do is find the Window to get the handle. To find the main window, we can use FindWindow with the Class Name or Window Name, called inline. We could FindWindowEx to find a child window but the EnumChildProc is a simpler method to use. But you do have to write a function to call it. There are actually 2 functions but it is still the easiest to use. The first function in the sequence is getThisWindowHandle, which accepts the parent window handle and the control Id of the child window of that parent and returns the handle of that child window. It uses a struct variable containing a handle and a uint control id. getThisWindowHandle sets the handle member to NULL and the uint member to the control id. Now it calls EnumChildWindows with the parent handle, the address of EnumChildProc, cast to a WNDENUMPROC and the address of the struct containing the control id. On return, the structure contains the child window handle which can be NULL. EnumChildWindows is an enumerator function. It works like a 'for (child in parents tree) do child processing', calling EnumChildProc for every child handle it finds. EnumChildProc calls GetDlgCtrlID with the handle of the child window and returns the id of that control. If that id matches the id in the struct, the child window handle is copied into the struct 's window handle and b_isNotDone is set to false, which ends enumeration. Control passes to getThisWindowHandle, which returns the child window handle to the caller. Here are the struct and the two functions.

The getThisWindowHandle and EnumChildProc Functions

C++
// Struct to Identify Window by CTRL-ID
typedef struct  ecwData {
  HWND hCWind;
  UINT iD;
} ecpWnd, lpecpWnd;
//  EnumChildProc is called repeatedly by EnumChildWindows function
// it returns FALSE or cannot find any more child windows of the HWND
// that EnumChildWindows gave it. In this version of EnumChildProc,
// we find the control id of the Child Window enumerations and compare
// it to our controlId. If it matches we set the HWND of our ECPWND
// structure to the hwndChild of the enumeration and set b_isNotDone
// to false. We return b_isNotDone to EnumChildWindows, which stops 
// calling EnumChildProc so that the bext statement is executed and
// our ECPWND may now contain the Child HWND or zero. Therefore we
// have to test thr HWND to satisfy the Structured Attributes Language
// specification because we don 't want SAL to be dis-satisfied.
BOOL WINAPI EnumChildProc ( HWND hwndChild, LPARAM  lPar ) {
  lpecpWnd * pecw = (lpecpWnd*)(LPARAM )lPar;
  BOOL b_isNotDone = TRUE;
  ULONG dlgId = GetDlgCtrlID (hwndChild );
  if ( dlgId == pecw->iD ) {
    pecw->hCWind = hwndChild;
    b_isNotDone = FALSE;// signal end of enumeration
  }
  return b_isNotDone;
}

// put an ECPWND structure on the stack and put it 's address
// in a pointer variable and call the EnumChildWindows function
// with the hWnd, the address of the EnumChildProc and controlId.
HWND WINAPI getThisWindowHandle ( HWND hWnd, UINT  controlId ) {
  ecpWnd ecw;
  ecw.hCWind = NULL;
  ecw.iD = controlId;
  lpecpWnd * pecw = &ecw;
  EnumChildWindows ( hWnd, ( WNDENUMPROC ) EnumChildProc, ( LPARAM ) pecw );
  return ecw.hCWind;
}

Sample getThisWindowHandle Function Call

C++
HWND hList = getThisWindowHandle ( hMainWnd, ( ULONG ) IDC_LIST1);
if (hLidt == 0) return 0;

Connecting the Viewer to the List: The sendMeMyKey Function

The richEditProc calls a function named sendMeMyKey from several in the WM_NOTIFY message handler and apparently stops processing. In reality, it has passed the ball(of execution) to another runner. The sendMeMyKey Function takes 2 parameters, a window handle and a virtual key code, returning a BOOL. It uses the SendInput function to insert an array of input events into the input stream of the window whose handle you supplied to sendMeMyKey. It doesn't send message to a window. It synthesizes the event in the window that has focus. So, the first thing it does is set focus to the window you sent and then send the array consisting of a key down and key up of the virtual character. If the input is sent as 2 single events, other programs were sometimes grabbing focus, causing problems, the most serious of which was a program dead-lock. The way this works is almost like the user set the focus and then typing the keys, but this is subject to UIPI blocking so you can only send input to applications of equal or lower integrity level.

The sendMeMyKey Function

C++
// Set the focus to intended target abd send it a keydown and keyup sequence
BOOL __forceinline sendMeMyKey ( HWND hFocus, unsigned char pfKey ) {
  SetFocus ( hFocus );
  INPUT keyPr [ 2 ] = { 0 };
  keyPr [ 0 ].type = INPUT_KEYBOARD;
  keyPr [ 0 ].ki.dwFlags = 0; // KEYEVENTF_KEYDOWN?;
  keyPr [ 0 ].ki.wScan = 0;
  keyPr [ 0 ].ki.time = 0;
  keyPr [ 0 ].ki.dwExtraInfo = 0;
  keyPr [ 0 ].ki.wVk = pfKey;

  keyPr [ 1 ].type = INPUT_KEYBOARD;
  keyPr [ 1 ].ki.dwFlags = KEYEVENTF_KEYUP;
  keyPr [ 1 ].ki.wScan = 0;
  keyPr [ 1 ].ki.time = 0;
  keyPr [ 1 ].ki.dwExtraInfo = 0;
  keyPr [ 1 ].ki.wVk = pfKey;
  SendInput ( 2, keyPr, sizeof ( INPUT ) );
  return TRUE;
}

FillRichEditFromFile: How to Load a File into RichEdit

When a key press or mouse click is received, one of the most common actions executed is to load a file into RichEdit. The FillRichEditFromFile function is called from five different points in the listViewProc and once from the WndProc. All of these calls, except for the one from WndProc, occur as the result of a keypress or mouse click. So it seemed appropriate to discuss the function here, after sendMeMyKey. It is code written by and copyrighted by Microsoft. It receives two parameters, The handle to a RICHEDIT Instance and the path and name of the file to load and if successful, creates an EDITSTREAM structure with the address of the EditStreamCallback function and the dword pointer to the file handle created earlier. It sends an EM_STREAMIN message to the RICHEDIT Control with the wParam set to SF_TEXT and the EDITSTREAM cast to an LPARAM. if the sendmessage returns non-zero and the structure 's dwerror member is zero, it sets fSuccess to TRUE and closes the file handle. The EditStreamCallback function is called multiple times to read the entire file. The Microsoft Visual Studio Online Documentation Article "How to Use Streams " is the source document of these two functions. If you need more information, you can find it there.

Tips on Using Two Stage Search

When the program is executed for the first time, it checks the Environment Block for two variables, The STARTINDIR and the SEARCHSTR. If they are not present, they are initialized to the same value as your USERPROFILE for STARTINDIR and "*.cpp;*.c" for SEARCHSTR. These values can be changed at any time thereafter and the value will be put into the Registry and therefore, they will be found and used in subsequent executions of the program.

Changing the STARTINDIR: The ROOT Folder of the File List

To change the start in directory, select the 'File ' menu command and choose one of Change_Directory|Temp_Change_CD|CD_AND_Build. The first item, Change_Directory will allow you to change the directory and save the change to the Registry. The second item will allow you to change the directory for the current execution but will not save the change to the Registry. The third item will also change the directory but not save it to the Registry. For each of these items, the TreeView is given keyboard focus. Using the cursor keys to move to the desired folder does not disturb the entries in the ListView. When the Tree Control receives an ENTER Key, it set the current Tree Node as the current directory. This allows files from several roots to be included in the File List. It is possible to click on the Tree Node with the mouse but this will clear the ListView and populate it with the child items of the node.

Changing the SEARCHSTR: The File Extension Set Used in the File List Build

To change the types of files included in the File List, click on the Combobox EditCtrl on the left side of the application window or the dropdown button for that Combobox. When ENTER is pushed or the Start Button is clicked the Combobox message handler compares the EditCtrl text with the current value of SEARCHSTR and if they differ the new value is saved in the Registry. If the EditCtrl is empty, the last known value is retrieved and used.

The Rules for the File Extension Set

A single suffix or ending part of a File Name. It can be the entire File Name but not the beginning part with the ending part missing.

An asterisk followed by a period and a file type extension

One or more of the previous rule, separated by semicolons, i.e.,*.a;*.b;*.c;*.d;...etc.

How To ENTER the String To Search For

There are two different ways to enter the String To Search For. Select a string in the Viewer Panel and push 'f ' while holding down the control key. You can select a string of characters with no white space in the string by clicking on any of the characters. To select a string with spaces, click on one end and drag the highlight to the other end.

The other method is to click on the Combobox EditCtrl on the right side of the application window and typing in the string. The string is added to the Combobox List allowing a previously entered string to be recalled. The string is saved in the Registry but a new string replaces the old one.

How to Find the Next or Previous Occurrence of the String to Search For

To find the next occurrence of the string you have entered push PF3. If the search reaches the end of file it searches the next file(s) until a match is found. If it reaches the end of the file list it wraps around and searches from the beginning. If the Shift is held down, the search direction is backwards. PF6 will always search backwards. PF5 will find the next file containing a match. When searching backwards and the search reaches the beginning of the file, the last occurrence of the previous file will be found.

How to Open the File in Another App

To use the 'OPEN WITH ' Dialog, Right Click on the file in the ListView. To open the file location in File Explorer, Double left click or if the file is selected you can push ENTER.

How to Run a Batch Command in Two Stage Search

To execute a cmd.exe command or batch file, click on the EditBox Control under the ComboBoxes and enter '#!' followed by the command to execute. That will open a Console Window to execute the command. If you want to see the output of the command enter '&& pause' after the command. This causes the system to wait for user input. Do not attempt to keep this window open permanently. Instead, select "Edit>CMD Console" This will give you an open Console Window without freezing Two Stage Search.

How to Get Rid of the Annoying Message Box That Is Shown When You Enter a String

The SHMessageBoxCheck is displayed whenever a value is saved in the Registry. Since it is purely informational, you can get rid of it by CHECKING the Checkbox in the lower left corner of the dialog. After you get rid of the annoying message, you may still be annoyed by an occasional message box displaying an error message. When this happens, the new value may not have been saved, therefore you should consider re-entering the value.

How to Re-Display the Annoying Message Box

On the Main Menu, select "View>Reset_CheckBox | Force_Reset_CheckBox". The first choice, Reset_CheckBox, will display a console window to ask for confirmation. If you have changed your mind, type an 'n' to cancel the request or a 'y' to reset it. The second choice, Force_Reset_CheckBox does not ask for confirmation, it just does it.

The Help Menu

The Help Menu has 6 choices, they are :

  1. About...____________ Two Stage Search
  2. About Extensions__ How to Change Extensions
  3. About Strings______ How to enter String to search for
  4. About Path ________ How to Change the Path for File List build
  5. About CheckBox___ How to reset Checkbox
  6. About CMD.EXE____ How to invoke a CMD.EXE Console

These 6 help panels, always available at the click of a button, should provide enough information to make Two Stage Search easy enough to use that a separate Help File will not be necessary. If enough readers disagree and want a Help file, I will be happy to provide one.

Points of Interest

When I first decided to publish the Least Frequent Character Offset Algorithm, I considered using it in a program that used SSE2 or AVX2 Instructions, but when I tested it on an older computer, it didn't work. The computer didn't have the instructions. So I pulled out an older program, U2Charfunc, that used SSE Instructions and discovered that it performed just as well on a Windows 8.1 machine, which only had SSE Instructions, as it did on a Windows 10 machine. So I am going with the older program.

The window in the middle, the RESIZING ListView window, seemed to me to be a much simpler concept than using the client background of the main window to simulate a splitter bar. Especially if you want more than 2 windows, say 3 or 9. For 3 panels, you do have to keep the top and bottom borders from being moved but that is simple with cursor clipping. With 9 panels, you can use all 4 borders of the center panel to control the other 8 panels. For the panels between 3 and 9, you have to use at least 1 more resizing border if you want to make them resizable.

History

  • 30th August, 2019: Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --