regedit: Fix memory leaks in favourites handling.
[wine] / programs / regedit / framewnd.c
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 St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define WIN32_LEAN_AND_MEAN     /* Exclude rarely-used stuff from Windows headers */
22
23 #include <windows.h>
24 #include <tchar.h>
25 #include <commctrl.h>
26 #include <commdlg.h>
27 #include <cderr.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <shellapi.h>
31
32 #include "main.h"
33 #include "regproc.h"
34
35 /********************************************************************************
36  * Global and Local Variables:
37  */
38
39 static WCHAR favoritesKey[] =  {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p','l','e','t','s','\\','R','e','g','E','d','i','t','\\','F','a','v','o','r','i','t','e','s',0};
40 static BOOL bInMenuLoop = FALSE;        /* Tells us if we are in the menu loop */
41 static WCHAR favoriteName[128];
42 static TCHAR searchString[128];
43 static int searchMask = SEARCH_KEYS | SEARCH_VALUES | SEARCH_CONTENT;
44
45 static TCHAR FileNameBuffer[_MAX_PATH];
46 static TCHAR FileTitleBuffer[_MAX_PATH];
47 static TCHAR FilterBuffer[_MAX_PATH];
48
49 /*******************************************************************************
50  * Local module support methods
51  */
52
53 static void resize_frame_rect(HWND hWnd, PRECT prect)
54 {
55     RECT rt;
56     /*
57         if (IsWindowVisible(hToolBar)) {
58                 SendMessage(hToolBar, WM_SIZE, 0, 0);
59                 GetClientRect(hToolBar, &rt);
60                 prect->top = rt.bottom+3;
61                 prect->bottom -= rt.bottom+3;
62         }
63      */
64     if (IsWindowVisible(hStatusBar)) {
65         SetupStatusBar(hWnd, TRUE);
66         GetClientRect(hStatusBar, &rt);
67         prect->bottom -= rt.bottom;
68     }
69     MoveWindow(g_pChildWnd->hWnd, prect->left, prect->top, prect->right, prect->bottom, TRUE);
70 }
71
72 static void resize_frame_client(HWND hWnd)
73 {
74     RECT rect;
75
76     GetClientRect(hWnd, &rect);
77     resize_frame_rect(hWnd, &rect);
78 }
79
80 /********************************************************************************/
81
82 static void OnEnterMenuLoop(HWND hWnd)
83 {
84     int nParts;
85
86     /* Update the status bar pane sizes */
87     nParts = -1;
88     SendMessage(hStatusBar, SB_SETPARTS, 1, (long)&nParts);
89     bInMenuLoop = TRUE;
90     SendMessage(hStatusBar, SB_SETTEXT, (WPARAM)0, (LPARAM)_T(""));
91 }
92
93 static void OnExitMenuLoop(HWND hWnd)
94 {
95     bInMenuLoop = FALSE;
96     /* Update the status bar pane sizes*/
97     SetupStatusBar(hWnd, TRUE);
98     UpdateStatusBar();
99 }
100
101 static void UpdateMenuItems(HMENU hMenu) {
102     HWND hwndTV = g_pChildWnd->hTreeWnd;
103     BOOL bAllowEdit = FALSE;
104     HKEY hRootKey = NULL;
105     LPCTSTR keyName;
106     keyName = GetItemPath(hwndTV, TreeView_GetSelection(hwndTV), &hRootKey);
107     if (GetFocus() != hwndTV || (keyName && *keyName)) { /* can't modify root keys, but allow for their values */
108         bAllowEdit = TRUE;
109     }
110     EnableMenuItem(hMenu, ID_EDIT_FIND, MF_ENABLED | MF_BYCOMMAND);
111     EnableMenuItem(hMenu, ID_EDIT_FINDNEXT, MF_ENABLED | MF_BYCOMMAND);
112     EnableMenuItem(hMenu, ID_EDIT_MODIFY, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
113     EnableMenuItem(hMenu, ID_EDIT_DELETE, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
114     EnableMenuItem(hMenu, ID_EDIT_RENAME, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
115     EnableMenuItem(hMenu, ID_FAVORITES_ADDTOFAVORITES, (hRootKey ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
116     EnableMenuItem(hMenu, ID_FAVORITES_REMOVEFAVORITE, 
117         (GetMenuItemCount(hMenu)>2 ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
118 }
119
120 static void OnInitMenuPopup(HWND hWnd, HMENU hMenu, short wItem)
121 {
122     if (wItem == 3) {
123         HKEY hKey;
124         while(GetMenuItemCount(hMenu)>2)
125             DeleteMenu(hMenu, 2, MF_BYPOSITION);
126         if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
127             0, KEY_READ, &hKey) == ERROR_SUCCESS) {
128             WCHAR namebuf[KEY_MAX_LEN];
129             BYTE valuebuf[4096];
130             int i = 0;
131             BOOL sep = FALSE;
132             DWORD ksize, vsize, type;
133             LONG error;
134             do {
135                 ksize = KEY_MAX_LEN;
136                 vsize = sizeof(valuebuf);
137                 error = RegEnumValueW(hKey, i, namebuf, &ksize, NULL, &type, valuebuf, &vsize);
138                 if (error != ERROR_SUCCESS)
139                     break;
140                 if (type == REG_SZ) {
141                     if (!sep) {
142                         AppendMenuW(hMenu, MF_SEPARATOR, -1, NULL);
143                         sep = TRUE;
144                     }
145                     AppendMenuW(hMenu, MF_STRING, ID_FAVORITE_FIRST+i, namebuf);
146                 }
147                 i++;
148             } while(error == ERROR_SUCCESS);
149             RegCloseKey(hKey);
150         }
151     }
152     UpdateMenuItems(hMenu);
153 }
154
155 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
156 {
157     TCHAR str[100];
158
159     _tcscpy(str, _T(""));
160     if (nFlags & MF_POPUP) {
161         if (hSysMenu != GetMenu(hWnd)) {
162             if (nItemID == 2) nItemID = 5;
163         }
164     }
165     if (LoadString(hInst, nItemID, str, 100)) {
166         /* load appropriate string*/
167         LPTSTR lpsz = str;
168         /* first newline terminates actual string*/
169         lpsz = _tcschr(lpsz, '\n');
170         if (lpsz != NULL)
171             *lpsz = '\0';
172     }
173     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)str);
174 }
175
176 void SetupStatusBar(HWND hWnd, BOOL bResize)
177 {
178     RECT  rc;
179     int nParts;
180     GetClientRect(hWnd, &rc);
181     nParts = rc.right;
182     /*    nParts = -1;*/
183     if (bResize)
184         SendMessage(hStatusBar, WM_SIZE, 0, 0);
185     SendMessage(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
186     UpdateStatusBar();
187 }
188
189 void UpdateStatusBar(void)
190 {
191     LPTSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, TRUE);
192     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)fullPath);
193     HeapFree(GetProcessHeap(), 0, fullPath);
194 }
195
196 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
197 {
198     BOOL vis = IsWindowVisible(hchild);
199     HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
200
201     CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
202     ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
203     resize_frame_client(hWnd);
204 }
205
206 static BOOL CheckCommDlgError(HWND hWnd)
207 {
208     DWORD dwErrorCode = CommDlgExtendedError();
209     switch (dwErrorCode) {
210     case CDERR_DIALOGFAILURE:
211         break;
212     case CDERR_FINDRESFAILURE:
213         break;
214     case CDERR_NOHINSTANCE:
215         break;
216     case CDERR_INITIALIZATION:
217         break;
218     case CDERR_NOHOOK:
219         break;
220     case CDERR_LOCKRESFAILURE:
221         break;
222     case CDERR_NOTEMPLATE:
223         break;
224     case CDERR_LOADRESFAILURE:
225         break;
226     case CDERR_STRUCTSIZE:
227         break;
228     case CDERR_LOADSTRFAILURE:
229         break;
230     case FNERR_BUFFERTOOSMALL:
231         break;
232     case CDERR_MEMALLOCFAILURE:
233         break;
234     case FNERR_INVALIDFILENAME:
235         break;
236     case CDERR_MEMLOCKFAILURE:
237         break;
238     case FNERR_SUBCLASSFAILURE:
239         break;
240     default:
241         break;
242     }
243     return TRUE;
244 }
245
246 static void ExportRegistryFile_StoreSelection(HWND hdlg, OPENFILENAME *pOpenFileName)
247 {
248     if (IsDlgButtonChecked(hdlg, IDC_EXPORT_SELECTED))
249     {
250         INT len = SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_GETTEXTLENGTH, 0, 0);
251         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(TCHAR));
252         SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_GETTEXT, len+1, pOpenFileName->lCustData);
253     }
254     else
255         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR));
256 }
257
258 static UINT CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
259 {
260     static OPENFILENAME* pOpenFileName;
261     OFNOTIFY *pOfNotify;
262     LPTSTR path;
263
264     switch (uiMsg) {
265     case WM_INITDIALOG:
266         pOpenFileName = (OPENFILENAME*)lParam;
267         break;
268     case WM_COMMAND:
269         if (LOWORD(wParam) == IDC_EXPORT_PATH && HIWORD(wParam) == EN_UPDATE)
270             CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, IDC_EXPORT_SELECTED);
271         break;
272     case WM_NOTIFY:
273         pOfNotify = (OFNOTIFY*)lParam;
274         switch (pOfNotify->hdr.code)
275         {
276             case CDN_INITDONE:
277                 path = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
278                 SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_SETTEXT, 0, (LPARAM)path);
279                 HeapFree(GetProcessHeap(), 0, path);
280                 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, pOpenFileName->lCustData ? IDC_EXPORT_SELECTED : IDC_EXPORT_ALL);
281                 break;
282             case CDN_FILEOK:
283                 ExportRegistryFile_StoreSelection(hdlg, pOpenFileName);
284                 break;
285         }
286         break;
287     default:
288         break;
289     }
290     return 0L;
291 }
292
293
294 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAME *pofn)
295 {
296     memset(pofn, 0, sizeof(OPENFILENAME));
297     pofn->lStructSize = sizeof(OPENFILENAME);
298     pofn->hwndOwner = hWnd;
299     pofn->hInstance = hInst;
300
301     if (FilterBuffer[0] == 0)
302         LoadString(hInst, IDS_FILEDIALOG_FILTER, FilterBuffer, _MAX_PATH);
303     pofn->lpstrFilter = FilterBuffer;
304     pofn->nFilterIndex = 1;
305     pofn->lpstrFile = FileNameBuffer;
306     pofn->nMaxFile = _MAX_PATH;
307     pofn->lpstrFileTitle = FileTitleBuffer;
308     pofn->nMaxFileTitle = _MAX_PATH;
309     pofn->Flags = OFN_HIDEREADONLY;
310     /* some other fields may be set by the caller */
311     return TRUE;
312 }
313
314 static BOOL import_registry_filename(LPTSTR filename)
315 {
316     BOOL Success;
317     FILE* reg_file = fopen(filename, "r");
318
319     if(!reg_file)
320         return FALSE;
321
322     Success = import_registry_file(reg_file);
323
324     if(fclose(reg_file) != 0)
325         Success = FALSE;
326
327     return Success;
328 }
329
330 static BOOL ImportRegistryFile(HWND hWnd)
331 {
332     OPENFILENAME ofn;
333     TCHAR title[128];
334
335     InitOpenFileName(hWnd, &ofn);
336     LoadString(hInst, IDS_FILEDIALOG_IMPORT_TITLE, title, COUNT_OF(title));
337     ofn.lpstrTitle = title;
338     if (GetOpenFileName(&ofn)) {
339         if (!import_registry_filename(ofn.lpstrFile)) {
340             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
341             return FALSE;
342         }
343     } else {
344         CheckCommDlgError(hWnd);
345     }
346     RefreshTreeView(g_pChildWnd->hTreeWnd);
347     return TRUE;
348 }
349
350
351 static BOOL ExportRegistryFile(HWND hWnd, BOOL export_branch)
352 {
353     OPENFILENAME ofn;
354     TCHAR ExportKeyPath[_MAX_PATH];
355     TCHAR title[128];
356
357     ExportKeyPath[0] = _T('\0');
358     InitOpenFileName(hWnd, &ofn);
359     LoadString(hInst, IDS_FILEDIALOG_EXPORT_TITLE, title, COUNT_OF(title));
360     ofn.lpstrTitle = title;
361     ofn.lCustData = export_branch;
362     ofn.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
363     ofn.lpfnHook = ExportRegistryFile_OFNHookProc;
364     ofn.lpTemplateName = MAKEINTRESOURCE(IDD_EXPORT_TEMPLATE);
365     if (GetSaveFileName(&ofn)) {
366         BOOL result;
367         result = export_registry_key(ofn.lpstrFile, (LPTSTR)ofn.lCustData);
368         if (!result) {
369             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
370             return FALSE;
371         }
372     } else {
373         CheckCommDlgError(hWnd);
374     }
375     return TRUE;
376 }
377
378 static BOOL PrintRegistryHive(HWND hWnd, LPCWSTR path)
379 {
380 #if 1
381     PRINTDLGW pd;
382
383     ZeroMemory(&pd, sizeof(PRINTDLG));
384     pd.lStructSize = sizeof(PRINTDLG);
385     pd.hwndOwner   = hWnd;
386     pd.hDevMode    = NULL;     /* Don't forget to free or store hDevMode*/
387     pd.hDevNames   = NULL;     /* Don't forget to free or store hDevNames*/
388     pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
389     pd.nCopies     = 1;
390     pd.nFromPage   = 0xFFFF;
391     pd.nToPage     = 0xFFFF;
392     pd.nMinPage    = 1;
393     pd.nMaxPage    = 0xFFFF;
394     if (PrintDlgW(&pd)) {
395         /* GDI calls to render output. */
396         DeleteDC(pd.hDC); /* Delete DC when done.*/
397     }
398 #else
399     HRESULT hResult;
400     PRINTDLGEXW pd;
401
402     hResult = PrintDlgExW(&pd);
403     if (hResult == S_OK) {
404         switch (pd.dwResultAction) {
405         case PD_RESULT_APPLY:
406             /*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. */
407             break;
408         case PD_RESULT_CANCEL:
409             /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
410             break;
411         case PD_RESULT_PRINT:
412             /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
413             break;
414         default:
415             break;
416         }
417     } else {
418         switch (hResult) {
419         case E_OUTOFMEMORY:
420             /*Insufficient memory. */
421             break;
422         case E_INVALIDARG:
423             /* One or more arguments are invalid. */
424             break;
425         case E_POINTER:
426             /*Invalid pointer. */
427             break;
428         case E_HANDLE:
429             /*Invalid handle. */
430             break;
431         case E_FAIL:
432             /*Unspecified error. */
433             break;
434         default:
435             break;
436         }
437         return FALSE;
438     }
439 #endif
440     return TRUE;
441 }
442
443 static BOOL CopyKeyName(HWND hWnd, LPCWSTR keyName)
444 {
445     BOOL result;
446
447     result = OpenClipboard(hWnd);
448     if (result) {
449         result = EmptyClipboard();
450         if (result) {
451             int len = (lstrlenW(keyName)+1)*sizeof(WCHAR);
452             HANDLE hClipData = GlobalAlloc(GHND, len);
453             LPVOID pLoc = GlobalLock(hClipData);
454             lstrcpyW(pLoc, keyName);
455             GlobalUnlock(hClipData);
456             hClipData = SetClipboardData(CF_UNICODETEXT, hClipData);
457
458         } else {
459             /* error emptying clipboard*/
460             /* DWORD dwError = GetLastError(); */
461             ;
462         }
463         if (!CloseClipboard()) {
464             /* error closing clipboard*/
465             /* DWORD dwError = GetLastError(); */
466             ;
467         }
468     } else {
469         /* error opening clipboard*/
470         /* DWORD dwError = GetLastError(); */
471         ;
472     }
473     return result;
474 }
475
476 static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
477 {
478     HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
479             
480     switch(uMsg) {
481         case WM_INITDIALOG:
482             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
483             CheckDlgButton(hwndDlg, IDC_FIND_KEYS, searchMask&SEARCH_KEYS ? BST_CHECKED : BST_UNCHECKED);
484             CheckDlgButton(hwndDlg, IDC_FIND_VALUES, searchMask&SEARCH_VALUES ? BST_CHECKED : BST_UNCHECKED);
485             CheckDlgButton(hwndDlg, IDC_FIND_CONTENT, searchMask&SEARCH_CONTENT ? BST_CHECKED : BST_UNCHECKED);
486             CheckDlgButton(hwndDlg, IDC_FIND_WHOLE, searchMask&SEARCH_WHOLE ? BST_CHECKED : BST_UNCHECKED);
487             SendMessage(hwndValue, EM_SETLIMITTEXT, 127, 0);
488             SetWindowText(hwndValue, searchString);
489             return TRUE;
490         case WM_COMMAND:
491             switch(LOWORD(wParam)) {
492             case IDC_VALUE_NAME:
493                 if (HIWORD(wParam) == EN_UPDATE) {
494                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  GetWindowTextLength(hwndValue)>0);
495                     return TRUE;
496                 }
497                 break;
498             case IDOK:
499                 if (GetWindowTextLength(hwndValue)>0) {
500                     int mask = 0;
501                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_KEYS)) mask |= SEARCH_KEYS;
502                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_VALUES)) mask |= SEARCH_VALUES;
503                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_CONTENT)) mask |= SEARCH_CONTENT;
504                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_WHOLE)) mask |= SEARCH_WHOLE;
505                     searchMask = mask;
506                     GetWindowText(hwndValue, searchString, 128);
507                     EndDialog(hwndDlg, IDOK);
508                 }
509                 return TRUE;
510             case IDCANCEL:
511                 EndDialog(hwndDlg, IDCANCEL);
512                 return TRUE;
513             }
514             break;
515     }
516     return FALSE;
517 }
518                     
519 static INT_PTR CALLBACK addtofavorites_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
520 {
521     HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
522             
523     switch(uMsg) {
524         case WM_INITDIALOG:
525         {
526             HKEY hKeyRoot = NULL;
527             LPWSTR ItemPath = GetItemPathW(g_pChildWnd->hTreeWnd, NULL, &hKeyRoot);
528
529             if(!ItemPath || !*ItemPath)
530                 ItemPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
531             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
532             SetWindowTextW(hwndValue, ItemPath);
533             SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
534             HeapFree(GetProcessHeap(), 0, ItemPath);
535             return TRUE;
536         }
537         case WM_COMMAND:
538             switch(LOWORD(wParam)) {
539             case IDC_VALUE_NAME:
540                 if (HIWORD(wParam) == EN_UPDATE) {
541                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  GetWindowTextLength(hwndValue)>0);
542                     return TRUE;
543                 }
544                 break;
545             case IDOK:
546                 if (GetWindowTextLengthW(hwndValue)>0) {
547                     GetWindowTextW(hwndValue, favoriteName, 128);
548                     EndDialog(hwndDlg, IDOK);
549                 }
550                 return TRUE;
551             case IDCANCEL:
552                 EndDialog(hwndDlg, IDCANCEL);
553                 return TRUE;
554             }
555             break;
556     }
557     return FALSE;
558 }
559                     
560 static INT_PTR CALLBACK removefavorite_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
561 {
562     HWND hwndList = GetDlgItem(hwndDlg, IDC_NAME_LIST);
563             
564     switch(uMsg) {
565         case WM_INITDIALOG: {
566             HKEY hKey;
567             int i = 0;
568             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
569             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
570                 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
571                 WCHAR namebuf[KEY_MAX_LEN];
572                 BYTE valuebuf[4096];
573                 DWORD ksize, vsize, type;
574                 LONG error;
575                 do {
576                     ksize = KEY_MAX_LEN;
577                     vsize = sizeof(valuebuf);
578                     error = RegEnumValueW(hKey, i, namebuf, &ksize, NULL, &type, valuebuf, &vsize);
579                     if (error != ERROR_SUCCESS)
580                         break;
581                     if (type == REG_SZ) {
582                         SendMessageW(hwndList, LB_ADDSTRING, 0, (LPARAM)namebuf);
583                     }
584                     i++;
585                 } while(error == ERROR_SUCCESS);
586                 RegCloseKey(hKey);
587             }
588             else
589                 return FALSE;
590             EnableWindow(GetDlgItem(hwndDlg, IDOK), i != 0);
591             SendMessageW(hwndList, LB_SETCURSEL, 0, 0);
592             return TRUE;
593         }
594         case WM_COMMAND:
595             switch(LOWORD(wParam)) {
596             case IDC_NAME_LIST:
597                 if (HIWORD(wParam) == LBN_SELCHANGE) {
598                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  lParam != -1);
599                     return TRUE;
600                 }
601                 break;
602             case IDOK: {
603                 int pos = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
604                 int len = SendMessage(hwndList, LB_GETTEXTLEN, pos, 0);
605                 if (len>0) {
606                     LPWSTR lpName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
607                     SendMessageW(hwndList, LB_GETTEXT, pos, (LPARAM)lpName);
608                     if (len>127)
609                         lpName[127] = '\0';
610                     lstrcpyW(favoriteName, lpName);
611                     EndDialog(hwndDlg, IDOK);
612                     HeapFree(GetProcessHeap(), 0, lpName);
613                 }
614                 return TRUE;
615             }
616             case IDCANCEL:
617                 EndDialog(hwndDlg, IDCANCEL);
618                 return TRUE;
619             }
620             break;
621     }
622     return FALSE;
623 }
624                     
625 /*******************************************************************************
626  *
627  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
628  *
629  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
630  *
631  */
632 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
633 {
634     HKEY hKeyRoot = 0;
635     LPCTSTR keyPath;
636     LPCTSTR valueName;
637     TCHAR newKey[MAX_NEW_KEY_LEN];
638     DWORD valueType;
639     int curIndex;
640     BOOL firstItem = TRUE;
641
642     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
643
644     if (LOWORD(wParam) >= ID_FAVORITE_FIRST && LOWORD(wParam) <= ID_FAVORITE_LAST) {
645         HKEY hKey;
646         if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
647             0, KEY_READ, &hKey) == ERROR_SUCCESS) {
648             WCHAR namebuf[KEY_MAX_LEN];
649             BYTE valuebuf[4096];
650             DWORD ksize = KEY_MAX_LEN, vsize = sizeof(valuebuf), type = 0;
651             if (RegEnumValueW(hKey, LOWORD(wParam) - ID_FAVORITE_FIRST, namebuf, &ksize, NULL,
652                 &type, valuebuf, &vsize) == ERROR_SUCCESS) {
653                 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET,
654                              (LPARAM) FindPathInTree(g_pChildWnd->hTreeWnd, (WCHAR *)valuebuf) );
655             }
656             RegCloseKey(hKey);
657         }
658         return TRUE;
659     }
660     switch (LOWORD(wParam)) {
661     case ID_REGISTRY_IMPORTREGISTRYFILE:
662         ImportRegistryFile(hWnd);
663         break;
664     case ID_EDIT_EXPORT:
665         ExportRegistryFile(hWnd, TRUE);
666         break;
667     case ID_REGISTRY_EXPORTREGISTRYFILE:
668         ExportRegistryFile(hWnd, FALSE);
669         break;
670     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
671         break;
672     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
673         break;
674     case ID_REGISTRY_PRINT:
675     {
676         const WCHAR empty = 0;
677         PrintRegistryHive(hWnd, &empty);
678         break;
679     }
680     case ID_EDIT_DELETE:
681         if (GetFocus() == g_pChildWnd->hTreeWnd) {
682             WCHAR* keyPathW = GetWideString(keyPath);
683             if (keyPath == 0 || *keyPath == 0) {
684                 MessageBeep(MB_ICONHAND); 
685             } else if (DeleteKey(hWnd, hKeyRoot, keyPathW)) {
686                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
687             }
688             HeapFree(GetProcessHeap(), 0, keyPathW);
689         } else if (GetFocus() == g_pChildWnd->hListWnd) {
690         curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
691         while(curIndex != -1) {
692             WCHAR* valueNameW;
693             WCHAR* keyPathW;
694
695             valueName = GetItemText(g_pChildWnd->hListWnd, curIndex);
696             curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, curIndex, LVNI_SELECTED);
697             if(curIndex != -1 && firstItem) {
698                 if (MessageBoxW(hWnd, MAKEINTRESOURCEW(IDS_DELETE_BOX_TEXT_MULTIPLE),
699                                 MAKEINTRESOURCEW(IDS_DELETE_BOX_TITLE),
700                                 MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
701                     break;
702             }
703             valueNameW = GetWideString(valueName);
704             keyPathW = GetWideString(keyPath);
705             if (!DeleteValue(hWnd, hKeyRoot, keyPathW, valueNameW, curIndex==-1 && firstItem))
706             {
707                 HeapFree(GetProcessHeap(), 0, valueNameW);
708                 HeapFree(GetProcessHeap(), 0, keyPathW);
709                 break;
710             }
711             firstItem = FALSE;
712             HeapFree(GetProcessHeap(), 0, valueNameW);
713             HeapFree(GetProcessHeap(), 0, keyPathW);
714         }
715                 RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
716         }
717         break;
718     case ID_EDIT_MODIFY:
719         valueName = GetValueName(g_pChildWnd->hListWnd);
720         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
721             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, valueName);
722         break;
723     case ID_EDIT_FIND:
724     case ID_EDIT_FINDNEXT:
725     {
726         HTREEITEM hItem;
727         if (LOWORD(wParam) == ID_EDIT_FIND &&
728             DialogBox(0, MAKEINTRESOURCE(IDD_FIND), hWnd, find_dlgproc) != IDOK)
729             break;
730         if (!*searchString)
731             break;
732         hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
733         if (hItem) {
734             int row = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED);
735             HCURSOR hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
736             hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
737             SetCursor(hcursorOld);
738             if (hItem) {
739                 SendMessage( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
740                 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
741                 UpdateWindow(g_pChildWnd->hTreeWnd);
742                 if (row != -1) {
743                     ListView_SetItemState(g_pChildWnd->hListWnd, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
744                     ListView_SetItemState(g_pChildWnd->hListWnd, row, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
745                     SetFocus(g_pChildWnd->hListWnd);
746                 } else {
747                     SetFocus(g_pChildWnd->hTreeWnd);
748                 }
749             } else {
750                 error(hWnd, IDS_NOTFOUND, searchString);
751             }
752         }
753         break;
754     }
755     case ID_EDIT_COPYKEYNAME:
756     {
757         LPWSTR fullPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
758         if (fullPath) {
759             CopyKeyName(hWnd, fullPath);
760             HeapFree(GetProcessHeap(), 0, fullPath);
761         }
762         break;
763     }
764     case ID_EDIT_NEW_KEY:
765     {
766         WCHAR newKeyW[MAX_NEW_KEY_LEN];
767         WCHAR* keyPathW = GetWideString(keyPath);
768         if (CreateKey(hWnd, hKeyRoot, keyPathW, newKeyW)) {
769             if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
770                 StartKeyRename(g_pChildWnd->hTreeWnd);
771         }
772         HeapFree(GetProcessHeap(), 0, keyPathW);
773     }
774         break;
775     case ID_EDIT_NEW_STRINGVALUE:
776         valueType = REG_SZ;
777         goto create_value;
778     case ID_EDIT_NEW_MULTI_STRINGVALUE:
779         valueType = REG_MULTI_SZ;
780         goto create_value;
781     case ID_EDIT_NEW_BINARYVALUE:
782         valueType = REG_BINARY;
783         goto create_value;
784     case ID_EDIT_NEW_DWORDVALUE:
785         valueType = REG_DWORD;
786         /* fall through */
787     create_value:
788         if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey)) {
789             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, newKey);
790             StartValueRename(g_pChildWnd->hListWnd);
791             /* FIXME: start rename */
792         }
793         break;
794     case ID_EDIT_RENAME:
795         if (keyPath == 0 || *keyPath == 0) {
796             MessageBeep(MB_ICONHAND); 
797         } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
798             StartKeyRename(g_pChildWnd->hTreeWnd);
799         } else if (GetFocus() == g_pChildWnd->hListWnd) {
800             StartValueRename(g_pChildWnd->hListWnd);
801         }
802         break;
803     case ID_REGISTRY_PRINTERSETUP:
804         /*PRINTDLG pd;*/
805         /*PrintDlg(&pd);*/
806         /*PAGESETUPDLG psd;*/
807         /*PageSetupDlg(&psd);*/
808         break;
809     case ID_REGISTRY_OPENLOCAL:
810         break;
811     case ID_REGISTRY_EXIT:
812         DestroyWindow(hWnd);
813         break;
814     case ID_FAVORITES_ADDTOFAVORITES:
815     {
816         HKEY hKey;
817         LPWSTR lpKeyPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
818         if (lpKeyPath) {
819             if (DialogBox(0, MAKEINTRESOURCE(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
820                 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
821                     0, NULL, 0, 
822                     KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
823                     RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
824                     RegCloseKey(hKey);
825                 }
826             }
827             HeapFree(GetProcessHeap(), 0, lpKeyPath);
828         }
829         break;
830     }
831     case ID_FAVORITES_REMOVEFAVORITE:
832     {
833         if (DialogBox(0, MAKEINTRESOURCE(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
834             HKEY hKey;
835             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
836                 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
837                 RegDeleteValueW(hKey, favoriteName);
838                 RegCloseKey(hKey);
839             }
840         }
841         break;
842     }
843     case ID_VIEW_REFRESH:
844         RefreshTreeView(g_pChildWnd->hTreeWnd);
845         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
846         break;
847    /*case ID_OPTIONS_TOOLBAR:*/
848    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
849    /*    break;*/
850     case ID_VIEW_STATUSBAR:
851         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
852         break;
853     case ID_HELP_HELPTOPICS:
854     {
855         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
856         WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
857         break;
858     }
859     case ID_HELP_ABOUT:
860         ShowAboutBox(hWnd);
861         break;
862     case ID_VIEW_SPLIT: {
863         RECT rt;
864         POINT pt, pts;
865         GetClientRect(g_pChildWnd->hWnd, &rt);
866         pt.x = rt.left + g_pChildWnd->nSplitPos;
867         pt.y = (rt.bottom / 2);
868         pts = pt;
869         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
870             SetCursorPos(pts.x, pts.y);
871             SetCursor(LoadCursor(0, IDC_SIZEWE));
872             SendMessage(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
873         }
874         return TRUE;
875     }
876     default:
877         return FALSE;
878     }
879
880     return TRUE;
881 }
882
883 /********************************************************************************
884  *
885  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
886  *
887  *  PURPOSE:  Processes messages for the main frame window.
888  *
889  *  WM_COMMAND  - process the application menu
890  *  WM_DESTROY  - post a quit message and return
891  *
892  */
893
894 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
895 {
896     switch (message) {
897     case WM_CREATE:
898         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
899                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
900                        hWnd, NULL, hInst, 0);
901         break;
902     case WM_COMMAND:
903         if (!_CmdWndProc(hWnd, message, wParam, lParam))
904             return DefWindowProc(hWnd, message, wParam, lParam);
905         break;
906     case WM_ACTIVATE:
907         if (LOWORD(hWnd)) 
908             SetFocus(g_pChildWnd->hWnd);
909         break;
910     case WM_SIZE:
911         resize_frame_client(hWnd);
912         break;
913     case WM_TIMER:
914         break;
915     case WM_ENTERMENULOOP:
916         OnEnterMenuLoop(hWnd);
917         break;
918     case WM_EXITMENULOOP:
919         OnExitMenuLoop(hWnd);
920         break;
921     case WM_INITMENUPOPUP:
922         if (!HIWORD(lParam))
923             OnInitMenuPopup(hWnd, (HMENU)wParam, LOWORD(lParam));
924         break;
925     case WM_MENUSELECT:
926         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
927         break;
928     case WM_DESTROY:
929     {
930         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
931         WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
932         PostQuitMessage(0);
933     }
934     default:
935         return DefWindowProc(hWnd, message, wParam, lParam);
936     }
937     return 0;
938 }