xref: /reactos/dll/cpl/console/console.c (revision 6e4f0365)
1 /*
2  * PROJECT:         ReactOS Console Configuration DLL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/cpl/console/console.c
5  * PURPOSE:         Initialization
6  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 #include "console.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 INT_PTR CALLBACK OptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
16 INT_PTR CALLBACK FontProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
17 INT_PTR CALLBACK LayoutProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
18 INT_PTR CALLBACK ColorsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
19 
20 HINSTANCE hApplet = NULL;
21 
22 /* Local copy of the console information */
23 PCONSOLE_STATE_INFO ConInfo = NULL;
24 /* What to do with the console information */
25 static BOOL SetConsoleInfo  = FALSE;
26 static BOOL SaveConsoleInfo = FALSE;
27 
28 static VOID
29 InitPropSheetPage(PROPSHEETPAGEW *psp,
30                   WORD idDlg,
31                   DLGPROC DlgProc)
32 {
33     ZeroMemory(psp, sizeof(*psp));
34     psp->dwSize      = sizeof(*psp);
35     psp->dwFlags     = PSP_DEFAULT;
36     psp->hInstance   = hApplet;
37     psp->pszTemplate = MAKEINTRESOURCEW(idDlg);
38     psp->pfnDlgProc  = DlgProc;
39     psp->lParam      = 0;
40 }
41 
42 static VOID
43 InitDefaultConsoleInfo(PCONSOLE_STATE_INFO pConInfo)
44 {
45     // FIXME: Also retrieve the value of REG_DWORD CurrentPage.
46     ConCfgGetDefaultSettings(pConInfo);
47 }
48 
49 static INT_PTR
50 CALLBACK
51 ApplyProc(HWND hwndDlg,
52           UINT uMsg,
53           WPARAM wParam,
54           LPARAM lParam)
55 {
56     UNREFERENCED_PARAMETER(lParam);
57 
58     switch (uMsg)
59     {
60         case WM_INITDIALOG:
61         {
62             CheckDlgButton(hwndDlg, IDC_RADIO_APPLY_CURRENT, BST_CHECKED);
63             return TRUE;
64         }
65         case WM_COMMAND:
66         {
67             if (LOWORD(wParam) == IDOK)
68             {
69                 if (IsDlgButtonChecked(hwndDlg, IDC_RADIO_APPLY_CURRENT) == BST_CHECKED)
70                     EndDialog(hwndDlg, IDC_RADIO_APPLY_CURRENT);
71                 else
72                     EndDialog(hwndDlg, IDC_RADIO_APPLY_ALL);
73             }
74             else if (LOWORD(wParam) == IDCANCEL)
75             {
76                 EndDialog(hwndDlg, IDCANCEL);
77             }
78             break;
79         }
80         default:
81             break;
82     }
83 
84     return FALSE;
85 }
86 
87 VOID
88 ApplyConsoleInfo(HWND hwndDlg)
89 {
90     static BOOL ConsoleInfoAlreadySaved = FALSE;
91 
92     /*
93      * We already applied all the console properties (and saved if needed).
94      * Nothing more needs to be done.
95      */
96     if (ConsoleInfoAlreadySaved)
97         goto Done;
98 
99     /*
100      * If we are setting the default parameters, just save them,
101      * otherwise display the confirmation & apply dialog.
102      */
103     if (ConInfo->hWnd == NULL)
104     {
105         SetConsoleInfo  = FALSE;
106         SaveConsoleInfo = TRUE;
107     }
108     else
109     {
110         INT_PTR res = DialogBoxW(hApplet, MAKEINTRESOURCEW(IDD_APPLYOPTIONS), hwndDlg, ApplyProc);
111 
112         SetConsoleInfo  = (res != IDCANCEL);
113         SaveConsoleInfo = (res == IDC_RADIO_APPLY_ALL);
114 
115         if (SetConsoleInfo == FALSE)
116         {
117             /* Don't destroy when the user presses cancel */
118             SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
119             return;
120         }
121     }
122 
123     /*
124      * We applied all the console properties (and saved if needed).
125      * Set the flag so that if this function is called again, we won't
126      * need to redo everything again.
127      */
128     ConsoleInfoAlreadySaved = TRUE;
129 
130 Done:
131     /* Options have been applied */
132     SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
133     return;
134 }
135 
136 static int CALLBACK
137 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
138 {
139     // NOTE: This callback is needed to set large icon correctly.
140     HICON hIcon;
141     switch (uMsg)
142     {
143         case PSCB_INITIALIZED:
144         {
145             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
146             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
147             break;
148         }
149     }
150     return 0;
151 }
152 
153 /* First Applet */
154 static LONG
155 APIENTRY
156 InitApplet(HANDLE hSectionOrWnd)
157 {
158     INT_PTR Result;
159     PCONSOLE_STATE_INFO pSharedInfo = NULL;
160     WCHAR szTitle[MAX_PATH + 1];
161     PROPSHEETPAGEW psp[4];
162     PROPSHEETHEADERW psh;
163     INT i = 0;
164 
165     /*
166      * Because of Windows compatibility, we need to behave the same concerning
167      * information sharing with CONSRV. For some obscure reason the designers
168      * decided to use the CPlApplet hWnd parameter as being either a handle to
169      * the applet's parent caller's window (in case we ask for displaying
170      * the global console settings), or a handle to a shared section holding
171      * a CONSOLE_STATE_INFO structure (they don't use the extra l/wParams).
172      */
173 
174     /*
175      * Try to open the shared section via the handle parameter. If we succeed,
176      * it means we were called by CONSRV for retrieving/setting parameters for
177      * a given console. If we fail, it means we are retrieving/setting default
178      * global parameters (and we were either called by CONSRV or directly by
179      * the user via the Control Panel, etc...)
180      */
181     pSharedInfo = MapViewOfFile(hSectionOrWnd, FILE_MAP_READ, 0, 0, 0);
182     if (pSharedInfo != NULL)
183     {
184         /*
185          * We succeeded. We were called by CONSRV and are retrieving
186          * parameters for a given console.
187          */
188 
189         /* Copy the shared data into our allocated buffer */
190         DPRINT1("pSharedInfo->cbSize == %lu ; sizeof(CONSOLE_STATE_INFO) == %u\n",
191                 pSharedInfo->cbSize, sizeof(CONSOLE_STATE_INFO));
192         ASSERT(pSharedInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
193 
194         /* Allocate a local buffer to hold console information */
195         ConInfo = HeapAlloc(GetProcessHeap(),
196                             HEAP_ZERO_MEMORY,
197                             pSharedInfo->cbSize);
198         if (ConInfo)
199             RtlCopyMemory(ConInfo, pSharedInfo, pSharedInfo->cbSize);
200 
201         /* Close the section */
202         UnmapViewOfFile(pSharedInfo);
203         CloseHandle(hSectionOrWnd);
204 
205         if (!ConInfo) return 0;
206     }
207     else
208     {
209         /*
210          * We failed. We are retrieving the default global parameters.
211          */
212 
213         /* Allocate a local buffer to hold console information */
214         ConInfo = HeapAlloc(GetProcessHeap(),
215                             HEAP_ZERO_MEMORY,
216                             sizeof(CONSOLE_STATE_INFO));
217         if (!ConInfo) return 0;
218 
219         /*
220          * Setting the console window handle to NULL indicates we are
221          * retrieving/setting the default console parameters.
222          */
223         ConInfo->hWnd = NULL;
224         ConInfo->ConsoleTitle[0] = UNICODE_NULL;
225 
226         /* Use defaults */
227         InitDefaultConsoleInfo(ConInfo);
228     }
229 
230     /* Initialize the font support */
231     FontPreview.hFont = CreateConsoleFont(ConInfo);
232     if (FontPreview.hFont == NULL)
233         DPRINT1("InitApplet: CreateConsoleFont() failed\n");
234     GetFontCellSize(NULL, FontPreview.hFont, &FontPreview.CharHeight, &FontPreview.CharWidth);
235 
236     /* Initialize the property sheet structure */
237     ZeroMemory(&psh, sizeof(psh));
238     psh.dwSize = sizeof(psh);
239     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | /* PSH_USEHICON | */ PSH_USEICONID | PSH_NOAPPLYNOW | PSH_USECALLBACK;
240 
241     if (ConInfo->ConsoleTitle[0] != UNICODE_NULL)
242         StringCchPrintfW(szTitle, ARRAYSIZE(szTitle), L"\"%s\"", ConInfo->ConsoleTitle);
243     else
244         StringCchCopyW(szTitle, ARRAYSIZE(szTitle), L"ReactOS Console");
245     psh.pszCaption = szTitle;
246 
247     if (pSharedInfo != NULL)
248     {
249         /* We were started from a console window: this is our parent (or ConInfo->hWnd is NULL) */
250         psh.hwndParent = ConInfo->hWnd;
251     }
252     else
253     {
254         /* We were started in another way (--> default parameters). Caller's window is our parent. */
255         psh.hwndParent = (HWND)hSectionOrWnd;
256     }
257 
258     psh.hInstance = hApplet;
259     // psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
260     psh.pszIcon = MAKEINTRESOURCEW(IDC_CPLICON);
261     psh.nPages = ARRAYSIZE(psp);
262     psh.nStartPage = 0;
263     psh.ppsp = psp;
264     psh.pfnCallback = PropSheetProc;
265 
266     InitPropSheetPage(&psp[i++], IDD_PROPPAGEOPTIONS, OptionsProc);
267     InitPropSheetPage(&psp[i++], IDD_PROPPAGEFONT   , FontProc   );
268     InitPropSheetPage(&psp[i++], IDD_PROPPAGELAYOUT , LayoutProc );
269     InitPropSheetPage(&psp[i++], IDD_PROPPAGECOLORS , ColorsProc );
270 
271     /* Display the property sheet */
272     RegisterWinPrevClass(hApplet);
273     Result = PropertySheetW(&psh);
274     UnRegisterWinPrevClass(hApplet);
275 
276     /* Clear the font support */
277     if (FontPreview.hFont) DeleteObject(FontPreview.hFont);
278     FontPreview.hFont = NULL;
279 
280     /* Save the console settings */
281     if (SetConsoleInfo)
282     {
283         HANDLE hSection;
284 
285         /*
286          * Create a memory section to share with CONSRV, and map it.
287          */
288         hSection = CreateFileMappingW(INVALID_HANDLE_VALUE,
289                                       NULL,
290                                       PAGE_READWRITE,
291                                       0,
292                                       ConInfo->cbSize,
293                                       NULL);
294         if (!hSection)
295         {
296             DPRINT1("Error when creating file mapping, error = %d\n", GetLastError());
297             goto Quit;
298         }
299 
300         pSharedInfo = MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS, 0, 0, 0);
301         if (!pSharedInfo)
302         {
303             DPRINT1("Error when mapping view of file, error = %d\n", GetLastError());
304             CloseHandle(hSection);
305             goto Quit;
306         }
307 
308         /* Copy the console information into the section */
309         RtlCopyMemory(pSharedInfo, ConInfo, ConInfo->cbSize);
310 
311         /* Unmap it */
312         UnmapViewOfFile(pSharedInfo);
313 
314         /* Signal to CONSRV that it can apply the new configuration */
315         SendMessageW(ConInfo->hWnd, WM_SETCONSOLEINFO, (WPARAM)hSection, 0);
316 
317         /* Close the section and return */
318         CloseHandle(hSection);
319     }
320 
321     if (SaveConsoleInfo)
322     {
323         /* Default settings saved when ConInfo->hWnd == NULL */
324         ConCfgWriteUserSettings(ConInfo, ConInfo->hWnd == NULL);
325     }
326 
327 Quit:
328     /* Cleanup */
329     HeapFree(GetProcessHeap(), 0, ConInfo);
330     ConInfo = NULL;
331 
332     return (Result != -1);
333 }
334 
335 /* Control Panel Callback */
336 LONG
337 CALLBACK
338 CPlApplet(HWND hwndCPl,
339           UINT uMsg,
340           LPARAM lParam1,
341           LPARAM lParam2)
342 {
343     switch (uMsg)
344     {
345         case CPL_INIT:
346             return TRUE;
347 
348         case CPL_EXIT:
349             // TODO: Free allocated memory
350             break;
351 
352         case CPL_GETCOUNT:
353             return 1;
354 
355         case CPL_INQUIRE:
356         {
357             CPLINFO *CPlInfo = (CPLINFO*)lParam2;
358             CPlInfo->idIcon  = IDC_CPLICON;
359             CPlInfo->idName  = IDS_CPLNAME;
360             CPlInfo->idInfo  = IDS_CPLDESCRIPTION;
361             break;
362         }
363 
364         case CPL_DBLCLK:
365             InitApplet((HANDLE)hwndCPl);
366             break;
367     }
368 
369     return FALSE;
370 }
371 
372 INT
373 WINAPI
374 DllMain(HINSTANCE hinstDLL,
375         DWORD     dwReason,
376         LPVOID    lpvReserved)
377 {
378     UNREFERENCED_PARAMETER(lpvReserved);
379 
380     switch (dwReason)
381     {
382         case DLL_PROCESS_ATTACH:
383             hApplet = hinstDLL;
384             DisableThreadLibraryCalls(hinstDLL);
385             break;
386     }
387 
388     return TRUE;
389 }
390