regedit: Convert menu & statusbar handling 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 keyPath;
640     LPCTSTR valueName;
641     TCHAR newKey[MAX_NEW_KEY_LEN];
642     DWORD valueType;
643     int curIndex;
644     BOOL firstItem = TRUE;
645
646     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
647
648     if (LOWORD(wParam) >= ID_FAVORITE_FIRST && LOWORD(wParam) <= ID_FAVORITE_LAST) {
649         HKEY hKey;
650         if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
651             0, KEY_READ, &hKey) == ERROR_SUCCESS) {
652             WCHAR namebuf[KEY_MAX_LEN];
653             BYTE valuebuf[4096];
654             DWORD ksize = KEY_MAX_LEN, vsize = sizeof(valuebuf), type = 0;
655             if (RegEnumValueW(hKey, LOWORD(wParam) - ID_FAVORITE_FIRST, namebuf, &ksize, NULL,
656                 &type, valuebuf, &vsize) == ERROR_SUCCESS) {
657                 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET,
658                              (LPARAM) FindPathInTree(g_pChildWnd->hTreeWnd, (WCHAR *)valuebuf) );
659             }
660             RegCloseKey(hKey);
661         }
662         return TRUE;
663     }
664     switch (LOWORD(wParam)) {
665     case ID_REGISTRY_IMPORTREGISTRYFILE:
666         ImportRegistryFile(hWnd);
667         break;
668     case ID_EDIT_EXPORT:
669         ExportRegistryFile(hWnd, TRUE);
670         break;
671     case ID_REGISTRY_EXPORTREGISTRYFILE:
672         ExportRegistryFile(hWnd, FALSE);
673         break;
674     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
675         break;
676     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
677         break;
678     case ID_REGISTRY_PRINT:
679     {
680         const WCHAR empty = 0;
681         PrintRegistryHive(hWnd, &empty);
682         break;
683     }
684     case ID_EDIT_DELETE:
685         if (GetFocus() == g_pChildWnd->hTreeWnd) {
686             WCHAR* keyPathW = GetWideString(keyPath);
687             if (keyPath == 0 || *keyPath == 0) {
688                 MessageBeep(MB_ICONHAND); 
689             } else if (DeleteKey(hWnd, hKeyRoot, keyPathW)) {
690                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
691             }
692             HeapFree(GetProcessHeap(), 0, keyPathW);
693         } else if (GetFocus() == g_pChildWnd->hListWnd) {
694         curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
695         while(curIndex != -1) {
696             WCHAR* valueNameW;
697             WCHAR* keyPathW;
698
699             valueName = GetItemText(g_pChildWnd->hListWnd, curIndex);
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             valueNameW = GetWideString(valueName);
708             keyPathW = GetWideString(keyPath);
709             if (!DeleteValue(hWnd, hKeyRoot, keyPathW, valueNameW, curIndex==-1 && firstItem))
710             {
711                 HeapFree(GetProcessHeap(), 0, valueNameW);
712                 HeapFree(GetProcessHeap(), 0, keyPathW);
713                 break;
714             }
715             firstItem = FALSE;
716             HeapFree(GetProcessHeap(), 0, valueNameW);
717             HeapFree(GetProcessHeap(), 0, keyPathW);
718         }
719                 RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
720         }
721         break;
722     case ID_EDIT_MODIFY:
723         valueName = GetValueName(g_pChildWnd->hListWnd);
724         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
725             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, valueName);
726         break;
727     case ID_EDIT_FIND:
728     case ID_EDIT_FINDNEXT:
729     {
730         HTREEITEM hItem;
731         if (LOWORD(wParam) == ID_EDIT_FIND &&
732             DialogBox(0, MAKEINTRESOURCE(IDD_FIND), hWnd, find_dlgproc) != IDOK)
733             break;
734         if (!*searchString)
735             break;
736         hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
737         if (hItem) {
738             int row = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED);
739             HCURSOR hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
740             hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
741             SetCursor(hcursorOld);
742             if (hItem) {
743                 SendMessage( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
744                 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
745                 UpdateWindow(g_pChildWnd->hTreeWnd);
746                 if (row != -1) {
747                     ListView_SetItemState(g_pChildWnd->hListWnd, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
748                     ListView_SetItemState(g_pChildWnd->hListWnd, row, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
749                     SetFocus(g_pChildWnd->hListWnd);
750                 } else {
751                     SetFocus(g_pChildWnd->hTreeWnd);
752                 }
753             } else {
754                 CHAR* searchStringA = GetMultiByteString(searchString);
755                 error(hWnd, IDS_NOTFOUND, searchStringA);
756                 HeapFree(GetProcessHeap(), 0, searchStringA);
757             }
758         }
759         break;
760     }
761     case ID_EDIT_COPYKEYNAME:
762     {
763         LPWSTR fullPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
764         if (fullPath) {
765             CopyKeyName(hWnd, fullPath);
766             HeapFree(GetProcessHeap(), 0, fullPath);
767         }
768         break;
769     }
770     case ID_EDIT_NEW_KEY:
771     {
772         WCHAR newKeyW[MAX_NEW_KEY_LEN];
773         WCHAR* keyPathW = GetWideString(keyPath);
774         if (CreateKey(hWnd, hKeyRoot, keyPathW, newKeyW)) {
775             if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
776                 StartKeyRename(g_pChildWnd->hTreeWnd);
777         }
778         HeapFree(GetProcessHeap(), 0, keyPathW);
779     }
780         break;
781     case ID_EDIT_NEW_STRINGVALUE:
782         valueType = REG_SZ;
783         goto create_value;
784     case ID_EDIT_NEW_MULTI_STRINGVALUE:
785         valueType = REG_MULTI_SZ;
786         goto create_value;
787     case ID_EDIT_NEW_BINARYVALUE:
788         valueType = REG_BINARY;
789         goto create_value;
790     case ID_EDIT_NEW_DWORDVALUE:
791         valueType = REG_DWORD;
792         /* fall through */
793     create_value:
794         if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey)) {
795             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, newKey);
796             StartValueRename(g_pChildWnd->hListWnd);
797             /* FIXME: start rename */
798         }
799         break;
800     case ID_EDIT_RENAME:
801         if (keyPath == 0 || *keyPath == 0) {
802             MessageBeep(MB_ICONHAND); 
803         } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
804             StartKeyRename(g_pChildWnd->hTreeWnd);
805         } else if (GetFocus() == g_pChildWnd->hListWnd) {
806             StartValueRename(g_pChildWnd->hListWnd);
807         }
808         break;
809     case ID_REGISTRY_PRINTERSETUP:
810         /*PRINTDLG pd;*/
811         /*PrintDlg(&pd);*/
812         /*PAGESETUPDLG psd;*/
813         /*PageSetupDlg(&psd);*/
814         break;
815     case ID_REGISTRY_OPENLOCAL:
816         break;
817     case ID_REGISTRY_EXIT:
818         DestroyWindow(hWnd);
819         break;
820     case ID_FAVORITES_ADDTOFAVORITES:
821     {
822         HKEY hKey;
823         LPWSTR lpKeyPath = GetItemFullPathW(g_pChildWnd->hTreeWnd, NULL, FALSE);
824         if (lpKeyPath) {
825             if (DialogBox(0, MAKEINTRESOURCE(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
826                 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
827                     0, NULL, 0, 
828                     KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
829                     RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
830                     RegCloseKey(hKey);
831                 }
832             }
833             HeapFree(GetProcessHeap(), 0, lpKeyPath);
834         }
835         break;
836     }
837     case ID_FAVORITES_REMOVEFAVORITE:
838     {
839         if (DialogBox(0, MAKEINTRESOURCE(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
840             HKEY hKey;
841             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
842                 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
843                 RegDeleteValueW(hKey, favoriteName);
844                 RegCloseKey(hKey);
845             }
846         }
847         break;
848     }
849     case ID_VIEW_REFRESH:
850         RefreshTreeView(g_pChildWnd->hTreeWnd);
851         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
852         break;
853    /*case ID_OPTIONS_TOOLBAR:*/
854    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
855    /*    break;*/
856     case ID_VIEW_STATUSBAR:
857         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
858         break;
859     case ID_HELP_HELPTOPICS:
860     {
861         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
862         WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
863         break;
864     }
865     case ID_HELP_ABOUT:
866         ShowAboutBox(hWnd);
867         break;
868     case ID_VIEW_SPLIT: {
869         RECT rt;
870         POINT pt, pts;
871         GetClientRect(g_pChildWnd->hWnd, &rt);
872         pt.x = rt.left + g_pChildWnd->nSplitPos;
873         pt.y = (rt.bottom / 2);
874         pts = pt;
875         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
876             SetCursorPos(pts.x, pts.y);
877             SetCursor(LoadCursor(0, IDC_SIZEWE));
878             SendMessage(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
879         }
880         return TRUE;
881     }
882     default:
883         return FALSE;
884     }
885
886     return TRUE;
887 }
888
889 /********************************************************************************
890  *
891  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
892  *
893  *  PURPOSE:  Processes messages for the main frame window.
894  *
895  *  WM_COMMAND  - process the application menu
896  *  WM_DESTROY  - post a quit message and return
897  *
898  */
899
900 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
901 {
902     switch (message) {
903     case WM_CREATE:
904         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
905                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
906                        hWnd, NULL, hInst, 0);
907         break;
908     case WM_COMMAND:
909         if (!_CmdWndProc(hWnd, message, wParam, lParam))
910             return DefWindowProc(hWnd, message, wParam, lParam);
911         break;
912     case WM_ACTIVATE:
913         if (LOWORD(hWnd)) 
914             SetFocus(g_pChildWnd->hWnd);
915         break;
916     case WM_SIZE:
917         resize_frame_client(hWnd);
918         break;
919     case WM_TIMER:
920         break;
921     case WM_ENTERMENULOOP:
922         OnEnterMenuLoop(hWnd);
923         break;
924     case WM_EXITMENULOOP:
925         OnExitMenuLoop(hWnd);
926         break;
927     case WM_INITMENUPOPUP:
928         if (!HIWORD(lParam))
929             OnInitMenuPopup(hWnd, (HMENU)wParam, LOWORD(lParam));
930         break;
931     case WM_MENUSELECT:
932         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
933         break;
934     case WM_DESTROY:
935     {
936         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
937         WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
938         PostQuitMessage(0);
939     }
940     default:
941         return DefWindowProc(hWnd, message, wParam, lParam);
942     }
943     return 0;
944 }