xref: /reactos/base/applications/regedit/find.c (revision b3194e32)
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     StringCbCopyW(szSubKey, sizeof(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             SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
308             *ppszFoundSubKey = malloc(cbFoundSubKey);
309             if (*ppszFoundSubKey == NULL)
310                 goto err;
311             if (szSubKey[0])
312             {
313                 StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
314                 StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, 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     StringCbCopyW(szSubKey, sizeof(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                 SIZE_T cbFoundSubKey = (wcslen(szSubKey) + wcslen(psz) + 2) * sizeof(WCHAR);
464                 *ppszFoundSubKey = malloc(cbFoundSubKey);
465                 if (*ppszFoundSubKey == NULL)
466                     goto err;
467                 if (szSubKey[0])
468                 {
469                     StringCbCopyW(*ppszFoundSubKey, cbFoundSubKey, szSubKey);
470                     StringCbCatW(*ppszFoundSubKey, cbFoundSubKey, s_backslash);
471                 }
472                 else
473                     **ppszFoundSubKey = 0;
474                 wcscat(*ppszFoundSubKey, psz);
475                 free(psz);
476                 goto success;
477             }
478         }
479         if (ppszNames != NULL)
480         {
481             for(i = 0; i < c; i++)
482                 free(ppszNames[i]);
483             free(ppszNames);
484         }
485         ppszNames = NULL;
486 
487         if (hBaseKey != hSubKey)
488             RegCloseKey(hSubKey);
489     }
490 
491     if (*phKey == HKEY_CLASSES_ROOT)
492     {
493         *phKey = HKEY_CURRENT_USER;
494         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
495                            ppszFoundValueName))
496             return TRUE;
497     }
498 
499     if (*phKey == HKEY_CURRENT_USER)
500     {
501         *phKey = HKEY_LOCAL_MACHINE;
502         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
503                            ppszFoundValueName))
504             goto success;
505     }
506 
507     if (*phKey == HKEY_LOCAL_MACHINE)
508     {
509         *phKey = HKEY_USERS;
510         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
511                            ppszFoundValueName))
512             goto success;
513     }
514 
515     if (*phKey == HKEY_USERS)
516     {
517         *phKey = HKEY_CURRENT_CONFIG;
518         if (RegFindRecurse(*phKey, s_empty, NULL, ppszFoundSubKey,
519                            ppszFoundValueName))
520             goto success;
521     }
522 
523 err:
524     if (ppszNames != NULL)
525     {
526         for(i = 0; i < c; i++)
527             free(ppszNames[i]);
528         free(ppszNames);
529     }
530     if (hBaseKey != hSubKey)
531         RegCloseKey(hSubKey);
532     return FALSE;
533 
534 success:
535     if (ppszNames != NULL)
536     {
537         for(i = 0; i < c; i++)
538             free(ppszNames[i]);
539         free(ppszNames);
540     }
541     if (hBaseKey != hSubKey)
542         RegCloseKey(hSubKey);
543     return TRUE;
544 }
545 
546 
547 static DWORD GetFindFlags(void)
548 {
549     HKEY hKey;
550     DWORD dwType, dwValue, cbData;
551     DWORD dwFlags = RSF_LOOKATKEYS | RSF_LOOKATVALUES | RSF_LOOKATDATA;
552 
553     if (RegOpenKeyW(HKEY_CURRENT_USER, g_szGeneralRegKey, &hKey) == ERROR_SUCCESS)
554     {
555         /* Retrieve flags from registry key */
556         cbData = sizeof(dwValue);
557         if (RegQueryValueExW(hKey, s_szFindFlags, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
558         {
559             if (dwType == REG_DWORD)
560                 dwFlags = (dwFlags & ~0x0000FFFF) | ((dwValue & 0x0000FFFF) << 0);
561         }
562 
563         /* Retrieve ReactOS Regedit specific flags from registry key */
564         cbData = sizeof(dwValue);
565         if (RegQueryValueExW(hKey, s_szFindFlagsR, NULL, &dwType, (LPBYTE) &dwValue, &cbData) == ERROR_SUCCESS)
566         {
567             if (dwType == REG_DWORD)
568                 dwFlags = (dwFlags & ~0xFFFF0000) | ((dwValue & 0x0000FFFF) << 16);
569         }
570 
571         RegCloseKey(hKey);
572     }
573     return dwFlags;
574 }
575 
576 static void SetFindFlags(DWORD dwFlags)
577 {
578     HKEY hKey;
579     DWORD dwDisposition;
580     DWORD dwData;
581 
582     if (RegCreateKeyExW(HKEY_CURRENT_USER, g_szGeneralRegKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS)
583     {
584         dwData = (dwFlags >> 0) & 0x0000FFFF;
585         RegSetValueExW(hKey, s_szFindFlags, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
586 
587         dwData = (dwFlags >> 16) & 0x0000FFFF;
588         RegSetValueExW(hKey, s_szFindFlagsR, 0, REG_DWORD, (const BYTE *) &dwData, sizeof(dwData));
589 
590         RegCloseKey(hKey);
591     }
592 }
593 
594 static INT_PTR CALLBACK AbortFindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
595 {
596     UNREFERENCED_PARAMETER(lParam);
597     UNREFERENCED_PARAMETER(hDlg);
598 
599     switch(uMsg)
600     {
601     case WM_CLOSE:
602         s_bAbort = TRUE;
603         break;
604 
605     case WM_COMMAND:
606         switch(HIWORD(wParam))
607         {
608         case BN_CLICKED:
609             switch(LOWORD(wParam))
610             {
611             case IDCANCEL:
612                 s_bAbort = TRUE;
613                 break;
614             }
615             break;
616         }
617         break;
618     }
619     return 0;
620 }
621 
622 BOOL FindNext(HWND hWnd)
623 {
624     HKEY hKeyRoot;
625     LPCWSTR pszKeyPath;
626     BOOL fSuccess;
627     WCHAR szFullKey[512];
628     LPCWSTR pszValueName;
629     LPWSTR pszFoundSubKey, pszFoundValueName;
630 
631     if (wcslen(s_szFindWhat) == 0)
632     {
633         FindDialog(hWnd);
634         return TRUE;
635     }
636 
637     s_dwFlags = GetFindFlags();
638 
639     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
640     if (pszKeyPath == NULL)
641     {
642         hKeyRoot = HKEY_CLASSES_ROOT;
643         pszKeyPath = s_empty;
644     }
645 
646     /* Create abort find dialog */
647     s_hwndAbortDialog = CreateDialogW(GetModuleHandle(NULL),
648                                      MAKEINTRESOURCEW(IDD_FINDING), hWnd, AbortFindDialogProc);
649     if (s_hwndAbortDialog)
650     {
651         ShowWindow(s_hwndAbortDialog, SW_SHOW);
652         UpdateWindow(s_hwndAbortDialog);
653     }
654     s_bAbort = FALSE;
655 
656     pszValueName = GetValueName(g_pChildWnd->hListWnd, -1);
657 
658     EnableWindow(hFrameWnd, FALSE);
659     EnableWindow(g_pChildWnd->hTreeWnd, FALSE);
660     EnableWindow(g_pChildWnd->hListWnd, FALSE);
661     EnableWindow(g_pChildWnd->hAddressBarWnd, FALSE);
662 
663     fSuccess = RegFindWalk(&hKeyRoot, pszKeyPath, pszValueName,
664                            &pszFoundSubKey, &pszFoundValueName);
665 
666     EnableWindow(hFrameWnd, TRUE);
667     EnableWindow(g_pChildWnd->hTreeWnd, TRUE);
668     EnableWindow(g_pChildWnd->hListWnd, TRUE);
669     EnableWindow(g_pChildWnd->hAddressBarWnd, TRUE);
670 
671     if (s_hwndAbortDialog)
672     {
673         DestroyWindow(s_hwndAbortDialog);
674         s_hwndAbortDialog = NULL;
675     }
676 
677     if (fSuccess)
678     {
679         GetKeyName(szFullKey, ARRAY_SIZE(szFullKey), hKeyRoot, pszFoundSubKey);
680         SelectNode(g_pChildWnd->hTreeWnd, szFullKey);
681         free(pszFoundSubKey);
682 
683         if (pszFoundValueName != NULL)
684         {
685             SetValueName(g_pChildWnd->hListWnd, pszFoundValueName);
686             free(pszFoundValueName);
687             SetFocus(g_pChildWnd->hListWnd);
688         }
689         else
690         {
691             SetFocus(g_pChildWnd->hTreeWnd);
692         }
693     }
694     return fSuccess || s_bAbort;
695 }
696 
697 static INT_PTR CALLBACK FindDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
698 {
699     INT_PTR iResult = 0;
700     HWND hControl;
701     LONG lStyle;
702     DWORD dwFlags;
703     static WCHAR s_szSavedFindValue[256];
704 
705     switch(uMsg)
706     {
707     case WM_INITDIALOG:
708         dwFlags = GetFindFlags();
709 
710         hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
711         if (hControl)
712             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATKEYS) ? TRUE : FALSE, 0);
713 
714         hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
715         if (hControl)
716             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATVALUES) ? TRUE : FALSE, 0);
717 
718         hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
719         if (hControl)
720             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_LOOKATDATA) ? TRUE : FALSE, 0);
721 
722         /* Match whole string */
723         hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
724         if (hControl)
725             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_WHOLESTRING) ? TRUE : FALSE, 0);
726 
727         /* Case sensitivity */
728         hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
729         if (hControl)
730             SendMessageW(hControl, BM_SETCHECK, (dwFlags & RSF_MATCHCASE) ? TRUE : FALSE, 0);
731 
732         hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
733         if (hControl)
734         {
735             SetWindowTextW(hControl, s_szSavedFindValue);
736             SetFocus(hControl);
737             SendMessageW(hControl, EM_SETSEL, 0, -1);
738         }
739         break;
740 
741     case WM_CLOSE:
742         EndDialog(hDlg, 0);
743         break;
744 
745     case WM_COMMAND:
746         switch(HIWORD(wParam))
747         {
748         case BN_CLICKED:
749             switch(LOWORD(wParam))
750             {
751             case IDOK:
752                 dwFlags = 0;
753 
754                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_KEYS);
755                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
756                     dwFlags |= RSF_LOOKATKEYS;
757 
758                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_VALUES);
759                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
760                     dwFlags |= RSF_LOOKATVALUES;
761 
762                 hControl = GetDlgItem(hDlg, IDC_LOOKAT_DATA);
763                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
764                     dwFlags |= RSF_LOOKATDATA;
765 
766                 hControl = GetDlgItem(hDlg, IDC_MATCHSTRING);
767                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
768                     dwFlags |= RSF_WHOLESTRING;
769 
770                 hControl = GetDlgItem(hDlg, IDC_MATCHCASE);
771                 if (hControl && (SendMessageW(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED))
772                     dwFlags |= RSF_MATCHCASE;
773 
774                 SetFindFlags(dwFlags);
775 
776                 hControl = GetDlgItem(hDlg, IDC_FINDWHAT);
777                 if (hControl)
778                     GetWindowTextW(hControl, s_szFindWhat, ARRAY_SIZE(s_szFindWhat));
779                 EndDialog(hDlg, 1);
780                 break;
781 
782             case IDCANCEL:
783                 EndDialog(hDlg, 0);
784                 break;
785             }
786             break;
787 
788         case EN_CHANGE:
789             switch(LOWORD(wParam))
790             {
791             case IDC_FINDWHAT:
792                 GetWindowTextW((HWND) lParam, s_szSavedFindValue, ARRAY_SIZE(s_szSavedFindValue));
793                 hControl = GetDlgItem(hDlg, IDOK);
794                 if (hControl)
795                 {
796                     lStyle = GetWindowLongPtr(hControl, GWL_STYLE);
797                     if (s_szSavedFindValue[0])
798                         lStyle &= ~WS_DISABLED;
799                     else
800                         lStyle |= WS_DISABLED;
801                     SetWindowLongPtr(hControl, GWL_STYLE, lStyle);
802                     RedrawWindow(hControl, NULL, NULL, RDW_INVALIDATE);
803                 }
804                 break;
805             }
806         }
807         break;
808     }
809     return iResult;
810 }
811 
812 void FindNextMessageBox(HWND hWnd)
813 {
814     if (!FindNext(hWnd))
815     {
816         WCHAR msg[128], caption[128];
817 
818         LoadStringW(hInst, IDS_FINISHEDFIND, msg, ARRAY_SIZE(msg));
819         LoadStringW(hInst, IDS_APP_TITLE, caption, ARRAY_SIZE(caption));
820         MessageBoxW(hWnd, msg, caption, MB_ICONINFORMATION);
821     }
822 }
823 
824 void FindDialog(HWND hWnd)
825 {
826     if (DialogBoxParamW(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDD_FIND),
827                        hWnd, FindDialogProc, 0) != 0)
828     {
829         FindNextMessageBox(hWnd);
830     }
831 }
832