1c2c66affSColin Finck /*
2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory
3c2c66affSColin Finck * PROJECT: ReactOS Console Server DLL
4c2c66affSColin Finck * FILE: win32ss/user/winsrv/consrv/frontends/gui/guisettings.c
5c2c66affSColin Finck * PURPOSE: GUI Terminal Front-End Settings Management
6c2c66affSColin Finck * PROGRAMMERS: Johannes Anderwald
7c2c66affSColin Finck * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8c2c66affSColin Finck */
9c2c66affSColin Finck
10c2c66affSColin Finck /* INCLUDES *******************************************************************/
11c2c66affSColin Finck
12c2c66affSColin Finck #include <consrv.h>
13c2c66affSColin Finck
14c2c66affSColin Finck #define NDEBUG
15c2c66affSColin Finck #include <debug.h>
16c2c66affSColin Finck
17c4e2826cSHermès Bélusca-Maïto #include "concfg/font.h"
18c2c66affSColin Finck #include "guiterm.h"
19c2c66affSColin Finck #include "guisettings.h"
20c2c66affSColin Finck
21c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
22c2c66affSColin Finck
23c2c66affSColin Finck BOOL
GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)24c2c66affSColin Finck GuiConsoleReadUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)
25c2c66affSColin Finck {
26c2c66affSColin Finck /* Do nothing */
27c2c66affSColin Finck return TRUE;
28c2c66affSColin Finck }
29c2c66affSColin Finck
30c2c66affSColin Finck BOOL
GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)31c2c66affSColin Finck GuiConsoleWriteUserSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)
32c2c66affSColin Finck {
33c2c66affSColin Finck /* Do nothing */
34c2c66affSColin Finck return TRUE;
35c2c66affSColin Finck }
36c2c66affSColin Finck
37c2c66affSColin Finck VOID
GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)38c2c66affSColin Finck GuiConsoleGetDefaultSettings(IN OUT PGUI_CONSOLE_INFO TermInfo)
39c2c66affSColin Finck {
40c2c66affSColin Finck /* Do nothing */
41c2c66affSColin Finck }
42c2c66affSColin Finck
43c2c66affSColin Finck VOID
GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,BOOL Defaults)44c2c66affSColin Finck GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
45c2c66affSColin Finck BOOL Defaults)
46c2c66affSColin Finck {
47c2c66affSColin Finck NTSTATUS Status;
48c2c66affSColin Finck PCONSRV_CONSOLE Console = GuiData->Console;
49c2c66affSColin Finck PCONSOLE_PROCESS_DATA ProcessData;
50c2c66affSColin Finck HANDLE hSection = NULL, hClientSection = NULL;
51c2c66affSColin Finck PVOID ThreadParameter = NULL; // Is either hClientSection or the console window handle,
52c2c66affSColin Finck // depending on whether we display the default settings or
53c2c66affSColin Finck // the settings of a particular console.
54c2c66affSColin Finck
55c2c66affSColin Finck DPRINT("GuiConsoleShowConsoleProperties entered\n");
56c2c66affSColin Finck
57c2c66affSColin Finck if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
58c2c66affSColin Finck
59c2c66affSColin Finck /* Get the console leader process, our client */
60c2c66affSColin Finck ProcessData = ConSrvGetConsoleLeaderProcess(Console);
61c2c66affSColin Finck
62c2c66affSColin Finck /*
63c2c66affSColin Finck * Be sure we effectively have a properties dialog routine (that launches
64c2c66affSColin Finck * the console control panel applet). It resides in kernel32.dll (client).
65c2c66affSColin Finck */
66c2c66affSColin Finck if (ProcessData->PropRoutine == NULL) goto Quit;
67c2c66affSColin Finck
68c2c66affSColin Finck /*
69c2c66affSColin Finck * Create a memory section to be shared with the console control panel applet
70c2c66affSColin Finck * in the case we are displaying the settings of a particular console.
71c2c66affSColin Finck * In that case the ThreadParameter is the hClientSection handle.
72c2c66affSColin Finck * In the case we display the default console parameters, we don't need to
73c2c66affSColin Finck * create a memory section. We just need to open the applet, and in this case
74c2c66affSColin Finck * the ThreadParameter is the parent window handle of the applet's window,
75c2c66affSColin Finck * that is, the console window.
76c2c66affSColin Finck */
77c2c66affSColin Finck if (!Defaults)
78c2c66affSColin Finck {
79c2c66affSColin Finck PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
80c2c66affSColin Finck LARGE_INTEGER SectionSize;
813323d117STimo Kreuzer SIZE_T ViewSize = 0;
82c2c66affSColin Finck PCONSOLE_STATE_INFO pSharedInfo = NULL;
83c2c66affSColin Finck
84c2c66affSColin Finck /*
85c2c66affSColin Finck * Create a memory section to share with the applet, and map it.
86c2c66affSColin Finck */
87c2c66affSColin Finck SectionSize.QuadPart = sizeof(CONSOLE_STATE_INFO); // Standard size
88c2c66affSColin Finck SectionSize.QuadPart += Console->OriginalTitle.Length; // Add the length in bytes of the console title string
89c2c66affSColin Finck
90c2c66affSColin Finck Status = NtCreateSection(&hSection,
91c2c66affSColin Finck SECTION_ALL_ACCESS,
92c2c66affSColin Finck NULL,
93c2c66affSColin Finck &SectionSize,
94c2c66affSColin Finck PAGE_READWRITE,
95c2c66affSColin Finck SEC_COMMIT,
96c2c66affSColin Finck NULL);
97c2c66affSColin Finck if (!NT_SUCCESS(Status))
98c2c66affSColin Finck {
99c2c66affSColin Finck DPRINT1("Error: Impossible to create a shared section, Status = 0x%08lx\n", Status);
100c2c66affSColin Finck goto Quit;
101c2c66affSColin Finck }
102c2c66affSColin Finck
103c2c66affSColin Finck Status = NtMapViewOfSection(hSection,
104c2c66affSColin Finck NtCurrentProcess(),
105c2c66affSColin Finck (PVOID*)&pSharedInfo,
106c2c66affSColin Finck 0,
107c2c66affSColin Finck 0,
108c2c66affSColin Finck NULL,
109c2c66affSColin Finck &ViewSize,
110c2c66affSColin Finck ViewUnmap,
111c2c66affSColin Finck 0,
112c2c66affSColin Finck PAGE_READWRITE);
113c2c66affSColin Finck if (!NT_SUCCESS(Status))
114c2c66affSColin Finck {
115c2c66affSColin Finck DPRINT1("Error: Impossible to map the shared section, Status = 0x%08lx\n", Status);
116c2c66affSColin Finck goto Quit;
117c2c66affSColin Finck }
118c2c66affSColin Finck
119c2c66affSColin Finck
120c2c66affSColin Finck /*
121c2c66affSColin Finck * Setup the shared console properties structure.
122c2c66affSColin Finck */
123c2c66affSColin Finck
124c2c66affSColin Finck /* Store the real size of the structure */
125c2c66affSColin Finck pSharedInfo->cbSize = SectionSize.QuadPart;
126c2c66affSColin Finck
127c2c66affSColin Finck /*
128c2c66affSColin Finck * When we setup the settings of a particular console, the parent window
129c2c66affSColin Finck * of the applet's window is the console window, and it is given via the
130c2c66affSColin Finck * hWnd member of the shared console info structure.
131c2c66affSColin Finck */
132c2c66affSColin Finck pSharedInfo->hWnd = GuiData->hWindow;
133c2c66affSColin Finck
134c2c66affSColin Finck /* Console information */
135c2c66affSColin Finck pSharedInfo->QuickEdit = Console->QuickEdit;
136c2c66affSColin Finck pSharedInfo->InsertMode = Console->InsertMode;
13719596768SHermès Bélusca-Maïto pSharedInfo->NumberOfHistoryBuffers = Console->MaxNumberOfHistoryBuffers;
13819596768SHermès Bélusca-Maïto pSharedInfo->HistoryBufferSize = Console->HistoryBufferSize;
13919596768SHermès Bélusca-Maïto pSharedInfo->HistoryNoDup = Console->HistoryNoDup;
140c2c66affSColin Finck /// pSharedInfo->InputBufferSize = 0;
141c2c66affSColin Finck pSharedInfo->ScreenBufferSize = ActiveBuffer->ScreenBufferSize;
142c2c66affSColin Finck pSharedInfo->WindowSize = ActiveBuffer->ViewSize;
143c2c66affSColin Finck pSharedInfo->CursorSize = ActiveBuffer->CursorInfo.dwSize;
144c2c66affSColin Finck if (GetType(ActiveBuffer) == TEXTMODE_BUFFER)
145c2c66affSColin Finck {
146c2c66affSColin Finck PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)ActiveBuffer;
147c2c66affSColin Finck
148c2c66affSColin Finck pSharedInfo->ScreenAttributes = Buffer->ScreenDefaultAttrib;
149c2c66affSColin Finck pSharedInfo->PopupAttributes = Buffer->PopupDefaultAttrib;
150c2c66affSColin Finck }
151c2c66affSColin Finck else // if (GetType(ActiveBuffer) == GRAPHICS_BUFFER)
152c2c66affSColin Finck {
153c2c66affSColin Finck // PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)ActiveBuffer;
154c2c66affSColin Finck
155c2c66affSColin Finck // FIXME: Gather defaults from the registry ?
156c2c66affSColin Finck pSharedInfo->ScreenAttributes = DEFAULT_SCREEN_ATTRIB;
157c2c66affSColin Finck pSharedInfo->PopupAttributes = DEFAULT_POPUP_ATTRIB;
158c2c66affSColin Finck }
159c2c66affSColin Finck
160c2c66affSColin Finck /* We display the output code page only */
161c2c66affSColin Finck pSharedInfo->CodePage = Console->OutputCodePage;
162c2c66affSColin Finck
163c2c66affSColin Finck /* GUI Information */
164c2c66affSColin Finck StringCchCopyNW(pSharedInfo->FaceName, ARRAYSIZE(pSharedInfo->FaceName),
165c2c66affSColin Finck GuiData->GuiInfo.FaceName, ARRAYSIZE(GuiData->GuiInfo.FaceName));
1665d3915d0SHermès Bélusca-Maïto pSharedInfo->FontWeight = GuiData->GuiInfo.FontWeight;
167c2c66affSColin Finck pSharedInfo->FontFamily = GuiData->GuiInfo.FontFamily;
168c2c66affSColin Finck pSharedInfo->FontSize = GuiData->GuiInfo.FontSize;
169c2c66affSColin Finck pSharedInfo->FullScreen = GuiData->GuiInfo.FullScreen;
170c2c66affSColin Finck pSharedInfo->AutoPosition = GuiData->GuiInfo.AutoPosition;
171c2c66affSColin Finck pSharedInfo->WindowPosition = GuiData->GuiInfo.WindowOrigin;
172c2c66affSColin Finck
173c2c66affSColin Finck /* Palette */
174c2c66affSColin Finck RtlCopyMemory(pSharedInfo->ColorTable,
175c2c66affSColin Finck Console->Colors, sizeof(Console->Colors));
176c2c66affSColin Finck
177c2c66affSColin Finck /* Copy the original title of the console and null-terminate it */
178c2c66affSColin Finck RtlCopyMemory(pSharedInfo->ConsoleTitle,
179c2c66affSColin Finck Console->OriginalTitle.Buffer,
180c2c66affSColin Finck Console->OriginalTitle.Length);
181c2c66affSColin Finck
182c2c66affSColin Finck pSharedInfo->ConsoleTitle[Console->OriginalTitle.Length / sizeof(WCHAR)] = UNICODE_NULL;
183c2c66affSColin Finck
184c2c66affSColin Finck
185c2c66affSColin Finck /* Unmap the view */
186c2c66affSColin Finck NtUnmapViewOfSection(NtCurrentProcess(), pSharedInfo);
187c2c66affSColin Finck
188c2c66affSColin Finck /* Duplicate the section handle for the client */
189c2c66affSColin Finck Status = NtDuplicateObject(NtCurrentProcess(),
190c2c66affSColin Finck hSection,
191c2c66affSColin Finck ProcessData->Process->ProcessHandle,
192c2c66affSColin Finck &hClientSection,
193c2c66affSColin Finck 0, 0, DUPLICATE_SAME_ACCESS);
194c2c66affSColin Finck if (!NT_SUCCESS(Status))
195c2c66affSColin Finck {
196c2c66affSColin Finck DPRINT1("Error: Impossible to duplicate section handle for client, Status = 0x%08lx\n", Status);
197c2c66affSColin Finck goto Quit;
198c2c66affSColin Finck }
199c2c66affSColin Finck
200c2c66affSColin Finck /* For the settings of a particular console, use the shared client section handle as the thread parameter */
201c2c66affSColin Finck ThreadParameter = (PVOID)hClientSection;
202c2c66affSColin Finck }
203c2c66affSColin Finck else
204c2c66affSColin Finck {
205c2c66affSColin Finck /* For the default settings, use the console window handle as the thread parameter */
206c2c66affSColin Finck ThreadParameter = (PVOID)GuiData->hWindow;
207c2c66affSColin Finck }
208c2c66affSColin Finck
209c2c66affSColin Finck /* Start the console control panel applet */
210c2c66affSColin Finck _SEH2_TRY
211c2c66affSColin Finck {
212c2c66affSColin Finck HANDLE Thread = NULL;
213c2c66affSColin Finck
214c2c66affSColin Finck _SEH2_TRY
215c2c66affSColin Finck {
216c2c66affSColin Finck Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
217c2c66affSColin Finck ProcessData->PropRoutine,
218c2c66affSColin Finck ThreadParameter, 0, NULL);
219c2c66affSColin Finck if (NULL == Thread)
220c2c66affSColin Finck {
221c2c66affSColin Finck DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
222c2c66affSColin Finck }
223c2c66affSColin Finck else
224c2c66affSColin Finck {
225c2c66affSColin Finck DPRINT("ProcessData->PropRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
226c2c66affSColin Finck ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
227c2c66affSColin Finck }
228c2c66affSColin Finck }
229c2c66affSColin Finck _SEH2_FINALLY
230c2c66affSColin Finck {
231c2c66affSColin Finck CloseHandle(Thread);
232c2c66affSColin Finck }
233c2c66affSColin Finck _SEH2_END;
234c2c66affSColin Finck }
235c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
236c2c66affSColin Finck {
237c2c66affSColin Finck Status = _SEH2_GetExceptionCode();
238c2c66affSColin Finck DPRINT1("GuiConsoleShowConsoleProperties - Caught an exception, Status = 0x%08lx\n", Status);
239c2c66affSColin Finck }
240c2c66affSColin Finck _SEH2_END;
241c2c66affSColin Finck
242c2c66affSColin Finck Quit:
243c2c66affSColin Finck /* We have finished, close the section handle if any */
244c2c66affSColin Finck if (hSection) NtClose(hSection);
245c2c66affSColin Finck
246c2c66affSColin Finck LeaveCriticalSection(&Console->Lock);
247c2c66affSColin Finck return;
248c2c66affSColin Finck }
249c2c66affSColin Finck
250c2c66affSColin Finck /*
251c2c66affSColin Finck * Function for dealing with the undocumented message and structure used by
252c2c66affSColin Finck * Windows' console.dll for setting console info.
253*fe11f7a2SKatayama Hirofumi MZ * See https://web.archive.org/web/20220808235525/https://www.catch22.net/assets/files/source/files/setconsoleinfo.c
254*fe11f7a2SKatayama Hirofumi MZ * and https://dl.packetstormsecurity.net/papers/win/MSBugPaper.pdf
255c2c66affSColin Finck * for more information.
256c2c66affSColin Finck */
257c2c66affSColin Finck VOID
GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,HANDLE hClientSection)258c2c66affSColin Finck GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
259c2c66affSColin Finck HANDLE hClientSection)
260c2c66affSColin Finck {
261c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS;
262c2c66affSColin Finck PCONSRV_CONSOLE Console = GuiData->Console;
263c2c66affSColin Finck PCONSOLE_PROCESS_DATA ProcessData;
264c2c66affSColin Finck HANDLE hSection = NULL;
2653323d117STimo Kreuzer SIZE_T ViewSize = 0;
266c2c66affSColin Finck PCONSOLE_STATE_INFO pConInfo = NULL;
267c2c66affSColin Finck
268c2c66affSColin Finck if (!ConDrvValidateConsoleUnsafe((PCONSOLE)Console, CONSOLE_RUNNING, TRUE)) return;
269c2c66affSColin Finck
270c2c66affSColin Finck /* Get the console leader process, our client */
271c2c66affSColin Finck ProcessData = ConSrvGetConsoleLeaderProcess(Console);
272c2c66affSColin Finck
273c2c66affSColin Finck /* Duplicate the section handle for ourselves */
274c2c66affSColin Finck Status = NtDuplicateObject(ProcessData->Process->ProcessHandle,
275c2c66affSColin Finck hClientSection,
276c2c66affSColin Finck NtCurrentProcess(),
277c2c66affSColin Finck &hSection,
278c2c66affSColin Finck 0, 0, DUPLICATE_SAME_ACCESS);
279c2c66affSColin Finck if (!NT_SUCCESS(Status))
280c2c66affSColin Finck {
281c2c66affSColin Finck DPRINT1("Error when mapping client handle, Status = 0x%08lx\n", Status);
282c2c66affSColin Finck goto Quit;
283c2c66affSColin Finck }
284c2c66affSColin Finck
285c2c66affSColin Finck /* Get a view of the shared section */
286c2c66affSColin Finck Status = NtMapViewOfSection(hSection,
287c2c66affSColin Finck NtCurrentProcess(),
288c2c66affSColin Finck (PVOID*)&pConInfo,
289c2c66affSColin Finck 0,
290c2c66affSColin Finck 0,
291c2c66affSColin Finck NULL,
292c2c66affSColin Finck &ViewSize,
293c2c66affSColin Finck ViewUnmap,
294c2c66affSColin Finck 0,
295c2c66affSColin Finck PAGE_READWRITE);
296c2c66affSColin Finck if (!NT_SUCCESS(Status))
297c2c66affSColin Finck {
298c2c66affSColin Finck DPRINT1("Error when mapping view of file, Status = 0x%08lx\n", Status);
299c2c66affSColin Finck goto Quit;
300c2c66affSColin Finck }
301c2c66affSColin Finck
302c2c66affSColin Finck _SEH2_TRY
303c2c66affSColin Finck {
304c2c66affSColin Finck /* Check that the section is well-sized */
305c2c66affSColin Finck if ( (ViewSize < sizeof(CONSOLE_STATE_INFO)) ||
306c2c66affSColin Finck (pConInfo->cbSize < sizeof(CONSOLE_STATE_INFO)) )
307c2c66affSColin Finck {
308c2c66affSColin Finck DPRINT1("Error: section bad-sized: sizeof(Section) < sizeof(CONSOLE_STATE_INFO)\n");
309c2c66affSColin Finck Status = STATUS_INVALID_VIEW_SIZE;
310c2c66affSColin Finck _SEH2_YIELD(goto Quit);
311c2c66affSColin Finck }
312c2c66affSColin Finck
313c2c66affSColin Finck // TODO: Check that GuiData->hWindow == pConInfo->hWnd
314c2c66affSColin Finck
315c2c66affSColin Finck /* Console information */
316c2c66affSColin Finck
317c2c66affSColin Finck /*
318c2c66affSColin Finck * Apply the settings
319c2c66affSColin Finck */
320c2c66affSColin Finck
3215d3915d0SHermès Bélusca-Maïto /* Refresh the additional TrueType fonts cache now,
3225d3915d0SHermès Bélusca-Maïto * as ConSrvApplyUserSettings() could change the output
3235d3915d0SHermès Bélusca-Maïto * code page and trigger a font change in the terminal. */
3245d3915d0SHermès Bélusca-Maïto RefreshTTFontCache();
3255d3915d0SHermès Bélusca-Maïto
3265d3915d0SHermès Bélusca-Maïto /* Apply the generic console settings */
327c2c66affSColin Finck ConSrvApplyUserSettings(Console, pConInfo);
328c2c66affSColin Finck
3295d3915d0SHermès Bélusca-Maïto /* Set the terminal settings */
330c2c66affSColin Finck
3315d3915d0SHermès Bélusca-Maïto /* Now, attempt to change the font to what the user specified */
332c2c66affSColin Finck InitFonts(GuiData,
333c2c66affSColin Finck pConInfo->FaceName,
3345d3915d0SHermès Bélusca-Maïto pConInfo->FontWeight,
335c2c66affSColin Finck pConInfo->FontFamily,
336c2c66affSColin Finck pConInfo->FontSize,
3375d3915d0SHermès Bélusca-Maïto 0, FALSE);
338c2c66affSColin Finck
339c2c66affSColin Finck /* Move the window to the user's values */
340c2c66affSColin Finck GuiData->GuiInfo.AutoPosition = !!pConInfo->AutoPosition;
341c2c66affSColin Finck GuiData->GuiInfo.WindowOrigin = pConInfo->WindowPosition;
342c2c66affSColin Finck GuiConsoleMoveWindow(GuiData);
343c2c66affSColin Finck
344c2c66affSColin Finck InvalidateRect(GuiData->hWindow, NULL, TRUE);
345c2c66affSColin Finck
346c2c66affSColin Finck /*
347c2c66affSColin Finck * Apply full-screen mode.
348c2c66affSColin Finck */
349c2c66affSColin Finck if (!!pConInfo->FullScreen != GuiData->GuiInfo.FullScreen)
350c2c66affSColin Finck {
351c2c66affSColin Finck SwitchFullScreen(GuiData, !!pConInfo->FullScreen);
352c2c66affSColin Finck }
353c2c66affSColin Finck
354c2c66affSColin Finck /*
355c2c66affSColin Finck * The settings are saved in the registry by console.dll itself, if needed.
356c2c66affSColin Finck */
357c2c66affSColin Finck // if (SaveSettings)
358c2c66affSColin Finck // {
359c2c66affSColin Finck // GuiConsoleWriteUserSettings(GuiInfo);
360c2c66affSColin Finck // }
361c2c66affSColin Finck
362c2c66affSColin Finck Status = STATUS_SUCCESS;
363c2c66affSColin Finck }
364c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
365c2c66affSColin Finck {
366c2c66affSColin Finck Status = _SEH2_GetExceptionCode();
367c2c66affSColin Finck DPRINT1("GuiApplyUserSettings - Caught an exception, Status = 0x%08lx\n", Status);
368c2c66affSColin Finck }
369c2c66affSColin Finck _SEH2_END;
370c2c66affSColin Finck
371c2c66affSColin Finck Quit:
372c2c66affSColin Finck /* Finally, close the section and return */
373c2c66affSColin Finck if (hSection)
374c2c66affSColin Finck {
375c2c66affSColin Finck NtUnmapViewOfSection(NtCurrentProcess(), pConInfo);
376c2c66affSColin Finck NtClose(hSection);
377c2c66affSColin Finck }
378c2c66affSColin Finck
379c2c66affSColin Finck LeaveCriticalSection(&Console->Lock);
380c2c66affSColin Finck return;
381c2c66affSColin Finck }
382c2c66affSColin Finck
383c2c66affSColin Finck /* EOF */
384