xref: /reactos/base/applications/regedit/find.c (revision 8a978a17)
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_cbName;
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     if (pszValueName == NULL)
164         pszValueName = s_empty;
165 
166     lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
167                               &c, NULL, NULL, NULL, NULL);
168     if (lResult != ERROR_SUCCESS)
169         goto err;
170     ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
171     if (ppszNames == NULL)
172         goto err;
173     ZeroMemory(ppszNames, c * sizeof(LPWSTR));
174 
175     for(i = 0; i < c; i++)
176     {
177         if (DoEvents())
178             goto err;
179 
180         s_cbName = MAX_PATH * sizeof(WCHAR);
181         lResult = RegEnumValueW(hSubKey, i, s_szName, &s_cbName, NULL, NULL,
182                                NULL, &cb);
183         if (lResult == ERROR_NO_MORE_ITEMS)
184         {
185             c = i;
186             break;
187         }
188         if (lResult != ERROR_SUCCESS)
189             goto err;
190         if (s_cbName >= MAX_PATH * sizeof(WCHAR))
191             continue;
192 
193         ppszNames[i] = _wcsdup(s_szName);
194     }
195 
196     qsort(ppszNames, c, sizeof(LPWSTR), compare);
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_cbName = MAX_PATH * sizeof(WCHAR);
271         lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cbName, 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_cbName >= MAX_PATH * sizeof(WCHAR))
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     if (RegFindRecurse(hBaseKey, pszSubKey, pszValueName, ppszFoundSubKey,
374                        ppszFoundValueName))
375         return TRUE;
376 
377     if (wcslen(pszSubKey) >= MAX_PATH)
378         return FALSE;
379 
380     wcscpy(szSubKey, pszSubKey);
381     while(szSubKey[0] != 0)
382     {
383         if (DoEvents())
384             return FALSE;
385 
386         pch = wcsrchr(szSubKey, L'\\');
387         if (pch == NULL)
388         {
389             wcscpy(szKeyName, szSubKey);
390             szSubKey[0] = 0;
391             hSubKey = hBaseKey;
392         }
393         else
394         {
395             lstrcpynW(szKeyName, pch + 1, MAX_PATH);
396             *pch = 0;
397             lResult = RegOpenKeyExW(hBaseKey, szSubKey, 0, KEY_ALL_ACCESS,
398                                    &hSubKey);
399             if (lResult != ERROR_SUCCESS)
400                 return FALSE;
401         }
402 
403         lResult = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &c, NULL, NULL,
404                                   NULL, NULL, NULL, NULL, NULL);
405         if (lResult != ERROR_SUCCESS)
406             goto err;
407 
408         ppszNames = (LPWSTR *) malloc(c * sizeof(LPWSTR));
409         if (ppszNames == NULL)
410             goto err;
411         ZeroMemory(ppszNames, c * sizeof(LPWSTR));
412 
413         for(i = 0; i < c; i++)
414         {
415             if (DoEvents())
416                 goto err;
417 
418             s_cbName = MAX_PATH * sizeof(WCHAR);
419             lResult = RegEnumKeyExW(hSubKey, i, s_szName, &s_cbName,
420                                     NULL, NULL, NULL, NULL);
421             if (lResult == ERROR_NO_MORE_ITEMS)
422             {
423                 c = i;
424                 break;
425             }
426             if (lResult != ERROR_SUCCESS)
427                 break;
428             ppszNames[i] = _wcsdup(s_szName);
429         }
430 
431         qsort(ppszNames, c, sizeof(LPWSTR), compare);
432 
433         fPast = FALSE;
434         for(i = 0; i < c; i++)
435         {
436             if (DoEvents())
437                 goto err;
438 
439             if (!fPast && _wcsicmp(ppszNames[i], szKeyName) == 0)
440             {
441                 fPast = TRUE;
442                 continue;
443             }
444             if (!fPast)
445                 continue;
446 
447             if ((s_dwFlags & RSF_LOOKATKEYS) &&
448                     CompareName(ppszNames[i], s_szFindWhat))
449             {
450                 *ppszFoundSubKey = malloc(
451                                        (wcslen(szSubKey) + wcslen(ppszNames[i]) + 2) *
452                                        sizeof(WCHAR));
453                 if (*ppszFoundSubKey == NULL)
454                     goto err;
455                 if (szSubKey[0])
456                 {
457                     wcscpy(*ppszFoundSubKey, szSubKey);
458                     wcscat(*ppszFoundSubKey, s_backslash);
459                 }
460                 else
461                     **ppszFoundSubKey = 0;
462                 wcscat(*ppszFoundSubKey, ppszNames[i]);
463                 *ppszFoundValueName = NULL;
464                 goto success;
465             }
466 
467             if (RegFindRecurse(hSubKey, ppszNames[i], NULL,
468                                ppszFoundSubKey, ppszFoundValueName))
469             {
470                 LPWSTR psz = *ppszFoundSubKey;
471                 *ppszFoundSubKey = malloc(
472                                        (wcslen(szSubKey) + wcslen(psz) + 2) *
473                                        sizeof(WCHAR));
474                 if (*ppszFoundSubKey == NULL)
475                     goto err;
476                 if (szSubKey[0])
477                 {
478                     wcscpy(*ppszFoundSubKey, szSubKey);
479                     wcscat(*ppszFoundSubKey, s_backslash);
480                 }
481                 else
482                     **ppszFoundSubKey = 0;
483                 wcscat(*ppszFoundSubKey, psz);
484                 free(psz);
485                 goto success;
486             }
487         }
488         if (ppszNames != NULL)
489         {
490             for(i = 0; i < c; i++)
491                 free(ppszNames[i]);
492             free(ppszNames);
493         }
494         ppszNames = NULL;
495 
496         if (hBaseKey != hSubKey)
497             RegCloseKey(hSubKey);
498     }
499 
500     if (*phKey == HKEY_CLASSES_ROOT)
501     {
502         *phKey = HKEY_CURRENT_USER;
503         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
504                            ppszFoundValueName))
505             return TRUE;
506     }
507 
508     if (*phKey == HKEY_CURRENT_USER)
509     {
510         *phKey = HKEY_LOCAL_MACHINE;
511         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
512                            ppszFoundValueName))
513             goto success;
514     }
515 
516     if (*phKey == HKEY_LOCAL_MACHINE)
517     {
518         *phKey = HKEY_USERS;
519         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
520                            ppszFoundValueName))
521             goto success;
522     }
523 
524     if (*phKey == HKEY_USERS)
525     {
526         *phKey = HKEY_CURRENT_CONFIG;
527         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
528                            ppszFoundValueName))
529             goto success;
530     }
531 
532 err:
533     if (ppszNames != NULL)
534     {
535         for(i = 0; i < c; i++)
536             free(ppszNames[i]);
537         free(ppszNames);
538     }
539     if (hBaseKey != hSubKey)
540         RegCloseKey(hSubKey);
541     return FALSE;
542 
543 success:
544     if (ppszNames != NULL)
545     {
546         for(i = 0; i < c; i++)
547             free(ppszNames[i]);
548         free(ppszNames);
549     }
550     if (hBaseKey != hSubKey)
551         RegCloseKey(hSubKey);
552     return TRUE;
553 }
554 
555 
556 static DWORD GetFindFlags(void)
557 {
558     HKEY hKey;
559     DWORD dwType, dwValue, cbData;
560     DWORD dwFlags = RSF_LOOKATKEYS | RSF_LOOKATVALUES | RSF_LOOKATDATA;
561 
562     if (RegOpenKeyW(HKEY_CURRENT_USER, g_szGeneralRegKey, &hKey) == ERROR_SUCCESS)
563     {
564         /* Retrieve flags from registry key */
565         cbData = sizeof(dwValue);
566         if (RegQueryValueExW(hKey, s_szFindFlags, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
567         {
568             if (dwType == REG_DWORD)
569                 dwFlags = (dwFlags & ~0x0000FFFF) | ((dwValue & 0x0000FFFF) << 0);
570         }
571 
572         /* Retrieve ReactOS Regedit specific flags from registry key */
573         cbData = sizeof(dwValue);
574         if (RegQueryValueExW(hKey, s_szFindFlagsR, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
575         {
576             if (dwType == REG_DWORD)
577                 dwFlags = (dwFlags & ~0xFFFF0000) | ((dwValue & 0x0000FFFF) << 16);
578         }
579 
580         RegCloseKey(hKey);
581     }
582     return dwFlags;
583 }
584 
585 static void SetFindFlags(DWORD dwFlags)
586 {
587     HKEY hKey;
588     DWORD dwDisposition;
589     DWORD dwData;
590 
591     if (RegCreateKeyExW(HKEY_CURRENT_USER, g_szGeneralRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS)
592     {
593         dwData = (dwFlags >> 0) & 0x0000FFFF;
594         RegSetValueExW(hKey, s_szFindFlags, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
595 
596         dwData = (dwFlags >> 16) & 0x0000FFFF;
597         RegSetValueExW(hKey, s_szFindFlagsR, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
598 
599         RegCloseKey(hKey);
600     }
601 }
602 
603 static INT_PTR CALLBACK AbortFindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
604 {
605     UNREFERENCED_PARAMETER(lParam);
606     UNREFERENCED_PARAMETER(hDlg);
607 
608     switch(uMsg)
609     {
610     case WM_CLOSE:
611         s_bAbort = TRUE;
612         break;
613 
614     case WM_COMMAND:
615         switch(HIWORD(wParam))
616         {
617         case BN_CLICKED:
618             switch(LOWORD(wParam))
619             {
620             case IDCANCEL:
621                 s_bAbort = TRUE;
622                 break;
623             }
624             break;
625         }
626         break;
627     }
628     return 0;
629 }
630 
631 BOOL FindNext(HWND hWnd)
632 {
633     HKEY hKeyRoot;
634     LPCWSTR pszKeyPath;
635     BOOL fSuccess;
636     WCHAR szFullKey[512];
637     LPCWSTR pszValueName;
638     LPWSTR pszFoundSubKey, pszFoundValueName;
639 
640     if (wcslen(s_szFindWhat) == 0)
641     {
642         FindDialog(hWnd);
643         return TRUE;
644     }
645 
646     s_dwFlags = GetFindFlags();
647 
648     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
649     if (pszKeyPath == NULL)
650     {
651         hKeyRoot = HKEY_CLASSES_ROOT;
652         pszKeyPath = s_empty;
653     }
654 
655     /* Create abort find dialog */
656     s_hwndAbortDialog = CreateDialogW(GetModuleHandle(NULL),
657                                      MAKEINTRESOURCEW(IDD_FINDING), hWnd, AbortFindDialogProc);
658     if (s_hwndAbortDialog)
659     {
660         ShowWindow(s_hwndAbortDialog, SW_SHOW);
661         UpdateWindow(s_hwndAbortDialog);
662     }
663     s_bAbort = FALSE;
664 
665     pszValueName = GetValueName(g_pChildWnd->hListWnd, -1);
666 
667     EnableWindow(hFrameWnd, FALSE);
668     EnableWindow(g_pChildWnd->hTreeWnd, FALSE);
669     EnableWindow(g_pChildWnd->hListWnd, FALSE);
670     EnableWindow(g_pChildWnd->hAddressBarWnd, FALSE);
671 
672     fSuccess = RegFindWalk(&hKeyRoot, pszKeyPath, pszValueName,
673                            &pszFoundSubKey, &pszFoundValueName);
674 
675     EnableWindow(hFrameWnd, TRUE);
676     EnableWindow(g_pChildWnd->hTreeWnd, TRUE);
677     EnableWindow(g_pChildWnd->hListWnd, TRUE);
678     EnableWindow(g_pChildWnd->hAddressBarWnd, TRUE);
679 
680     if (s_hwndAbortDialog)
681     {
682         DestroyWindow(s_hwndAbortDialog);
683         s_hwndAbortDialog = NULL;
684     }
685 
686     if (fSuccess)
687     {
688         GetKeyName(szFullKey, COUNT_OF(szFullKey), hKeyRoot, pszFoundSubKey);
689         SelectNode(g_pChildWnd->hTreeWnd, szFullKey);
690         SetValueName(g_pChildWnd->hListWnd, pszFoundValueName);
691         free(pszFoundSubKey);
692         free(pszFoundValueName);
693         SetFocus(g_pChildWnd->hListWnd);
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, COUNT_OF(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, COUNT_OF(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 FindDialog(HWND hWnd)
814 {
815     if (DialogBoxParamW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_FIND),
816                        hWnd, FindDialogProc, 0) != 0)
817     {
818         if (!FindNext(hWnd))
819         {
820             WCHAR msg[128], caption[128];
821 
822             LoadStringW(hInst, IDS_FINISHEDFIND, msg, COUNT_OF(msg));
823             LoadStringW(hInst, IDS_APP_TITLE, caption, COUNT_OF(caption));
824             MessageBoxW(0, msg, caption, MB_ICONINFORMATION);
825         }
826     }
827 }
828