There's no way to properly unload a driver, so don't try.
[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 static 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     UpdateStatusBar();
125 }
126
127 void UpdateStatusBar(void)
128 {
129     /* real updating of status bar happens in the treeview selection
130      * change handler, so fake a selection change to it, but don't
131      * refresh the listview or the current selection will change */
132     OnTreeSelectionChanged(g_pChildWnd->hTreeWnd, g_pChildWnd->hListWnd,
133         TreeView_GetSelection(g_pChildWnd->hTreeWnd), FALSE);
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 static 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 static BOOL PrintRegistryHive(HWND hWnd, LPCTSTR 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)) {
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 static BOOL CopyKeyName(HWND hWnd, LPCTSTR 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 /*******************************************************************************
418  *
419  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
420  *
421  *  PURPOSE:  Processes WM_COMMAND messages for the main frame window.
422  *
423  */
424 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
425 {
426     HKEY hKeyRoot = 0;
427     LPCTSTR keyPath;
428     LPCTSTR valueName;
429     TCHAR newKey[MAX_NEW_KEY_LEN];
430     DWORD valueType;
431
432     keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
433     valueName = GetValueName(g_pChildWnd->hListWnd);
434
435     switch (LOWORD(wParam)) {
436     case ID_REGISTRY_IMPORTREGISTRYFILE:
437         ImportRegistryFile(hWnd);
438         break;
439     case ID_REGISTRY_EXPORTREGISTRYFILE:
440         ExportRegistryFile(hWnd);
441         break;
442     case ID_REGISTRY_CONNECTNETWORKREGISTRY:
443         break;
444     case ID_REGISTRY_DISCONNECTNETWORKREGISTRY:
445         break;
446     case ID_REGISTRY_PRINT:
447         PrintRegistryHive(hWnd, _T(""));
448         break;
449     case ID_EDIT_DELETE:
450         if (GetFocus() == g_pChildWnd->hTreeWnd) {
451             if (keyPath == 0 || *keyPath == 0) {
452                 MessageBeep(MB_ICONHAND); 
453             } else if (DeleteKey(hWnd, hKeyRoot, keyPath)) {
454                 DeleteNode(g_pChildWnd->hTreeWnd, 0);
455             }
456         } else if (GetFocus() == g_pChildWnd->hListWnd) {
457             if (DeleteValue(hWnd, hKeyRoot, keyPath, valueName))
458                 RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL);
459         }
460         break;
461     case ID_EDIT_MODIFY:
462         if (ModifyValue(hWnd, hKeyRoot, keyPath, valueName))
463             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, valueName);
464         break;
465     case ID_EDIT_COPYKEYNAME:
466         CopyKeyName(hWnd, _T(""));
467         break;
468     case ID_EDIT_NEW_KEY:
469         if (CreateKey(hWnd, hKeyRoot, keyPath, newKey)) {
470             if (InsertNode(g_pChildWnd->hTreeWnd, 0, newKey))
471                 StartKeyRename(g_pChildWnd->hTreeWnd);
472         }
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, newKey)) {
485             RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, newKey);
486             StartValueRename(g_pChildWnd->hListWnd);
487             /* FIXME: start rename */
488         }
489         break;
490     case ID_EDIT_RENAME:
491         if (keyPath == 0 || *keyPath == 0) {
492             MessageBeep(MB_ICONHAND); 
493         } else if (GetFocus() == g_pChildWnd->hTreeWnd) {
494             StartKeyRename(g_pChildWnd->hTreeWnd);
495         } else if (GetFocus() == g_pChildWnd->hListWnd) {
496             StartValueRename(g_pChildWnd->hListWnd);
497         }
498         break;
499     break;
500     case ID_REGISTRY_PRINTERSETUP:
501         /*PRINTDLG pd;*/
502         /*PrintDlg(&pd);*/
503         /*PAGESETUPDLG psd;*/
504         /*PageSetupDlg(&psd);*/
505         break;
506     case ID_REGISTRY_OPENLOCAL:
507         break;
508     case ID_REGISTRY_EXIT:
509         DestroyWindow(hWnd);
510         break;
511     case ID_VIEW_REFRESH:
512         RefreshTreeView(g_pChildWnd->hTreeWnd);
513         /*RefreshListView(g_pChildWnd->hListWnd, hKeyRoot, keyPath, NULL); */
514         break;
515    /*case ID_OPTIONS_TOOLBAR:*/
516    /*   toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
517    /*    break;*/
518     case ID_VIEW_STATUSBAR:
519         toggle_child(hWnd, LOWORD(wParam), hStatusBar);
520         break;
521     case ID_HELP_HELPTOPICS:
522         WinHelp(hWnd, _T("regedit"), HELP_FINDER, 0);
523         break;
524     case ID_HELP_ABOUT:
525         ShowAboutBox(hWnd);
526         break;
527     case ID_VIEW_SPLIT: {
528         RECT rt;
529         POINT pt, pts;
530         GetClientRect(g_pChildWnd->hWnd, &rt);
531         pt.x = rt.left + g_pChildWnd->nSplitPos;
532         pt.y = (rt.bottom / 2);
533         pts = pt;
534         if(ClientToScreen(g_pChildWnd->hWnd, &pts)) {
535             SetCursorPos(pts.x, pts.y);
536             SetCursor(LoadCursor(0, IDC_SIZEWE));
537             SendMessage(g_pChildWnd->hWnd, WM_LBUTTONDOWN, 0, MAKELPARAM(pt.x, pt.y));
538         }
539         return TRUE;
540     }
541     default:
542         return FALSE;
543     }
544
545     return TRUE;
546 }
547
548 /********************************************************************************
549  *
550  *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
551  *
552  *  PURPOSE:  Processes messages for the main frame window.
553  *
554  *  WM_COMMAND  - process the application menu
555  *  WM_DESTROY  - post a quit message and return
556  *
557  */
558
559 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
560 {
561     switch (message) {
562     case WM_CREATE:
563         CreateWindowEx(0, szChildClass, _T("regedit child window"), WS_CHILD | WS_VISIBLE,
564                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
565                        hWnd, NULL, hInst, 0);
566         break;
567     case WM_COMMAND:
568         if (!_CmdWndProc(hWnd, message, wParam, lParam))
569             return DefWindowProc(hWnd, message, wParam, lParam);
570         break;
571     case WM_ACTIVATE:
572         if (LOWORD(hWnd)) 
573             SetFocus(g_pChildWnd->hWnd);
574         break;
575     case WM_SIZE:
576         resize_frame_client(hWnd);
577         break;
578     case WM_TIMER:
579         break;
580     case WM_ENTERMENULOOP:
581         OnEnterMenuLoop(hWnd);
582         break;
583     case WM_EXITMENULOOP:
584         OnExitMenuLoop(hWnd);
585         break;
586     case WM_MENUSELECT:
587         OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
588         break;
589     case WM_DESTROY:
590         WinHelp(hWnd, _T("regedit"), HELP_QUIT, 0);
591         PostQuitMessage(0);
592     default:
593         return DefWindowProc(hWnd, message, wParam, lParam);
594     }
595     return 0;
596 }