Sync up with trunk r61578.
[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 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 /*
222 * On Windows Server 2003, CSR Servers contain
223 * the API Names Table only in Debug Builds.
224 */
225 #ifdef CSR_DBG
226 PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
227 {
228 "OpenConsole",
229 "GetConsoleInput",
230 "WriteConsoleInput",
231 "ReadConsoleOutput",
232 "WriteConsoleOutput",
233 "ReadConsoleOutputString",
234 "WriteConsoleOutputString",
235 "FillConsoleOutput",
236 "GetConsoleMode",
237 "GetConsoleNumberOfFonts",
238 "GetConsoleNumberOfInputEvents",
239 "GetConsoleScreenBufferInfo",
240 "GetConsoleCursorInfo",
241 "GetConsoleMouseInfo",
242 "GetConsoleFontInfo",
243 "GetConsoleFontSize",
244 "GetConsoleCurrentFont",
245 "SetConsoleMode",
246 "SetConsoleActiveScreenBuffer",
247 "FlushConsoleInputBuffer",
248 "GetLargestConsoleWindowSize",
249 "SetConsoleScreenBufferSize",
250 "SetConsoleCursorPosition",
251 "SetConsoleCursorInfo",
252 "SetConsoleWindowInfo",
253 "ScrollConsoleScreenBuffer",
254 "SetConsoleTextAttribute",
255 "SetConsoleFont",
256 "SetConsoleIcon",
257 "ReadConsole",
258 "WriteConsole",
259 "DuplicateHandle",
260 "GetHandleInformation",
261 "SetHandleInformation",
262 "CloseHandle",
263 "VerifyConsoleIoHandle",
264 "AllocConsole",
265 "FreeConsole",
266 "GetConsoleTitle",
267 "SetConsoleTitle",
268 "CreateConsoleScreenBuffer",
269 "InvalidateBitMapRect",
270 "VDMConsoleOperation",
271 "SetConsoleCursor",
272 "ShowConsoleCursor",
273 "ConsoleMenuControl",
274 "SetConsolePalette",
275 "SetConsoleDisplayMode",
276 "RegisterConsoleVDM",
277 "GetConsoleHardwareState",
278 "SetConsoleHardwareState",
279 "GetConsoleDisplayMode",
280 "AddConsoleAlias",
281 "GetConsoleAlias",
282 "GetConsoleAliasesLength",
283 "GetConsoleAliasExesLength",
284 "GetConsoleAliases",
285 "GetConsoleAliasExes",
286 "ExpungeConsoleCommandHistory",
287 "SetConsoleNumberOfCommands",
288 "GetConsoleCommandHistoryLength",
289 "GetConsoleCommandHistory",
290 "SetConsoleCommandHistoryMode",
291 "GetConsoleCP",
292 "SetConsoleCP",
293 "SetConsoleKeyShortcuts",
294 "SetConsoleMenuClose",
295 "ConsoleNotifyLastClose",
296 "GenerateConsoleCtrlEvent",
297 "GetConsoleKeyboardLayoutName",
298 "GetConsoleWindow",
299 "GetConsoleCharType",
300 "SetConsoleLocalEUDC",
301 "SetConsoleCursorMode",
302 "GetConsoleCursorMode",
303 "RegisterConsoleOS2",
304 "SetConsoleOS2OemFormat",
305 "GetConsoleNlsMode",
306 "SetConsoleNlsMode",
307 "RegisterConsoleIME",
308 "UnregisterConsoleIME",
309 // "QueryConsoleIME",
310 "GetConsoleLangId",
311 "AttachConsole",
312 "GetConsoleSelectionInfo",
313 "GetConsoleProcessList",
314
315 "GetConsoleHistory",
316 "SetConsoleHistory",
317 // "SetConsoleCurrentFont",
318 // "SetScreenBufferInfo",
319 // "ConsoleClientConnect",
320 };
321 #endif
322
323 /* FUNCTIONS ******************************************************************/
324
325 /* See handle.c */
326 NTSTATUS
327 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
328 IN PCONSOLE_PROCESS_DATA TargetProcessData);
329
330 NTSTATUS
331 NTAPI
332 ConSrvNewProcess(PCSR_PROCESS SourceProcess,
333 PCSR_PROCESS TargetProcess)
334 {
335 /**************************************************************************
336 * This function is called whenever a new process (GUI or CUI) is created.
337 *
338 * Copy the parent's handles table here if both the parent and the child
339 * processes are CUI. If we must actually create our proper console (and
340 * thus do not inherit from the console handles of the parent's), then we
341 * will clean this table in the next ConSrvConnect call. Why we are doing
342 * this? It's because here, we still don't know whether or not we must create
343 * a new console instead of inherit it from the parent, and, because in
344 * ConSrvConnect we don't have any reference to the parent process anymore.
345 **************************************************************************/
346
347 NTSTATUS Status = STATUS_SUCCESS;
348 PCONSOLE_PROCESS_DATA TargetProcessData;
349
350 /* An empty target process is invalid */
351 if (!TargetProcess) return STATUS_INVALID_PARAMETER;
352
353 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
354
355 /* Initialize the new (target) process */
356 RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
357 TargetProcessData->Process = TargetProcess;
358 TargetProcessData->ConsoleEvent = NULL;
359 TargetProcessData->ConsoleHandle = TargetProcessData->ParentConsoleHandle = NULL;
360 TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
361
362 /*
363 * The handles table gets initialized either when inheriting from
364 * another console process, or when creating a new console.
365 */
366 TargetProcessData->HandleTableSize = 0;
367 TargetProcessData->HandleTable = NULL;
368
369 RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
370
371 /* Do nothing if the source process is NULL */
372 if (!SourceProcess) return STATUS_SUCCESS;
373
374 // SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
375
376 /*
377 * If the child process is a console application and the parent process is
378 * either a console application or just has a valid console (with a valid
379 * handles table: this can happen if it is a GUI application having called
380 * AllocConsole), then try to inherit handles from the parent process.
381 */
382 if (TargetProcessData->ConsoleApp /* && SourceProcessData->ConsoleApp */)
383 {
384 PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
385 PCONSOLE SourceConsole;
386
387 /* Validate and lock the parent's console */
388 if (ConDrvValidateConsole(&SourceConsole,
389 SourceProcessData->ConsoleHandle,
390 CONSOLE_RUNNING, TRUE))
391 {
392 /* Inherit the parent's handles table */
393 Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
394 if (NT_SUCCESS(Status))
395 {
396 /* Temporary save the parent's console too */
397 TargetProcessData->ParentConsoleHandle = SourceProcessData->ConsoleHandle;
398 }
399
400 /* Unlock the parent's console */
401 LeaveCriticalSection(&SourceConsole->Lock);
402 }
403 }
404
405 return Status;
406 }
407
408 NTSTATUS
409 NTAPI
410 ConSrvConnect(IN PCSR_PROCESS CsrProcess,
411 IN OUT PVOID ConnectionInfo,
412 IN OUT PULONG ConnectionInfoLength)
413 {
414 /**************************************************************************
415 * This function is called whenever a CUI new process is created.
416 **************************************************************************/
417
418 NTSTATUS Status = STATUS_SUCCESS;
419 PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo;
420 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
421
422 if ( ConnectionInfo == NULL ||
423 ConnectionInfoLength == NULL ||
424 *ConnectionInfoLength != sizeof(CONSRV_API_CONNECTINFO) )
425 {
426 DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), wanted %lu\n",
427 ConnectionInfo,
428 ConnectionInfoLength,
429 ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1,
430 sizeof(CONSRV_API_CONNECTINFO));
431 return STATUS_UNSUCCESSFUL;
432 }
433
434 /* If we don't need a console, then get out of here */
435 if (!ConnectInfo->ConsoleStartInfo.ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
436 {
437 return STATUS_SUCCESS;
438 }
439
440 /* If we don't have a console, then create a new one... */
441 if (!ConnectInfo->ConsoleHandle ||
442 ConnectInfo->ConsoleHandle != ProcessData->ParentConsoleHandle)
443 {
444 DPRINT("ConSrvConnect - Allocate a new console\n");
445
446 /*
447 * We are about to create a new console. However when ConSrvNewProcess
448 * was called, we didn't know that we wanted to create a new console and
449 * therefore, we by default inherited the handles table from our parent
450 * process. It's only now that we notice that in fact we do not need
451 * them, because we've created a new console and thus we must use it.
452 *
453 * ConSrvAllocateConsole will free our old handles table
454 * and recreate a new valid one.
455 */
456
457 /* Initialize a new Console owned by the Console Leader Process */
458 Status = ConSrvAllocateConsole(ProcessData,
459 &ConnectInfo->InputHandle,
460 &ConnectInfo->OutputHandle,
461 &ConnectInfo->ErrorHandle,
462 &ConnectInfo->ConsoleStartInfo);
463 if (!NT_SUCCESS(Status))
464 {
465 DPRINT1("Console allocation failed\n");
466 return Status;
467 }
468 }
469 else /* We inherit it from the parent */
470 {
471 DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
472
473 /* Reuse our current console */
474 Status = ConSrvInheritConsole(ProcessData,
475 ConnectInfo->ConsoleHandle,
476 FALSE,
477 NULL, // &ConnectInfo->InputHandle,
478 NULL, // &ConnectInfo->OutputHandle,
479 NULL); // &ConnectInfo->ErrorHandle);
480 if (!NT_SUCCESS(Status))
481 {
482 DPRINT1("Console inheritance failed\n");
483 return Status;
484 }
485 }
486
487 /* Return the console handle and the input wait handle to the caller */
488 ConnectInfo->ConsoleHandle = ProcessData->ConsoleHandle;
489 ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
490
491 /* Set the Property-Dialog and Control-Dispatcher handlers */
492 ProcessData->PropDispatcher = ConnectInfo->ConsoleStartInfo.PropDispatcher;
493 ProcessData->CtrlDispatcher = ConnectInfo->ConsoleStartInfo.CtrlDispatcher;
494
495 return STATUS_SUCCESS;
496 }
497
498 VOID
499 NTAPI
500 ConSrvDisconnect(PCSR_PROCESS Process)
501 {
502 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
503
504 /**************************************************************************
505 * This function is called whenever a new process (GUI or CUI) is destroyed.
506 **************************************************************************/
507
508 if ( ProcessData->ConsoleHandle != NULL ||
509 ProcessData->HandleTable != NULL )
510 {
511 DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
512 ConSrvRemoveConsole(ProcessData);
513 }
514
515 RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
516 }
517
518 CSR_SERVER_DLL_INIT(ConServerDllInitialization)
519 {
520 /* Initialize the memory */
521 ConSrvHeap = RtlGetProcessHeap();
522 /*
523 // We can use our own heap instead of the CSR heap to investigate heap corruptions :)
524 ConSrvHeap = RtlCreateHeap(HEAP_GROWABLE |
525 HEAP_PROTECTION_ENABLED |
526 HEAP_FREE_CHECKING_ENABLED |
527 HEAP_TAIL_CHECKING_ENABLED |
528 HEAP_VALIDATE_ALL_ENABLED,
529 NULL, 0, 0, NULL, NULL);
530 if (!ConSrvHeap) return STATUS_NO_MEMORY;
531 */
532
533 ConDrvInitConsoleSupport();
534
535 /* Setup the DLL Object */
536 LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;
537 LoadedServerDll->HighestApiSupported = ConsolepMaxApiNumber;
538 LoadedServerDll->DispatchTable = ConsoleServerApiDispatchTable;
539 LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
540 #ifdef CSR_DBG
541 LoadedServerDll->NameTable = ConsoleServerApiNameTable;
542 #endif
543 LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
544 LoadedServerDll->ConnectCallback = ConSrvConnect;
545 LoadedServerDll->DisconnectCallback = ConSrvDisconnect;
546 LoadedServerDll->NewProcessCallback = ConSrvNewProcess;
547 // LoadedServerDll->HardErrorCallback = ConSrvHardError;
548 LoadedServerDll->ShutdownProcessCallback = NULL;
549
550 ConSrvDllInstance = LoadedServerDll->ServerHandle;
551
552 /* All done */
553 return STATUS_SUCCESS;
554 }
555
556 /* EOF */