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