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