reactos/base/applications/regedit/find.c
Katayama Hirofumi MZ 84e580b67e
[REGEDIT] Fix ListView selection and finding (#5150)
We will check the data size correctly, instead of 3 NUL byte appending hack. Add bSelectNone parameter to UpdateAddress and RefreshListView functions. If bSelectNone is TRUE, then select nothing of ListView. Fix item selection of ListView. Rename CompareData helper function as MatchData and improve it. Improve the search algorithm. If the item selection of ListView changed, scroll down to the item. Follow up to #5146. CORE-15986, CORE-18230
2023-04-01 22:21:59 +09:00

833 lines
23 KiB
C

/*
* Regedit find dialog
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "regedit.h"
#define RSF_WHOLESTRING 0x00000001
#define RSF_LOOKATKEYS 0x00000002
#define RSF_LOOKATVALUES 0x00000004
#define RSF_LOOKATDATA 0x00000008
#define RSF_MATCHCASE 0x00010000
static WCHAR s_szFindWhat[256];
static const WCHAR s_szFindFlags[] = L"FindFlags";
static const WCHAR s_szFindFlagsR[] = L"FindFlagsReactOS";
static HWND s_hwndAbortDialog;
static BOOL s_bAbort;
static DWORD s_dwFlags;
static WCHAR s_szName[MAX_PATH];
static DWORD s_cchName;
static const WCHAR s_empty[] = L"";
static const WCHAR s_backslash[] = L"\\";
extern VOID SetValueName(HWND hwndLV, LPCWSTR pszValueName);
BOOL DoEvents(VOID)
{
MSG msg;
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
s_bAbort = TRUE;
if (!IsDialogMessageW(s_hwndAbortDialog, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return s_bAbort;
}
static LPWSTR lstrstri(LPCWSTR psz1, LPCWSTR psz2)
{
INT i, cch1, cch2;
cch1 = wcslen(psz1);
cch2 = wcslen(psz2);
for(i = 0; i <= cch1 - cch2; i++)
{
if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
psz1 + i, cch2, psz2, cch2) == 2)
return (LPWSTR) (psz1 + i);
}
return NULL;
}
static BOOL CompareName(LPCWSTR pszName1, LPCWSTR pszName2)
{
if (s_dwFlags & RSF_WHOLESTRING)
{
if (s_dwFlags & RSF_MATCHCASE)
return wcscmp(pszName1, pszName2) == 0;
else
return _wcsicmp(pszName1, pszName2) == 0;
}
else
{
if (s_dwFlags & RSF_MATCHCASE)
return wcsstr(pszName1, pszName2) != NULL;
else
return lstrstri(pszName1, pszName2) != NULL;
}
}
/* Do not assume that pch1 is terminated with UNICODE_NULL */
static BOOL MatchString(LPCWCH pch1, INT cch1, LPCWCH pch2, INT cch2)
{
INT i;
DWORD dwNorm = ((s_dwFlags & RSF_MATCHCASE) ? NORM_IGNORECASE : 0);
if (s_dwFlags & RSF_WHOLESTRING)
return 2 == CompareStringW(LOCALE_SYSTEM_DEFAULT, dwNorm, pch1, cch1, pch2, cch2);
if (cch1 < cch2)
return FALSE;
for (i = 0; i <= cch1 - cch2; i++)
{
if (2 == CompareStringW(LOCALE_SYSTEM_DEFAULT, dwNorm, pch1 + i, cch2, pch2, cch2))
return TRUE;
}
return FALSE;
}
static BOOL MatchData(DWORD dwType, LPCVOID pv1, DWORD cb1)
{
if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
return MatchString(pv1, (INT)(cb1 / sizeof(WCHAR)), s_szFindWhat, lstrlenW(s_szFindWhat));
return FALSE;
}
int compare(const void *x, const void *y)
{
const LPCWSTR *a = (const LPCWSTR *)x;
const LPCWSTR *b = (const LPCWSTR *)y;
return _wcsicmp(*a, *b);
}
BOOL RegFindRecurse(
HKEY hKey,
LPCWSTR pszSubKey,
LPCWSTR pszValueName,
LPWSTR *ppszFoundSubKey,
LPWSTR *ppszFoundValueName)
{
HKEY hSubKey;
LONG lResult;
WCHAR szSubKey[MAX_PATH];
DWORD i, c, cb, type;
BOOL fPast;
LPWSTR *ppszNames = NULL;
LPBYTE pb = NULL;
if (DoEvents())
return FALSE;
if(wcslen(pszSubKey) >= _countof(szSubKey))
return FALSE;
wcscpy(szSubKey, pszSubKey);
hSubKey = NULL;
lResult = RegOpenKeyExW(hKey, szSubKey, 0, KEY_ALL_ACCESS, &hSubKey);
if (lResult != ERROR_SUCCESS)
return FALSE;
lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
&c, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS)
goto err;
ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
if (ppszNames == NULL)
goto err;
ZeroMemory(ppszNames, c * sizeof(LPWSTR));
/* Retrieve the value names associated with the current key */
for(i = 0; i < c; i++)
{
if (DoEvents())
goto err;
s_cchName = _countof(s_szName);
lResult = RegEnumValueW(hSubKey, i, s_szName, &s_cchName, NULL, NULL,
NULL, &cb);
if (lResult == ERROR_NO_MORE_ITEMS)
{
c = i;
break;
}
if (lResult != ERROR_SUCCESS)
goto err;
if (s_cchName >= _countof(s_szName))
continue;
ppszNames[i] = _wcsdup(s_szName);
}
qsort(ppszNames, c, sizeof(LPWSTR), compare);
/* If pszValueName is NULL, the function will search for all values within the key */
fPast = (pszValueName == NULL);
/* Search within the values */
for (i = 0; i < c; i++)
{
if (DoEvents())
goto err;
if (!fPast && _wcsicmp(ppszNames[i], pszValueName) == 0)
{
fPast = TRUE;
continue;
}
if (!fPast)
continue;
if ((s_dwFlags & RSF_LOOKATVALUES) &&
CompareName(ppszNames[i], s_szFindWhat))
{
*ppszFoundSubKey = _wcsdup(szSubKey);
*ppszFoundValueName = _wcsdup(ppszNames[i]);
goto success;
}
lResult = RegQueryValueExW(hSubKey, ppszNames[i], NULL, &type,
NULL, &cb);
if (lResult != ERROR_SUCCESS)
goto err;
pb = malloc(cb);
if (pb == NULL)
goto err;
lResult = RegQueryValueExW(hSubKey, ppszNames[i], NULL, &type,
pb, &cb);
if (lResult != ERROR_SUCCESS)
goto err;
if ((s_dwFlags & RSF_LOOKATDATA) && MatchData(type, pb, cb))
{
*ppszFoundSubKey = _wcsdup(szSubKey);
*ppszFoundValueName = _wcsdup(ppszNames[i]);
goto success;
}
free(pb);
pb = NULL;
}
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
ppszNames = NULL;
/* Retrieve the number of sub-keys */
lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &c, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS)
goto err;
ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
if (ppszNames == NULL)
goto err;
ZeroMemory(ppszNames, c * sizeof(LPWSTR));
/* Retrieve the names of the sub-keys */
for(i = 0; i < c; i++)
{
if (DoEvents())
goto err;
s_cchName = _countof(s_szName);
lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cchName, NULL, NULL,
NULL, NULL);
if (lResult == ERROR_NO_MORE_ITEMS)
{
c = i;
break;
}
if (lResult != ERROR_SUCCESS)
goto err;
if (s_cchName >= _countof(s_szName))
continue;
ppszNames[i] = _wcsdup(s_szName);
}
qsort(ppszNames, c, sizeof(LPWSTR), compare);
/* Search within the sub-keys */
for(i = 0; i < c; i++)
{
if (DoEvents())
goto err;
if ((s_dwFlags & RSF_LOOKATKEYS) &&
CompareName(ppszNames[i], s_szFindWhat))
{
*ppszFoundSubKey = malloc(
(wcslen(szSubKey) + wcslen(ppszNames[i]) + 2) *
sizeof(WCHAR));
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
wcscpy(*ppszFoundSubKey, szSubKey);
wcscat(*ppszFoundSubKey, s_backslash);
}
else
**ppszFoundSubKey = 0;
wcscat(*ppszFoundSubKey, ppszNames[i]);
*ppszFoundValueName = NULL;
goto success;
}
/* Search within the value entries of the sub-key */
if (RegFindRecurse(hSubKey, ppszNames[i], NULL, ppszFoundSubKey,
ppszFoundValueName))
{
LPWSTR psz = *ppszFoundSubKey;
*ppszFoundSubKey = malloc(
(wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR));
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
wcscpy(*ppszFoundSubKey, szSubKey);
wcscat(*ppszFoundSubKey, s_backslash);
}
else
**ppszFoundSubKey = 0;
wcscat(*ppszFoundSubKey, psz);
free(psz);
goto success;
}
}
err:
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
free(pb);
RegCloseKey(hSubKey);
return FALSE;
success:
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
RegCloseKey(hSubKey);
return TRUE;
}
BOOL RegFindWalk(
HKEY * phKey,
LPCWSTR pszSubKey,
LPCWSTR pszValueName,
LPWSTR *ppszFoundSubKey,
LPWSTR *ppszFoundValueName)
{
LONG lResult;
DWORD i, c;
HKEY hBaseKey, hSubKey;
WCHAR szKeyName[MAX_PATH];
WCHAR szSubKey[MAX_PATH];
LPWSTR pch;
BOOL fPast, fKeyMatched;
LPWSTR *ppszNames = NULL;
hBaseKey = *phKey;
if (wcslen(pszSubKey) >= _countof(szSubKey))
return FALSE;
if (RegFindRecurse(hBaseKey, pszSubKey, pszValueName, ppszFoundSubKey,
ppszFoundValueName))
return TRUE;
wcscpy(szSubKey, pszSubKey);
while(szSubKey[0] != 0)
{
if (DoEvents())
return FALSE;
pch = wcsrchr(szSubKey, L'\\');
if (pch == NULL)
{
wcscpy(szKeyName, szSubKey);
szSubKey[0] = 0;
hSubKey = hBaseKey;
}
else
{
lstrcpynW(szKeyName, pch + 1, MAX_PATH);
*pch = 0;
lResult = RegOpenKeyExW(hBaseKey, szSubKey, 0, KEY_ALL_ACCESS,
&hSubKey);
if (lResult != ERROR_SUCCESS)
return FALSE;
}
lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &c, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (lResult != ERROR_SUCCESS)
goto err;
ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
if (ppszNames == NULL)
goto err;
ZeroMemory(ppszNames, c * sizeof(LPWSTR));
for(i = 0; i < c; i++)
{
if (DoEvents())
goto err;
s_cchName = _countof(s_szName);
lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cchName,
NULL, NULL, NULL, NULL);
if (lResult == ERROR_NO_MORE_ITEMS)
{
c = i;
break;
}
if (lResult != ERROR_SUCCESS)
break;
ppszNames[i] = _wcsdup(s_szName);
}
qsort(ppszNames, c, sizeof(LPWSTR), compare);
fPast = FALSE;
for(i = 0; i < c; i++)
{
if (DoEvents())
goto err;
if (!fPast && _wcsicmp(ppszNames[i], szKeyName) == 0)
{
fPast = TRUE;
continue;
}
if (!fPast)
continue;
if ((s_dwFlags & RSF_LOOKATKEYS) &&
CompareName(ppszNames[i], s_szFindWhat))
{
*ppszFoundSubKey = malloc(
(wcslen(szSubKey) + wcslen(ppszNames[i]) + 2) *
sizeof(WCHAR));
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
wcscpy(*ppszFoundSubKey, szSubKey);
wcscat(*ppszFoundSubKey, s_backslash);
}
else
**ppszFoundSubKey = 0;
wcscat(*ppszFoundSubKey, ppszNames[i]);
*ppszFoundValueName = NULL;
goto success;
}
fKeyMatched = (_wcsicmp(ppszNames[i], szKeyName) == 0);
if (RegFindRecurse(hSubKey, ppszNames[i], (fKeyMatched ? pszValueName : NULL),
ppszFoundSubKey, ppszFoundValueName))
{
LPWSTR psz = *ppszFoundSubKey;
*ppszFoundSubKey = malloc(
(wcslen(szSubKey) + wcslen(psz) + 2) *
sizeof(WCHAR));
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
wcscpy(*ppszFoundSubKey, szSubKey);
wcscat(*ppszFoundSubKey, s_backslash);
}
else
**ppszFoundSubKey = 0;
wcscat(*ppszFoundSubKey, psz);
free(psz);
goto success;
}
}
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
ppszNames = NULL;
if (hBaseKey != hSubKey)
RegCloseKey(hSubKey);
}
if (*phKey == HKEY_CLASSES_ROOT)
{
*phKey = HKEY_CURRENT_USER;
if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
ppszFoundValueName))
return TRUE;
}
if (*phKey == HKEY_CURRENT_USER)
{
*phKey = HKEY_LOCAL_MACHINE;
if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
ppszFoundValueName))
goto success;
}
if (*phKey == HKEY_LOCAL_MACHINE)
{
*phKey = HKEY_USERS;
if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
ppszFoundValueName))
goto success;
}
if (*phKey == HKEY_USERS)
{
*phKey = HKEY_CURRENT_CONFIG;
if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
ppszFoundValueName))
goto success;
}
err:
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
if (hBaseKey != hSubKey)
RegCloseKey(hSubKey);
return FALSE;
success:
if (ppszNames != NULL)
{
for(i = 0; i < c; i++)
free(ppszNames[i]);
free(ppszNames);
}
if (hBaseKey != hSubKey)
RegCloseKey(hSubKey);
return TRUE;
}
static DWORD GetFindFlags(void)
{
HKEY hKey;
DWORD dwType, dwValue, cbData;
DWORD dwFlags = RSF_LOOKATKEYS | RSF_LOOKATVALUES | RSF_LOOKATDATA;
if (RegOpenKeyW(HKEY_CURRENT_USER, g_szGeneralRegKey, &hKey) == ERROR_SUCCESS)
{
/* Retrieve flags from registry key */
cbData = sizeof(dwValue);
if (RegQueryValueExW(hKey, s_szFindFlags, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
{
if (dwType == REG_DWORD)
dwFlags = (dwFlags & ~0x0000FFFF) | ((dwValue & 0x0000FFFF) << 0);
}
/* Retrieve ReactOS Regedit specific flags from registry key */
cbData = sizeof(dwValue);
if (RegQueryValueExW(hKey, s_szFindFlagsR, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
{
if (dwType == REG_DWORD)
dwFlags = (dwFlags & ~0xFFFF0000) | ((dwValue & 0x0000FFFF) << 16);
}
RegCloseKey(hKey);
}
return dwFlags;
}
static void SetFindFlags(DWORD dwFlags)
{
HKEY hKey;
DWORD dwDisposition;
DWORD dwData;
if (RegCreateKeyExW(HKEY_CURRENT_USER, g_szGeneralRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS)
{
dwData = (dwFlags >> 0) & 0x0000FFFF;
RegSetValueExW(hKey, s_szFindFlags, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
dwData = (dwFlags >> 16) & 0x0000FFFF;
RegSetValueExW(hKey, s_szFindFlagsR, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
RegCloseKey(hKey);
}
}
static INT_PTR CALLBACK AbortFindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(hDlg);
switch(uMsg)
{
case WM_CLOSE:
s_bAbort = TRUE;
break;
case WM_COMMAND:
switch(HIWORD(wParam))
{
case BN_CLICKED:
switch(LOWORD(wParam))
{
case IDCANCEL:
s_bAbort = TRUE;
break;
}
break;
}
break;
}
return 0;
}
BOOL FindNext(HWND hWnd)
{
HKEY hKeyRoot;
LPCWSTR pszKeyPath;
BOOL fSuccess;
WCHAR szFullKey[512];
LPCWSTR pszValueName;
LPWSTR pszFoundSubKey, pszFoundValueName;
if (wcslen(s_szFindWhat) == 0)
{
FindDialog(hWnd);
return TRUE;
}
s_dwFlags = GetFindFlags();
pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
if (pszKeyPath == NULL)
{
hKeyRoot = HKEY_CLASSES_ROOT;
pszKeyPath = s_empty;
}
/* Create abort find dialog */
s_hwndAbortDialog = CreateDialogW(GetModuleHandle(NULL),
MAKEINTRESOURCEW(IDD_FINDING), hWnd, AbortFindDialogProc);
if (s_hwndAbortDialog)
{
ShowWindow(s_hwndAbortDialog, SW_SHOW);
UpdateWindow(s_hwndAbortDialog);
}
s_bAbort = FALSE;
pszValueName = GetValueName(g_pChildWnd->hListWnd, -1);
EnableWindow(hFrameWnd, FALSE);
EnableWindow(g_pChildWnd->hTreeWnd, FALSE);
EnableWindow(g_pChildWnd->hListWnd, FALSE);
EnableWindow(g_pChildWnd->hAddressBarWnd, FALSE);
fSuccess = RegFindWalk(&hKeyRoot, pszKeyPath, pszValueName,
&pszFoundSubKey, &pszFoundValueName);
EnableWindow(hFrameWnd, TRUE);
EnableWindow(g_pChildWnd->hTreeWnd, TRUE);
EnableWindow(g_pChildWnd->hListWnd, TRUE);
EnableWindow(g_pChildWnd->hAddressBarWnd, TRUE);
if (s_hwndAbortDialog)
{
DestroyWindow(s_hwndAbortDialog);
s_hwndAbortDialog = NULL;
}
if (fSuccess)
{
GetKeyName(szFullKey, ARRAY_SIZE(szFullKey), hKeyRoot, pszFoundSubKey);
SelectNode(g_pChildWnd->hTreeWnd, szFullKey);
free(pszFoundSubKey);
if (pszFoundValueName != NULL)
{
SetValueName(g_pChildWnd->hListWnd, pszFoundValueName);
free(pszFoundValueName);
SetFocus(g_pChildWnd->hListWnd);
}
else
{
SetFocus(g_pChildWnd->hTreeWnd);
}
}
return fSuccess || s_bAbort;
}
static INT_PTR CALLBACK FindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR iResult = 0;
HWND hControl;
LONG lStyle;
DWORD dwFlags;
static WCHAR s_szSavedFindValue[256];
switch(uMsg)
{
case WM_INITDIALOG:
dwFlags = GetFindFlags();
hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
if (hControl)
SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATKEYS) ? TRUE : FALSE, 0);
hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
if (hControl)
SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATVALUES) ? TRUE : FALSE, 0);
hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
if (hControl)
SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATDATA) ? TRUE : FALSE, 0);
/* Match whole string */
hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
if (hControl)
SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_WHOLESTRING) ? TRUE : FALSE, 0);
/* Case sensitivity */
hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
if (hControl)
SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_MATCHCASE) ? TRUE : FALSE, 0);
hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
if (hControl)
{
SetWindowTextW(hControl, s_szSavedFindValue);
SetFocus(hControl);
SendMessageW(hControl, EM_SETSEL, 0, -1);
}
break;
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
case WM_COMMAND:
switch(HIWORD(wParam))
{
case BN_CLICKED:
switch(LOWORD(wParam))
{
case IDOK:
dwFlags = 0;
hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
dwFlags |= RSF_LOOKATKEYS;
hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
dwFlags |= RSF_LOOKATVALUES;
hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
dwFlags |= RSF_LOOKATDATA;
hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
dwFlags |= RSF_WHOLESTRING;
hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
dwFlags |= RSF_MATCHCASE;
SetFindFlags(dwFlags);
hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
if (hControl)
GetWindowTextW(hControl, s_szFindWhat, ARRAY_SIZE(s_szFindWhat));
EndDialog(hDlg, 1);
break;
case IDCANCEL:
EndDialog(hDlg, 0);
break;
}
break;
case EN_CHANGE:
switch(LOWORD(wParam))
{
case IDC_FINDWHAT:
GetWindowTextW((HWND) lParam, s_szSavedFindValue, ARRAY_SIZE(s_szSavedFindValue));
hControl = GetDlgItem(hDlg, IDOK);
if (hControl)
{
lStyle = GetWindowLongPtr(hControl, GWL_STYLE);
if (s_szSavedFindValue[0])
lStyle &= ~WS_DISABLED;
else
lStyle |= WS_DISABLED;
SetWindowLongPtr(hControl, GWL_STYLE, lStyle);
RedrawWindow(hControl, NULL, NULL, RDW_INVALIDATE);
}
break;
}
}
break;
}
return iResult;
}
void FindNextMessageBox(HWND hWnd)
{
if (!FindNext(hWnd))
{
WCHAR msg[128], caption[128];
LoadStringW(hInst, IDS_FINISHEDFIND, msg, ARRAY_SIZE(msg));
LoadStringW(hInst, IDS_APP_TITLE, caption, ARRAY_SIZE(caption));
MessageBoxW(hWnd, msg, caption, MB_ICONINFORMATION);
}
}
void FindDialog(HWND hWnd)
{
if (DialogBoxParamW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_FIND),
hWnd, FindDialogProc, 0) != 0)
{
FindNextMessageBox(hWnd);
}
}