[CONSRV]: Reduce code duplication and remove unused InputWaitHandle member.
[reactos.git] / reactos / win32ss / user / winsrv / consrv / console.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Gé van Geldorp
7 * Jeffrey Morlan
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include "consrv.h"
14
15 #include <ndk/psfuncs.h>
16
17 /* This is for COM usage */
18 #define COBJMACROS
19 #include <shlobj.h>
20
21
22 #include <alias.h>
23 #include <history.h>
24 #include "procinit.h"
25
26 #define NDEBUG
27 #include <debug.h>
28
29 // FIXME: Add this prototype to winternl.h / rtlfuncs.h / ...
30 NTSTATUS NTAPI RtlGetLastNtStatus(VOID);
31
32 /* GLOBALS ********************************************************************/
33
34 /* The list of the ConSrv consoles */
35 static ULONG ConsoleListSize;
36 static PCONSRV_CONSOLE* ConsoleList;
37 static RTL_RESOURCE ListLock;
38
39 #define ConSrvLockConsoleListExclusive() \
40 RtlAcquireResourceExclusive(&ListLock, TRUE)
41
42 #define ConSrvLockConsoleListShared() \
43 RtlAcquireResourceShared(&ListLock, TRUE)
44
45 #define ConSrvUnlockConsoleList() \
46 RtlReleaseResource(&ListLock)
47
48
49 static NTSTATUS
50 InsertConsole(OUT PHANDLE Handle,
51 IN PCONSRV_CONSOLE Console)
52 {
53 #define CONSOLE_HANDLES_INCREMENT 2 * 3
54
55 NTSTATUS Status = STATUS_SUCCESS;
56 ULONG i = 0;
57 PCONSRV_CONSOLE* Block;
58
59 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
60 (ConsoleList != NULL && ConsoleListSize != 0) );
61
62 /* All went right, so add the console to the list */
63 ConSrvLockConsoleListExclusive();
64 DPRINT("Insert in the list\n");
65
66 if (ConsoleList)
67 {
68 for (i = 0; i < ConsoleListSize; i++)
69 {
70 if (ConsoleList[i] == NULL) break;
71 }
72 }
73
74 if (i >= ConsoleListSize)
75 {
76 DPRINT("Creation of a new handles table\n");
77 /* Allocate a new handles table */
78 Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
79 (ConsoleListSize +
80 CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSRV_CONSOLE));
81 if (Block == NULL)
82 {
83 Status = STATUS_UNSUCCESSFUL;
84 goto Quit;
85 }
86
87 /* If we previously had a handles table, free it and use the new one */
88 if (ConsoleList)
89 {
90 /* Copy the handles from the old table to the new one */
91 RtlCopyMemory(Block,
92 ConsoleList,
93 ConsoleListSize * sizeof(PCONSRV_CONSOLE));
94 ConsoleFreeHeap(ConsoleList);
95 }
96 ConsoleList = Block;
97 ConsoleListSize += CONSOLE_HANDLES_INCREMENT;
98 }
99
100 ConsoleList[i] = Console;
101 *Handle = ULongToHandle((i << 2) | 0x3);
102
103 Quit:
104 /* Unlock the console list and return status */
105 ConSrvUnlockConsoleList();
106 return Status;
107 }
108
109 /* Unused */
110 #if 0
111 static NTSTATUS
112 RemoveConsoleByHandle(IN HANDLE Handle)
113 {
114 NTSTATUS Status = STATUS_SUCCESS;
115 PCONSRV_CONSOLE Console;
116
117 BOOLEAN ValidHandle = ((HandleToULong(Handle) & 0x3) == 0x3);
118 ULONG Index = HandleToULong(Handle) >> 2;
119
120 if (!ValidHandle) return STATUS_INVALID_HANDLE;
121
122 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
123 (ConsoleList != NULL && ConsoleListSize != 0) );
124
125 /* Remove the console from the list */
126 ConSrvLockConsoleListExclusive();
127
128 if (Index >= ConsoleListSize ||
129 (Console = ConsoleList[Index]) == NULL)
130 {
131 Status = STATUS_INVALID_HANDLE;
132 goto Quit;
133 }
134
135 ConsoleList[Index] = NULL;
136
137 Quit:
138 /* Unlock the console list and return status */
139 ConSrvUnlockConsoleList();
140 return Status;
141 }
142 #endif
143
144 static NTSTATUS
145 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console)
146 {
147 ULONG i = 0;
148
149 if (!Console) return STATUS_INVALID_PARAMETER;
150
151 ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
152 (ConsoleList != NULL && ConsoleListSize != 0) );
153
154 /* Remove the console from the list */
155 ConSrvLockConsoleListExclusive();
156
157 if (ConsoleList)
158 {
159 for (i = 0; i < ConsoleListSize; i++)
160 {
161 if (ConsoleList[i] == Console) ConsoleList[i] = NULL;
162 }
163 }
164
165 /* Unlock the console list and return */
166 ConSrvUnlockConsoleList();
167 return STATUS_SUCCESS;
168 }
169
170 BOOLEAN NTAPI
171 ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console,
172 IN HANDLE ConsoleHandle,
173 IN CONSOLE_STATE ExpectedState,
174 IN BOOLEAN LockConsole)
175 {
176 BOOLEAN RetVal = FALSE;
177 PCONSRV_CONSOLE ValidatedConsole;
178
179 BOOLEAN ValidHandle = ((HandleToULong(ConsoleHandle) & 0x3) == 0x3);
180 ULONG Index = HandleToULong(ConsoleHandle) >> 2;
181
182 if (!ValidHandle) return FALSE;
183
184 if (!Console) return FALSE;
185 *Console = NULL;
186
187 /*
188 * Forbid creation or deletion of consoles when
189 * checking for the existence of a console.
190 */
191 ConSrvLockConsoleListShared();
192
193 if (Index >= ConsoleListSize ||
194 (ValidatedConsole = ConsoleList[Index]) == NULL)
195 {
196 /* Unlock the console list and return */
197 ConSrvUnlockConsoleList();
198 return FALSE;
199 }
200
201 ValidatedConsole = ConsoleList[Index];
202
203 /* Unlock the console list and return */
204 ConSrvUnlockConsoleList();
205
206 RetVal = ConDrvValidateConsoleUnsafe((PCONSOLE)ValidatedConsole,
207 ExpectedState,
208 LockConsole);
209 if (RetVal) *Console = ValidatedConsole;
210
211 return RetVal;
212 }
213
214
215 /* PRIVATE FUNCTIONS **********************************************************/
216
217 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
218 static BOOLEAN
219 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest,
220 IN PCWSTR Source)
221 {
222 SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR);
223 if (Size > MAXUSHORT) return FALSE;
224
225 UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
226 if (UniDest->Buffer == NULL) return FALSE;
227
228 RtlCopyMemory(UniDest->Buffer, Source, Size);
229 UniDest->MaximumLength = (USHORT)Size;
230 UniDest->Length = (USHORT)Size - sizeof(WCHAR);
231
232 return TRUE;
233 }
234
235 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
236 static VOID
237 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
238 {
239 if (UnicodeString->Buffer)
240 {
241 ConsoleFreeHeap(UnicodeString->Buffer);
242 RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
243 }
244 }
245
246 VOID
247 ConioPause(PCONSRV_CONSOLE Console, UINT Flags)
248 {
249 Console->PauseFlags |= Flags;
250 ConDrvPause((PCONSOLE)Console);
251 }
252
253 VOID
254 ConioUnpause(PCONSRV_CONSOLE Console, UINT Flags)
255 {
256 Console->PauseFlags &= ~Flags;
257
258 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
259 if (Console->PauseFlags == 0)
260 {
261 ConDrvUnpause((PCONSOLE)Console);
262
263 CsrNotifyWait(&Console->WriteWaitQueue,
264 TRUE,
265 NULL,
266 NULL);
267 if (!IsListEmpty(&Console->WriteWaitQueue))
268 {
269 CsrDereferenceWait(&Console->WriteWaitQueue);
270 }
271 }
272 }
273
274 NTSTATUS
275 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData,
276 OUT PCONSRV_CONSOLE* Console,
277 IN BOOLEAN LockConsole)
278 {
279 NTSTATUS Status = STATUS_INVALID_HANDLE;
280 PCONSRV_CONSOLE GrabConsole;
281
282 // if (Console == NULL) return STATUS_INVALID_PARAMETER;
283 ASSERT(Console);
284 *Console = NULL;
285
286 if (ConSrvValidateConsole(&GrabConsole,
287 ProcessData->ConsoleHandle,
288 CONSOLE_RUNNING,
289 LockConsole))
290 {
291 InterlockedIncrement(&GrabConsole->ReferenceCount);
292 *Console = GrabConsole;
293 Status = STATUS_SUCCESS;
294 }
295
296 return Status;
297 }
298
299 VOID
300 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console,
301 IN BOOLEAN WasConsoleLocked)
302 {
303 LONG RefCount = 0;
304
305 if (!Console) return;
306 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
307 ASSERT(Console->ReferenceCount > 0);
308
309 /* The console must be locked */
310 // ASSERT(Console_locked);
311
312 /*
313 * Decrement the reference count. Save the new value too,
314 * because Console->ReferenceCount might be modified after
315 * the console gets unlocked but before we check whether we
316 * can destroy it.
317 */
318 RefCount = _InterlockedDecrement(&Console->ReferenceCount);
319
320 /* Unlock the console if needed */
321 if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock);
322
323 /* Delete the console if needed */
324 if (RefCount <= 0) ConSrvDeleteConsole(Console);
325 }
326
327
328 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
329
330 VOID NTAPI
331 ConSrvInitConsoleSupport(VOID)
332 {
333 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
334
335 /* Initialize the console list and its lock */
336 ConsoleListSize = 0;
337 ConsoleList = NULL;
338 RtlInitializeResource(&ListLock);
339
340 /* Should call LoadKeyboardLayout */
341 }
342
343 NTSTATUS NTAPI
344 ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
345 IN OUT PCONSOLE_INFO ConsoleInfo,
346 IN OUT PVOID ExtraConsoleInfo,
347 IN ULONG ProcessId);
348 NTSTATUS NTAPI
349 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal);
350
351
352 static BOOL
353 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_INFO ConsoleInfo,
354 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo)
355 {
356 #define PATH_SEPARATOR L'\\'
357
358 BOOL RetVal = FALSE;
359 HRESULT hRes = S_OK;
360 SIZE_T Length = 0;
361 LPWSTR LinkName = NULL;
362 LPWSTR IconPath = NULL;
363 WCHAR Buffer[MAX_PATH + 1];
364
365 ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
366
367 if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
368 {
369 // return FALSE; // FIXME!! (for icon loading)
370 RetVal = TRUE;
371 goto Finish;
372 }
373
374 /* 1- Find the last path separator if any */
375 LinkName = wcsrchr(ConsoleInfo->ConsoleTitle, PATH_SEPARATOR);
376 if (LinkName == NULL)
377 LinkName = ConsoleInfo->ConsoleTitle;
378 else
379 ++LinkName; // Skip the path separator
380
381 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
382 Length = wcslen(LinkName);
383 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
384 return FALSE;
385
386 /* 3- It may be a link. Try to retrieve some properties */
387 hRes = CoInitialize(NULL);
388 if (SUCCEEDED(hRes))
389 {
390 /* Get a pointer to the IShellLink interface */
391 IShellLinkW* pshl = NULL;
392 hRes = CoCreateInstance(&CLSID_ShellLink,
393 NULL,
394 CLSCTX_INPROC_SERVER,
395 &IID_IShellLinkW,
396 (LPVOID*)&pshl);
397 if (SUCCEEDED(hRes))
398 {
399 /* Get a pointer to the IPersistFile interface */
400 IPersistFile* ppf = NULL;
401 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
402 if (SUCCEEDED(hRes))
403 {
404 /* Load the shortcut */
405 hRes = IPersistFile_Load(ppf, ConsoleInfo->ConsoleTitle, STGM_READ);
406 if (SUCCEEDED(hRes))
407 {
408 /*
409 * Finally we can get the properties !
410 * Update the old ones if needed.
411 */
412 INT ShowCmd = 0;
413 // WORD HotKey = 0;
414
415 /* Reset the name of the console with the name of the shortcut */
416 Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
417 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
418 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
419 ConsoleInfo->ConsoleTitle[Length] = L'\0';
420
421 /* Get the window showing command */
422 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
423 if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
424
425 /* Get the hotkey */
426 // hRes = pshl->GetHotkey(&ShowCmd);
427 // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey;
428
429 /* Get the icon location, if any */
430 hRes = IShellLinkW_GetIconLocation(pshl,
431 Buffer,
432 sizeof(Buffer)/sizeof(Buffer[0]) - 1, // == MAX_PATH
433 &ConsoleInitInfo->ConsoleStartInfo->IconIndex);
434 if (!SUCCEEDED(hRes))
435 {
436 ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
437 }
438 else
439 {
440 IconPath = Buffer;
441 }
442
443 // FIXME: Since we still don't load console properties from the shortcut,
444 // return false. When this will be done, we will return true instead.
445 RetVal = TRUE; // FALSE;
446 }
447 IPersistFile_Release(ppf);
448 }
449 IShellLinkW_Release(pshl);
450 }
451 }
452 CoUninitialize();
453
454 Finish:
455
456 if (RetVal)
457 {
458 /* Get the associated icon, if any */
459 if (IconPath == NULL)
460 {
461 // Question: How to retrieve the full path name
462 // of the app we are going to run??
463 Length = RtlDosSearchPath_U(ConsoleInitInfo->CurDir,
464 ConsoleInitInfo->AppName,
465 NULL,
466 sizeof(Buffer),
467 Buffer,
468 NULL);
469 if (Length > 0 && Length < sizeof(Buffer))
470 IconPath = Buffer;
471 else
472 IconPath = ConsoleInitInfo->AppName;
473
474 // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
475 }
476 DPRINT("IconPath = '%S' ; IconIndex = %lu\n",
477 IconPath, ConsoleInitInfo->ConsoleStartInfo->IconIndex);
478 if (IconPath && *IconPath)
479 {
480 HICON hIcon = NULL, hIconSm = NULL;
481 PrivateExtractIconExW(IconPath,
482 ConsoleInitInfo->ConsoleStartInfo->IconIndex,
483 &hIcon,
484 &hIconSm,
485 1);
486 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
487 if (hIcon != NULL) ConsoleInitInfo->ConsoleStartInfo->hIcon = hIcon;
488 if (hIconSm != NULL) ConsoleInitInfo->ConsoleStartInfo->hIconSm = hIconSm;
489 }
490 }
491
492 // FIXME: See the previous FIXME above.
493 RetVal = FALSE;
494
495 return RetVal;
496 }
497
498 NTSTATUS NTAPI
499 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
500 OUT PCONSRV_CONSOLE* NewConsole,
501 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
502 IN ULONG ConsoleLeaderProcessId)
503 {
504 NTSTATUS Status;
505 HANDLE ConsoleHandle;
506 PCONSRV_CONSOLE Console;
507 CONSOLE_INFO ConsoleInfo;
508 SIZE_T Length = 0;
509
510 TERMINAL Terminal; /* The ConSrv terminal for this console */
511
512 if (NewConsole == NULL || ConsoleInitInfo == NULL)
513 return STATUS_INVALID_PARAMETER;
514
515 *NewConsole = NULL;
516
517 /*
518 * Load the console settings
519 */
520
521 /* 1. Load the default settings */
522 ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId);
523
524 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
525 Length = min(ConsoleInitInfo->TitleLength,
526 sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
527 wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length);
528 ConsoleInfo.ConsoleTitle[Length] = L'\0'; // NULL-terminate it.
529
530 /* 3. Initialize the ConSrv terminal */
531 Status = ConSrvInitTerminal(&Terminal,
532 &ConsoleInfo,
533 ConsoleInitInfo,
534 ConsoleLeaderProcessId);
535 if (!NT_SUCCESS(Status))
536 {
537 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status);
538 return Status;
539 }
540 DPRINT("CONSRV: Terminal initialized\n");
541
542 /*
543 * Load per-application terminal settings.
544 *
545 * Check whether the process creating the console was launched via
546 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
547 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
548 */
549 // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
550 {
551 if (!LoadShellLinkConsoleInfo(&ConsoleInfo, ConsoleInitInfo))
552 {
553 ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
554 }
555 }
556
557 /*
558 * 4. Load the remaining console settings via the registry.
559 */
560 if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
561 {
562 /*
563 * Either we weren't created by an app launched via a shell-link,
564 * or we failed to load shell-link console properties.
565 * Therefore, load the console infos for the application from the registry.
566 */
567 ConSrvReadUserSettings(&ConsoleInfo, ConsoleLeaderProcessId);
568
569 /*
570 * Now, update them with the properties the user might gave to us
571 * via the STARTUPINFO structure before calling CreateProcess
572 * (and which was transmitted via the ConsoleStartInfo structure).
573 * We therefore overwrite the values read in the registry.
574 */
575 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
576 {
577 ConsoleInfo.ScreenAttrib = (USHORT)ConsoleInitInfo->ConsoleStartInfo->wFillAttribute;
578 }
579 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
580 {
581 ConsoleInfo.ScreenBufferSize = ConsoleInitInfo->ConsoleStartInfo->dwScreenBufferSize;
582 }
583 if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
584 {
585 ConsoleInfo.ConsoleSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize;
586 }
587 }
588
589 /* Set-up the code page */
590 ConsoleInfo.CodePage = GetOEMCP();
591
592 /* Initialize a new console via the driver */
593 Status = ConDrvInitConsole(&Console, &ConsoleInfo);
594 if (!NT_SUCCESS(Status))
595 {
596 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status);
597 ConSrvDeinitTerminal(&Terminal);
598 return Status;
599 }
600
601 ASSERT(Console);
602 DPRINT("Console initialized\n");
603
604 /*** Register ConSrv features ***/
605
606 /* Initialize the console title */
607 #if 0
608 WCHAR DefaultTitle[128];
609 #endif
610 ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
611 #if 0
612 if (ConsoleInfo.ConsoleTitle[0] == L'\0')
613 {
614 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0])))
615 {
616 ConsoleCreateUnicodeString(&Console->Title, DefaultTitle);
617 }
618 else
619 {
620 ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console");
621 }
622 }
623 else
624 {
625 #endif
626 ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
627 #if 0
628 }
629 #endif
630
631 /* Initialize process support */
632 InitializeListHead(&Console->ProcessList);
633 Console->NotifiedLastCloseProcess = NULL;
634 Console->NotifyLastClose = FALSE;
635
636 /* Initialize pausing support */
637 Console->PauseFlags = 0;
638 InitializeListHead(&Console->ReadWaitQueue);
639 InitializeListHead(&Console->WriteWaitQueue);
640
641 /* Initialize the alias and history buffers */
642 Console->Aliases = NULL;
643 InitializeListHead(&Console->HistoryBuffers);
644 Console->HistoryBufferSize = ConsoleInfo.HistoryBufferSize;
645 Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
646 Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
647
648 /* Initialize the Input Line Discipline */
649 Console->LineBuffer = NULL;
650 Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
651 Console->LineComplete = Console->LineUpPressed = FALSE;
652 // LineWakeupMask
653 Console->LineInsertToggle =
654 Console->InsertMode = ConsoleInfo.InsertMode;
655 Console->QuickEdit = ConsoleInfo.QuickEdit;
656
657 /* Popup windows */
658 InitializeListHead(&Console->PopupWindows);
659
660 /* Colour table */
661 memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
662
663 /* Create the Initialization Events */
664 Status = NtCreateEvent(&Console->InitEvents[INIT_SUCCESS], EVENT_ALL_ACCESS,
665 NULL, NotificationEvent, FALSE);
666 if (!NT_SUCCESS(Status))
667 {
668 DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
669 ConDrvDeleteConsole(Console);
670 ConSrvDeinitTerminal(&Terminal);
671 return Status;
672 }
673 Status = NtCreateEvent(&Console->InitEvents[INIT_FAILURE], EVENT_ALL_ACCESS,
674 NULL, NotificationEvent, FALSE);
675 if (!NT_SUCCESS(Status))
676 {
677 DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
678 NtClose(Console->InitEvents[INIT_SUCCESS]);
679 ConDrvDeleteConsole(Console);
680 ConSrvDeinitTerminal(&Terminal);
681 return Status;
682 }
683
684 /*
685 * Attach the ConSrv terminal to the console.
686 * This call makes a copy of our local Terminal variable.
687 */
688 Status = ConDrvRegisterTerminal(Console, &Terminal);
689 if (!NT_SUCCESS(Status))
690 {
691 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status);
692 NtClose(Console->InitEvents[INIT_FAILURE]);
693 NtClose(Console->InitEvents[INIT_SUCCESS]);
694 ConDrvDeleteConsole(Console);
695 ConSrvDeinitTerminal(&Terminal);
696 return Status;
697 }
698 DPRINT("Terminal registered\n");
699
700 /* All went right, so add the console to the list */
701 Status = InsertConsole(&ConsoleHandle, Console);
702
703 // FIXME! We do not support at all asynchronous console creation!
704 NtSetEvent(Console->InitEvents[INIT_SUCCESS], NULL);
705 // NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL);
706
707 /* Return the newly created console to the caller and a success code too */
708 *NewConsoleHandle = ConsoleHandle;
709 *NewConsole = Console;
710 return STATUS_SUCCESS;
711 }
712
713 VOID NTAPI
714 ConSrvDeleteConsole(PCONSRV_CONSOLE Console)
715 {
716 DPRINT("ConSrvDeleteConsole\n");
717
718 // FIXME: Send a terminate message to all the processes owning this console
719
720 /* Remove the console from the list */
721 RemoveConsoleByPointer(Console);
722
723 /* Destroy the Initialization Events */
724 NtClose(Console->InitEvents[INIT_FAILURE]);
725 NtClose(Console->InitEvents[INIT_SUCCESS]);
726
727 /* Clean the Input Line Discipline */
728 if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer);
729
730 /* Clean aliases and history */
731 IntDeleteAllAliases(Console);
732 HistoryDeleteBuffers(Console);
733
734 /* Free the console title */
735 ConsoleFreeUnicodeString(&Console->OriginalTitle);
736 ConsoleFreeUnicodeString(&Console->Title);
737
738 /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */
739 ConDrvDeleteConsole((PCONSOLE)Console);
740
741 /* Deinit the ConSrv terminal */
742 // FIXME!!
743 // ConSrvDeinitTerminal(&Terminal); // &ConSrvConsole->Console->TermIFace
744 }
745
746
747
748
749
750
751 static NTSTATUS
752 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
753 IN PCONSOLE_PROCESS_DATA ProcessData,
754 IN ULONG Timeout)
755 {
756 NTSTATUS Status = STATUS_SUCCESS;
757
758 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
759
760 if (ProcessData->CtrlRoutine)
761 {
762 _SEH2_TRY
763 {
764 HANDLE Thread = NULL;
765
766 _SEH2_TRY
767 {
768 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
769 ProcessData->CtrlRoutine,
770 UlongToPtr(CtrlEvent), 0, NULL);
771 if (NULL == Thread)
772 {
773 Status = RtlGetLastNtStatus();
774 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status);
775 }
776 else
777 {
778 DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
779 ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
780 WaitForSingleObject(Thread, Timeout);
781 }
782 }
783 _SEH2_FINALLY
784 {
785 CloseHandle(Thread);
786 }
787 _SEH2_END;
788 }
789 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
790 {
791 Status = _SEH2_GetExceptionCode();
792 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status);
793 }
794 _SEH2_END;
795 }
796
797 return Status;
798 }
799
800 NTSTATUS
801 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent,
802 IN PCONSOLE_PROCESS_DATA ProcessData)
803 {
804 return ConSrvConsoleCtrlEventTimeout(CtrlEvent, ProcessData, 0);
805 }
806
807 PCONSOLE_PROCESS_DATA NTAPI
808 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console)
809 {
810 if (Console == NULL) return NULL;
811
812 return CONTAINING_RECORD(Console->ProcessList.Blink,
813 CONSOLE_PROCESS_DATA,
814 ConsoleLink);
815 }
816
817 NTSTATUS NTAPI
818 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console,
819 IN OUT PULONG ProcessIdsList,
820 IN ULONG MaxIdListItems,
821 OUT PULONG ProcessIdsTotal)
822 {
823 PCONSOLE_PROCESS_DATA current;
824 PLIST_ENTRY current_entry;
825
826 if (Console == NULL || ProcessIdsList == NULL || ProcessIdsTotal == NULL)
827 return STATUS_INVALID_PARAMETER;
828
829 *ProcessIdsTotal = 0;
830
831 for (current_entry = Console->ProcessList.Flink;
832 current_entry != &Console->ProcessList;
833 current_entry = current_entry->Flink)
834 {
835 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
836 if (++(*ProcessIdsTotal) <= MaxIdListItems)
837 {
838 *ProcessIdsList++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
839 }
840 }
841
842 return STATUS_SUCCESS;
843 }
844
845 // ConSrvGenerateConsoleCtrlEvent
846 NTSTATUS NTAPI
847 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console,
848 IN ULONG ProcessGroupId,
849 IN ULONG CtrlEvent)
850 {
851 NTSTATUS Status = STATUS_SUCCESS;
852 PLIST_ENTRY current_entry;
853 PCONSOLE_PROCESS_DATA current;
854
855 /* If the console is already being destroyed, just return */
856 if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING))
857 return STATUS_UNSUCCESSFUL;
858
859 /*
860 * Loop through the process list, from the most recent process
861 * (the active one) to the oldest one (the first created, i.e.
862 * the console leader process), and for each, send an event
863 * (new processes are inserted at the head of the console process list).
864 */
865 current_entry = Console->ProcessList.Flink;
866 while (current_entry != &Console->ProcessList)
867 {
868 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
869 current_entry = current_entry->Flink;
870
871 /*
872 * Only processes belonging to the same process group are signaled.
873 * If the process group ID is zero, then all the processes are signaled.
874 */
875 if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId)
876 {
877 Status = ConSrvConsoleCtrlEvent(CtrlEvent, current);
878 }
879 }
880
881 return Status;
882 }
883
884
885 /* PUBLIC SERVER APIS *********************************************************/
886
887 CSR_API(SrvAllocConsole)
888 {
889 NTSTATUS Status = STATUS_SUCCESS;
890 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
891 PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
892 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
893 CONSOLE_INIT_INFO ConsoleInitInfo;
894
895 if (ProcessData->ConsoleHandle != NULL)
896 {
897 DPRINT1("Process already has a console\n");
898 return STATUS_ACCESS_DENIED;
899 }
900
901 if ( !CsrValidateMessageBuffer(ApiMessage,
902 (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
903 1,
904 sizeof(CONSOLE_START_INFO)) ||
905 !CsrValidateMessageBuffer(ApiMessage,
906 (PVOID*)&AllocConsoleRequest->ConsoleTitle,
907 AllocConsoleRequest->TitleLength,
908 sizeof(BYTE)) ||
909 !CsrValidateMessageBuffer(ApiMessage,
910 (PVOID*)&AllocConsoleRequest->Desktop,
911 AllocConsoleRequest->DesktopLength,
912 sizeof(BYTE)) ||
913 !CsrValidateMessageBuffer(ApiMessage,
914 (PVOID*)&AllocConsoleRequest->CurDir,
915 AllocConsoleRequest->CurDirLength,
916 sizeof(BYTE)) ||
917 !CsrValidateMessageBuffer(ApiMessage,
918 (PVOID*)&AllocConsoleRequest->AppName,
919 AllocConsoleRequest->AppNameLength,
920 sizeof(BYTE)) )
921 {
922 return STATUS_INVALID_PARAMETER;
923 }
924
925 /* Initialize the console initialization info structure */
926 ConsoleInitInfo.ConsoleStartInfo = AllocConsoleRequest->ConsoleStartInfo;
927 ConsoleInitInfo.TitleLength = AllocConsoleRequest->TitleLength;
928 ConsoleInitInfo.ConsoleTitle = AllocConsoleRequest->ConsoleTitle;
929 ConsoleInitInfo.DesktopLength = AllocConsoleRequest->DesktopLength;
930 ConsoleInitInfo.Desktop = AllocConsoleRequest->Desktop;
931 ConsoleInitInfo.AppNameLength = AllocConsoleRequest->AppNameLength;
932 ConsoleInitInfo.AppName = AllocConsoleRequest->AppName;
933 ConsoleInitInfo.CurDirLength = AllocConsoleRequest->CurDirLength;
934 ConsoleInitInfo.CurDir = AllocConsoleRequest->CurDir;
935
936 /* Initialize a new Console owned by the Console Leader Process */
937 Status = ConSrvAllocateConsole(ProcessData,
938 &AllocConsoleRequest->ConsoleStartInfo->InputHandle,
939 &AllocConsoleRequest->ConsoleStartInfo->OutputHandle,
940 &AllocConsoleRequest->ConsoleStartInfo->ErrorHandle,
941 &ConsoleInitInfo);
942 if (!NT_SUCCESS(Status))
943 {
944 DPRINT1("Console allocation failed\n");
945 return Status;
946 }
947
948 /* Set the Property-Dialog and Control-Dispatcher handlers */
949 ProcessData->PropRoutine = AllocConsoleRequest->PropRoutine;
950 ProcessData->CtrlRoutine = AllocConsoleRequest->CtrlRoutine;
951
952 return STATUS_SUCCESS;
953 }
954
955 CSR_API(SrvAttachConsole)
956 {
957 NTSTATUS Status = STATUS_SUCCESS;
958 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
959 PCSR_PROCESS SourceProcess = NULL; // The parent process.
960 PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
961 HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
962 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
963
964 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
965
966 if (TargetProcessData->ConsoleHandle != NULL)
967 {
968 DPRINT1("Process already has a console\n");
969 return STATUS_ACCESS_DENIED;
970 }
971
972 if (!CsrValidateMessageBuffer(ApiMessage,
973 (PVOID*)&AttachConsoleRequest->ConsoleStartInfo,
974 1,
975 sizeof(CONSOLE_START_INFO)))
976 {
977 return STATUS_INVALID_PARAMETER;
978 }
979
980 /* Check whether we try to attach to the parent's console */
981 if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
982 {
983 PROCESS_BASIC_INFORMATION ProcessInfo;
984 ULONG Length = sizeof(ProcessInfo);
985
986 /* Get the real parent's ID */
987
988 Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
989 ProcessBasicInformation,
990 &ProcessInfo,
991 Length, &Length);
992 if (!NT_SUCCESS(Status))
993 {
994 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
995 return Status;
996 }
997
998 ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
999 }
1000
1001 /* Lock the source process via its PID */
1002 Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
1003 if (!NT_SUCCESS(Status)) return Status;
1004
1005 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
1006
1007 if (SourceProcessData->ConsoleHandle == NULL)
1008 {
1009 Status = STATUS_INVALID_HANDLE;
1010 goto Quit;
1011 }
1012
1013 /*
1014 * Inherit the console from the parent,
1015 * if any, otherwise return an error.
1016 */
1017 Status = ConSrvInheritConsole(TargetProcessData,
1018 SourceProcessData->ConsoleHandle,
1019 TRUE,
1020 &AttachConsoleRequest->ConsoleStartInfo->InputHandle,
1021 &AttachConsoleRequest->ConsoleStartInfo->OutputHandle,
1022 &AttachConsoleRequest->ConsoleStartInfo->ErrorHandle,
1023 AttachConsoleRequest->ConsoleStartInfo);
1024 if (!NT_SUCCESS(Status))
1025 {
1026 DPRINT1("Console inheritance failed\n");
1027 goto Quit;
1028 }
1029
1030 /* Set the Property-Dialog and Control-Dispatcher handlers */
1031 TargetProcessData->PropRoutine = AttachConsoleRequest->PropRoutine;
1032 TargetProcessData->CtrlRoutine = AttachConsoleRequest->CtrlRoutine;
1033
1034 Status = STATUS_SUCCESS;
1035
1036 Quit:
1037 /* Unlock the "source" process and exit */
1038 CsrUnlockProcess(SourceProcess);
1039 return Status;
1040 }
1041
1042 CSR_API(SrvFreeConsole)
1043 {
1044 return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
1045 }
1046
1047 NTSTATUS NTAPI
1048 ConDrvGetConsoleMode(IN PCONSOLE Console,
1049 IN PCONSOLE_IO_OBJECT Object,
1050 OUT PULONG ConsoleMode);
1051 CSR_API(SrvGetConsoleMode)
1052 {
1053 NTSTATUS Status;
1054 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
1055 PCONSOLE_IO_OBJECT Object;
1056
1057 PULONG ConsoleMode = &ConsoleModeRequest->Mode;
1058
1059 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1060 ConsoleModeRequest->Handle,
1061 &Object, NULL, GENERIC_READ, TRUE, 0);
1062 if (!NT_SUCCESS(Status)) return Status;
1063
1064 /* Get the standard console modes */
1065 Status = ConDrvGetConsoleMode(Object->Console, Object,
1066 ConsoleMode);
1067 if (NT_SUCCESS(Status))
1068 {
1069 /*
1070 * If getting the console modes succeeds, then retrieve
1071 * the extended CONSRV-specific input modes.
1072 */
1073 if (INPUT_BUFFER == Object->Type)
1074 {
1075 if (Object->Console->InsertMode || Object->Console->QuickEdit)
1076 {
1077 /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
1078 *ConsoleMode |= ENABLE_EXTENDED_FLAGS;
1079
1080 if (Object->Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
1081 if (Object->Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
1082 }
1083 }
1084 }
1085
1086 ConSrvReleaseObject(Object, TRUE);
1087 return Status;
1088 }
1089
1090 NTSTATUS NTAPI
1091 ConDrvSetConsoleMode(IN PCONSOLE Console,
1092 IN PCONSOLE_IO_OBJECT Object,
1093 IN ULONG ConsoleMode);
1094 CSR_API(SrvSetConsoleMode)
1095 {
1096 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
1097 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1098
1099 NTSTATUS Status;
1100 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
1101 PCONSOLE_IO_OBJECT Object;
1102
1103 ULONG ConsoleMode = ConsoleModeRequest->Mode;
1104
1105 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1106 ConsoleModeRequest->Handle,
1107 &Object, NULL, GENERIC_WRITE, TRUE, 0);
1108 if (!NT_SUCCESS(Status)) return Status;
1109
1110 /* Set the standard console modes (without the CONSRV-specific input modes) */
1111 ConsoleMode &= ~CONSOLE_VALID_CONTROL_MODES; // Remove CONSRV-specific input modes.
1112 Status = ConDrvSetConsoleMode(Object->Console, Object,
1113 ConsoleMode);
1114 if (NT_SUCCESS(Status))
1115 {
1116 /*
1117 * If setting the console modes succeeds, then set
1118 * the extended CONSRV-specific input modes.
1119 */
1120 if (INPUT_BUFFER == Object->Type)
1121 {
1122 ConsoleMode = ConsoleModeRequest->Mode;
1123
1124 if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
1125 {
1126 /*
1127 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1128 * then consider the flags invalid.
1129 */
1130 if ((ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0)
1131 {
1132 Status = STATUS_INVALID_PARAMETER;
1133 }
1134 else
1135 {
1136 Object->Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
1137 Object->Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
1138 }
1139 }
1140 }
1141 }
1142
1143 ConSrvReleaseObject(Object, TRUE);
1144 return Status;
1145 }
1146
1147 CSR_API(SrvGetConsoleTitle)
1148 {
1149 NTSTATUS Status;
1150 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
1151 PCONSRV_CONSOLE Console;
1152 ULONG Length;
1153
1154 if (!CsrValidateMessageBuffer(ApiMessage,
1155 (PVOID)&TitleRequest->Title,
1156 TitleRequest->Length,
1157 sizeof(BYTE)))
1158 {
1159 return STATUS_INVALID_PARAMETER;
1160 }
1161
1162 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1163 if (!NT_SUCCESS(Status))
1164 {
1165 DPRINT1("Can't get console\n");
1166 return Status;
1167 }
1168
1169 /* Copy title of the console to the user title buffer */
1170 if (TitleRequest->Unicode)
1171 {
1172 if (TitleRequest->Length >= sizeof(WCHAR))
1173 {
1174 Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
1175 RtlCopyMemory(TitleRequest->Title, Console->Title.Buffer, Length);
1176 ((PWCHAR)TitleRequest->Title)[Length / sizeof(WCHAR)] = L'\0';
1177 TitleRequest->Length = Length;
1178 }
1179 else
1180 {
1181 TitleRequest->Length = Console->Title.Length;
1182 }
1183 }
1184 else
1185 {
1186 if (TitleRequest->Length >= sizeof(CHAR))
1187 {
1188 Length = min(TitleRequest->Length - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
1189 Length = WideCharToMultiByte(Console->InputCodePage, 0,
1190 Console->Title.Buffer, Length,
1191 TitleRequest->Title, Length,
1192 NULL, NULL);
1193 ((PCHAR)TitleRequest->Title)[Length] = '\0';
1194 TitleRequest->Length = Length;
1195 }
1196 else
1197 {
1198 TitleRequest->Length = Console->Title.Length / sizeof(WCHAR);
1199 }
1200 }
1201
1202 ConSrvReleaseConsole(Console, TRUE);
1203 return Status;
1204 }
1205
1206 CSR_API(SrvSetConsoleTitle)
1207 {
1208 NTSTATUS Status;
1209 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
1210 PCONSRV_CONSOLE Console;
1211
1212 PWCHAR Buffer;
1213 ULONG Length;
1214
1215 if (!CsrValidateMessageBuffer(ApiMessage,
1216 (PVOID)&TitleRequest->Title,
1217 TitleRequest->Length,
1218 sizeof(BYTE)))
1219 {
1220 return STATUS_INVALID_PARAMETER;
1221 }
1222
1223 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1224 if (!NT_SUCCESS(Status))
1225 {
1226 DPRINT1("Can't get console\n");
1227 return Status;
1228 }
1229
1230 if (TitleRequest->Unicode)
1231 {
1232 /* Length is in bytes */
1233 Length = TitleRequest->Length;
1234 }
1235 else
1236 {
1237 /* Use the console input CP for the conversion */
1238 Length = MultiByteToWideChar(Console->InputCodePage, 0,
1239 TitleRequest->Title, TitleRequest->Length,
1240 NULL, 0);
1241 /* The returned Length was in number of wchars, convert it in bytes */
1242 Length *= sizeof(WCHAR);
1243 }
1244
1245 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1246 Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
1247 if (!Buffer)
1248 {
1249 Status = STATUS_NO_MEMORY;
1250 goto Quit;
1251 }
1252
1253 /* Free the old title */
1254 ConsoleFreeUnicodeString(&Console->Title);
1255
1256 /* Copy title to console */
1257 Console->Title.Buffer = Buffer;
1258 Console->Title.Length = Length;
1259 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
1260
1261 if (TitleRequest->Unicode)
1262 {
1263 RtlCopyMemory(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length);
1264 }
1265 else
1266 {
1267 MultiByteToWideChar(Console->InputCodePage, 0,
1268 TitleRequest->Title, TitleRequest->Length,
1269 Console->Title.Buffer,
1270 Console->Title.Length / sizeof(WCHAR));
1271 }
1272
1273 /* NULL-terminate */
1274 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1275
1276 TermChangeTitle(Console);
1277 Status = STATUS_SUCCESS;
1278
1279 Quit:
1280 ConSrvReleaseConsole(Console, TRUE);
1281 return Status;
1282 }
1283
1284 NTSTATUS NTAPI
1285 ConDrvGetConsoleCP(IN PCONSOLE Console,
1286 OUT PUINT CodePage,
1287 IN BOOLEAN OutputCP);
1288 CSR_API(SrvGetConsoleCP)
1289 {
1290 NTSTATUS Status;
1291 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCPRequest;
1292 PCONSRV_CONSOLE Console;
1293
1294 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1295 GetConsoleCPRequest->OutputCP ? "Output" : "Input");
1296
1297 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1298 if (!NT_SUCCESS(Status)) return Status;
1299
1300 Status = ConDrvGetConsoleCP(Console,
1301 &GetConsoleCPRequest->CodePage,
1302 GetConsoleCPRequest->OutputCP);
1303
1304 ConSrvReleaseConsole(Console, TRUE);
1305 return Status;
1306 }
1307
1308 NTSTATUS NTAPI
1309 ConDrvSetConsoleCP(IN PCONSOLE Console,
1310 IN UINT CodePage,
1311 IN BOOLEAN OutputCP);
1312 CSR_API(SrvSetConsoleCP)
1313 {
1314 NTSTATUS Status = STATUS_INVALID_PARAMETER;
1315 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCPRequest;
1316 PCONSRV_CONSOLE Console;
1317
1318 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1319 SetConsoleCPRequest->OutputCP ? "Output" : "Input");
1320
1321 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1322 if (!NT_SUCCESS(Status)) return Status;
1323
1324 Status = ConDrvSetConsoleCP(Console,
1325 SetConsoleCPRequest->CodePage,
1326 SetConsoleCPRequest->OutputCP);
1327
1328 ConSrvReleaseConsole(Console, TRUE);
1329 return Status;
1330 }
1331
1332 CSR_API(SrvGetConsoleProcessList)
1333 {
1334 NTSTATUS Status;
1335 PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
1336 PCONSRV_CONSOLE Console;
1337
1338 if (!CsrValidateMessageBuffer(ApiMessage,
1339 (PVOID)&GetProcessListRequest->ProcessIdsList,
1340 GetProcessListRequest->ProcessCount,
1341 sizeof(DWORD)))
1342 {
1343 return STATUS_INVALID_PARAMETER;
1344 }
1345
1346 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1347 if (!NT_SUCCESS(Status)) return Status;
1348
1349 Status = ConSrvGetConsoleProcessList(Console,
1350 GetProcessListRequest->ProcessIdsList,
1351 GetProcessListRequest->ProcessCount,
1352 &GetProcessListRequest->ProcessCount);
1353
1354 ConSrvReleaseConsole(Console, TRUE);
1355 return Status;
1356 }
1357
1358 CSR_API(SrvGenerateConsoleCtrlEvent)
1359 {
1360 NTSTATUS Status;
1361 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
1362 PCONSRV_CONSOLE Console;
1363
1364 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1365 if (!NT_SUCCESS(Status)) return Status;
1366
1367 Status = ConSrvConsoleProcessCtrlEvent(Console,
1368 GenerateCtrlEventRequest->ProcessGroupId,
1369 GenerateCtrlEventRequest->CtrlEvent);
1370
1371 ConSrvReleaseConsole(Console, TRUE);
1372 return Status;
1373 }
1374
1375 CSR_API(SrvConsoleNotifyLastClose)
1376 {
1377 NTSTATUS Status;
1378 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
1379 PCONSRV_CONSOLE Console;
1380
1381 Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
1382 if (!NT_SUCCESS(Status)) return Status;
1383
1384 /* Only one process is allowed to be registered for last close notification */
1385 if (!Console->NotifyLastClose)
1386 {
1387 Console->NotifyLastClose = TRUE;
1388 Console->NotifiedLastCloseProcess = ProcessData;
1389 Status = STATUS_SUCCESS;
1390 }
1391 else
1392 {
1393 Status = STATUS_ACCESS_DENIED;
1394 }
1395
1396 ConSrvReleaseConsole(Console, TRUE);
1397 return Status;
1398 }
1399
1400
1401
1402 CSR_API(SrvGetConsoleMouseInfo)
1403 {
1404 NTSTATUS Status;
1405 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetMouseInfoRequest;
1406 PCONSRV_CONSOLE Console;
1407
1408 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1409 if (!NT_SUCCESS(Status)) return Status;
1410
1411 /* Just retrieve the number of buttons of the mouse attached to this console */
1412 GetMouseInfoRequest->NumButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
1413
1414 ConSrvReleaseConsole(Console, TRUE);
1415 return STATUS_SUCCESS;
1416 }
1417
1418 CSR_API(SrvSetConsoleKeyShortcuts)
1419 {
1420 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1421 return STATUS_NOT_IMPLEMENTED;
1422 }
1423
1424 CSR_API(SrvGetConsoleKeyboardLayoutName)
1425 {
1426 NTSTATUS Status;
1427 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetKbdLayoutNameRequest;
1428 PCONSRV_CONSOLE Console;
1429
1430 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1431 if (!NT_SUCCESS(Status)) return Status;
1432
1433 /* Retrieve the keyboard layout name of the system */
1434 if (GetKbdLayoutNameRequest->Ansi)
1435 GetKeyboardLayoutNameA((PCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
1436 else
1437 GetKeyboardLayoutNameW((PWCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
1438
1439 ConSrvReleaseConsole(Console, TRUE);
1440 return STATUS_SUCCESS;
1441 }
1442
1443 CSR_API(SrvGetConsoleCharType)
1444 {
1445 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1446 return STATUS_NOT_IMPLEMENTED;
1447 }
1448
1449 CSR_API(SrvSetConsoleLocalEUDC)
1450 {
1451 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1452 return STATUS_NOT_IMPLEMENTED;
1453 }
1454
1455 CSR_API(SrvSetConsoleCursorMode)
1456 {
1457 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1458 return STATUS_NOT_IMPLEMENTED;
1459 }
1460
1461 CSR_API(SrvGetConsoleCursorMode)
1462 {
1463 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1464 return STATUS_NOT_IMPLEMENTED;
1465 }
1466
1467 CSR_API(SrvGetConsoleNlsMode)
1468 {
1469 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1470 return STATUS_NOT_IMPLEMENTED;
1471 }
1472
1473 CSR_API(SrvSetConsoleNlsMode)
1474 {
1475 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1476 return STATUS_NOT_IMPLEMENTED;
1477 }
1478
1479 CSR_API(SrvGetConsoleLangId)
1480 {
1481 DPRINT1("%s not yet implemented\n", __FUNCTION__);
1482 return STATUS_NOT_IMPLEMENTED;
1483 }
1484
1485 /* EOF */