ws2_32: name is never NULL as array (Coverity).
[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     keyName = GetItemPath(hwndTV, TreeView_GetSelection(hwndTV), &hRootKey);
109     if (GetFocus() != hwndTV || (keyName && *keyName)) { /* can't modify root keys, but allow for their values */
110         bAllowEdit = TRUE;
111     }
112     EnableMenuItem(hMenu, ID_EDIT_FIND, MF_ENABLED | MF_BYCOMMAND);
113     EnableMenuItem(hMenu, ID_EDIT_FINDNEXT, MF_ENABLED | MF_BYCOMMAND);
114     EnableMenuItem(hMenu, ID_EDIT_MODIFY, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
115     EnableMenuItem(hMenu, ID_EDIT_DELETE, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
116     EnableMenuItem(hMenu, ID_EDIT_RENAME, (bAllowEdit ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
117     EnableMenuItem(hMenu, ID_FAVORITES_ADDTOFAVORITES, (hRootKey ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
118     EnableMenuItem(hMenu, ID_FAVORITES_REMOVEFAVORITE, 
119         (GetMenuItemCount(hMenu)>2 ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
120
121     HeapFree(GetProcessHeap(), 0, keyName);
122 }
123
124 static void OnInitMenuPopup(HWND hWnd, HMENU hMenu, short wItem)
125 {
126     if (wItem == 3) {
127         HKEY hKey;
128         while(GetMenuItemCount(hMenu)>2)
129             DeleteMenu(hMenu, 2, MF_BYPOSITION);
130         if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
131             0, KEY_READ, &hKey) == ERROR_SUCCESS) {
132             WCHAR namebuf[KEY_MAX_LEN];
133             BYTE valuebuf[4096];
134             int i = 0;
135             BOOL sep = FALSE;
136             DWORD ksize, vsize, type;
137             LONG error;
138             do {
139                 ksize = KEY_MAX_LEN;
140                 vsize = sizeof(valuebuf);
141                 error = RegEnumValueW(hKey, i, namebuf, &ksize, NULL, &type, valuebuf, &vsize);
142                 if (error != ERROR_SUCCESS)
143                     break;
144                 if (type == REG_SZ) {
145                     if (!sep) {
146                         AppendMenuW(hMenu, MF_SEPARATOR, -1, NULL);
147                         sep = TRUE;
148                     }
149                     AppendMenuW(hMenu, MF_STRING, ID_FAVORITE_FIRST+i, namebuf);
150                 }
151                 i++;
152             } while(error == ERROR_SUCCESS);
153             RegCloseKey(hKey);
154         }
155     }
156     UpdateMenuItems(hMenu);
157 }
158
159 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
160 {
161     WCHAR str[100];
162
163     str[0] = 0;
164     if (nFlags & MF_POPUP) {
165         if (hSysMenu != GetMenu(hWnd)) {
166             if (nItemID == 2) nItemID = 5;
167         }
168     }
169     if (LoadStringW(hInst, nItemID, str, 100)) {
170         /* load appropriate string*/
171         LPWSTR lpsz = str;
172         /* first newline terminates actual string*/
173         lpsz = strchrW(lpsz, '\n');
174         if (lpsz != NULL)
175             *lpsz = '\0';
176     }
177     SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)str);
178 }
179
180 void SetupStatusBar(HWND hWnd, BOOL bResize)
181 {
182     RECT  rc;
183     int nParts;
184     GetClientRect(hWnd, &rc);
185     nParts = rc.right;
186     /*    nParts = -1;*/
187     if (bResize)
188         SendMessageW(hStatusBar, WM_SIZE, 0, 0);
189     SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
190     UpdateStatusBar();
191 }
192
193 void UpdateStatusBar(void)
194 {
195     LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, TRUE);
196     SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath);
197     HeapFree(GetProcessHeap(), 0, fullPath);
198 }
199
200 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
201 {
202     BOOL vis = IsWindowVisible(hchild);
203     HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
204
205     CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
206     ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
207     resize_frame_client(hWnd);
208 }
209
210 static BOOL CheckCommDlgError(HWND hWnd)
211 {
212     DWORD dwErrorCode = CommDlgExtendedError();
213     switch (dwErrorCode) {
214     case CDERR_DIALOGFAILURE:
215         break;
216     case CDERR_FINDRESFAILURE:
217         break;
218     case CDERR_NOHINSTANCE:
219         break;
220     case CDERR_INITIALIZATION:
221         break;
222     case CDERR_NOHOOK:
223         break;
224     case CDERR_LOCKRESFAILURE:
225         break;
226     case CDERR_NOTEMPLATE:
227         break;
228     case CDERR_LOADRESFAILURE:
229         break;
230     case CDERR_STRUCTSIZE:
231         break;
232     case CDERR_LOADSTRFAILURE:
233         break;
234     case FNERR_BUFFERTOOSMALL:
235         break;
236     case CDERR_MEMALLOCFAILURE:
237         break;
238     case FNERR_INVALIDFILENAME:
239         break;
240     case CDERR_MEMLOCKFAILURE:
241         break;
242     case FNERR_SUBCLASSFAILURE:
243         break;
244     default:
245         break;
246     }
247     return TRUE;
248 }
249
250 static void ExportRegistryFile_StoreSelection(HWND hdlg, OPENFILENAMEW *pOpenFileName)
251 {
252     if (IsDlgButtonChecked(hdlg, IDC_EXPORT_SELECTED))
253     {
254         INT len = SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXTLENGTH, 0, 0);
255         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
256         SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXT, len+1, pOpenFileName->lCustData);
257     }
258     else
259         pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
260 }
261
262 static UINT_PTR CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
263 {
264     static OPENFILENAMEW* pOpenFileName;
265     OFNOTIFYW *pOfNotify;
266
267     switch (uiMsg) {
268     case WM_INITDIALOG:
269         pOpenFileName = (OPENFILENAMEW*)lParam;
270         break;
271     case WM_COMMAND:
272         if (LOWORD(wParam) == IDC_EXPORT_PATH && HIWORD(wParam) == EN_UPDATE)
273             CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, IDC_EXPORT_SELECTED);
274         break;
275     case WM_NOTIFY:
276         pOfNotify = (OFNOTIFYW*)lParam;
277         switch (pOfNotify->hdr.code)
278         {
279             case CDN_INITDONE:
280             {
281                 BOOL export_branch = FALSE;
282                 WCHAR* path = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
283                 SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_SETTEXT, 0, (LPARAM)path);
284                 if (path && strlenW(path) > 0)
285                     export_branch = TRUE;
286                 HeapFree(GetProcessHeap(), 0, path);
287                 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, export_branch ? IDC_EXPORT_SELECTED : IDC_EXPORT_ALL);
288                 break;
289             }
290             case CDN_FILEOK:
291                 ExportRegistryFile_StoreSelection(hdlg, pOpenFileName);
292                 break;
293         }
294         break;
295     default:
296         break;
297     }
298     return 0L;
299 }
300
301
302 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAMEW *pofn)
303 {
304     memset(pofn, 0, sizeof(OPENFILENAMEW));
305     pofn->lStructSize = sizeof(OPENFILENAMEW);
306     pofn->hwndOwner = hWnd;
307     pofn->hInstance = hInst;
308
309     if (FilterBuffer[0] == 0)
310     {
311         static const WCHAR filterW[] = {'%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','*','%','c',0};
312         WCHAR filter_reg[MAX_PATH], filter_reg4[MAX_PATH], filter_all[MAX_PATH];
313
314         LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG, filter_reg, MAX_PATH);
315         LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG4, filter_reg4, MAX_PATH);
316         LoadStringW(hInst, IDS_FILEDIALOG_FILTER_ALL, filter_all, MAX_PATH);
317         snprintfW( FilterBuffer, MAX_PATH, filterW, filter_reg, 0, 0, filter_reg4, 0, 0, filter_all, 0, 0 );
318     }
319     pofn->lpstrFilter = FilterBuffer;
320     pofn->nFilterIndex = 2;
321     pofn->lpstrFile = FileNameBuffer;
322     pofn->nMaxFile = _MAX_PATH;
323     pofn->lpstrFileTitle = FileTitleBuffer;
324     pofn->nMaxFileTitle = _MAX_PATH;
325     pofn->Flags = OFN_HIDEREADONLY;
326     /* some other fields may be set by the caller */
327     return TRUE;
328 }
329
330 static BOOL import_registry_filename(LPTSTR filename)
331 {
332     BOOL Success;
333     FILE* reg_file = fopen(filename, "r");
334
335     if(!reg_file)
336         return FALSE;
337
338     Success = import_registry_file(reg_file);
339
340     if(fclose(reg_file) != 0)
341         Success = FALSE;
342
343     return Success;
344 }
345
346 static BOOL ImportRegistryFile(HWND hWnd)
347 {
348     OPENFILENAMEW ofn;
349     WCHAR title[128];
350
351     InitOpenFileName(hWnd, &ofn);
352     ofn.Flags |= OFN_ENABLESIZING;
353     LoadStringW(hInst, IDS_FILEDIALOG_IMPORT_TITLE, title, COUNT_OF(title));
354     ofn.lpstrTitle = title;
355     if (GetOpenFileNameW(&ofn)) {
356         CHAR* fileA = GetMultiByteString(ofn.lpstrFile);
357         if (!import_registry_filename(fileA)) {
358             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
359             HeapFree(GetProcessHeap(), 0, fileA);
360             return FALSE;
361         }
362         HeapFree(GetProcessHeap(), 0, fileA);
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(PRINTDLG));
401     pd.lStructSize = sizeof(PRINTDLG);
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),  GetWindowTextLength(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_CONNECTNETWORKREGISTRY:
681         break;
682     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
683         break;
684     case ID_REGISTRY_PRINT:
685     {
686         const WCHAR empty = 0;
687         PrintRegistryHive(hWnd, &empty);
688         break;
689     }
690     case ID_EDIT_DELETE:
691     {
692         HWND hWndDelete = GetFocus();
693         if (hWndDelete == g_pChildWnd->hTreeWnd) {
694             WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
695             if (keyPath == 0 || *keyPath == 0) {
696                 MessageBeep(MB_ICONHAND);
697             } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) {
698                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
699             }
700             HeapFree(GetProcessHeap(), 0, keyPath);
701         } else if (hWndDelete == g_pChildWnd->hListWnd) {
702         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
703         curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_SELECTED);
704         while(curIndex != -1) {
705             WCHAR* valueName = GetItemText(g_pChildWnd->hListWnd, curIndex);
706
707             curIndex = ListView_GetNextItem(g_pChildWnd->hListWnd, curIndex, LVNI_SELECTED);
708             if(curIndex != -1 && firstItem) {
709                 if (MessageBoxW(hWnd, MAKEINTRESOURCEW(IDS_DELETE_BOX_TEXT_MULTIPLE),
710                                 MAKEINTRESOURCEW(IDS_DELETE_BOX_TITLE),
711                                 MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
712                     break;
713             }
714
715             if (!DeleteValue(hWnd, hKeyRoot, keyPath, valueName, curIndex==-1 && firstItem))
716             {
717                 HeapFree(GetProcessHeap(), 0, valueName);
718                 break;
719             }
720             firstItem = FALSE;
721             HeapFree(GetProcessHeap(), 0, valueName);
722         }
723         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
724         HeapFree(GetProcessHeap(), 0, keyPath);
725         } else if (IsChild(g_pChildWnd->hTreeWnd, hWndDelete) ||
726                    IsChild(g_pChildWnd->hListWnd, hWndDelete)) {
727             SendMessage(hWndDelete, WM_KEYDOWN, VK_DELETE, 0);
728         }
729         break;
730     }
731     case ID_EDIT_MODIFY:
732     {
733         LPCWSTR valueName = GetValueName(g_pChildWnd->hListWnd);
734         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
735         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
736             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, valueName);
737         HeapFree(GetProcessHeap(), 0, keyPath);
738         break;
739     }
740     case ID_EDIT_FIND:
741     case ID_EDIT_FINDNEXT:
742     {
743         HTREEITEM hItem;
744         if (LOWORD(wParam) == ID_EDIT_FIND &&
745             DialogBox(0, MAKEINTRESOURCE(IDD_FIND), hWnd, find_dlgproc) != IDOK)
746             break;
747         if (!*searchString)
748             break;
749         hItem = TreeView_GetSelection(g_pChildWnd->hTreeWnd);
750         if (hItem) {
751             int row = ListView_GetNextItem(g_pChildWnd->hListWnd, -1, LVNI_FOCUSED);
752             HCURSOR hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
753             hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
754             SetCursor(hcursorOld);
755             if (hItem) {
756                 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
757                 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
758                 UpdateWindow(g_pChildWnd->hTreeWnd);
759                 if (row != -1) {
760                     ListView_SetItemState(g_pChildWnd->hListWnd, -1, 0, LVIS_FOCUSED|LVIS_SELECTED);
761                     ListView_SetItemState(g_pChildWnd->hListWnd, row, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
762                     SetFocus(g_pChildWnd->hListWnd);
763                 } else {
764                     SetFocus(g_pChildWnd->hTreeWnd);
765                 }
766             } else {
767                 error(hWnd, IDS_NOTFOUND, searchString);
768             }
769         }
770         break;
771     }
772     case ID_EDIT_COPYKEYNAME:
773     {
774         LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
775         if (fullPath) {
776             CopyKeyName(hWnd, fullPath);
777             HeapFree(GetProcessHeap(), 0, fullPath);
778         }
779         break;
780     }
781     case ID_EDIT_NEW_KEY:
782     {
783         WCHAR newKeyW[MAX_NEW_KEY_LEN];
784         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
785         if (CreateKey(hWnd, hKeyRoot, keyPath, newKeyW)) {
786             if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
787                 StartKeyRename(g_pChildWnd->hTreeWnd);
788         }
789         HeapFree(GetProcessHeap(), 0, keyPath);
790     }
791         break;
792     case ID_EDIT_NEW_STRINGVALUE:
793         valueType = REG_SZ;
794         goto create_value;
795     case ID_EDIT_NEW_MULTI_STRINGVALUE:
796         valueType = REG_MULTI_SZ;
797         goto create_value;
798     case ID_EDIT_NEW_BINARYVALUE:
799         valueType = REG_BINARY;
800         goto create_value;
801     case ID_EDIT_NEW_DWORDVALUE:
802         valueType = REG_DWORD;
803         /* fall through */
804     create_value:
805     {
806         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
807         WCHAR newKey[MAX_NEW_KEY_LEN];
808         if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey)) {
809             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, newKey);
810             StartValueRename(g_pChildWnd->hListWnd);
811         }
812         HeapFree(GetProcessHeap(), 0, keyPath);
813     }
814         break;
815     case ID_EDIT_RENAME:
816     {
817         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
818         if (keyPath == 0 || *keyPath == 0) {
819             MessageBeep(MB_ICONHAND);
820         } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
821             StartKeyRename(g_pChildWnd->hTreeWnd);
822         } else if (GetFocus() == g_pChildWnd->hListWnd) {
823             StartValueRename(g_pChildWnd->hListWnd);
824         }
825         HeapFree(GetProcessHeap(), 0, keyPath);
826     }
827         break;
828     case ID_REGISTRY_PRINTERSETUP:
829         /*PRINTDLG pd;*/
830         /*PrintDlg(&pd);*/
831         /*PAGESETUPDLG psd;*/
832         /*PageSetupDlg(&psd);*/
833         break;
834     case ID_REGISTRY_OPENLOCAL:
835         break;
836     case ID_REGISTRY_EXIT:
837         DestroyWindow(hWnd);
838         break;
839     case ID_FAVORITES_ADDTOFAVORITES:
840     {
841         HKEY hKey;
842         LPWSTR lpKeyPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
843         if (lpKeyPath) {
844             if (DialogBox(0, MAKEINTRESOURCE(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
845                 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
846                     0, NULL, 0, 
847                     KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
848                     RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
849                     RegCloseKey(hKey);
850                 }
851             }
852             HeapFree(GetProcessHeap(), 0, lpKeyPath);
853         }
854         break;
855     }
856     case ID_FAVORITES_REMOVEFAVORITE:
857     {
858         if (DialogBox(0, MAKEINTRESOURCE(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
859             HKEY hKey;
860             if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
861                 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
862                 RegDeleteValueW(hKey, favoriteName);
863                 RegCloseKey(hKey);
864             }
865         }
866         break;
867     }
868     case ID_VIEW_REFRESH:
869     {
870         WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
871         RefreshTreeView(g_pChildWnd->hTreeWnd);
872         RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
873         HeapFree(GetProcessHeap(), 0, keyPath);
874     }
875         break;
876    /*case ID_OPTIONS_TOOLBAR:*/
877    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
878    /*    break;*/
879     case ID_VIEW_STATUSBAR:
880         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
881         break;
882     case ID_HELP_HELPTOPICS:
883     {
884         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
885         WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
886         break;
887     }
888     case ID_HELP_ABOUT:
889         ShowAboutBox(hWnd);
890         break;
891     case ID_VIEW_SPLIT: {
892         RECT rt;
893         POINT pt, pts;
894         GetClientRect(g_pChildWnd->hWnd, &rt);
895         pt.x = rt.left + g_pChildWnd->nSplitPos;
896         pt.y = (rt.bottom / 2);
897         pts = pt;
898         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
899             SetCursorPos(pts.x, pts.y);
900             SetCursor(LoadCursor(0, IDC_SIZEWE));
901             SendMessageW(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
902         }
903         return TRUE;
904     }
905     default:
906         return FALSE;
907     }
908
909     return TRUE;
910 }
911
912 /********************************************************************************
913  *
914  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
915  *
916  *  PURPOSE:  Processes messages for the main frame window.
917  *
918  *  WM_COMMAND  - process the application menu
919  *  WM_DESTROY  - post a quit message and return
920  *
921  */
922
923 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
924 {
925     switch (message) {
926     case WM_CREATE:
927         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
928                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
929                        hWnd, NULL, hInst, 0);
930         break;
931     case WM_COMMAND:
932         if (!_CmdWndProc(hWnd, message, wParam, lParam))
933             return DefWindowProc(hWnd, message, wParam, lParam);
934         break;
935     case WM_ACTIVATE:
936         if (LOWORD(hWnd)) 
937             SetFocus(g_pChildWnd->hWnd);
938         break;
939     case WM_SIZE:
940         resize_frame_client(hWnd);
941         break;
942     case WM_TIMER:
943         break;
944     case WM_ENTERMENULOOP:
945         OnEnterMenuLoop(hWnd);
946         break;
947     case WM_EXITMENULOOP:
948         OnExitMenuLoop(hWnd);
949         break;
950     case WM_INITMENUPOPUP:
951         if (!HIWORD(lParam))
952             OnInitMenuPopup(hWnd, (HMENU)wParam, LOWORD(lParam));
953         break;
954     case WM_MENUSELECT:
955         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
956         break;
957     case WM_DESTROY:
958     {
959         const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
960         WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
961         PostQuitMessage(0);
962     }
963     default:
964         return DefWindowProc(hWnd, message, wParam, lParam);
965     }
966     return 0;
967 }