Windows2003-3790/windows/core/ntcon/client/dllinit.c

1272 lines
32 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
dllinit.c
Abstract:
This module implements console dll initialization
Author:
Therese Stowell (thereses) 11-Nov-1990
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#if !defined(BUILD_WOW64)
#include <cpl.h>
#define DEFAULT_WINDOW_TITLE (L"Command Prompt")
extern HANDLE InputWaitHandle;
extern WCHAR ExeNameBuffer[];
extern USHORT ExeNameLength;
extern WCHAR StartDirBuffer[];
extern USHORT StartDirLength;
DWORD
CtrlRoutine(
IN LPVOID lpThreadParameter
);
DWORD
PropRoutine(
IN LPVOID lpThreadParameter
);
#if defined(FE_SB)
#if defined(FE_IME)
DWORD
ConsoleIMERoutine(
IN LPVOID lpThreadParameter
);
#endif // FE_IME
#endif // FE_SB
#define MAX_SESSION_PATH 256
#define SESSION_ROOT L"\\Sessions"
BOOLEAN
ConsoleApp( VOID )
/*++
This routine determines whether the current process is a console or
windows app.
Parameters:
none.
Return Value:
TRUE if console app.
--*/
{
PIMAGE_NT_HEADERS NtHeaders;
NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
return ((NtHeaders != NULL) &&
(NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)) ? TRUE : FALSE;
}
VOID
SetUpAppName(
IN OUT LPDWORD CurDirLength,
OUT LPWSTR CurDir,
IN OUT LPDWORD AppNameLength,
OUT LPWSTR AppName
)
{
DWORD Length;
*CurDirLength -= sizeof(WCHAR);
Length = (StartDirLength*sizeof(WCHAR)) > *CurDirLength ? *CurDirLength : (StartDirLength*sizeof(WCHAR));
RtlCopyMemory(CurDir,StartDirBuffer,Length+sizeof(WCHAR));
*CurDirLength = Length + sizeof(WCHAR); // add terminating NULL
*AppNameLength -= sizeof(WCHAR);
Length = (ExeNameLength*sizeof(WCHAR)) > *AppNameLength ? *AppNameLength : (ExeNameLength*sizeof(WCHAR));
RtlCopyMemory(AppName,ExeNameBuffer,Length+sizeof(WCHAR));
*AppNameLength = Length + sizeof(WCHAR); // add terminating NULL
}
ULONG
ParseReserved(
WCHAR *pchReserved,
WCHAR *pchFind
)
{
ULONG dw;
WCHAR *pch, *pchT, ch;
UNICODE_STRING uString;
dw = 0;
if ((pch = wcsstr(pchReserved, pchFind)) != NULL) {
pch += lstrlenW(pchFind);
pchT = pch;
while (*pchT >= '0' && *pchT <= '9')
pchT++;
ch = *pchT;
*pchT = 0;
RtlInitUnicodeString(&uString, pch);
*pchT = ch;
RtlUnicodeStringToInteger(&uString, 0, &dw);
}
return dw;
}
VOID
SetUpConsoleInfo(
IN BOOL DllInit,
OUT LPDWORD TitleLength,
OUT LPWSTR Title OPTIONAL,
OUT LPDWORD DesktopLength,
OUT LPWSTR *Desktop OPTIONAL,
OUT PCONSOLE_INFO ConsoleInfo
)
/*++
This routine fills in the ConsoleInfo structure with the values
specified by the user.
Parameters:
ConsoleInfo - pointer to structure to fill in.
Return Value:
none.
--*/
{
STARTUPINFOW StartupInfo;
HANDLE h;
int id;
HANDLE ghInstance;
BOOL Success;
GetStartupInfoW(&StartupInfo);
ghInstance = (HANDLE)((PVOID)NtCurrentPeb()->ImageBaseAddress );
// these will eventually be filled in using menu input
ConsoleInfo->nFont = 0;
ConsoleInfo->nInputBufferSize = 0;
ConsoleInfo->hIcon = NULL;
ConsoleInfo->hSmIcon = NULL;
ConsoleInfo->iIconId = 0;
ConsoleInfo->dwStartupFlags = StartupInfo.dwFlags;
#if defined(FE_SB)
ConsoleInfo->uCodePage = GetOEMCP();
#endif
if (StartupInfo.lpTitle == NULL) {
StartupInfo.lpTitle = DEFAULT_WINDOW_TITLE;
}
//
// if the desktop name was specified, set up the pointers.
//
if (DllInit && Desktop != NULL &&
StartupInfo.lpDesktop != NULL && *StartupInfo.lpDesktop != 0) {
*DesktopLength = (lstrlenW(StartupInfo.lpDesktop) + 1) * sizeof(WCHAR);
*Desktop = StartupInfo.lpDesktop;
} else {
*DesktopLength = 0;
if (Desktop != NULL)
*Desktop = NULL;
}
// Nope, do normal initialization (TitleLength is in BYTES, not CHARS!)
*TitleLength = (USHORT)((lstrlenW(StartupInfo.lpTitle)+1)*sizeof(WCHAR));
*TitleLength = (USHORT)(min(*TitleLength,MAX_TITLE_LENGTH));
if (DllInit) {
RtlCopyMemory(Title,StartupInfo.lpTitle,*TitleLength);
// ensure the title is NULL terminated
if (*TitleLength == MAX_TITLE_LENGTH)
Title[ (MAX_TITLE_LENGTH/sizeof(WCHAR)) - 1 ] = L'\0';
}
if (StartupInfo.dwFlags & STARTF_USESHOWWINDOW) {
ConsoleInfo->wShowWindow = StartupInfo.wShowWindow;
}
if (StartupInfo.dwFlags & STARTF_USEFILLATTRIBUTE) {
ConsoleInfo->wFillAttribute = (WORD)StartupInfo.dwFillAttribute;
}
if (StartupInfo.dwFlags & STARTF_USECOUNTCHARS) {
ConsoleInfo->dwScreenBufferSize.X = (WORD)(StartupInfo.dwXCountChars);
ConsoleInfo->dwScreenBufferSize.Y = (WORD)(StartupInfo.dwYCountChars);
}
if (StartupInfo.dwFlags & STARTF_USESIZE) {
ConsoleInfo->dwWindowSize.X = (WORD)(StartupInfo.dwXSize);
ConsoleInfo->dwWindowSize.Y = (WORD)(StartupInfo.dwYSize);
}
if (StartupInfo.dwFlags & STARTF_USEPOSITION) {
ConsoleInfo->dwWindowOrigin.X = (WORD)(StartupInfo.dwX);
ConsoleInfo->dwWindowOrigin.Y = (WORD)(StartupInfo.dwY);
}
//
// Grab information passed on lpReserved line...
//
if (StartupInfo.lpReserved != 0) {
//
// the program manager has an icon for the exe. store the
// index in the iIconId field.
//
ConsoleInfo->iIconId = ParseReserved(StartupInfo.lpReserved, L"dde.");
//
// The new "Chicago" way of doing things is to pass the hotkey in the
// hStdInput field and set the STARTF_USEHOTKEY flag. So, if this is
// specified, we get the hotkey from there instead
//
if (StartupInfo.dwFlags & STARTF_USEHOTKEY) {
ConsoleInfo->dwHotKey = HandleToUlong(StartupInfo.hStdInput);
} else {
ConsoleInfo->dwHotKey = ParseReserved(StartupInfo.lpReserved, L"hotkey.");
}
}
}
VOID
SetUpHandles(
IN PCONSOLE_INFO ConsoleInfo
)
/*++
This routine sets up the console and std* handles for the process.
Parameters:
ConsoleInfo - pointer to structure containing handles.
Return Value:
none.
--*/
{
if (ConsoleInfo->dwStartupFlags & STARTF_USEHOTKEY) {
NtCurrentPeb()->ProcessParameters->WindowFlags &= ~STARTF_USEHOTKEY;
}
if (ConsoleInfo->dwStartupFlags & STARTF_HASSHELLDATA) {
NtCurrentPeb()->ProcessParameters->WindowFlags &= ~STARTF_HASSHELLDATA;
}
SET_CONSOLE_HANDLE(ConsoleInfo->ConsoleHandle);
if (!(ConsoleInfo->dwStartupFlags & STARTF_USESTDHANDLES)) {
SetStdHandle(STD_INPUT_HANDLE,ConsoleInfo->StdIn);
SetStdHandle(STD_OUTPUT_HANDLE,ConsoleInfo->StdOut);
SetStdHandle(STD_ERROR_HANDLE,ConsoleInfo->StdErr);
}
}
#endif //!defined(BUILD_WOW64)
#if !defined(BUILD_WOW6432)
BOOL
WINAPI
GetConsoleLangId(
OUT LANGID *lpLangId
)
/*++
Parameters:
lpLangId - Supplies a pointer to a LANGID in which to store the Language ID.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
CONSOLE_API_MSG m;
PCONSOLE_LANGID_MSG a = &m.u.GetConsoleLangId;
a->ConsoleHandle = GET_CONSOLE_HANDLE;
CsrClientCallServer( (PCSR_API_MSG)&m,
NULL,
CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
ConsolepGetLangId
),
sizeof( *a )
);
if (NT_SUCCESS( m.ReturnValue )) {
try {
*lpLangId = a->LangId;
} except( EXCEPTION_EXECUTE_HANDLER ) {
return FALSE;
}
return TRUE;
} else {
return FALSE;
}
}
#endif //!defined(BUILD_WOW6432)
#if !defined(BUILD_WOW64)
VOID
SetTEBLangID(
VOID
)
/*++
Sets the Language Id in the TEB to Far East if code page CP are
Japanese/Korean/Chinese. This is done in order for FormatMessage
to display any Far East character when cmd is running in its code page.
All messages displayed in non-FE code page will be displayed in English.
--*/
{
LANGID LangId;
if (GetConsoleLangId(&LangId)) {
SetThreadLocale( MAKELCID(LangId, SORT_DEFAULT) );
}
}
#endif //!defined(BUILD_WOW64)
#if !defined(BUILD_WOW6432)
BOOL
APIENTRY
ConnectConsoleInternal(IN PWSTR pObjectDirectory,
IN OUT PCONSOLE_API_CONNECTINFO pConnectInfo,
OUT PBOOLEAN pServerProcess
)
/*++
Routine Description:
Helper function for establishing a connection with the console server.
Waits for the server to signal completion.
Arguments:
pObjectDirectory - Supplies a null terminated string that is the same
as the value of the ObjectDirectory= argument passed to the CSRSS
program.
pConnectInfo - Supplies and recieves the connection information.
pServerProcess - Recieves TRUE if this is a server process.
Return Value:
TRUE - Success
FALSE - An error occured.
--*/
{
NTSTATUS Status;
ULONG ConnectionInformationLength = sizeof(CONSOLE_API_CONNECTINFO);
Status = CsrClientConnectToServer( pObjectDirectory,
CONSRV_SERVERDLL_INDEX,
pConnectInfo,
&ConnectionInformationLength,
pServerProcess
);
if (!NT_SUCCESS( Status )) {
return FALSE;
}
//
// we return success although no console api can be called because
// loading shouldn't fail. we'll fail the api calls later.
//
if (*pServerProcess) {
return TRUE;
}
//
// if this is not a console app, return success - nothing else to do.
//
if (!pConnectInfo->ConsoleApp) {
return TRUE;
}
//
// wait for initialization to complete. we have to use the NT
// wait because the heap hasn't been initialized yet.
//
Status = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
pConnectInfo->ConsoleInfo.InitEvents,
WaitAny,
FALSE,
NULL
);
if (!NT_SUCCESS(Status)) {
SET_LAST_NT_ERROR(Status);
return FALSE;
}
NtClose(pConnectInfo->ConsoleInfo.InitEvents[INITIALIZATION_SUCCEEDED]);
NtClose(pConnectInfo->ConsoleInfo.InitEvents[INITIALIZATION_FAILED]);
if (Status != INITIALIZATION_SUCCEEDED) {
SET_CONSOLE_HANDLE(NULL);
return FALSE;
}
return TRUE;
}
#endif //!defined(BUILD_WOW6432)
#if !defined(BUILD_WOW64)
BOOLEAN
ConDllInitialize(
IN ULONG Reason,
IN PWSTR pObjectDirectory OPTIONAL
)
/*++
Routine Description:
This function implements console dll initialization.
Arguments:
Reason - DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, etc.
pObjectDiretory - Session directory name; only valid/required when
Reason == DLL_PROCESS_ATTACH.
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOL bStatus;
BOOLEAN ServerProcess;
//
// if we're attaching the DLL, we need to connect to the server.
// if no console exists, we also need to create it and set up stdin,
// stdout, and stderr.
//
if (Reason == DLL_PROCESS_ATTACH) {
CONSOLE_API_CONNECTINFO ConnectionInformation;
//
// Remember in the connect information if this app is a console
// app. need to actually connect to the console server for windowed
// apps so that we know NOT to do any special work during
// ConsoleClientDisconnectRoutine(). Store ConsoleApp info in the
// CSR managed per-process data.
//
Status = RtlInitializeCriticalSection(&DllLock);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
ConnectionInformation.CtrlRoutine = CtrlRoutine;
ConnectionInformation.PropRoutine = PropRoutine;
#if defined(FE_SB)
#if defined(FE_IME)
ConnectionInformation.ConsoleIMERoutine = ConsoleIMERoutine;
#endif // FE_IME
#endif // FE_SB
ConnectionInformation.WindowVisible = TRUE;
ConnectionInformation.ConsoleApp = ConsoleApp();
if (GET_CONSOLE_HANDLE == CONSOLE_DETACHED_PROCESS) {
SET_CONSOLE_HANDLE(NULL);
ConnectionInformation.ConsoleApp = FALSE;
} else if (GET_CONSOLE_HANDLE == CONSOLE_NEW_CONSOLE) {
SET_CONSOLE_HANDLE(NULL);
} else if (GET_CONSOLE_HANDLE == CONSOLE_CREATE_NO_WINDOW) {
SET_CONSOLE_HANDLE(NULL);
ConnectionInformation.WindowVisible = FALSE;
}
if (!ConnectionInformation.ConsoleApp) {
SET_CONSOLE_HANDLE(NULL);
}
ConnectionInformation.ConsoleInfo.ConsoleHandle = GET_CONSOLE_HANDLE;
//
// if no console exists, pass parameters for console creation
//
if (GET_CONSOLE_HANDLE == NULL && ConnectionInformation.ConsoleApp) {
SetUpConsoleInfo(TRUE,
&ConnectionInformation.TitleLength,
ConnectionInformation.Title,
&ConnectionInformation.DesktopLength,
&ConnectionInformation.Desktop,
&ConnectionInformation.ConsoleInfo);
} else {
ConnectionInformation.TitleLength = 0;
ConnectionInformation.DesktopLength = 0;
}
if (ConnectionInformation.ConsoleApp) {
InitExeName();
ConnectionInformation.CurDirLength = sizeof(ConnectionInformation.CurDir);
ConnectionInformation.AppNameLength = sizeof(ConnectionInformation.AppName);
SetUpAppName(&ConnectionInformation.CurDirLength,
ConnectionInformation.CurDir,
&ConnectionInformation.AppNameLength,
ConnectionInformation.AppName);
} else {
ConnectionInformation.AppNameLength = 0;
ConnectionInformation.CurDirLength = 0;
}
//
// initialize ctrl handling. This should work for all apps, so
// initialize it before we check for ConsoleApp (which means the
// console bit was set in the module header).
//
InitializeCtrlHandling();
//
// Connect to the server process
//
ASSERT(pObjectDirectory != NULL);
bStatus = ConnectConsoleInternal(pObjectDirectory,
&ConnectionInformation,
&ServerProcess
);
if (!bStatus) {
return FALSE;
}
//
// we return success although no console api can be called because
// loading shouldn't fail. we'll fail the api calls later.
//
if (ServerProcess) {
return TRUE;
}
//
// if this is not a console app, return success - nothing else to do.
//
if (!ConnectionInformation.ConsoleApp) {
return TRUE;
}
//
// if console was just created, fill in peb values
//
if (GET_CONSOLE_HANDLE == NULL) {
SetUpHandles(&ConnectionInformation.ConsoleInfo);
}
InputWaitHandle = ConnectionInformation.ConsoleInfo.InputWaitHandle;
SetTEBLangID();
} else if (Reason == DLL_THREAD_ATTACH) {
if (ConsoleApp()) {
SetTEBLangID();
}
}
return TRUE;
}
#endif //!defined(BUILD_WOW64)
#if !defined(BUILD_WOW6432)
BOOL
APIENTRY
AllocConsoleInternal(IN LPWSTR lpTitle,
IN DWORD dwTitleLength,
IN LPWSTR lpDesktop,
IN DWORD dwDesktopLength,
IN LPWSTR lpCurDir,
IN DWORD dwCurDirLength,
IN LPWSTR lpAppName,
IN DWORD dwAppNameLength,
IN LPTHREAD_START_ROUTINE CtrlRoutine,
IN LPTHREAD_START_ROUTINE PropRoutine,
IN OUT PCONSOLE_INFO pConsoleInfo
)
/*++
Routine Description:
Marshels the parameters for the ConsolepAlloc command.
Arguments:
See the CONSOLE_ALLOC_MSG structure and AllocConsole.
Return Value:
TRUE - Success
FALSE - An error occured.
--*/
{
CONSOLE_API_MSG m;
PCONSOLE_ALLOC_MSG a = &m.u.AllocConsole;
PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
BOOL bStatus = FALSE;
NTSTATUS Status;
try {
a->CtrlRoutine = CtrlRoutine;
a->PropRoutine = PropRoutine;
// Allocate 4 extra pointer sizes to compensate for any alignment done
// by CsrCaptureMessageBuffer.
CaptureBuffer = CsrAllocateCaptureBuffer( 5,
dwTitleLength + dwDesktopLength + dwCurDirLength +
dwAppNameLength + sizeof( CONSOLE_INFO ) + (4 * sizeof(PVOID))
);
if (CaptureBuffer == NULL) {
SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
bStatus = FALSE;
leave;
}
// Allocate the CONSOLE_INFO first so that it is aligned on a pointer
// boundry. This is necessary since NtWaitForMultipleObject expects
// its arguments aligned on a handle boundry.
CsrCaptureMessageBuffer( CaptureBuffer,
pConsoleInfo,
sizeof( CONSOLE_INFO ),
(PVOID *) &a->ConsoleInfo
);
a->TitleLength = dwTitleLength;
CsrCaptureMessageBuffer( CaptureBuffer,
lpTitle,
dwTitleLength,
(PVOID *) &a->Title
);
a->DesktopLength = dwDesktopLength;
CsrCaptureMessageBuffer( CaptureBuffer,
lpDesktop,
dwDesktopLength,
(PVOID *) &a->Desktop
);
a->CurDirLength = dwCurDirLength;
CsrCaptureMessageBuffer( CaptureBuffer,
lpCurDir,
dwCurDirLength,
(PVOID *) &a->CurDir
);
a->AppNameLength = dwAppNameLength;
CsrCaptureMessageBuffer( CaptureBuffer,
lpAppName,
dwAppNameLength,
(PVOID *) &a->AppName
);
//
// Connect to the server process
//
CsrClientCallServer( (PCSR_API_MSG)&m,
CaptureBuffer,
CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
ConsolepAlloc
),
sizeof( *a )
);
if (!NT_SUCCESS( m.ReturnValue )) {
SET_LAST_NT_ERROR (m.ReturnValue);
bStatus = FALSE;
leave;
}
Status = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
a->ConsoleInfo->InitEvents,
WaitAny,
FALSE,
NULL
);
if (!NT_SUCCESS(Status)) {
SET_LAST_NT_ERROR(Status);
bStatus = FALSE;
leave;
}
//The handles to be closed are events, so NtClose works fine.
NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_SUCCEEDED]);
NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_FAILED]);
if (Status != INITIALIZATION_SUCCEEDED) {
SET_CONSOLE_HANDLE(NULL);
bStatus = FALSE;
leave;
}
RtlCopyMemory(pConsoleInfo, a->ConsoleInfo, sizeof(CONSOLE_INFO));
bStatus = TRUE;
}
finally {
if (CaptureBuffer) {
CsrFreeCaptureBuffer( CaptureBuffer );
}
}
return bStatus;
}
#endif //!defined(BUILD_WOW6432)
#if !defined(BUILD_WOW64)
BOOL
APIENTRY
AllocConsole( VOID )
/*++
Routine Description:
This API creates a console for the calling process.
Arguments:
none.
Return Value:
TRUE - function was successful.
--*/
{
CONSOLE_INFO ConsoleInfo;
STARTUPINFOW StartupInfo;
WCHAR CurDir[MAX_PATH+1];
WCHAR AppName[MAX_APP_NAME_LENGTH/2];
BOOL Status = FALSE;
DWORD dwTitleLength;
DWORD dwDesktopLength;
DWORD dwCurDirLength;
DWORD dwAppNameLength;
LockDll();
try {
if (GET_CONSOLE_HANDLE != NULL) {
SetLastError(ERROR_ACCESS_DENIED);
Status = FALSE;
leave;
}
//
// set up initialization parameters
//
SetUpConsoleInfo(FALSE,
&dwTitleLength,
NULL,
&dwDesktopLength,
NULL,
&ConsoleInfo);
InitExeName();
dwCurDirLength = sizeof(CurDir);
dwAppNameLength = sizeof(AppName);
SetUpAppName(&dwCurDirLength,
CurDir,
&dwAppNameLength,
AppName);
GetStartupInfoW(&StartupInfo);
if (StartupInfo.lpTitle == NULL) {
StartupInfo.lpTitle = DEFAULT_WINDOW_TITLE;
}
dwTitleLength = (USHORT)((lstrlenW(StartupInfo.lpTitle)+1)*sizeof(WCHAR));
dwTitleLength = (USHORT)(min(dwTitleLength,MAX_TITLE_LENGTH));
if (StartupInfo.lpDesktop != NULL && *StartupInfo.lpDesktop != 0) {
dwDesktopLength = (USHORT)((lstrlenW(StartupInfo.lpDesktop)+1)*sizeof(WCHAR));
dwDesktopLength = (USHORT)(min(dwDesktopLength,MAX_TITLE_LENGTH));
} else {
dwDesktopLength = 0;
}
Status = AllocConsoleInternal(StartupInfo.lpTitle,
dwTitleLength,
StartupInfo.lpDesktop,
dwDesktopLength,
CurDir,
dwCurDirLength,
AppName,
dwAppNameLength,
CtrlRoutine,
PropRoutine,
&ConsoleInfo
);
if (!Status) {
leave;
}
//
// fill in peb values
//
SetUpHandles(&ConsoleInfo);
//
// create ctrl-c thread
//
InitializeCtrlHandling();
InputWaitHandle = ConsoleInfo.InputWaitHandle;
SetTEBLangID();
Status = TRUE;
} finally {
UnlockDll();
}
return Status;
}
#endif //!defined(BUILD_WOW64)
#if !defined(BUILD_WOW6432)
BOOL
APIENTRY
FreeConsoleInternal(
VOID
)
/*++
Routine Description:
Marshels the parameters for the ConsolepFree command.
Arguments:
See the CONSOLE_FREE_MSG structure and FreeConsole.
Return Value:
TRUE - Success
FALSE - An error occured.
--*/
{
CONSOLE_API_MSG m;
PCONSOLE_FREE_MSG a = &m.u.FreeConsole;
a->ConsoleHandle = GET_CONSOLE_HANDLE;
//
// Connect to the server process
//
CsrClientCallServer( (PCSR_API_MSG)&m,
NULL,
CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
ConsolepFree
),
sizeof( *a )
);
if (!NT_SUCCESS( m.ReturnValue )) {
SET_LAST_NT_ERROR (m.ReturnValue);
return FALSE;
} else {
SET_CONSOLE_HANDLE(NULL);
return TRUE;
}
}
#endif //!defined(BUILD_WOW6432)
#if !defined(BUILD_WOW64)
BOOL
APIENTRY
FreeConsole( VOID )
/*++
Routine Description:
This API frees the calling process's console.
Arguments:
none.
Return Value:
TRUE - function was successful.
--*/
{
BOOL Success=TRUE;
LockDll();
if (GET_CONSOLE_HANDLE == NULL) {
SET_LAST_ERROR(ERROR_INVALID_PARAMETER);
Success = FALSE;
} else {
Success = FreeConsoleInternal();
if (Success) {
CloseHandle(InputWaitHandle);
}
}
UnlockDll();
return Success;
}
DWORD
PropRoutine(
IN LPVOID lpThreadParameter
)
/*++
Routine Description:
This thread is created when the user tries to change console
properties from the system menu. It invokes the control panel
applet.
Arguments:
lpThreadParameter - not used.
Return Value:
STATUS_SUCCESS - function was successful
--*/
{
NTSTATUS Status;
HANDLE hLibrary;
APPLET_PROC pfnCplApplet;
static BOOL fInPropRoutine = FALSE;
//
// Prevent the user from launching multiple applets attached
// to a single console
//
if (fInPropRoutine) {
if (lpThreadParameter) {
CloseHandle((HANDLE)lpThreadParameter);
}
return (ULONG)STATUS_UNSUCCESSFUL;
}
fInPropRoutine = TRUE;
hLibrary = LoadLibraryW(L"CONSOLE.DLL");
if (hLibrary != NULL) {
pfnCplApplet = (APPLET_PROC)GetProcAddress(hLibrary, "CPlApplet");
if (pfnCplApplet != NULL) {
(*pfnCplApplet)((HWND)lpThreadParameter, CPL_INIT, 0, 0);
(*pfnCplApplet)((HWND)lpThreadParameter, CPL_DBLCLK, 0, 0);
(*pfnCplApplet)((HWND)lpThreadParameter, CPL_EXIT, 0, 0);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_UNSUCCESSFUL;
}
FreeLibrary(hLibrary);
} else {
Status = STATUS_UNSUCCESSFUL;
}
fInPropRoutine = FALSE;
return Status;
}
#endif //!defined(BUILD_WOW64)
#if !defined(BUILD_WOW6432)
BOOL
APIENTRY
AttachConsoleInternal(
IN DWORD dwProcessId,
IN LPTHREAD_START_ROUTINE CtrlRoutine,
IN LPTHREAD_START_ROUTINE PropRoutine,
IN OUT PCONSOLE_INFO pConsoleInfo
)
/*++
Routine Description:
Marshels the parameters for the ConsolepAttach command.
Arguments:
See the CONSOLE_ATTACH_MSG structure and AttachConsole.
Return Value:
TRUE - Success
FALSE - An error occured.
--*/
{
CONSOLE_API_MSG m;
PCONSOLE_ATTACH_MSG a = &m.u.AttachConsole;
PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
BOOL Status = FALSE;
NTSTATUS St;
try {
a->ProcessId = dwProcessId;
a->CtrlRoutine = CtrlRoutine;
a->PropRoutine = PropRoutine;
CaptureBuffer = CsrAllocateCaptureBuffer( 1,
sizeof( CONSOLE_INFO )
);
if (CaptureBuffer == NULL) {
SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
Status = FALSE;
leave;
}
CsrCaptureMessageBuffer( CaptureBuffer,
pConsoleInfo,
sizeof( CONSOLE_INFO ),
(PVOID *) &a->ConsoleInfo
);
//
// Connect to the server process
//
CsrClientCallServer( (PCSR_API_MSG)&m,
CaptureBuffer,
CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
ConsolepAttach
),
sizeof( *a )
);
if (!NT_SUCCESS( m.ReturnValue )) {
SET_LAST_NT_ERROR (m.ReturnValue);
Status = FALSE;
leave;
}
St = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
a->ConsoleInfo->InitEvents,
WaitAny,
FALSE,
NULL
);
if (!NT_SUCCESS(St)) {
SET_LAST_NT_ERROR(St);
Status = FALSE;
leave;
}
//The handles to be closed are events, so NtClose works fine.
NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_SUCCEEDED]);
NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_FAILED]);
if (St != INITIALIZATION_SUCCEEDED) {
SET_CONSOLE_HANDLE(NULL);
Status = FALSE;
leave;
}
RtlCopyMemory(pConsoleInfo, a->ConsoleInfo, sizeof(CONSOLE_INFO));
Status = TRUE;
}
finally {
if (CaptureBuffer) {
CsrFreeCaptureBuffer( CaptureBuffer );
}
}
return Status;
}
#endif //!defined(BUILD_WOW6432)
#if !defined(BUILD_WOW64)
BOOL
APIENTRY
AttachConsole(
IN DWORD dwProcessId
)
/*++
Routine Description:
This API attaches the calling process to the console of the given process.
Arguments:
none.
Return Value:
TRUE - function was successful.
--*/
{
CONSOLE_INFO ConsoleInfo;
DWORD dwTitleLength;
DWORD dwDesktopLength;
BOOL Status = FALSE;
LockDll();
try {
//
// bail if we already have a console
//
if (GET_CONSOLE_HANDLE != NULL) {
SetLastError(ERROR_ACCESS_DENIED);
Status = FALSE;
leave;
}
//
// set up initialization parameters
//
SetUpConsoleInfo(FALSE,
&dwTitleLength,
NULL,
&dwDesktopLength,
NULL,
&ConsoleInfo);
//
// attach to the console
//
Status = AttachConsoleInternal(dwProcessId,
CtrlRoutine,
PropRoutine,
&ConsoleInfo
);
if (!Status) {
leave;
}
//
// fill in peb values
//
SetUpHandles(&ConsoleInfo);
//
// create ctrl-c thread
//
InitializeCtrlHandling();
InputWaitHandle = ConsoleInfo.InputWaitHandle;
SetTEBLangID();
Status = TRUE;
} finally {
UnlockDll();
}
return Status;
}
#endif //!defined(BUILD_WOW64)