[CONSRV]
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / guiterm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
5 * PURPOSE: GUI Terminal Front-End
6 * PROGRAMMERS: Gé van Geldorp
7 * Johannes Anderwald
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <consrv.h>
15
16 #define COBJMACROS
17 #include <shlobj.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 #include "guiterm.h"
23 #include "resource.h"
24
25 // HACK!! Remove it when the hack in GuiWriteStream is fixed
26 #define CONGUI_UPDATE_TIME 0
27 #define CONGUI_UPDATE_TIMER 1
28
29 #define PM_CREATE_CONSOLE (WM_APP + 1)
30 #define PM_DESTROY_CONSOLE (WM_APP + 2)
31
32
33 /* Not defined in any header file */
34 extern VOID NTAPI PrivateCsrssManualGuiCheck(LONG Check);
35 // See winsrv/usersrv/init.c line 234
36
37
38 /* GLOBALS ********************************************************************/
39
40 typedef struct _GUI_INIT_INFO
41 {
42 PCONSOLE_INFO ConsoleInfo;
43 PCONSOLE_START_INFO ConsoleStartInfo;
44 ULONG ProcessId;
45 } GUI_INIT_INFO, *PGUI_INIT_INFO;
46
47 static BOOL ConsInitialized = FALSE;
48 static HWND NotifyWnd = NULL;
49
50 extern HICON ghDefaultIcon;
51 extern HICON ghDefaultIconSm;
52 extern HCURSOR ghDefaultCursor;
53
54 VOID
55 SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData);
56 BOOLEAN
57 RegisterConWndClass(IN HINSTANCE hInstance);
58 BOOLEAN
59 UnRegisterConWndClass(HINSTANCE hInstance);
60
61 /* FUNCTIONS ******************************************************************/
62
63 static VOID
64 GetScreenBufferSizeUnits(IN PCONSOLE_SCREEN_BUFFER Buffer,
65 IN PGUI_CONSOLE_DATA GuiData,
66 OUT PUINT WidthUnit,
67 OUT PUINT HeightUnit)
68 {
69 if (Buffer == NULL || GuiData == NULL ||
70 WidthUnit == NULL || HeightUnit == NULL)
71 {
72 return;
73 }
74
75 if (GetType(Buffer) == TEXTMODE_BUFFER)
76 {
77 *WidthUnit = GuiData->CharWidth ;
78 *HeightUnit = GuiData->CharHeight;
79 }
80 else /* if (GetType(Buffer) == GRAPHICS_BUFFER) */
81 {
82 *WidthUnit = 1;
83 *HeightUnit = 1;
84 }
85 }
86
87 VOID
88 GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData)
89 {
90 /* Move the window if needed (not positioned by the system) */
91 if (!GuiData->GuiInfo.AutoPosition)
92 {
93 SetWindowPos(GuiData->hWindow,
94 NULL,
95 GuiData->GuiInfo.WindowOrigin.x,
96 GuiData->GuiInfo.WindowOrigin.y,
97 0, 0,
98 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
99 }
100 }
101
102 static VOID
103 SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
104 {
105 PCONSOLE_SCREEN_BUFFER Buffer = GuiData->ActiveBuffer;
106 UINT WidthUnit, HeightUnit;
107
108 GetScreenBufferSizeUnits(Buffer, GuiData, &WidthUnit, &HeightUnit);
109
110 Rect->left = (SmallRect->Left - Buffer->ViewOrigin.X) * WidthUnit ;
111 Rect->top = (SmallRect->Top - Buffer->ViewOrigin.Y) * HeightUnit;
112 Rect->right = (SmallRect->Right + 1 - Buffer->ViewOrigin.X) * WidthUnit ;
113 Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
114 }
115
116 static VOID
117 DrawRegion(PGUI_CONSOLE_DATA GuiData,
118 SMALL_RECT* Region)
119 {
120 RECT RegionRect;
121
122 SmallRectToRect(GuiData, &RegionRect, Region);
123 /* Do not erase the background: it speeds up redrawing and reduce flickering */
124 InvalidateRect(GuiData->hWindow, &RegionRect, FALSE);
125 /**UpdateWindow(GuiData->hWindow);**/
126 }
127
128 VOID
129 InvalidateCell(PGUI_CONSOLE_DATA GuiData,
130 SHORT x, SHORT y)
131 {
132 SMALL_RECT CellRect = { x, y, x, y };
133 DrawRegion(GuiData, &CellRect);
134 }
135
136
137 /******************************************************************************
138 * GUI Terminal Initialization *
139 ******************************************************************************/
140
141 VOID
142 SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
143
144 static LRESULT CALLBACK
145 GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
146 {
147 HWND NewWindow;
148 LONG WindowCount;
149 MSG Msg;
150
151 switch (msg)
152 {
153 case WM_CREATE:
154 {
155 SetWindowLongW(hWnd, GWL_USERDATA, 0);
156 return 0;
157 }
158
159 case PM_CREATE_CONSOLE:
160 {
161 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
162 PCONSOLE Console = GuiData->Console;
163 RECT rcWnd;
164
165 DPRINT("PM_CREATE_CONSOLE -- creating window\n");
166
167 NewWindow = CreateWindowExW(WS_EX_CLIENTEDGE,
168 GUI_CONWND_CLASS,
169 Console->Title.Buffer,
170 WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
171 CW_USEDEFAULT,
172 CW_USEDEFAULT,
173 CW_USEDEFAULT,
174 CW_USEDEFAULT,
175 NULL,
176 NULL,
177 ConSrvDllInstance,
178 (PVOID)GuiData);
179 if (NULL != NewWindow)
180 {
181 ASSERT(NewWindow == GuiData->hWindow);
182
183 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
184 WindowCount++;
185 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
186
187 //
188 // FIXME: TODO: Move everything there into conwnd.c!OnNcCreate()
189 //
190
191 /* Retrieve our real position */
192 // See conwnd.c!OnMove()
193 GetWindowRect(GuiData->hWindow, &rcWnd);
194 GuiData->GuiInfo.WindowOrigin.x = rcWnd.left;
195 GuiData->GuiInfo.WindowOrigin.y = rcWnd.top;
196
197 /* Move and resize the window to the user's values */
198 /* CAN WE DEADLOCK ?? */
199 GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
200 SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
201
202 /* Switch to full-screen mode if necessary */
203 // FIXME: Move elsewhere, it cause misdrawings of the window.
204 if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
205
206 DPRINT("PM_CREATE_CONSOLE -- showing window\n");
207 // ShowWindow(NewWindow, (int)wParam);
208 ShowWindowAsync(NewWindow, (int)wParam);
209 DPRINT("Window showed\n");
210 }
211
212 return (LRESULT)NewWindow;
213 }
214
215 case PM_DESTROY_CONSOLE:
216 {
217 PGUI_CONSOLE_DATA GuiData = (PGUI_CONSOLE_DATA)lParam;
218
219 /* Exit the full screen mode if it was already set */
220 // LeaveFullScreen(GuiData);
221
222 /*
223 * Window creation is done using a PostMessage(), so it's possible
224 * that the window that we want to destroy doesn't exist yet.
225 * So first empty the message queue.
226 */
227 /*
228 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE))
229 {
230 TranslateMessage(&Msg);
231 DispatchMessageW(&Msg);
232 }*/
233 while (PeekMessageW(&Msg, NULL, 0, 0, PM_REMOVE)) ;
234
235 if (GuiData->hWindow != NULL) /* && DestroyWindow(GuiData->hWindow) */
236 {
237 DestroyWindow(GuiData->hWindow);
238
239 WindowCount = GetWindowLongW(hWnd, GWL_USERDATA);
240 WindowCount--;
241 SetWindowLongW(hWnd, GWL_USERDATA, WindowCount);
242 if (0 == WindowCount)
243 {
244 NotifyWnd = NULL;
245 DestroyWindow(hWnd);
246 DPRINT("CONSRV: Going to quit the Gui Thread!!\n");
247 PostQuitMessage(0);
248 }
249 }
250
251 return 0;
252 }
253
254 default:
255 return DefWindowProcW(hWnd, msg, wParam, lParam);
256 }
257 }
258
259 static DWORD NTAPI
260 GuiConsoleGuiThread(PVOID Data)
261 {
262 MSG msg;
263 PHANDLE GraphicsStartupEvent = (PHANDLE)Data;
264
265 /*
266 * This thread dispatches all the console notifications to the notify window.
267 * It is common for all the console windows.
268 */
269
270 PrivateCsrssManualGuiCheck(+1);
271
272 NotifyWnd = CreateWindowW(L"ConSrvCreateNotify",
273 L"",
274 WS_OVERLAPPEDWINDOW,
275 CW_USEDEFAULT,
276 CW_USEDEFAULT,
277 CW_USEDEFAULT,
278 CW_USEDEFAULT,
279 NULL,
280 NULL,
281 ConSrvDllInstance,
282 NULL);
283 if (NULL == NotifyWnd)
284 {
285 PrivateCsrssManualGuiCheck(-1);
286 SetEvent(*GraphicsStartupEvent);
287 return 1;
288 }
289
290 SetEvent(*GraphicsStartupEvent);
291
292 while (GetMessageW(&msg, NULL, 0, 0))
293 {
294 TranslateMessage(&msg);
295 DispatchMessageW(&msg);
296 }
297
298 DPRINT("CONSRV: Quit the Gui Thread!!\n");
299 PrivateCsrssManualGuiCheck(-1);
300
301 return 1;
302 }
303
304 static BOOL
305 GuiInit(VOID)
306 {
307 WNDCLASSEXW wc;
308
309 /* Exit if we were already initialized */
310 // if (ConsInitialized) return TRUE;
311
312 /*
313 * Initialize and register the different window classes, if needed.
314 */
315 if (!ConsInitialized)
316 {
317 /* Initialize the notification window class */
318 wc.cbSize = sizeof(WNDCLASSEXW);
319 wc.lpszClassName = L"ConSrvCreateNotify";
320 wc.lpfnWndProc = GuiConsoleNotifyWndProc;
321 wc.style = 0;
322 wc.hInstance = ConSrvDllInstance;
323 wc.hIcon = NULL;
324 wc.hIconSm = NULL;
325 wc.hCursor = NULL;
326 wc.hbrBackground = NULL;
327 wc.lpszMenuName = NULL;
328 wc.cbClsExtra = 0;
329 wc.cbWndExtra = 0;
330 if (RegisterClassExW(&wc) == 0)
331 {
332 DPRINT1("Failed to register GUI notify wndproc\n");
333 return FALSE;
334 }
335
336 /* Initialize the console window class */
337 if (!RegisterConWndClass(ConSrvDllInstance))
338 return FALSE;
339
340 ConsInitialized = TRUE;
341 }
342
343 /*
344 * Set-up the notification window
345 */
346 if (NULL == NotifyWnd)
347 {
348 HANDLE ThreadHandle;
349 HANDLE GraphicsStartupEvent;
350
351 GraphicsStartupEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
352 if (NULL == GraphicsStartupEvent) return FALSE;
353
354 ThreadHandle = CreateThread(NULL,
355 0,
356 GuiConsoleGuiThread,
357 (PVOID)&GraphicsStartupEvent,
358 0,
359 NULL);
360 if (NULL == ThreadHandle)
361 {
362 CloseHandle(GraphicsStartupEvent);
363 DPRINT1("CONSRV: Failed to create graphics console thread. Expect problems\n");
364 return FALSE;
365 }
366 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
367 CloseHandle(ThreadHandle);
368
369 WaitForSingleObject(GraphicsStartupEvent, INFINITE);
370 CloseHandle(GraphicsStartupEvent);
371
372 if (NULL == NotifyWnd)
373 {
374 DPRINT1("CONSRV: Failed to create notification window.\n");
375 return FALSE;
376 }
377 }
378
379 // ConsInitialized = TRUE;
380
381 return TRUE;
382 }
383
384
385
386 /******************************************************************************
387 * GUI Console Driver *
388 ******************************************************************************/
389
390 static VOID NTAPI
391 GuiDeinitFrontEnd(IN OUT PFRONTEND This);
392
393 NTSTATUS NTAPI
394 GuiInitFrontEnd(IN OUT PFRONTEND This,
395 IN PCONSOLE Console)
396 {
397 PGUI_INIT_INFO GuiInitInfo;
398 PCONSOLE_INFO ConsoleInfo;
399 PCONSOLE_START_INFO ConsoleStartInfo;
400
401 PGUI_CONSOLE_DATA GuiData;
402 GUI_CONSOLE_INFO TermInfo;
403
404 SIZE_T Length = 0;
405 LPWSTR IconPath = NULL;
406 INT IconIndex = 0;
407
408 if (This == NULL || Console == NULL || This->OldData == NULL)
409 return STATUS_INVALID_PARAMETER;
410
411 ASSERT(This->Console == Console);
412
413 GuiInitInfo = This->OldData;
414
415 if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL)
416 return STATUS_INVALID_PARAMETER;
417
418 ConsoleInfo = GuiInitInfo->ConsoleInfo;
419 ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo;
420
421 IconPath = ConsoleStartInfo->IconPath;
422 IconIndex = ConsoleStartInfo->IconIndex;
423
424
425 /* Terminal data allocation */
426 GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA));
427 if (!GuiData)
428 {
429 DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n");
430 return STATUS_UNSUCCESSFUL;
431 }
432 ///// /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */
433 GuiData->Console = Console;
434 GuiData->ActiveBuffer = Console->ActiveBuffer;
435 GuiData->hWindow = NULL;
436
437 /* The console can be resized */
438 Console->FixedSize = FALSE;
439
440 InitializeCriticalSection(&GuiData->Lock);
441
442
443 /*
444 * Load terminal settings
445 */
446
447 /* 1. Load the default settings */
448 GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId);
449
450 /* 3. Load the remaining console settings via the registry. */
451 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
452 {
453 /* Load the terminal infos from the registry. */
454 GuiConsoleReadUserSettings(&TermInfo,
455 ConsoleInfo->ConsoleTitle,
456 GuiInitInfo->ProcessId);
457
458 /*
459 * Now, update them with the properties the user might gave to us
460 * via the STARTUPINFO structure before calling CreateProcess
461 * (and which was transmitted via the ConsoleStartInfo structure).
462 * We therefore overwrite the values read in the registry.
463 */
464 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
465 {
466 TermInfo.ShowWindow = ConsoleStartInfo->wShowWindow;
467 }
468 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
469 {
470 TermInfo.AutoPosition = FALSE;
471 TermInfo.WindowOrigin.x = ConsoleStartInfo->dwWindowOrigin.X;
472 TermInfo.WindowOrigin.y = ConsoleStartInfo->dwWindowOrigin.Y;
473 }
474 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
475 {
476 TermInfo.FullScreen = TRUE;
477 }
478 }
479
480
481 /*
482 * Set up GUI data
483 */
484
485 Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen
486 wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE);
487 GuiData->GuiInfo.FaceName[Length] = L'\0';
488 GuiData->GuiInfo.FontFamily = TermInfo.FontFamily;
489 GuiData->GuiInfo.FontSize = TermInfo.FontSize;
490 GuiData->GuiInfo.FontWeight = TermInfo.FontWeight;
491 GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts;
492 GuiData->GuiInfo.FullScreen = TermInfo.FullScreen;
493 GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow;
494 GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition;
495 GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin;
496
497 /* Initialize the icon handles to their default values */
498 GuiData->hIcon = ghDefaultIcon;
499 GuiData->hIconSm = ghDefaultIconSm;
500
501 /* Get the associated icon, if any */
502 if (IconPath == NULL || IconPath[0] == L'\0')
503 {
504 IconPath = ConsoleStartInfo->AppPath;
505 IconIndex = 0;
506 }
507 DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex);
508 if (IconPath && IconPath[0] != L'\0')
509 {
510 HICON hIcon = NULL, hIconSm = NULL;
511 PrivateExtractIconExW(IconPath,
512 IconIndex,
513 &hIcon,
514 &hIconSm,
515 1);
516 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
517 if (hIcon != NULL) GuiData->hIcon = hIcon;
518 if (hIconSm != NULL) GuiData->hIconSm = hIconSm;
519 }
520 ASSERT(GuiData->hIcon && GuiData->hIconSm);
521
522 /* Mouse is shown by default with its default cursor shape */
523 GuiData->hCursor = ghDefaultCursor;
524 GuiData->MouseCursorRefCount = 0;
525
526 /* A priori don't ignore mouse signals */
527 GuiData->IgnoreNextMouseSignal = FALSE;
528
529 /* Close button and the corresponding system menu item are enabled by default */
530 GuiData->IsCloseButtonEnabled = TRUE;
531
532 /* There is no user-reserved menu id range by default */
533 GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
534
535 /* Initialize the selection */
536 RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
537 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
538 RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
539 GuiData->LineSelection = FALSE; // Default to block selection
540 // TODO: Retrieve the selection mode via the registry.
541
542 /*
543 * We need to wait until the GUI has been fully initialized
544 * to retrieve custom settings i.e. WindowSize etc...
545 * Ideally we could use SendNotifyMessage for this but its not
546 * yet implemented.
547 */
548 GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
549
550 DPRINT("GUI - Checkpoint\n");
551
552 /* Create the terminal window */
553 PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData);
554
555 /* Wait until initialization has finished */
556 WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE);
557 DPRINT("OK we created the console window\n");
558 CloseHandle(GuiData->hGuiInitEvent);
559 GuiData->hGuiInitEvent = NULL;
560
561 /* Check whether we really succeeded in initializing the terminal window */
562 if (GuiData->hWindow == NULL)
563 {
564 DPRINT("GuiInitConsole - We failed at creating a new terminal window\n");
565 GuiDeinitFrontEnd(This);
566 return STATUS_UNSUCCESSFUL;
567 }
568
569 /* Finally, finish to initialize the frontend structure */
570 This->Data = GuiData;
571 if (This->OldData) ConsoleFreeHeap(This->OldData);
572 This->OldData = NULL;
573
574 return STATUS_SUCCESS;
575 }
576
577 static VOID NTAPI
578 GuiDeinitFrontEnd(IN OUT PFRONTEND This)
579 {
580 PGUI_CONSOLE_DATA GuiData = This->Data;
581
582 SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData);
583
584 DPRINT("Destroying icons !! - GuiData->hIcon = 0x%p ; ghDefaultIcon = 0x%p ; GuiData->hIconSm = 0x%p ; ghDefaultIconSm = 0x%p\n",
585 GuiData->hIcon, ghDefaultIcon, GuiData->hIconSm, ghDefaultIconSm);
586 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
587 {
588 DPRINT("Destroy hIcon\n");
589 DestroyIcon(GuiData->hIcon);
590 }
591 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
592 {
593 DPRINT("Destroy hIconSm\n");
594 DestroyIcon(GuiData->hIconSm);
595 }
596
597 This->Data = NULL;
598 DeleteCriticalSection(&GuiData->Lock);
599 ConsoleFreeHeap(GuiData);
600
601 DPRINT("Quit GuiDeinitFrontEnd\n");
602 }
603
604 static VOID NTAPI
605 GuiDrawRegion(IN OUT PFRONTEND This,
606 SMALL_RECT* Region)
607 {
608 PGUI_CONSOLE_DATA GuiData = This->Data;
609 DrawRegion(GuiData, Region);
610 }
611
612 static VOID NTAPI
613 GuiWriteStream(IN OUT PFRONTEND This,
614 SMALL_RECT* Region,
615 SHORT CursorStartX,
616 SHORT CursorStartY,
617 UINT ScrolledLines,
618 PWCHAR Buffer,
619 UINT Length)
620 {
621 PGUI_CONSOLE_DATA GuiData = This->Data;
622 PCONSOLE_SCREEN_BUFFER Buff;
623 SHORT CursorEndX, CursorEndY;
624 RECT ScrollRect;
625
626 if (NULL == GuiData || NULL == GuiData->hWindow) return;
627
628 Buff = GuiData->ActiveBuffer;
629 if (GetType(Buff) != TEXTMODE_BUFFER) return;
630
631 if (0 != ScrolledLines)
632 {
633 ScrollRect.left = 0;
634 ScrollRect.top = 0;
635 ScrollRect.right = Buff->ViewSize.X * GuiData->CharWidth;
636 ScrollRect.bottom = Region->Top * GuiData->CharHeight;
637
638 ScrollWindowEx(GuiData->hWindow,
639 0,
640 -(int)(ScrolledLines * GuiData->CharHeight),
641 &ScrollRect,
642 NULL,
643 NULL,
644 NULL,
645 SW_INVALIDATE);
646 }
647
648 DrawRegion(GuiData, Region);
649
650 if (CursorStartX < Region->Left || Region->Right < CursorStartX
651 || CursorStartY < Region->Top || Region->Bottom < CursorStartY)
652 {
653 InvalidateCell(GuiData, CursorStartX, CursorStartY);
654 }
655
656 CursorEndX = Buff->CursorPosition.X;
657 CursorEndY = Buff->CursorPosition.Y;
658 if ((CursorEndX < Region->Left || Region->Right < CursorEndX
659 || CursorEndY < Region->Top || Region->Bottom < CursorEndY)
660 && (CursorEndX != CursorStartX || CursorEndY != CursorStartY))
661 {
662 InvalidateCell(GuiData, CursorEndX, CursorEndY);
663 }
664
665 // HACK!!
666 // Set up the update timer (very short interval) - this is a "hack" for getting the OS to
667 // repaint the window without having it just freeze up and stay on the screen permanently.
668 Buff->CursorBlinkOn = TRUE;
669 SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
670 }
671
672 static BOOL NTAPI
673 GuiSetCursorInfo(IN OUT PFRONTEND This,
674 PCONSOLE_SCREEN_BUFFER Buff)
675 {
676 PGUI_CONSOLE_DATA GuiData = This->Data;
677
678 if (GuiData->ActiveBuffer == Buff)
679 {
680 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
681 }
682
683 return TRUE;
684 }
685
686 static BOOL NTAPI
687 GuiSetScreenInfo(IN OUT PFRONTEND This,
688 PCONSOLE_SCREEN_BUFFER Buff,
689 SHORT OldCursorX,
690 SHORT OldCursorY)
691 {
692 PGUI_CONSOLE_DATA GuiData = This->Data;
693
694 if (GuiData->ActiveBuffer == Buff)
695 {
696 /* Redraw char at old position (remove cursor) */
697 InvalidateCell(GuiData, OldCursorX, OldCursorY);
698 /* Redraw char at new position (show cursor) */
699 InvalidateCell(GuiData, Buff->CursorPosition.X, Buff->CursorPosition.Y);
700 }
701
702 return TRUE;
703 }
704
705 static VOID NTAPI
706 GuiResizeTerminal(IN OUT PFRONTEND This)
707 {
708 PGUI_CONSOLE_DATA GuiData = This->Data;
709
710 /* Resize the window to the user's values */
711 PostMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
712 }
713
714 static VOID NTAPI
715 GuiSetActiveScreenBuffer(IN OUT PFRONTEND This)
716 {
717 PGUI_CONSOLE_DATA GuiData = This->Data;
718 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
719 HPALETTE hPalette;
720
721 EnterCriticalSection(&GuiData->Lock);
722 GuiData->WindowSizeLock = TRUE;
723
724 InterlockedExchangePointer(&GuiData->ActiveBuffer,
725 ConDrvGetActiveScreenBuffer(GuiData->Console));
726
727 GuiData->WindowSizeLock = FALSE;
728 LeaveCriticalSection(&GuiData->Lock);
729
730 ActiveBuffer = GuiData->ActiveBuffer;
731
732 /* Change the current palette */
733 if (ActiveBuffer->PaletteHandle == NULL)
734 {
735 hPalette = GuiData->hSysPalette;
736 }
737 else
738 {
739 hPalette = ActiveBuffer->PaletteHandle;
740 }
741
742 DPRINT1("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
743
744 /* Set the new palette for the framebuffer */
745 SelectPalette(GuiData->hMemDC, hPalette, FALSE);
746
747 /* Specify the use of the system palette for the framebuffer */
748 SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
749
750 /* Realize the (logical) palette */
751 RealizePalette(GuiData->hMemDC);
752
753 GuiResizeTerminal(This);
754 // ConioDrawConsole(Console);
755 }
756
757 static VOID NTAPI
758 GuiReleaseScreenBuffer(IN OUT PFRONTEND This,
759 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
760 {
761 PGUI_CONSOLE_DATA GuiData = This->Data;
762
763 /*
764 * If we were notified to release a screen buffer that is not actually
765 * ours, then just ignore the notification...
766 */
767 if (ScreenBuffer != GuiData->ActiveBuffer) return;
768
769 /*
770 * ... else, we must release our active buffer. Two cases are present:
771 * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
772 * active screen buffer, then we can safely switch to it.
773 * - If ScreenBuffer IS the console active screen buffer, we must release
774 * it ONLY.
775 */
776
777 /* Release the old active palette and set the default one */
778 if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
779 {
780 /* Set the new palette */
781 SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
782 }
783
784 /* Set the adequate active screen buffer */
785 if (ScreenBuffer != GuiData->Console->ActiveBuffer)
786 {
787 GuiSetActiveScreenBuffer(This);
788 }
789 else
790 {
791 EnterCriticalSection(&GuiData->Lock);
792 GuiData->WindowSizeLock = TRUE;
793
794 InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
795
796 GuiData->WindowSizeLock = FALSE;
797 LeaveCriticalSection(&GuiData->Lock);
798 }
799 }
800
801 static BOOL NTAPI
802 GuiProcessKeyCallback(IN OUT PFRONTEND This,
803 MSG* msg,
804 BYTE KeyStateMenu,
805 DWORD ShiftState,
806 UINT VirtualKeyCode,
807 BOOL Down)
808 {
809 if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) &&
810 (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE))
811 {
812 DPRINT1("GuiProcessKeyCallback\n");
813 //DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam);
814 //return TRUE;
815 }
816
817 return FALSE;
818 }
819
820 static BOOL NTAPI
821 GuiSetMouseCursor(IN OUT PFRONTEND This,
822 HCURSOR CursorHandle);
823
824 static VOID NTAPI
825 GuiRefreshInternalInfo(IN OUT PFRONTEND This)
826 {
827 PGUI_CONSOLE_DATA GuiData = This->Data;
828
829 /* Update the console leader information held by the window */
830 SetConWndConsoleLeaderCID(GuiData);
831
832 /*
833 * HACK:
834 * We reset the cursor here so that, when a console app quits, we reset
835 * the cursor to the default one. It's quite a hack since it doesn't proceed
836 * per - console process... This must be fixed.
837 *
838 * See GuiInitConsole(...) for more information.
839 */
840
841 /* Mouse is shown by default with its default cursor shape */
842 GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter
843 GuiSetMouseCursor(This, NULL);
844 }
845
846 static VOID NTAPI
847 GuiChangeTitle(IN OUT PFRONTEND This)
848 {
849 PGUI_CONSOLE_DATA GuiData = This->Data;
850 // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0);
851 SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer);
852 }
853
854 static BOOL NTAPI
855 GuiChangeIcon(IN OUT PFRONTEND This,
856 HICON IconHandle)
857 {
858 PGUI_CONSOLE_DATA GuiData = This->Data;
859 HICON hIcon, hIconSm;
860
861 if (IconHandle == NULL)
862 {
863 hIcon = ghDefaultIcon;
864 hIconSm = ghDefaultIconSm;
865 }
866 else
867 {
868 hIcon = CopyIcon(IconHandle);
869 hIconSm = CopyIcon(IconHandle);
870 }
871
872 if (hIcon == NULL)
873 {
874 return FALSE;
875 }
876
877 if (hIcon != GuiData->hIcon)
878 {
879 if (GuiData->hIcon != NULL && GuiData->hIcon != ghDefaultIcon)
880 {
881 DestroyIcon(GuiData->hIcon);
882 }
883 if (GuiData->hIconSm != NULL && GuiData->hIconSm != ghDefaultIconSm)
884 {
885 DestroyIcon(GuiData->hIconSm);
886 }
887
888 GuiData->hIcon = hIcon;
889 GuiData->hIconSm = hIconSm;
890
891 DPRINT("Set icons in GuiChangeIcon\n");
892 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_BIG , (LPARAM)GuiData->hIcon );
893 PostMessageW(GuiData->hWindow, WM_SETICON, ICON_SMALL, (LPARAM)GuiData->hIconSm);
894 }
895
896 return TRUE;
897 }
898
899 static HWND NTAPI
900 GuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
901 {
902 PGUI_CONSOLE_DATA GuiData = This->Data;
903 return GuiData->hWindow;
904 }
905
906 static VOID NTAPI
907 GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
908 PCOORD pSize)
909 {
910 PGUI_CONSOLE_DATA GuiData = This->Data;
911 PCONSOLE_SCREEN_BUFFER ActiveBuffer;
912 RECT WorkArea;
913 LONG width, height;
914 UINT WidthUnit, HeightUnit;
915
916 if (!pSize) return;
917
918 if (!SystemParametersInfoW(SPI_GETWORKAREA, 0, &WorkArea, 0))
919 {
920 DPRINT1("SystemParametersInfoW failed - What to do ??\n");
921 return;
922 }
923
924 ActiveBuffer = GuiData->ActiveBuffer;
925 if (ActiveBuffer)
926 {
927 GetScreenBufferSizeUnits(ActiveBuffer, GuiData, &WidthUnit, &HeightUnit);
928 }
929 else
930 {
931 /* Default: text mode */
932 WidthUnit = GuiData->CharWidth ;
933 HeightUnit = GuiData->CharHeight;
934 }
935
936 width = WorkArea.right;
937 height = WorkArea.bottom;
938
939 width -= (2 * (GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXEDGE)));
940 height -= (2 * (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYEDGE)) + GetSystemMetrics(SM_CYCAPTION));
941
942 if (width < 0) width = 0;
943 if (height < 0) height = 0;
944
945 pSize->X = (SHORT)(width / (int)WidthUnit ) /* HACK */ + 2;
946 pSize->Y = (SHORT)(height / (int)HeightUnit) /* HACK */ + 1;
947 }
948
949 static BOOL NTAPI
950 GuiGetSelectionInfo(IN OUT PFRONTEND This,
951 PCONSOLE_SELECTION_INFO pSelectionInfo)
952 {
953 PGUI_CONSOLE_DATA GuiData = This->Data;
954
955 if (pSelectionInfo == NULL) return FALSE;
956
957 ZeroMemory(pSelectionInfo, sizeof(CONSOLE_SELECTION_INFO));
958 if (GuiData->Selection.dwFlags != CONSOLE_NO_SELECTION)
959 RtlCopyMemory(pSelectionInfo, &GuiData->Selection, sizeof(CONSOLE_SELECTION_INFO));
960
961 return TRUE;
962 }
963
964 static BOOL NTAPI
965 GuiSetPalette(IN OUT PFRONTEND This,
966 HPALETTE PaletteHandle,
967 UINT PaletteUsage)
968 {
969 PGUI_CONSOLE_DATA GuiData = This->Data;
970 HPALETTE OldPalette;
971
972 // if (GetType(GuiData->ActiveBuffer) != GRAPHICS_BUFFER) return FALSE;
973 if (PaletteHandle == NULL) return FALSE;
974
975 /* Set the new palette for the framebuffer */
976 OldPalette = SelectPalette(GuiData->hMemDC, PaletteHandle, FALSE);
977 if (OldPalette == NULL) return FALSE;
978
979 /* Specify the use of the system palette for the framebuffer */
980 SetSystemPaletteUse(GuiData->hMemDC, PaletteUsage);
981
982 /* Realize the (logical) palette */
983 RealizePalette(GuiData->hMemDC);
984
985 /* Save the original system palette handle */
986 if (GuiData->hSysPalette == NULL) GuiData->hSysPalette = OldPalette;
987
988 return TRUE;
989 }
990
991 static ULONG NTAPI
992 GuiGetDisplayMode(IN OUT PFRONTEND This)
993 {
994 PGUI_CONSOLE_DATA GuiData = This->Data;
995 ULONG DisplayMode = 0;
996
997 if (GuiData->GuiInfo.FullScreen)
998 DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
999 else
1000 DisplayMode |= CONSOLE_WINDOWED;
1001
1002 return DisplayMode;
1003 }
1004
1005 static BOOL NTAPI
1006 GuiSetDisplayMode(IN OUT PFRONTEND This,
1007 ULONG NewMode)
1008 {
1009 PGUI_CONSOLE_DATA GuiData = This->Data;
1010 BOOL FullScreen;
1011
1012 if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1013 return FALSE;
1014
1015 FullScreen = ((NewMode & CONSOLE_FULLSCREEN_MODE) != 0);
1016
1017 if (FullScreen != GuiData->GuiInfo.FullScreen)
1018 {
1019 SwitchFullScreen(GuiData, FullScreen);
1020 }
1021
1022 return TRUE;
1023 }
1024
1025 static INT NTAPI
1026 GuiShowMouseCursor(IN OUT PFRONTEND This,
1027 BOOL Show)
1028 {
1029 PGUI_CONSOLE_DATA GuiData = This->Data;
1030
1031 /* Set the reference count */
1032 if (Show) ++GuiData->MouseCursorRefCount;
1033 else --GuiData->MouseCursorRefCount;
1034
1035 /* Effectively show (or hide) the cursor (use special values for (w|l)Param) */
1036 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1037
1038 return GuiData->MouseCursorRefCount;
1039 }
1040
1041 static BOOL NTAPI
1042 GuiSetMouseCursor(IN OUT PFRONTEND This,
1043 HCURSOR CursorHandle)
1044 {
1045 PGUI_CONSOLE_DATA GuiData = This->Data;
1046
1047 /*
1048 * Set the cursor's handle. If the given handle is NULL,
1049 * then restore the default cursor.
1050 */
1051 GuiData->hCursor = (CursorHandle ? CursorHandle : ghDefaultCursor);
1052
1053 /* Effectively modify the shape of the cursor (use special values for (w|l)Param) */
1054 PostMessageW(GuiData->hWindow, WM_SETCURSOR, -1, -1);
1055
1056 return TRUE;
1057 }
1058
1059 static HMENU NTAPI
1060 GuiMenuControl(IN OUT PFRONTEND This,
1061 UINT CmdIdLow,
1062 UINT CmdIdHigh)
1063 {
1064 PGUI_CONSOLE_DATA GuiData = This->Data;
1065
1066 GuiData->CmdIdLow = CmdIdLow ;
1067 GuiData->CmdIdHigh = CmdIdHigh;
1068
1069 return GetSystemMenu(GuiData->hWindow, FALSE);
1070 }
1071
1072 static BOOL NTAPI
1073 GuiSetMenuClose(IN OUT PFRONTEND This,
1074 BOOL Enable)
1075 {
1076 /*
1077 * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html
1078 * or http://harbour-devel.1590103.n2.nabble.com/Question-about-hb-gt-win-CtrlHandler-usage-td4670862i20.html
1079 * for more information.
1080 */
1081
1082 PGUI_CONSOLE_DATA GuiData = This->Data;
1083 HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE);
1084
1085 if (hSysMenu == NULL) return FALSE;
1086
1087 GuiData->IsCloseButtonEnabled = Enable;
1088 EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND | (Enable ? MF_ENABLED : MF_GRAYED));
1089
1090 return TRUE;
1091 }
1092
1093 static FRONTEND_VTBL GuiVtbl =
1094 {
1095 GuiInitFrontEnd,
1096 GuiDeinitFrontEnd,
1097 GuiDrawRegion,
1098 GuiWriteStream,
1099 GuiSetCursorInfo,
1100 GuiSetScreenInfo,
1101 GuiResizeTerminal,
1102 GuiSetActiveScreenBuffer,
1103 GuiReleaseScreenBuffer,
1104 GuiProcessKeyCallback,
1105 GuiRefreshInternalInfo,
1106 GuiChangeTitle,
1107 GuiChangeIcon,
1108 GuiGetConsoleWindowHandle,
1109 GuiGetLargestConsoleWindowSize,
1110 GuiGetSelectionInfo,
1111 GuiSetPalette,
1112 GuiGetDisplayMode,
1113 GuiSetDisplayMode,
1114 GuiShowMouseCursor,
1115 GuiSetMouseCursor,
1116 GuiMenuControl,
1117 GuiSetMenuClose,
1118 };
1119
1120
1121 static BOOL
1122 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
1123 IN OUT PCONSOLE_INFO ConsoleInfo)
1124 {
1125 #define PATH_SEPARATOR L'\\'
1126
1127 BOOL RetVal = FALSE;
1128 HRESULT hRes = S_OK;
1129 LPWSTR LinkName = NULL;
1130 SIZE_T Length = 0;
1131
1132 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
1133 return FALSE;
1134
1135 ConsoleStartInfo->IconPath[0] = L'\0';
1136 ConsoleStartInfo->IconIndex = 0;
1137
1138 /* 1- Find the last path separator if any */
1139 LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
1140 if (LinkName == NULL)
1141 {
1142 LinkName = ConsoleStartInfo->ConsoleTitle;
1143 }
1144 else
1145 {
1146 /* Skip the path separator */
1147 ++LinkName;
1148 }
1149
1150 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
1151 Length = wcslen(LinkName);
1152 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
1153 return FALSE;
1154
1155 /* 3- It may be a link. Try to retrieve some properties */
1156 hRes = CoInitialize(NULL);
1157 if (SUCCEEDED(hRes))
1158 {
1159 /* Get a pointer to the IShellLink interface */
1160 IShellLinkW* pshl = NULL;
1161 hRes = CoCreateInstance(&CLSID_ShellLink,
1162 NULL,
1163 CLSCTX_INPROC_SERVER,
1164 &IID_IShellLinkW,
1165 (LPVOID*)&pshl);
1166 if (SUCCEEDED(hRes))
1167 {
1168 /* Get a pointer to the IPersistFile interface */
1169 IPersistFile* ppf = NULL;
1170 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
1171 if (SUCCEEDED(hRes))
1172 {
1173 /* Load the shortcut */
1174 hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
1175 if (SUCCEEDED(hRes))
1176 {
1177 /*
1178 * Finally we can get the properties !
1179 * Update the old ones if needed.
1180 */
1181 INT ShowCmd = 0;
1182 // WORD HotKey = 0;
1183
1184 /* Reset the name of the console with the name of the shortcut */
1185 Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
1186 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
1187 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
1188 ConsoleInfo->ConsoleTitle[Length] = L'\0';
1189
1190 /* Get the window showing command */
1191 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
1192 if (SUCCEEDED(hRes)) ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
1193
1194 /* Get the hotkey */
1195 // hRes = pshl->GetHotkey(&ShowCmd);
1196 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
1197
1198 /* Get the icon location, if any */
1199
1200 hRes = IShellLinkW_GetIconLocation(pshl,
1201 ConsoleStartInfo->IconPath,
1202 sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH
1203 &ConsoleStartInfo->IconIndex);
1204 if (!SUCCEEDED(hRes))
1205 {
1206 ConsoleStartInfo->IconPath[0] = L'\0';
1207 ConsoleStartInfo->IconIndex = 0;
1208 }
1209
1210 // FIXME: Since we still don't load console properties from the shortcut,
1211 // return false. When this will be done, we will return true instead.
1212 RetVal = FALSE;
1213 }
1214 IPersistFile_Release(ppf);
1215 }
1216 IShellLinkW_Release(pshl);
1217 }
1218 }
1219 CoUninitialize();
1220
1221 return RetVal;
1222 }
1223
1224 NTSTATUS NTAPI
1225 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
1226 IN OUT PCONSOLE_INFO ConsoleInfo,
1227 IN OUT PVOID ExtraConsoleInfo,
1228 IN ULONG ProcessId)
1229 {
1230 PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo;
1231 PGUI_INIT_INFO GuiInitInfo;
1232
1233 if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL)
1234 return STATUS_INVALID_PARAMETER;
1235
1236 /* Initialize GUI terminal emulator common functionalities */
1237 if (!GuiInit()) return STATUS_UNSUCCESSFUL;
1238
1239 /*
1240 * Load per-application terminal settings.
1241 *
1242 * Check whether the process creating the console was launched via
1243 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
1244 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
1245 */
1246 if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
1247 {
1248 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo))
1249 {
1250 ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
1251 }
1252 }
1253
1254 /*
1255 * Initialize a private initialization info structure for later use.
1256 * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd.
1257 */
1258 GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO));
1259 if (GuiInitInfo == NULL) return STATUS_NO_MEMORY;
1260
1261 // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd...
1262 GuiInitInfo->ConsoleInfo = ConsoleInfo;
1263 GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo;
1264 GuiInitInfo->ProcessId = ProcessId;
1265
1266 /* Finally, initialize the frontend structure */
1267 FrontEnd->Vtbl = &GuiVtbl;
1268 FrontEnd->Data = NULL;
1269 FrontEnd->OldData = GuiInitInfo;
1270
1271 return STATUS_SUCCESS;
1272 }
1273
1274 NTSTATUS NTAPI
1275 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
1276 {
1277 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
1278
1279 if (FrontEnd->Data) GuiDeinitFrontEnd(FrontEnd);
1280 if (FrontEnd->OldData) ConsoleFreeHeap(FrontEnd->OldData);
1281
1282 return STATUS_SUCCESS;
1283 }
1284
1285 /* EOF */