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