Fix value renaming. Cleanup code, fix a few leaks.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define WIN32_LEAN_AND_MEAN     /* Exclude rarely-used stuff from Windows headers */
22
23 #include <windows.h>
24 #include <tchar.h>
25 #include <commctrl.h>
26 #include <commdlg.h>
27 #include <cderr.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <shellapi.h>
31
32 #include "main.h"
33 #include "regproc.h"
34
35 /********************************************************************************
36  * Global and Local Variables:
37  */
38
39 static BOOL bInMenuLoop = FALSE;        /* Tells us if we are in the menu loop */
40
41 /*******************************************************************************
42  * Local module support methods
43  */
44
45 static void resize_frame_rect(HWND hWnd, PRECT prect)
46 {
47     RECT rt;
48     /*
49         if (IsWindowVisible(hToolBar)) {
50                 SendMessage(hToolBar, WM_SIZE, 0, 0);
51                 GetClientRect(hToolBar, &rt);
52                 prect->top = rt.bottom+3;
53                 prect->bottom -= rt.bottom+3;
54         }
55      */
56     if (IsWindowVisible(hStatusBar)) {
57         SetupStatusBar(hWnd, TRUE);
58         GetClientRect(hStatusBar, &rt);
59         prect->bottom -= rt.bottom;
60     }
61     MoveWindow(g_pChildWnd->hWnd, prect->left, prect->top, prect->right, prect->bottom, TRUE);
62 }
63
64 void resize_frame_client(HWND hWnd)
65 {
66     RECT rect;
67
68     GetClientRect(hWnd, &rect);
69     resize_frame_rect(hWnd, &rect);
70 }
71
72 /********************************************************************************/
73
74 static void OnEnterMenuLoop(HWND hWnd)
75 {
76     int nParts;
77
78     /* Update the status bar pane sizes */
79     nParts = -1;
80     SendMessage(hStatusBar, SB_SETPARTS, 1, (long)&nParts);
81     bInMenuLoop = TRUE;
82     SendMessage(hStatusBar, SB_SETTEXT, (WPARAM)0, (LPARAM)_T(""));
83 }
84
85 static void OnExitMenuLoop(HWND hWnd)
86 {
87     bInMenuLoop = FALSE;
88     /* Update the status bar pane sizes*/
89     SetupStatusBar(hWnd, TRUE);
90     UpdateStatusBar();
91 }
92
93 static void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
94 {
95     TCHAR str[100];
96
97     _tcscpy(str, _T(""));
98     if (nFlags & MF_POPUP) {
99         if (hSysMenu != GetMenu(hWnd)) {
100             if (nItemID == 2) nItemID = 5;
101         }
102     }
103     if (LoadString(hInst, nItemID, str, 100)) {
104         /* load appropriate string*/
105         LPTSTR lpsz = str;
106         /* first newline terminates actual string*/
107         lpsz = _tcschr(lpsz, '\n');
108         if (lpsz != NULL)
109             *lpsz = '\0';
110     }
111     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)str);
112 }
113
114 void SetupStatusBar(HWND hWnd, BOOL bResize)
115 {
116     RECT  rc;
117     int nParts;
118     GetClientRect(hWnd, &rc);
119     nParts = rc.right;
120     /*    nParts = -1;*/
121     if (bResize)
122         SendMessage(hStatusBar, WM_SIZE, 0, 0);
123     SendMessage(hStatusBar, SB_SETPARTS, 1, (LPARAM)&nParts);
124 }
125
126 void UpdateStatusBar(void)
127 {
128     TCHAR text[260];
129     DWORD size;
130
131     size = sizeof(text)/sizeof(TCHAR);
132     GetComputerName(text, &size);
133     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)text);
134 }
135
136 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
137 {
138     BOOL vis = IsWindowVisible(hchild);
139     HMENU hMenuView = GetSubMenu(hMenuFrame, ID_VIEW_MENU);
140
141     CheckMenuItem(hMenuView, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
142     ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
143     resize_frame_client(hWnd);
144 }
145
146 static BOOL CheckCommDlgError(HWND hWnd)
147 {
148     DWORD dwErrorCode = CommDlgExtendedError();
149     switch (dwErrorCode) {
150     case CDERR_DIALOGFAILURE:
151         break;
152     case CDERR_FINDRESFAILURE:
153         break;
154     case CDERR_NOHINSTANCE:
155         break;
156     case CDERR_INITIALIZATION:
157         break;
158     case CDERR_NOHOOK:
159         break;
160     case CDERR_LOCKRESFAILURE:
161         break;
162     case CDERR_NOTEMPLATE:
163         break;
164     case CDERR_LOADRESFAILURE:
165         break;
166     case CDERR_STRUCTSIZE:
167         break;
168     case CDERR_LOADSTRFAILURE:
169         break;
170     case FNERR_BUFFERTOOSMALL:
171         break;
172     case CDERR_MEMALLOCFAILURE:
173         break;
174     case FNERR_INVALIDFILENAME:
175         break;
176     case CDERR_MEMLOCKFAILURE:
177         break;
178     case FNERR_SUBCLASSFAILURE:
179         break;
180     default:
181         break;
182     }
183     return TRUE;
184 }
185
186 UINT_PTR CALLBACK ImportRegistryFile_OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
187 {
188     OPENFILENAME* pOpenFileName;
189     OFNOTIFY* pOfNotify;
190
191     switch (uiMsg) {
192     case WM_INITDIALOG:
193         pOpenFileName = (OPENFILENAME*)lParam;
194         break;
195     case WM_NOTIFY:
196         pOfNotify = (OFNOTIFY*)lParam;
197     if (pOfNotify->hdr.code == CDN_INITDONE) {}
198         break;
199     default:
200         break;
201     }
202     return 0L;
203 }
204
205 #define MAX_CUSTOM_FILTER_SIZE 50
206 TCHAR CustomFilterBuffer[MAX_CUSTOM_FILTER_SIZE];
207 TCHAR FileNameBuffer[_MAX_PATH];
208 TCHAR FileTitleBuffer[_MAX_PATH];
209
210 static BOOL InitOpenFileName(HWND hWnd, OPENFILENAME* pofn)
211 {
212     memset(pofn, 0, sizeof(OPENFILENAME));
213     pofn->lStructSize = sizeof(OPENFILENAME);
214     pofn->hwndOwner = hWnd;
215     pofn->hInstance = hInst;
216
217     pofn->lpstrFilter = _T("Registration Files\0*.reg\0Win9x/NT4 Registration Files (REGEDIT4)\0*.reg\0All Files (*.*)\0*.*\0\0");
218     pofn->lpstrCustomFilter = CustomFilterBuffer;
219     pofn->nMaxCustFilter = MAX_CUSTOM_FILTER_SIZE;
220     pofn->nFilterIndex = 0;
221     pofn->lpstrFile = FileNameBuffer;
222     pofn->nMaxFile = _MAX_PATH;
223     pofn->lpstrFileTitle = FileTitleBuffer;
224     pofn->nMaxFileTitle = _MAX_PATH;
225     /*    pofn->lpstrInitialDir = _T("");*/
226     /*    pofn->lpstrTitle = _T("Import Registry File");*/
227     /*    pofn->Flags = OFN_ENABLETEMPLATE + OFN_EXPLORER + OFN_ENABLESIZING;*/
228     pofn->Flags = OFN_HIDEREADONLY;
229     /*    pofn->nFileOffset = ;*/
230     /*    pofn->nFileExtension = ;*/
231     /*    pofn->lpstrDefExt = _T("");*/
232     /*    pofn->lCustData = ;*/
233     /*    pofn->lpfnHook = ImportRegistryFile_OFNHookProc;*/
234     /*    pofn->lpTemplateName = _T("ID_DLG_IMPORT_REGFILE");*/
235     /*    pofn->lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);*/
236     /*    pofn->FlagsEx = ;*/
237     return TRUE;
238 }
239
240 static BOOL ImportRegistryFile(HWND hWnd)
241 {
242     OPENFILENAME ofn;
243
244     InitOpenFileName(hWnd, &ofn);
245     ofn.lpstrTitle = _T("Import Registry File");
246     /*    ofn.lCustData = ;*/
247     if (GetOpenFileName(&ofn)) {
248         if (!import_registry_file(ofn.lpstrFile)) {
249             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
250             return FALSE;
251         }
252 #if 0
253         get_file_name(&s, filename, MAX_PATH);
254         if (!filename[0]) {
255             printf("No file name is specified\n%s", usage);
256             return FALSE;
257             /*exit(1);*/
258         }
259         while (filename[0]) {
260             if (!import_registry_file(filename)) {
261                 perror("");
262                 printf("Can't open file \"%s\"\n", filename);
263                 return FALSE;
264                 /*exit(1);*/
265             }
266             get_file_name(&s, filename, MAX_PATH);
267         }
268 #endif
269
270     } else {
271         CheckCommDlgError(hWnd);
272     }
273     return TRUE;
274 }
275
276
277 static BOOL ExportRegistryFile(HWND hWnd)
278 {
279     OPENFILENAME ofn;
280     TCHAR ExportKeyPath[_MAX_PATH];
281
282     ExportKeyPath[0] = _T('\0');
283     InitOpenFileName(hWnd, &ofn);
284     ofn.lpstrTitle = _T("Export Registry File");
285     /*    ofn.lCustData = ;*/
286     ofn.Flags = OFN_ENABLETEMPLATE + OFN_EXPLORER;
287     ofn.lpfnHook = ImportRegistryFile_OFNHookProc;
288     ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);
289     if (GetSaveFileName(&ofn)) {
290         BOOL result;
291         result = export_registry_key(ofn.lpstrFile, ExportKeyPath);
292         /*result = export_registry_key(ofn.lpstrFile, NULL);*/
293         /*if (!export_registry_key(ofn.lpstrFile, NULL)) {*/
294         if (!result) {
295             /*printf("Can't open file \"%s\"\n", ofn.lpstrFile);*/
296             return FALSE;
297         }
298 #if 0
299         TCHAR filename[MAX_PATH];
300         filename[0] = '\0';
301         get_file_name(&s, filename, MAX_PATH);
302         if (!filename[0]) {
303             printf("No file name is specified\n%s", usage);
304             return FALSE;
305             /*exit(1);*/
306         }
307         if (s[0]) {
308             TCHAR reg_key_name[KEY_MAX_LEN];
309             get_file_name(&s, reg_key_name, KEY_MAX_LEN);
310             export_registry_key(filename, reg_key_name);
311         } else {
312             export_registry_key(filename, NULL);
313         }
314 #endif
315
316     } else {
317         CheckCommDlgError(hWnd);
318     }
319     return TRUE;
320 }
321
322 BOOL PrintRegistryHive(HWND hWnd, LPTSTR path)
323 {
324 #if 1
325     PRINTDLG pd;
326
327     ZeroMemory(&pd, sizeof(PRINTDLG));
328     pd.lStructSize = sizeof(PRINTDLG);
329     pd.hwndOwner   = hWnd;
330     pd.hDevMode    = NULL;     /* Don't forget to free or store hDevMode*/
331     pd.hDevNames   = NULL;     /* Don't forget to free or store hDevNames*/
332     pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
333     pd.nCopies     = 1;
334     pd.nFromPage   = 0xFFFF;
335     pd.nToPage     = 0xFFFF;
336     pd.nMinPage    = 1;
337     pd.nMaxPage    = 0xFFFF;
338     if (PrintDlg(&pd) == TRUE) {
339         /* GDI calls to render output. */
340         DeleteDC(pd.hDC); /* Delete DC when done.*/
341     }
342 #else
343     HRESULT hResult;
344     PRINTDLGEX pd;
345
346     hResult = PrintDlgEx(&pd);
347     if (hResult == S_OK) {
348         switch (pd.dwResultAction) {
349         case PD_RESULT_APPLY:
350             /*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. */
351             break;
352         case PD_RESULT_CANCEL:
353             /*The user clicked the Cancel button. The information in the PRINTDLGEX structure is unchanged. */
354             break;
355         case PD_RESULT_PRINT:
356             /*The user clicked the Print button. The PRINTDLGEX structure contains the information specified by the user. */
357             break;
358         default:
359             break;
360         }
361     } else {
362         switch (hResult) {
363         case E_OUTOFMEMORY:
364             /*Insufficient memory. */
365             break;
366         case E_INVALIDARG:
367             /* One or more arguments are invalid. */
368             break;
369         case E_POINTER:
370             /*Invalid pointer. */
371             break;
372         case E_HANDLE:
373             /*Invalid handle. */
374             break;
375         case E_FAIL:
376             /*Unspecified error. */
377             break;
378         default:
379             break;
380         }
381         return FALSE;
382     }
383 #endif
384     return TRUE;
385 }
386
387 BOOL CopyKeyName(HWND hWnd, LPTSTR keyName)
388 {
389     BOOL result;
390
391     result = OpenClipboard(hWnd);
392     if (result) {
393         result = EmptyClipboard();
394         if (result) {
395
396             /*HANDLE hClipData;*/
397             /*hClipData = SetClipboardData(UINT uFormat, HANDLE hMem);*/
398
399         } else {
400             /* error emptying clipboard*/
401             /* DWORD dwError = GetLastError(); */
402             ;
403         }
404         if (!CloseClipboard()) {
405             /* error closing clipboard*/
406             /* DWORD dwError = GetLastError(); */
407             ;
408         }
409     } else {
410         /* error opening clipboard*/
411         /* DWORD dwError = GetLastError(); */
412         ;
413     }
414     return result;
415 }
416
417 BOOL RefreshView(HWND hWnd)
418 {
419     /* TODO:*/
420     MessageBeep(-1);
421     MessageBeep(MB_ICONASTERISK);
422     MessageBeep(MB_ICONEXCLAMATION);
423     MessageBeep(MB_ICONHAND);
424     MessageBeep(MB_ICONQUESTION);
425     MessageBeep(MB_OK);
426     return TRUE;
427 }
428
429 /*******************************************************************************
430  *
431  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
432  *
433  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
434  *
435  */
436 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
437 {
438     HKEY hKeyRoot = 0;
439     LPCTSTR keyPath;
440     LPCTSTR valueName;
441     DWORD valueType;
442
443     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
444     valueName = GetValueName(g_pChildWnd->hListWnd);
445
446     switch (LOWORD(wParam)) {
447     case ID_REGISTRY_IMPORTREGISTRYFILE:
448         ImportRegistryFile(hWnd);
449         break;
450     case ID_REGISTRY_EXPORTREGISTRYFILE:
451         ExportRegistryFile(hWnd);
452         break;
453     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
454         break;
455     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
456         break;
457     case ID_REGISTRY_PRINT:
458         PrintRegistryHive(hWnd, _T(""));
459         break;
460     case ID_EDIT_DELETE:
461         if (DeleteValue(hWnd, hKeyRoot, keyPath, valueName))
462             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
463         break;
464     case ID_EDIT_MODIFY:
465         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
466             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
467         break;
468     case ID_EDIT_COPYKEYNAME:
469         CopyKeyName(hWnd, _T(""));
470         break;
471     case ID_EDIT_NEW_KEY:
472         CreateKey(hWnd, hKeyRoot, keyPath);
473         break;
474     case ID_EDIT_NEW_STRINGVALUE:
475         valueType = REG_SZ;
476         goto create_value;
477     case ID_EDIT_NEW_BINARYVALUE:
478         valueType = REG_BINARY;
479         goto create_value;
480     case ID_EDIT_NEW_DWORDVALUE:
481         valueType = REG_DWORD;
482         /* fall through */
483     create_value:
484         if (CreateValue(hWnd, hKeyRoot, keyPath, valueType))
485             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath);
486     case ID_EDIT_RENAME:
487         StartValueRename(g_pChildWnd->hListWnd);
488         break;
489     break;
490     case ID_REGISTRY_PRINTERSETUP:
491         /*PRINTDLG pd;*/
492         /*PrintDlg(&pd);*/
493         /*PAGESETUPDLG psd;*/
494         /*PageSetupDlg(&psd);*/
495         break;
496     case ID_REGISTRY_OPENLOCAL:
497         break;
498     case ID_REGISTRY_EXIT:
499         DestroyWindow(hWnd);
500         break;
501     case ID_VIEW_REFRESH:
502         RefreshView(hWnd);
503         break;
504    /*case ID_OPTIONS_TOOLBAR:*/
505    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
506    /*    break;*/
507     case ID_VIEW_STATUSBAR:
508         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
509         break;
510     case ID_HELP_HELPTOPICS:
511         WinHelp(hWnd, _T("regedit"), HELP_FINDER, 0);
512         break;
513     case ID_HELP_ABOUT:
514         ShowAboutBox(hWnd);
515         break;
516     case ID_VIEW_SPLIT: {
517         RECT rt;
518         POINT pt, pts;
519         GetClientRect(g_pChildWnd->hWnd, &rt);
520         pt.x = rt.left + g_pChildWnd->nSplitPos;
521         pt.y = (rt.bottom / 2);
522         pts = pt;
523         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
524             SetCursorPos(pts.x, pts.y);
525             SetCursor(LoadCursor(0, IDC_SIZEWE));
526             SendMessage(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
527         }
528         return TRUE;
529     }
530     default:
531         return FALSE;
532     }
533
534     return TRUE;
535 }
536
537 /********************************************************************************
538  *
539  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
540  *
541  *  PURPOSE:  Processes messages for the main frame window.
542  *
543  *  WM_COMMAND  - process the application menu
544  *  WM_DESTROY  - post a quit message and return
545  *
546  */
547
548 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
549 {
550     switch (message) {
551     case WM_CREATE:
552         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
553                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
554                        hWnd, (HMENU)0, hInst, 0);
555         break;
556     case WM_COMMAND:
557         if (!_CmdWndProc(hWnd, message, wParam, lParam))
558             return DefWindowProc(hWnd, message, wParam, lParam);
559         break;
560     case WM_SIZE:
561         resize_frame_client(hWnd);
562         break;
563     case WM_TIMER:
564         break;
565     case WM_ENTERMENULOOP:
566         OnEnterMenuLoop(hWnd);
567         break;
568     case WM_EXITMENULOOP:
569         OnExitMenuLoop(hWnd);
570         break;
571     case WM_MENUSELECT:
572         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
573         break;
574     case WM_DESTROY:
575         WinHelp(hWnd, _T("regedit"), HELP_QUIT, 0);
576         PostQuitMessage(0);
577     default:
578         return DefWindowProc(hWnd, message, wParam, lParam);
579     }
580     return 0;
581 }