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