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