Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/kernel32/client/console/init.c * PURPOSE: Console API Client Initialization * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Aleksey Bragin (aleksey@reactos.org) * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */
/* INCLUDES *******************************************************************/
#include <k32.h>
// For Control Panel Applet#include <cpl.h>
#define NDEBUG#include <debug.h>
/* GLOBALS ********************************************************************/
RTL_CRITICAL_SECTION ConsoleLock;BOOLEAN ConsoleInitialized = FALSE;extern HANDLE InputWaitHandle;
static const PWSTR DefaultConsoleTitle = L"ReactOS Console";
/* FUNCTIONS ******************************************************************/
DWORDWINAPIPropDialogHandler(IN LPVOID lpThreadParameter){ // NOTE: lpThreadParameter corresponds to the client shared section handle.
NTSTATUS Status = STATUS_SUCCESS; HMODULE hConsoleApplet = NULL; APPLET_PROC CPlApplet; static BOOL AlreadyDisplayingProps = FALSE; WCHAR szBuffer[MAX_PATH];
/* * Do not launch more than once the console property dialog applet, * or (albeit less probable), if we are not initialized. */ if (!ConsoleInitialized || AlreadyDisplayingProps) { /* Close the associated client shared section handle if needed */ if (lpThreadParameter) CloseHandle((HANDLE)lpThreadParameter);
return STATUS_UNSUCCESSFUL; }
AlreadyDisplayingProps = TRUE;
/* Load the control applet */ GetSystemDirectoryW(szBuffer, MAX_PATH); wcscat(szBuffer, L"\\console.dll"); hConsoleApplet = LoadLibraryW(szBuffer); if (hConsoleApplet == NULL) { DPRINT1("Failed to load console.dll\n"); Status = STATUS_UNSUCCESSFUL; goto Quit; }
/* Load its main function */ CPlApplet = (APPLET_PROC)GetProcAddress(hConsoleApplet, "CPlApplet"); if (CPlApplet == NULL) { DPRINT1("Error: console.dll misses CPlApplet export\n"); Status = STATUS_UNSUCCESSFUL; goto Quit; }
/* Initialize the applet */ if (CPlApplet(NULL, CPL_INIT, 0, 0) == FALSE) { DPRINT1("Error: failed to initialize console.dll\n"); Status = STATUS_UNSUCCESSFUL; goto Quit; }
/* Check the count */ if (CPlApplet(NULL, CPL_GETCOUNT, 0, 0) != 1) { DPRINT1("Error: console.dll returned unexpected CPL count\n"); Status = STATUS_UNSUCCESSFUL; goto Quit; }
/* * Start the applet. For Windows compatibility purposes we need * to pass the client shared section handle (lpThreadParameter) * via the hWnd parameter of the CPlApplet function. */ CPlApplet((HWND)lpThreadParameter, CPL_DBLCLK, 0, 0);
/* We have finished */ CPlApplet(NULL, CPL_EXIT, 0, 0);
Quit: if (hConsoleApplet) FreeLibrary(hConsoleApplet); AlreadyDisplayingProps = FALSE; return Status;}
static INTParseShellInfo(LPCWSTR lpszShellInfo, LPCWSTR lpszKeyword){ DPRINT("ParseShellInfo is UNIMPLEMENTED\n"); return 0;}
/* * NOTE: * The "LPDWORD Length" parameters point on input to the maximum size of * the buffers that can hold data (if != 0), and on output they hold the * real size of the data. If "Length" are == 0 on input, then on output * they receive the full size of the data. * The "LPWSTR* lpTitle" parameter has a double meaning: * - when "CaptureTitle" is TRUE, data is copied to the buffer pointed * by the pointer (*lpTitle). * - when "CaptureTitle" is FALSE, "*lpTitle" is set to the address of * the source data. */VOIDSetUpConsoleInfo(IN BOOLEAN CaptureTitle, IN OUT LPDWORD pTitleLength, IN OUT LPWSTR* lpTitle OPTIONAL, IN OUT LPDWORD pDesktopLength, IN OUT LPWSTR* lpDesktop OPTIONAL, IN OUT PCONSOLE_START_INFO ConsoleStartInfo){ PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; DWORD Length;
/* Initialize the fields */
ConsoleStartInfo->IconIndex = 0; ConsoleStartInfo->hIcon = NULL; ConsoleStartInfo->hIconSm = NULL; ConsoleStartInfo->dwStartupFlags = Parameters->WindowFlags; ConsoleStartInfo->nFont = 0; ConsoleStartInfo->nInputBufferSize = 0; ConsoleStartInfo->uCodePage = GetOEMCP();
if (lpTitle) { LPWSTR Title;
/* If we don't have any title, use the default one */ if (Parameters->WindowTitle.Buffer == NULL) { Title = DefaultConsoleTitle; Length = lstrlenW(DefaultConsoleTitle) * sizeof(WCHAR); // sizeof(DefaultConsoleTitle); } else { Title = Parameters->WindowTitle.Buffer; Length = Parameters->WindowTitle.Length; }
/* Retrieve the needed buffer size */ Length += sizeof(WCHAR); if (*pTitleLength > 0) Length = min(Length, *pTitleLength); *pTitleLength = Length;
/* Capture the data if needed, or, return a pointer to it */ if (CaptureTitle) { /* * Length is always >= sizeof(WCHAR). Copy everything but the * possible trailing NULL character, and then NULL-terminate. */ Length -= sizeof(WCHAR); RtlCopyMemory(*lpTitle, Title, Length); (*lpTitle)[Length / sizeof(WCHAR)] = UNICODE_NULL; } else { *lpTitle = Title; } } else { *pTitleLength = 0; }
if (lpDesktop && Parameters->DesktopInfo.Buffer && *Parameters->DesktopInfo.Buffer) { /* Retrieve the needed buffer size */ Length = Parameters->DesktopInfo.Length + sizeof(WCHAR); if (*pDesktopLength > 0) Length = min(Length, *pDesktopLength); *pDesktopLength = Length;
/* Return a pointer to the data */ *lpDesktop = Parameters->DesktopInfo.Buffer; } else { *pDesktopLength = 0; if (lpDesktop) *lpDesktop = NULL; }
if (Parameters->WindowFlags & STARTF_USEFILLATTRIBUTE) { ConsoleStartInfo->wFillAttribute = (WORD)Parameters->FillAttribute; } if (Parameters->WindowFlags & STARTF_USECOUNTCHARS) { ConsoleStartInfo->dwScreenBufferSize.X = (SHORT)Parameters->CountCharsX; ConsoleStartInfo->dwScreenBufferSize.Y = (SHORT)Parameters->CountCharsY; } if (Parameters->WindowFlags & STARTF_USESHOWWINDOW) { ConsoleStartInfo->wShowWindow = (WORD)Parameters->ShowWindowFlags; } if (Parameters->WindowFlags & STARTF_USEPOSITION) { ConsoleStartInfo->dwWindowOrigin.X = (SHORT)Parameters->StartingX; ConsoleStartInfo->dwWindowOrigin.Y = (SHORT)Parameters->StartingY; } if (Parameters->WindowFlags & STARTF_USESIZE) { ConsoleStartInfo->dwWindowSize.X = (SHORT)Parameters->CountX; ConsoleStartInfo->dwWindowSize.Y = (SHORT)Parameters->CountY; }
/* Get shell information (ShellInfo.Buffer is NULL-terminated) */ if (Parameters->ShellInfo.Buffer != NULL) { ConsoleStartInfo->IconIndex = ParseShellInfo(Parameters->ShellInfo.Buffer, L"dde.");
if ((Parameters->WindowFlags & STARTF_USEHOTKEY) == 0) ConsoleStartInfo->dwHotKey = ParseShellInfo(Parameters->ShellInfo.Buffer, L"hotkey."); else ConsoleStartInfo->dwHotKey = HandleToUlong(Parameters->StandardInput); }}
VOIDSetUpHandles(IN PCONSOLE_START_INFO ConsoleStartInfo){ PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
if (ConsoleStartInfo->dwStartupFlags & STARTF_USEHOTKEY) { Parameters->WindowFlags &= ~STARTF_USEHOTKEY; } if (ConsoleStartInfo->dwStartupFlags & STARTF_SHELLPRIVATE) { Parameters->WindowFlags &= ~STARTF_SHELLPRIVATE; }
/* We got the handles, let's set them */ Parameters->ConsoleHandle = ConsoleStartInfo->ConsoleHandle;
if ((ConsoleStartInfo->dwStartupFlags & STARTF_USESTDHANDLES) == 0) { Parameters->StandardInput = ConsoleStartInfo->InputHandle; Parameters->StandardOutput = ConsoleStartInfo->OutputHandle; Parameters->StandardError = ConsoleStartInfo->ErrorHandle; }}
static BOOLEANIsConsoleApp(VOID){ PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); return (ImageNtHeader && (ImageNtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI));}
static BOOLEANConnectConsole(IN PWSTR SessionDir, IN PCONSRV_API_CONNECTINFO ConnectInfo, OUT PBOOLEAN InServerProcess){ NTSTATUS Status; ULONG ConnectInfoSize = sizeof(*ConnectInfo);
ASSERT(SessionDir);
/* Connect to the Console Server */ DPRINT("Connecting to the Console Server...\n"); Status = CsrClientConnectToServer(SessionDir, CONSRV_SERVERDLL_INDEX, ConnectInfo, &ConnectInfoSize, InServerProcess); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status); return FALSE; }
/* Nothing to do for server-to-server */ if (*InServerProcess) return TRUE;
/* Nothing to do if this is not a console app */ if (!ConnectInfo->IsConsoleApp) return TRUE;
/* Wait for the connection to finish */ // Is ConnectInfo->ConsoleStartInfo.InitEvents aligned on handle boundary ???? Status = NtWaitForMultipleObjects(MAX_INIT_EVENTS, ConnectInfo->ConsoleStartInfo.InitEvents, WaitAny, FALSE, NULL); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return FALSE; }
NtClose(ConnectInfo->ConsoleStartInfo.InitEvents[INIT_SUCCESS]); NtClose(ConnectInfo->ConsoleStartInfo.InitEvents[INIT_FAILURE]); if (Status != INIT_SUCCESS) { NtCurrentPeb()->ProcessParameters->ConsoleHandle = NULL; return FALSE; }
return TRUE;}
BOOLEANWINAPIConDllInitialize(IN ULONG Reason, IN PWSTR SessionDir){ NTSTATUS Status; PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; BOOLEAN InServerProcess = FALSE; CONSRV_API_CONNECTINFO ConnectInfo;
if (Reason != DLL_PROCESS_ATTACH) { if ((Reason == DLL_THREAD_ATTACH) && IsConsoleApp()) { /* Sync the new thread's LangId with the console's one */ SetTEBLangID(); } else if (Reason == DLL_PROCESS_DETACH) { /* Free our resources */ if (ConsoleInitialized != FALSE) { ConsoleInitialized = FALSE; RtlDeleteCriticalSection(&ConsoleLock); } }
return TRUE; }
DPRINT("ConDllInitialize for: %wZ\n" "Our current console handles are: 0x%p, 0x%p, 0x%p 0x%p\n", &Parameters->ImagePathName, Parameters->ConsoleHandle, Parameters->StandardInput, Parameters->StandardOutput, Parameters->StandardError);
/* Initialize our global console DLL lock */ Status = RtlInitializeCriticalSection(&ConsoleLock); if (!NT_SUCCESS(Status)) return FALSE; ConsoleInitialized = TRUE;
/* Show by default the console window when applicable */ ConnectInfo.IsWindowVisible = TRUE; /* If this is a console app, a console will be created/opened */ ConnectInfo.IsConsoleApp = IsConsoleApp();
/* Do nothing if this is not a console app... */ if (!ConnectInfo.IsConsoleApp) { DPRINT("Image is not a console application\n"); }
/* * Handle the special flags given to us by BasePushProcessParameters. */ if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS) { /* No console to create */ DPRINT("No console to create\n"); /* * The new process does not inherit its parent's console and cannot * attach to the console of its parent. The new process can call the * AllocConsole function at a later time to create a console. */ Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. ConnectInfo.IsConsoleApp = FALSE; // Do not create any console. } else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE) { /* We'll get the real one soon */ DPRINT("Creating a new separate console\n"); /* * The new process has a new console, instead of inheriting * its parent's console. */ Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. } else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW) { /* We'll get the real one soon */ DPRINT("Creating a new invisible console\n"); /* * The process is a console application that is being run * without a console window. Therefore, the console handle * for the application is not set. */ Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. ConnectInfo.IsWindowVisible = FALSE; // A console is created but is not shown to the user. } else { DPRINT("Using existing console: 0x%p\n", Parameters->ConsoleHandle); }
/* Do nothing if this is not a console app... */ if (!ConnectInfo.IsConsoleApp) { /* Do not inherit the parent's console if we are not a console app */ Parameters->ConsoleHandle = NULL; }
/* Now use the proper console handle */ ConnectInfo.ConsoleStartInfo.ConsoleHandle = Parameters->ConsoleHandle;
/* Initialize the console dispatchers */ ConnectInfo.CtrlRoutine = ConsoleControlDispatcher; ConnectInfo.PropRoutine = PropDialogHandler; // ConnectInfo.ImeRoutine = ImeRoutine;
/* Set up the console properties */ if (ConnectInfo.IsConsoleApp && Parameters->ConsoleHandle == NULL) { /* * We can set up the console properties only if we create a new one * (we do not inherit it from our parent). */
LPWSTR ConsoleTitle = ConnectInfo.ConsoleTitle;
ConnectInfo.TitleLength = sizeof(ConnectInfo.ConsoleTitle); ConnectInfo.DesktopLength = 0; // SetUpConsoleInfo will give us the real length.
SetUpConsoleInfo(TRUE, &ConnectInfo.TitleLength, &ConsoleTitle, &ConnectInfo.DesktopLength, &ConnectInfo.Desktop, &ConnectInfo.ConsoleStartInfo); DPRINT("ConsoleTitle = '%S' - Desktop = '%S'\n", ConsoleTitle, ConnectInfo.Desktop); } else { ConnectInfo.TitleLength = 0; ConnectInfo.DesktopLength = 0; }
/* Initialize the Input EXE name */ if (ConnectInfo.IsConsoleApp) { LPWSTR CurDir = ConnectInfo.CurDir; LPWSTR AppName = ConnectInfo.AppName;
InitExeName();
ConnectInfo.CurDirLength = sizeof(ConnectInfo.CurDir); ConnectInfo.AppNameLength = sizeof(ConnectInfo.AppName);
SetUpAppName(TRUE, &ConnectInfo.CurDirLength, &CurDir, &ConnectInfo.AppNameLength, &AppName); DPRINT("CurDir = '%S' - AppName = '%S'\n", CurDir, AppName); } else { ConnectInfo.CurDirLength = 0; ConnectInfo.AppNameLength = 0; }
/* * Initialize Console Ctrl Handling, that needs to be supported by * all applications, especially because it is used at shutdown. */ InitializeCtrlHandling();
/* Connect to the Console Server */ if (!ConnectConsole(SessionDir, &ConnectInfo, &InServerProcess)) { // DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status); return FALSE; }
/* If we are not doing server-to-server init and if this is a console app... */ if (!InServerProcess && ConnectInfo.IsConsoleApp) { /* ... set the handles that we got */ if (Parameters->ConsoleHandle == NULL) SetUpHandles(&ConnectInfo.ConsoleStartInfo);
InputWaitHandle = ConnectInfo.ConsoleStartInfo.InputWaitHandle;
/* Sync the current thread's LangId with the console's one */ SetTEBLangID(); }
DPRINT("Console setup: 0x%p, 0x%p, 0x%p, 0x%p\n", Parameters->ConsoleHandle, Parameters->StandardInput, Parameters->StandardOutput, Parameters->StandardError);
return TRUE;}
/* EOF */