xref: /reactos/base/applications/regedit/find.c (revision 84344399)
1 /*
2  * Regedit find dialog
3  *
4  * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
5  */
6 
7 #include "regedit.h"
8 
9 #define RSF_WHOLESTRING    0x00000001
10 #define RSF_LOOKATKEYS     0x00000002
11 #define RSF_LOOKATVALUES   0x00000004
12 #define RSF_LOOKATDATA     0x00000008
13 #define RSF_MATCHCASE      0x00010000
14 
15 static WCHAR s_szFindWhat[256];
16 static const WCHAR s_szFindFlags[] = L"FindFlags";
17 static const WCHAR s_szFindFlagsR[] = L"FindFlagsReactOS";
18 static HWND s_hwndAbortDialog;
19 static BOOL s_bAbort;
20 
21 static DWORD s_dwFlags;
22 static WCHAR s_szName[MAX_PATH];
23 static DWORD s_cchName;
24 static const WCHAR s_empty[] = L"";
25 static const WCHAR s_backslash[] = L"\\";
26 
27 extern VOID SetValueName(HWND hwndLV, LPCWSTR pszValueName);
28 
29 BOOL DoEvents(VOID)
30 {
31     MSG msg;
32     if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
33     {
34         if (msg.message == WM_QUIT)
35             s_bAbort = TRUE;
36         if (!IsDialogMessageW(s_hwndAbortDialog, &msg))
37         {
38             TranslateMessage(&msg);
39             DispatchMessageW(&msg);
40         }
41     }
42     return s_bAbort;
43 }
44 
45 static LPWSTR lstrstri(LPCWSTR psz1, LPCWSTR psz2)
46 {
47     INT i, cch1, cch2;
48 
49     cch1 = wcslen(psz1);
50     cch2 = wcslen(psz2);
51     for(i = 0; i <= cch1 - cch2; i++)
52     {
53         if (CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
54                            psz1 + i, cch2, psz2, cch2) == 2)
55             return (LPWSTR) (psz1 + i);
56     }
57     return NULL;
58 }
59 
60 static BOOL CompareName(LPCWSTR pszName1, LPCWSTR pszName2)
61 {
62     if (s_dwFlags & RSF_WHOLESTRING)
63     {
64         if (s_dwFlags & RSF_MATCHCASE)
65             return wcscmp(pszName1, pszName2) == 0;
66         else
67             return _wcsicmp(pszName1, pszName2) == 0;
68     }
69     else
70     {
71         if (s_dwFlags & RSF_MATCHCASE)
72             return wcsstr(pszName1, pszName2) != NULL;
73         else
74             return lstrstri(pszName1, pszName2) != NULL;
75     }
76 }
77 
78 /* Do not assume that pch1 is terminated with UNICODE_NULL */
79 static BOOL MatchString(LPCWCH pch1, INT cch1, LPCWCH pch2, INT cch2)
80 {
81     INT i;
82     DWORD dwNorm = ((s_dwFlags & RSF_MATCHCASE) ? 0 : NORM_IGNORECASE);
83 
84     if (s_dwFlags & RSF_WHOLESTRING)
85         return 2 == CompareStringW(LOCALE_SYSTEM_DEFAULT, dwNorm, pch1, cch1, pch2, cch2);
86 
87     if (cch1 < cch2)
88         return FALSE;
89 
90     for (i = 0; i <= cch1 - cch2; i++)
91     {
92         if (2 == CompareStringW(LOCALE_SYSTEM_DEFAULT, dwNorm, pch1 + i, cch2, pch2, cch2))
93             return TRUE;
94     }
95 
96     return FALSE;
97 }
98 
99 static BOOL MatchData(DWORD dwType, LPCVOID pv1, DWORD cb1)
100 {
101     if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
102         return MatchString(pv1, (INT)(cb1 / sizeof(WCHAR)), s_szFindWhat, lstrlenW(s_szFindWhat));
103 
104     return FALSE;
105 }
106 
107 int compare(const void *x, const void *y)
108 {
109     const LPCWSTR *a = (const LPCWSTR *)x;
110     const LPCWSTR *b = (const LPCWSTR *)y;
111     return _wcsicmp(*a, *b);
112 }
113 
114 BOOL RegFindRecurse(
115     HKEY    hKey,
116     LPCWSTR pszSubKey,
117     LPCWSTR pszValueName,
118     LPWSTR *ppszFoundSubKey,
119     LPWSTR *ppszFoundValueName)
120 {
121     HKEY hSubKey;
122     LONG lResult;
123     WCHAR szSubKey[MAX_PATH];
124     DWORD i, c, cb, type;
125     BOOL fPast;
126     LPWSTR *ppszNames = NULL;
127     LPBYTE pb = NULL;
128 
129     if (DoEvents())
130         return FALSE;
131 
132     if(wcslen(pszSubKey) >= _countof(szSubKey))
133         return FALSE;
134 
135     StringCbCopyW(szSubKey, sizeof(szSubKey), pszSubKey);
136     hSubKey = NULL;
137 
138     lResult = RegOpenKeyExW(hKey, szSubKey, 0, KEY_ALL_ACCESS, &hSubKey);
139     if (lResult != ERROR_SUCCESS)
140         return FALSE;
141 
142     lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
143                               &c, NULL, NULL, NULL, NULL);
144     if (lResult != ERROR_SUCCESS)
145         goto err;
146     ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
147     if (ppszNames == NULL)
148         goto err;
149     ZeroMemory(ppszNames, c * sizeof(LPWSTR));
150 
151     /* Retrieve the value names associated with the current key */
152     for(i = 0; i < c; i++)
153     {
154         if (DoEvents())
155             goto err;
156 
157         s_cchName = _countof(s_szName);
158         lResult = RegEnumValueW(hSubKey, i, s_szName, &s_cchName, NULL, NULL,
159                                NULL, &cb);
160         if (lResult == ERROR_NO_MORE_ITEMS)
161         {
162             c = i;
163             break;
164         }
165         if (lResult != ERROR_SUCCESS)
166             goto err;
167         if (s_cchName >= _countof(s_szName))
168             continue;
169 
170         ppszNames[i] = _wcsdup(s_szName);
171     }
172 
173     qsort(ppszNames, c, sizeof(LPWSTR), compare);
174 
175     /* If pszValueName is NULL, the function will search for all values within the key */
176     fPast = (pszValueName == NULL);
177 
178     /* Search within the values */
179     for (i = 0; i < c; i++)
180     {
181         if (DoEvents())
182             goto err;
183 
184         if (!fPast && _wcsicmp(ppszNames[i], pszValueName) == 0)
185         {
186             fPast = TRUE;
187             continue;
188         }
189         if (!fPast)
190             continue;
191 
192         if ((s_dwFlags & RSF_LOOKATVALUES) &&
193                 CompareName(ppszNames[i], s_szFindWhat))
194         {
195             *ppszFoundSubKey = _wcsdup(szSubKey);
196             *ppszFoundValueName = _wcsdup(ppszNames[i]);
197             goto success;
198         }
199 
200         lResult = RegQueryValueExW(hSubKey, ppszNames[i], NULL, &type,
201                                   NULL, &cb);
202         if (lResult != ERROR_SUCCESS)
203             goto err;
204         pb = malloc(cb);
205         if (pb == NULL)
206             goto err;
207         lResult = RegQueryValueExW(hSubKey, ppszNames[i], NULL, &type,
208                                   pb, &cb);
209         if (lResult != ERROR_SUCCESS)
210             goto err;
211 
212         if ((s_dwFlags & RSF_LOOKATDATA) && MatchData(type, pb, cb))
213         {
214             *ppszFoundSubKey = _wcsdup(szSubKey);
215             *ppszFoundValueName = _wcsdup(ppszNames[i]);
216             goto success;
217         }
218         free(pb);
219         pb = NULL;
220     }
221 
222     if (ppszNames != NULL)
223     {
224         for(i = 0; i < c; i++)
225             free(ppszNames[i]);
226         free(ppszNames);
227     }
228     ppszNames = NULL;
229 
230     /* Retrieve the number of sub-keys */
231     lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &c, NULL, NULL,
232                               NULL, NULL, NULL, NULL, NULL);
233     if (lResult != ERROR_SUCCESS)
234         goto err;
235     ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
236     if (ppszNames == NULL)
237         goto err;
238     ZeroMemory(ppszNames, c * sizeof(LPWSTR));
239 
240     /* Retrieve the names of the sub-keys */
241     for(i = 0; i < c; i++)
242     {
243         if (DoEvents())
244             goto err;
245 
246         s_cchName = _countof(s_szName);
247         lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cchName, NULL, NULL,
248                                NULL, NULL);
249         if (lResult == ERROR_NO_MORE_ITEMS)
250         {
251             c = i;
252             break;
253         }
254         if (lResult != ERROR_SUCCESS)
255             goto err;
256         if (s_cchName >= _countof(s_szName))
257             continue;
258 
259         ppszNames[i] = _wcsdup(s_szName);
260     }
261 
262     qsort(ppszNames, c, sizeof(LPWSTR), compare);
263 
264     /* Search within the sub-keys */
265     for(i = 0; i < c; i++)
266     {
267         if (DoEvents())
268             goto err;
269 
270         if ((s_dwFlags & RSF_LOOKATKEYS) &&
271                 CompareName(ppszNames[i], s_szFindWhat))
272         {
273             *ppszFoundSubKey = malloc(
274                                    (wcslen(szSubKey) + wcslen(ppszNames[i]) + 2) *
275                                    sizeof(WCHAR));
276             if (*ppszFoundSubKey == NULL)
277                 goto err;
278             if (szSubKey[0])
279             {
280                 wcscpy(*ppszFoundSubKey, szSubKey);
281                 wcscat(*ppszFoundSubKey, s_backslash);
282             }
283             else
284                 **ppszFoundSubKey = 0;
285             wcscat(*ppszFoundSubKey, ppszNames[i]);
286             *ppszFoundValueName = NULL;
287             goto success;
288         }
289 
290         /* Search within the value entries of the sub-key */
291         if (RegFindRecurse(hSubKey, ppszNames[i], NULL, ppszFoundSubKey,
292                            ppszFoundValueName))
293         {
294             LPWSTR psz = *ppszFoundSubKey;
295             SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
296             *ppszFoundSubKey = malloc(cbFoundSubKey);
297             if (*ppszFoundSubKey == NULL)
298                 goto err;
299             if (szSubKey[0])
300             {
301                 StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
302                 StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, s_backslash);
303             }
304             else
305                 **ppszFoundSubKey = 0;
306             wcscat(*ppszFoundSubKey, psz);
307             free(psz);
308             goto success;
309         }
310     }
311 
312 err:
313     if (ppszNames != NULL)
314     {
315         for(i = 0; i < c; i++)
316             free(ppszNames[i]);
317         free(ppszNames);
318     }
319     free(pb);
320     RegCloseKey(hSubKey);
321     return FALSE;
322 
323 success:
324     if (ppszNames != NULL)
325     {
326         for(i = 0; i < c; i++)
327             free(ppszNames[i]);
328         free(ppszNames);
329     }
330     RegCloseKey(hSubKey);
331     return TRUE;
332 }
333 
334 BOOL RegFindWalk(
335     HKEY *  phKey,
336     LPCWSTR pszSubKey,
337     LPCWSTR pszValueName,
338     LPWSTR *ppszFoundSubKey,
339     LPWSTR *ppszFoundValueName)
340 {
341     LONG lResult;
342     DWORD i, c;
343     HKEY hBaseKey, hSubKey;
344     WCHAR szKeyName[MAX_PATH];
345     WCHAR szSubKey[MAX_PATH];
346     LPWSTR pch;
347     BOOL fPast, fKeyMatched;
348     LPWSTR *ppszNames = NULL;
349 
350     hBaseKey = *phKey;
351 
352     if (wcslen(pszSubKey) >= _countof(szSubKey))
353         return FALSE;
354 
355     if (RegFindRecurse(hBaseKey, pszSubKey, pszValueName, ppszFoundSubKey,
356                        ppszFoundValueName))
357         return TRUE;
358 
359     StringCbCopyW(szSubKey, sizeof(szSubKey), pszSubKey);
360     while(szSubKey[0] != 0)
361     {
362         if (DoEvents())
363             return FALSE;
364 
365         pch = wcsrchr(szSubKey, L'\\');
366         if (pch == NULL)
367         {
368             wcscpy(szKeyName, szSubKey);
369             szSubKey[0] = 0;
370             hSubKey = hBaseKey;
371         }
372         else
373         {
374             lstrcpynW(szKeyName, pch + 1, MAX_PATH);
375             *pch = 0;
376             lResult = RegOpenKeyExW(hBaseKey, szSubKey, 0, KEY_ALL_ACCESS,
377                                    &hSubKey);
378             if (lResult != ERROR_SUCCESS)
379                 return FALSE;
380         }
381 
382         lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &c, NULL, NULL,
383                                   NULL, NULL, NULL, NULL, NULL);
384         if (lResult != ERROR_SUCCESS)
385             goto err;
386 
387         ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
388         if (ppszNames == NULL)
389             goto err;
390         ZeroMemory(ppszNames, c * sizeof(LPWSTR));
391 
392         for(i = 0; i < c; i++)
393         {
394             if (DoEvents())
395                 goto err;
396 
397             s_cchName = _countof(s_szName);
398             lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cchName,
399                                     NULL, NULL, NULL, NULL);
400             if (lResult == ERROR_NO_MORE_ITEMS)
401             {
402                 c = i;
403                 break;
404             }
405             if (lResult != ERROR_SUCCESS)
406                 break;
407             ppszNames[i] = _wcsdup(s_szName);
408         }
409 
410         qsort(ppszNames, c, sizeof(LPWSTR), compare);
411 
412         fPast = FALSE;
413         for(i = 0; i < c; i++)
414         {
415             if (DoEvents())
416                 goto err;
417 
418             if (!fPast && _wcsicmp(ppszNames[i], szKeyName) == 0)
419             {
420                 fPast = TRUE;
421                 continue;
422             }
423             if (!fPast)
424                 continue;
425 
426             if ((s_dwFlags & RSF_LOOKATKEYS) &&
427                     CompareName(ppszNames[i], s_szFindWhat))
428             {
429                 *ppszFoundSubKey = malloc(
430                                        (wcslen(szSubKey) + wcslen(ppszNames[i]) + 2) *
431                                        sizeof(WCHAR));
432                 if (*ppszFoundSubKey == NULL)
433                     goto err;
434                 if (szSubKey[0])
435                 {
436                     wcscpy(*ppszFoundSubKey, szSubKey);
437                     wcscat(*ppszFoundSubKey, s_backslash);
438                 }
439                 else
440                     **ppszFoundSubKey = 0;
441                 wcscat(*ppszFoundSubKey, ppszNames[i]);
442                 *ppszFoundValueName = NULL;
443                 goto success;
444             }
445 
446             fKeyMatched = (_wcsicmp(ppszNames[i], szKeyName) == 0);
447             if (RegFindRecurse(hSubKey, ppszNames[i], (fKeyMatched ? pszValueName : NULL),
448                                ppszFoundSubKey, ppszFoundValueName))
449             {
450                 LPWSTR psz = *ppszFoundSubKey;
451                 SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
452                 *ppszFoundSubKey = malloc(cbFoundSubKey);
453                 if (*ppszFoundSubKey == NULL)
454                     goto err;
455                 if (szSubKey[0])
456                 {
457                     StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
458                     StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, s_backslash);
459                 }
460                 else
461                     **ppszFoundSubKey = 0;
462                 wcscat(*ppszFoundSubKey, psz);
463                 free(psz);
464                 goto success;
465             }
466         }
467         if (ppszNames != NULL)
468         {
469             for(i = 0; i < c; i++)
470                 free(ppszNames[i]);
471             free(ppszNames);
472         }
473         ppszNames = NULL;
474 
475         if (hBaseKey != hSubKey)
476             RegCloseKey(hSubKey);
477     }
478 
479     if (*phKey == HKEY_CLASSES_ROOT)
480     {
481         *phKey = HKEY_CURRENT_USER;
482         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
483                            ppszFoundValueName))
484             return TRUE;
485     }
486 
487     if (*phKey == HKEY_CURRENT_USER)
488     {
489         *phKey = HKEY_LOCAL_MACHINE;
490         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
491                            ppszFoundValueName))
492             goto success;
493     }
494 
495     if (*phKey == HKEY_LOCAL_MACHINE)
496     {
497         *phKey = HKEY_USERS;
498         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
499                            ppszFoundValueName))
500             goto success;
501     }
502 
503     if (*phKey == HKEY_USERS)
504     {
505         *phKey = HKEY_CURRENT_CONFIG;
506         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
507                            ppszFoundValueName))
508             goto success;
509     }
510 
511 err:
512     if (ppszNames != NULL)
513     {
514         for(i = 0; i < c; i++)
515             free(ppszNames[i]);
516         free(ppszNames);
517     }
518     if (hBaseKey != hSubKey)
519         RegCloseKey(hSubKey);
520     return FALSE;
521 
522 success:
523     if (ppszNames != NULL)
524     {
525         for(i = 0; i < c; i++)
526             free(ppszNames[i]);
527         free(ppszNames);
528     }
529     if (hBaseKey != hSubKey)
530         RegCloseKey(hSubKey);
531     return TRUE;
532 }
533 
534 static DWORD GetFindFlags(void)
535 {
536     HKEY hKey;
537     DWORD dwType, dwValue, cbData;
538     DWORD dwFlags = RSF_LOOKATKEYS | RSF_LOOKATVALUES | RSF_LOOKATDATA;
539 
540     if (RegOpenKeyW(HKEY_CURRENT_USER, g_szGeneralRegKey, &hKey) == ERROR_SUCCESS)
541     {
542         /* Retrieve flags from registry key */
543         cbData = sizeof(dwValue);
544         if (RegQueryValueExW(hKey, s_szFindFlags, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
545         {
546             if (dwType == REG_DWORD)
547                 dwFlags = (dwFlags & ~0x0000FFFF) | ((dwValue & 0x0000FFFF) << 0);
548         }
549 
550         /* Retrieve ReactOS Regedit specific flags from registry key */
551         cbData = sizeof(dwValue);
552         if (RegQueryValueExW(hKey, s_szFindFlagsR, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
553         {
554             if (dwType == REG_DWORD)
555                 dwFlags = (dwFlags & ~0xFFFF0000) | ((dwValue & 0x0000FFFF) << 16);
556         }
557 
558         RegCloseKey(hKey);
559     }
560     return dwFlags;
561 }
562 
563 static void SetFindFlags(DWORD dwFlags)
564 {
565     HKEY hKey;
566     DWORD dwDisposition;
567     DWORD dwData;
568 
569     if (RegCreateKeyExW(HKEY_CURRENT_USER, g_szGeneralRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS)
570     {
571         dwData = (dwFlags >> 0) & 0x0000FFFF;
572         RegSetValueExW(hKey, s_szFindFlags, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
573 
574         dwData = (dwFlags >> 16) & 0x0000FFFF;
575         RegSetValueExW(hKey, s_szFindFlagsR, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
576 
577         RegCloseKey(hKey);
578     }
579 }
580 
581 static INT_PTR CALLBACK AbortFindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
582 {
583     UNREFERENCED_PARAMETER(lParam);
584     UNREFERENCED_PARAMETER(hDlg);
585 
586     switch(uMsg)
587     {
588     case WM_CLOSE:
589         s_bAbort = TRUE;
590         break;
591 
592     case WM_COMMAND:
593         switch(HIWORD(wParam))
594         {
595         case BN_CLICKED:
596             switch(LOWORD(wParam))
597             {
598             case IDCANCEL:
599                 s_bAbort = TRUE;
600                 break;
601             }
602             break;
603         }
604         break;
605     }
606     return 0;
607 }
608 
609 BOOL FindNext(HWND hWnd)
610 {
611     HKEY hKeyRoot;
612     LPCWSTR pszKeyPath;
613     BOOL fSuccess;
614     WCHAR szFullKey[512];
615     LPCWSTR pszValueName;
616     LPWSTR pszFoundSubKey, pszFoundValueName;
617 
618     if (wcslen(s_szFindWhat) == 0)
619     {
620         FindDialog(hWnd);
621         return TRUE;
622     }
623 
624     s_dwFlags = GetFindFlags();
625 
626     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
627     if (pszKeyPath == NULL)
628     {
629         hKeyRoot = HKEY_CLASSES_ROOT;
630         pszKeyPath = s_empty;
631     }
632 
633     /* Create abort find dialog */
634     s_hwndAbortDialog = CreateDialogW(GetModuleHandle(NULL),
635                                      MAKEINTRESOURCEW(IDD_FINDING), hWnd, AbortFindDialogProc);
636     if (s_hwndAbortDialog)
637     {
638         ShowWindow(s_hwndAbortDialog, SW_SHOW);
639         UpdateWindow(s_hwndAbortDialog);
640     }
641     s_bAbort = FALSE;
642 
643     pszValueName = GetValueName(g_pChildWnd->hListWnd, -1);
644 
645     EnableWindow(hFrameWnd, FALSE);
646     EnableWindow(g_pChildWnd->hTreeWnd, FALSE);
647     EnableWindow(g_pChildWnd->hListWnd, FALSE);
648     EnableWindow(g_pChildWnd->hAddressBarWnd, FALSE);
649 
650     fSuccess = RegFindWalk(&hKeyRoot, pszKeyPath, pszValueName,
651                            &pszFoundSubKey, &pszFoundValueName);
652 
653     EnableWindow(hFrameWnd, TRUE);
654     EnableWindow(g_pChildWnd->hTreeWnd, TRUE);
655     EnableWindow(g_pChildWnd->hListWnd, TRUE);
656     EnableWindow(g_pChildWnd->hAddressBarWnd, TRUE);
657 
658     if (s_hwndAbortDialog)
659     {
660         DestroyWindow(s_hwndAbortDialog);
661         s_hwndAbortDialog = NULL;
662     }
663 
664     if (fSuccess)
665     {
666         GetKeyName(szFullKey, ARRAY_SIZE(szFullKey), hKeyRoot, pszFoundSubKey);
667         SelectNode(g_pChildWnd->hTreeWnd, szFullKey);
668         free(pszFoundSubKey);
669 
670         if (pszFoundValueName != NULL)
671         {
672             SetValueName(g_pChildWnd->hListWnd, pszFoundValueName);
673             free(pszFoundValueName);
674             SetFocus(g_pChildWnd->hListWnd);
675         }
676         else
677         {
678             SetFocus(g_pChildWnd->hTreeWnd);
679         }
680     }
681     return fSuccess || s_bAbort;
682 }
683 
684 static INT_PTR CALLBACK FindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
685 {
686     INT_PTR iResult = 0;
687     HWND hControl;
688     LONG lStyle;
689     DWORD dwFlags;
690     static WCHAR s_szSavedFindValue[256];
691 
692     switch(uMsg)
693     {
694     case WM_INITDIALOG:
695         dwFlags = GetFindFlags();
696 
697         hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
698         if (hControl)
699             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATKEYS) ? TRUE : FALSE, 0);
700 
701         hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
702         if (hControl)
703             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATVALUES) ? TRUE : FALSE, 0);
704 
705         hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
706         if (hControl)
707             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATDATA) ? TRUE : FALSE, 0);
708 
709         /* Match whole string */
710         hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
711         if (hControl)
712             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_WHOLESTRING) ? TRUE : FALSE, 0);
713 
714         /* Case sensitivity */
715         hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
716         if (hControl)
717             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_MATCHCASE) ? TRUE : FALSE, 0);
718 
719         hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
720         if (hControl)
721         {
722             SetWindowTextW(hControl, s_szSavedFindValue);
723             SetFocus(hControl);
724             SendMessageW(hControl, EM_SETSEL, 0, -1);
725         }
726         break;
727 
728     case WM_CLOSE:
729         EndDialog(hDlg, 0);
730         break;
731 
732     case WM_COMMAND:
733         switch(HIWORD(wParam))
734         {
735         case BN_CLICKED:
736             switch(LOWORD(wParam))
737             {
738             case IDOK:
739                 dwFlags = 0;
740 
741                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
742                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
743                     dwFlags |= RSF_LOOKATKEYS;
744 
745                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
746                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
747                     dwFlags |= RSF_LOOKATVALUES;
748 
749                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
750                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
751                     dwFlags |= RSF_LOOKATDATA;
752 
753                 hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
754                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
755                     dwFlags |= RSF_WHOLESTRING;
756 
757                 hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
758                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
759                     dwFlags |= RSF_MATCHCASE;
760 
761                 SetFindFlags(dwFlags);
762 
763                 hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
764                 if (hControl)
765                     GetWindowTextW(hControl, s_szFindWhat, ARRAY_SIZE(s_szFindWhat));
766                 EndDialog(hDlg, 1);
767                 break;
768 
769             case IDCANCEL:
770                 EndDialog(hDlg, 0);
771                 break;
772             }
773             break;
774 
775         case EN_CHANGE:
776             switch(LOWORD(wParam))
777             {
778             case IDC_FINDWHAT:
779                 GetWindowTextW((HWND) lParam, s_szSavedFindValue, ARRAY_SIZE(s_szSavedFindValue));
780                 hControl = GetDlgItem(hDlg, IDOK);
781                 if (hControl)
782                 {
783                     lStyle = GetWindowLongPtr(hControl, GWL_STYLE);
784                     if (s_szSavedFindValue[0])
785                         lStyle &= ~WS_DISABLED;
786                     else
787                         lStyle |= WS_DISABLED;
788                     SetWindowLongPtr(hControl, GWL_STYLE, lStyle);
789                     RedrawWindow(hControl, NULL, NULL, RDW_INVALIDATE);
790                 }
791                 break;
792             }
793         }
794         break;
795     }
796     return iResult;
797 }
798 
799 void FindNextMessageBox(HWND hWnd)
800 {
801     if (!FindNext(hWnd))
802     {
803         WCHAR msg[128], caption[128];
804 
805         LoadStringW(hInst, IDS_FINISHEDFIND, msg, ARRAY_SIZE(msg));
806         LoadStringW(hInst, IDS_APP_TITLE, caption, ARRAY_SIZE(caption));
807         MessageBoxW(hWnd, msg, caption, MB_ICONINFORMATION);
808     }
809 }
810 
811 void FindDialog(HWND hWnd)
812 {
813     if (DialogBoxParamW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_FIND),
814                        hWnd, FindDialogProc, 0) != 0)
815     {
816         FindNextMessageBox(hWnd);
817     }
818 }
819