1 /*
2  * Regedit frame window
3  *
4  * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "regedit.h"
22 
23 #include <commdlg.h>
24 #include <cderr.h>
25 #include <objsel.h>
26 
27 /********************************************************************************
28  * Global and Local Variables:
29  */
30 
31 #define FAVORITES_MENU_POSITION 3
32 
33 static WCHAR s_szFavoritesRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites";
34 
35 static BOOL bInMenuLoop = FALSE;        /* Tells us if we are in the menu loop */
36 
37 extern WCHAR Suggestions[256];
38 /*******************************************************************************
39  * Local module support methods
40  */
41 
42 static void resize_frame_rect(HWND hWnd, PRECT prect)
43 {
44     if (IsWindowVisible(hStatusBar))
45     {
46         RECT rt;
47 
48         SetupStatusBar(hWnd, TRUE);
49         GetWindowRect(hStatusBar, &rt);
50         prect->bottom -= rt.bottom - rt.top;
51     }
52     MoveWindow(g_pChildWnd->hWnd, prect->left, prect->top, prect->right, prect->bottom, TRUE);
53 }
54 
55 static void resize_frame_client(HWND hWnd)
56 {
57     RECT rect;
58 
59     GetClientRect(hWnd, &rect);
60     resize_frame_rect(hWnd, &rect);
61 }
62 
63 /********************************************************************************/
64 
65 static void OnInitMenu(HWND hWnd)
66 {
67     LONG lResult;
68     HKEY hKey = NULL;
69     DWORD dwIndex, cbValueName, cbValueData, dwType;
70     WCHAR szValueName[256];
71     BYTE abValueData[256];
72     static int s_nFavoriteMenuSubPos = -1;
73     HMENU hMenu;
74     BOOL bDisplayedAny = FALSE;
75 
76     /* Find Favorites menu and clear it out */
77     hMenu = GetSubMenu(GetMenu(hWnd), FAVORITES_MENU_POSITION);
78     if (!hMenu)
79         goto done;
80     if (s_nFavoriteMenuSubPos < 0)
81     {
82         s_nFavoriteMenuSubPos = GetMenuItemCount(hMenu);
83     }
84     else
85     {
86         while(RemoveMenu(hMenu, s_nFavoriteMenuSubPos, MF_BYPOSITION)) ;
87     }
88 
89     lResult = RegOpenKeyW(HKEY_CURRENT_USER, s_szFavoritesRegKey, &hKey);
90     if (lResult != ERROR_SUCCESS)
91         goto done;
92 
93     dwIndex = 0;
94     do
95     {
96         cbValueName = ARRAY_SIZE(szValueName);
97         cbValueData = sizeof(abValueData);
98         lResult = RegEnumValueW(hKey, dwIndex, szValueName, &cbValueName, NULL, &dwType, abValueData, &cbValueData);
99         if ((lResult == ERROR_SUCCESS) && (dwType == REG_SZ))
100         {
101             if (!bDisplayedAny)
102             {
103                 AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
104                 bDisplayedAny = TRUE;
105             }
106             AppendMenu(hMenu, 0, ID_FAVORITES_MIN + GetMenuItemCount(hMenu), szValueName);
107         }
108         dwIndex++;
109     }
110     while(lResult == ERROR_SUCCESS);
111 
112 done:
113     if (hKey)
114         RegCloseKey(hKey);
115 }
116 
117 static void OnEnterMenuLoop(HWND hWnd)
118 {
119     int nParts;
120     UNREFERENCED_PARAMETER(hWnd);
121 
122     /* Update the status bar pane sizes */
123     nParts = -1;
124     SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
125     bInMenuLoop = TRUE;
126     SendMessageW(hStatusBar, SB_SETTEXTW, (WPARAM)0, (LPARAM)L"");
127 }
128 
129 static void OnExitMenuLoop(HWND hWnd)
130 {
131     bInMenuLoop = FALSE;
132     /* Update the status bar pane sizes*/
133     SetupStatusBar(hWnd, TRUE);
134     UpdateStatusBar();
135 }
136 
137 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
138 {
139     WCHAR str[100];
140 
141     str[0] = UNICODE_NULL;
142     if (nFlags & MF_POPUP)
143     {
144         if (hSysMenu != GetMenu(hWnd))
145         {
146             if (nItemID == 2) nItemID = 5;
147         }
148     }
149     if (LoadStringW(hInst, nItemID, str, 100))
150     {
151         /* load appropriate string*/
152         LPWSTR lpsz = str;
153         /* first newline terminates actual string*/
154         lpsz = wcschr(lpsz, L'\n');
155         if (lpsz != NULL)
156             *lpsz = L'\0';
157     }
158     SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)str);
159 }
160 
161 void SetupStatusBar(HWND hWnd, BOOL bResize)
162 {
163     RECT  rc;
164     int nParts;
165     GetClientRect(hWnd, &rc);
166     nParts = rc.right;
167     /*    nParts = -1;*/
168     if (bResize)
169         SendMessageW(hStatusBar, WM_SIZE, 0, 0);
170     SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
171 }
172 
173 void UpdateStatusBar(void)
174 {
175     HKEY hKeyRoot;
176     LPCWSTR pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
177 
178     SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)pszKeyPath);
179 }
180 
181 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
182 {
183     BOOL vis = IsWindowVisible(hchild);
184     HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
185 
186     CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
187     ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
188     resize_frame_client(hWnd);
189 }
190 
191 static BOOL CheckCommDlgError(HWND hWnd)
192 {
193     DWORD dwErrorCode = CommDlgExtendedError();
194     UNREFERENCED_PARAMETER(hWnd);
195     switch (dwErrorCode)
196     {
197         case CDERR_DIALOGFAILURE:
198             break;
199         case CDERR_FINDRESFAILURE:
200             break;
201         case CDERR_NOHINSTANCE:
202             break;
203         case CDERR_INITIALIZATION:
204             break;
205         case CDERR_NOHOOK:
206             break;
207         case CDERR_LOCKRESFAILURE:
208             break;
209         case CDERR_NOTEMPLATE:
210             break;
211         case CDERR_LOADRESFAILURE:
212             break;
213         case CDERR_STRUCTSIZE:
214             break;
215         case CDERR_LOADSTRFAILURE:
216             break;
217         case FNERR_BUFFERTOOSMALL:
218             break;
219         case CDERR_MEMALLOCFAILURE:
220             break;
221         case FNERR_INVALIDFILENAME:
222             break;
223         case CDERR_MEMLOCKFAILURE:
224             break;
225         case FNERR_SUBCLASSFAILURE:
226             break;
227         default:
228             break;
229     }
230     return TRUE;
231 }
232 
233 WCHAR FileNameBuffer[MAX_PATH];
234 
235 typedef struct
236 {
237     UINT DisplayID;
238     UINT FilterID;
239 } FILTERPAIR, *PFILTERPAIR;
240 
241 void
242 BuildFilterStrings(WCHAR *Filter, PFILTERPAIR Pairs, int PairCount)
243 {
244     int i, c;
245 
246     c = 0;
247     for(i = 0; i < PairCount; i++)
248     {
249         c += LoadStringW(hInst, Pairs[i].DisplayID, &Filter[c], 255);
250         Filter[++c] = L'\0';
251         c += LoadStringW(hInst, Pairs[i].FilterID, &Filter[c], 255);
252         Filter[++c] = L'\0';
253     }
254     Filter[++c] = L'\0';
255 }
256 
257 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAME* pofn, BOOL bSave)
258 {
259     FILTERPAIR FilterPairs[5];
260     static WCHAR Filter[1024];
261 
262     memset(pofn, 0, sizeof(OPENFILENAME));
263     pofn->lStructSize = sizeof(OPENFILENAME);
264     pofn->hwndOwner = hWnd;
265     pofn->hInstance = hInst;
266 
267     /* create filter string */
268     FilterPairs[0].DisplayID = IDS_FLT_REGFILES;
269     FilterPairs[0].FilterID = IDS_FLT_REGFILES_FLT;
270     FilterPairs[1].DisplayID = IDS_FLT_HIVFILES;
271     FilterPairs[1].FilterID = IDS_FLT_HIVFILES_FLT;
272     FilterPairs[2].DisplayID = IDS_FLT_REGEDIT4;
273     FilterPairs[2].FilterID = IDS_FLT_REGEDIT4_FLT;
274     if (bSave)
275     {
276         FilterPairs[3].DisplayID = IDS_FLT_TXTFILES;
277         FilterPairs[3].FilterID = IDS_FLT_TXTFILES_FLT;
278         FilterPairs[4].DisplayID = IDS_FLT_ALLFILES;
279         FilterPairs[4].FilterID = IDS_FLT_ALLFILES_FLT;
280     }
281     else
282     {
283         FilterPairs[3].DisplayID = IDS_FLT_ALLFILES;
284         FilterPairs[3].FilterID = IDS_FLT_ALLFILES_FLT;
285     }
286 
287     BuildFilterStrings(Filter, FilterPairs, ARRAY_SIZE(FilterPairs) - !bSave);
288 
289     pofn->lpstrFilter = Filter;
290     pofn->lpstrFile = FileNameBuffer;
291     pofn->nMaxFile = _countof(FileNameBuffer);
292     pofn->Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
293     pofn->lpstrDefExt = L"reg";
294     if (bSave)
295         pofn->Flags |= OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
296     else
297         pofn->Flags |= OFN_FILEMUSTEXIST;
298 
299     return TRUE;
300 }
301 
302 #define LOADHIVE_KEYNAMELENGTH 128
303 
304 static INT_PTR CALLBACK LoadHive_KeyNameInHookProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
305 {
306     static LPWSTR sKey = NULL;
307     switch(uMsg)
308     {
309     case WM_INITDIALOG:
310         sKey = (LPWSTR)lParam;
311         break;
312     case WM_COMMAND:
313         switch(LOWORD(wParam))
314         {
315         case IDOK:
316             if(GetDlgItemTextW(hWndDlg, IDC_EDIT_KEY, sKey, LOADHIVE_KEYNAMELENGTH))
317                 return EndDialog(hWndDlg, -1);
318             else
319                 return EndDialog(hWndDlg, 0);
320         case IDCANCEL:
321             return EndDialog(hWndDlg, 0);
322         }
323         break;
324     }
325     return FALSE;
326 }
327 
328 static BOOL EnablePrivilege(LPCWSTR lpszPrivilegeName, LPCWSTR lpszSystemName, BOOL bEnablePrivilege)
329 {
330     BOOL   bRet   = FALSE;
331     HANDLE hToken = NULL;
332 
333     if (OpenProcessToken(GetCurrentProcess(),
334                          TOKEN_ADJUST_PRIVILEGES,
335                          &hToken))
336     {
337         TOKEN_PRIVILEGES tp;
338 
339         tp.PrivilegeCount = 1;
340         tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
341 
342         if (LookupPrivilegeValueW(lpszSystemName,
343                                   lpszPrivilegeName,
344                                   &tp.Privileges[0].Luid))
345         {
346             bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
347 
348             if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
349                 bRet = FALSE;
350         }
351 
352         CloseHandle(hToken);
353     }
354 
355     return bRet;
356 }
357 
358 static BOOL LoadHive(HWND hWnd)
359 {
360     OPENFILENAME ofn;
361     WCHAR Caption[128];
362     LPCWSTR pszKeyPath;
363     WCHAR xPath[LOADHIVE_KEYNAMELENGTH];
364     HKEY hRootKey;
365     WCHAR Filter[1024];
366     FILTERPAIR filter;
367     /* get the item key to load the hive in */
368     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey);
369     /* initialize the "open file" dialog */
370     InitOpenFileName(hWnd, &ofn, FALSE);
371     /* build the "All Files" filter up */
372     filter.DisplayID = IDS_FLT_ALLFILES;
373     filter.FilterID = IDS_FLT_ALLFILES_FLT;
374     BuildFilterStrings(Filter, &filter, 1);
375     ofn.lpstrFilter = Filter;
376     /* load and set the caption and flags for dialog */
377     LoadStringW(hInst, IDS_LOAD_HIVE, Caption, ARRAY_SIZE(Caption));
378     ofn.lpstrTitle = Caption;
379     ofn.Flags |= OFN_ENABLESIZING;
380 
381     /* now load the hive */
382     if (GetOpenFileName(&ofn))
383     {
384         if (DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_LOADHIVE), hWnd,
385                             &LoadHive_KeyNameInHookProc, (LPARAM)xPath))
386         {
387             LONG regLoadResult;
388 
389             /* Enable the 'restore' privilege, load the hive, disable the privilege */
390             EnablePrivilege(SE_RESTORE_NAME, NULL, TRUE);
391             regLoadResult = RegLoadKeyW(hRootKey, xPath, ofn.lpstrFile);
392             EnablePrivilege(SE_RESTORE_NAME, NULL, FALSE);
393 
394             if(regLoadResult == ERROR_SUCCESS)
395             {
396                 /* refresh tree and list views */
397                 RefreshTreeView(g_pChildWnd->hTreeWnd);
398                 pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey);
399                 RefreshListView(g_pChildWnd->hListWnd, hRootKey, pszKeyPath, TRUE);
400             }
401             else
402             {
403                 ErrorMessageBox(hWnd, Caption, regLoadResult);
404                 return FALSE;
405             }
406         }
407     }
408     else
409     {
410         CheckCommDlgError(hWnd);
411     }
412     return TRUE;
413 }
414 
415 static BOOL UnloadHive(HWND hWnd)
416 {
417     WCHAR Caption[128];
418     LPCWSTR pszKeyPath;
419     HKEY hRootKey;
420     LONG regUnloadResult;
421 
422     /* get the item key to unload */
423     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey);
424     /* load and set the caption and flags for dialog */
425     LoadStringW(hInst, IDS_UNLOAD_HIVE, Caption, ARRAY_SIZE(Caption));
426 
427     /* Enable the 'restore' privilege, unload the hive, disable the privilege */
428     EnablePrivilege(SE_RESTORE_NAME, NULL, TRUE);
429     regUnloadResult = RegUnLoadKeyW(hRootKey, pszKeyPath);
430     EnablePrivilege(SE_RESTORE_NAME, NULL, FALSE);
431 
432     if(regUnloadResult == ERROR_SUCCESS)
433     {
434         /* refresh tree and list views */
435         RefreshTreeView(g_pChildWnd->hTreeWnd);
436         pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey);
437         RefreshListView(g_pChildWnd->hListWnd, hRootKey, pszKeyPath, TRUE);
438     }
439     else
440     {
441         ErrorMessageBox(hWnd, Caption, regUnloadResult);
442         return FALSE;
443     }
444     return TRUE;
445 }
446 
447 static BOOL ImportRegistryFile(HWND hWnd)
448 {
449     BOOL bRet = FALSE;
450     OPENFILENAME ofn;
451     WCHAR Caption[128], szTitle[512], szText[512];
452     HKEY hKeyRoot;
453     LPCWSTR pszKeyPath;
454 
455     /* Figure out in which key path we are importing */
456     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
457 
458     InitOpenFileName(hWnd, &ofn, FALSE);
459     LoadStringW(hInst, IDS_IMPORT_REG_FILE, Caption, ARRAY_SIZE(Caption));
460     ofn.lpstrTitle = Caption;
461     ofn.Flags |= OFN_ENABLESIZING;
462 
463     if (GetOpenFileName(&ofn))
464     {
465         /* Look at the extension of the file to determine its type */
466         if (ofn.nFileExtension >= 1 &&
467             _wcsicmp(ofn.lpstrFile + ofn.nFileExtension, L"reg") == 0) /* REGEDIT4 or Windows Registry Editor Version 5.00 */
468         {
469             /* Open the file */
470             FILE* fp = _wfopen(ofn.lpstrFile, L"rb");
471 
472             /* Import it */
473             if (fp == NULL || !import_registry_file(fp))
474             {
475                 /* Error opening the file */
476                 LoadStringW(hInst, IDS_APP_TITLE, szTitle, ARRAY_SIZE(szTitle));
477                 LoadStringW(hInst, IDS_IMPORT_ERROR, szText, ARRAY_SIZE(szText));
478                 InfoMessageBox(hWnd, MB_OK | MB_ICONERROR, szTitle, szText, ofn.lpstrFile);
479                 bRet = FALSE;
480             }
481             else
482             {
483                 /* Show successful import */
484                 LoadStringW(hInst, IDS_APP_TITLE, szTitle, ARRAY_SIZE(szTitle));
485                 LoadStringW(hInst, IDS_IMPORT_OK, szText, ARRAY_SIZE(szText));
486                 InfoMessageBox(hWnd, MB_OK | MB_ICONINFORMATION, szTitle, szText, ofn.lpstrFile);
487                 bRet = TRUE;
488             }
489 
490             /* Close the file */
491             if (fp) fclose(fp);
492         }
493         else /* Registry Hive Files */
494         {
495             LoadStringW(hInst, IDS_QUERY_IMPORT_HIVE_CAPTION, szTitle, ARRAY_SIZE(szTitle));
496             LoadStringW(hInst, IDS_QUERY_IMPORT_HIVE_MSG, szText, ARRAY_SIZE(szText));
497 
498             /* Display a confirmation message */
499             if (MessageBoxW(g_pChildWnd->hWnd, szText, szTitle, MB_ICONWARNING | MB_YESNO) == IDYES)
500             {
501                 LONG lResult;
502                 HKEY hSubKey;
503 
504                 /* Open the subkey */
505                 lResult = RegOpenKeyExW(hKeyRoot, pszKeyPath, 0, KEY_WRITE, &hSubKey);
506                 if (lResult == ERROR_SUCCESS)
507                 {
508                     /* Enable the 'restore' privilege, restore the hive then disable the privilege */
509                     EnablePrivilege(SE_RESTORE_NAME, NULL, TRUE);
510                     lResult = RegRestoreKey(hSubKey, ofn.lpstrFile, REG_FORCE_RESTORE);
511                     EnablePrivilege(SE_RESTORE_NAME, NULL, FALSE);
512 
513                     /* Flush the subkey and close it */
514                     RegFlushKey(hSubKey);
515                     RegCloseKey(hSubKey);
516                 }
517 
518                 /* Set the return value */
519                 bRet = (lResult == ERROR_SUCCESS);
520 
521                 /* Display error, if any */
522                 if (!bRet) ErrorMessageBox(hWnd, Caption, lResult);
523             }
524         }
525     }
526     else
527     {
528         CheckCommDlgError(hWnd);
529     }
530 
531     /* refresh tree and list views */
532     RefreshTreeView(g_pChildWnd->hTreeWnd);
533     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
534     RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, pszKeyPath, TRUE);
535 
536     return bRet;
537 }
538 
539 static UINT_PTR CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
540 {
541     HWND hwndExportAll;
542     HWND hwndExportBranch;
543     HWND hwndExportBranchText;
544     UINT_PTR iResult = 0;
545     OPENFILENAME *pOfn;
546     LPWSTR pszSelectedKey;
547     OFNOTIFY *pOfnNotify;
548 
549     UNREFERENCED_PARAMETER(wParam);
550 
551     switch(uiMsg)
552     {
553     case WM_INITDIALOG:
554         pOfn = (OPENFILENAME *) lParam;
555         pszSelectedKey = (LPWSTR) pOfn->lCustData;
556 
557         hwndExportAll = GetDlgItem(hdlg, IDC_EXPORT_ALL);
558         if (hwndExportAll)
559             SendMessageW(hwndExportAll, BM_SETCHECK, pszSelectedKey ? BST_UNCHECKED : BST_CHECKED, 0);
560 
561         hwndExportBranch = GetDlgItem(hdlg, IDC_EXPORT_BRANCH);
562         if (hwndExportBranch)
563             SendMessageW(hwndExportBranch, BM_SETCHECK, pszSelectedKey ? BST_CHECKED : BST_UNCHECKED, 0);
564 
565         hwndExportBranchText = GetDlgItem(hdlg, IDC_EXPORT_BRANCH_TEXT);
566         if (hwndExportBranchText)
567             SetWindowTextW(hwndExportBranchText, pszSelectedKey);
568         break;
569 
570     case WM_NOTIFY:
571         if (((NMHDR *) lParam)->code == CDN_FILEOK)
572         {
573             pOfnNotify = (OFNOTIFY *) lParam;
574             pszSelectedKey = (LPWSTR) pOfnNotify->lpOFN->lCustData;
575 
576             hwndExportBranch = GetDlgItem(hdlg, IDC_EXPORT_BRANCH);
577             hwndExportBranchText = GetDlgItem(hdlg, IDC_EXPORT_BRANCH_TEXT);
578             if (hwndExportBranch && hwndExportBranchText
579                     && (SendMessageW(hwndExportBranch, BM_GETCHECK, 0, 0) == BST_CHECKED))
580             {
581                 GetWindowTextW(hwndExportBranchText, pszSelectedKey, _MAX_PATH);
582             }
583             else if (pszSelectedKey)
584             {
585                 pszSelectedKey[0] = L'\0';
586             }
587         }
588         break;
589     }
590     return iResult;
591 }
592 
593 BOOL ExportRegistryFile(HWND hWnd)
594 {
595     BOOL bRet = FALSE;
596     OPENFILENAME ofn;
597     WCHAR ExportKeyPath[_MAX_PATH] = {0};
598     WCHAR Caption[128], szTitle[512], szText[512];
599     HKEY hKeyRoot;
600     LPCWSTR pszKeyPath;
601 
602     /* Figure out which key path we are exporting */
603     pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
604     GetKeyName(ExportKeyPath, ARRAY_SIZE(ExportKeyPath), hKeyRoot, pszKeyPath);
605 
606     InitOpenFileName(hWnd, &ofn, TRUE);
607     LoadStringW(hInst, IDS_EXPORT_REG_FILE, Caption, ARRAY_SIZE(Caption));
608     ofn.lpstrTitle = Caption;
609 
610     /* Only set the path if a key (not the root node) is selected */
611     if (hKeyRoot != 0)
612     {
613         ofn.lCustData = (LPARAM) ExportKeyPath;
614     }
615     ofn.Flags |= OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
616     ofn.lpfnHook = ExportRegistryFile_OFNHookProc;
617     ofn.lpTemplateName = MAKEINTRESOURCEW(IDD_EXPORTRANGE);
618     if (GetSaveFileName(&ofn))
619     {
620         switch (ofn.nFilterIndex)
621         {
622             case 2: /* Registry Hive Files */
623             {
624                 LONG lResult;
625                 HKEY hSubKey;
626 
627                 /* Open the subkey */
628                 lResult = RegOpenKeyExW(hKeyRoot, pszKeyPath, 0, KEY_READ, &hSubKey);
629                 if (lResult == ERROR_SUCCESS)
630                 {
631                     /* Enable the 'backup' privilege, save the hive then disable the privilege */
632                     EnablePrivilege(SE_BACKUP_NAME, NULL, TRUE);
633                     lResult = RegSaveKeyW(hSubKey, ofn.lpstrFile, NULL);
634                     if (lResult == ERROR_ALREADY_EXISTS)
635                     {
636                         /*
637                          * We are here, that means that we already said "yes" to the confirmation dialog.
638                          * So we absolutely want to replace the hive file.
639                          */
640                         if (DeleteFileW(ofn.lpstrFile))
641                         {
642                             /* Try again */
643                             lResult = RegSaveKeyW(hSubKey, ofn.lpstrFile, NULL);
644                         }
645                     }
646                     EnablePrivilege(SE_BACKUP_NAME, NULL, FALSE);
647 
648                     if (lResult != ERROR_SUCCESS)
649                     {
650                         /*
651                          * If we are here, it's because RegSaveKeyW has failed for any reason.
652                          * The problem is that even if it has failed, it has created or
653                          * replaced the exported hive file with a new empty file. We don't
654                          * want to keep this file, so we delete it.
655                          */
656                         DeleteFileW(ofn.lpstrFile);
657                     }
658 
659                     /* Close the subkey */
660                     RegCloseKey(hSubKey);
661                 }
662 
663                 /* Set the return value */
664                 bRet = (lResult == ERROR_SUCCESS);
665 
666                 /* Display error, if any */
667                 if (!bRet) ErrorMessageBox(hWnd, Caption, lResult);
668 
669                 break;
670             }
671 
672             case 1:  /* Windows Registry Editor Version 5.00 */
673             case 3:  /* REGEDIT4 */
674             default: /* All files ==> use Windows Registry Editor Version 5.00 */
675             {
676                 if (!export_registry_key(ofn.lpstrFile, ExportKeyPath,
677                                          (ofn.nFilterIndex == 3 ? REG_FORMAT_4
678                                                                 : REG_FORMAT_5)))
679                 {
680                     /* Error creating the file */
681                     LoadStringW(hInst, IDS_APP_TITLE, szTitle, ARRAY_SIZE(szTitle));
682                     LoadStringW(hInst, IDS_EXPORT_ERROR, szText, ARRAY_SIZE(szText));
683                     InfoMessageBox(hWnd, MB_OK | MB_ICONERROR, szTitle, szText, ofn.lpstrFile);
684                     bRet = FALSE;
685                 }
686                 else
687                 {
688                     bRet = TRUE;
689                 }
690 
691                 break;
692             }
693 
694             case 4:  /* Text File */
695             {
696                 bRet = txt_export_registry_key(ofn.lpstrFile, ExportKeyPath);
697                 if (!bRet)
698                 {
699                     /* Error creating the file */
700                     LoadStringW(hInst, IDS_APP_TITLE, szTitle, ARRAY_SIZE(szTitle));
701                     LoadStringW(hInst, IDS_EXPORT_ERROR, szText, ARRAY_SIZE(szText));
702                     InfoMessageBox(hWnd, MB_OK | MB_ICONERROR, szTitle, szText, ofn.lpstrFile);
703                 }
704                 break;
705             }
706         }
707     }
708     else
709     {
710         CheckCommDlgError(hWnd);
711     }
712 
713     return bRet;
714 }
715 
716 BOOL PrintRegistryHive(HWND hWnd, LPWSTR path)
717 {
718 #if 1
719     PRINTDLG pd;
720     UNREFERENCED_PARAMETER(path);
721 
722     ZeroMemory(&pd, sizeof(PRINTDLG));
723     pd.lStructSize = sizeof(PRINTDLG);
724     pd.hwndOwner   = hWnd;
725     pd.hDevMode    = NULL;     /* Don't forget to free or store hDevMode*/
726     pd.hDevNames   = NULL;     /* Don't forget to free or store hDevNames*/
727     pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
728     pd.nCopies     = 1;
729     pd.nFromPage   = 0xFFFF;
730     pd.nToPage     = 0xFFFF;
731     pd.nMinPage    = 1;
732     pd.nMaxPage    = 0xFFFF;
733     if (PrintDlg(&pd))
734     {
735         /* GDI calls to render output. */
736         DeleteDC(pd.hDC); /* Delete DC when done.*/
737     }
738 #else
739     HRESULT hResult;
740     PRINTDLGEX pd;
741 
742     hResult = PrintDlgEx(&pd);
743     if (hResult == S_OK)
744     {
745         switch (pd.dwResultAction)
746         {
747         case PD_RESULT_APPLY:
748             /*The user clicked the Apply button and later clicked the Cancel button. This indicates that the user wants to apply the changes made in the property sheet, but does not yet want to print. The PRINTDLGEX structure contains the information specified by the user at the time the Apply button was clicked. */
749             break;
750         case PD_RESULT_CANCEL:
751             /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
752             break;
753         case PD_RESULT_PRINT:
754             /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
755             break;
756         default:
757             break;
758         }
759     }
760     else
761     {
762         switch (hResult)
763         {
764         case E_OUTOFMEMORY:
765             /*Insufficient memory. */
766             break;
767         case E_INVALIDARG:
768             /* One or more arguments are invalid. */
769             break;
770         case E_POINTER:
771             /*Invalid pointer. */
772             break;
773         case E_HANDLE:
774             /*Invalid handle. */
775             break;
776         case E_FAIL:
777             /*Unspecified error. */
778             break;
779         default:
780             break;
781         }
782         return FALSE;
783     }
784 #endif
785     return TRUE;
786 }
787 
788 static void ChooseFavorite(LPCWSTR pszFavorite)
789 {
790     HKEY hKey = NULL;
791     WCHAR szFavoritePath[512];
792     DWORD cbData, dwType;
793 
794     if (RegOpenKeyExW(HKEY_CURRENT_USER, s_szFavoritesRegKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
795         goto done;
796 
797     cbData = sizeof(szFavoritePath);
798     memset(szFavoritePath, 0, sizeof(szFavoritePath));
799     if (RegQueryValueExW(hKey, pszFavorite, NULL, &dwType, (LPBYTE) szFavoritePath, &cbData) != ERROR_SUCCESS)
800         goto done;
801 
802     if (dwType == REG_SZ)
803         SelectNode(g_pChildWnd->hTreeWnd, szFavoritePath);
804 
805 done:
806     if (hKey)
807         RegCloseKey(hKey);
808 }
809 
810 BOOL CopyKeyName(HWND hWnd, HKEY hRootKey, LPCWSTR keyName)
811 {
812     BOOL bClipboardOpened = FALSE;
813     BOOL bSuccess = FALSE;
814     WCHAR szBuffer[512];
815     HGLOBAL hGlobal;
816     LPWSTR s;
817     SIZE_T cbGlobal;
818 
819     if (!OpenClipboard(hWnd))
820         goto done;
821     bClipboardOpened = TRUE;
822 
823     if (!EmptyClipboard())
824         goto done;
825 
826     if (!GetKeyName(szBuffer, ARRAY_SIZE(szBuffer), hRootKey, keyName))
827         goto done;
828 
829     cbGlobal = (wcslen(szBuffer) + 1) * sizeof(WCHAR);
830     hGlobal = GlobalAlloc(GMEM_MOVEABLE, cbGlobal);
831     if (!hGlobal)
832         goto done;
833 
834     s = GlobalLock(hGlobal);
835     StringCbCopyW(s, cbGlobal, szBuffer);
836     GlobalUnlock(hGlobal);
837 
838     SetClipboardData(CF_UNICODETEXT, hGlobal);
839     bSuccess = TRUE;
840 
841 done:
842     if (bClipboardOpened)
843         CloseClipboard();
844     return bSuccess;
845 }
846 
847 static BOOL CreateNewValue(HKEY hRootKey, LPCWSTR pszKeyPath, DWORD dwType)
848 {
849     WCHAR szNewValueFormat[128];
850     WCHAR szNewValue[128];
851     int iIndex = 1;
852     BYTE data[128];
853     DWORD dwExistingType, cbData;
854     LONG lResult;
855     HKEY hKey;
856     LVFINDINFO lvfi;
857 
858     if (RegOpenKeyExW(hRootKey, pszKeyPath, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
859                       &hKey) != ERROR_SUCCESS)
860         return FALSE;
861 
862     LoadStringW(hInst, IDS_NEW_VALUE, szNewValueFormat, ARRAY_SIZE(szNewValueFormat));
863 
864     do
865     {
866         wsprintf(szNewValue, szNewValueFormat, iIndex++);
867         cbData = sizeof(data);
868         lResult = RegQueryValueExW(hKey, szNewValue, NULL, &dwExistingType, data, &cbData);
869     }
870     while(lResult == ERROR_SUCCESS);
871 
872     switch(dwType)
873     {
874         case REG_DWORD:
875             cbData = sizeof(DWORD);
876             break;
877         case REG_SZ:
878         case REG_EXPAND_SZ:
879             cbData = sizeof(WCHAR);
880             break;
881         case REG_MULTI_SZ:
882             /*
883              * WARNING: An empty multi-string has only one null char.
884              * Indeed, multi-strings are built in the following form:
885              * str1\0str2\0...strN\0\0
886              * where each strI\0 is a null-terminated string, and it
887              * ends with a terminating empty string.
888              * Therefore an empty multi-string contains only the terminating
889              * empty string, that is, one null char.
890              */
891             cbData = sizeof(WCHAR);
892             break;
893         case REG_QWORD: /* REG_QWORD_LITTLE_ENDIAN */
894             cbData = sizeof(DWORDLONG); // == sizeof(DWORD) * 2;
895             break;
896         default:
897             cbData = 0;
898             break;
899     }
900     memset(data, 0, cbData);
901     lResult = RegSetValueExW(hKey, szNewValue, 0, dwType, data, cbData);
902     RegCloseKey(hKey);
903     if (lResult != ERROR_SUCCESS)
904     {
905         return FALSE;
906     }
907 
908     RefreshListView(g_pChildWnd->hListWnd, hRootKey, pszKeyPath, TRUE);
909 
910     /* locate the newly added value, and get ready to rename it */
911     memset(&lvfi, 0, sizeof(lvfi));
912     lvfi.flags = LVFI_STRING;
913     lvfi.psz = szNewValue;
914     iIndex = ListView_FindItem(g_pChildWnd->hListWnd, -1, &lvfi);
915     if (iIndex >= 0)
916     {
917         ListView_SetItemState(g_pChildWnd->hListWnd, iIndex,
918                               LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
919         ListView_EnsureVisible(g_pChildWnd->hListWnd, iIndex, FALSE);
920         (void)ListView_EditLabel(g_pChildWnd->hListWnd, iIndex);
921     }
922 
923     return TRUE;
924 }
925 
926 static HRESULT
927 InitializeRemoteRegistryPicker(OUT IDsObjectPicker **pDsObjectPicker)
928 {
929     HRESULT hRet;
930 
931     *pDsObjectPicker = NULL;
932 
933     hRet = CoCreateInstance(&CLSID_DsObjectPicker,
934                             NULL,
935                             CLSCTX_INPROC_SERVER,
936                             &IID_IDsObjectPicker,
937                             (LPVOID*)pDsObjectPicker);
938     if (SUCCEEDED(hRet))
939     {
940         DSOP_INIT_INFO InitInfo;
941         static DSOP_SCOPE_INIT_INFO Scopes[] =
942         {
943             {
944                 sizeof(DSOP_SCOPE_INIT_INFO),
945                 DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE | DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE |
946                 DSOP_SCOPE_TYPE_GLOBAL_CATALOG | DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN |
947                 DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN | DSOP_SCOPE_TYPE_WORKGROUP |
948                 DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,
949                 0,
950                 {
951                     {
952                         DSOP_FILTER_COMPUTERS,
953                         0,
954                         0
955                     },
956                     DSOP_DOWNLEVEL_FILTER_COMPUTERS
957                 },
958                 NULL,
959                 NULL,
960                 S_OK
961             },
962         };
963 
964         InitInfo.cbSize = sizeof(InitInfo);
965         InitInfo.pwzTargetComputer = NULL;
966         InitInfo.cDsScopeInfos = ARRAY_SIZE(Scopes);
967         InitInfo.aDsScopeInfos = Scopes;
968         InitInfo.flOptions = 0;
969         InitInfo.cAttributesToFetch = 0;
970         InitInfo.apwzAttributeNames = NULL;
971 
972         hRet = (*pDsObjectPicker)->lpVtbl->Initialize(*pDsObjectPicker,
973                 &InitInfo);
974 
975         if (FAILED(hRet))
976         {
977             /* delete the object picker in case initialization failed! */
978             (*pDsObjectPicker)->lpVtbl->Release(*pDsObjectPicker);
979         }
980     }
981 
982     return hRet;
983 }
984 
985 static HRESULT
986 InvokeRemoteRegistryPickerDialog(IN IDsObjectPicker *pDsObjectPicker,
987                                  IN HWND hwndParent  OPTIONAL,
988                                  OUT LPWSTR lpBuffer,
989                                  IN UINT uSize)
990 {
991     IDataObject *pdo = NULL;
992     HRESULT hRet;
993 
994     hRet = pDsObjectPicker->lpVtbl->InvokeDialog(pDsObjectPicker,
995             hwndParent,
996             &pdo);
997     if (hRet == S_OK)
998     {
999         STGMEDIUM stm;
1000         FORMATETC fe;
1001 
1002         fe.cfFormat = (CLIPFORMAT) RegisterClipboardFormatW(CFSTR_DSOP_DS_SELECTION_LIST);
1003         fe.ptd = NULL;
1004         fe.dwAspect = DVASPECT_CONTENT;
1005         fe.lindex = -1;
1006         fe.tymed = TYMED_HGLOBAL;
1007 
1008         hRet = pdo->lpVtbl->GetData(pdo,
1009                                     &fe,
1010                                     &stm);
1011         if (SUCCEEDED(hRet))
1012         {
1013             PDS_SELECTION_LIST SelectionList = (PDS_SELECTION_LIST)GlobalLock(stm.hGlobal);
1014             if (SelectionList != NULL)
1015             {
1016                 if (SelectionList->cItems == 1)
1017                 {
1018                     size_t nlen = wcslen(SelectionList->aDsSelection[0].pwzName);
1019                     if (nlen >= uSize)
1020                     {
1021                         nlen = uSize - 1;
1022                     }
1023 
1024                     memcpy(lpBuffer,
1025                            SelectionList->aDsSelection[0].pwzName,
1026                            nlen * sizeof(WCHAR));
1027 
1028                     lpBuffer[nlen] = L'\0';
1029                 }
1030 
1031                 GlobalUnlock(stm.hGlobal);
1032             }
1033 
1034             ReleaseStgMedium(&stm);
1035         }
1036 
1037         pdo->lpVtbl->Release(pdo);
1038     }
1039 
1040     return hRet;
1041 }
1042 
1043 static VOID
1044 FreeObjectPicker(IN IDsObjectPicker *pDsObjectPicker)
1045 {
1046     pDsObjectPicker->lpVtbl->Release(pDsObjectPicker);
1047 }
1048 
1049 /*******************************************************************************
1050  *
1051  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
1052  *
1053  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
1054  *
1055  */
1056 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1057 {
1058     HKEY hKeyRoot = 0, hKey = 0;
1059     LPCWSTR keyPath;
1060     LPCWSTR valueName;
1061     BOOL result = TRUE;
1062     REGSAM regsam = KEY_READ;
1063     int item;
1064 
1065     UNREFERENCED_PARAMETER(lParam);
1066     UNREFERENCED_PARAMETER(message);
1067 
1068     switch (LOWORD(wParam))
1069     {
1070     case ID_REGISTRY_LOADHIVE:
1071         LoadHive(hWnd);
1072         return TRUE;
1073     case ID_REGISTRY_UNLOADHIVE:
1074         UnloadHive(hWnd);
1075         return TRUE;
1076     case ID_REGISTRY_IMPORTREGISTRYFILE:
1077         ImportRegistryFile(hWnd);
1078         return TRUE;
1079     case ID_REGISTRY_EXPORTREGISTRYFILE:
1080         ExportRegistryFile(hWnd);
1081         return TRUE;
1082     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
1083     {
1084         IDsObjectPicker *ObjectPicker;
1085         WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1086         HRESULT hRet;
1087 
1088         hRet = CoInitialize(NULL);
1089         if (SUCCEEDED(hRet))
1090         {
1091             hRet = InitializeRemoteRegistryPicker(&ObjectPicker);
1092             if (SUCCEEDED(hRet))
1093             {
1094                 hRet = InvokeRemoteRegistryPickerDialog(ObjectPicker,
1095                                                         hWnd,
1096                                                         szComputerName,
1097                                                         ARRAY_SIZE(szComputerName));
1098                 if (hRet == S_OK)
1099                 {
1100                     /* FIXME - connect to the registry */
1101                 }
1102 
1103                 FreeObjectPicker(ObjectPicker);
1104             }
1105 
1106             CoUninitialize();
1107         }
1108 
1109         return TRUE;
1110     }
1111     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
1112         return TRUE;
1113     case ID_REGISTRY_PRINT:
1114         PrintRegistryHive(hWnd, L"");
1115         return TRUE;
1116     case ID_REGISTRY_EXIT:
1117         DestroyWindow(hWnd);
1118         return TRUE;
1119     case ID_VIEW_STATUSBAR:
1120         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
1121         return TRUE;
1122     case ID_HELP_HELPTOPICS:
1123         WinHelpW(hWnd, L"regedit", HELP_FINDER, 0);
1124         return TRUE;
1125     case ID_HELP_ABOUT:
1126         ShowAboutBox(hWnd);
1127         return TRUE;
1128     case ID_VIEW_SPLIT:
1129     {
1130         RECT rt;
1131         POINT pt, pts;
1132         GetClientRect(g_pChildWnd->hWnd, &rt);
1133         pt.x = rt.left + g_pChildWnd->nSplitPos;
1134         pt.y = (rt.bottom / 2);
1135         pts = pt;
1136         if(ClientToScreen(g_pChildWnd->hWnd, &pts))
1137         {
1138             SetCursorPos(pts.x, pts.y);
1139             SetCursor(LoadCursorW(0, IDC_SIZEWE));
1140             SendMessageW(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
1141         }
1142         return TRUE;
1143     }
1144     case ID_EDIT_RENAME:
1145     case ID_EDIT_MODIFY:
1146     case ID_EDIT_MODIFY_BIN:
1147     case ID_EDIT_DELETE:
1148         regsam |= KEY_WRITE;
1149         break;
1150     }
1151 
1152     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1153     valueName = GetValueName(g_pChildWnd->hListWnd, -1);
1154     if (keyPath)
1155     {
1156         if (RegOpenKeyExW(hKeyRoot, keyPath, 0, regsam, &hKey) != ERROR_SUCCESS)
1157             hKey = 0;
1158     }
1159 
1160     switch (LOWORD(wParam))
1161     {
1162     case ID_EDIT_MODIFY:
1163         if (valueName && ModifyValue(hWnd, hKey, valueName, FALSE))
1164             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, FALSE);
1165         break;
1166     case ID_EDIT_MODIFY_BIN:
1167         if (valueName && ModifyValue(hWnd, hKey, valueName, TRUE))
1168             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, FALSE);
1169         break;
1170     case ID_EDIT_RENAME:
1171         if (GetFocus() == g_pChildWnd->hListWnd)
1172         {
1173             if(ListView_GetSelectedCount(g_pChildWnd->hListWnd) == 1)
1174             {
1175                 item = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
1176                 if(item > -1)
1177                 {
1178                     (void)ListView_EditLabel(g_pChildWnd->hListWnd, item);
1179                 }
1180             }
1181         }
1182         else if (GetFocus() == g_pChildWnd->hTreeWnd)
1183         {
1184             /* Get focused entry of treeview (if any) */
1185             HTREEITEM hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
1186             if (hItem != NULL)
1187                 (void)TreeView_EditLabel(g_pChildWnd->hTreeWnd, hItem);
1188         }
1189         break;
1190     case ID_EDIT_DELETE:
1191     {
1192         if (GetFocus() == g_pChildWnd->hListWnd && hKey)
1193         {
1194             UINT nSelected = ListView_GetSelectedCount(g_pChildWnd->hListWnd);
1195             if(nSelected >= 1)
1196             {
1197                 WCHAR msg[128], caption[128];
1198                 LoadStringW(hInst, IDS_QUERY_DELETE_CONFIRM, caption, ARRAY_SIZE(caption));
1199                 LoadStringW(hInst, (nSelected == 1 ? IDS_QUERY_DELETE_ONE : IDS_QUERY_DELETE_MORE), msg, ARRAY_SIZE(msg));
1200                 if(MessageBoxW(g_pChildWnd->hWnd, msg, caption, MB_ICONQUESTION | MB_YESNO) == IDYES)
1201                 {
1202                     int ni, errs;
1203 
1204                     item = -1;
1205                     errs = 0;
1206                     while((ni = ListView_GetNextItem(g_pChildWnd->hListWnd, item, LVNI_SELECTED)) > -1)
1207                     {
1208                         valueName = GetValueName(g_pChildWnd->hListWnd, item);
1209                         if(RegDeleteValueW(hKey, valueName) != ERROR_SUCCESS)
1210                         {
1211                             errs++;
1212                         }
1213                         item = ni;
1214                     }
1215 
1216                     RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, FALSE);
1217                     if(errs > 0)
1218                     {
1219                         LoadStringW(hInst, IDS_ERR_DELVAL_CAPTION, caption, ARRAY_SIZE(caption));
1220                         LoadStringW(hInst, IDS_ERR_DELETEVALUE, msg, ARRAY_SIZE(msg));
1221                         MessageBoxW(g_pChildWnd->hWnd, msg, caption, MB_ICONSTOP);
1222                     }
1223                 }
1224             }
1225         }
1226         else if (GetFocus() == g_pChildWnd->hTreeWnd)
1227         {
1228             if (keyPath == NULL || *keyPath == UNICODE_NULL)
1229             {
1230                 MessageBeep(MB_ICONHAND);
1231             }
1232             else if (DeleteKey(hWnd, hKeyRoot, keyPath))
1233             {
1234                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
1235                 RefreshTreeView(g_pChildWnd->hTreeWnd);
1236             }
1237         }
1238         break;
1239     }
1240     case ID_EDIT_NEW_STRINGVALUE:
1241         CreateNewValue(hKeyRoot, keyPath, REG_SZ);
1242         break;
1243     case ID_EDIT_NEW_BINARYVALUE:
1244         CreateNewValue(hKeyRoot, keyPath, REG_BINARY);
1245         break;
1246     case ID_EDIT_NEW_DWORDVALUE:
1247         CreateNewValue(hKeyRoot, keyPath, REG_DWORD);
1248         break;
1249     case ID_EDIT_NEW_MULTISTRINGVALUE:
1250         CreateNewValue(hKeyRoot, keyPath, REG_MULTI_SZ);
1251         break;
1252     case ID_EDIT_NEW_EXPANDABLESTRINGVALUE:
1253         CreateNewValue(hKeyRoot, keyPath, REG_EXPAND_SZ);
1254         break;
1255     case ID_EDIT_FIND:
1256         FindDialog(hWnd);
1257         break;
1258     case ID_EDIT_FINDNEXT:
1259         FindNextMessageBox(hWnd);
1260         break;
1261     case ID_EDIT_COPYKEYNAME:
1262         CopyKeyName(hWnd, hKeyRoot, keyPath);
1263         break;
1264     case ID_EDIT_PERMISSIONS:
1265         RegKeyEditPermissions(hWnd, hKeyRoot, NULL, keyPath);
1266         break;
1267     case ID_REGISTRY_PRINTERSETUP:
1268         /*PRINTDLG pd;*/
1269         /*PrintDlg(&pd);*/
1270         /*PAGESETUPDLG psd;*/
1271         /*PageSetupDlg(&psd);*/
1272         break;
1273     case ID_REGISTRY_OPENLOCAL:
1274         break;
1275 
1276     case ID_VIEW_REFRESH:
1277         RefreshTreeView(g_pChildWnd->hTreeWnd);
1278         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1279         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, TRUE);
1280         break;
1281         /*case ID_OPTIONS_TOOLBAR:*/
1282         /*	toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
1283         /*    break;*/
1284     case ID_EDIT_NEW_KEY:
1285         CreateNewKey(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
1286         break;
1287 
1288     case ID_TREE_EXPANDBRANCH:
1289         TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_EXPAND);
1290         break;
1291     case ID_TREE_COLLAPSEBRANCH:
1292         TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_COLLAPSE);
1293         break;
1294     case ID_TREE_RENAME:
1295         SetFocus(g_pChildWnd->hTreeWnd);
1296         TreeView_EditLabel(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
1297         break;
1298     case ID_TREE_DELETE:
1299         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), &hKeyRoot);
1300         if (keyPath == 0 || *keyPath == 0)
1301         {
1302             MessageBeep(MB_ICONHAND);
1303         }
1304         else if (DeleteKey(hWnd, hKeyRoot, keyPath))
1305             DeleteNode(g_pChildWnd->hTreeWnd, 0);
1306         break;
1307     case ID_TREE_EXPORT:
1308         ExportRegistryFile(g_pChildWnd->hTreeWnd);
1309         break;
1310     case ID_TREE_PERMISSIONS:
1311         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), &hKeyRoot);
1312         RegKeyEditPermissions(hWnd, hKeyRoot, NULL, keyPath);
1313         break;
1314     case ID_SWITCH_PANELS:
1315         {
1316             BOOL bShiftDown = GetKeyState(VK_SHIFT) < 0;
1317             HWND hwndItem = GetNextDlgTabItem(g_pChildWnd->hWnd, GetFocus(), bShiftDown);
1318             if (hwndItem == g_pChildWnd->hAddressBarWnd)
1319                 PostMessageW(hwndItem, EM_SETSEL, 0, -1);
1320             SetFocus(hwndItem);
1321         }
1322         break;
1323 
1324     case ID_ADDRESS_FOCUS:
1325         SendMessageW(g_pChildWnd->hAddressBarWnd, EM_SETSEL, 0, -1);
1326         SetFocus(g_pChildWnd->hAddressBarWnd);
1327         break;
1328 
1329     default:
1330         if ((LOWORD(wParam) >= ID_FAVORITES_MIN) && (LOWORD(wParam) <= ID_FAVORITES_MAX))
1331         {
1332             HMENU hMenu;
1333             MENUITEMINFOW mii;
1334             WCHAR szFavorite[512];
1335 
1336             hMenu = GetSubMenu(GetMenu(hWnd), FAVORITES_MENU_POSITION);
1337 
1338             memset(&mii, 0, sizeof(mii));
1339             mii.cbSize = sizeof(mii);
1340             mii.fMask = MIIM_TYPE;
1341             mii.fType = MFT_STRING;
1342             mii.dwTypeData = szFavorite;
1343             mii.cch = ARRAY_SIZE(szFavorite);
1344 
1345             if (GetMenuItemInfo(hMenu, LOWORD(wParam) - ID_FAVORITES_MIN, TRUE, &mii))
1346             {
1347                 ChooseFavorite(szFavorite);
1348             }
1349         }
1350         else if ((LOWORD(wParam) >= ID_TREE_SUGGESTION_MIN) && (LOWORD(wParam) <= ID_TREE_SUGGESTION_MAX))
1351         {
1352             WORD wID = LOWORD(wParam);
1353             LPCWSTR s = Suggestions;
1354             while(wID > ID_TREE_SUGGESTION_MIN)
1355             {
1356                 if (*s)
1357                     s += wcslen(s) + 1;
1358                 wID--;
1359             }
1360             SelectNode(g_pChildWnd->hTreeWnd, s);
1361         }
1362         else
1363         {
1364             result = FALSE;
1365         }
1366         break;
1367     }
1368 
1369     if(hKey)
1370         RegCloseKey(hKey);
1371     return result;
1372 }
1373 
1374 /********************************************************************************
1375  *
1376  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
1377  *
1378  *  PURPOSE:  Processes messages for the main frame window.
1379  *
1380  *  WM_COMMAND  - process the application menu
1381  *  WM_DESTROY  - post a quit message and return
1382  *
1383  */
1384 
1385 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1386 {
1387     RECT rc;
1388     switch (message)
1389     {
1390     case WM_CREATE:
1391         // For now, the Help dialog item is disabled because of lacking of HTML Help support
1392         EnableMenuItem(GetMenu(hWnd), ID_HELP_HELPTOPICS, MF_BYCOMMAND | MF_GRAYED);
1393         GetClientRect(hWnd, &rc);
1394         CreateWindowExW(0, szChildClass, NULL, WS_CHILD | WS_VISIBLE,
1395                         rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
1396                         hWnd, (HMENU)0, hInst, 0);
1397         break;
1398     case WM_COMMAND:
1399         if (!_CmdWndProc(hWnd, message, wParam, lParam))
1400             return DefWindowProcW(hWnd, message, wParam, lParam);
1401         break;
1402     case WM_ACTIVATE:
1403         if (LOWORD(hWnd) && g_pChildWnd)
1404             SetFocus(g_pChildWnd->hWnd);
1405         break;
1406     case WM_SIZE:
1407         resize_frame_client(hWnd);
1408         break;
1409     case WM_TIMER:
1410         break;
1411     case WM_INITMENU:
1412         OnInitMenu(hWnd);
1413         break;
1414     case WM_ENTERMENULOOP:
1415         OnEnterMenuLoop(hWnd);
1416         break;
1417     case WM_EXITMENULOOP:
1418         OnExitMenuLoop(hWnd);
1419         break;
1420     case WM_MENUSELECT:
1421         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
1422         break;
1423     case WM_SYSCOLORCHANGE:
1424         /* Forward WM_SYSCOLORCHANGE to common controls */
1425         SendMessageW(g_pChildWnd->hListWnd, WM_SYSCOLORCHANGE, 0, 0);
1426         SendMessageW(g_pChildWnd->hTreeWnd, WM_SYSCOLORCHANGE, 0, 0);
1427         break;
1428     case WM_DESTROY:
1429         WinHelpW(hWnd, L"regedit", HELP_QUIT, 0);
1430         SaveSettings();
1431         PostQuitMessage(0);
1432     default:
1433         return DefWindowProcW(hWnd, message, wParam, lParam);
1434     }
1435     return 0;
1436 }
1437