/*******************************************************************************
*
*  (C) COPYRIGHT MICROSOFT CORP., 1993-1994
*
*  TITLE:       REGFIND.C
*
*  VERSION:     4.0
*
*  AUTHOR:      Tracy Sharpe
*
*  DATE:        14 Jul 1994
*
*  Find routines for the Registry Editor.
*
*******************************************************************************/

#include "pch.h"
#include "regedit.h"
#include "regkey.h"
#include "regresid.h"
#include "reghelp.h"
#include "regvalue.h"

#define SIZE_FINDSPEC                   (max(MAXKEYNAME, MAXVALUENAME_LENGTH))

TCHAR s_FindSpecification[SIZE_FINDSPEC] = { 0 };

#define FIND_EXACT                      0x00000001
#define FIND_KEYS                       0x00000002
#define FIND_VALUES                     0x00000004
#define FIND_DATA                       0x00000008

//  Initialized value is the default if we don't find last known state in the
//  registry.
DWORD g_FindFlags = FIND_KEYS | FIND_VALUES | FIND_DATA;

//  Global needed to monitor the find abort dialog status.
BOOL s_fContinueFind;

//
//  Reference data for the RegFind dialog.
//

typedef struct _REGFINDDATA {
    UINT LookForCount;
}   REGFINDDATA;

REGFINDDATA s_RegFindData;

//
//  Association between the items of the RegFind dialog and the find flags.
//

typedef struct _DLGITEMFINDFLAGASSOC {
    int DlgItem;
    DWORD Flag;
}   DLGITEMFINDFLAGASSOC;

const DLGITEMFINDFLAGASSOC s_DlgItemFindFlagAssoc[] = {
    IDC_WHOLEWORDONLY,      FIND_EXACT,
        IDC_FORKEYS,            FIND_KEYS,
        IDC_FORVALUES,          FIND_VALUES,
        IDC_FORDATA,            FIND_DATA
};

const DWORD s_RegFindHelpIDs[] = {
    IDC_FINDWHAT,      IDH_FIND_SEARCHTEXT,
        IDC_GROUPBOX,      IDH_REGEDIT_LOOK,
        IDC_FORKEYS,       IDH_REGEDIT_LOOK,
        IDC_FORVALUES,     IDH_REGEDIT_LOOK,
        IDC_FORDATA,       IDH_REGEDIT_LOOK,
        IDC_WHOLEWORDONLY, IDH_FIND_WHOLE,
        IDOK,              IDH_FIND_NEXT_BUTTON,
        
        0, 0
};

BOOL
PASCAL
FindCompare(
            LPTSTR lpString
            );

INT_PTR
PASCAL
RegFindDlgProc(
               HWND hWnd,
               UINT Message,
               WPARAM wParam,
               LPARAM lParam
               );

BOOL
PASCAL
RegFind_OnInitDialog(
                     HWND hWnd,
                     HWND hFocusWnd,
                     LPARAM lParam
                     );

VOID
PASCAL
RegFind_OnCommand(
                  HWND hWnd,
                  int DlgItem,
                  HWND hControlWnd,
                  UINT NotificationCode
                  );

BOOL
PASCAL
RegFindAbortProc(
                 HWND hRegFindAbortWnd
                 );

INT_PTR
CALLBACK
RegFindAbortDlgProc(
                    HWND hWnd,
                    UINT Message,
                    WPARAM wParam,
                    LPARAM lParam
                    );

/*******************************************************************************
*
*  RegEdit_OnCommandFindNext
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

VOID
PASCAL
RegEdit_OnCommandFindNext(
                          HWND hWnd,
                          BOOL fForceDialog
                          )
{
    UINT uErrorStringID;
    BOOL fError = FALSE;
    BOOL fSearchedToEnd;
    HWND hFocusWnd;
    LV_ITEM LVItem;
    TCHAR ValueName[MAXVALUENAME_LENGTH];
    DWORD Type;
    DWORD cbValueData;
    TV_ITEM TVItem;
    TCHAR KeyName[MAXKEYNAME];
    HWND hRegFindAbortWnd;
    HTREEITEM hTempTreeItem;
    UINT ExpandCounter;
    HKEY hRootKey;
    HKEY hKey;
    DWORD EnumIndex;
    DWORD cbValueName;
    BOOL fFoundMatch;
    TCHAR BestValueName[MAXVALUENAME_LENGTH];
    LV_FINDINFO LVFindInfo;
    
    fSearchedToEnd = FALSE;
    hFocusWnd = NULL;
    hRegFindAbortWnd = NULL;
    
    //
    //  Check if we're to show the find dialog.  This is either due to the user
    //  explicitly choosing the "Find" menu item or causing a "Find Next" with
    //  the search specification being uninitialized.
    //
    
    if (fForceDialog || s_FindSpecification[0] == 0) {
        
        if (DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_REGFIND), hWnd,
            RegFindDlgProc) != IDOK)
            return;
        
    }
    
    RegEdit_SetWaitCursor(TRUE);
    
    //
    //  Check if we're trying to finding either value names or data.  If so,
    //  then the next match might be part of the current ValueList.
    //
    
    if (g_FindFlags & (FIND_VALUES | FIND_DATA)) {
        
        LVItem.iItem = ListView_GetNextItem(g_RegEditData.hValueListWnd, -1,
            LVNI_FOCUSED);
        LVItem.iSubItem = 0;
        LVItem.mask = LVIF_TEXT;
        LVItem.pszText = ValueName;
        LVItem.cchTextMax = sizeof(ValueName)/sizeof(TCHAR);
        
        //
        //  Walk over all of the rest of the value names attempting to find a
        //  match.
        //
        
        while ((LVItem.iItem = ListView_GetNextItem(g_RegEditData.hValueListWnd,
            LVItem.iItem, LVNI_ALL)) != -1) {
            
            ListView_GetItem(g_RegEditData.hValueListWnd, &LVItem);
            
            //
            //  Check if this value name meets our search specification.  We'll
            //  assume that this value name still exists.
            //
            
            if ((g_FindFlags & FIND_VALUES) && FindCompare(ValueName))
                goto SelectListItem;
            
            //
            //  Check if this value data meets our search specification.  We'll
            //  have to go back to the registry to determine this.
            //
            
            if (g_FindFlags & FIND_DATA) 
            {
                if ((RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
                    NULL, &Type, NULL, &cbValueData) == ERROR_SUCCESS) && 
                    IsRegStringType(Type))
                {
                    // Allocate storage space
                    PBYTE pbDataValue = (PBYTE)LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
                    if (pbDataValue)
                    {
                        BOOL fSuccess = FALSE;
                        
                        if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
                            NULL, &Type, pbDataValue, &cbValueData) == ERROR_SUCCESS)
                        {
                            if (Type == REG_MULTI_SZ)
                            {
                                EDITVALUEPARAM evp;
                                evp.pValueData = pbDataValue; 
                                evp.cbValueData = cbValueData;
                                
                                if (ValueList_MultiStringToString(&evp))
                                {
                                    pbDataValue = evp.pValueData;
                                }  
                            }
                            fSuccess = FindCompare((PTSTR)pbDataValue);
                        }
                        
                        LocalFree(pbDataValue);
                        if (fSuccess)
                        {
                            goto SelectListItem;
                        }
                    }
                    else
                    {
                        fError = TRUE;
                        uErrorStringID = IDS_NOMEMORY;
                        goto DismissRegFindAbortWnd;
                    }
                }
                
            }
            
        }
        
    }
    
    //
    //  Searching the registry (especially with this code!) is a lengthy
    //  operation, so we must provide a way for the user to cancel the
    //  operation.
    //
    
    s_fContinueFind = TRUE;
    
    if ((hRegFindAbortWnd = CreateDialog(g_hInstance,
        MAKEINTRESOURCE(IDD_REGFINDABORT), hWnd, RegFindAbortDlgProc)) !=
        NULL) {
        
        EnableWindow(hWnd, FALSE);
        
        //
        //  Major hack:  The following code sequence relies heavily on the
        //  TreeView to maintain the state of the find process.  Even though I'm
        //  inserting and deleting non-visible tree items, the TreeView
        //  currently flickers despite this.
        //
        //  So, we set this internal flag and turn off the TreeView's redraw
        //  flag.  Whenever we get a WM_PAINT message for our main window, we
        //  temporarily "let" it redraw itself then and only then.  That way,
        //  the user can move the modeless abort dialog or switch away and back
        //  and still have the TreeView look normal.
        //
        //  Yes, it's difficult at this time to fix the TreeView's paint logic.
        //
        
        g_RegEditData.fProcessingFind = TRUE;
        SetWindowRedraw(g_RegEditData.hKeyTreeWnd, FALSE);
        
    }
    
    //
    //  Either the user wasn't trying to find value names or data or else no
    //  matches were found.  This means that we must move on to the next branch
    //  of the registry.
    //
    //  We first walk into the children of the current branch, then the
    //  siblings, and finally pop back through the parent.
    //
    //  We use the information already in the KeyTree pane as much as possible.
    //
    
    ExpandCounter = 0;
    fFoundMatch = FALSE;
    BestValueName[0] = '\0';
    
    TVItem.mask = TVIF_TEXT | TVIF_STATE | TVIF_CHILDREN;
    TVItem.pszText = KeyName;
    TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
    
    TVItem.hItem = TreeView_GetSelection(g_RegEditData.hKeyTreeWnd);
    TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
    
    while (TRUE) {
        
        //
        //  Check if we should cancel the find operation.  If so, restore our
        //  initial state and exit.
        //
        
        if (!RegFindAbortProc(hRegFindAbortWnd)) {
            
            if (ExpandCounter) {
                
                hTempTreeItem = TVItem.hItem;
                
                do {
                    
                    hTempTreeItem =
                        TreeView_GetParent(g_RegEditData.hKeyTreeWnd,
                        hTempTreeItem);
                    
                }   while (--ExpandCounter);
                
                TreeView_Expand(g_RegEditData.hKeyTreeWnd, hTempTreeItem,
                    TVE_COLLAPSE | TVE_COLLAPSERESET);
                
            }
            
            goto DismissRegFindAbortWnd;
            
        }
        
        //
        //  Does this branch have any children?  This would have been determined
        //  when the tree item was built by the routine KeyTree_ExpandBranch.
        //
        
        if (TVItem.cChildren) {
            
            //
            //  The branch may have children, but it may not have been expanded
            //  yet.
            //
            
            if ((hTempTreeItem = TreeView_GetChild(g_RegEditData.hKeyTreeWnd,
                TVItem.hItem)) == NULL) {
                
                if (!KeyTree_ExpandBranch(g_RegEditData.hKeyTreeWnd,
                    TVItem.hItem))
                    goto SkipToSibling;
                
                if ((hTempTreeItem = TreeView_GetChild(g_RegEditData.hKeyTreeWnd,
                    TVItem.hItem)) == NULL)
                    goto SkipToSibling;
                
                ExpandCounter++;
                
            }
            
            TVItem.hItem = hTempTreeItem;
            
        }
        
        //
        //  The branch doesn't have any children, so we'll move on to the next
        //  sibling of the current branch.  If none exists, then try finding
        //  the next sibling of the parent branch, and so on.
        //
        
        else {
            
SkipToSibling:
        while (TRUE) {
            
            if ((hTempTreeItem =
                TreeView_GetNextSibling(g_RegEditData.hKeyTreeWnd,
                TVItem.hItem)) != NULL) {
                
                TVItem.hItem = hTempTreeItem;
                break;
                
            }
            
            //
            //  If no more parents exist, then we've finished searching the
            //  tree.  We're outta here!
            //
            
            if ((TVItem.hItem =
                TreeView_GetParent(g_RegEditData.hKeyTreeWnd,
                TVItem.hItem)) == NULL) {
                
                fSearchedToEnd = TRUE;
                
                goto DismissRegFindAbortWnd;
                
            }
            
            if (ExpandCounter) {
                
                ExpandCounter--;
                
                TreeView_Expand(g_RegEditData.hKeyTreeWnd, TVItem.hItem,
                    TVE_COLLAPSE | TVE_COLLAPSERESET);
                
            }
            
        }
        
        }
        
        //
        //  If we made it this far, then we're at the next branch of the
        //  registry to evaluate.
        //
        
        TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
        
        //
        //  Check if we're trying to find keys.
        //
        
        if (g_FindFlags & FIND_KEYS) {
            
            if (FindCompare(KeyName))
                goto SelectTreeItem;
            
        }
        
        //
        //  Check if we're trying to find value names or data.
        //
        
        if (g_FindFlags & (FIND_VALUES | FIND_DATA)) {
            
            //
            //  Try to open the registry at the new current branch.
            //
            
            hRootKey = KeyTree_BuildKeyPath(g_RegEditData.hKeyTreeWnd,
                TVItem.hItem, KeyName, BKP_TOSUBKEY);
            
            if(hRootKey && RegOpenKeyEx(hRootKey,KeyName,0,KEY_QUERY_VALUE,&hKey) ==
                ERROR_SUCCESS) {
                
                //
                //  Here's the simple case-- we're trying to find an exact match
                //  for a value name.  We can just use the registry API to do
                //  this for us!
                //
                
                if ((g_FindFlags & (FIND_VALUES | FIND_DATA | FIND_EXACT)) ==
                    (FIND_VALUES | FIND_EXACT)) {
                    
                    if (RegEdit_QueryValueEx(hKey, s_FindSpecification, NULL, NULL,
                        NULL, NULL) == ERROR_SUCCESS) {
                        
                        lstrcpy(BestValueName, s_FindSpecification);
                        fFoundMatch = TRUE;
                        
                    }
                    
                }
                
                //
                //  Bummer... we need to walk through all of the registry
                //  value/data pairs for this key to try to find a match.  Even
                //  worse, we have to look at _all_ of the entries, not just the
                //  first hit... we must display the first alphabetically
                //  matching entry!
                //
                
                else {
                    
                    EnumIndex = 0;
                    
                    while (TRUE) 
                    {
                        cbValueName = sizeof(ValueName)/sizeof(TCHAR);
                        
                        if (RegEnumValue(hKey, EnumIndex++, ValueName,
                            &cbValueName, NULL, &Type, NULL,
                            &cbValueData) == ERROR_SUCCESS)
                        {
                            PBYTE pbValueData = (g_FindFlags & FIND_DATA) ? 
                                (PBYTE)LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type)) : NULL;
                            
                            if (pbValueData || !(g_FindFlags & FIND_DATA))
                            {
                                if (RegEdit_QueryValueEx(hKey, ValueName, NULL, &Type, 
                                    pbValueData, &cbValueData) == ERROR_SUCCESS)
                                {
                                    if (pbValueData && (Type == REG_MULTI_SZ))
                                    {
                                        EDITVALUEPARAM evp;
                                        evp.pValueData = pbValueData; 
                                        evp.cbValueData = cbValueData;
                                        
                                        if (ValueList_MultiStringToString(&evp))
                                        {
                                            pbValueData = evp.pValueData;
                                        }
                                    }
                                    
                                    if (((g_FindFlags & FIND_VALUES) &&
                                        FindCompare(ValueName)) ||
                                        ((g_FindFlags & FIND_DATA) && IsRegStringType(Type) &&
                                        FindCompare((PTSTR)pbValueData))) 
                                    {
                                        //
                                        //  We've got to check if we've found a "better"
                                        //  value name to display-- one that's at the top of
                                        //  the sorted list.
                                        //
                                        
                                        if (fFoundMatch) {
                                            
                                            if (lstrcmpi(BestValueName, ValueName) > 0)
                                                lstrcpy(BestValueName, ValueName);
                                            
                                        }
                                        
                                        else {
                                            
                                            lstrcpy(BestValueName, ValueName);
                                            fFoundMatch = TRUE;
                                            
                                        }
                                        
                                    }
                                }
                                if (pbValueData)
                                {
                                    LocalFree(pbValueData);
                                }
                            }
                            else
                            {
                                fError = TRUE;
                                uErrorStringID = IDS_NOMEMORY;
                                goto DismissRegFindAbortWnd;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    
                }
                
                RegCloseKey(hKey);
                
                if (fFoundMatch)
                    goto SelectTreeItem;
                
            }
            
        }
        
    }
    
SelectTreeItem:
    TreeView_EnsureVisible(g_RegEditData.hKeyTreeWnd, TVItem.hItem);
    TreeView_SelectItem(g_RegEditData.hKeyTreeWnd, TVItem.hItem);
    
    if (!fFoundMatch)
        hFocusWnd = g_RegEditData.hKeyTreeWnd;
    
    else {
        
        //
        //  Right now, the TreeView_SelectItem above will cause the ValueListWnd
        //  to update, but only after a short time delay.  We want the list
        //  immediately updated, so force the timer to go off now.
        //
        
        RegEdit_OnSelChangedTimer(hWnd);
        
        if (BestValueName[0] == 0)
            LVItem.iItem = 0;
        
        else {
            
            LVFindInfo.flags = LVFI_STRING;
            LVFindInfo.psz = BestValueName;
            
            LVItem.iItem = ListView_FindItem(g_RegEditData.hValueListWnd,
                -1, &LVFindInfo);
            
        }
        
SelectListItem:
        ListView_SetItemState(g_RegEditData.hValueListWnd, -1, 0,
            LVIS_SELECTED | LVIS_FOCUSED);
        ListView_SetItemState(g_RegEditData.hValueListWnd, LVItem.iItem,
            LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
        ListView_EnsureVisible(g_RegEditData.hValueListWnd, LVItem.iItem,
            FALSE);
        
        hFocusWnd = g_RegEditData.hValueListWnd;
        
    }
    
DismissRegFindAbortWnd:
    RegEdit_SetWaitCursor(FALSE);
    
    if (hRegFindAbortWnd != NULL) {
        
        g_RegEditData.fProcessingFind = FALSE;
        SetWindowRedraw(g_RegEditData.hKeyTreeWnd, TRUE);
        
        EnableWindow(hWnd, TRUE);
        DestroyWindow(hRegFindAbortWnd);
        
    }
    
    if (hFocusWnd != NULL)
        SetFocus(hFocusWnd);
    
    if (fError)
    {
        InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(uErrorStringID),
            MAKEINTRESOURCE(IDS_REGEDIT), MB_ICONERROR | MB_OK);
    }
    
    if (fSearchedToEnd)
        InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_SEARCHEDTOEND),
        MAKEINTRESOURCE(IDS_REGEDIT), MB_ICONINFORMATION | MB_OK);
}

/*******************************************************************************
*
*  FindCompare
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

BOOL
PASCAL
FindCompare(
            LPTSTR lpString
            )
{
    
    if (g_FindFlags & FIND_EXACT)
        return lstrcmpi(lpString, s_FindSpecification) == 0;
    
    else
        return StrStrI(lpString, s_FindSpecification) != NULL;
    
}

/*******************************************************************************
*
*  RegFindDlgProc
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

INT_PTR
PASCAL
RegFindDlgProc(
               HWND hWnd,
               UINT Message,
               WPARAM wParam,
               LPARAM lParam
               )
{
    
    switch (Message) {
        
        HANDLE_MSG(hWnd, WM_INITDIALOG, RegFind_OnInitDialog);
        HANDLE_MSG(hWnd, WM_COMMAND, RegFind_OnCommand);
        
    case WM_HELP:
        WinHelp(((LPHELPINFO) lParam)-> hItemHandle, g_pHelpFileName,
            HELP_WM_HELP, (ULONG_PTR) s_RegFindHelpIDs);
        break;
        
    case WM_CONTEXTMENU:
        WinHelp((HWND) wParam, g_pHelpFileName, HELP_CONTEXTMENU,
            (ULONG_PTR) s_RegFindHelpIDs);
        break;
        
    default:
        return FALSE;
        
    }
    
    return TRUE;
    
}

/*******************************************************************************
*
*  RegFind_OnInitDialog
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

BOOL
PASCAL
RegFind_OnInitDialog(
                     HWND hWnd,
                     HWND hFocusWnd,
                     LPARAM lParam
                     )
{
    
    UINT Counter;
    int DlgItem;
    
    //
    //  Initialize the "Find What" edit control.
    //
    
    SendDlgItemMessage(hWnd, IDC_FINDWHAT, EM_SETLIMITTEXT,
        SIZE_FINDSPEC, 0);
    SetDlgItemText(hWnd, IDC_FINDWHAT, s_FindSpecification);
    
    //
    //  Initialize the checkboxes based on the state of the global find flags.
    //
    
    s_RegFindData.LookForCount = 0;
    
    for (Counter = 0; Counter < sizeof(s_DlgItemFindFlagAssoc) /
        sizeof(DLGITEMFINDFLAGASSOC); Counter++) {
        
        if (g_FindFlags & s_DlgItemFindFlagAssoc[Counter].Flag) {
            
            DlgItem = s_DlgItemFindFlagAssoc[Counter].DlgItem;
            
            CheckDlgButton(hWnd, DlgItem, TRUE);
            
            if (DlgItem >= IDC_FORKEYS && DlgItem <= IDC_FORDATA)
                s_RegFindData.LookForCount++;
            
        }
        
    }
    
    return TRUE;
    
    UNREFERENCED_PARAMETER(hFocusWnd);
    UNREFERENCED_PARAMETER(lParam);
    
}

/*******************************************************************************
*
*  RegFind_OnCommand
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

VOID
PASCAL
RegFind_OnCommand(
                  HWND hWnd,
                  int DlgItem,
                  HWND hControlWnd,
                  UINT NotificationCode
                  )
{
    
    UINT Counter;
    
    if (DlgItem >= IDC_FORKEYS && DlgItem <= IDC_FORDATA) {
        
        if (NotificationCode == BN_CLICKED) {
            
            IsDlgButtonChecked(hWnd, DlgItem) ? s_RegFindData.LookForCount++ :
        s_RegFindData.LookForCount--;
        
        goto EnableFindNextButton;
        
        }
        
    }
    
    else {
        
        switch (DlgItem) {
            
        case IDC_FINDWHAT:
            if (NotificationCode == EN_CHANGE) {
                
EnableFindNextButton:
            EnableWindow(GetDlgItem(hWnd, IDOK),
                s_RegFindData.LookForCount > 0 &&
                SendDlgItemMessage(hWnd, IDC_FINDWHAT,
                WM_GETTEXTLENGTH, 0, 0) != 0);
            
            }
            break;
            
        case IDOK:
            GetDlgItemText(hWnd, IDC_FINDWHAT, s_FindSpecification,
                sizeof(s_FindSpecification)/sizeof(TCHAR));
            
            for (Counter = 0; Counter < sizeof(s_DlgItemFindFlagAssoc) /
                sizeof(DLGITEMFINDFLAGASSOC); Counter++) {
                
                if (IsDlgButtonChecked(hWnd,
                    s_DlgItemFindFlagAssoc[Counter].DlgItem))
                    g_FindFlags |= s_DlgItemFindFlagAssoc[Counter].Flag;
                else
                    g_FindFlags &= ~s_DlgItemFindFlagAssoc[Counter].Flag;
                
            }
            
            //  FALL THROUGH
            
        case IDCANCEL:
            EndDialog(hWnd, DlgItem);
            break;
            
        }
        
    }
    
}

/*******************************************************************************
*
*  RegFindAbortProc
*
*  DESCRIPTION:
*
*  PARAMETERS:
*     (returns), TRUE to continue the find, else FALSE to cancel.
*
*******************************************************************************/

BOOL
PASCAL
RegFindAbortProc(
                 HWND hRegFindAbortWnd
                 )
{
    
    while (s_fContinueFind && MessagePump(hRegFindAbortWnd))
        ;
    
    return s_fContinueFind;
    
}

/*******************************************************************************
*
*  RegAbortDlgProc
*
*  DESCRIPTION:
*     Callback procedure for the RegAbort dialog box.
*
*  PARAMETERS:
*     hWnd, handle of RegAbort window.
*     Message,
*     wParam,
*     lParam,
*     (returns),
*
*******************************************************************************/

INT_PTR
CALLBACK
RegFindAbortDlgProc(
                    HWND hWnd,
                    UINT Message,
                    WPARAM wParam,
                    LPARAM lParam
                    )
{
    
    switch (Message) {
        
    case WM_INITDIALOG:
        break;
        
    case WM_CLOSE:
    case WM_COMMAND:
        s_fContinueFind = FALSE;
        break;
        
    default:
        return FALSE;
        
    }
    
    return TRUE;
    
}
