regedit: Export Unicode registry files by default.
[wine.git] / programs / regedit / framewnd.c
blobc6fcee466d50ae3f966a4361fdfe75b8c77ccf1e
1 /*
2 * Regedit frame window
4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
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.
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.
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
21 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
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>
31 #include "main.h"
32 #include "regproc.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(regedit);
38 /********************************************************************************
39 * Global and Local Variables:
42 static const 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;
48 static WCHAR FileNameBuffer[_MAX_PATH];
49 static WCHAR FileTitleBuffer[_MAX_PATH];
50 static WCHAR FilterBuffer[_MAX_PATH];
51 static WCHAR expandW[32], collapseW[32];
52 static WCHAR modifyW[32], modify_binaryW[64];
54 /*******************************************************************************
55 * Local module support methods
58 static void resize_frame_rect(HWND hWnd, PRECT prect)
60 if (IsWindowVisible(hStatusBar)) {
61 RECT rt;
63 SetupStatusBar(hWnd, TRUE);
64 GetClientRect(hStatusBar, &rt);
65 prect->bottom -= rt.bottom;
67 MoveWindow(g_pChildWnd->hWnd, prect->left, prect->top, prect->right, prect->bottom, TRUE);
70 static void resize_frame_client(HWND hWnd)
72 RECT rect;
74 GetClientRect(hWnd, &rect);
75 resize_frame_rect(hWnd, &rect);
78 /********************************************************************************/
80 static void OnEnterMenuLoop(HWND hWnd)
82 int nParts;
83 WCHAR empty = 0;
85 /* Update the status bar pane sizes */
86 nParts = -1;
87 SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
88 bInMenuLoop = TRUE;
89 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)&empty);
92 static void OnExitMenuLoop(HWND hWnd)
94 bInMenuLoop = FALSE;
95 /* Update the status bar pane sizes*/
96 SetupStatusBar(hWnd, TRUE);
97 UpdateStatusBar();
100 static void update_expand_or_collapse_item(HWND hwndTV, HTREEITEM selection, HMENU hMenu)
102 TVITEMW item;
103 MENUITEMINFOW info;
105 item.hItem = selection;
106 item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE;
107 item.stateMask = TVIS_EXPANDED;
108 SendMessageW(hwndTV, TVM_GETITEMW, 0, (LPARAM)&item);
110 info.cbSize = sizeof(MENUITEMINFOW);
111 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
112 info.fType = MFT_STRING;
113 info.fState = MFS_ENABLED;
114 info.dwTypeData = expandW;
116 if (!item.cChildren)
118 info.fState = MFS_GRAYED;
119 goto update;
122 if (item.state & TVIS_EXPANDED)
123 info.dwTypeData = collapseW;
125 update:
126 SetMenuItemInfoW(hMenu, ID_TREE_EXPAND_COLLAPSE, FALSE, &info);
129 static void update_modify_items(HMENU hMenu, int index)
131 unsigned int state = MF_ENABLED;
133 if (index == -1)
134 state = MF_GRAYED;
136 EnableMenuItem(hMenu, ID_EDIT_MODIFY, state | MF_BYCOMMAND);
137 EnableMenuItem(hMenu, ID_EDIT_MODIFY_BIN, state | MF_BYCOMMAND);
140 static void update_delete_and_rename_items(HMENU hMenu, WCHAR *keyName, int index)
142 unsigned int state_d = MF_ENABLED, state_r = MF_ENABLED;
144 if (!g_pChildWnd->nFocusPanel)
146 if (!keyName || !*keyName)
147 state_d = state_r = MF_GRAYED;
149 else if (index < 1)
151 state_r = MF_GRAYED;
152 if (index == -1) state_d = MF_GRAYED;
155 EnableMenuItem(hMenu, ID_EDIT_DELETE, state_d | MF_BYCOMMAND);
156 EnableMenuItem(hMenu, ID_EDIT_RENAME, state_r | MF_BYCOMMAND);
159 static void update_new_items_and_copy_keyname(HMENU hMenu, WCHAR *keyName)
161 unsigned int state = MF_ENABLED, i;
162 unsigned int items[] = {ID_EDIT_NEW_KEY, ID_EDIT_NEW_STRINGVALUE, ID_EDIT_NEW_BINARYVALUE,
163 ID_EDIT_NEW_DWORDVALUE, ID_EDIT_NEW_MULTI_STRINGVALUE,
164 ID_EDIT_NEW_EXPANDVALUE, ID_EDIT_COPYKEYNAME};
166 if (!keyName)
167 state = MF_GRAYED;
169 for (i = 0; i < COUNT_OF(items); i++)
170 EnableMenuItem(hMenu, items[i], state | MF_BYCOMMAND);
173 static void UpdateMenuItems(HMENU hMenu) {
174 HWND hwndTV = g_pChildWnd->hTreeWnd;
175 HKEY hRootKey = NULL;
176 LPWSTR keyName;
177 HTREEITEM selection;
178 int index;
180 selection = (HTREEITEM)SendMessageW(hwndTV, TVM_GETNEXTITEM, TVGN_CARET, 0);
181 keyName = GetItemPath(hwndTV, selection, &hRootKey);
182 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1,
183 MAKELPARAM(LVNI_FOCUSED | LVNI_SELECTED, 0));
185 update_expand_or_collapse_item(hwndTV, selection, hMenu);
186 update_modify_items(hMenu, index);
187 update_delete_and_rename_items(hMenu, keyName, index);
188 update_new_items_and_copy_keyname(hMenu, keyName);
189 EnableMenuItem(hMenu, ID_FAVORITES_ADDTOFAVORITES, (hRootKey ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
190 EnableMenuItem(hMenu, ID_FAVORITES_REMOVEFAVORITE,
191 (GetMenuItemCount(hMenu)>2 ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
193 heap_free(keyName);
196 static void add_remove_modify_menu_items(HMENU hMenu)
198 if (!g_pChildWnd->nFocusPanel)
200 while (GetMenuItemCount(hMenu) > 9)
201 DeleteMenu(hMenu, 0, MF_BYPOSITION);
203 else if (GetMenuItemCount(hMenu) < 10)
205 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
206 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_STRING, ID_EDIT_MODIFY_BIN, modify_binaryW);
207 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_STRING, ID_EDIT_MODIFY, modifyW);
211 static int add_favourite_key_items(HMENU hMenu, HWND hList)
213 HKEY hkey;
214 LONG rc;
215 DWORD num_values, max_value_len, value_len, type, i = 0;
216 WCHAR *value_name;
218 rc = RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey, 0, KEY_READ, &hkey);
219 if (rc != ERROR_SUCCESS) return 0;
221 rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &num_values,
222 &max_value_len, NULL, NULL, NULL);
223 if (rc != ERROR_SUCCESS)
225 ERR("RegQueryInfoKey failed: %d\n", rc);
226 goto exit;
229 if (!num_values) goto exit;
231 max_value_len++;
232 value_name = heap_xalloc(max_value_len * sizeof(WCHAR));
234 if (hMenu) AppendMenuW(hMenu, MF_SEPARATOR, 0, 0);
236 for (i = 0; i < num_values; i++)
238 value_len = max_value_len;
239 rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, NULL, NULL);
240 if (rc == ERROR_SUCCESS && type == REG_SZ)
242 if (hMenu)
243 AppendMenuW(hMenu, MF_ENABLED | MF_STRING, ID_FAVORITE_FIRST + i, value_name);
244 else if (hList)
245 SendMessageW(hList, LB_ADDSTRING, 0, (LPARAM)value_name);
249 heap_free(value_name);
250 exit:
251 RegCloseKey(hkey);
252 return i;
255 static void OnInitMenuPopup(HWND hWnd, HMENU hMenu)
257 if (hMenu == GetSubMenu(hMenuFrame, ID_EDIT_MENU))
258 add_remove_modify_menu_items(hMenu);
259 else if (hMenu == GetSubMenu(hMenuFrame, ID_FAVORITES_MENU))
261 while (GetMenuItemCount(hMenu) > 2)
262 DeleteMenu(hMenu, 2, MF_BYPOSITION);
264 add_favourite_key_items(hMenu, NULL);
267 UpdateMenuItems(hMenu);
270 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
272 WCHAR str[100];
274 str[0] = 0;
275 if (nFlags & MF_POPUP) {
276 if (hSysMenu != GetMenu(hWnd)) {
277 if (nItemID == 2) nItemID = 5;
280 if (LoadStringW(hInst, nItemID, str, 100)) {
281 /* load appropriate string*/
282 LPWSTR lpsz = str;
283 /* first newline terminates actual string*/
284 lpsz = strchrW(lpsz, '\n');
285 if (lpsz != NULL)
286 *lpsz = '\0';
288 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)str);
291 void SetupStatusBar(HWND hWnd, BOOL bResize)
293 RECT rc;
294 int nParts;
295 GetClientRect(hWnd, &rc);
296 nParts = rc.right;
297 /* nParts = -1;*/
298 if (bResize)
299 SendMessageW(hStatusBar, WM_SIZE, 0, 0);
300 SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
301 UpdateStatusBar();
304 void UpdateStatusBar(void)
306 LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, TRUE);
307 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath);
308 heap_free(fullPath);
311 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
313 BOOL vis = IsWindowVisible(hchild);
314 HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
316 CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
317 ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
318 resize_frame_client(hWnd);
321 static BOOL CheckCommDlgError(HWND hWnd)
323 DWORD dwErrorCode = CommDlgExtendedError();
324 switch (dwErrorCode) {
325 case CDERR_DIALOGFAILURE:
326 break;
327 case CDERR_FINDRESFAILURE:
328 break;
329 case CDERR_NOHINSTANCE:
330 break;
331 case CDERR_INITIALIZATION:
332 break;
333 case CDERR_NOHOOK:
334 break;
335 case CDERR_LOCKRESFAILURE:
336 break;
337 case CDERR_NOTEMPLATE:
338 break;
339 case CDERR_LOADRESFAILURE:
340 break;
341 case CDERR_STRUCTSIZE:
342 break;
343 case CDERR_LOADSTRFAILURE:
344 break;
345 case FNERR_BUFFERTOOSMALL:
346 break;
347 case CDERR_MEMALLOCFAILURE:
348 break;
349 case FNERR_INVALIDFILENAME:
350 break;
351 case CDERR_MEMLOCKFAILURE:
352 break;
353 case FNERR_SUBCLASSFAILURE:
354 break;
355 default:
356 break;
358 return TRUE;
361 static void ExportRegistryFile_StoreSelection(HWND hdlg, OPENFILENAMEW *pOpenFileName)
363 if (IsDlgButtonChecked(hdlg, IDC_EXPORT_SELECTED))
365 INT len = SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXTLENGTH, 0, 0);
366 pOpenFileName->lCustData = (LPARAM)heap_xalloc((len + 1) * sizeof(WCHAR));
367 SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXT, len+1, pOpenFileName->lCustData);
369 else
371 pOpenFileName->lCustData = (LPARAM)heap_xalloc(sizeof(WCHAR));
372 *(WCHAR *)pOpenFileName->lCustData = 0;
376 static UINT_PTR CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
378 static OPENFILENAMEW* pOpenFileName;
379 OFNOTIFYW *pOfNotify;
381 switch (uiMsg) {
382 case WM_INITDIALOG:
383 pOpenFileName = (OPENFILENAMEW*)lParam;
384 break;
385 case WM_COMMAND:
386 if (LOWORD(wParam) == IDC_EXPORT_PATH && HIWORD(wParam) == EN_UPDATE)
387 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, IDC_EXPORT_SELECTED);
388 break;
389 case WM_NOTIFY:
390 pOfNotify = (OFNOTIFYW*)lParam;
391 switch (pOfNotify->hdr.code)
393 case CDN_INITDONE:
395 BOOL export_branch = FALSE;
396 WCHAR* path = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
397 SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_SETTEXT, 0, (LPARAM)path);
398 if (path && path[0])
399 export_branch = TRUE;
400 heap_free(path);
401 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, export_branch ? IDC_EXPORT_SELECTED : IDC_EXPORT_ALL);
402 break;
404 case CDN_FILEOK:
405 ExportRegistryFile_StoreSelection(hdlg, pOpenFileName);
406 break;
408 break;
409 default:
410 break;
412 return 0L;
416 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAMEW *pofn)
418 memset(pofn, 0, sizeof(OPENFILENAMEW));
419 pofn->lStructSize = sizeof(OPENFILENAMEW);
420 pofn->hwndOwner = hWnd;
421 pofn->hInstance = hInst;
423 if (FilterBuffer[0] == 0)
425 static const WCHAR filterW[] = {'%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','*','%','c',0};
426 WCHAR filter_reg[MAX_PATH], filter_reg4[MAX_PATH], filter_all[MAX_PATH];
428 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG, filter_reg, MAX_PATH);
429 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG4, filter_reg4, MAX_PATH);
430 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_ALL, filter_all, MAX_PATH);
431 snprintfW( FilterBuffer, MAX_PATH, filterW, filter_reg, 0, 0, filter_reg4, 0, 0, filter_all, 0, 0 );
433 pofn->lpstrFilter = FilterBuffer;
434 pofn->nFilterIndex = 1;
435 pofn->lpstrFile = FileNameBuffer;
436 pofn->nMaxFile = _MAX_PATH;
437 pofn->lpstrFileTitle = FileTitleBuffer;
438 pofn->nMaxFileTitle = _MAX_PATH;
439 pofn->Flags = OFN_HIDEREADONLY;
440 /* some other fields may be set by the caller */
441 return TRUE;
444 static BOOL import_registry_filename(LPWSTR filename)
446 static const WCHAR rb_mode[] = {'r','b',0};
448 BOOL Success;
449 FILE* reg_file = _wfopen(filename, rb_mode);
451 if(!reg_file)
452 return FALSE;
454 Success = import_registry_file(reg_file);
456 if(fclose(reg_file) != 0)
457 Success = FALSE;
459 return Success;
462 static BOOL ImportRegistryFile(HWND hWnd)
464 OPENFILENAMEW ofn;
465 WCHAR title[128];
466 HKEY root_key = NULL;
467 WCHAR *key_path;
469 InitOpenFileName(hWnd, &ofn);
470 ofn.Flags |= OFN_ENABLESIZING;
471 LoadStringW(hInst, IDS_FILEDIALOG_IMPORT_TITLE, title, COUNT_OF(title));
472 ofn.lpstrTitle = title;
473 if (GetOpenFileNameW(&ofn)) {
474 if (!import_registry_filename(ofn.lpstrFile)) {
475 messagebox(hWnd, MB_OK|MB_ICONERROR, IDS_APP_TITLE, IDS_IMPORT_FAILED, ofn.lpstrFile);
476 return FALSE;
477 } else {
478 messagebox(hWnd, MB_OK|MB_ICONINFORMATION, IDS_APP_TITLE,
479 IDS_IMPORT_SUCCESSFUL, ofn.lpstrFile);
481 } else {
482 CheckCommDlgError(hWnd);
484 RefreshTreeView(g_pChildWnd->hTreeWnd);
486 key_path = GetItemPath(g_pChildWnd->hTreeWnd, 0, &root_key);
487 RefreshListView(g_pChildWnd->hListWnd, root_key, key_path, NULL);
488 heap_free(key_path);
490 return TRUE;
494 static BOOL ExportRegistryFile(HWND hWnd)
496 OPENFILENAMEW ofn;
497 WCHAR title[128];
499 InitOpenFileName(hWnd, &ofn);
500 LoadStringW(hInst, IDS_FILEDIALOG_EXPORT_TITLE, title, COUNT_OF(title));
501 ofn.lpstrTitle = title;
502 ofn.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
503 ofn.lpfnHook = ExportRegistryFile_OFNHookProc;
504 ofn.lpTemplateName = MAKEINTRESOURCEW(IDD_EXPORT_TEMPLATE);
505 if (GetSaveFileNameW(&ofn)) {
506 BOOL result;
507 result = export_registry_key(ofn.lpstrFile, (LPWSTR)ofn.lCustData, ofn.nFilterIndex);
508 if (!result) {
509 /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
510 return FALSE;
512 } else {
513 CheckCommDlgError(hWnd);
515 return TRUE;
518 static BOOL PrintRegistryHive(HWND hWnd, LPCWSTR path)
520 #if 1
521 PRINTDLGW pd;
523 ZeroMemory(&pd, sizeof(PRINTDLGW));
524 pd.lStructSize = sizeof(PRINTDLGW);
525 pd.hwndOwner = hWnd;
526 pd.hDevMode = NULL; /* Don't forget to free or store hDevMode*/
527 pd.hDevNames = NULL; /* Don't forget to free or store hDevNames*/
528 pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
529 pd.nCopies = 1;
530 pd.nFromPage = 0xFFFF;
531 pd.nToPage = 0xFFFF;
532 pd.nMinPage = 1;
533 pd.nMaxPage = 0xFFFF;
534 if (PrintDlgW(&pd)) {
535 FIXME("printing is not yet implemented.\n");
536 /* GDI calls to render output. */
537 DeleteDC(pd.hDC); /* Delete DC when done.*/
539 #else
540 HRESULT hResult;
541 PRINTDLGEXW pd;
543 hResult = PrintDlgExW(&pd);
544 if (hResult == S_OK) {
545 switch (pd.dwResultAction) {
546 case PD_RESULT_APPLY:
547 /*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. */
548 FIXME("printing is not yet implemented.\n");
549 break;
550 case PD_RESULT_CANCEL:
551 /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
552 break;
553 case PD_RESULT_PRINT:
554 FIXME("printing is not yet implemented.\n");
555 /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
556 break;
557 default:
558 break;
560 } else {
561 switch (hResult) {
562 case E_OUTOFMEMORY:
563 /*Insufficient memory. */
564 break;
565 case E_INVALIDARG:
566 /* One or more arguments are invalid. */
567 break;
568 case E_POINTER:
569 /*Invalid pointer. */
570 break;
571 case E_HANDLE:
572 /*Invalid handle. */
573 break;
574 case E_FAIL:
575 /*Unspecified error. */
576 break;
577 default:
578 break;
580 return FALSE;
582 #endif
583 return TRUE;
586 static BOOL CopyKeyName(HWND hWnd, LPCWSTR keyName)
588 BOOL result;
590 result = OpenClipboard(hWnd);
591 if (result) {
592 result = EmptyClipboard();
593 if (result) {
594 int len = (lstrlenW(keyName)+1)*sizeof(WCHAR);
595 HANDLE hClipData = GlobalAlloc(GHND, len);
596 LPVOID pLoc = GlobalLock(hClipData);
597 lstrcpyW(pLoc, keyName);
598 GlobalUnlock(hClipData);
599 SetClipboardData(CF_UNICODETEXT, hClipData);
601 } else {
602 /* error emptying clipboard*/
603 /* DWORD dwError = GetLastError(); */
606 if (!CloseClipboard()) {
607 /* error closing clipboard*/
608 /* DWORD dwError = GetLastError(); */
611 } else {
612 /* error opening clipboard*/
613 /* DWORD dwError = GetLastError(); */
616 return result;
619 static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
621 HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
623 switch(uMsg) {
624 case WM_INITDIALOG:
625 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
626 CheckDlgButton(hwndDlg, IDC_FIND_KEYS, searchMask&SEARCH_KEYS ? BST_CHECKED : BST_UNCHECKED);
627 CheckDlgButton(hwndDlg, IDC_FIND_VALUES, searchMask&SEARCH_VALUES ? BST_CHECKED : BST_UNCHECKED);
628 CheckDlgButton(hwndDlg, IDC_FIND_CONTENT, searchMask&SEARCH_CONTENT ? BST_CHECKED : BST_UNCHECKED);
629 CheckDlgButton(hwndDlg, IDC_FIND_WHOLE, searchMask&SEARCH_WHOLE ? BST_CHECKED : BST_UNCHECKED);
630 SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
631 SetWindowTextW(hwndValue, searchString);
632 return TRUE;
633 case WM_COMMAND:
634 switch(LOWORD(wParam)) {
635 case IDC_VALUE_NAME:
636 if (HIWORD(wParam) == EN_UPDATE) {
637 EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLengthW(hwndValue)>0);
638 return TRUE;
640 break;
641 case IDOK:
642 if (GetWindowTextLengthW(hwndValue)>0) {
643 int mask = 0;
644 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_KEYS)) mask |= SEARCH_KEYS;
645 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_VALUES)) mask |= SEARCH_VALUES;
646 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_CONTENT)) mask |= SEARCH_CONTENT;
647 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_WHOLE)) mask |= SEARCH_WHOLE;
648 searchMask = mask;
649 GetWindowTextW(hwndValue, searchString, 128);
650 EndDialog(hwndDlg, IDOK);
652 return TRUE;
653 case IDCANCEL:
654 EndDialog(hwndDlg, IDCANCEL);
655 return TRUE;
657 break;
659 return FALSE;
662 static INT_PTR CALLBACK addtofavorites_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
664 HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
666 switch(uMsg) {
667 case WM_INITDIALOG:
669 HTREEITEM selected;
670 TVITEMW item;
671 WCHAR buf[128];
673 selected = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
675 item.mask = TVIF_HANDLE | TVIF_TEXT;
676 item.hItem = selected;
677 item.pszText = buf;
678 item.cchTextMax = COUNT_OF(buf);
679 SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETITEMW, 0, (LPARAM)&item);
681 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
682 SetWindowTextW(hwndValue, buf);
683 SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
684 return TRUE;
686 case WM_COMMAND:
687 switch(LOWORD(wParam)) {
688 case IDC_VALUE_NAME:
689 if (HIWORD(wParam) == EN_UPDATE) {
690 EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLengthW(hwndValue) > 0);
691 return TRUE;
693 break;
694 case IDOK:
695 if (GetWindowTextLengthW(hwndValue)>0) {
696 GetWindowTextW(hwndValue, favoriteName, 128);
697 EndDialog(hwndDlg, IDOK);
699 return TRUE;
700 case IDCANCEL:
701 EndDialog(hwndDlg, IDCANCEL);
702 return TRUE;
704 break;
706 return FALSE;
709 static INT_PTR CALLBACK removefavorite_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
711 HWND hwndList = GetDlgItem(hwndDlg, IDC_NAME_LIST);
713 switch(uMsg) {
714 case WM_INITDIALOG:
715 if (!add_favourite_key_items(NULL, hwndList))
716 return FALSE;
717 SendMessageW(hwndList, LB_SETCURSEL, 0, 0);
718 return TRUE;
719 case WM_COMMAND:
720 switch(LOWORD(wParam)) {
721 case IDC_NAME_LIST:
722 if (HIWORD(wParam) == LBN_SELCHANGE) {
723 EnableWindow(GetDlgItem(hwndDlg, IDOK), lParam != -1);
724 return TRUE;
726 break;
727 case IDOK: {
728 int pos = SendMessageW(hwndList, LB_GETCURSEL, 0, 0);
729 int len = SendMessageW(hwndList, LB_GETTEXTLEN, pos, 0);
730 if (len>0) {
731 WCHAR *lpName = heap_xalloc((len + 1) * sizeof(WCHAR));
732 SendMessageW(hwndList, LB_GETTEXT, pos, (LPARAM)lpName);
733 if (len>127)
734 lpName[127] = '\0';
735 lstrcpyW(favoriteName, lpName);
736 EndDialog(hwndDlg, IDOK);
737 heap_free(lpName);
739 return TRUE;
741 case IDCANCEL:
742 EndDialog(hwndDlg, IDCANCEL);
743 return TRUE;
745 break;
747 return FALSE;
750 /*******************************************************************************
752 * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
754 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
757 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
759 HKEY hKeyRoot = 0;
760 DWORD valueType;
762 if (LOWORD(wParam) >= ID_FAVORITE_FIRST && LOWORD(wParam) <= ID_FAVORITE_LAST) {
763 HKEY hKey;
764 if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
765 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
766 WCHAR namebuf[KEY_MAX_LEN];
767 BYTE valuebuf[4096];
768 DWORD ksize = KEY_MAX_LEN, vsize = sizeof(valuebuf), type = 0;
769 if (RegEnumValueW(hKey, LOWORD(wParam) - ID_FAVORITE_FIRST, namebuf, &ksize, NULL,
770 &type, valuebuf, &vsize) == ERROR_SUCCESS) {
771 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET,
772 (LPARAM) FindPathInTree(g_pChildWnd->hTreeWnd, (WCHAR *)valuebuf) );
774 RegCloseKey(hKey);
776 return TRUE;
778 switch (LOWORD(wParam)) {
779 case ID_REGISTRY_IMPORTREGISTRYFILE:
780 ImportRegistryFile(hWnd);
781 break;
782 case ID_EDIT_EXPORT:
783 case ID_REGISTRY_EXPORTREGISTRYFILE:
784 ExportRegistryFile(hWnd);
785 break;
786 case ID_REGISTRY_PRINT:
788 const WCHAR empty = 0;
789 PrintRegistryHive(hWnd, &empty);
790 break;
792 case ID_EDIT_DELETE:
794 HWND hWndDelete = GetFocus();
795 if (hWndDelete == g_pChildWnd->hTreeWnd) {
796 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
797 if (keyPath == 0 || *keyPath == 0) {
798 MessageBeep(MB_ICONHAND);
799 } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) {
800 DeleteNode(g_pChildWnd->hTreeWnd, 0);
802 heap_free(keyPath);
803 } else if (hWndDelete == g_pChildWnd->hListWnd) {
804 unsigned int num_selected, index, focus_idx;
805 WCHAR *keyPath;
807 if (!(num_selected = SendMessageW(g_pChildWnd->hListWnd, LVM_GETSELECTEDCOUNT, 0, 0L)))
808 break;
810 if (num_selected > 1)
812 if (messagebox(hWnd, MB_YESNO | MB_ICONEXCLAMATION, IDS_DELETE_VALUE_TITLE,
813 IDS_DELETE_VALUE_TEXT_MULTIPLE) != IDYES)
814 break;
817 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
819 focus_idx = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED, 0));
820 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));
822 while (index != -1)
824 WCHAR *valueName = GetItemText(g_pChildWnd->hListWnd, index);
825 if (!DeleteValue(hWnd, hKeyRoot, keyPath, valueName, num_selected == 1))
827 heap_free(valueName);
828 break;
830 heap_free(valueName);
831 SendMessageW(g_pChildWnd->hListWnd, LVM_DELETEITEM, index, 0L);
832 /* the default value item is always visible, so add it back in */
833 if (!index)
835 AddEntryToList(g_pChildWnd->hListWnd, NULL, REG_SZ, NULL, 0, 0);
836 if (!focus_idx)
838 LVITEMW item;
839 item.state = item.stateMask = LVIS_FOCUSED;
840 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
843 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));
845 heap_free(keyPath);
846 } else if (IsChild(g_pChildWnd->hTreeWnd, hWndDelete) ||
847 IsChild(g_pChildWnd->hListWnd, hWndDelete)) {
848 SendMessageW(hWndDelete, WM_KEYDOWN, VK_DELETE, 0);
850 break;
852 case ID_EDIT_MODIFY:
853 case ID_EDIT_MODIFY_BIN:
855 LPCWSTR valueName = GetValueName(g_pChildWnd->hListWnd);
856 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
857 ModifyValue(hWnd, hKeyRoot, keyPath, valueName);
858 heap_free(keyPath);
859 break;
861 case ID_EDIT_FIND:
862 case ID_EDIT_FINDNEXT:
864 HTREEITEM hItem;
865 if (LOWORD(wParam) == ID_EDIT_FIND &&
866 DialogBoxW(0, MAKEINTRESOURCEW(IDD_FIND), hWnd, find_dlgproc) != IDOK)
867 break;
868 if (!*searchString)
869 break;
870 hItem = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
871 if (hItem) {
872 int row = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED, 0));
873 HCURSOR hcursorOld = SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_WAIT));
874 hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
875 SetCursor(hcursorOld);
876 if (hItem) {
877 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
878 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
879 UpdateWindow(g_pChildWnd->hTreeWnd);
880 if (row != -1) {
881 LVITEMW item;
883 item.state = 0;
884 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
885 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, (UINT)-1, (LPARAM)&item);
887 item.state = LVIS_FOCUSED | LVIS_SELECTED;
888 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
889 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, row, (LPARAM)&item);
890 SetFocus(g_pChildWnd->hListWnd);
891 } else {
892 SetFocus(g_pChildWnd->hTreeWnd);
894 } else {
895 messagebox(hWnd, MB_OK|MB_ICONINFORMATION, IDS_APP_TITLE, IDS_NOTFOUND, searchString);
898 break;
900 case ID_EDIT_COPYKEYNAME:
902 LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
903 if (fullPath) {
904 CopyKeyName(hWnd, fullPath);
905 heap_free(fullPath);
907 break;
909 case ID_EDIT_NEW_KEY:
911 WCHAR newKeyW[MAX_NEW_KEY_LEN];
912 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
913 if (CreateKey(hWnd, hKeyRoot, keyPath, newKeyW)) {
914 if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
915 StartKeyRename(g_pChildWnd->hTreeWnd);
917 heap_free(keyPath);
919 break;
920 case ID_EDIT_NEW_STRINGVALUE:
921 valueType = REG_SZ;
922 goto create_value;
923 case ID_EDIT_NEW_EXPANDVALUE:
924 valueType = REG_EXPAND_SZ;
925 goto create_value;
926 case ID_EDIT_NEW_MULTI_STRINGVALUE:
927 valueType = REG_MULTI_SZ;
928 goto create_value;
929 case ID_EDIT_NEW_BINARYVALUE:
930 valueType = REG_BINARY;
931 goto create_value;
932 case ID_EDIT_NEW_DWORDVALUE:
933 valueType = REG_DWORD;
934 /* fall through */
935 create_value:
937 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
938 WCHAR newKey[MAX_NEW_KEY_LEN];
939 if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey))
940 StartValueRename(g_pChildWnd->hListWnd);
941 heap_free(keyPath);
943 break;
944 case ID_EDIT_RENAME:
946 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
947 if (keyPath == 0 || *keyPath == 0) {
948 MessageBeep(MB_ICONHAND);
949 } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
950 StartKeyRename(g_pChildWnd->hTreeWnd);
951 } else if (GetFocus() == g_pChildWnd->hListWnd) {
952 StartValueRename(g_pChildWnd->hListWnd);
954 heap_free(keyPath);
955 break;
957 case ID_TREE_EXPAND_COLLAPSE:
959 HTREEITEM selected = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
960 SendMessageW(g_pChildWnd->hTreeWnd, TVM_EXPAND, TVE_TOGGLE, (LPARAM)selected);
961 break;
963 case ID_REGISTRY_PRINTERSETUP:
964 /*PRINTDLG pd;*/
965 /*PrintDlg(&pd);*/
966 /*PAGESETUPDLG psd;*/
967 /*PageSetupDlg(&psd);*/
968 break;
969 case ID_REGISTRY_OPENLOCAL:
970 break;
971 case ID_REGISTRY_EXIT:
972 DestroyWindow(hWnd);
973 break;
974 case ID_FAVORITES_ADDTOFAVORITES:
976 HKEY hKey;
977 LPWSTR lpKeyPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
978 if (lpKeyPath) {
979 if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
980 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
981 0, NULL, 0,
982 KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
983 RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
984 RegCloseKey(hKey);
987 heap_free(lpKeyPath);
989 break;
991 case ID_FAVORITES_REMOVEFAVORITE:
993 if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
994 HKEY hKey;
995 if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
996 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
997 RegDeleteValueW(hKey, favoriteName);
998 RegCloseKey(hKey);
1001 break;
1003 case ID_VIEW_REFRESH:
1005 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1006 RefreshTreeView(g_pChildWnd->hTreeWnd);
1007 RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
1008 heap_free(keyPath);
1010 break;
1011 /*case ID_OPTIONS_TOOLBAR:*/
1012 /* toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
1013 /* break;*/
1014 case ID_VIEW_STATUSBAR:
1015 toggle_child(hWnd, LOWORD(wParam), hStatusBar);
1016 break;
1017 case ID_HELP_HELPTOPICS:
1019 const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
1020 WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
1021 break;
1023 case ID_HELP_ABOUT:
1024 ShowAboutBox(hWnd);
1025 break;
1026 case ID_VIEW_SPLIT: {
1027 RECT rt;
1028 POINT pt, pts;
1029 GetClientRect(g_pChildWnd->hWnd, &rt);
1030 pt.x = rt.left + g_pChildWnd->nSplitPos;
1031 pt.y = (rt.bottom / 2);
1032 pts = pt;
1033 if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
1034 SetCursorPos(pts.x, pts.y);
1035 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_SIZEWE));
1036 SendMessageW(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
1038 return TRUE;
1040 default:
1041 return FALSE;
1044 return TRUE;
1047 /********************************************************************************
1049 * FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
1051 * PURPOSE: Processes messages for the main frame window.
1053 * WM_COMMAND - process the application menu
1054 * WM_DESTROY - post a quit message and return
1058 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1060 static const WCHAR captionW[] = {'r','e','g','e','d','i','t',' ','c','h','i','l','d',' ','w','i','n','d','o','w',0};
1062 switch (message) {
1063 case WM_CREATE:
1064 CreateWindowExW(0, szChildClass, captionW, WS_CHILD | WS_VISIBLE,
1065 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1066 hWnd, NULL, hInst, 0);
1067 LoadStringW(hInst, IDS_EXPAND, expandW, COUNT_OF(expandW));
1068 LoadStringW(hInst, IDS_COLLAPSE, collapseW, COUNT_OF(collapseW));
1069 LoadStringW(hInst, IDS_EDIT_MODIFY, modifyW, COUNT_OF(modifyW));
1070 LoadStringW(hInst, IDS_EDIT_MODIFY_BIN, modify_binaryW, COUNT_OF(modify_binaryW));
1071 break;
1072 case WM_COMMAND:
1073 if (!_CmdWndProc(hWnd, message, wParam, lParam))
1074 return DefWindowProcW(hWnd, message, wParam, lParam);
1075 break;
1076 case WM_ACTIVATE:
1077 if (LOWORD(hWnd))
1078 SetFocus(g_pChildWnd->hWnd);
1079 break;
1080 case WM_SIZE:
1081 resize_frame_client(hWnd);
1082 break;
1083 case WM_TIMER:
1084 break;
1085 case WM_ENTERMENULOOP:
1086 OnEnterMenuLoop(hWnd);
1087 break;
1088 case WM_EXITMENULOOP:
1089 OnExitMenuLoop(hWnd);
1090 break;
1091 case WM_INITMENUPOPUP:
1092 if (!HIWORD(lParam))
1093 OnInitMenuPopup(hWnd, (HMENU)wParam);
1094 break;
1095 case WM_MENUSELECT:
1096 OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
1097 break;
1098 case WM_DESTROY:
1100 const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
1101 WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
1102 PostQuitMessage(0);
1104 default:
1105 return DefWindowProcW(hWnd, message, wParam, lParam);
1107 return 0;