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);
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);
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);
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);
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         (void)ListView_EditLabel(g_pChildWnd->hListWnd, iIndex);
889 
890     return TRUE;
891 }
892 
893 static HRESULT
894 InitializeRemoteRegistryPicker(OUT IDsObjectPicker **pDsObjectPicker)
895 {
896     HRESULT hRet;
897 
898     *pDsObjectPicker = NULL;
899 
900     hRet = CoCreateInstance(&CLSID_DsObjectPicker,
901                             NULL,
902                             CLSCTX_INPROC_SERVER,
903                             &IID_IDsObjectPicker,
904                             (LPVOID*)pDsObjectPicker);
905     if (SUCCEEDED(hRet))
906     {
907         DSOP_INIT_INFO InitInfo;
908         static DSOP_SCOPE_INIT_INFO Scopes[] =
909         {
910             {
911                 sizeof(DSOP_SCOPE_INIT_INFO),
912                 DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE | DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE |
913                 DSOP_SCOPE_TYPE_GLOBAL_CATALOG | DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN |
914                 DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN | DSOP_SCOPE_TYPE_WORKGROUP |
915                 DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,
916                 0,
917                 {
918                     {
919                         DSOP_FILTER_COMPUTERS,
920                         0,
921                         0
922                     },
923                     DSOP_DOWNLEVEL_FILTER_COMPUTERS
924                 },
925                 NULL,
926                 NULL,
927                 S_OK
928             },
929         };
930 
931         InitInfo.cbSize = sizeof(InitInfo);
932         InitInfo.pwzTargetComputer = NULL;
933         InitInfo.cDsScopeInfos = ARRAY_SIZE(Scopes);
934         InitInfo.aDsScopeInfos = Scopes;
935         InitInfo.flOptions = 0;
936         InitInfo.cAttributesToFetch = 0;
937         InitInfo.apwzAttributeNames = NULL;
938 
939         hRet = (*pDsObjectPicker)->lpVtbl->Initialize(*pDsObjectPicker,
940                 &InitInfo);
941 
942         if (FAILED(hRet))
943         {
944             /* delete the object picker in case initialization failed! */
945             (*pDsObjectPicker)->lpVtbl->Release(*pDsObjectPicker);
946         }
947     }
948 
949     return hRet;
950 }
951 
952 static HRESULT
953 InvokeRemoteRegistryPickerDialog(IN IDsObjectPicker *pDsObjectPicker,
954                                  IN HWND hwndParent  OPTIONAL,
955                                  OUT LPWSTR lpBuffer,
956                                  IN UINT uSize)
957 {
958     IDataObject *pdo = NULL;
959     HRESULT hRet;
960 
961     hRet = pDsObjectPicker->lpVtbl->InvokeDialog(pDsObjectPicker,
962             hwndParent,
963             &pdo);
964     if (hRet == S_OK)
965     {
966         STGMEDIUM stm;
967         FORMATETC fe;
968 
969         fe.cfFormat = (CLIPFORMAT) RegisterClipboardFormatW(CFSTR_DSOP_DS_SELECTION_LIST);
970         fe.ptd = NULL;
971         fe.dwAspect = DVASPECT_CONTENT;
972         fe.lindex = -1;
973         fe.tymed = TYMED_HGLOBAL;
974 
975         hRet = pdo->lpVtbl->GetData(pdo,
976                                     &fe,
977                                     &stm);
978         if (SUCCEEDED(hRet))
979         {
980             PDS_SELECTION_LIST SelectionList = (PDS_SELECTION_LIST)GlobalLock(stm.hGlobal);
981             if (SelectionList != NULL)
982             {
983                 if (SelectionList->cItems == 1)
984                 {
985                     size_t nlen = wcslen(SelectionList->aDsSelection[0].pwzName);
986                     if (nlen >= uSize)
987                     {
988                         nlen = uSize - 1;
989                     }
990 
991                     memcpy(lpBuffer,
992                            SelectionList->aDsSelection[0].pwzName,
993                            nlen * sizeof(WCHAR));
994 
995                     lpBuffer[nlen] = L'\0';
996                 }
997 
998                 GlobalUnlock(stm.hGlobal);
999             }
1000 
1001             ReleaseStgMedium(&stm);
1002         }
1003 
1004         pdo->lpVtbl->Release(pdo);
1005     }
1006 
1007     return hRet;
1008 }
1009 
1010 static VOID
1011 FreeObjectPicker(IN IDsObjectPicker *pDsObjectPicker)
1012 {
1013     pDsObjectPicker->lpVtbl->Release(pDsObjectPicker);
1014 }
1015 
1016 /*******************************************************************************
1017  *
1018  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
1019  *
1020  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
1021  *
1022  */
1023 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1024 {
1025     HKEY hKeyRoot = 0, hKey = 0;
1026     LPCWSTR keyPath;
1027     LPCWSTR valueName;
1028     BOOL result = TRUE;
1029     REGSAM regsam = KEY_READ;
1030     int item;
1031 
1032     UNREFERENCED_PARAMETER(lParam);
1033     UNREFERENCED_PARAMETER(message);
1034 
1035     switch (LOWORD(wParam))
1036     {
1037     case ID_REGISTRY_LOADHIVE:
1038         LoadHive(hWnd);
1039         return TRUE;
1040     case ID_REGISTRY_UNLOADHIVE:
1041         UnloadHive(hWnd);
1042         return TRUE;
1043     case ID_REGISTRY_IMPORTREGISTRYFILE:
1044         ImportRegistryFile(hWnd);
1045         return TRUE;
1046     case ID_REGISTRY_EXPORTREGISTRYFILE:
1047         ExportRegistryFile(hWnd);
1048         return TRUE;
1049     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
1050     {
1051         IDsObjectPicker *ObjectPicker;
1052         WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1053         HRESULT hRet;
1054 
1055         hRet = CoInitialize(NULL);
1056         if (SUCCEEDED(hRet))
1057         {
1058             hRet = InitializeRemoteRegistryPicker(&ObjectPicker);
1059             if (SUCCEEDED(hRet))
1060             {
1061                 hRet = InvokeRemoteRegistryPickerDialog(ObjectPicker,
1062                                                         hWnd,
1063                                                         szComputerName,
1064                                                         ARRAY_SIZE(szComputerName));
1065                 if (hRet == S_OK)
1066                 {
1067                     /* FIXME - connect to the registry */
1068                 }
1069 
1070                 FreeObjectPicker(ObjectPicker);
1071             }
1072 
1073             CoUninitialize();
1074         }
1075 
1076         return TRUE;
1077     }
1078     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
1079         return TRUE;
1080     case ID_REGISTRY_PRINT:
1081         PrintRegistryHive(hWnd, L"");
1082         return TRUE;
1083     case ID_REGISTRY_EXIT:
1084         DestroyWindow(hWnd);
1085         return TRUE;
1086     case ID_VIEW_STATUSBAR:
1087         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
1088         return TRUE;
1089     case ID_HELP_HELPTOPICS:
1090         WinHelpW(hWnd, L"regedit", HELP_FINDER, 0);
1091         return TRUE;
1092     case ID_HELP_ABOUT:
1093         ShowAboutBox(hWnd);
1094         return TRUE;
1095     case ID_VIEW_SPLIT:
1096     {
1097         RECT rt;
1098         POINT pt, pts;
1099         GetClientRect(g_pChildWnd->hWnd, &rt);
1100         pt.x = rt.left + g_pChildWnd->nSplitPos;
1101         pt.y = (rt.bottom / 2);
1102         pts = pt;
1103         if(ClientToScreen(g_pChildWnd->hWnd, &pts))
1104         {
1105             SetCursorPos(pts.x, pts.y);
1106             SetCursor(LoadCursorW(0, IDC_SIZEWE));
1107             SendMessageW(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
1108         }
1109         return TRUE;
1110     }
1111     case ID_EDIT_RENAME:
1112     case ID_EDIT_MODIFY:
1113     case ID_EDIT_MODIFY_BIN:
1114     case ID_EDIT_DELETE:
1115         regsam |= KEY_WRITE;
1116         break;
1117     }
1118 
1119     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1120     valueName = GetValueName(g_pChildWnd->hListWnd, -1);
1121     if (keyPath)
1122     {
1123         if (RegOpenKeyExW(hKeyRoot, keyPath, 0, regsam, &hKey) != ERROR_SUCCESS)
1124             hKey = 0;
1125     }
1126 
1127     switch (LOWORD(wParam))
1128     {
1129     case ID_EDIT_MODIFY:
1130         if (valueName && ModifyValue(hWnd, hKey, valueName, FALSE))
1131             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
1132         break;
1133     case ID_EDIT_MODIFY_BIN:
1134         if (valueName && ModifyValue(hWnd, hKey, valueName, TRUE))
1135             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
1136         break;
1137     case ID_EDIT_RENAME:
1138         if (GetFocus() == g_pChildWnd->hListWnd)
1139         {
1140             if(ListView_GetSelectedCount(g_pChildWnd->hListWnd) == 1)
1141             {
1142                 item = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
1143                 if(item > -1)
1144                 {
1145                     (void)ListView_EditLabel(g_pChildWnd->hListWnd, item);
1146                 }
1147             }
1148         }
1149         else if (GetFocus() == g_pChildWnd->hTreeWnd)
1150         {
1151             /* Get focused entry of treeview (if any) */
1152             HTREEITEM hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
1153             if (hItem != NULL)
1154                 (void)TreeView_EditLabel(g_pChildWnd->hTreeWnd, hItem);
1155         }
1156         break;
1157     case ID_EDIT_DELETE:
1158     {
1159         if (GetFocus() == g_pChildWnd->hListWnd && hKey)
1160         {
1161             UINT nSelected = ListView_GetSelectedCount(g_pChildWnd->hListWnd);
1162             if(nSelected >= 1)
1163             {
1164                 WCHAR msg[128], caption[128];
1165                 LoadStringW(hInst, IDS_QUERY_DELETE_CONFIRM, caption, ARRAY_SIZE(caption));
1166                 LoadStringW(hInst, (nSelected == 1 ? IDS_QUERY_DELETE_ONE : IDS_QUERY_DELETE_MORE), msg, ARRAY_SIZE(msg));
1167                 if(MessageBoxW(g_pChildWnd->hWnd, msg, caption, MB_ICONQUESTION | MB_YESNO) == IDYES)
1168                 {
1169                     int ni, errs;
1170 
1171                     item = -1;
1172                     errs = 0;
1173                     while((ni = ListView_GetNextItem(g_pChildWnd->hListWnd, item, LVNI_SELECTED)) > -1)
1174                     {
1175                         valueName = GetValueName(g_pChildWnd->hListWnd, item);
1176                         if(RegDeleteValueW(hKey, valueName) != ERROR_SUCCESS)
1177                         {
1178                             errs++;
1179                         }
1180                         item = ni;
1181                     }
1182 
1183                     RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
1184                     if(errs > 0)
1185                     {
1186                         LoadStringW(hInst, IDS_ERR_DELVAL_CAPTION, caption, ARRAY_SIZE(caption));
1187                         LoadStringW(hInst, IDS_ERR_DELETEVALUE, msg, ARRAY_SIZE(msg));
1188                         MessageBoxW(g_pChildWnd->hWnd, msg, caption, MB_ICONSTOP);
1189                     }
1190                 }
1191             }
1192         }
1193         else if (GetFocus() == g_pChildWnd->hTreeWnd)
1194         {
1195             if (keyPath == NULL || *keyPath == UNICODE_NULL)
1196             {
1197                 MessageBeep(MB_ICONHAND);
1198             }
1199             else if (DeleteKey(hWnd, hKeyRoot, keyPath))
1200             {
1201                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
1202                 RefreshTreeView(g_pChildWnd->hTreeWnd);
1203             }
1204         }
1205         break;
1206     }
1207     case ID_EDIT_NEW_STRINGVALUE:
1208         CreateNewValue(hKeyRoot, keyPath, REG_SZ);
1209         break;
1210     case ID_EDIT_NEW_BINARYVALUE:
1211         CreateNewValue(hKeyRoot, keyPath, REG_BINARY);
1212         break;
1213     case ID_EDIT_NEW_DWORDVALUE:
1214         CreateNewValue(hKeyRoot, keyPath, REG_DWORD);
1215         break;
1216     case ID_EDIT_NEW_MULTISTRINGVALUE:
1217         CreateNewValue(hKeyRoot, keyPath, REG_MULTI_SZ);
1218         break;
1219     case ID_EDIT_NEW_EXPANDABLESTRINGVALUE:
1220         CreateNewValue(hKeyRoot, keyPath, REG_EXPAND_SZ);
1221         break;
1222     case ID_EDIT_FIND:
1223         FindDialog(hWnd);
1224         break;
1225     case ID_EDIT_FINDNEXT:
1226         FindNextMessageBox(hWnd);
1227         break;
1228     case ID_EDIT_COPYKEYNAME:
1229         CopyKeyName(hWnd, hKeyRoot, keyPath);
1230         break;
1231     case ID_EDIT_PERMISSIONS:
1232         RegKeyEditPermissions(hWnd, hKeyRoot, NULL, keyPath);
1233         break;
1234     case ID_REGISTRY_PRINTERSETUP:
1235         /*PRINTDLG pd;*/
1236         /*PrintDlg(&pd);*/
1237         /*PAGESETUPDLG psd;*/
1238         /*PageSetupDlg(&psd);*/
1239         break;
1240     case ID_REGISTRY_OPENLOCAL:
1241         break;
1242 
1243     case ID_VIEW_REFRESH:
1244         RefreshTreeView(g_pChildWnd->hTreeWnd);
1245         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1246         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
1247         break;
1248         /*case ID_OPTIONS_TOOLBAR:*/
1249         /*	toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
1250         /*    break;*/
1251     case ID_EDIT_NEW_KEY:
1252         CreateNewKey(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
1253         break;
1254 
1255     case ID_TREE_EXPANDBRANCH:
1256         TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_EXPAND);
1257         break;
1258     case ID_TREE_COLLAPSEBRANCH:
1259         TreeView_Expand(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), TVE_COLLAPSE);
1260         break;
1261     case ID_TREE_RENAME:
1262         SetFocus(g_pChildWnd->hTreeWnd);
1263         TreeView_EditLabel(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
1264         break;
1265     case ID_TREE_DELETE:
1266         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), &hKeyRoot);
1267         if (keyPath == 0 || *keyPath == 0)
1268         {
1269             MessageBeep(MB_ICONHAND);
1270         }
1271         else if (DeleteKey(hWnd, hKeyRoot, keyPath))
1272             DeleteNode(g_pChildWnd->hTreeWnd, 0);
1273         break;
1274     case ID_TREE_EXPORT:
1275         ExportRegistryFile(g_pChildWnd->hTreeWnd);
1276         break;
1277     case ID_TREE_PERMISSIONS:
1278         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd), &hKeyRoot);
1279         RegKeyEditPermissions(hWnd, hKeyRoot, NULL, keyPath);
1280         break;
1281     case ID_SWITCH_PANELS:
1282         {
1283             BOOL bShiftDown = GetKeyState(VK_SHIFT) < 0;
1284             HWND hwndItem = GetNextDlgTabItem(g_pChildWnd->hWnd, GetFocus(), bShiftDown);
1285             if (hwndItem == g_pChildWnd->hAddressBarWnd)
1286                 PostMessageW(hwndItem, EM_SETSEL, 0, -1);
1287             SetFocus(hwndItem);
1288         }
1289         break;
1290 
1291     case ID_ADDRESS_FOCUS:
1292         SendMessageW(g_pChildWnd->hAddressBarWnd, EM_SETSEL, 0, -1);
1293         SetFocus(g_pChildWnd->hAddressBarWnd);
1294         break;
1295 
1296     default:
1297         if ((LOWORD(wParam) >= ID_FAVORITES_MIN) && (LOWORD(wParam) <= ID_FAVORITES_MAX))
1298         {
1299             HMENU hMenu;
1300             MENUITEMINFOW mii;
1301             WCHAR szFavorite[512];
1302 
1303             hMenu = GetSubMenu(GetMenu(hWnd), FAVORITES_MENU_POSITION);
1304 
1305             memset(&mii, 0, sizeof(mii));
1306             mii.cbSize = sizeof(mii);
1307             mii.fMask = MIIM_TYPE;
1308             mii.fType = MFT_STRING;
1309             mii.dwTypeData = szFavorite;
1310             mii.cch = ARRAY_SIZE(szFavorite);
1311 
1312             if (GetMenuItemInfo(hMenu, LOWORD(wParam) - ID_FAVORITES_MIN, TRUE, &mii))
1313             {
1314                 ChooseFavorite(szFavorite);
1315             }
1316         }
1317         else if ((LOWORD(wParam) >= ID_TREE_SUGGESTION_MIN) && (LOWORD(wParam) <= ID_TREE_SUGGESTION_MAX))
1318         {
1319             WORD wID = LOWORD(wParam);
1320             LPCWSTR s = Suggestions;
1321             while(wID > ID_TREE_SUGGESTION_MIN)
1322             {
1323                 if (*s)
1324                     s += wcslen(s) + 1;
1325                 wID--;
1326             }
1327             SelectNode(g_pChildWnd->hTreeWnd, s);
1328         }
1329         else
1330         {
1331             result = FALSE;
1332         }
1333         break;
1334     }
1335 
1336     if(hKey)
1337         RegCloseKey(hKey);
1338     return result;
1339 }
1340 
1341 /********************************************************************************
1342  *
1343  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
1344  *
1345  *  PURPOSE:  Processes messages for the main frame window.
1346  *
1347  *  WM_COMMAND  - process the application menu
1348  *  WM_DESTROY  - post a quit message and return
1349  *
1350  */
1351 
1352 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1353 {
1354     RECT rc;
1355     switch (message)
1356     {
1357     case WM_CREATE:
1358         // For now, the Help dialog item is disabled because of lacking of HTML Help support
1359         EnableMenuItem(GetMenu(hWnd), ID_HELP_HELPTOPICS, MF_BYCOMMAND | MF_GRAYED);
1360         GetClientRect(hWnd, &rc);
1361         CreateWindowExW(0, szChildClass, NULL, WS_CHILD | WS_VISIBLE,
1362                         rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
1363                         hWnd, (HMENU)0, hInst, 0);
1364         break;
1365     case WM_COMMAND:
1366         if (!_CmdWndProc(hWnd, message, wParam, lParam))
1367             return DefWindowProcW(hWnd, message, wParam, lParam);
1368         break;
1369     case WM_ACTIVATE:
1370         if (LOWORD(hWnd) && g_pChildWnd)
1371             SetFocus(g_pChildWnd->hWnd);
1372         break;
1373     case WM_SIZE:
1374         resize_frame_client(hWnd);
1375         break;
1376     case WM_TIMER:
1377         break;
1378     case WM_INITMENU:
1379         OnInitMenu(hWnd);
1380         break;
1381     case WM_ENTERMENULOOP:
1382         OnEnterMenuLoop(hWnd);
1383         break;
1384     case WM_EXITMENULOOP:
1385         OnExitMenuLoop(hWnd);
1386         break;
1387     case WM_MENUSELECT:
1388         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
1389         break;
1390     case WM_SYSCOLORCHANGE:
1391         /* Forward WM_SYSCOLORCHANGE to common controls */
1392         SendMessageW(g_pChildWnd->hListWnd, WM_SYSCOLORCHANGE, 0, 0);
1393         SendMessageW(g_pChildWnd->hTreeWnd, WM_SYSCOLORCHANGE, 0, 0);
1394         break;
1395     case WM_DESTROY:
1396         WinHelpW(hWnd, L"regedit", HELP_QUIT, 0);
1397         SaveSettings();
1398         PostQuitMessage(0);
1399     default:
1400         return DefWindowProcW(hWnd, message, wParam, lParam);
1401     }
1402     return 0;
1403 }
1404