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