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