Synchronize with trunk revision 59781.
[reactos.git] / 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\n");
408 return STATUS_UNSUCCESSFUL;
409 }
410
411 /* If we don't need a console, then get out of here */
412 if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
413 {
414 return STATUS_SUCCESS;
415 }
416
417 /* If we don't have a console, then create a new one... */
418 if (!ConnectInfo->ConsoleHandle ||
419 ConnectInfo->ConsoleHandle != ProcessData->ParentConsoleHandle)
420 {
421 DPRINT("ConSrvConnect - Allocate a new console\n");
422
423 /*
424 * We are about to create a new console. However when ConSrvNewProcess
425 * was called, we didn't know that we wanted to create a new console and
426 * therefore, we by default inherited the handles table from our parent
427 * process. It's only now that we notice that in fact we do not need
428 * them, because we've created a new console and thus we must use it.
429 *
430 * ConSrvAllocateConsole will free our old handles table
431 * and recreate a new valid one.
432 */
433
434 /* Initialize a new Console owned by the Console Leader Process */
435 Status = ConSrvAllocateConsole(ProcessData,
436 &ConnectInfo->InputHandle,
437 &ConnectInfo->OutputHandle,
438 &ConnectInfo->ErrorHandle,
439 &ConnectInfo->ConsoleStartInfo);
440 if (!NT_SUCCESS(Status))
441 {
442 DPRINT1("Console allocation failed\n");
443 return Status;
444 }
445 }
446 else /* We inherit it from the parent */
447 {
448 DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
449
450 /* Reuse our current console */
451 Status = ConSrvInheritConsole(ProcessData,
452 ConnectInfo->ConsoleHandle,
453 FALSE,
454 NULL, // &ConnectInfo->InputHandle,
455 NULL, // &ConnectInfo->OutputHandle,
456 NULL); // &ConnectInfo->ErrorHandle);
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT1("Console inheritance failed\n");
460 return Status;
461 }
462 }
463
464 /* Return the console handle and the input wait handle to the caller */
465 ConnectInfo->ConsoleHandle = ProcessData->ConsoleHandle;
466 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
467
468 /* Set the Property-Dialog and Control-Dispatcher handlers */
469 ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
470 ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
471
472 return STATUS_SUCCESS;
473 }
474
475 VOID
476 NTAPI
477 ConSrvDisconnect(PCSR_PROCESS Process)
478 {
479 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
480
481 /**************************************************************************
482 * This function is called whenever a new process (GUI or CUI) is destroyed.
483 **************************************************************************/
484
485 if ( ProcessData->ConsoleHandle != NULL ||
486 ProcessData->HandleTable != NULL )
487 {
488 DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
489 ConSrvRemoveConsole(ProcessData);
490 }
491
492 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
493 }
494
495 CSR_SERVER_DLL_INIT(ConServerDllInitialization)
496 {
497 /* Initialize the memory */
498 ConSrvHeap = RtlGetProcessHeap();
499 /*
500 // We can use our own heap instead of the CSR heap to investigate heap corruptions :)
501 ConSrvHeap = RtlCreateHeap(HEAP_GROWABLE |
502 HEAP_PROTECTION_ENABLED |
503 HEAP_FREE_CHECKING_ENABLED |
504 HEAP_TAIL_CHECKING_ENABLED |
505 HEAP_VALIDATE_ALL_ENABLED,
506 NULL, 0, 0, NULL, NULL);
507 if (!ConSrvHeap) return STATUS_NO_MEMORY;
508 */
509
510 ConDrvInitConsoleSupport();
511
512 /* Setup the DLL Object */
513 LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;
514 LoadedServerDll->HighestApiSupported = ConsolepMaxApiNumber;
515 LoadedServerDll->DispatchTable = ConsoleServerApiDispatchTable;
516 LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
517 LoadedServerDll->NameTable = ConsoleServerApiNameTable;
518 LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
519 LoadedServerDll->ConnectCallback = ConSrvConnect;
520 LoadedServerDll->DisconnectCallback = ConSrvDisconnect;
521 LoadedServerDll->NewProcessCallback = ConSrvNewProcess;
522 // LoadedServerDll->HardErrorCallback = ConSrvHardError;
523 LoadedServerDll->ShutdownProcessCallback = NULL;
524
525 ConSrvDllInstance = LoadedServerDll->ServerHandle;
526
527 /* All done */
528 return STATUS_SUCCESS;
529 }
530
531 /* EOF */