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