Synchronize with trunk r58457.
[reactos.git] / win32ss / user / consrv / console.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/console.c
5 * PURPOSE: Console I/O functions
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #define COBJMACROS
12 #define NONAMELESSUNION
13
14 #include "consrv.h"
15 #include "settings.h"
16 #include "guiconsole.h"
17
18 #ifdef TUI_CONSOLE
19 #include "tuiconsole.h"
20 #endif
21
22 #include <shlwapi.h>
23 #include <shlobj.h>
24
25 //#define NDEBUG
26 #include <debug.h>
27
28
29 /* FUNCTIONS *****************************************************************/
30
31 BOOL FASTCALL
32 DtbgIsDesktopVisible(VOID)
33 {
34 return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
35 }
36
37 VOID FASTCALL
38 ConSrvConsoleCtrlEventTimeout(DWORD Event,
39 PCONSOLE_PROCESS_DATA ProcessData,
40 DWORD Timeout)
41 {
42 HANDLE Thread;
43
44 DPRINT("ConSrvConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
45
46 if (ProcessData->CtrlDispatcher)
47 {
48 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
49 ProcessData->CtrlDispatcher,
50 UlongToPtr(Event), 0, NULL);
51 if (NULL == Thread)
52 {
53 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
54 return;
55 }
56
57 DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
58 WaitForSingleObject(Thread, Timeout);
59 CloseHandle(Thread);
60 }
61 }
62
63 VOID FASTCALL
64 ConSrvConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
65 {
66 ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
67 }
68
69 VOID FASTCALL
70 ConioPause(PCONSOLE Console, UINT Flags)
71 {
72 Console->PauseFlags |= Flags;
73 if (!Console->UnpauseEvent)
74 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
75 }
76
77 VOID FASTCALL
78 ConioUnpause(PCONSOLE Console, UINT Flags)
79 {
80 Console->PauseFlags &= ~Flags;
81
82 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
83 if (Console->PauseFlags == 0 && Console->UnpauseEvent)
84 {
85 SetEvent(Console->UnpauseEvent);
86 CloseHandle(Console->UnpauseEvent);
87 Console->UnpauseEvent = NULL;
88
89 CsrNotifyWait(&Console->WriteWaitQueue,
90 WaitAll,
91 NULL,
92 NULL);
93 if (!IsListEmpty(&Console->WriteWaitQueue))
94 {
95 CsrDereferenceWait(&Console->WriteWaitQueue);
96 }
97 }
98 }
99
100 static BOOL
101 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
102 OUT PCONSOLE_INFO ConsoleInfo,
103 OUT LPWSTR IconPath,
104 IN SIZE_T IconPathLength,
105 OUT PINT piIcon)
106 {
107 #define PATH_SEPARATOR L'\\'
108
109 BOOL RetVal = FALSE;
110 LPWSTR LinkName = NULL;
111 SIZE_T Length = 0;
112
113 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
114 return FALSE;
115
116 if (IconPath == NULL || piIcon == NULL)
117 return FALSE;
118
119 IconPath[0] = L'\0';
120 *piIcon = 0;
121
122 /* 1- Find the last path separator if any */
123 LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
124 if (LinkName == NULL)
125 {
126 LinkName = ConsoleStartInfo->ConsoleTitle;
127 }
128 else
129 {
130 /* Skip the path separator */
131 ++LinkName;
132 }
133
134 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
135 Length = wcslen(LinkName);
136 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
137 return FALSE;
138
139 /* 3- It may be a link. Try to retrieve some properties */
140 HRESULT hRes = CoInitialize(NULL);
141 if (SUCCEEDED(hRes))
142 {
143 /* Get a pointer to the IShellLink interface */
144 IShellLinkW* pshl = NULL;
145 hRes = CoCreateInstance(&CLSID_ShellLink,
146 NULL,
147 CLSCTX_INPROC_SERVER,
148 &IID_IShellLinkW,
149 (LPVOID*)&pshl);
150 if (SUCCEEDED(hRes))
151 {
152 /* Get a pointer to the IPersistFile interface */
153 IPersistFile* ppf = NULL;
154 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
155 if (SUCCEEDED(hRes))
156 {
157 /* Load the shortcut */
158 hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
159 if (SUCCEEDED(hRes))
160 {
161 /*
162 * Finally we can get the properties !
163 * Update the old ones if needed.
164 */
165 INT ShowCmd = 0;
166 // WORD HotKey = 0;
167
168 /* Get the name of the shortcut */
169 Length = min(Length - 4,
170 sizeof(ConsoleStartInfo->ConsoleTitle) / sizeof(ConsoleStartInfo->ConsoleTitle[0]) - 1);
171 wcsncpy(ConsoleStartInfo->ConsoleTitle, LinkName, Length);
172 ConsoleStartInfo->ConsoleTitle[Length] = L'\0';
173
174 // HACK: Copy also the name of the shortcut
175 Length = min(Length,
176 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
177 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
178 ConsoleInfo->ConsoleTitle[Length] = L'\0';
179
180 /* Get the window showing command */
181 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
182 if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd;
183
184 /* Get the hotkey */
185 // hRes = pshl->GetHotkey(&ShowCmd);
186 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
187
188 /* Get the icon location, if any */
189 hRes = IShellLinkW_GetIconLocation(pshl, IconPath, IconPathLength, piIcon);
190 if (!SUCCEEDED(hRes))
191 {
192 IconPath[0] = L'\0';
193 }
194
195 // FIXME: Since we still don't load console properties from the shortcut,
196 // return false. When this will be done, we will return true instead.
197 RetVal = FALSE;
198 }
199 IPersistFile_Release(ppf);
200 }
201 IShellLinkW_Release(pshl);
202 }
203 }
204 CoUninitialize();
205
206 return RetVal;
207 }
208
209 NTSTATUS WINAPI
210 ConSrvInitConsole(OUT PCONSOLE* NewConsole,
211 IN LPCWSTR AppPath,
212 IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
213 IN PCSR_PROCESS ConsoleLeaderProcess)
214 {
215 NTSTATUS Status;
216 SECURITY_ATTRIBUTES SecurityAttributes;
217 CONSOLE_INFO ConsoleInfo;
218 SIZE_T Length = 0;
219 DWORD ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess);
220 PCONSOLE Console;
221 PCONSOLE_SCREEN_BUFFER NewBuffer;
222 BOOL GuiMode;
223 WCHAR Title[128];
224 WCHAR IconPath[MAX_PATH + 1] = L"";
225 INT iIcon = 0;
226
227 if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
228 *NewConsole = NULL;
229
230 /*
231 * Allocate a console structure
232 */
233 Console = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE));
234 if (NULL == Console)
235 {
236 DPRINT1("Not enough memory for console creation.\n");
237 return STATUS_NO_MEMORY;
238 }
239
240 /*
241 * Load the console settings
242 */
243
244 /* 1. Load the default settings */
245 ConSrvGetDefaultSettings(&ConsoleInfo, ProcessId);
246
247 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
248 Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
249 sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
250 wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
251 ConsoleInfo.ConsoleTitle[Length] = L'\0';
252
253 /*
254 * 3. Check whether the process creating the
255 * console was launched via a shell-link
256 * (ConsoleInfo.ConsoleTitle may be updated).
257 */
258 if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
259 {
260 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo,
261 &ConsoleInfo,
262 IconPath,
263 MAX_PATH,
264 &iIcon))
265 {
266 ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
267 }
268 }
269
270 /*
271 * 4. Load the remaining console settings via the registry.
272 */
273 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
274 {
275 /*
276 * Either we weren't created by an app launched via a shell-link,
277 * or we failed to load shell-link console properties.
278 * Therefore, load the console infos for the application from the registry.
279 */
280 ConSrvReadUserSettings(&ConsoleInfo, ProcessId);
281
282 /*
283 * Now, update them with the properties the user might gave to us
284 * via the STARTUPINFO structure before calling CreateProcess
285 * (and which was transmitted via the ConsoleStartInfo structure).
286 */
287 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
288 {
289 ConsoleInfo.ScreenAttrib = ConsoleStartInfo->FillAttribute;
290 }
291 if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
292 {
293 ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
294 }
295 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
296 {
297 ConsoleInfo.u.GuiInfo.ShowWindow = ConsoleStartInfo->ShowWindow;
298 }
299 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
300 {
301 ConsoleInfo.u.GuiInfo.AutoPosition = FALSE;
302 ConsoleInfo.u.GuiInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin;
303 }
304 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
305 {
306 // ConsoleInfo.ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
307 ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx;
308 ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy;
309 }
310 /*
311 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
312 {
313 }
314 */
315 }
316
317 /*
318 * Initialize the console
319 */
320 InitializeCriticalSection(&Console->Lock);
321 Console->ReferenceCount = 0;
322 InitializeListHead(&Console->ProcessList);
323 memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
324 Console->Size = ConsoleInfo.ConsoleSize;
325
326 /*
327 * Initialize the input buffer
328 */
329 Console->InputBuffer.Header.Type = CONIO_INPUT_BUFFER_MAGIC;
330 Console->InputBuffer.Header.Console = Console;
331
332 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
333 SecurityAttributes.lpSecurityDescriptor = NULL;
334 SecurityAttributes.bInheritHandle = TRUE;
335 Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
336 if (NULL == Console->InputBuffer.ActiveEvent)
337 {
338 DeleteCriticalSection(&Console->Lock);
339 RtlFreeHeap(ConSrvHeap, 0, Console);
340 return STATUS_UNSUCCESSFUL;
341 }
342
343 // TODO: Use the values from ConsoleInfo.
344 Console->InputBuffer.Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
345 ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
346 Console->QuickEdit = ConsoleInfo.QuickEdit;
347 Console->InsertMode = ConsoleInfo.InsertMode;
348 InitializeListHead(&Console->InputBuffer.ReadWaitQueue);
349 InitializeListHead(&Console->InputBuffer.InputEvents);
350 Console->LineBuffer = NULL;
351 Console->CodePage = GetOEMCP();
352 Console->OutputCodePage = GetOEMCP();
353
354 /* Initialize a new screen buffer with default settings */
355 InitializeListHead(&Console->BufferList);
356 Status = ConSrvCreateScreenBuffer(Console,
357 &NewBuffer,
358 ConsoleInfo.ScreenBufferSize,
359 ConsoleInfo.ScreenAttrib,
360 ConsoleInfo.PopupAttrib,
361 TRUE,
362 ConsoleInfo.CursorSize);
363 if (!NT_SUCCESS(Status))
364 {
365 DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
366 CloseHandle(Console->InputBuffer.ActiveEvent);
367 DeleteCriticalSection(&Console->Lock);
368 RtlFreeHeap(ConSrvHeap, 0, Console);
369 return Status;
370 }
371 /* Make the new screen buffer active */
372 Console->ActiveBuffer = NewBuffer;
373 Console->FullScreen = ConsoleInfo.FullScreen;
374 InitializeListHead(&Console->WriteWaitQueue);
375
376 /*
377 * Initialize the history buffers
378 */
379 InitializeListHead(&Console->HistoryBuffers);
380 Console->HistoryBufferSize = ConsoleInfo.HistoryBufferSize;
381 Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
382 Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
383
384 /* Initialize the console title */
385 RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleStartInfo->ConsoleTitle);
386 if (ConsoleStartInfo->ConsoleTitle[0] == L'\0')
387 {
388 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, Title, sizeof(Title) / sizeof(Title[0])))
389 {
390 RtlCreateUnicodeString(&Console->Title, Title);
391 }
392 else
393 {
394 RtlCreateUnicodeString(&Console->Title, L"ReactOS Console");
395 }
396 }
397 else
398 {
399 RtlCreateUnicodeString(&Console->Title, ConsoleStartInfo->ConsoleTitle);
400 }
401
402 /*
403 * If we are not in GUI-mode, start the text-mode terminal emulator.
404 * If we fail, try to start the GUI-mode terminal emulator.
405 */
406 #ifdef TUI_CONSOLE
407 GuiMode = DtbgIsDesktopVisible();
408 #else
409 GuiMode = TRUE;
410 #endif
411
412 #ifdef TUI_CONSOLE
413 if (!GuiMode)
414 {
415 DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
416 Status = TuiInitConsole(Console, &ConsoleInfo);
417 if (!NT_SUCCESS(Status))
418 {
419 DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status);
420 GuiMode = TRUE;
421 }
422 }
423 #endif
424
425 /*
426 * Try to open the GUI-mode terminal emulator. Two cases are possible:
427 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
428 * failed and we start GUI-mode terminal emulator.
429 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
430 * succeeded BUT we failed at starting text-mode terminal emulator.
431 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
432 * terminal emulator (win32k will automatically switch to graphical mode,
433 * therefore no additional code is needed).
434 */
435 if (GuiMode)
436 {
437 DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
438 Status = GuiInitConsole(Console,
439 AppPath,
440 &ConsoleInfo,
441 IconPath,
442 iIcon);
443 if (!NT_SUCCESS(Status))
444 {
445 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
446 RtlFreeUnicodeString(&Console->Title);
447 RtlFreeUnicodeString(&Console->OriginalTitle);
448 ConioDeleteScreenBuffer(NewBuffer);
449 CloseHandle(Console->InputBuffer.ActiveEvent);
450 DeleteCriticalSection(&Console->Lock);
451 RtlFreeHeap(ConSrvHeap, 0, Console);
452 return Status;
453 }
454 }
455
456 /* Copy buffer contents to screen */
457 ConioDrawConsole(Console);
458
459 /* Return the newly created console to the caller and a success code too */
460 *NewConsole = Console;
461 return STATUS_SUCCESS;
462 }
463
464 VOID WINAPI
465 ConSrvInitConsoleSupport(VOID)
466 {
467 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
468
469 /* Should call LoadKeyboardLayout */
470 }
471
472 VOID WINAPI
473 ConSrvDeleteConsole(PCONSOLE Console)
474 {
475 ConsoleInput *Event;
476
477 DPRINT("ConSrvDeleteConsole\n");
478
479 /* Drain input event queue */
480 while (Console->InputBuffer.InputEvents.Flink != &Console->InputBuffer.InputEvents)
481 {
482 Event = (ConsoleInput *) Console->InputBuffer.InputEvents.Flink;
483 Console->InputBuffer.InputEvents.Flink = Console->InputBuffer.InputEvents.Flink->Flink;
484 Console->InputBuffer.InputEvents.Flink->Flink->Blink = &Console->InputBuffer.InputEvents;
485 RtlFreeHeap(ConSrvHeap, 0, Event);
486 }
487
488 ConioCleanupConsole(Console);
489 if (Console->LineBuffer)
490 RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
491 while (!IsListEmpty(&Console->HistoryBuffers))
492 HistoryDeleteBuffer((struct _HISTORY_BUFFER *)Console->HistoryBuffers.Flink);
493
494 ConioDeleteScreenBuffer(Console->ActiveBuffer);
495 if (!IsListEmpty(&Console->BufferList))
496 {
497 DPRINT1("BUG: screen buffer list not empty\n");
498 }
499
500 CloseHandle(Console->InputBuffer.ActiveEvent);
501 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
502 DeleteCriticalSection(&Console->Lock);
503
504 RtlFreeUnicodeString(&Console->OriginalTitle);
505 RtlFreeUnicodeString(&Console->Title);
506 IntDeleteAllAliases(Console->Aliases);
507 RtlFreeHeap(ConSrvHeap, 0, Console);
508 }
509
510 CSR_API(SrvOpenConsole)
511 {
512 NTSTATUS Status = STATUS_SUCCESS;
513 PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
514 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
515
516 DPRINT("SrvOpenConsole\n");
517
518 OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
519
520 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
521
522 DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
523
524 if (ProcessData->Console)
525 {
526 DWORD DesiredAccess = OpenConsoleRequest->Access;
527 DWORD ShareMode = OpenConsoleRequest->ShareMode;
528
529 PCONSOLE Console = ProcessData->Console;
530 Object_t *Object;
531
532 DPRINT1("SrvOpenConsole - Checkpoint 1\n");
533 EnterCriticalSection(&Console->Lock);
534 DPRINT1("SrvOpenConsole - Checkpoint 2\n");
535
536 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
537 {
538 Object = &Console->ActiveBuffer->Header;
539 }
540 else // HANDLE_INPUT
541 {
542 Object = &Console->InputBuffer.Header;
543 }
544
545 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
546 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
547 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
548 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
549 {
550 DPRINT1("Sharing violation\n");
551 Status = STATUS_SHARING_VIOLATION;
552 }
553 else
554 {
555 Status = ConSrvInsertObject(ProcessData,
556 &OpenConsoleRequest->ConsoleHandle,
557 Object,
558 DesiredAccess,
559 OpenConsoleRequest->Inheritable,
560 ShareMode);
561 }
562
563 LeaveCriticalSection(&Console->Lock);
564 }
565
566 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
567
568 return Status;
569 }
570
571 CSR_API(SrvAllocConsole)
572 {
573 NTSTATUS Status = STATUS_SUCCESS;
574 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
575 PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
576 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
577
578 DPRINT("SrvAllocConsole\n");
579
580 if (ProcessData->Console != NULL)
581 {
582 DPRINT1("Process already has a console\n");
583 return STATUS_ACCESS_DENIED;
584 }
585
586 if ( !CsrValidateMessageBuffer(ApiMessage,
587 (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
588 1,
589 sizeof(CONSOLE_START_INFO)) ||
590 !CsrValidateMessageBuffer(ApiMessage,
591 (PVOID*)&AllocConsoleRequest->AppPath,
592 MAX_PATH + 1,
593 sizeof(WCHAR)) )
594 {
595 return STATUS_INVALID_PARAMETER;
596 }
597
598 /*
599 * We are about to create a new console. However when ConSrvNewProcess
600 * was called, we didn't know that we wanted to create a new console and
601 * therefore, we by default inherited the handles table from our parent
602 * process. It's only now that we notice that in fact we do not need
603 * them, because we've created a new console and thus we must use it.
604 *
605 * Therefore, free the console we can have and our handles table,
606 * and recreate a new one later on.
607 */
608 ConSrvRemoveConsole(ProcessData);
609 // ConSrvFreeHandlesTable(ProcessData);
610
611 /* Initialize a new Console owned by the Console Leader Process */
612 Status = ConSrvAllocateConsole(ProcessData,
613 AllocConsoleRequest->AppPath,
614 &AllocConsoleRequest->InputHandle,
615 &AllocConsoleRequest->OutputHandle,
616 &AllocConsoleRequest->ErrorHandle,
617 AllocConsoleRequest->ConsoleStartInfo);
618 if (!NT_SUCCESS(Status))
619 {
620 DPRINT1("Console allocation failed\n");
621 return Status;
622 }
623
624 /* Return it to the caller */
625 AllocConsoleRequest->Console = ProcessData->Console;
626
627 /* Input Wait Handle */
628 AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
629
630 /* Set the Property Dialog Handler */
631 ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
632
633 /* Set the Ctrl Dispatcher */
634 ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
635 DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
636
637 return STATUS_SUCCESS;
638 }
639
640 CSR_API(SrvAttachConsole)
641 {
642 NTSTATUS Status = STATUS_SUCCESS;
643 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
644 PCSR_PROCESS SourceProcess = NULL; // The parent process.
645 PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
646 HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
647 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
648
649 DPRINT("SrvAttachConsole\n");
650
651 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
652
653 if (TargetProcessData->Console != NULL)
654 {
655 DPRINT1("Process already has a console\n");
656 return STATUS_ACCESS_DENIED;
657 }
658
659 /* Check whether we try to attach to the parent's console */
660 if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
661 {
662 PROCESS_BASIC_INFORMATION ProcessInfo;
663 ULONG Length = sizeof(ProcessInfo);
664
665 /* Get the real parent's ID */
666
667 Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
668 ProcessBasicInformation,
669 &ProcessInfo,
670 Length, &Length);
671 if (!NT_SUCCESS(Status))
672 {
673 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
674 return Status;
675 }
676
677 DPRINT("We, process (ID) %lu;%lu\n", TargetProcess->ClientId.UniqueProcess, TargetProcess->ClientId.UniqueThread);
678 ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
679 DPRINT("Parent process ID = %lu\n", ProcessId);
680 }
681
682 /* Lock the source process via its PID */
683 Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
684 DPRINT1("Lock process Id %lu - Status %lu\n", ProcessId, Status);
685 if (!NT_SUCCESS(Status)) return Status;
686
687 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
688
689 DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData->Console);
690 if (SourceProcessData->Console == NULL)
691 {
692 Status = STATUS_INVALID_HANDLE;
693 goto Quit;
694 }
695
696 /*
697 * We are about to create a new console. However when ConSrvNewProcess
698 * was called, we didn't know that we wanted to create a new console and
699 * therefore, we by default inherited the handles table from our parent
700 * process. It's only now that we notice that in fact we do not need
701 * them, because we've created a new console and thus we must use it.
702 *
703 * Therefore, free the console we can have and our handles table,
704 * and recreate a new one later on.
705 */
706 ConSrvRemoveConsole(TargetProcessData);
707 // ConSrvFreeHandlesTable(TargetProcessData);
708
709 /*
710 * Inherit the console from the parent,
711 * if any, otherwise return an error.
712 */
713 Status = ConSrvInheritConsole(TargetProcessData,
714 SourceProcessData->Console,
715 TRUE,
716 &AttachConsoleRequest->InputHandle,
717 &AttachConsoleRequest->OutputHandle,
718 &AttachConsoleRequest->ErrorHandle);
719 if (!NT_SUCCESS(Status))
720 {
721 DPRINT1("Console inheritance failed\n");
722 goto Quit;
723 }
724
725 /* Return it to the caller */
726 AttachConsoleRequest->Console = TargetProcessData->Console;
727
728 /* Input Wait Handle */
729 AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
730
731 /* Set the Property Dialog Handler */
732 TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
733
734 /* Set the Ctrl Dispatcher */
735 TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
736 DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData->CtrlDispatcher);
737
738 Status = STATUS_SUCCESS;
739
740 Quit:
741 /* Unlock the "source" process and exit */
742 CsrUnlockProcess(SourceProcess);
743 return Status;
744 }
745
746 CSR_API(SrvFreeConsole)
747 {
748 DPRINT1("SrvFreeConsole\n");
749 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
750 return STATUS_SUCCESS;
751 }
752
753 CSR_API(SrvSetConsoleMode)
754 {
755 #define CONSOLE_INPUT_MODE_VALID ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
756 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
757 ENABLE_MOUSE_INPUT | \
758 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS )
759 #define CONSOLE_OUTPUT_MODE_VALID ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
760
761 NTSTATUS Status;
762 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
763 Object_t* Object = NULL;
764
765 DPRINT("SrvSetConsoleMode\n");
766
767 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
768 ConsoleModeRequest->ConsoleHandle,
769 &Object, NULL, GENERIC_WRITE, TRUE, 0);
770 if (!NT_SUCCESS(Status)) return Status;
771
772 Status = STATUS_SUCCESS;
773
774 if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
775 {
776 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
777 InputBuffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
778 }
779 else if (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
780 {
781 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
782 Buffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
783 }
784 else
785 {
786 Status = STATUS_INVALID_HANDLE;
787 }
788
789 ConSrvReleaseObject(Object, TRUE);
790
791 return Status;
792 }
793
794 CSR_API(SrvGetConsoleMode)
795 {
796 NTSTATUS Status;
797 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
798 Object_t* Object = NULL;
799
800 DPRINT("SrvGetConsoleMode\n");
801
802 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
803 ConsoleModeRequest->ConsoleHandle,
804 &Object, NULL, GENERIC_READ, TRUE, 0);
805 if (!NT_SUCCESS(Status)) return Status;
806
807 Status = STATUS_SUCCESS;
808
809 if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
810 {
811 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
812 ConsoleModeRequest->ConsoleMode = InputBuffer->Mode;
813 }
814 else if (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
815 {
816 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
817 ConsoleModeRequest->ConsoleMode = Buffer->Mode;
818 }
819 else
820 {
821 Status = STATUS_INVALID_HANDLE;
822 }
823
824 ConSrvReleaseObject(Object, TRUE);
825
826 return Status;
827 }
828
829 CSR_API(SrvSetConsoleTitle)
830 {
831 NTSTATUS Status;
832 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
833 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
834 PCONSOLE Console;
835 PWCHAR Buffer;
836
837 DPRINT("SrvSetConsoleTitle\n");
838
839 if (!CsrValidateMessageBuffer(ApiMessage,
840 (PVOID)&TitleRequest->Title,
841 TitleRequest->Length,
842 sizeof(BYTE)))
843 {
844 return STATUS_INVALID_PARAMETER;
845 }
846
847 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
848 if (!NT_SUCCESS(Status))
849 {
850 DPRINT1("Can't get console\n");
851 return Status;
852 }
853
854 /* Allocate a new buffer to hold the new title (NULL-terminated) */
855 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
856 if (Buffer)
857 {
858 /* Free the old title */
859 RtlFreeUnicodeString(&Console->Title);
860
861 /* Copy title to console */
862 Console->Title.Buffer = Buffer;
863 Console->Title.Length = TitleRequest->Length;
864 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
865 RtlCopyMemory(Console->Title.Buffer,
866 TitleRequest->Title,
867 Console->Title.Length);
868 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
869
870 ConioChangeTitle(Console);
871 Status = STATUS_SUCCESS;
872 }
873 else
874 {
875 Status = STATUS_NO_MEMORY;
876 }
877
878 ConSrvReleaseConsole(Console, TRUE);
879 return Status;
880 }
881
882 CSR_API(SrvGetConsoleTitle)
883 {
884 NTSTATUS Status;
885 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
886 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
887 PCONSOLE Console;
888 DWORD Length;
889
890 DPRINT("SrvGetConsoleTitle\n");
891
892 if (!CsrValidateMessageBuffer(ApiMessage,
893 (PVOID)&TitleRequest->Title,
894 TitleRequest->Length,
895 sizeof(BYTE)))
896 {
897 return STATUS_INVALID_PARAMETER;
898 }
899
900 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
901 if (!NT_SUCCESS(Status))
902 {
903 DPRINT1("Can't get console\n");
904 return Status;
905 }
906
907 /* Copy title of the console to the user title buffer */
908 if (TitleRequest->Length >= sizeof(WCHAR))
909 {
910 Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
911 memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
912 TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
913 }
914
915 TitleRequest->Length = Console->Title.Length;
916
917 ConSrvReleaseConsole(Console, TRUE);
918 return STATUS_SUCCESS;
919 }
920
921 /**********************************************************************
922 * HardwareStateProperty
923 *
924 * DESCRIPTION
925 * Set/Get the value of the HardwareState and switch
926 * between direct video buffer ouput and GDI windowed
927 * output.
928 * ARGUMENTS
929 * Client hands us a CONSOLE_GETSETHWSTATE object.
930 * We use the same object to Request.
931 * NOTE
932 * ConsoleHwState has the correct size to be compatible
933 * with NT's, but values are not.
934 */
935 static NTSTATUS FASTCALL
936 SetConsoleHardwareState(PCONSOLE Console, DWORD ConsoleHwState)
937 {
938 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
939
940 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
941 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
942 {
943 if (Console->HardwareState != ConsoleHwState)
944 {
945 /* TODO: implement switching from full screen to windowed mode */
946 /* TODO: or back; now simply store the hardware state */
947 Console->HardwareState = ConsoleHwState;
948 }
949
950 return STATUS_SUCCESS;
951 }
952
953 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
954 }
955
956 CSR_API(SrvGetConsoleHardwareState)
957 {
958 NTSTATUS Status;
959 PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
960 PCONSOLE_SCREEN_BUFFER Buff;
961 PCONSOLE Console;
962
963 DPRINT("SrvGetConsoleHardwareState\n");
964
965 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
966 HardwareStateRequest->OutputHandle,
967 &Buff,
968 GENERIC_READ,
969 TRUE);
970 if (!NT_SUCCESS(Status))
971 {
972 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
973 return Status;
974 }
975
976 Console = Buff->Header.Console;
977 HardwareStateRequest->State = Console->HardwareState;
978
979 ConSrvReleaseScreenBuffer(Buff, TRUE);
980
981 return Status;
982 }
983
984 CSR_API(SrvSetConsoleHardwareState)
985 {
986 NTSTATUS Status;
987 PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
988 PCONSOLE_SCREEN_BUFFER Buff;
989 PCONSOLE Console;
990
991 DPRINT("SrvSetConsoleHardwareState\n");
992
993 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
994 HardwareStateRequest->OutputHandle,
995 &Buff,
996 GENERIC_READ,
997 TRUE);
998 if (!NT_SUCCESS(Status))
999 {
1000 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
1001 return Status;
1002 }
1003
1004 DPRINT("Setting console hardware state.\n");
1005 Console = Buff->Header.Console;
1006 Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
1007
1008 ConSrvReleaseScreenBuffer(Buff, TRUE);
1009
1010 return Status;
1011 }
1012
1013 CSR_API(SrvGetConsoleWindow)
1014 {
1015 NTSTATUS Status;
1016 PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
1017 PCONSOLE Console;
1018
1019 DPRINT("SrvGetConsoleWindow\n");
1020
1021 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1022 if (!NT_SUCCESS(Status)) return Status;
1023
1024 GetWindowRequest->WindowHandle = Console->TermIFace.Vtbl->GetConsoleWindowHandle(Console);
1025 ConSrvReleaseConsole(Console, TRUE);
1026
1027 return STATUS_SUCCESS;
1028 }
1029
1030 CSR_API(SrvSetConsoleIcon)
1031 {
1032 NTSTATUS Status;
1033 PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
1034 PCONSOLE Console;
1035
1036 DPRINT("SrvSetConsoleIcon\n");
1037
1038 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1039 if (!NT_SUCCESS(Status)) return Status;
1040
1041 Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon)
1042 ? STATUS_SUCCESS
1043 : STATUS_UNSUCCESSFUL);
1044
1045 ConSrvReleaseConsole(Console, TRUE);
1046
1047 return Status;
1048 }
1049
1050 CSR_API(SrvGetConsoleCP)
1051 {
1052 NTSTATUS Status;
1053 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
1054 PCONSOLE Console;
1055
1056 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1057 ConsoleCPRequest->InputCP ? "Input" : "Output");
1058
1059 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1060 if (!NT_SUCCESS(Status)) return Status;
1061
1062 ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
1063 : Console->OutputCodePage);
1064 ConSrvReleaseConsole(Console, TRUE);
1065 return STATUS_SUCCESS;
1066 }
1067
1068 CSR_API(SrvSetConsoleCP)
1069 {
1070 NTSTATUS Status;
1071 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
1072 PCONSOLE Console;
1073
1074 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1075 ConsoleCPRequest->InputCP ? "Input" : "Output");
1076
1077 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1078 if (!NT_SUCCESS(Status)) return Status;
1079
1080 if (IsValidCodePage(ConsoleCPRequest->CodePage))
1081 {
1082 if (ConsoleCPRequest->InputCP)
1083 Console->CodePage = ConsoleCPRequest->CodePage;
1084 else
1085 Console->OutputCodePage = ConsoleCPRequest->CodePage;
1086
1087 ConSrvReleaseConsole(Console, TRUE);
1088 return STATUS_SUCCESS;
1089 }
1090
1091 ConSrvReleaseConsole(Console, TRUE);
1092 return STATUS_INVALID_PARAMETER;
1093 }
1094
1095 CSR_API(SrvGetConsoleProcessList)
1096 {
1097 NTSTATUS Status;
1098 PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
1099 PDWORD Buffer;
1100 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1101 PCONSOLE Console;
1102 PCONSOLE_PROCESS_DATA current;
1103 PLIST_ENTRY current_entry;
1104 ULONG nItems = 0;
1105
1106 DPRINT("SrvGetConsoleProcessList\n");
1107
1108 if (!CsrValidateMessageBuffer(ApiMessage,
1109 (PVOID)&GetProcessListRequest->pProcessIds,
1110 GetProcessListRequest->nMaxIds,
1111 sizeof(DWORD)))
1112 {
1113 return STATUS_INVALID_PARAMETER;
1114 }
1115
1116 Buffer = GetProcessListRequest->pProcessIds;
1117
1118 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1119 if (!NT_SUCCESS(Status)) return Status;
1120
1121 for (current_entry = Console->ProcessList.Flink;
1122 current_entry != &Console->ProcessList;
1123 current_entry = current_entry->Flink)
1124 {
1125 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
1126 if (++nItems <= GetProcessListRequest->nMaxIds)
1127 {
1128 *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
1129 }
1130 }
1131
1132 ConSrvReleaseConsole(Console, TRUE);
1133
1134 GetProcessListRequest->nProcessIdsTotal = nItems;
1135 return STATUS_SUCCESS;
1136 }
1137
1138 CSR_API(SrvGenerateConsoleCtrlEvent)
1139 {
1140 NTSTATUS Status;
1141 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
1142 PCONSOLE Console;
1143 PCONSOLE_PROCESS_DATA current;
1144 PLIST_ENTRY current_entry;
1145 DWORD Group;
1146
1147 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1148 if (!NT_SUCCESS(Status)) return Status;
1149
1150 Group = GenerateCtrlEventRequest->ProcessGroup;
1151 Status = STATUS_INVALID_PARAMETER;
1152 for (current_entry = Console->ProcessList.Flink;
1153 current_entry != &Console->ProcessList;
1154 current_entry = current_entry->Flink)
1155 {
1156 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
1157 if (Group == 0 || current->Process->ProcessGroupId == Group)
1158 {
1159 ConSrvConsoleCtrlEvent(GenerateCtrlEventRequest->Event, current);
1160 Status = STATUS_SUCCESS;
1161 }
1162 }
1163
1164 ConSrvReleaseConsole(Console, TRUE);
1165
1166 return Status;
1167 }
1168
1169 CSR_API(SrvGetConsoleSelectionInfo)
1170 {
1171 NTSTATUS Status;
1172 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest;
1173 PCONSOLE Console;
1174
1175 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1176 if (NT_SUCCESS(Status))
1177 {
1178 memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
1179 if (Console->Selection.dwFlags != 0)
1180 GetSelectionInfoRequest->Info = Console->Selection;
1181 ConSrvReleaseConsole(Console, TRUE);
1182 }
1183
1184 return Status;
1185 }
1186
1187 /* EOF */