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