2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/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"
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 DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
81 if (!OpenProcessToken(hProcess
, TOKEN_QUERY
, &hProcessToken
))
83 DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
84 CloseHandle(hProcess
);
88 if (!GetTokenInformation(hProcessToken
, TokenUser
, (PVOID
)Buffer
, sizeof(Buffer
), &Length
))
90 DPRINT("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 DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
100 CloseHandle(hProcessToken
);
101 CloseHandle(hProcess
);
105 bRet
= (RegOpenKeyExW(HKEY_USERS
,
109 hResult
) == ERROR_SUCCESS
);
111 RtlFreeUnicodeString(&SidName
);
113 CloseHandle(hProcessToken
);
114 CloseHandle(hProcess
);
120 ConSrvOpenUserSettings(DWORD ProcessId
,
121 LPCWSTR ConsoleTitle
,
127 WCHAR szBuffer
[MAX_PATH
] = L
"Console\\";
128 WCHAR szBuffer2
[MAX_PATH
] = L
"";
132 * Console properties are stored under the HKCU\Console\* key.
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.
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>
145 /* Open the registry key where we saved the console properties */
146 if (!OpenUserRegistryPathPerProcessId(ProcessId
, &hKey
, samDesired
))
148 DPRINT1("OpenUserRegistryPathPerProcessId failed\n");
153 * Try to open properties via the console title:
154 * to make the registry happy, replace all the
155 * backslashes by underscores.
157 TranslateConsoleName(szBuffer2
, ConsoleTitle
, MAX_PATH
);
159 /* Create the registry path */
160 wcsncat(szBuffer
, szBuffer2
, MAX_PATH
);
162 /* Create or open the registry key */
166 bRet
= (RegCreateKeyExW(hKey
,
169 REG_OPTION_NON_VOLATILE
,
173 NULL
) == ERROR_SUCCESS
);
178 bRet
= (RegOpenKeyExW(hKey
,
182 hSubKey
) == ERROR_SUCCESS
);
185 /* Close the parent key and return success or not */
191 ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
196 DWORD dwNumSubKeys
= 0;
198 DWORD dwColorIndex
= 0;
200 WCHAR szValueName
[MAX_PATH
];
202 WCHAR szValue
[LF_FACESIZE
] = L
"\0";
206 if (!ConSrvOpenUserSettings(ProcessId
,
207 ConsoleInfo
->ConsoleTitle
,
211 DPRINT("ConSrvOpenUserSettings failed\n");
215 if (RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
216 &dwNumSubKeys
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
218 DPRINT("ConSrvReadUserSettings: RegQueryInfoKey failed\n");
223 DPRINT("ConSrvReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys
);
225 for (dwIndex
= 0; dwIndex
< dwNumSubKeys
; dwIndex
++)
227 dwValue
= sizeof(Value
);
228 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
230 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, &dwType
, (BYTE
*)&Value
, &dwValue
) != ERROR_SUCCESS
)
232 if (dwType
== REG_SZ
)
235 * Retry in case of string value
237 dwValue
= sizeof(szValue
);
238 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
239 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, NULL
, (BYTE
*)szValue
, &dwValue
) != ERROR_SUCCESS
)
248 /* Maybe it is UI-specific ?? */
249 if (!wcsncmp(szValueName
, L
"ColorTable", wcslen(L
"ColorTable")))
252 swscanf(szValueName
, L
"ColorTable%2d", &dwColorIndex
);
253 if (dwColorIndex
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]))
255 ConsoleInfo
->Colors
[dwColorIndex
] = Value
;
259 else if (!wcscmp(szValueName
, L
"HistoryBufferSize"))
261 ConsoleInfo
->HistoryBufferSize
= Value
;
264 else if (!wcscmp(szValueName
, L
"NumberOfHistoryBuffers"))
266 ConsoleInfo
->NumberOfHistoryBuffers
= Value
;
269 else if (!wcscmp(szValueName
, L
"HistoryNoDup"))
271 ConsoleInfo
->HistoryNoDup
= (BOOLEAN
)Value
;
274 else if (!wcscmp(szValueName
, L
"FullScreen"))
276 ConsoleInfo
->FullScreen
= Value
;
279 else if (!wcscmp(szValueName
, L
"QuickEdit"))
281 ConsoleInfo
->QuickEdit
= (BOOLEAN
)Value
;
284 else if (!wcscmp(szValueName
, L
"InsertMode"))
286 ConsoleInfo
->InsertMode
= (BOOLEAN
)Value
;
289 else if (!wcscmp(szValueName
, L
"ScreenBufferSize"))
291 ConsoleInfo
->ScreenBufferSize
.X
= LOWORD(Value
);
292 ConsoleInfo
->ScreenBufferSize
.Y
= HIWORD(Value
);
295 else if (!wcscmp(szValueName
, L
"WindowSize"))
297 ConsoleInfo
->ConsoleSize
.X
= LOWORD(Value
);
298 ConsoleInfo
->ConsoleSize
.Y
= HIWORD(Value
);
301 else if (!wcscmp(szValueName
, L
"CursorSize"))
303 ConsoleInfo
->CursorSize
= min(max(Value
, 0), 100);
306 else if (!wcscmp(szValueName
, L
"ScreenColors"))
308 ConsoleInfo
->ScreenAttrib
= (USHORT
)Value
;
311 else if (!wcscmp(szValueName
, L
"PopupColors"))
313 ConsoleInfo
->PopupAttrib
= (USHORT
)Value
;
323 ConSrvWriteUserSettings(IN PCONSOLE_INFO ConsoleInfo
,
326 BOOL GlobalSettings
= (ConsoleInfo
->ConsoleTitle
[0] == L
'\0');
330 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
332 if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
334 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
338 RegDeleteValue(hKey, (SettingName)); \
342 WCHAR szValueName
[15];
345 if (!ConSrvOpenUserSettings(ProcessId
,
346 ConsoleInfo
->ConsoleTitle
,
353 for (i
= 0 ; i
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]) ; ++i
)
356 * Write only the new value if we are saving the global settings
357 * or we are saving settings for a particular console, which differs
358 * from the default ones.
360 swprintf(szValueName
, L
"ColorTable%02d", i
);
361 SetConsoleSetting(szValueName
, REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->Colors
[i
], s_Colors
[i
]);
364 SetConsoleSetting(L
"HistoryBufferSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->HistoryBufferSize
, 50);
365 SetConsoleSetting(L
"NumberOfHistoryBuffers", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->NumberOfHistoryBuffers
, 4);
367 Storage
= ConsoleInfo
->HistoryNoDup
;
368 SetConsoleSetting(L
"HistoryNoDup", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
370 Storage
= ConsoleInfo
->FullScreen
;
371 SetConsoleSetting(L
"FullScreen", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
373 Storage
= ConsoleInfo
->QuickEdit
;
374 SetConsoleSetting(L
"QuickEdit", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
376 Storage
= ConsoleInfo
->InsertMode
;
377 SetConsoleSetting(L
"InsertMode", REG_DWORD
, sizeof(DWORD
), &Storage
, TRUE
);
379 Storage
= MAKELONG(ConsoleInfo
->ScreenBufferSize
.X
, ConsoleInfo
->ScreenBufferSize
.Y
);
380 SetConsoleSetting(L
"ScreenBufferSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 300));
382 Storage
= MAKELONG(ConsoleInfo
->ConsoleSize
.X
, ConsoleInfo
->ConsoleSize
.Y
);
383 SetConsoleSetting(L
"WindowSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 25));
385 SetConsoleSetting(L
"CursorSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->CursorSize
, CSR_DEFAULT_CURSOR_SIZE
);
387 Storage
= ConsoleInfo
->ScreenAttrib
;
388 SetConsoleSetting(L
"ScreenColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_SCREEN_ATTRIB
);
390 Storage
= ConsoleInfo
->PopupAttrib
;
391 SetConsoleSetting(L
"PopupColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_POPUP_ATTRIB
);
398 ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
401 if (ConsoleInfo
== NULL
) return;
403 /// HKCU,"Console","LoadConIme",0x00010003,1
406 * 1. Load the default values
408 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
409 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
410 ConsoleInfo
->HistoryBufferSize
= 50;
411 ConsoleInfo
->NumberOfHistoryBuffers
= 4;
412 ConsoleInfo
->HistoryNoDup
= FALSE
;
414 ConsoleInfo
->FullScreen
= FALSE
;
415 ConsoleInfo
->QuickEdit
= FALSE
;
416 ConsoleInfo
->InsertMode
= TRUE
;
417 // ConsoleInfo->InputBufferSize;
418 ConsoleInfo
->ScreenBufferSize
.X
= 80;
419 ConsoleInfo
->ScreenBufferSize
.Y
= 300;
420 ConsoleInfo
->ConsoleSize
.X
= 80;
421 ConsoleInfo
->ConsoleSize
.Y
= 25;
423 ConsoleInfo
->CursorBlinkOn
;
424 ConsoleInfo
->ForceCursorOff
;
425 ConsoleInfo
->CursorSize
= CSR_DEFAULT_CURSOR_SIZE
; // #define SMALL_SIZE 25
427 ConsoleInfo
->ScreenAttrib
= DEFAULT_SCREEN_ATTRIB
;
428 ConsoleInfo
->PopupAttrib
= DEFAULT_POPUP_ATTRIB
;
430 memcpy(ConsoleInfo
->Colors
, s_Colors
, sizeof(s_Colors
));
432 // ConsoleInfo->CodePage;
434 ConsoleInfo
->ConsoleTitle
[0] = L
'\0';
437 * 2. Overwrite them with the ones stored in HKCU\Console.
438 * If the HKCU\Console key doesn't exist, create it
439 * and store the default values inside.
441 if (!ConSrvReadUserSettings(ConsoleInfo
, ProcessId
))
443 ConSrvWriteUserSettings(ConsoleInfo
, ProcessId
);
448 ConSrvApplyUserSettings(IN PCONSOLE Console
,
449 IN PCONSOLE_INFO ConsoleInfo
)
451 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= Console
->ActiveBuffer
;
453 BOOL SizeChanged
= FALSE
;
456 * Apply full-screen mode.
458 if (ConsoleInfo
->FullScreen
)
459 Console
->ActiveBuffer
->DisplayMode
|= CONSOLE_FULLSCREEN_MODE
;
461 Console
->ActiveBuffer
->DisplayMode
&= ~CONSOLE_FULLSCREEN_MODE
;
462 // TODO: Apply it really
465 * Apply terminal-edition settings:
466 * - QuickEdit and Insert modes,
467 * - history settings.
469 Console
->QuickEdit
= ConsoleInfo
->QuickEdit
;
470 Console
->InsertMode
= ConsoleInfo
->InsertMode
;
473 * Apply foreground and background colors for both screen and popup
474 * and copy the new palette.
476 ActiveBuffer
->ScreenDefaultAttrib
= ConsoleInfo
->ScreenAttrib
;
477 ActiveBuffer
->PopupDefaultAttrib
= ConsoleInfo
->PopupAttrib
;
478 memcpy(Console
->Colors
, ConsoleInfo
->Colors
, sizeof(s_Colors
)); // FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors.
480 // TODO: Really update the screen attributes as FillConsoleOutputAttribute does.
482 /* Apply cursor size */
483 ActiveBuffer
->CursorInfo
.bVisible
= (ConsoleInfo
->CursorSize
!= 0);
484 ActiveBuffer
->CursorInfo
.dwSize
= min(max(ConsoleInfo
->CursorSize
, 0), 100);
486 /* Resize the console */
487 if (ConsoleInfo
->ConsoleSize
.X
!= Console
->ConsoleSize
.X
||
488 ConsoleInfo
->ConsoleSize
.Y
!= Console
->ConsoleSize
.Y
)
490 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
494 /* Resize its active screen-buffer */
495 BufSize
= ConsoleInfo
->ScreenBufferSize
;
496 if (BufSize
.X
!= ActiveBuffer
->ScreenBufferSize
.X
||
497 BufSize
.Y
!= ActiveBuffer
->ScreenBufferSize
.Y
)
499 if (NT_SUCCESS(ConioResizeBuffer(Console
, ActiveBuffer
, BufSize
)))
503 if (SizeChanged
) ConioResizeTerminal(Console
);