10522953f39160959a8c3b4a9246c136b9f015c5
[reactos.git] / reactos / win32ss / user / winsrv / consrv / init.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/init.c
5 * PURPOSE: Initialization
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "consrv.h"
12 #include "api.h"
13 #include "procinit.h"
14 #include "include/conio.h"
15 #include "include/console.h"
16 #include "console.h"
17
18 #define NDEBUG
19 #include <debug.h>
20
21 /* GLOBALS ********************************************************************/
22
23 HINSTANCE ConSrvDllInstance = NULL;
24
25 /* Memory */
26 HANDLE ConSrvHeap = NULL; // Our own heap.
27
28 // Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3
29 PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
30 {
31 SrvOpenConsole,
32 SrvGetConsoleInput,
33 SrvWriteConsoleInput,
34 SrvReadConsoleOutput,
35 SrvWriteConsoleOutput,
36 SrvReadConsoleOutputString,
37 SrvWriteConsoleOutputString,
38 SrvFillConsoleOutput,
39 SrvGetConsoleMode,
40 SrvGetConsoleNumberOfFonts,
41 SrvGetConsoleNumberOfInputEvents,
42 SrvGetConsoleScreenBufferInfo,
43 SrvGetConsoleCursorInfo,
44 SrvGetConsoleMouseInfo,
45 SrvGetConsoleFontInfo,
46 SrvGetConsoleFontSize,
47 SrvGetConsoleCurrentFont,
48 SrvSetConsoleMode,
49 SrvSetConsoleActiveScreenBuffer,
50 SrvFlushConsoleInputBuffer,
51 SrvGetLargestConsoleWindowSize,
52 SrvSetConsoleScreenBufferSize,
53 SrvSetConsoleCursorPosition,
54 SrvSetConsoleCursorInfo,
55 SrvSetConsoleWindowInfo,
56 SrvScrollConsoleScreenBuffer,
57 SrvSetConsoleTextAttribute,
58 SrvSetConsoleFont,
59 SrvSetConsoleIcon,
60 SrvReadConsole,
61 SrvWriteConsole,
62 SrvDuplicateHandle,
63 SrvGetHandleInformation,
64 SrvSetHandleInformation,
65 SrvCloseHandle,
66 SrvVerifyConsoleIoHandle,
67 SrvAllocConsole, // Not present in Win7
68 SrvFreeConsole, // Not present in Win7
69 SrvGetConsoleTitle,
70 SrvSetConsoleTitle,
71 SrvCreateConsoleScreenBuffer,
72 SrvInvalidateBitMapRect,
73 SrvVDMConsoleOperation,
74 SrvSetConsoleCursor,
75 SrvShowConsoleCursor,
76 SrvConsoleMenuControl,
77 SrvSetConsolePalette,
78 SrvSetConsoleDisplayMode,
79 SrvRegisterConsoleVDM,
80 SrvGetConsoleHardwareState,
81 SrvSetConsoleHardwareState,
82 SrvGetConsoleDisplayMode,
83 SrvAddConsoleAlias,
84 SrvGetConsoleAlias,
85 SrvGetConsoleAliasesLength,
86 SrvGetConsoleAliasExesLength,
87 SrvGetConsoleAliases,
88 SrvGetConsoleAliasExes,
89 SrvExpungeConsoleCommandHistory,
90 SrvSetConsoleNumberOfCommands,
91 SrvGetConsoleCommandHistoryLength,
92 SrvGetConsoleCommandHistory,
93 SrvSetConsoleCommandHistoryMode, // Not present in Vista+
94 SrvGetConsoleCP,
95 SrvSetConsoleCP,
96 SrvSetConsoleKeyShortcuts,
97 SrvSetConsoleMenuClose,
98 SrvConsoleNotifyLastClose,
99 SrvGenerateConsoleCtrlEvent,
100 SrvGetConsoleKeyboardLayoutName,
101 SrvGetConsoleWindow,
102 SrvGetConsoleCharType,
103 SrvSetConsoleLocalEUDC,
104 SrvSetConsoleCursorMode,
105 SrvGetConsoleCursorMode,
106 SrvRegisterConsoleOS2,
107 SrvSetConsoleOS2OemFormat,
108 SrvGetConsoleNlsMode,
109 SrvSetConsoleNlsMode,
110 SrvRegisterConsoleIME, // Not present in Win7
111 SrvUnregisterConsoleIME, // Not present in Win7
112 // SrvQueryConsoleIME, // Added only in Vista and Win2k8, not present in Win7
113 SrvGetConsoleLangId,
114 SrvAttachConsole, // Not present in Win7
115 SrvGetConsoleSelectionInfo,
116 SrvGetConsoleProcessList,
117
118 SrvGetConsoleHistory, // Added in Vista+
119 SrvSetConsoleHistory, // Added in Vista+
120 // SrvSetConsoleCurrentFont, // Added in Vista+
121 // SrvSetScreenBufferInfo, // Added in Vista+
122 // SrvConsoleClientConnect, // Added in Win7
123 };
124
125 BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
126 {
127 FALSE, // SrvOpenConsole,
128 FALSE, // SrvGetConsoleInput,
129 FALSE, // SrvWriteConsoleInput,
130 FALSE, // SrvReadConsoleOutput,
131 FALSE, // SrvWriteConsoleOutput,
132 FALSE, // SrvReadConsoleOutputString,
133 FALSE, // SrvWriteConsoleOutputString,
134 FALSE, // SrvFillConsoleOutput,
135 FALSE, // SrvGetConsoleMode,
136 FALSE, // SrvGetConsoleNumberOfFonts,
137 FALSE, // SrvGetConsoleNumberOfInputEvents,
138 FALSE, // SrvGetConsoleScreenBufferInfo,
139 FALSE, // SrvGetConsoleCursorInfo,
140 FALSE, // SrvGetConsoleMouseInfo,
141 FALSE, // SrvGetConsoleFontInfo,
142 FALSE, // SrvGetConsoleFontSize,
143 FALSE, // SrvGetConsoleCurrentFont,
144 FALSE, // SrvSetConsoleMode,
145 FALSE, // SrvSetConsoleActiveScreenBuffer,
146 FALSE, // SrvFlushConsoleInputBuffer,
147 FALSE, // SrvGetLargestConsoleWindowSize,
148 FALSE, // SrvSetConsoleScreenBufferSize,
149 FALSE, // SrvSetConsoleCursorPosition,
150 FALSE, // SrvSetConsoleCursorInfo,
151 FALSE, // SrvSetConsoleWindowInfo,
152 FALSE, // SrvScrollConsoleScreenBuffer,
153 FALSE, // SrvSetConsoleTextAttribute,
154 FALSE, // SrvSetConsoleFont,
155 FALSE, // SrvSetConsoleIcon,
156 FALSE, // SrvReadConsole,
157 FALSE, // SrvWriteConsole,
158 FALSE, // SrvDuplicateHandle,
159 FALSE, // SrvGetHandleInformation,
160 FALSE, // SrvSetHandleInformation,
161 FALSE, // SrvCloseHandle,
162 FALSE, // SrvVerifyConsoleIoHandle,
163 FALSE, // SrvAllocConsole,
164 FALSE, // SrvFreeConsole,
165 FALSE, // SrvGetConsoleTitle,
166 FALSE, // SrvSetConsoleTitle,
167 FALSE, // SrvCreateConsoleScreenBuffer,
168 FALSE, // SrvInvalidateBitMapRect,
169 FALSE, // SrvVDMConsoleOperation,
170 FALSE, // SrvSetConsoleCursor,
171 FALSE, // SrvShowConsoleCursor,
172 FALSE, // SrvConsoleMenuControl,
173 FALSE, // SrvSetConsolePalette,
174 FALSE, // SrvSetConsoleDisplayMode,
175 FALSE, // SrvRegisterConsoleVDM,
176 FALSE, // SrvGetConsoleHardwareState,
177 FALSE, // SrvSetConsoleHardwareState,
178 TRUE, // SrvGetConsoleDisplayMode,
179 FALSE, // SrvAddConsoleAlias,
180 FALSE, // SrvGetConsoleAlias,
181 FALSE, // SrvGetConsoleAliasesLength,
182 FALSE, // SrvGetConsoleAliasExesLength,
183 FALSE, // SrvGetConsoleAliases,
184 FALSE, // SrvGetConsoleAliasExes,
185 FALSE, // SrvExpungeConsoleCommandHistory,
186 FALSE, // SrvSetConsoleNumberOfCommands,
187 FALSE, // SrvGetConsoleCommandHistoryLength,
188 FALSE, // SrvGetConsoleCommandHistory,
189 FALSE, // SrvSetConsoleCommandHistoryMode,
190 FALSE, // SrvGetConsoleCP,
191 FALSE, // SrvSetConsoleCP,
192 FALSE, // SrvSetConsoleKeyShortcuts,
193 FALSE, // SrvSetConsoleMenuClose,
194 FALSE, // SrvConsoleNotifyLastClose,
195 FALSE, // SrvGenerateConsoleCtrlEvent,
196 FALSE, // SrvGetConsoleKeyboardLayoutName,
197 FALSE, // SrvGetConsoleWindow,
198 FALSE, // SrvGetConsoleCharType,
199 FALSE, // SrvSetConsoleLocalEUDC,
200 FALSE, // SrvSetConsoleCursorMode,
201 FALSE, // SrvGetConsoleCursorMode,
202 FALSE, // SrvRegisterConsoleOS2,
203 FALSE, // SrvSetConsoleOS2OemFormat,
204 FALSE, // SrvGetConsoleNlsMode,
205 FALSE, // SrvSetConsoleNlsMode,
206 FALSE, // SrvRegisterConsoleIME,
207 FALSE, // SrvUnregisterConsoleIME,
208 // FALSE, // SrvQueryConsoleIME,
209 FALSE, // SrvGetConsoleLangId,
210 FALSE, // SrvAttachConsole,
211 FALSE, // SrvGetConsoleSelectionInfo,
212 FALSE, // SrvGetConsoleProcessList,
213
214 FALSE, // SrvGetConsoleHistory,
215 FALSE, // SrvSetConsoleHistory
216 // FALSE, // SrvSetConsoleCurrentFont,
217 // FALSE, // SrvSetScreenBufferInfo,
218 // FALSE, // SrvConsoleClientConnect,
219 };
220
221 PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
222 {
223 "OpenConsole",
224 "GetConsoleInput",
225 "WriteConsoleInput",
226 "ReadConsoleOutput",
227 "WriteConsoleOutput",
228 "ReadConsoleOutputString",
229 "WriteConsoleOutputString",
230 "FillConsoleOutput",
231 "GetConsoleMode",
232 "GetConsoleNumberOfFonts",
233 "GetConsoleNumberOfInputEvents",
234 "GetConsoleScreenBufferInfo",
235 "GetConsoleCursorInfo",
236 "GetConsoleMouseInfo",
237 "GetConsoleFontInfo",
238 "GetConsoleFontSize",
239 "GetConsoleCurrentFont",
240 "SetConsoleMode",
241 "SetConsoleActiveScreenBuffer",
242 "FlushConsoleInputBuffer",
243 "GetLargestConsoleWindowSize",
244 "SetConsoleScreenBufferSize",
245 "SetConsoleCursorPosition",
246 "SetConsoleCursorInfo",
247 "SetConsoleWindowInfo",
248 "ScrollConsoleScreenBuffer",
249 "SetConsoleTextAttribute",
250 "SetConsoleFont",
251 "SetConsoleIcon",
252 "ReadConsole",
253 "WriteConsole",
254 "DuplicateHandle",
255 "GetHandleInformation",
256 "SetHandleInformation",
257 "CloseHandle",
258 "VerifyConsoleIoHandle",
259 "AllocConsole",
260 "FreeConsole",
261 "GetConsoleTitle",
262 "SetConsoleTitle",
263 "CreateConsoleScreenBuffer",
264 "InvalidateBitMapRect",
265 "VDMConsoleOperation",
266 "SetConsoleCursor",
267 "ShowConsoleCursor",
268 "ConsoleMenuControl",
269 "SetConsolePalette",
270 "SetConsoleDisplayMode",
271 "RegisterConsoleVDM",
272 "GetConsoleHardwareState",
273 "SetConsoleHardwareState",
274 "GetConsoleDisplayMode",
275 "AddConsoleAlias",
276 "GetConsoleAlias",
277 "GetConsoleAliasesLength",
278 "GetConsoleAliasExesLength",
279 "GetConsoleAliases",
280 "GetConsoleAliasExes",
281 "ExpungeConsoleCommandHistory",
282 "SetConsoleNumberOfCommands",
283 "GetConsoleCommandHistoryLength",
284 "GetConsoleCommandHistory",
285 "SetConsoleCommandHistoryMode",
286 "GetConsoleCP",
287 "SetConsoleCP",
288 "SetConsoleKeyShortcuts",
289 "SetConsoleMenuClose",
290 "ConsoleNotifyLastClose",
291 "GenerateConsoleCtrlEvent",
292 "GetConsoleKeyboardLayoutName",
293 "GetConsoleWindow",
294 "GetConsoleCharType",
295 "SetConsoleLocalEUDC",
296 "SetConsoleCursorMode",
297 "GetConsoleCursorMode",
298 "RegisterConsoleOS2",
299 "SetConsoleOS2OemFormat",
300 "GetConsoleNlsMode",
301 "SetConsoleNlsMode",
302 "RegisterConsoleIME",
303 "UnregisterConsoleIME",
304 // "QueryConsoleIME",
305 "GetConsoleLangId",
306 "AttachConsole",
307 "GetConsoleSelectionInfo",
308 "GetConsoleProcessList",
309
310 "GetConsoleHistory",
311 "SetConsoleHistory",
312 // "SetConsoleCurrentFont",
313 // "SetScreenBufferInfo",
314 // "ConsoleClientConnect",
315 };
316
317
318 /* FUNCTIONS ******************************************************************/
319
320 /* See handle.c */
321 NTSTATUS
322 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
323 IN PCONSOLE_PROCESS_DATA TargetProcessData);
324
325 NTSTATUS
326 NTAPI
327 ConSrvNewProcess(PCSR_PROCESS SourceProcess,
328 PCSR_PROCESS TargetProcess)
329 {
330 /**************************************************************************
331 * This function is called whenever a new process (GUI or CUI) is created.
332 *
333 * Copy the parent's handles table here if both the parent and the child
334 * processes are CUI. If we must actually create our proper console (and
335 * thus do not inherit from the console handles of the parent's), then we
336 * will clean this table in the next ConSrvConnect call. Why we are doing
337 * this? It's because here, we still don't know whether or not we must create
338 * a new console instead of inherit it from the parent, and, because in
339 * ConSrvConnect we don't have any reference to the parent process anymore.
340 **************************************************************************/
341
342 NTSTATUS Status = STATUS_SUCCESS;
343 PCONSOLE_PROCESS_DATA TargetProcessData;
344
345 /* An empty target process is invalid */
346 if (!TargetProcess) return STATUS_INVALID_PARAMETER;
347
348 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
349
350 /* Initialize the new (target) process */
351 RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
352 TargetProcessData->Process = TargetProcess;
353 TargetProcessData->ConsoleEvent = NULL;
354 TargetProcessData->ConsoleHandle = TargetProcessData->ParentConsoleHandle = NULL;
355 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
356
357 /*
358 * The handles table gets initialized either when inheriting from
359 * another console process, or when creating a new console.
360 */
361 TargetProcessData->HandleTableSize = 0;
362 TargetProcessData->HandleTable = NULL;
363
364 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
365
366 /* Do nothing if the source process is NULL */
367 if (!SourceProcess) return STATUS_SUCCESS;
368
369 // SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
370
371 /*
372 * If the child process is a console application and the parent process is
373 * either a console application or just has a valid console (with a valid
374 * handles table: this can happen if it is a GUI application having called
375 * AllocConsole), then try to inherit handles from the parent process.
376 */
377 if (TargetProcessData->ConsoleApp /* && SourceProcessData->ConsoleApp */)
378 {
379 PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
380 PCONSOLE SourceConsole;
381
382 /* Validate and lock the parent's console */
383 if (ConDrvValidateConsole(&SourceConsole,
384 SourceProcessData->ConsoleHandle,
385 CONSOLE_RUNNING, TRUE))
386 {
387 /* Inherit the parent's handles table */
388 Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
389 if (NT_SUCCESS(Status))
390 {
391 /* Temporary save the parent's console too */
392 TargetProcessData->ParentConsoleHandle = SourceProcessData->ConsoleHandle;
393 }
394
395 /* Unlock the parent's console */
396 LeaveCriticalSection(&SourceConsole->Lock);
397 }
398 }
399
400 return Status;
401 }
402
403 NTSTATUS
404 NTAPI
405 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
406 IN OUT PVOID ConnectionInfo,
407 IN OUT PULONG ConnectionInfoLength)
408 {
409 /**************************************************************************
410 * This function is called whenever a CUI new process is created.
411 **************************************************************************/
412
413 NTSTATUS Status = STATUS_SUCCESS;
414 PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo;
415 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
416
417 if ( ConnectionInfo == NULL ||
418 ConnectionInfoLength == NULL ||
419 *ConnectionInfoLength != sizeof(CONSRV_API_CONNECTINFO) )
420 {
421 DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), wanted %lu\n",
422 ConnectionInfo,
423 ConnectionInfoLength,
424 ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1,
425 sizeof(CONSRV_API_CONNECTINFO));
426 return STATUS_UNSUCCESSFUL;
427 }
428
429 /* If we don't need a console, then get out of here */
430 if (!ConnectInfo->ConsoleStartInfo.ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
431 {
432 return STATUS_SUCCESS;
433 }
434
435 /* If we don't have a console, then create a new one... */
436 if (!ConnectInfo->ConsoleHandle ||
437 ConnectInfo->ConsoleHandle != ProcessData->ParentConsoleHandle)
438 {
439 DPRINT("ConSrvConnect - Allocate a new console\n");
440
441 /*
442 * We are about to create a new console. However when ConSrvNewProcess
443 * was called, we didn't know that we wanted to create a new console and
444 * therefore, we by default inherited the handles table from our parent
445 * process. It's only now that we notice that in fact we do not need
446 * them, because we've created a new console and thus we must use it.
447 *
448 * ConSrvAllocateConsole will free our old handles table
449 * and recreate a new valid one.
450 */
451
452 /* Initialize a new Console owned by the Console Leader Process */
453 Status = ConSrvAllocateConsole(ProcessData,
454 &ConnectInfo->InputHandle,
455 &ConnectInfo->OutputHandle,
456 &ConnectInfo->ErrorHandle,
457 &ConnectInfo->ConsoleStartInfo);
458 if (!NT_SUCCESS(Status))
459 {
460 DPRINT1("Console allocation failed\n");
461 return Status;
462 }
463 }
464 else /* We inherit it from the parent */
465 {
466 DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
467
468 /* Reuse our current console */
469 Status = ConSrvInheritConsole(ProcessData,
470 ConnectInfo->ConsoleHandle,
471 FALSE,
472 NULL, // &ConnectInfo->InputHandle,
473 NULL, // &ConnectInfo->OutputHandle,
474 NULL); // &ConnectInfo->ErrorHandle);
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("Console inheritance failed\n");
478 return Status;
479 }
480 }
481
482 /* Return the console handle and the input wait handle to the caller */
483 ConnectInfo->ConsoleHandle = ProcessData->ConsoleHandle;
484 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
485
486 /* Set the Property-Dialog and Control-Dispatcher handlers */
487 ProcessData->PropDispatcher = ConnectInfo->ConsoleStartInfo.PropDispatcher;
488 ProcessData->CtrlDispatcher = ConnectInfo->ConsoleStartInfo.CtrlDispatcher;
489
490 return STATUS_SUCCESS;
491 }
492
493 VOID
494 NTAPI
495 ConSrvDisconnect(PCSR_PROCESS Process)
496 {
497 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
498
499 /**************************************************************************
500 * This function is called whenever a new process (GUI or CUI) is destroyed.
501 **************************************************************************/
502
503 if ( ProcessData->ConsoleHandle != NULL ||
504 ProcessData->HandleTable != NULL )
505 {
506 DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
507 ConSrvRemoveConsole(ProcessData);
508 }
509
510 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
511 }
512
513 CSR_SERVER_DLL_INIT(ConServerDllInitialization)
514 {
515 /* Initialize the memory */
516 ConSrvHeap = RtlGetProcessHeap();
517 /*
518 // We can use our own heap instead of the CSR heap to investigate heap corruptions :)
519 ConSrvHeap = RtlCreateHeap(HEAP_GROWABLE |
520 HEAP_PROTECTION_ENABLED |
521 HEAP_FREE_CHECKING_ENABLED |
522 HEAP_TAIL_CHECKING_ENABLED |
523 HEAP_VALIDATE_ALL_ENABLED,
524 NULL, 0, 0, NULL, NULL);
525 if (!ConSrvHeap) return STATUS_NO_MEMORY;
526 */
527
528 ConDrvInitConsoleSupport();
529
530 /* Setup the DLL Object */
531 LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;
532 LoadedServerDll->HighestApiSupported = ConsolepMaxApiNumber;
533 LoadedServerDll->DispatchTable = ConsoleServerApiDispatchTable;
534 LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
535 LoadedServerDll->NameTable = ConsoleServerApiNameTable;
536 LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
537 LoadedServerDll->ConnectCallback = ConSrvConnect;
538 LoadedServerDll->DisconnectCallback = ConSrvDisconnect;
539 LoadedServerDll->NewProcessCallback = ConSrvNewProcess;
540 // LoadedServerDll->HardErrorCallback = ConSrvHardError;
541 LoadedServerDll->ShutdownProcessCallback = NULL;
542
543 ConSrvDllInstance = LoadedServerDll->ServerHandle;
544
545 /* All done */
546 return STATUS_SUCCESS;
547 }
548
549 /* EOF */