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