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)
9 /* INCLUDES *******************************************************************/
14 #include "include/conio.h"
15 #include "include/console.h"
21 /* GLOBALS ********************************************************************/
23 HINSTANCE ConSrvDllInstance
= NULL
;
26 HANDLE ConSrvHeap
= NULL
; // Our own heap.
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
] =
36 SrvWriteConsoleOutput
,
37 SrvReadConsoleOutputString
,
38 SrvWriteConsoleOutputString
,
41 // SrvGetConsoleNumberOfFonts,
42 SrvGetConsoleNumberOfInputEvents
,
43 SrvGetConsoleScreenBufferInfo
,
44 SrvGetConsoleCursorInfo
,
45 // SrvGetConsoleMouseInfo,
46 // SrvGetConsoleFontInfo,
47 // SrvGetConsoleFontSize,
48 // SrvGetConsoleCurrentFont,
50 SrvSetConsoleActiveScreenBuffer
,
51 SrvFlushConsoleInputBuffer
,
52 SrvGetLargestConsoleWindowSize
,
53 SrvSetConsoleScreenBufferSize
,
54 SrvSetConsoleCursorPosition
,
55 SrvSetConsoleCursorInfo
,
56 SrvSetConsoleWindowInfo
,
57 SrvScrollConsoleScreenBuffer
,
58 SrvSetConsoleTextAttribute
,
64 // SrvGetHandleInformation,
65 // SrvSetHandleInformation,
67 SrvVerifyConsoleIoHandle
,
72 SrvCreateConsoleScreenBuffer
,
73 SrvInvalidateBitMapRect
,
74 // SrvVDMConsoleOperation,
77 SrvConsoleMenuControl
,
79 SrvSetConsoleDisplayMode
,
80 // SrvRegisterConsoleVDM,
81 SrvGetConsoleHardwareState
,
82 SrvSetConsoleHardwareState
,
83 SrvGetConsoleDisplayMode
,
86 SrvGetConsoleAliasesLength
,
87 SrvGetConsoleAliasExesLength
,
89 SrvGetConsoleAliasExes
,
90 SrvExpungeConsoleCommandHistory
,
91 SrvSetConsoleNumberOfCommands
,
92 SrvGetConsoleCommandHistoryLength
,
93 SrvGetConsoleCommandHistory
,
94 // SrvSetConsoleCommandHistoryMode,
97 // SrvSetConsoleKeyShortcuts,
98 SrvSetConsoleMenuClose
,
99 // SrvConsoleNotifyLastClose,
100 SrvGenerateConsoleCtrlEvent
,
101 // SrvGetConsoleKeyboardLayoutName,
103 // SrvGetConsoleCharType,
104 // SrvSetConsoleLocalEUDC,
105 // SrvSetConsoleCursorMode,
106 // SrvGetConsoleCursorMode,
107 // SrvRegisterConsoleOS2,
108 // SrvSetConsoleOS2OemFormat,
109 // SrvGetConsoleNlsMode,
110 // SrvSetConsoleNlsMode,
111 // SrvRegisterConsoleIME,
112 // SrvUnregisterConsoleIME,
113 // SrvGetConsoleLangId,
115 SrvGetConsoleSelectionInfo
,
116 SrvGetConsoleProcessList
,
117 SrvGetConsoleHistory
,
118 SrvSetConsoleHistory
,
121 BOOLEAN ConsoleServerApiServerValidTable
[ConsolepMaxApiNumber
- CONSRV_FIRST_API_NUMBER
] =
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
212 PCHAR ConsoleServerApiNameTable
[ConsolepMaxApiNumber
- CONSRV_FIRST_API_NUMBER
] =
218 "WriteConsoleOutput",
219 "ReadConsoleOutputString",
220 "WriteConsoleOutputString",
223 // "GetConsoleNumberOfFonts",
224 "GetConsoleNumberOfInputEvents",
225 "GetConsoleScreenBufferInfo",
226 "GetConsoleCursorInfo",
227 // "GetConsoleMouseInfo",
228 // "GetConsoleFontInfo",
229 // "GetConsoleFontSize",
230 // "GetConsoleCurrentFont",
232 "SetConsoleActiveScreenBuffer",
233 "FlushConsoleInputBuffer",
234 "GetLargestConsoleWindowSize",
235 "SetConsoleScreenBufferSize",
236 "SetConsoleCursorPosition",
237 "SetConsoleCursorInfo",
238 "SetConsoleWindowInfo",
239 "ScrollConsoleScreenBuffer",
240 "SetConsoleTextAttribute",
246 // "GetHandleInformation",
247 // "SetHandleInformation",
249 "VerifyConsoleIoHandle",
254 "CreateConsoleScreenBuffer",
255 "InvalidateBitMapRect",
256 // "VDMConsoleOperation",
259 "ConsoleMenuControl",
261 "SetConsoleDisplayMode",
262 // "RegisterConsoleVDM",
263 "GetConsoleHardwareState",
264 "SetConsoleHardwareState",
265 "GetConsoleDisplayMode",
268 "GetConsoleAliasesLength",
269 "GetConsoleAliasExesLength",
271 "GetConsoleAliasExes",
272 "ExpungeConsoleCommandHistory",
273 "SetConsoleNumberOfCommands",
274 "GetConsoleCommandHistoryLength",
275 "GetConsoleCommandHistory",
276 // "SetConsoleCommandHistoryMode",
279 // "SetConsoleKeyShortcuts",
280 "SetConsoleMenuClose",
281 // "ConsoleNotifyLastClose",
282 "GenerateConsoleCtrlEvent",
283 // "GetConsoleKeyboardLayoutName",
285 // "GetConsoleCharType",
286 // "SetConsoleLocalEUDC",
287 // "SetConsoleCursorMode",
288 // "GetConsoleCursorMode",
289 // "RegisterConsoleOS2",
290 // "SetConsoleOS2OemFormat",
291 // "GetConsoleNlsMode",
292 // "SetConsoleNlsMode",
293 // "RegisterConsoleIME",
294 // "UnregisterConsoleIME",
295 // "GetConsoleLangId",
297 "GetConsoleSelectionInfo",
298 "GetConsoleProcessList",
304 /* FUNCTIONS ******************************************************************/
308 ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData
,
309 IN PCONSOLE_PROCESS_DATA TargetProcessData
);
313 ConSrvNewProcess(PCSR_PROCESS SourceProcess
,
314 PCSR_PROCESS TargetProcess
)
316 /**************************************************************************
317 * This function is called whenever a new process (GUI or CUI) is created.
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 **************************************************************************/
328 NTSTATUS Status
= STATUS_SUCCESS
;
329 PCONSOLE_PROCESS_DATA TargetProcessData
;
331 /* An empty target process is invalid */
332 if (!TargetProcess
) return STATUS_INVALID_PARAMETER
;
334 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
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
);
344 * The handles table gets initialized either when inheriting from
345 * another console process, or when creating a new console.
347 TargetProcessData
->HandleTableSize
= 0;
348 TargetProcessData
->HandleTable
= NULL
;
350 RtlInitializeCriticalSection(&TargetProcessData
->HandleTableLock
);
352 /* Do nothing if the source process is NULL */
353 if (!SourceProcess
) return STATUS_SUCCESS
;
355 // SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
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.
363 if (TargetProcessData
->ConsoleApp
/* && SourceProcessData->ConsoleApp */)
365 PCONSOLE_PROCESS_DATA SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
366 PCONSOLE SourceConsole
;
368 /* Validate and lock the parent's console */
369 if (ConDrvValidateConsole(&SourceConsole
,
370 SourceProcessData
->ConsoleHandle
,
371 CONSOLE_RUNNING
, TRUE
))
373 /* Inherit the parent's handles table */
374 Status
= ConSrvInheritHandlesTable(SourceProcessData
, TargetProcessData
);
375 if (NT_SUCCESS(Status
))
377 /* Temporary save the parent's console too */
378 TargetProcessData
->ParentConsoleHandle
= SourceProcessData
->ConsoleHandle
;
381 /* Unlock the parent's console */
382 LeaveCriticalSection(&SourceConsole
->Lock
);
391 ConSrvConnect(IN PCSR_PROCESS CsrProcess
,
392 IN OUT PVOID ConnectionInfo
,
393 IN OUT PULONG ConnectionInfoLength
)
395 /**************************************************************************
396 * This function is called whenever a CUI new process is created.
397 **************************************************************************/
399 NTSTATUS Status
= STATUS_SUCCESS
;
400 PCONSRV_API_CONNECTINFO ConnectInfo
= (PCONSRV_API_CONNECTINFO
)ConnectionInfo
;
401 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
403 if ( ConnectionInfo
== NULL
||
404 ConnectionInfoLength
== NULL
||
405 *ConnectionInfoLength
!= sizeof(CONSRV_API_CONNECTINFO
) )
407 DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), wanted %lu\n",
409 ConnectionInfoLength
,
410 ConnectionInfoLength
? *ConnectionInfoLength
: (ULONG
)-1,
411 sizeof(CONSRV_API_CONNECTINFO
));
412 return STATUS_UNSUCCESSFUL
;
415 /* If we don't need a console, then get out of here */
416 if (!ConnectInfo
->ConsoleStartInfo
.ConsoleNeeded
|| !ProcessData
->ConsoleApp
) // In fact, it is for GUI apps.
418 return STATUS_SUCCESS
;
421 /* If we don't have a console, then create a new one... */
422 if (!ConnectInfo
->ConsoleHandle
||
423 ConnectInfo
->ConsoleHandle
!= ProcessData
->ParentConsoleHandle
)
425 DPRINT("ConSrvConnect - Allocate a new console\n");
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.
434 * ConSrvAllocateConsole will free our old handles table
435 * and recreate a new valid one.
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
))
446 DPRINT1("Console allocation failed\n");
450 else /* We inherit it from the parent */
452 DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
454 /* Reuse our current console */
455 Status
= ConSrvInheritConsole(ProcessData
,
456 ConnectInfo
->ConsoleHandle
,
458 NULL
, // &ConnectInfo->InputHandle,
459 NULL
, // &ConnectInfo->OutputHandle,
460 NULL
); // &ConnectInfo->ErrorHandle);
461 if (!NT_SUCCESS(Status
))
463 DPRINT1("Console inheritance failed\n");
468 /* Return the console handle and the input wait handle to the caller */
469 ConnectInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
470 ConnectInfo
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
472 /* Set the Property-Dialog and Control-Dispatcher handlers */
473 ProcessData
->PropDispatcher
= ConnectInfo
->ConsoleStartInfo
.PropDispatcher
;
474 ProcessData
->CtrlDispatcher
= ConnectInfo
->ConsoleStartInfo
.CtrlDispatcher
;
476 return STATUS_SUCCESS
;
481 ConSrvDisconnect(PCSR_PROCESS Process
)
483 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(Process
);
485 /**************************************************************************
486 * This function is called whenever a new process (GUI or CUI) is destroyed.
487 **************************************************************************/
489 if ( ProcessData
->ConsoleHandle
!= NULL
||
490 ProcessData
->HandleTable
!= NULL
)
492 DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
493 ConSrvRemoveConsole(ProcessData
);
496 RtlDeleteCriticalSection(&ProcessData
->HandleTableLock
);
499 CSR_SERVER_DLL_INIT(ConServerDllInitialization
)
501 /* Initialize the memory */
502 ConSrvHeap
= RtlGetProcessHeap();
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;
514 ConDrvInitConsoleSupport();
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
;
529 ConSrvDllInstance
= LoadedServerDll
->ServerHandle
;
532 return STATUS_SUCCESS
;