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