2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/settings.c
5 * PURPOSE: Console settings management
6 * PROGRAMMERS: Johannes Anderwald
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
13 #include "include/conio.h"
14 #include "include/conio2.h"
15 #include "include/settings.h"
17 #include <stdio.h> // for swprintf
23 /* GLOBALS ********************************************************************/
25 extern const COLORREF s_Colors
[16];
28 /* FUNCTIONS ******************************************************************/
31 TranslateConsoleName(OUT LPWSTR DestString
,
32 IN LPCWSTR ConsoleName
,
35 #define PATH_SEPARATOR L'\\'
39 if ( DestString
== NULL
|| ConsoleName
== NULL
||
40 *ConsoleName
== L
'\0' || MaxStrLen
== 0 )
45 wLength
= GetWindowsDirectoryW(DestString
, MaxStrLen
);
46 if ((wLength
> 0) && (_wcsnicmp(ConsoleName
, DestString
, wLength
) == 0))
48 wcsncpy(DestString
, L
"%SystemRoot%", MaxStrLen
);
49 // FIXME: Fix possible buffer overflows there !!!!!
50 wcsncat(DestString
, ConsoleName
+ wLength
, MaxStrLen
);
54 wcsncpy(DestString
, ConsoleName
, MaxStrLen
);
57 /* Replace path separators (backslashes) by underscores */
58 while ((DestString
= wcschr(DestString
, PATH_SEPARATOR
))) *DestString
= L
'_';
62 OpenUserRegistryPathPerProcessId(DWORD ProcessId
,
67 HANDLE hProcessToken
= NULL
;
71 UNICODE_STRING SidName
;
74 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
| READ_CONTROL
, FALSE
, ProcessId
);
77 DPRINT1("Error: OpenProcess failed(0x%x)\n", GetLastError());
81 if (!OpenProcessToken(hProcess
, TOKEN_QUERY
, &hProcessToken
))
83 DPRINT1("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
84 CloseHandle(hProcess
);
88 if (!GetTokenInformation(hProcessToken
, TokenUser
, (PVOID
)Buffer
, sizeof(Buffer
), &Length
))
90 DPRINT1("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
91 CloseHandle(hProcessToken
);
92 CloseHandle(hProcess
);
96 TokUser
= ((PTOKEN_USER
)Buffer
)->User
.Sid
;
97 if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName
, TokUser
, TRUE
)))
99 DPRINT1("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
100 CloseHandle(hProcessToken
);
101 CloseHandle(hProcess
);
106 * Might fail for LiveCD... Why ? Because only HKU\.DEFAULT exists.
108 bRet
= (RegOpenKeyExW(HKEY_USERS
,
112 hResult
) == ERROR_SUCCESS
);
114 RtlFreeUnicodeString(&SidName
);
116 CloseHandle(hProcessToken
);
117 CloseHandle(hProcess
);
123 ConSrvOpenUserSettings(DWORD ProcessId
,
124 LPCWSTR ConsoleTitle
,
130 WCHAR szBuffer
[MAX_PATH
] = L
"Console\\";
131 WCHAR szBuffer2
[MAX_PATH
] = L
"";
135 * Console properties are stored under the HKCU\Console\* key.
137 * We use the original console title as the subkey name for storing
138 * console properties. We need to distinguish whether we were launched
139 * via the console application directly or via a shortcut.
141 * If the title of the console corresponds to a path (more precisely,
142 * if the title is of the form: C:\ReactOS\<some_path>\<some_app.exe>),
143 * then use the corresponding unexpanded path and with the backslashes
144 * replaced by underscores, to make the registry happy,
145 * i.e. %SystemRoot%_<some_path>_<some_app.exe>
148 /* Open the registry key where we saved the console properties */
149 if (!OpenUserRegistryPathPerProcessId(ProcessId
, &hKey
, samDesired
))
151 DPRINT1("OpenUserRegistryPathPerProcessId failed\n");
156 * Try to open properties via the console title:
157 * to make the registry happy, replace all the
158 * backslashes by underscores.
160 TranslateConsoleName(szBuffer2
, ConsoleTitle
, MAX_PATH
);
162 /* Create the registry path */
163 wcsncat(szBuffer
, szBuffer2
, MAX_PATH
);
165 /* Create or open the registry key */
169 bRet
= (RegCreateKeyExW(hKey
,
172 REG_OPTION_NON_VOLATILE
,
176 NULL
) == ERROR_SUCCESS
);
181 bRet
= (RegOpenKeyExW(hKey
,
185 hSubKey
) == ERROR_SUCCESS
);
188 /* Close the parent key and return success or not */
194 ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
199 DWORD dwNumSubKeys
= 0;
201 DWORD dwColorIndex
= 0;
203 WCHAR szValueName
[MAX_PATH
];
205 WCHAR szValue
[LF_FACESIZE
] = L
"\0";
209 if (!ConSrvOpenUserSettings(ProcessId
,
210 ConsoleInfo
->ConsoleTitle
,
214 DPRINT("ConSrvOpenUserSettings failed\n");
218 if (RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
219 &dwNumSubKeys
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
221 DPRINT("ConSrvReadUserSettings: RegQueryInfoKey failed\n");
226 DPRINT("ConSrvReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys
);
228 for (dwIndex
= 0; dwIndex
< dwNumSubKeys
; dwIndex
++)
230 dwValue
= sizeof(Value
);
231 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
233 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, &dwType
, (BYTE
*)&Value
, &dwValue
) != ERROR_SUCCESS
)
235 if (dwType
== REG_SZ
)
238 * Retry in case of string value
240 dwValue
= sizeof(szValue
);
241 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
242 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, NULL
, (BYTE
*)szValue
, &dwValue
) != ERROR_SUCCESS
)
251 /* Maybe it is UI-specific ?? */
252 if (!wcsncmp(szValueName
, L
"ColorTable", wcslen(L
"ColorTable")))
255 swscanf(szValueName
, L
"ColorTable%2d", &dwColorIndex
);
256 if (dwColorIndex
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]))
258 ConsoleInfo
->Colors
[dwColorIndex
] = Value
;
262 else if (!wcscmp(szValueName
, L
"HistoryBufferSize"))
264 ConsoleInfo
->HistoryBufferSize
= Value
;
267 else if (!wcscmp(szValueName
, L
"NumberOfHistoryBuffers"))
269 ConsoleInfo
->NumberOfHistoryBuffers
= Value
;
272 else if (!wcscmp(szValueName
, L
"HistoryNoDup"))
274 ConsoleInfo
->HistoryNoDup
= (BOOLEAN
)Value
;
277 else if (!wcscmp(szValueName
, L
"QuickEdit"))
279 ConsoleInfo
->QuickEdit
= (BOOLEAN
)Value
;
282 else if (!wcscmp(szValueName
, L
"InsertMode"))
284 ConsoleInfo
->InsertMode
= (BOOLEAN
)Value
;
287 else if (!wcscmp(szValueName
, L
"ScreenBufferSize"))
289 ConsoleInfo
->ScreenBufferSize
.X
= LOWORD(Value
);
290 ConsoleInfo
->ScreenBufferSize
.Y
= HIWORD(Value
);
293 else if (!wcscmp(szValueName
, L
"WindowSize"))
295 ConsoleInfo
->ConsoleSize
.X
= LOWORD(Value
);
296 ConsoleInfo
->ConsoleSize
.Y
= HIWORD(Value
);
299 else if (!wcscmp(szValueName
, L
"CursorSize"))
301 ConsoleInfo
->CursorSize
= min(max(Value
, 0), 100);
304 else if (!wcscmp(szValueName
, L
"ScreenColors"))
306 ConsoleInfo
->ScreenAttrib
= (USHORT
)Value
;
309 else if (!wcscmp(szValueName
, L
"PopupColors"))
311 ConsoleInfo
->PopupAttrib
= (USHORT
)Value
;
321 ConSrvWriteUserSettings(IN PCONSOLE_INFO ConsoleInfo
,
324 BOOL GlobalSettings
= (ConsoleInfo
->ConsoleTitle
[0] == L
'\0');
328 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
330 if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
332 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
336 RegDeleteValue(hKey, (SettingName)); \
340 WCHAR szValueName
[15];
343 if (!ConSrvOpenUserSettings(ProcessId
,
344 ConsoleInfo
->ConsoleTitle
,
351 for (i
= 0 ; i
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]) ; ++i
)
354 * Write only the new value if we are saving the global settings
355 * or we are saving settings for a particular console, which differs
356 * from the default ones.
358 swprintf(szValueName
, L
"ColorTable%02d", i
);
359 SetConsoleSetting(szValueName
, REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->Colors
[i
], s_Colors
[i
]);
362 SetConsoleSetting(L
"HistoryBufferSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->HistoryBufferSize
, 50);
363 SetConsoleSetting(L
"NumberOfHistoryBuffers", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->NumberOfHistoryBuffers
, 4);
365 Storage
= ConsoleInfo
->HistoryNoDup
;
366 SetConsoleSetting(L
"HistoryNoDup", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
368 Storage
= ConsoleInfo
->QuickEdit
;
369 SetConsoleSetting(L
"QuickEdit", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
371 Storage
= ConsoleInfo
->InsertMode
;
372 SetConsoleSetting(L
"InsertMode", REG_DWORD
, sizeof(DWORD
), &Storage
, TRUE
);
374 Storage
= MAKELONG(ConsoleInfo
->ScreenBufferSize
.X
, ConsoleInfo
->ScreenBufferSize
.Y
);
375 SetConsoleSetting(L
"ScreenBufferSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 300));
377 Storage
= MAKELONG(ConsoleInfo
->ConsoleSize
.X
, ConsoleInfo
->ConsoleSize
.Y
);
378 SetConsoleSetting(L
"WindowSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 25));
380 SetConsoleSetting(L
"CursorSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->CursorSize
, CSR_DEFAULT_CURSOR_SIZE
);
382 Storage
= ConsoleInfo
->ScreenAttrib
;
383 SetConsoleSetting(L
"ScreenColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_SCREEN_ATTRIB
);
385 Storage
= ConsoleInfo
->PopupAttrib
;
386 SetConsoleSetting(L
"PopupColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_POPUP_ATTRIB
);
393 ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
396 if (ConsoleInfo
== NULL
) return;
398 /// HKCU,"Console","LoadConIme",0x00010003,1
401 * 1. Load the default values
403 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
404 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
405 ConsoleInfo
->HistoryBufferSize
= 50;
406 ConsoleInfo
->NumberOfHistoryBuffers
= 4;
407 ConsoleInfo
->HistoryNoDup
= FALSE
;
409 ConsoleInfo
->QuickEdit
= FALSE
;
410 ConsoleInfo
->InsertMode
= TRUE
;
411 // ConsoleInfo->InputBufferSize;
413 // Rule: ScreenBufferSize >= ConsoleSize
414 ConsoleInfo
->ScreenBufferSize
.X
= 80;
415 ConsoleInfo
->ScreenBufferSize
.Y
= 300;
416 ConsoleInfo
->ConsoleSize
.X
= 80;
417 ConsoleInfo
->ConsoleSize
.Y
= 25;
419 ConsoleInfo
->CursorBlinkOn
;
420 ConsoleInfo
->ForceCursorOff
;
421 ConsoleInfo
->CursorSize
= CSR_DEFAULT_CURSOR_SIZE
; // #define SMALL_SIZE 25
423 ConsoleInfo
->ScreenAttrib
= DEFAULT_SCREEN_ATTRIB
;
424 ConsoleInfo
->PopupAttrib
= DEFAULT_POPUP_ATTRIB
;
426 memcpy(ConsoleInfo
->Colors
, s_Colors
, sizeof(s_Colors
));
428 // ConsoleInfo->CodePage;
430 ConsoleInfo
->ConsoleTitle
[0] = L
'\0';
433 * 2. Overwrite them with the ones stored in HKCU\Console.
434 * If the HKCU\Console key doesn't exist, create it
435 * and store the default values inside.
437 if (!ConSrvReadUserSettings(ConsoleInfo
, ProcessId
))
439 ConSrvWriteUserSettings(ConsoleInfo
, ProcessId
);
444 ConSrvApplyUserSettings(IN PCONSOLE Console
,
445 IN PCONSOLE_INFO ConsoleInfo
)
447 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= Console
->ActiveBuffer
;
450 * Apply terminal-edition settings:
451 * - QuickEdit and Insert modes,
452 * - history settings.
454 Console
->QuickEdit
= ConsoleInfo
->QuickEdit
;
455 Console
->InsertMode
= ConsoleInfo
->InsertMode
;
458 * Apply foreground and background colors for both screen and popup
459 * and copy the new palette.
461 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
463 PTEXTMODE_SCREEN_BUFFER Buffer
= (PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
;
465 Buffer
->ScreenDefaultAttrib
= ConsoleInfo
->ScreenAttrib
;
466 Buffer
->PopupDefaultAttrib
= ConsoleInfo
->PopupAttrib
;
468 else // if (Console->ActiveBuffer->Header.Type == GRAPHICS_BUFFER)
472 // FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors.
473 memcpy(Console
->Colors
, ConsoleInfo
->Colors
, sizeof(s_Colors
));
475 // TODO: Really update the screen attributes as FillConsoleOutputAttribute does.
477 /* Apply cursor size */
478 ActiveBuffer
->CursorInfo
.bVisible
= (ConsoleInfo
->CursorSize
!= 0);
479 ActiveBuffer
->CursorInfo
.dwSize
= min(max(ConsoleInfo
->CursorSize
, 0), 100);
481 if (GetType(ActiveBuffer
) == TEXTMODE_BUFFER
)
483 PTEXTMODE_SCREEN_BUFFER Buffer
= (PTEXTMODE_SCREEN_BUFFER
)ActiveBuffer
;
486 /* Resize its active screen-buffer */
487 BufSize
= ConsoleInfo
->ScreenBufferSize
;
489 if (Console
->FixedSize
)
492 * The console is in fixed-size mode, so we cannot resize anything
493 * at the moment. However, keep those settings somewhere so that
494 * we can try to set them up when we will be allowed to do so.
496 if (ConsoleInfo
->ConsoleSize
.X
!= Buffer
->OldViewSize
.X
||
497 ConsoleInfo
->ConsoleSize
.Y
!= Buffer
->OldViewSize
.Y
)
499 Buffer
->OldViewSize
= ConsoleInfo
->ConsoleSize
;
502 /* Buffer size is not allowed to be smaller than the view size */
503 if (BufSize
.X
>= Buffer
->OldViewSize
.X
&& BufSize
.Y
>= Buffer
->OldViewSize
.Y
)
505 if (BufSize
.X
!= Buffer
->OldScreenBufferSize
.X
||
506 BufSize
.Y
!= Buffer
->OldScreenBufferSize
.Y
)
509 * The console is in fixed-size mode, so we cannot resize anything
510 * at the moment. However, keep those settings somewhere so that
511 * we can try to set them up when we will be allowed to do so.
513 Buffer
->OldScreenBufferSize
= BufSize
;
519 BOOL SizeChanged
= FALSE
;
521 /* Resize the console */
522 if (ConsoleInfo
->ConsoleSize
.X
!= Buffer
->ViewSize
.X
||
523 ConsoleInfo
->ConsoleSize
.Y
!= Buffer
->ViewSize
.Y
)
525 Buffer
->ViewSize
= ConsoleInfo
->ConsoleSize
;
529 /* Resize the screen-buffer */
530 if (BufSize
.X
!= Buffer
->ScreenBufferSize
.X
||
531 BufSize
.Y
!= Buffer
->ScreenBufferSize
.Y
)
533 if (NT_SUCCESS(ConioResizeBuffer(Console
, Buffer
, BufSize
)))
537 if (SizeChanged
) ConioResizeTerminal(Console
);
540 else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
542 PGRAPHICS_SCREEN_BUFFER Buffer
= (PGRAPHICS_SCREEN_BUFFER
)ActiveBuffer
;
545 * In any case we do NOT modify the size of the graphics screen-buffer.
546 * We just allow resizing the view only if the new size is smaller
547 * than the older one.
550 if (Console
->FixedSize
)
553 * The console is in fixed-size mode, so we cannot resize anything
554 * at the moment. However, keep those settings somewhere so that
555 * we can try to set them up when we will be allowed to do so.
557 if (ConsoleInfo
->ConsoleSize
.X
<= Buffer
->ViewSize
.X
||
558 ConsoleInfo
->ConsoleSize
.Y
<= Buffer
->ViewSize
.Y
)
560 Buffer
->OldViewSize
= ConsoleInfo
->ConsoleSize
;
565 /* Resize the view if its size is bigger than the specified size */
566 if (ConsoleInfo
->ConsoleSize
.X
<= Buffer
->ViewSize
.X
||
567 ConsoleInfo
->ConsoleSize
.Y
<= Buffer
->ViewSize
.Y
)
569 Buffer
->ViewSize
= ConsoleInfo
->ConsoleSize
;
570 // SizeChanged = TRUE;