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