|
|
/*++
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)
|