xref: /reactos/dll/cpl/console/console.c (revision 6b2eeb0a)
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
InitPropSheetPage(PROPSHEETPAGEW * psp,WORD idDlg,DLGPROC DlgProc)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
InitDefaultConsoleInfo(PCONSOLE_STATE_INFO pConInfo)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
ApplyProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)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
ApplyConsoleInfo(HWND hwndDlg)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)
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
PropSheetProc(HWND hwndDlg,UINT uMsg,LPARAM lParam)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
InitApplet(HANDLE hSectionOrWnd)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 -- additional TrueType font cache and current preview font */
231     InitTTFontCache();
232     RefreshFontPreview(&FontPreview, ConInfo);
233 
234     /* Initialize the property sheet structure */
235     ZeroMemory(&psh, sizeof(psh));
236     psh.dwSize = sizeof(psh);
237     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | /* PSH_USEHICON | */ PSH_USEICONID | PSH_NOAPPLYNOW | PSH_USECALLBACK;
238 
239     if (ConInfo->ConsoleTitle[0] != UNICODE_NULL)
240     {
241         StringCchPrintfW(szTitle, ARRAYSIZE(szTitle), L"\"%s\"", ConInfo->ConsoleTitle);
242         psh.pszCaption = szTitle;
243     }
244     else
245     {
246         psh.pszCaption = MAKEINTRESOURCEW(IDS_CPLNAME);
247     }
248 
249     if (pSharedInfo != NULL)
250     {
251         /* We were started from a console window: this is our parent (or ConInfo->hWnd is NULL) */
252         psh.hwndParent = ConInfo->hWnd;
253     }
254     else
255     {
256         /* We were started in another way (--> default parameters). Caller's window is our parent. */
257         psh.hwndParent = (HWND)hSectionOrWnd;
258     }
259 
260     psh.hInstance = hApplet;
261     // psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCEW(IDC_CPLICON));
262     psh.pszIcon = MAKEINTRESOURCEW(IDC_CPLICON);
263     psh.nPages = ARRAYSIZE(psp);
264     psh.nStartPage = 0;
265     psh.ppsp = psp;
266     psh.pfnCallback = PropSheetProc;
267 
268     InitPropSheetPage(&psp[i++], IDD_PROPPAGEOPTIONS, OptionsProc);
269     InitPropSheetPage(&psp[i++], IDD_PROPPAGEFONT   , FontProc   );
270     InitPropSheetPage(&psp[i++], IDD_PROPPAGELAYOUT , LayoutProc );
271     InitPropSheetPage(&psp[i++], IDD_PROPPAGECOLORS , ColorsProc );
272 
273     /* Display the property sheet */
274     RegisterWinPrevClass(hApplet);
275     Result = PropertySheetW(&psh);
276     UnRegisterWinPrevClass(hApplet);
277 
278     /* Clear the font support */
279     ResetFontPreview(&FontPreview);
280     ClearTTFontCache();
281 
282     /* Apply the console settings if necessary */
283     if (SetConsoleInfo)
284     {
285         HANDLE hSection;
286 
287         /*
288          * Create a memory section to share with CONSRV, and map it.
289          */
290         hSection = CreateFileMappingW(INVALID_HANDLE_VALUE,
291                                       NULL,
292                                       PAGE_READWRITE,
293                                       0,
294                                       ConInfo->cbSize,
295                                       NULL);
296         if (!hSection)
297         {
298             DPRINT1("Error when creating file mapping, error = %d\n", GetLastError());
299             goto Quit;
300         }
301 
302         pSharedInfo = MapViewOfFile(hSection, FILE_MAP_ALL_ACCESS, 0, 0, 0);
303         if (!pSharedInfo)
304         {
305             DPRINT1("Error when mapping view of file, error = %d\n", GetLastError());
306             CloseHandle(hSection);
307             goto Quit;
308         }
309 
310         /* Copy the console information into the section and unmap it */
311         RtlCopyMemory(pSharedInfo, ConInfo, ConInfo->cbSize);
312         UnmapViewOfFile(pSharedInfo);
313 
314         /*
315          * Signal to CONSRV that it can apply the new settings.
316          *
317          * NOTE: SetConsoleInfo set to TRUE by ApplyConsoleInfo()
318          * *only* when ConInfo->hWnd != NULL and the user did not
319          * press IDCANCEL in the confirmation dialog.
320          */
321         ASSERT(ConInfo->hWnd);
322         SendMessageW(ConInfo->hWnd, WM_SETCONSOLEINFO, (WPARAM)hSection, 0);
323 
324         /* Close the section and return */
325         CloseHandle(hSection);
326     }
327 
328     /* Save the console settings */
329     if (SaveConsoleInfo)
330     {
331         /* Default settings saved when ConInfo->hWnd == NULL */
332         ConCfgWriteUserSettings(ConInfo, ConInfo->hWnd == NULL);
333     }
334 
335 Quit:
336     /* Cleanup */
337     HeapFree(GetProcessHeap(), 0, ConInfo);
338     ConInfo = NULL;
339 
340     return (Result != -1);
341 }
342 
343 /* Control Panel Callback */
344 LONG
345 CALLBACK
CPlApplet(HWND hwndCPl,UINT uMsg,LPARAM lParam1,LPARAM lParam2)346 CPlApplet(HWND hwndCPl,
347           UINT uMsg,
348           LPARAM lParam1,
349           LPARAM lParam2)
350 {
351     switch (uMsg)
352     {
353         case CPL_INIT:
354             return TRUE;
355 
356         case CPL_EXIT:
357             // TODO: Free allocated memory
358             break;
359 
360         case CPL_GETCOUNT:
361             return 1;
362 
363         case CPL_INQUIRE:
364         {
365             CPLINFO *CPlInfo = (CPLINFO*)lParam2;
366             CPlInfo->idIcon  = IDC_CPLICON;
367             CPlInfo->idName  = IDS_CPLNAME;
368             CPlInfo->idInfo  = IDS_CPLDESCRIPTION;
369             break;
370         }
371 
372         case CPL_DBLCLK:
373             InitApplet((HANDLE)hwndCPl);
374             break;
375     }
376 
377     return FALSE;
378 }
379 
380 INT
381 WINAPI
DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved)382 DllMain(HINSTANCE hinstDLL,
383         DWORD     dwReason,
384         LPVOID    lpvReserved)
385 {
386     UNREFERENCED_PARAMETER(lpvReserved);
387 
388     switch (dwReason)
389     {
390         case DLL_PROCESS_ATTACH:
391             hApplet = hinstDLL;
392             DisableThreadLibraryCalls(hinstDLL);
393             break;
394     }
395 
396     return TRUE;
397 }
398