ntdll: Move the plaform-independent thread data to the GdiTebBatch TEB field.
[wine.git] / programs / regedit / framewnd.c
blob361da7e9507c4db376944dfa349763682514fb90
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 RECT rt;
62 if (IsWindowVisible(hToolBar)) {
63 SendMessageW(hToolBar, WM_SIZE, 0, 0);
64 GetClientRect(hToolBar, &rt);
65 prect->top = rt.bottom+3;
66 prect->bottom -= rt.bottom+3;
69 if (IsWindowVisible(hStatusBar)) {
70 SetupStatusBar(hWnd, TRUE);
71 GetClientRect(hStatusBar, &rt);
72 prect->bottom -= rt.bottom;
74 MoveWindow(g_pChildWnd->hWnd, prect->left, prect->top, prect->right, prect->bottom, TRUE);
77 static void resize_frame_client(HWND hWnd)
79 RECT rect;
81 GetClientRect(hWnd, &rect);
82 resize_frame_rect(hWnd, &rect);
85 /********************************************************************************/
87 static void OnEnterMenuLoop(HWND hWnd)
89 int nParts;
90 WCHAR empty = 0;
92 /* Update the status bar pane sizes */
93 nParts = -1;
94 SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
95 bInMenuLoop = TRUE;
96 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)&empty);
99 static void OnExitMenuLoop(HWND hWnd)
101 bInMenuLoop = FALSE;
102 /* Update the status bar pane sizes*/
103 SetupStatusBar(hWnd, TRUE);
104 UpdateStatusBar();
107 static void update_expand_or_collapse_item(HWND hwndTV, HTREEITEM selection, HMENU hMenu)
109 TVITEMW item;
110 MENUITEMINFOW info;
112 item.hItem = selection;
113 item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE;
114 item.stateMask = TVIS_EXPANDED;
115 SendMessageW(hwndTV, TVM_GETITEMW, 0, (LPARAM)&item);
117 info.cbSize = sizeof(MENUITEMINFOW);
118 info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
119 info.fType = MFT_STRING;
120 info.fState = MFS_ENABLED;
121 info.dwTypeData = expandW;
123 if (!item.cChildren)
125 info.fState = MFS_GRAYED;
126 goto update;
129 if (item.state & TVIS_EXPANDED)
130 info.dwTypeData = collapseW;
132 update:
133 SetMenuItemInfoW(hMenu, ID_TREE_EXPAND_COLLAPSE, FALSE, &info);
136 static void update_modify_items(HMENU hMenu, int index)
138 unsigned int state = MF_ENABLED;
140 if (index == -1)
141 state = MF_GRAYED;
143 EnableMenuItem(hMenu, ID_EDIT_MODIFY, state | MF_BYCOMMAND);
144 EnableMenuItem(hMenu, ID_EDIT_MODIFY_BIN, state | MF_BYCOMMAND);
147 static void update_delete_and_rename_items(HMENU hMenu, WCHAR *keyName, int index)
149 unsigned int state_d = MF_ENABLED, state_r = MF_ENABLED;
151 if (!g_pChildWnd->nFocusPanel)
153 if (!keyName || !*keyName)
154 state_d = state_r = MF_GRAYED;
156 else if (index < 1)
158 state_r = MF_GRAYED;
159 if (index == -1) state_d = MF_GRAYED;
162 EnableMenuItem(hMenu, ID_EDIT_DELETE, state_d | MF_BYCOMMAND);
163 EnableMenuItem(hMenu, ID_EDIT_RENAME, state_r | MF_BYCOMMAND);
166 static void update_new_items_and_copy_keyname(HMENU hMenu, WCHAR *keyName)
168 unsigned int state = MF_ENABLED, i;
169 unsigned int items[] = {ID_EDIT_NEW_KEY, ID_EDIT_NEW_STRINGVALUE, ID_EDIT_NEW_BINARYVALUE,
170 ID_EDIT_NEW_DWORDVALUE, ID_EDIT_NEW_MULTI_STRINGVALUE,
171 ID_EDIT_NEW_EXPANDVALUE, ID_EDIT_COPYKEYNAME};
173 if (!keyName)
174 state = MF_GRAYED;
176 for (i = 0; i < COUNT_OF(items); i++)
177 EnableMenuItem(hMenu, items[i], state | MF_BYCOMMAND);
180 static void UpdateMenuItems(HMENU hMenu) {
181 HWND hwndTV = g_pChildWnd->hTreeWnd;
182 HKEY hRootKey = NULL;
183 LPWSTR keyName;
184 HTREEITEM selection;
185 int index;
187 selection = (HTREEITEM)SendMessageW(hwndTV, TVM_GETNEXTITEM, TVGN_CARET, 0);
188 keyName = GetItemPath(hwndTV, selection, &hRootKey);
189 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1,
190 MAKELPARAM(LVNI_FOCUSED | LVNI_SELECTED, 0));
192 update_expand_or_collapse_item(hwndTV, selection, hMenu);
193 update_modify_items(hMenu, index);
194 update_delete_and_rename_items(hMenu, keyName, index);
195 update_new_items_and_copy_keyname(hMenu, keyName);
196 EnableMenuItem(hMenu, ID_FAVORITES_ADDTOFAVORITES, (hRootKey ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
197 EnableMenuItem(hMenu, ID_FAVORITES_REMOVEFAVORITE,
198 (GetMenuItemCount(hMenu)>2 ? MF_ENABLED : MF_GRAYED) | MF_BYCOMMAND);
200 HeapFree(GetProcessHeap(), 0, keyName);
203 static void add_remove_modify_menu_items(HMENU hMenu)
205 if (!g_pChildWnd->nFocusPanel)
207 while (GetMenuItemCount(hMenu) > 9)
208 DeleteMenu(hMenu, 0, MF_BYPOSITION);
210 else if (GetMenuItemCount(hMenu) < 10)
212 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, 0);
213 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_STRING, ID_EDIT_MODIFY_BIN, modify_binaryW);
214 InsertMenuW(hMenu, 0, MF_BYPOSITION | MF_STRING, ID_EDIT_MODIFY, modifyW);
218 static int add_favourite_key_items(HMENU hMenu, HWND hList)
220 HKEY hkey;
221 LONG rc;
222 DWORD num_values, max_value_len, value_len, type, i = 0;
223 WCHAR *value_name;
225 rc = RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey, 0, KEY_READ, &hkey);
226 if (rc != ERROR_SUCCESS) return 0;
228 rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &num_values,
229 &max_value_len, NULL, NULL, NULL);
230 if (rc != ERROR_SUCCESS)
232 ERR("RegQueryInfoKey failed: %d\n", rc);
233 goto exit;
236 if (!num_values) goto exit;
238 max_value_len++;
239 value_name = HeapAlloc(GetProcessHeap(), 0, max_value_len * sizeof(WCHAR));
240 CHECK_ENOUGH_MEMORY(value_name);
242 if (hMenu) AppendMenuW(hMenu, MF_SEPARATOR, 0, 0);
244 for (i = 0; i < num_values; i++)
246 value_len = max_value_len;
247 rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, NULL, NULL);
248 if (rc == ERROR_SUCCESS && type == REG_SZ)
250 if (hMenu)
251 AppendMenuW(hMenu, MF_ENABLED | MF_STRING, ID_FAVORITE_FIRST + i, value_name);
252 else if (hList)
253 SendMessageW(hList, LB_ADDSTRING, 0, (LPARAM)value_name);
257 HeapFree(GetProcessHeap(), 0, value_name);
258 exit:
259 RegCloseKey(hkey);
260 return i;
263 static void OnInitMenuPopup(HWND hWnd, HMENU hMenu)
265 if (hMenu == GetSubMenu(hMenuFrame, ID_EDIT_MENU))
266 add_remove_modify_menu_items(hMenu);
267 else if (hMenu == GetSubMenu(hMenuFrame, ID_FAVORITES_MENU))
269 while (GetMenuItemCount(hMenu) > 2)
270 DeleteMenu(hMenu, 2, MF_BYPOSITION);
272 add_favourite_key_items(hMenu, NULL);
275 UpdateMenuItems(hMenu);
278 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
280 WCHAR str[100];
282 str[0] = 0;
283 if (nFlags & MF_POPUP) {
284 if (hSysMenu != GetMenu(hWnd)) {
285 if (nItemID == 2) nItemID = 5;
288 if (LoadStringW(hInst, nItemID, str, 100)) {
289 /* load appropriate string*/
290 LPWSTR lpsz = str;
291 /* first newline terminates actual string*/
292 lpsz = strchrW(lpsz, '\n');
293 if (lpsz != NULL)
294 *lpsz = '\0';
296 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)str);
299 void SetupStatusBar(HWND hWnd, BOOL bResize)
301 RECT rc;
302 int nParts;
303 GetClientRect(hWnd, &rc);
304 nParts = rc.right;
305 /* nParts = -1;*/
306 if (bResize)
307 SendMessageW(hStatusBar, WM_SIZE, 0, 0);
308 SendMessageW(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
309 UpdateStatusBar();
312 void UpdateStatusBar(void)
314 LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, TRUE);
315 SendMessageW(hStatusBar, SB_SETTEXTW, 0, (LPARAM)fullPath);
316 HeapFree(GetProcessHeap(), 0, fullPath);
319 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
321 BOOL vis = IsWindowVisible(hchild);
322 HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
324 CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
325 ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
326 resize_frame_client(hWnd);
329 static BOOL CheckCommDlgError(HWND hWnd)
331 DWORD dwErrorCode = CommDlgExtendedError();
332 switch (dwErrorCode) {
333 case CDERR_DIALOGFAILURE:
334 break;
335 case CDERR_FINDRESFAILURE:
336 break;
337 case CDERR_NOHINSTANCE:
338 break;
339 case CDERR_INITIALIZATION:
340 break;
341 case CDERR_NOHOOK:
342 break;
343 case CDERR_LOCKRESFAILURE:
344 break;
345 case CDERR_NOTEMPLATE:
346 break;
347 case CDERR_LOADRESFAILURE:
348 break;
349 case CDERR_STRUCTSIZE:
350 break;
351 case CDERR_LOADSTRFAILURE:
352 break;
353 case FNERR_BUFFERTOOSMALL:
354 break;
355 case CDERR_MEMALLOCFAILURE:
356 break;
357 case FNERR_INVALIDFILENAME:
358 break;
359 case CDERR_MEMLOCKFAILURE:
360 break;
361 case FNERR_SUBCLASSFAILURE:
362 break;
363 default:
364 break;
366 return TRUE;
369 static void ExportRegistryFile_StoreSelection(HWND hdlg, OPENFILENAMEW *pOpenFileName)
371 if (IsDlgButtonChecked(hdlg, IDC_EXPORT_SELECTED))
373 INT len = SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXTLENGTH, 0, 0);
374 pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
375 SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_GETTEXT, len+1, pOpenFileName->lCustData);
377 else
378 pOpenFileName->lCustData = (LPARAM)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
381 static UINT_PTR CALLBACK ExportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
383 static OPENFILENAMEW* pOpenFileName;
384 OFNOTIFYW *pOfNotify;
386 switch (uiMsg) {
387 case WM_INITDIALOG:
388 pOpenFileName = (OPENFILENAMEW*)lParam;
389 break;
390 case WM_COMMAND:
391 if (LOWORD(wParam) == IDC_EXPORT_PATH && HIWORD(wParam) == EN_UPDATE)
392 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, IDC_EXPORT_SELECTED);
393 break;
394 case WM_NOTIFY:
395 pOfNotify = (OFNOTIFYW*)lParam;
396 switch (pOfNotify->hdr.code)
398 case CDN_INITDONE:
400 BOOL export_branch = FALSE;
401 WCHAR* path = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
402 SendDlgItemMessageW(hdlg, IDC_EXPORT_PATH, WM_SETTEXT, 0, (LPARAM)path);
403 if (path && path[0])
404 export_branch = TRUE;
405 HeapFree(GetProcessHeap(), 0, path);
406 CheckRadioButton(hdlg, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, export_branch ? IDC_EXPORT_SELECTED : IDC_EXPORT_ALL);
407 break;
409 case CDN_FILEOK:
410 ExportRegistryFile_StoreSelection(hdlg, pOpenFileName);
411 break;
413 break;
414 default:
415 break;
417 return 0L;
421 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAMEW *pofn)
423 memset(pofn, 0, sizeof(OPENFILENAMEW));
424 pofn->lStructSize = sizeof(OPENFILENAMEW);
425 pofn->hwndOwner = hWnd;
426 pofn->hInstance = hInst;
428 if (FilterBuffer[0] == 0)
430 static const WCHAR filterW[] = {'%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','r','e','g','%','c','%','s','%','c','*','.','*','%','c',0};
431 WCHAR filter_reg[MAX_PATH], filter_reg4[MAX_PATH], filter_all[MAX_PATH];
433 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG, filter_reg, MAX_PATH);
434 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_REG4, filter_reg4, MAX_PATH);
435 LoadStringW(hInst, IDS_FILEDIALOG_FILTER_ALL, filter_all, MAX_PATH);
436 snprintfW( FilterBuffer, MAX_PATH, filterW, filter_reg, 0, 0, filter_reg4, 0, 0, filter_all, 0, 0 );
438 pofn->lpstrFilter = FilterBuffer;
439 pofn->nFilterIndex = 2;
440 pofn->lpstrFile = FileNameBuffer;
441 pofn->nMaxFile = _MAX_PATH;
442 pofn->lpstrFileTitle = FileTitleBuffer;
443 pofn->nMaxFileTitle = _MAX_PATH;
444 pofn->Flags = OFN_HIDEREADONLY;
445 /* some other fields may be set by the caller */
446 return TRUE;
449 static BOOL import_registry_filename(LPWSTR filename)
451 static const WCHAR rb_mode[] = {'r','b',0};
453 BOOL Success;
454 FILE* reg_file = _wfopen(filename, rb_mode);
456 if(!reg_file)
457 return FALSE;
459 Success = import_registry_file(reg_file);
461 if(fclose(reg_file) != 0)
462 Success = FALSE;
464 return Success;
467 static BOOL ImportRegistryFile(HWND hWnd)
469 OPENFILENAMEW ofn;
470 WCHAR title[128];
471 HKEY root_key = NULL;
472 WCHAR *key_path;
474 InitOpenFileName(hWnd, &ofn);
475 ofn.Flags |= OFN_ENABLESIZING;
476 LoadStringW(hInst, IDS_FILEDIALOG_IMPORT_TITLE, title, COUNT_OF(title));
477 ofn.lpstrTitle = title;
478 if (GetOpenFileNameW(&ofn)) {
479 if (!import_registry_filename(ofn.lpstrFile)) {
480 messagebox(hWnd, MB_OK|MB_ICONERROR, IDS_APP_TITLE, IDS_IMPORT_FAILED, ofn.lpstrFile);
481 return FALSE;
482 } else {
483 messagebox(hWnd, MB_OK|MB_ICONINFORMATION, IDS_APP_TITLE,
484 IDS_IMPORT_SUCCESSFUL, ofn.lpstrFile);
486 } else {
487 CheckCommDlgError(hWnd);
489 RefreshTreeView(g_pChildWnd->hTreeWnd);
491 key_path = GetItemPath(g_pChildWnd->hTreeWnd, 0, &root_key);
492 RefreshListView(g_pChildWnd->hListWnd, root_key, key_path, NULL);
493 HeapFree(GetProcessHeap(), 0, key_path);
495 return TRUE;
499 static BOOL ExportRegistryFile(HWND hWnd)
501 OPENFILENAMEW ofn;
502 WCHAR title[128];
504 InitOpenFileName(hWnd, &ofn);
505 LoadStringW(hInst, IDS_FILEDIALOG_EXPORT_TITLE, title, COUNT_OF(title));
506 ofn.lpstrTitle = title;
507 ofn.Flags = OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
508 ofn.lpfnHook = ExportRegistryFile_OFNHookProc;
509 ofn.lpTemplateName = MAKEINTRESOURCEW(IDD_EXPORT_TEMPLATE);
510 if (GetSaveFileNameW(&ofn)) {
511 BOOL result;
512 result = export_registry_key(ofn.lpstrFile, (LPWSTR)ofn.lCustData, ofn.nFilterIndex);
513 if (!result) {
514 /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
515 return FALSE;
517 } else {
518 CheckCommDlgError(hWnd);
520 return TRUE;
523 static BOOL PrintRegistryHive(HWND hWnd, LPCWSTR path)
525 #if 1
526 PRINTDLGW pd;
528 ZeroMemory(&pd, sizeof(PRINTDLGW));
529 pd.lStructSize = sizeof(PRINTDLGW);
530 pd.hwndOwner = hWnd;
531 pd.hDevMode = NULL; /* Don't forget to free or store hDevMode*/
532 pd.hDevNames = NULL; /* Don't forget to free or store hDevNames*/
533 pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
534 pd.nCopies = 1;
535 pd.nFromPage = 0xFFFF;
536 pd.nToPage = 0xFFFF;
537 pd.nMinPage = 1;
538 pd.nMaxPage = 0xFFFF;
539 if (PrintDlgW(&pd)) {
540 FIXME("printing is not yet implemented.\n");
541 /* GDI calls to render output. */
542 DeleteDC(pd.hDC); /* Delete DC when done.*/
544 #else
545 HRESULT hResult;
546 PRINTDLGEXW pd;
548 hResult = PrintDlgExW(&pd);
549 if (hResult == S_OK) {
550 switch (pd.dwResultAction) {
551 case PD_RESULT_APPLY:
552 /*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. */
553 FIXME("printing is not yet implemented.\n");
554 break;
555 case PD_RESULT_CANCEL:
556 /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
557 break;
558 case PD_RESULT_PRINT:
559 FIXME("printing is not yet implemented.\n");
560 /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
561 break;
562 default:
563 break;
565 } else {
566 switch (hResult) {
567 case E_OUTOFMEMORY:
568 /*Insufficient memory. */
569 break;
570 case E_INVALIDARG:
571 /* One or more arguments are invalid. */
572 break;
573 case E_POINTER:
574 /*Invalid pointer. */
575 break;
576 case E_HANDLE:
577 /*Invalid handle. */
578 break;
579 case E_FAIL:
580 /*Unspecified error. */
581 break;
582 default:
583 break;
585 return FALSE;
587 #endif
588 return TRUE;
591 static BOOL CopyKeyName(HWND hWnd, LPCWSTR keyName)
593 BOOL result;
595 result = OpenClipboard(hWnd);
596 if (result) {
597 result = EmptyClipboard();
598 if (result) {
599 int len = (lstrlenW(keyName)+1)*sizeof(WCHAR);
600 HANDLE hClipData = GlobalAlloc(GHND, len);
601 LPVOID pLoc = GlobalLock(hClipData);
602 lstrcpyW(pLoc, keyName);
603 GlobalUnlock(hClipData);
604 SetClipboardData(CF_UNICODETEXT, hClipData);
606 } else {
607 /* error emptying clipboard*/
608 /* DWORD dwError = GetLastError(); */
611 if (!CloseClipboard()) {
612 /* error closing clipboard*/
613 /* DWORD dwError = GetLastError(); */
616 } else {
617 /* error opening clipboard*/
618 /* DWORD dwError = GetLastError(); */
621 return result;
624 static INT_PTR CALLBACK find_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
626 HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
628 switch(uMsg) {
629 case WM_INITDIALOG:
630 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
631 CheckDlgButton(hwndDlg, IDC_FIND_KEYS, searchMask&SEARCH_KEYS ? BST_CHECKED : BST_UNCHECKED);
632 CheckDlgButton(hwndDlg, IDC_FIND_VALUES, searchMask&SEARCH_VALUES ? BST_CHECKED : BST_UNCHECKED);
633 CheckDlgButton(hwndDlg, IDC_FIND_CONTENT, searchMask&SEARCH_CONTENT ? BST_CHECKED : BST_UNCHECKED);
634 CheckDlgButton(hwndDlg, IDC_FIND_WHOLE, searchMask&SEARCH_WHOLE ? BST_CHECKED : BST_UNCHECKED);
635 SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
636 SetWindowTextW(hwndValue, searchString);
637 return TRUE;
638 case WM_COMMAND:
639 switch(LOWORD(wParam)) {
640 case IDC_VALUE_NAME:
641 if (HIWORD(wParam) == EN_UPDATE) {
642 EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLengthW(hwndValue)>0);
643 return TRUE;
645 break;
646 case IDOK:
647 if (GetWindowTextLengthW(hwndValue)>0) {
648 int mask = 0;
649 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_KEYS)) mask |= SEARCH_KEYS;
650 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_VALUES)) mask |= SEARCH_VALUES;
651 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_CONTENT)) mask |= SEARCH_CONTENT;
652 if (IsDlgButtonChecked(hwndDlg, IDC_FIND_WHOLE)) mask |= SEARCH_WHOLE;
653 searchMask = mask;
654 GetWindowTextW(hwndValue, searchString, 128);
655 EndDialog(hwndDlg, IDOK);
657 return TRUE;
658 case IDCANCEL:
659 EndDialog(hwndDlg, IDCANCEL);
660 return TRUE;
662 break;
664 return FALSE;
667 static INT_PTR CALLBACK addtofavorites_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
669 HWND hwndValue = GetDlgItem(hwndDlg, IDC_VALUE_NAME);
671 switch(uMsg) {
672 case WM_INITDIALOG:
674 HTREEITEM selected;
675 TVITEMW item;
676 WCHAR buf[128];
678 selected = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
680 item.mask = TVIF_HANDLE | TVIF_TEXT;
681 item.hItem = selected;
682 item.pszText = buf;
683 item.cchTextMax = COUNT_OF(buf);
684 SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETITEMW, 0, (LPARAM)&item);
686 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
687 SetWindowTextW(hwndValue, buf);
688 SendMessageW(hwndValue, EM_SETLIMITTEXT, 127, 0);
689 return TRUE;
691 case WM_COMMAND:
692 switch(LOWORD(wParam)) {
693 case IDC_VALUE_NAME:
694 if (HIWORD(wParam) == EN_UPDATE) {
695 EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLengthW(hwndValue) > 0);
696 return TRUE;
698 break;
699 case IDOK:
700 if (GetWindowTextLengthW(hwndValue)>0) {
701 GetWindowTextW(hwndValue, favoriteName, 128);
702 EndDialog(hwndDlg, IDOK);
704 return TRUE;
705 case IDCANCEL:
706 EndDialog(hwndDlg, IDCANCEL);
707 return TRUE;
709 break;
711 return FALSE;
714 static INT_PTR CALLBACK removefavorite_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
716 HWND hwndList = GetDlgItem(hwndDlg, IDC_NAME_LIST);
718 switch(uMsg) {
719 case WM_INITDIALOG:
720 if (!add_favourite_key_items(NULL, hwndList))
721 return FALSE;
722 SendMessageW(hwndList, LB_SETCURSEL, 0, 0);
723 return TRUE;
724 case WM_COMMAND:
725 switch(LOWORD(wParam)) {
726 case IDC_NAME_LIST:
727 if (HIWORD(wParam) == LBN_SELCHANGE) {
728 EnableWindow(GetDlgItem(hwndDlg, IDOK), lParam != -1);
729 return TRUE;
731 break;
732 case IDOK: {
733 int pos = SendMessageW(hwndList, LB_GETCURSEL, 0, 0);
734 int len = SendMessageW(hwndList, LB_GETTEXTLEN, pos, 0);
735 if (len>0) {
736 LPWSTR lpName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
737 SendMessageW(hwndList, LB_GETTEXT, pos, (LPARAM)lpName);
738 if (len>127)
739 lpName[127] = '\0';
740 lstrcpyW(favoriteName, lpName);
741 EndDialog(hwndDlg, IDOK);
742 HeapFree(GetProcessHeap(), 0, lpName);
744 return TRUE;
746 case IDCANCEL:
747 EndDialog(hwndDlg, IDCANCEL);
748 return TRUE;
750 break;
752 return FALSE;
755 /*******************************************************************************
757 * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
759 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
762 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
764 HKEY hKeyRoot = 0;
765 DWORD valueType;
767 if (LOWORD(wParam) >= ID_FAVORITE_FIRST && LOWORD(wParam) <= ID_FAVORITE_LAST) {
768 HKEY hKey;
769 if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
770 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
771 WCHAR namebuf[KEY_MAX_LEN];
772 BYTE valuebuf[4096];
773 DWORD ksize = KEY_MAX_LEN, vsize = sizeof(valuebuf), type = 0;
774 if (RegEnumValueW(hKey, LOWORD(wParam) - ID_FAVORITE_FIRST, namebuf, &ksize, NULL,
775 &type, valuebuf, &vsize) == ERROR_SUCCESS) {
776 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET,
777 (LPARAM) FindPathInTree(g_pChildWnd->hTreeWnd, (WCHAR *)valuebuf) );
779 RegCloseKey(hKey);
781 return TRUE;
783 switch (LOWORD(wParam)) {
784 case ID_REGISTRY_IMPORTREGISTRYFILE:
785 ImportRegistryFile(hWnd);
786 break;
787 case ID_EDIT_EXPORT:
788 case ID_REGISTRY_EXPORTREGISTRYFILE:
789 ExportRegistryFile(hWnd);
790 break;
791 case ID_REGISTRY_PRINT:
793 const WCHAR empty = 0;
794 PrintRegistryHive(hWnd, &empty);
795 break;
797 case ID_EDIT_DELETE:
799 HWND hWndDelete = GetFocus();
800 if (hWndDelete == g_pChildWnd->hTreeWnd) {
801 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
802 if (keyPath == 0 || *keyPath == 0) {
803 MessageBeep(MB_ICONHAND);
804 } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) {
805 DeleteNode(g_pChildWnd->hTreeWnd, 0);
807 HeapFree(GetProcessHeap(), 0, keyPath);
808 } else if (hWndDelete == g_pChildWnd->hListWnd) {
809 unsigned int num_selected, index, focus_idx;
810 WCHAR *keyPath;
812 if (!(num_selected = SendMessageW(g_pChildWnd->hListWnd, LVM_GETSELECTEDCOUNT, 0, 0L)))
813 break;
815 if (num_selected > 1)
817 if (messagebox(hWnd, MB_YESNO | MB_ICONEXCLAMATION, IDS_DELETE_VALUE_TITLE,
818 IDS_DELETE_VALUE_TEXT_MULTIPLE) != IDYES)
819 break;
822 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
824 focus_idx = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED, 0));
825 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));
827 while (index != -1)
829 WCHAR *valueName = GetItemText(g_pChildWnd->hListWnd, index);
830 if (!DeleteValue(hWnd, hKeyRoot, keyPath, valueName, num_selected == 1))
832 HeapFree(GetProcessHeap(), 0, valueName);
833 break;
835 HeapFree(GetProcessHeap(), 0, valueName);
836 SendMessageW(g_pChildWnd->hListWnd, LVM_DELETEITEM, index, 0L);
837 /* the default value item is always visible, so add it back in */
838 if (!index)
840 AddEntryToList(g_pChildWnd->hListWnd, NULL, REG_SZ, NULL, 0, 0);
841 if (!focus_idx)
843 LVITEMW item;
844 item.state = item.stateMask = LVIS_FOCUSED;
845 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, 0, (LPARAM)&item);
848 index = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_SELECTED, 0));
850 HeapFree(GetProcessHeap(), 0, keyPath);
851 } else if (IsChild(g_pChildWnd->hTreeWnd, hWndDelete) ||
852 IsChild(g_pChildWnd->hListWnd, hWndDelete)) {
853 SendMessageW(hWndDelete, WM_KEYDOWN, VK_DELETE, 0);
855 break;
857 case ID_EDIT_MODIFY:
858 case ID_EDIT_MODIFY_BIN:
860 LPCWSTR valueName = GetValueName(g_pChildWnd->hListWnd);
861 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
862 ModifyValue(hWnd, hKeyRoot, keyPath, valueName);
863 HeapFree(GetProcessHeap(), 0, keyPath);
864 break;
866 case ID_EDIT_FIND:
867 case ID_EDIT_FINDNEXT:
869 HTREEITEM hItem;
870 if (LOWORD(wParam) == ID_EDIT_FIND &&
871 DialogBoxW(0, MAKEINTRESOURCEW(IDD_FIND), hWnd, find_dlgproc) != IDOK)
872 break;
873 if (!*searchString)
874 break;
875 hItem = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
876 if (hItem) {
877 int row = SendMessageW(g_pChildWnd->hListWnd, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED, 0));
878 HCURSOR hcursorOld = SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_WAIT));
879 hItem = FindNext(g_pChildWnd->hTreeWnd, hItem, searchString, searchMask, &row);
880 SetCursor(hcursorOld);
881 if (hItem) {
882 SendMessageW( g_pChildWnd->hTreeWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) hItem );
883 InvalidateRect(g_pChildWnd->hTreeWnd, NULL, TRUE);
884 UpdateWindow(g_pChildWnd->hTreeWnd);
885 if (row != -1) {
886 LVITEMW item;
888 item.state = 0;
889 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
890 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, (UINT)-1, (LPARAM)&item);
892 item.state = LVIS_FOCUSED | LVIS_SELECTED;
893 item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
894 SendMessageW(g_pChildWnd->hListWnd, LVM_SETITEMSTATE, row, (LPARAM)&item);
895 SetFocus(g_pChildWnd->hListWnd);
896 } else {
897 SetFocus(g_pChildWnd->hTreeWnd);
899 } else {
900 messagebox(hWnd, MB_OK|MB_ICONINFORMATION, IDS_APP_TITLE, IDS_NOTFOUND, searchString);
903 break;
905 case ID_EDIT_COPYKEYNAME:
907 LPWSTR fullPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
908 if (fullPath) {
909 CopyKeyName(hWnd, fullPath);
910 HeapFree(GetProcessHeap(), 0, fullPath);
912 break;
914 case ID_EDIT_NEW_KEY:
916 WCHAR newKeyW[MAX_NEW_KEY_LEN];
917 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
918 if (CreateKey(hWnd, hKeyRoot, keyPath, newKeyW)) {
919 if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKeyW))
920 StartKeyRename(g_pChildWnd->hTreeWnd);
922 HeapFree(GetProcessHeap(), 0, keyPath);
924 break;
925 case ID_EDIT_NEW_STRINGVALUE:
926 valueType = REG_SZ;
927 goto create_value;
928 case ID_EDIT_NEW_EXPANDVALUE:
929 valueType = REG_EXPAND_SZ;
930 goto create_value;
931 case ID_EDIT_NEW_MULTI_STRINGVALUE:
932 valueType = REG_MULTI_SZ;
933 goto create_value;
934 case ID_EDIT_NEW_BINARYVALUE:
935 valueType = REG_BINARY;
936 goto create_value;
937 case ID_EDIT_NEW_DWORDVALUE:
938 valueType = REG_DWORD;
939 /* fall through */
940 create_value:
942 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
943 WCHAR newKey[MAX_NEW_KEY_LEN];
944 if (CreateValue(hWnd, hKeyRoot, keyPath, valueType, newKey))
945 StartValueRename(g_pChildWnd->hListWnd);
946 HeapFree(GetProcessHeap(), 0, keyPath);
948 break;
949 case ID_EDIT_RENAME:
951 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
952 if (keyPath == 0 || *keyPath == 0) {
953 MessageBeep(MB_ICONHAND);
954 } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
955 StartKeyRename(g_pChildWnd->hTreeWnd);
956 } else if (GetFocus() == g_pChildWnd->hListWnd) {
957 StartValueRename(g_pChildWnd->hListWnd);
959 HeapFree(GetProcessHeap(), 0, keyPath);
960 break;
962 case ID_TREE_EXPAND_COLLAPSE:
964 HTREEITEM selected = (HTREEITEM)SendMessageW(g_pChildWnd->hTreeWnd, TVM_GETNEXTITEM, TVGN_CARET, 0);
965 SendMessageW(g_pChildWnd->hTreeWnd, TVM_EXPAND, TVE_TOGGLE, (LPARAM)selected);
966 break;
968 case ID_REGISTRY_PRINTERSETUP:
969 /*PRINTDLG pd;*/
970 /*PrintDlg(&pd);*/
971 /*PAGESETUPDLG psd;*/
972 /*PageSetupDlg(&psd);*/
973 break;
974 case ID_REGISTRY_OPENLOCAL:
975 break;
976 case ID_REGISTRY_EXIT:
977 DestroyWindow(hWnd);
978 break;
979 case ID_FAVORITES_ADDTOFAVORITES:
981 HKEY hKey;
982 LPWSTR lpKeyPath = GetItemFullPath(g_pChildWnd->hTreeWnd, NULL, FALSE);
983 if (lpKeyPath) {
984 if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_ADDFAVORITE), hWnd, addtofavorites_dlgproc) == IDOK) {
985 if (RegCreateKeyExW(HKEY_CURRENT_USER, favoritesKey,
986 0, NULL, 0,
987 KEY_READ|KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
988 RegSetValueExW(hKey, favoriteName, 0, REG_SZ, (BYTE *)lpKeyPath, (lstrlenW(lpKeyPath)+1)*sizeof(WCHAR));
989 RegCloseKey(hKey);
992 HeapFree(GetProcessHeap(), 0, lpKeyPath);
994 break;
996 case ID_FAVORITES_REMOVEFAVORITE:
998 if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_DELFAVORITE), hWnd, removefavorite_dlgproc) == IDOK) {
999 HKEY hKey;
1000 if (RegOpenKeyExW(HKEY_CURRENT_USER, favoritesKey,
1001 0, KEY_READ|KEY_WRITE, &hKey) == ERROR_SUCCESS) {
1002 RegDeleteValueW(hKey, favoriteName);
1003 RegCloseKey(hKey);
1006 break;
1008 case ID_VIEW_REFRESH:
1010 WCHAR* keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
1011 RefreshTreeView(g_pChildWnd->hTreeWnd);
1012 RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
1013 HeapFree(GetProcessHeap(), 0, keyPath);
1015 break;
1016 /*case ID_OPTIONS_TOOLBAR:*/
1017 /* toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
1018 /* break;*/
1019 case ID_VIEW_STATUSBAR:
1020 toggle_child(hWnd, LOWORD(wParam), hStatusBar);
1021 break;
1022 case ID_HELP_HELPTOPICS:
1024 const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
1025 WinHelpW(hWnd, help_regedit, HELP_FINDER, 0);
1026 break;
1028 case ID_HELP_ABOUT:
1029 ShowAboutBox(hWnd);
1030 break;
1031 case ID_VIEW_SPLIT: {
1032 RECT rt;
1033 POINT pt, pts;
1034 GetClientRect(g_pChildWnd->hWnd, &rt);
1035 pt.x = rt.left + g_pChildWnd->nSplitPos;
1036 pt.y = (rt.bottom / 2);
1037 pts = pt;
1038 if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
1039 SetCursorPos(pts.x, pts.y);
1040 SetCursor(LoadCursorW(0, (LPCWSTR)IDC_SIZEWE));
1041 SendMessageW(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
1043 return TRUE;
1045 default:
1046 return FALSE;
1049 return TRUE;
1052 /********************************************************************************
1054 * FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
1056 * PURPOSE: Processes messages for the main frame window.
1058 * WM_COMMAND - process the application menu
1059 * WM_DESTROY - post a quit message and return
1063 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1065 static const WCHAR captionW[] = {'r','e','g','e','d','i','t',' ','c','h','i','l','d',' ','w','i','n','d','o','w',0};
1067 switch (message) {
1068 case WM_CREATE:
1069 CreateWindowExW(0, szChildClass, captionW, WS_CHILD | WS_VISIBLE,
1070 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1071 hWnd, NULL, hInst, 0);
1072 LoadStringW(hInst, IDS_EXPAND, expandW, COUNT_OF(expandW));
1073 LoadStringW(hInst, IDS_COLLAPSE, collapseW, COUNT_OF(collapseW));
1074 LoadStringW(hInst, IDS_EDIT_MODIFY, modifyW, COUNT_OF(modifyW));
1075 LoadStringW(hInst, IDS_EDIT_MODIFY_BIN, modify_binaryW, COUNT_OF(modify_binaryW));
1076 break;
1077 case WM_COMMAND:
1078 if (!_CmdWndProc(hWnd, message, wParam, lParam))
1079 return DefWindowProcW(hWnd, message, wParam, lParam);
1080 break;
1081 case WM_ACTIVATE:
1082 if (LOWORD(hWnd))
1083 SetFocus(g_pChildWnd->hWnd);
1084 break;
1085 case WM_SIZE:
1086 resize_frame_client(hWnd);
1087 break;
1088 case WM_TIMER:
1089 break;
1090 case WM_ENTERMENULOOP:
1091 OnEnterMenuLoop(hWnd);
1092 break;
1093 case WM_EXITMENULOOP:
1094 OnExitMenuLoop(hWnd);
1095 break;
1096 case WM_INITMENUPOPUP:
1097 if (!HIWORD(lParam))
1098 OnInitMenuPopup(hWnd, (HMENU)wParam);
1099 break;
1100 case WM_MENUSELECT:
1101 OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
1102 break;
1103 case WM_DESTROY:
1105 const WCHAR help_regedit[] = {'r','e','g','e','d','i','t',0};
1106 WinHelpW(hWnd, help_regedit, HELP_QUIT, 0);
1107 PostQuitMessage(0);
1109 default:
1110 return DefWindowProcW(hWnd, message, wParam, lParam);
1112 return 0;