eadf949abe8831172810ac4513c5c03f2767c825
[reactos.git] / reactos / win32ss / user / winsrv / concfg / settings.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/concfg/settings.c
5 * PURPOSE: Console settings management
6 * PROGRAMMERS: Johannes Anderwald
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 /* PSDK/NDK Headers */
13
14 #define WIN32_NO_STATUS
15 #define _INC_WINDOWS
16 #define COM_NO_WINDOWS_H
17
18 #include <windef.h>
19 #include <winbase.h>
20 #include <wingdi.h> // For LF_FACESIZE
21 #include <wincon.h>
22 #include <winnls.h>
23 #include <winreg.h>
24 // #include <winuser.h>
25 // #include <imm.h>
26
27 // /* Undocumented user definitions */
28 // #include <undocuser.h>
29
30 #define NTOS_MODE_USER
31 // #include <ndk/cmfuncs.h>
32 // #include <ndk/exfuncs.h>
33 #include <ndk/obfuncs.h>
34 // #include <ndk/psfuncs.h>
35 #include <ndk/rtlfuncs.h>
36
37 #include "settings.h"
38
39 #include <stdio.h> // for swprintf
40 #include <strsafe.h>
41
42 #define NDEBUG
43 #include <debug.h>
44
45 /* GLOBALS ********************************************************************/
46
47 /* Default cursor size -- see conio_winsrv.h */
48 #define CSR_DEFAULT_CURSOR_SIZE 25
49
50 /* Default attributes -- see conio.h */
51 #define DEFAULT_SCREEN_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
52 #define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | \
53 BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
54
55 /*
56 * Default 16-color palette for foreground and background
57 * (corresponding flags in comments).
58 */
59 static const COLORREF s_Colors[16] =
60 {
61 RGB(0, 0, 0), // (Black)
62 RGB(0, 0, 128), // BLUE
63 RGB(0, 128, 0), // GREEN
64 RGB(0, 128, 128), // BLUE | GREEN
65 RGB(128, 0, 0), // RED
66 RGB(128, 0, 128), // BLUE | RED
67 RGB(128, 128, 0), // GREEN | RED
68 RGB(192, 192, 192), // BLUE | GREEN | RED
69
70 RGB(128, 128, 128), // (Grey) INTENSITY
71 RGB(0, 0, 255), // BLUE | INTENSITY
72 RGB(0, 255, 0), // GREEN | INTENSITY
73 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
74 RGB(255, 0, 0), // RED | INTENSITY
75 RGB(255, 0, 255), // BLUE | RED | INTENSITY
76 RGB(255, 255, 0), // GREEN | RED | INTENSITY
77 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
78 };
79 // /* Default attributes */
80 // #define DEFAULT_SCREEN_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
81 // #define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | /
82 // BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
83 // /* Cursor size */
84 // #define CSR_DEFAULT_CURSOR_SIZE 25
85
86
87 /* FUNCTIONS ******************************************************************/
88
89 static VOID
90 TranslateConsoleName(OUT LPWSTR DestString,
91 IN LPCWSTR ConsoleName,
92 IN UINT MaxStrLen)
93 {
94 #define PATH_SEPARATOR L'\\'
95
96 UINT wLength;
97
98 if ( DestString == NULL || ConsoleName == NULL ||
99 *ConsoleName == L'\0' || MaxStrLen == 0 )
100 {
101 return;
102 }
103
104 wLength = GetSystemWindowsDirectoryW(DestString, MaxStrLen);
105 if ((wLength > 0) && (_wcsnicmp(ConsoleName, DestString, wLength) == 0))
106 {
107 StringCchCopyW(DestString, MaxStrLen, L"%SystemRoot%");
108 StringCchCatW(DestString, MaxStrLen, ConsoleName + wLength);
109 }
110 else
111 {
112 StringCchCopyW(DestString, MaxStrLen, ConsoleName);
113 }
114
115 /* Replace path separators (backslashes) by underscores */
116 while ((DestString = wcschr(DestString, PATH_SEPARATOR))) *DestString = L'_';
117 }
118
119 BOOLEAN
120 ConCfgOpenUserSettings(LPCWSTR ConsoleTitle,
121 PHKEY hSubKey,
122 REGSAM samDesired,
123 BOOLEAN Create)
124 {
125 BOOLEAN Success = TRUE;
126 NTSTATUS Status;
127 WCHAR szBuffer[MAX_PATH] = L"Console\\";
128 WCHAR szBuffer2[MAX_PATH] = L"";
129 HKEY hKey; // CurrentUserKeyHandle
130
131 /*
132 * Console properties are stored under the HKCU\Console\* key.
133 *
134 * We use the original console title as the subkey name for storing
135 * console properties. We need to distinguish whether we were launched
136 * via the console application directly or via a shortcut.
137 *
138 * If the title of the console corresponds to a path (more precisely,
139 * if the title is of the form: C:\ReactOS\<some_path>\<some_app.exe>),
140 * then use the corresponding unexpanded path and with the backslashes
141 * replaced by underscores, to make the registry happy,
142 * i.e. %SystemRoot%_<some_path>_<some_app.exe>
143 */
144
145 /* Open the per-user registry key where the console properties are saved */
146 Status = RtlOpenCurrentUser(/*samDesired*/MAXIMUM_ALLOWED, (PHANDLE)&/*CurrentUserKeyHandle*/hKey);
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT1("RtlOpenCurrentUser failed, Status = 0x%08lx\n", Status);
150 SetLastError(RtlNtStatusToDosError(Status));
151 return FALSE;
152 }
153
154 /*
155 * Try to open properties via the console title:
156 * to make the registry happy, replace all the
157 * backslashes by underscores.
158 */
159 TranslateConsoleName(szBuffer2, ConsoleTitle, ARRAYSIZE(szBuffer2));
160
161 /* Create the registry path */
162 StringCchCatW(szBuffer, MAX_PATH - wcslen(szBuffer) - 1, szBuffer2);
163
164 /* Create or open the registry key */
165 if (Create)
166 {
167 /* Create the key */
168 Success = (RegCreateKeyExW(hKey,
169 szBuffer,
170 0, NULL,
171 REG_OPTION_NON_VOLATILE,
172 samDesired,
173 NULL,
174 hSubKey,
175 NULL) == ERROR_SUCCESS);
176 }
177 else
178 {
179 /* Open the key */
180 Success = (RegOpenKeyExW(hKey,
181 szBuffer,
182 0,
183 samDesired,
184 hSubKey) == ERROR_SUCCESS);
185 }
186
187 /* Close the parent key and return success or not */
188 NtClose(hKey);
189 return Success;
190 }
191
192 BOOLEAN
193 ConCfgReadUserSettings(IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
194 IN BOOLEAN DefaultSettings)
195 {
196 BOOLEAN Success = FALSE;
197 HKEY hKey;
198 DWORD dwNumSubKeys = 0;
199 DWORD dwIndex;
200 DWORD dwColorIndex = 0;
201 DWORD dwType;
202 WCHAR szValueName[MAX_PATH];
203 DWORD dwValueName;
204 WCHAR szValue[LF_FACESIZE] = L"";
205 DWORD Value;
206 DWORD dwValue;
207
208 if (!ConCfgOpenUserSettings(DefaultSettings ? L"" : ConsoleInfo->ConsoleTitle,
209 &hKey, KEY_READ, FALSE))
210 {
211 DPRINT("ConCfgOpenUserSettings failed\n");
212 return FALSE;
213 }
214
215 if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
216 &dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
217 {
218 DPRINT("ConCfgReadUserSettings: RegQueryInfoKeyW failed\n");
219 RegCloseKey(hKey);
220 return FALSE;
221 }
222
223 DPRINT("ConCfgReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
224
225 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
226 {
227 dwValue = sizeof(Value);
228 dwValueName = ARRAYSIZE(szValueName);
229
230 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
231 {
232 if (dwType == REG_SZ)
233 {
234 /*
235 * Retry in case of string value
236 */
237 dwValue = sizeof(szValue);
238 dwValueName = ARRAYSIZE(szValueName);
239 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
240 break;
241 }
242 else
243 {
244 break;
245 }
246 }
247
248 if (!wcsncmp(szValueName, L"ColorTable", wcslen(L"ColorTable")))
249 {
250 dwColorIndex = 0;
251 swscanf(szValueName, L"ColorTable%2d", &dwColorIndex);
252 if (dwColorIndex < ARRAYSIZE(ConsoleInfo->ColorTable))
253 {
254 ConsoleInfo->ColorTable[dwColorIndex] = Value;
255 Success = TRUE;
256 }
257 }
258 if (!wcscmp(szValueName, L"CodePage"))
259 {
260 if (IsValidCodePage(Value))
261 ConsoleInfo->CodePage = Value;
262 Success = TRUE;
263 }
264 else if (!wcscmp(szValueName, L"FaceName"))
265 {
266 wcsncpy(ConsoleInfo->FaceName, szValue, LF_FACESIZE);
267 ConsoleInfo->FaceName[LF_FACESIZE - 1] = UNICODE_NULL;
268 Success = TRUE;
269 }
270 else if (!wcscmp(szValueName, L"FontFamily"))
271 {
272 ConsoleInfo->FontFamily = Value;
273 Success = TRUE;
274 }
275 else if (!wcscmp(szValueName, L"FontSize"))
276 {
277 ConsoleInfo->FontSize.X = LOWORD(Value); // Width
278 ConsoleInfo->FontSize.Y = HIWORD(Value); // Height
279 Success = TRUE;
280 }
281 else if (!wcscmp(szValueName, L"FontWeight"))
282 {
283 ConsoleInfo->FontWeight = Value;
284 Success = TRUE;
285 }
286 else if (!wcscmp(szValueName, L"HistoryBufferSize"))
287 {
288 ConsoleInfo->HistoryBufferSize = Value;
289 Success = TRUE;
290 }
291 else if (!wcscmp(szValueName, L"NumberOfHistoryBuffers"))
292 {
293 ConsoleInfo->NumberOfHistoryBuffers = Value;
294 Success = TRUE;
295 }
296 else if (!wcscmp(szValueName, L"HistoryNoDup"))
297 {
298 ConsoleInfo->HistoryNoDup = !!Value;
299 Success = TRUE;
300 }
301 else if (!wcscmp(szValueName, L"QuickEdit"))
302 {
303 ConsoleInfo->QuickEdit = !!Value;
304 Success = TRUE;
305 }
306 else if (!wcscmp(szValueName, L"InsertMode"))
307 {
308 ConsoleInfo->InsertMode = !!Value;
309 Success = TRUE;
310 }
311 else if (!wcscmp(szValueName, L"ScreenBufferSize"))
312 {
313 ConsoleInfo->ScreenBufferSize.X = LOWORD(Value);
314 ConsoleInfo->ScreenBufferSize.Y = HIWORD(Value);
315 Success = TRUE;
316 }
317 else if (!wcscmp(szValueName, L"FullScreen"))
318 {
319 ConsoleInfo->FullScreen = Value;
320 Success = TRUE;
321 }
322 else if (!wcscmp(szValueName, L"WindowPosition"))
323 {
324 ConsoleInfo->AutoPosition = FALSE;
325 ConsoleInfo->WindowPosition.x = LOWORD(Value);
326 ConsoleInfo->WindowPosition.y = HIWORD(Value);
327 Success = TRUE;
328 }
329 else if (!wcscmp(szValueName, L"WindowSize"))
330 {
331 ConsoleInfo->WindowSize.X = LOWORD(Value);
332 ConsoleInfo->WindowSize.Y = HIWORD(Value);
333 Success = TRUE;
334 }
335 else if (!wcscmp(szValueName, L"CursorSize"))
336 {
337 ConsoleInfo->CursorSize = min(max(Value, 0), 100);
338 Success = TRUE;
339 }
340 else if (!wcscmp(szValueName, L"ScreenColors"))
341 {
342 ConsoleInfo->ScreenAttributes = (USHORT)Value;
343 Success = TRUE;
344 }
345 else if (!wcscmp(szValueName, L"PopupColors"))
346 {
347 ConsoleInfo->PopupAttributes = (USHORT)Value;
348 Success = TRUE;
349 }
350 }
351
352 RegCloseKey(hKey);
353 return Success;
354 }
355
356 BOOLEAN
357 ConCfgWriteUserSettings(IN PCONSOLE_STATE_INFO ConsoleInfo,
358 IN BOOLEAN DefaultSettings)
359 {
360 HKEY hKey;
361 DWORD Storage = 0;
362
363 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
364 do { \
365 if (DefaultSettings || (!DefaultSettings && (*(Setting) != (DefaultValue)))) \
366 { \
367 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
368 } \
369 else \
370 { \
371 RegDeleteValueW(hKey, (SettingName)); \
372 } \
373 } while (0)
374
375 WCHAR szValueName[15];
376 UINT i;
377
378 if (!ConCfgOpenUserSettings(DefaultSettings ? L"" : ConsoleInfo->ConsoleTitle,
379 &hKey, KEY_WRITE, TRUE))
380 {
381 return FALSE;
382 }
383
384 for (i = 0; i < ARRAYSIZE(ConsoleInfo->ColorTable); ++i)
385 {
386 /*
387 * Write only the new value if we are saving the global settings
388 * or we are saving settings for a particular console, which differs
389 * from the default ones.
390 */
391 swprintf(szValueName, L"ColorTable%02u", i);
392 SetConsoleSetting(szValueName, REG_DWORD, sizeof(DWORD), &ConsoleInfo->ColorTable[i], s_Colors[i]);
393 }
394
395 SetConsoleSetting(L"CodePage", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CodePage, CP_ACP /* CP_OEMCP */);
396 SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(ConsoleInfo->FaceName) + 1) * sizeof(WCHAR), ConsoleInfo->FaceName, UNICODE_NULL); // wcsnlen
397 SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontFamily, FF_DONTCARE);
398
399 Storage = MAKELONG(ConsoleInfo->FontSize.X, ConsoleInfo->FontSize.Y); // Width, Height
400 SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &Storage, 0);
401
402 SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontWeight, FW_DONTCARE);
403
404 SetConsoleSetting(L"HistoryBufferSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->HistoryBufferSize, 50);
405 SetConsoleSetting(L"NumberOfHistoryBuffers", REG_DWORD, sizeof(DWORD), &ConsoleInfo->NumberOfHistoryBuffers, 4);
406
407 Storage = ConsoleInfo->HistoryNoDup;
408 SetConsoleSetting(L"HistoryNoDup", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
409
410 Storage = ConsoleInfo->QuickEdit;
411 SetConsoleSetting(L"QuickEdit", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
412
413 Storage = ConsoleInfo->InsertMode;
414 SetConsoleSetting(L"InsertMode", REG_DWORD, sizeof(DWORD), &Storage, TRUE);
415
416 Storage = MAKELONG(ConsoleInfo->ScreenBufferSize.X, ConsoleInfo->ScreenBufferSize.Y);
417 SetConsoleSetting(L"ScreenBufferSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 300));
418
419 Storage = ConsoleInfo->FullScreen;
420 SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
421
422 if (ConsoleInfo->AutoPosition == FALSE)
423 {
424 Storage = MAKELONG(ConsoleInfo->WindowPosition.x, ConsoleInfo->WindowPosition.y);
425 RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
426 }
427 else
428 {
429 RegDeleteValueW(hKey, L"WindowPosition");
430 }
431
432 Storage = MAKELONG(ConsoleInfo->WindowSize.X, ConsoleInfo->WindowSize.Y);
433 SetConsoleSetting(L"WindowSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 25));
434
435 SetConsoleSetting(L"CursorSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CursorSize, CSR_DEFAULT_CURSOR_SIZE);
436
437 Storage = ConsoleInfo->ScreenAttributes;
438 SetConsoleSetting(L"ScreenColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_SCREEN_ATTRIB);
439
440 Storage = ConsoleInfo->PopupAttributes;
441 SetConsoleSetting(L"PopupColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_POPUP_ATTRIB);
442
443 RegCloseKey(hKey);
444 return TRUE;
445 }
446
447 VOID
448 ConCfgInitDefaultSettings(IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
449 {
450 if (ConsoleInfo == NULL) return;
451
452 // ASSERT(ConsoleInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
453
454 /// HKCU,"Console","LoadConIme",0x00010003,1
455
456 // wcsncpy(ConsoleInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
457 // ConsoleInfo->FontSize = MAKELONG(8, 12); // 0x000C0008; // font is 8x12
458 // ConsoleInfo->FontSize = MAKELONG(16, 16); // font is 16x16
459
460 wcsncpy(ConsoleInfo->FaceName, L"VGA", LF_FACESIZE); // HACK: !!
461 // ConsoleInfo->FaceName[0] = UNICODE_NULL;
462 ConsoleInfo->FontFamily = FF_DONTCARE;
463 ConsoleInfo->FontSize.X = 0;
464 ConsoleInfo->FontSize.Y = 0;
465 ConsoleInfo->FontWeight = FW_NORMAL; // HACK: !!
466 // ConsoleInfo->FontWeight = FW_DONTCARE;
467
468 /* Initialize the default properties */
469
470 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
471 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
472 ConsoleInfo->HistoryBufferSize = 50;
473 ConsoleInfo->NumberOfHistoryBuffers = 4;
474 ConsoleInfo->HistoryNoDup = FALSE;
475
476 ConsoleInfo->QuickEdit = FALSE;
477 ConsoleInfo->InsertMode = TRUE;
478 // ConsoleInfo->InputBufferSize = 0;
479
480 // Rule: ScreenBufferSize >= WindowSize
481 ConsoleInfo->ScreenBufferSize.X = 80;
482 ConsoleInfo->ScreenBufferSize.Y = 300;
483 ConsoleInfo->WindowSize.X = 80;
484 ConsoleInfo->WindowSize.Y = 25;
485
486 ConsoleInfo->FullScreen = FALSE;
487 ConsoleInfo->AutoPosition = TRUE;
488 ConsoleInfo->WindowPosition.x = 0;
489 ConsoleInfo->WindowPosition.y = 0;
490
491 ConsoleInfo->CursorSize = CSR_DEFAULT_CURSOR_SIZE; // #define SMALL_SIZE 25
492
493 ConsoleInfo->ScreenAttributes = DEFAULT_SCREEN_ATTRIB;
494 ConsoleInfo->PopupAttributes = DEFAULT_POPUP_ATTRIB;
495
496 RtlCopyMemory(ConsoleInfo->ColorTable, s_Colors, sizeof(s_Colors));
497
498 ConsoleInfo->CodePage = GetOEMCP();
499 }
500
501 VOID
502 ConCfgGetDefaultSettings(IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
503 {
504 if (ConsoleInfo == NULL) return;
505
506 /*
507 * 1. Load the default values
508 */
509 ConCfgInitDefaultSettings(ConsoleInfo);
510
511 /*
512 * 2. Overwrite them with the ones stored in HKCU\Console.
513 * If the HKCU\Console key doesn't exist, create it
514 * and store the default values inside.
515 */
516 if (!ConCfgReadUserSettings(ConsoleInfo, TRUE))
517 ConCfgWriteUserSettings(ConsoleInfo, TRUE);
518 }
519
520 /* EOF */