regedit: Convert value editing to unicode.
[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 TCHAR FileNameBuffer[_MAX_PATH];
47 static TCHAR FileTitleBuffer[_MAX_PATH];
48 static TCHAR 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                 SendMessage(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, (WPARAM)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 = GetItemPathW(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 = GetItemFullPathW(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, OPENFILENAME *pOpenFileName)
251 {
252     if (IsDlgButtonChecked(hdlg, IDC_EXPORT_SELECTED))
253     {
254         INT len = SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_GETTEXTLENGTH, 0, 0);
255         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(TCHAR));
256         SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_GETTEXT, len+1, pOpenFileName->lCustData);
257     }
258     else
259         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR));
260 }
261
262 static UINT CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
263 {
264     static OPENFILENAME* pOpenFileName;
265     OFNOTIFY *pOfNotify;
266     LPTSTR path;
267
268     switch (uiMsg) {
269     case WM_INITDIALOG:
270         pOpenFileName = (OPENFILENAME*)lParam;
271         break;
272     case WM_COMMAND:
273         if (LOWORD(wParam) == IDC_EXPORT_PATH && HIWORD(wParam) == EN_UPDATE)
274             CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, IDC_EXPORT_SELECTED);
275         break;
276     case WM_NOTIFY:
277         pOfNotify = (OFNOTIFY*)lParam;
278         switch (pOfNotify->hdr.code)
279         {
280             case CDN_INITDONE:
281                 path = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
282                 SendDlgItemMessage(hdlg, IDC_EXPORT_PATH, WM_SETTEXT, 0, (LPARAM)path);
283                 HeapFree(GetProcessHeap(), 0, path);
284                 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, pOpenFileName->lCustData ? IDC_EXPORT_SELECTED : IDC_EXPORT_ALL);
285                 break;
286             case CDN_FILEOK:
287                 ExportRegistryFile_StoreSelection(hdlg, pOpenFileName);
288                 break;
289         }
290         break;
291     default:
292         break;
293     }
294     return 0L;
295 }
296
297
298 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAME *pofn)
299 {
300     memset(pofn, 0, sizeof(OPENFILENAME));
301     pofn->lStructSize = sizeof(OPENFILENAME);
302     pofn->hwndOwner = hWnd;
303     pofn->hInstance = hInst;
304
305     if (FilterBuffer[0] == 0)
306         LoadString(hInst, IDS_FILEDIALOG_FILTER, FilterBuffer, _MAX_PATH);
307     pofn->lpstrFilter = FilterBuffer;
308     pofn->nFilterIndex = 1;
309     pofn->lpstrFile = FileNameBuffer;
310     pofn->nMaxFile = _MAX_PATH;
311     pofn->lpstrFileTitle = FileTitleBuffer;
312     pofn->nMaxFileTitle = _MAX_PATH;
313     pofn->Flags = OFN_HIDEREADONLY;
314     /* some other fields may be set by the caller */
315     return TRUE;
316 }
317
318 static BOOL import_registry_filename(LPTSTR filename)
319 {
320     BOOL Success;
321     FILE* reg_file = fopen(filename, "r");
322
323     if(!reg_file)
324         return FALSE;
325
326     Success = import_registry_file(reg_file);
327
328     if(fclose(reg_file) != 0)
329         Success = FALSE;
330
331     return Success;
332 }
333
334 static BOOL ImportRegistryFile(HWND hWnd)
335 {
336     OPENFILENAME ofn;
337     TCHAR title[128];
338
339     InitOpenFileName(hWnd, &ofn);
340     LoadString(hInst, IDS_FILEDIALOG_IMPORT_TITLE, title, COUNT_OF(title));
341     ofn.lpstrTitle = title;
342     if (GetOpenFileName(&ofn)) {
343         if (!import_registry_filename(ofn.lpstrFile)) {
344             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
345             return FALSE;
346         }
347     } else {
348         CheckCommDlgError(hWnd);
349     }
350     RefreshTreeView(g_pChildWnd->hTreeWnd);
351     return TRUE;
352 }
353
354
355 static BOOL ExportRegistryFile(HWND hWnd, BOOL export_branch)
356 {
357     OPENFILENAME ofn;
358     TCHAR ExportKeyPath[_MAX_PATH];
359     TCHAR title[128];
360
361     ExportKeyPath[0] = _T('\0');
362     InitOpenFileName(hWnd, &ofn);
363     LoadString(hInst, IDS_FILEDIALOG_EXPORT_TITLE, title, COUNT_OF(title));
364     ofn.lpstrTitle = title;
365     ofn.lCustData = export_branch;
366     ofn.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
367     ofn.lpfnHook = ExportRegistryFile_OFNHookProc;
368     ofn.lpTemplateName = MAKEINTRESOURCE(IDD_EXPORT_TEMPLATE);
369     if (GetSaveFileName(&ofn)) {
370         BOOL result;
371         result = export_registry_key(ofn.lpstrFile, (LPTSTR)ofn.lCustData);
372         if (!result) {
373             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
374             return FALSE;
375         }
376     } else {
377         CheckCommDlgError(hWnd);
378     }
379     return TRUE;
380 }
381
382 static BOOL PrintRegistryHive(HWND hWnd, LPCWSTR path)
383 {
384 #if 1
385     PRINTDLGW pd;
386
387     ZeroMemory(&pd, sizeof(PRINTDLG));
388     pd.lStructSize = sizeof(PRINTDLG);
389     pd.hwndOwner   = hWnd;
390     pd.hDevMode    = NULL;     /* Don't forget to free or store hDevMode*/
391     pd.hDevNames   = NULL;     /* Don't forget to free or store hDevNames*/
392     pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
393     pd.nCopies     = 1;
394     pd.nFromPage   = 0xFFFF;
395     pd.nToPage     = 0xFFFF;
396     pd.nMinPage    = 1;
397     pd.nMaxPage    = 0xFFFF;
398     if (PrintDlgW(&pd)) {
399         /* GDI calls to render output. */
400         DeleteDC(pd.hDC); /* Delete DC when done.*/
401     }
402 #else
403     HRESULT hResult;
404     PRINTDLGEXW pd;
405
406     hResult = PrintDlgExW(&pd);
407     if (hResult == S_OK) {
408         switch (pd.dwResultAction) {
409         case PD_RESULT_APPLY:
410             /*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. */
411             break;
412         case PD_RESULT_CANCEL:
413             /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
414             break;
415         case PD_RESULT_PRINT:
416             /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
417             break;
418         default:
419             break;
420         }
421     } else {
422         switch (hResult) {
423         case E_OUTOFMEMORY:
424             /*Insufficient memory. */
425             break;
426         case E_INVALIDARG:
427             /* One or more arguments are invalid. */
428             break;
429         case E_POINTER:
430             /*Invalid pointer. */
431             break;
432         case E_HANDLE:
433             /*Invalid handle. */
434             break;
435         case E_FAIL:
436             /*Unspecified error. */
437             break;
438         default:
439             break;
440         }
441         return FALSE;
442     }
443 #endif
444     return TRUE;
445 }
446
447 static BOOL CopyKeyName(HWND hWnd, LPCWSTR keyName)
448 {
449     BOOL result;
450
451     result = OpenClipboard(hWnd);
452     if (result) {
453         result = EmptyClipboard();
454         if (result) {
455             int len = (lstrlenW(keyName)+1)*sizeof(WCHAR);
456             HANDLE hClipData = GlobalAlloc(GHND, len);
457             LPVOID pLoc = GlobalLock(hClipData);
458             lstrcpyW(pLoc, keyName);
459             GlobalUnlock(hClipData);
460             hClipData = SetClipboardData(CF_UNICODETEXT, hClipData);
461
462         } else {
463             /* error emptying clipboard*/
464             /* DWORD dwError = GetLastError(); */
465             ;
466         }
467         if (!CloseClipboard()) {
468             /* error closing clipboard*/
469             /* DWORD dwError = GetLastError(); */
470             ;
471         }
472     } else {
473         /* error opening clipboard*/
474         /* DWORD dwError = GetLastError(); */
475         ;
476     }
477     return result;
478 }
479
480 static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
481 {
482     HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
483             
484     switch(uMsg) {
485         case WM_INITDIALOG:
486             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
487             CheckDlgButton(hwndDlg, IDC_FIND_KEYS, searchMask&SEARCH_KEYS ? BST_CHECKED : BST_UNCHECKED);
488             CheckDlgButton(hwndDlg, IDC_FIND_VALUES, searchMask&SEARCH_VALUES ? BST_CHECKED : BST_UNCHECKED);
489             CheckDlgButton(hwndDlg, IDC_FIND_CONTENT, searchMask&SEARCH_CONTENT ? BST_CHECKED : BST_UNCHECKED);
490             CheckDlgButton(hwndDlg, IDC_FIND_WHOLE, searchMask&SEARCH_WHOLE ? BST_CHECKED : BST_UNCHECKED);
491             SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
492             SetWindowTextW(hwndValue, searchString);
493             return TRUE;
494         case WM_COMMAND:
495             switch(LOWORD(wParam)) {
496             case IDC_VALUE_NAME:
497                 if (HIWORD(wParam) == EN_UPDATE) {
498                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  GetWindowTextLengthW(hwndValue)>0);
499                     return TRUE;
500                 }
501                 break;
502             case IDOK:
503                 if (GetWindowTextLengthW(hwndValue)>0) {
504                     int mask = 0;
505                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_KEYS)) mask |= SEARCH_KEYS;
506                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_VALUES)) mask |= SEARCH_VALUES;
507                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_CONTENT)) mask |= SEARCH_CONTENT;
508                     if (IsDlgButtonChecked(hwndDlg, IDC_FIND_WHOLE)) mask |= SEARCH_WHOLE;
509                     searchMask = mask;
510                     GetWindowTextW(hwndValue, searchString, 128);
511                     EndDialog(hwndDlg, IDOK);
512                 }
513                 return TRUE;
514             case IDCANCEL:
515                 EndDialog(hwndDlg, IDCANCEL);
516                 return TRUE;
517             }
518             break;
519     }
520     return FALSE;
521 }
522                     
523 static INT_PTR CALLBACK addtofavorites_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
524 {
525     HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
526             
527     switch(uMsg) {
528         case WM_INITDIALOG:
529         {
530             HKEY hKeyRoot = NULL;
531             LPWSTR ItemPath = GetItemPathW(g_pChildWnd->hTreeWnd, NULL, &hKeyRoot);
532
533             if(!ItemPath || !*ItemPath)
534                 ItemPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
535             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
536             SetWindowTextW(hwndValue, ItemPath);
537             SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
538             HeapFree(GetProcessHeap(), 0, ItemPath);
539             return TRUE;
540         }
541         case WM_COMMAND:
542             switch(LOWORD(wParam)) {
543             case IDC_VALUE_NAME:
544                 if (HIWORD(wParam) == EN_UPDATE) {
545                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  GetWindowTextLength(hwndValue)>0);
546                     return TRUE;
547                 }
548                 break;
549             case IDOK:
550                 if (GetWindowTextLengthW(hwndValue)>0) {
551                     GetWindowTextW(hwndValue, favoriteName, 128);
552                     EndDialog(hwndDlg, IDOK);
553                 }
554                 return TRUE;
555             case IDCANCEL:
556                 EndDialog(hwndDlg, IDCANCEL);
557                 return TRUE;
558             }
559             break;
560     }
561     return FALSE;
562 }
563                     
564 static INT_PTR CALLBACK removefavorite_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
565 {
566     HWND hwndList = GetDlgItem(hwndDlg, IDC_NAME_LIST);
567             
568     switch(uMsg) {
569         case WM_INITDIALOG: {
570             HKEY hKey;
571             int i = 0;
572             EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
573             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
574                 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
575                 WCHAR namebuf[KEY_MAX_LEN];
576                 BYTE valuebuf[4096];
577                 DWORD ksize, vsize, type;
578                 LONG error;
579                 do {
580                     ksize = KEY_MAX_LEN;
581                     vsize = sizeof(valuebuf);
582                     error = RegEnumValueW(hKey, i, namebuf, &ksize, NULL, &type, valuebuf, &vsize);
583                     if (error != ERROR_SUCCESS)
584                         break;
585                     if (type == REG_SZ) {
586                         SendMessageW(hwndList, LB_ADDSTRING, 0, (LPARAM)namebuf);
587                     }
588                     i++;
589                 } while(error == ERROR_SUCCESS);
590                 RegCloseKey(hKey);
591             }
592             else
593                 return FALSE;
594             EnableWindow(GetDlgItem(hwndDlg, IDOK), i != 0);
595             SendMessageW(hwndList, LB_SETCURSEL, 0, 0);
596             return TRUE;
597         }
598         case WM_COMMAND:
599             switch(LOWORD(wParam)) {
600             case IDC_NAME_LIST:
601                 if (HIWORD(wParam) == LBN_SELCHANGE) {
602                     EnableWindow(GetDlgItem(hwndDlg, IDOK),  lParam != -1);
603                     return TRUE;
604                 }
605                 break;
606             case IDOK: {
607                 int pos = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
608                 int len = SendMessage(hwndList, LB_GETTEXTLEN, pos, 0);
609                 if (len>0) {
610                     LPWSTR lpName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
611                     SendMessageW(hwndList, LB_GETTEXT, pos, (LPARAM)lpName);
612                     if (len>127)
613                         lpName[127] = '\0';
614                     lstrcpyW(favoriteName, lpName);
615                     EndDialog(hwndDlg, IDOK);
616                     HeapFree(GetProcessHeap(), 0, lpName);
617                 }
618                 return TRUE;
619             }
620             case IDCANCEL:
621                 EndDialog(hwndDlg, IDCANCEL);
622                 return TRUE;
623             }
624             break;
625     }
626     return FALSE;
627 }
628                     
629 /*******************************************************************************
630  *
631  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
632  *
633  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
634  *
635  */
636 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
637 {
638     HKEY hKeyRoot = 0;
639     LPCTSTR valueName;
640     DWORD valueType;
641     int curIndex;
642     BOOL firstItem = TRUE;
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* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
683             if (keyPath == 0 || *keyPath == 0) {
684                 MessageBeep(MB_ICONHAND);
685             } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) {
686                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
687             }
688             HeapFree(GetProcessHeap(), 0, keyPath);
689         } else if (GetFocus() == g_pChildWnd->hListWnd) {
690         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
691         curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
692         while(curIndex != -1) {
693             WCHAR* valueNameW;
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             if (!DeleteValue(hWnd, hKeyRoot, keyPath, valueNameW, curIndex==-1 && firstItem))
705             {
706                 HeapFree(GetProcessHeap(), 0, valueNameW);
707                 break;
708             }
709             firstItem = FALSE;
710             HeapFree(GetProcessHeap(), 0, valueNameW);
711         }
712         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
713         HeapFree(GetProcessHeap(), 0, keyPath);
714         }
715         break;
716     case ID_EDIT_MODIFY:
717     {
718         LPCWSTR valueName = GetValueName(g_pChildWnd->hListWnd);
719         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
720         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
721             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, valueName);
722         HeapFree(GetProcessHeap(), 0, keyPath);
723         break;
724     }
725     case ID_EDIT_FIND:
726     case ID_EDIT_FINDNEXT:
727     {
728         HTREEITEM hItem;
729         if (LOWORD(wParam) == ID_EDIT_FIND &&
730             DialogBox(0, MAKEINTRESOURCE(IDD_FIND), hWnd, find_dlgproc) != IDOK)
731             break;
732         if (!*searchString)
733             break;
734         hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
735         if (hItem) {
736             int row = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED);
737             HCURSOR hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
738             hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
739             SetCursor(hcursorOld);
740             if (hItem) {
741                 SendMessage( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
742                 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
743                 UpdateWindow(g_pChildWnd->hTreeWnd);
744                 if (row != -1) {
745                     ListView_SetItemState(g_pChildWnd->hListWnd, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
746                     ListView_SetItemState(g_pChildWnd->hListWnd, row, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
747                     SetFocus(g_pChildWnd->hListWnd);
748                 } else {
749                     SetFocus(g_pChildWnd->hTreeWnd);
750                 }
751             } else {
752                 CHAR* searchStringA = GetMultiByteString(searchString);
753                 error(hWnd, IDS_NOTFOUND, searchStringA);
754                 HeapFree(GetProcessHeap(), 0, searchStringA);
755             }
756         }
757         break;
758     }
759     case ID_EDIT_COPYKEYNAME:
760     {
761         LPWSTR fullPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
762         if (fullPath) {
763             CopyKeyName(hWnd, fullPath);
764             HeapFree(GetProcessHeap(), 0, fullPath);
765         }
766         break;
767     }
768     case ID_EDIT_NEW_KEY:
769     {
770         WCHAR newKeyW[MAX_NEW_KEY_LEN];
771         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
772         if (CreateKey(hWnd, hKeyRoot, keyPath, newKeyW)) {
773             if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
774                 StartKeyRename(g_pChildWnd->hTreeWnd);
775         }
776         HeapFree(GetProcessHeap(), 0, keyPath);
777     }
778         break;
779     case ID_EDIT_NEW_STRINGVALUE:
780         valueType = REG_SZ;
781         goto create_value;
782     case ID_EDIT_NEW_MULTI_STRINGVALUE:
783         valueType = REG_MULTI_SZ;
784         goto create_value;
785     case ID_EDIT_NEW_BINARYVALUE:
786         valueType = REG_BINARY;
787         goto create_value;
788     case ID_EDIT_NEW_DWORDVALUE:
789         valueType = REG_DWORD;
790         /* fall through */
791     create_value:
792     {
793         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
794         WCHAR newKey[MAX_NEW_KEY_LEN];
795         if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey)) {
796             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, newKey);
797             StartValueRename(g_pChildWnd->hListWnd);
798             /* FIXME: start rename */
799         }
800         HeapFree(GetProcessHeap(), 0, keyPath);
801     }
802         break;
803     case ID_EDIT_RENAME:
804     {
805         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
806         if (keyPath == 0 || *keyPath == 0) {
807             MessageBeep(MB_ICONHAND);
808         } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
809             StartKeyRename(g_pChildWnd->hTreeWnd);
810         } else if (GetFocus() == g_pChildWnd->hListWnd) {
811             StartValueRename(g_pChildWnd->hListWnd);
812         }
813         HeapFree(GetProcessHeap(), 0, keyPath);
814     }
815         break;
816     case ID_REGISTRY_PRINTERSETUP:
817         /*PRINTDLG pd;*/
818         /*PrintDlg(&pd);*/
819         /*PAGESETUPDLG psd;*/
820         /*PageSetupDlg(&psd);*/
821         break;
822     case ID_REGISTRY_OPENLOCAL:
823         break;
824     case ID_REGISTRY_EXIT:
825         DestroyWindow(hWnd);
826         break;
827     case ID_FAVORITES_ADDTOFAVORITES:
828     {
829         HKEY hKey;
830         LPWSTR lpKeyPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
831         if (lpKeyPath) {
832             if (DialogBox(0, MAKEINTRESOURCE(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
833                 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
834                     0, NULL, 0, 
835                     KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
836                     RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
837                     RegCloseKey(hKey);
838                 }
839             }
840             HeapFree(GetProcessHeap(), 0, lpKeyPath);
841         }
842         break;
843     }
844     case ID_FAVORITES_REMOVEFAVORITE:
845     {
846         if (DialogBox(0, MAKEINTRESOURCE(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
847             HKEY hKey;
848             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
849                 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
850                 RegDeleteValueW(hKey, favoriteName);
851                 RegCloseKey(hKey);
852             }
853         }
854         break;
855     }
856     case ID_VIEW_REFRESH:
857     {
858         WCHAR* keyPath = GetItemPathW(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
859         RefreshTreeView(g_pChildWnd->hTreeWnd);
860         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
861         HeapFree(GetProcessHeap(), 0, keyPath);
862     }
863         break;
864    /*case ID_OPTIONS_TOOLBAR:*/
865    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
866    /*    break;*/
867     case ID_VIEW_STATUSBAR:
868         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
869         break;
870     case ID_HELP_HELPTOPICS:
871     {
872         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
873         WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
874         break;
875     }
876     case ID_HELP_ABOUT:
877         ShowAboutBox(hWnd);
878         break;
879     case ID_VIEW_SPLIT: {
880         RECT rt;
881         POINT pt, pts;
882         GetClientRect(g_pChildWnd->hWnd, &rt);
883         pt.x = rt.left + g_pChildWnd->nSplitPos;
884         pt.y = (rt.bottom / 2);
885         pts = pt;
886         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
887             SetCursorPos(pts.x, pts.y);
888             SetCursor(LoadCursor(0, IDC_SIZEWE));
889             SendMessage(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
890         }
891         return TRUE;
892     }
893     default:
894         return FALSE;
895     }
896
897     return TRUE;
898 }
899
900 /********************************************************************************
901  *
902  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
903  *
904  *  PURPOSE:  Processes messages for the main frame window.
905  *
906  *  WM_COMMAND  - process the application menu
907  *  WM_DESTROY  - post a quit message and return
908  *
909  */
910
911 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
912 {
913     switch (message) {
914     case WM_CREATE:
915         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
916                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
917                        hWnd, NULL, hInst, 0);
918         break;
919     case WM_COMMAND:
920         if (!_CmdWndProc(hWnd, message, wParam, lParam))
921             return DefWindowProc(hWnd, message, wParam, lParam);
922         break;
923     case WM_ACTIVATE:
924         if (LOWORD(hWnd)) 
925             SetFocus(g_pChildWnd->hWnd);
926         break;
927     case WM_SIZE:
928         resize_frame_client(hWnd);
929         break;
930     case WM_TIMER:
931         break;
932     case WM_ENTERMENULOOP:
933         OnEnterMenuLoop(hWnd);
934         break;
935     case WM_EXITMENULOOP:
936         OnExitMenuLoop(hWnd);
937         break;
938     case WM_INITMENUPOPUP:
939         if (!HIWORD(lParam))
940             OnInitMenuPopup(hWnd, (HMENU)wParam, LOWORD(lParam));
941         break;
942     case WM_MENUSELECT:
943         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
944         break;
945     case WM_DESTROY:
946     {
947         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
948         WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
949         PostQuitMessage(0);
950     }
951     default:
952         return DefWindowProc(hWnd, message, wParam, lParam);
953     }
954     return 0;
955 }