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