reactos/base/applications/regedit/find.c

832 lines
24 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) ? 0 : NORM_IGNORECASE);
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;
StringCbCopyW(szSubKey, sizeof(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;
SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
*ppszFoundSubKey = malloc(cbFoundSubKey);
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, 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;
StringCbCopyW(szSubKey, sizeof(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;
SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
*ppszFoundSubKey = malloc(cbFoundSubKey);
if (*ppszFoundSubKey == NULL)
goto err;
if (szSubKey[0])
{
StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, 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);
}
}