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: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 * NOTE: Adapted from existing code.
11 /* INCLUDES *******************************************************************/
14 #include "include/conio.h"
16 #include "include/settings.h"
18 #include <stdio.h> // for swprintf
24 /* GLOBALS ********************************************************************/
26 extern const COLORREF s_Colors
[16];
29 /* FUNCTIONS ******************************************************************/
32 TranslateConsoleName(OUT LPWSTR DestString
,
33 IN LPCWSTR ConsoleName
,
36 #define PATH_SEPARATOR L'\\'
40 if ( DestString
== NULL
|| ConsoleName
== NULL
||
41 *ConsoleName
== L
'\0' || MaxStrLen
== 0 )
46 wLength
= GetWindowsDirectoryW(DestString
, MaxStrLen
);
47 if ((wLength
> 0) && (_wcsnicmp(ConsoleName
, DestString
, wLength
) == 0))
49 wcsncpy(DestString
, L
"%SystemRoot%", MaxStrLen
);
50 // FIXME: Fix possible buffer overflows there !!!!!
51 wcsncat(DestString
, ConsoleName
+ wLength
, MaxStrLen
);
55 wcsncpy(DestString
, ConsoleName
, MaxStrLen
);
58 /* Replace path separators (backslashes) by underscores */
59 while ((DestString
= wcschr(DestString
, PATH_SEPARATOR
))) *DestString
= L
'_';
63 OpenUserRegistryPathPerProcessId(DWORD ProcessId
,
68 HANDLE hProcessToken
= NULL
;
72 UNICODE_STRING SidName
;
75 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ
| READ_CONTROL
, FALSE
, ProcessId
);
78 DPRINT("Error: OpenProcess failed(0x%x)\n", GetLastError());
82 if (!OpenProcessToken(hProcess
, TOKEN_QUERY
, &hProcessToken
))
84 DPRINT("Error: OpenProcessToken failed(0x%x)\n", GetLastError());
85 CloseHandle(hProcess
);
89 if (!GetTokenInformation(hProcessToken
, TokenUser
, (PVOID
)Buffer
, sizeof(Buffer
), &Length
))
91 DPRINT("Error: GetTokenInformation failed(0x%x)\n",GetLastError());
92 CloseHandle(hProcessToken
);
93 CloseHandle(hProcess
);
97 TokUser
= ((PTOKEN_USER
)Buffer
)->User
.Sid
;
98 if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName
, TokUser
, TRUE
)))
100 DPRINT("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError());
101 CloseHandle(hProcessToken
);
102 CloseHandle(hProcess
);
106 bRet
= (RegOpenKeyExW(HKEY_USERS
,
110 hResult
) == ERROR_SUCCESS
);
112 RtlFreeUnicodeString(&SidName
);
114 CloseHandle(hProcessToken
);
115 CloseHandle(hProcess
);
121 ConSrvOpenUserSettings(DWORD ProcessId
,
122 LPCWSTR ConsoleTitle
,
128 WCHAR szBuffer
[MAX_PATH
] = L
"Console\\";
129 WCHAR szBuffer2
[MAX_PATH
] = L
"";
133 * Console properties are stored under the HKCU\Console\* key.
135 * We use the original console title as the subkey name for storing
136 * console properties. We need to distinguish whether we were launched
137 * via the console application directly or via a shortcut.
139 * If the title of the console corresponds to a path (more precisely,
140 * if the title is of the form: C:\ReactOS\<some_path>\<some_app.exe>),
141 * then use the corresponding unexpanded path and with the backslashes
142 * replaced by underscores, to make the registry happy,
143 * i.e. %SystemRoot%_<some_path>_<some_app.exe>
146 /* Open the registry key where we saved the console properties */
147 if (!OpenUserRegistryPathPerProcessId(ProcessId
, &hKey
, samDesired
))
149 DPRINT1("OpenUserRegistryPathPerProcessId failed\n");
154 * Try to open properties via the console title:
155 * to make the registry happy, replace all the
156 * backslashes by underscores.
158 TranslateConsoleName(szBuffer2
, ConsoleTitle
, MAX_PATH
);
160 /* Create the registry path */
161 wcsncat(szBuffer
, szBuffer2
, MAX_PATH
);
163 /* Create or open the registry key */
167 bRet
= (RegCreateKeyExW(hKey
,
170 REG_OPTION_NON_VOLATILE
,
174 NULL
) == ERROR_SUCCESS
);
179 bRet
= (RegOpenKeyExW(hKey
,
183 hSubKey
) == ERROR_SUCCESS
);
186 /* Close the parent key and return success or not */
192 ConSrvReadUserSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
197 DWORD dwNumSubKeys
= 0;
199 DWORD dwColorIndex
= 0;
201 WCHAR szValueName
[MAX_PATH
];
203 WCHAR szValue
[LF_FACESIZE
] = L
"\0";
207 if (!ConSrvOpenUserSettings(ProcessId
,
208 ConsoleInfo
->ConsoleTitle
,
212 DPRINT("ConSrvOpenUserSettings failed\n");
216 if (RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
217 &dwNumSubKeys
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
219 DPRINT("ConSrvReadUserSettings: RegQueryInfoKey failed\n");
224 DPRINT("ConSrvReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys
);
226 for (dwIndex
= 0; dwIndex
< dwNumSubKeys
; dwIndex
++)
228 dwValue
= sizeof(Value
);
229 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
231 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, &dwType
, (BYTE
*)&Value
, &dwValue
) != ERROR_SUCCESS
)
233 if (dwType
== REG_SZ
)
236 * Retry in case of string value
238 dwValue
= sizeof(szValue
);
239 dwValueName
= MAX_PATH
; // sizeof(szValueName)/sizeof(szValueName[0])
240 if (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwValueName
, NULL
, NULL
, (BYTE
*)szValue
, &dwValue
) != ERROR_SUCCESS
)
249 /* Maybe it is UI-specific ?? */
250 if (!wcsncmp(szValueName
, L
"ColorTable", wcslen(L
"ColorTable")))
253 swscanf(szValueName
, L
"ColorTable%2d", &dwColorIndex
);
254 if (dwColorIndex
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]))
256 ConsoleInfo
->Colors
[dwColorIndex
] = Value
;
260 else if (!wcscmp(szValueName
, L
"HistoryBufferSize"))
262 ConsoleInfo
->HistoryBufferSize
= Value
;
265 else if (!wcscmp(szValueName
, L
"NumberOfHistoryBuffers"))
267 ConsoleInfo
->NumberOfHistoryBuffers
= Value
;
270 else if (!wcscmp(szValueName
, L
"HistoryNoDup"))
272 ConsoleInfo
->HistoryNoDup
= Value
;
275 else if (!wcscmp(szValueName
, L
"FullScreen"))
277 ConsoleInfo
->FullScreen
= Value
;
280 else if (!wcscmp(szValueName
, L
"QuickEdit"))
282 ConsoleInfo
->QuickEdit
= Value
;
285 else if (!wcscmp(szValueName
, L
"InsertMode"))
287 ConsoleInfo
->InsertMode
= Value
;
290 else if (!wcscmp(szValueName
, L
"ScreenBufferSize"))
292 ConsoleInfo
->ScreenBufferSize
.X
= LOWORD(Value
);
293 ConsoleInfo
->ScreenBufferSize
.Y
= HIWORD(Value
);
296 else if (!wcscmp(szValueName
, L
"WindowSize"))
298 ConsoleInfo
->ConsoleSize
.X
= LOWORD(Value
);
299 ConsoleInfo
->ConsoleSize
.Y
= HIWORD(Value
);
302 else if (!wcscmp(szValueName
, L
"CursorSize"))
304 ConsoleInfo
->CursorSize
= min(max(Value
, 0), 100);
307 else if (!wcscmp(szValueName
, L
"ScreenColors"))
309 ConsoleInfo
->ScreenAttrib
= Value
;
312 else if (!wcscmp(szValueName
, L
"PopupColors"))
314 ConsoleInfo
->PopupAttrib
= Value
;
324 ConSrvWriteUserSettings(IN PCONSOLE_INFO ConsoleInfo
,
327 BOOL GlobalSettings
= (ConsoleInfo
->ConsoleTitle
[0] == L
'\0');
331 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
333 if (GlobalSettings || (!GlobalSettings && (*(Setting) != (DefaultValue)))) \
335 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
339 RegDeleteValue(hKey, (SettingName)); \
343 WCHAR szValueName
[15];
346 if (!ConSrvOpenUserSettings(ProcessId
,
347 ConsoleInfo
->ConsoleTitle
,
354 for (i
= 0 ; i
< sizeof(ConsoleInfo
->Colors
)/sizeof(ConsoleInfo
->Colors
[0]) ; ++i
)
357 * Write only the new value if we are saving the global settings
358 * or we are saving settings for a particular console, which differs
359 * from the default ones.
361 swprintf(szValueName
, L
"ColorTable%02d", i
);
362 SetConsoleSetting(szValueName
, REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->Colors
[i
], s_Colors
[i
]);
365 SetConsoleSetting(L
"HistoryBufferSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->HistoryBufferSize
, 50);
366 SetConsoleSetting(L
"NumberOfHistoryBuffers", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->NumberOfHistoryBuffers
, 4);
368 Storage
= ConsoleInfo
->HistoryNoDup
;
369 SetConsoleSetting(L
"HistoryNoDup", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
371 Storage
= ConsoleInfo
->FullScreen
;
372 SetConsoleSetting(L
"FullScreen", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
374 Storage
= ConsoleInfo
->QuickEdit
;
375 SetConsoleSetting(L
"QuickEdit", REG_DWORD
, sizeof(DWORD
), &Storage
, FALSE
);
377 Storage
= ConsoleInfo
->InsertMode
;
378 SetConsoleSetting(L
"InsertMode", REG_DWORD
, sizeof(DWORD
), &Storage
, TRUE
);
380 Storage
= MAKELONG(ConsoleInfo
->ScreenBufferSize
.X
, ConsoleInfo
->ScreenBufferSize
.Y
);
381 SetConsoleSetting(L
"ScreenBufferSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 300));
383 Storage
= MAKELONG(ConsoleInfo
->ConsoleSize
.X
, ConsoleInfo
->ConsoleSize
.Y
);
384 SetConsoleSetting(L
"WindowSize", REG_DWORD
, sizeof(DWORD
), &Storage
, MAKELONG(80, 25));
386 SetConsoleSetting(L
"CursorSize", REG_DWORD
, sizeof(DWORD
), &ConsoleInfo
->CursorSize
, CSR_DEFAULT_CURSOR_SIZE
);
388 Storage
= ConsoleInfo
->ScreenAttrib
;
389 SetConsoleSetting(L
"ScreenColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_SCREEN_ATTRIB
);
391 Storage
= ConsoleInfo
->PopupAttrib
;
392 SetConsoleSetting(L
"PopupColors", REG_DWORD
, sizeof(DWORD
), &Storage
, DEFAULT_POPUP_ATTRIB
);
399 ConSrvGetDefaultSettings(IN OUT PCONSOLE_INFO ConsoleInfo
,
402 if (ConsoleInfo
== NULL
) return;
404 /// HKCU,"Console","LoadConIme",0x00010003,1
407 * 1. Load the default values
409 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
410 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
411 ConsoleInfo
->HistoryBufferSize
= 50;
412 ConsoleInfo
->NumberOfHistoryBuffers
= 4;
413 ConsoleInfo
->HistoryNoDup
= FALSE
;
415 ConsoleInfo
->FullScreen
= FALSE
;
416 ConsoleInfo
->QuickEdit
= FALSE
;
417 ConsoleInfo
->InsertMode
= TRUE
;
418 // ConsoleInfo->InputBufferSize;
419 ConsoleInfo
->ScreenBufferSize
= (COORD
){80, 300};
420 ConsoleInfo
->ConsoleSize
= (COORD
){80, 25 };
422 ConsoleInfo
->CursorBlinkOn
;
423 ConsoleInfo
->ForceCursorOff
;
424 ConsoleInfo
->CursorSize
= CSR_DEFAULT_CURSOR_SIZE
; // #define SMALL_SIZE 25
426 ConsoleInfo
->ScreenAttrib
= DEFAULT_SCREEN_ATTRIB
;
427 ConsoleInfo
->PopupAttrib
= DEFAULT_POPUP_ATTRIB
;
429 memcpy(ConsoleInfo
->Colors
, s_Colors
, sizeof(s_Colors
));
431 // ConsoleInfo->CodePage;
433 ConsoleInfo
->ConsoleTitle
[0] = L
'\0';
436 * 2. Overwrite them with the ones stored in HKCU\Console.
437 * If the HKCU\Console key doesn't exist, create it
438 * and store the default values inside.
440 if (!ConSrvReadUserSettings(ConsoleInfo
, ProcessId
))
442 ConSrvWriteUserSettings(ConsoleInfo
, ProcessId
);
447 ConSrvApplyUserSettings(IN PCONSOLE Console
,
448 IN PCONSOLE_INFO ConsoleInfo
)
450 PCONSOLE_SCREEN_BUFFER ActiveBuffer
= Console
->ActiveBuffer
;
452 BOOL SizeChanged
= FALSE
;
455 * Apply full-screen mode.
457 if (ConsoleInfo
->FullScreen
)
458 Console
->ActiveBuffer
->DisplayMode
|= CONSOLE_FULLSCREEN_MODE
;
460 Console
->ActiveBuffer
->DisplayMode
&= ~CONSOLE_FULLSCREEN_MODE
;
461 // TODO: Apply it really
464 * Apply terminal-edition settings:
465 * - QuickEdit and Insert modes,
466 * - history settings.
468 Console
->QuickEdit
= ConsoleInfo
->QuickEdit
;
469 Console
->InsertMode
= ConsoleInfo
->InsertMode
;
472 * Apply foreground and background colors for both screen and popup
473 * and copy the new palette.
475 ActiveBuffer
->ScreenDefaultAttrib
= ConsoleInfo
->ScreenAttrib
;
476 ActiveBuffer
->PopupDefaultAttrib
= ConsoleInfo
->PopupAttrib
;
477 memcpy(Console
->Colors
, ConsoleInfo
->Colors
, sizeof(s_Colors
)); // FIXME: Possible buffer overflow if s_colors is bigger than pConInfo->Colors.
479 // TODO: Really update the screen attributes as FillConsoleOutputAttribute does.
481 /* Apply cursor size */
482 ActiveBuffer
->CursorInfo
.bVisible
= (ConsoleInfo
->CursorSize
!= 0);
483 ActiveBuffer
->CursorInfo
.dwSize
= min(max(ConsoleInfo
->CursorSize
, 0), 100);
485 /* Resize the console */
486 if (ConsoleInfo
->ConsoleSize
.X
!= Console
->ConsoleSize
.X
||
487 ConsoleInfo
->ConsoleSize
.Y
!= Console
->ConsoleSize
.Y
)
489 Console
->ConsoleSize
= ConsoleInfo
->ConsoleSize
;
493 /* Resize its active screen-buffer */
494 BufSize
= ConsoleInfo
->ScreenBufferSize
;
495 if (BufSize
.X
!= ActiveBuffer
->ScreenBufferSize
.X
||
496 BufSize
.Y
!= ActiveBuffer
->ScreenBufferSize
.Y
)
498 if (NT_SUCCESS(ConioResizeBuffer(Console
, ActiveBuffer
, BufSize
)))
502 if (SizeChanged
) ConioResizeTerminal(Console
);