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