/*++ Copyright (c) 1989 Microsoft Corporation Module Name: conrqust.c Abstract: This module implements the OS/2 V2.0 console API calls Author: Avi Nathan (avin) 23-Jul-1991 Revision History: --*/ #define INCL_OS2V20_ERRORS #include "os2dll.h" #include "conrqust.h" extern PVOID Os2SessionCtrlDataBaseAddress; extern HANDLE Od2StdHandleLockHandle; APIRET DosSleep( IN ULONG MilliSeconds ); NTSTATUS Od2AlertableWaitForSingleObject( IN HANDLE handle ); #if DBG PSZ Od2ExecPgmTable[] = { "RemoveConsoleThread", "RestartConsoleThread", "AddWin32ChildProcess", "RemWin32ChildProcess", "UnKnown" }; #endif APIRET Od2SendExecPgmRequest( IN EXECREQUESTNUMBER RequestType ) { SCREQUESTMSG Request; NTSTATUS Status; #if DBG IF_OD2_DEBUG( LPC ) { DbgPrint( "Od2SendExecPgmRequest: send %s(%u) request\n", (RequestType > 3) ? Od2ExecPgmTable[4] : Od2ExecPgmTable[RequestType], RequestType ); } #endif Request.Request = WinCreateProcess; Request.d.WinExecPgm.Request = RequestType; //PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG); //PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE); PORT_MSG_TOTAL_LENGTH(Request) = FIELD_OFFSET( SCREQUESTMSG, d) + sizeof(WINEXECPGM_MSG); PORT_MSG_DATA_LENGTH(Request) = FIELD_OFFSET( SCREQUESTMSG, d) + sizeof(WINEXECPGM_MSG) - sizeof(PORT_MESSAGE); PORT_MSG_ZERO_INIT(Request) = 0L; Status = NtRequestWaitReplyPort( CtrlPortHandle, (PPORT_MESSAGE) &Request, (PPORT_MESSAGE) &Request); if (!NT_SUCCESS(Status)){ #if DBG DbgPrint( "Od2SendExecPgmRequest(%u): failure at NtRequestReplyPort %lx\n", RequestType, Status); #endif return(Or2MapNtStatusToOs2Error( Status,ERROR_ACCESS_DENIED)); } return(Request.Status); } APIRET Od2RemoveConsoleThread() { return(Od2SendExecPgmRequest(RemoveConsoleThread)); } APIRET Od2RestartConsoleThread() { return(Od2SendExecPgmRequest(RestartConsoleThread)); } APIRET Od2AddWin32ChildProcess() { return(Od2SendExecPgmRequest(AddWin32ChildProcess)); } APIRET Od2RemoveWin32ChildProcess() { return(Od2SendExecPgmRequest(RemWin32ChildProcess)); } APIRET Od2CallRootProcessThruLPC( IN OUT PSCREQUESTMSG Request, IN PCH OutBuffer, OUT PCH InBuffer, IN HANDLE hSem, IN ULONG ArgLength ) { NTSTATUS NtStatus; APIRET Status; ULONG *pLeng, MaxLen; PCH InPtr = (PCH)Os2SessionCtrlDataBaseAddress; //PORT_MSG_TOTAL_LENGTH(*Request) = sizeof(SCREQUESTMSG); //PORT_MSG_DATA_LENGTH(*Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE); PORT_MSG_TOTAL_LENGTH(*Request) = (CSHORT)(FIELD_OFFSET( SCREQUESTMSG, d) + ArgLength); PORT_MSG_DATA_LENGTH(*Request) = (CSHORT)(FIELD_OFFSET( SCREQUESTMSG, d) + ArgLength - sizeof(PORT_MESSAGE)); PORT_MSG_ZERO_INIT(*Request) = 0L; #if DBG IF_OD2_DEBUG2(OS2_EXE, LPC) { DbgPrint("SendCtrlConsoleRequest: Request %u:%u, In %p, Out %p, hSem %lx\n", Request->Request, Request->d.Prt.Request, OutBuffer, InBuffer, hSem); } #endif if (hSem != NULL) { Status = Od2AlertableWaitForSingleObject(hSem); if ( Status ) { return(ERROR_VIO_INVALID_HANDLE); /* =>BUGBUG fix the error code */ } } if (Request->Request == KbdRequest || Request->Request == MouRequest || Request->Request == MonRequest || Request->Request == PrtRequest) { if ((InBuffer != NULL) || (OutBuffer != NULL)) { MaxLen = OS2_CON_PORT_MSG_SIZE; pLeng = &Request->d.Prt.d.Write.Length; if ( Request->Request == KbdRequest ) { pLeng = &Request->d.Kbd.Length; MaxLen = OS2_KBD_PORT_MSG_SIZE; InPtr += KBD_OFFSET; } if ( *pLeng > MaxLen ) { #if DBG IF_OD2_DEBUG( OS2_EXE ) DbgPrint("SendCtrlConsoleRequest: length 0x%lx too long\n", *pLeng); #endif *pLeng = MaxLen; } if (OutBuffer != NULL) { RtlMoveMemory(InPtr, OutBuffer, *pLeng); } } NtStatus = NtRequestWaitReplyPort( CtrlPortHandle, (PPORT_MESSAGE) Request, (PPORT_MESSAGE) Request); if ( !NT_SUCCESS( NtStatus )) { #if DBG DbgPrint( "OS2DLL: Unable to send CTRL request - Status == %X\n", NtStatus); #endif if (hSem != NULL) { NtReleaseMutant(hSem, NULL); } return(ERROR_VIO_INVALID_HANDLE); // =>BUGBUG fix the error code } ASSERT ( PORT_MSG_TYPE(*Request) == LPC_REPLY ); if ((InBuffer != NULL) && ! Request->Status ) { RtlMoveMemory(InBuffer, InPtr, *pLeng); } } else { #if DBG DbgPrint ("SendCtrlConsoleRequest: illegal request %lu\n", Request->Request); return( ERROR_INVALID_PARAMETER ); #endif } Status = Request->Status; if (hSem != NULL) { NtReleaseMutant(hSem, NULL); } if ( Status == -2) { /* * This call is from EventReleaseLPC * terminate thread if not Thread1 */ if (Od2CurrentThreadId() != 1); { DosSleep((ULONG)-1); } Status = 0; } return( Status ); } APIRET SendCtrlConsoleRequest( IN OUT PSCREQUESTMSG Request, IN PCH OutBuffer, OUT PCH InBuffer, IN HANDLE hSem ) { return (Od2CallRootProcessThruLPC( Request, OutBuffer, InBuffer, hSem, sizeof(Request->d))); } APIRET Od2LockCtrlRequestDataBuffer() { APIRET Status; Status = Od2WaitForSingleObject( CtrlDataSemaphore, TRUE, NULL); if ( Status ) { return(ERROR_VIO_INVALID_HANDLE); /* =>BUGBUG fix the error code */ } } VOID Od2UnlockCtrlRequestDataBuffer() { NtReleaseSemaphore( CtrlDataSemaphore, 1, NULL); } #if DBG VOID AcquireStdHandleLock( IN PSZ CallingRoutine ) { PTEB Teb; IF_OD2_DEBUG( OS2_EXE ) { Teb = NtCurrentTeb(); DbgPrint("entering AcquireStdHandleLock for client id %ld%ld in %s\n", Teb->ClientId.UniqueProcess, Teb->ClientId.UniqueThread, CallingRoutine); Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL ); DbgPrint("leaving AcquireStdHandleLock for client id %ld%ld in %s\n", Teb->ClientId.UniqueProcess, Teb->ClientId.UniqueThread, CallingRoutine); } else { Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL ); } } VOID ReleaseStdHandleLock( IN PSZ CallingRoutine ) { PTEB Teb; IF_OD2_DEBUG( OS2_EXE ) { Teb = NtCurrentTeb(); DbgPrint("entering ReleaseStdHandleLock for client id %ld%ld in %s\n", Teb->ClientId.UniqueProcess, Teb->ClientId.UniqueThread, CallingRoutine); NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL); DbgPrint("leaving ReleaseStdHandleLock for client id %ld%ld in %s\n", Teb->ClientId.UniqueProcess, Teb->ClientId.UniqueThread, CallingRoutine); } else { NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL); } } #else VOID AcquireStdHandleLock() { Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL ); } VOID ReleaseStdHandleLock() { NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL); } #endif APIRET KbdDupLogHandle( IN HANDLE hKbd ) { SCREQUESTMSG Request; NTSTATUS Status; #if DBG PSZ RoutineName; RoutineName = "KbdDupLogHandle"; IF_OD2_DEBUG(KBD) { DbgPrint("%s: entering\n", RoutineName); } #endif /* * prepare Message parameters & send request to server (OS2) */ Request.Request = KbdRequest; Request.d.Kbd.Request = KBDDupLogHandle; Request.d.Kbd.hKbd = hKbd; Status = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL); /* * handle return status (free handle if failed, validate if successed) */ if ( Status ) { #if DBG IF_OD2_DEBUG( KBD ) DbgPrint("%s: status %lx\n", RoutineName, Status); #endif return(Status); } return NO_ERROR; } APIRET Od2WaitForSingleObject( IN HANDLE Semaphore, IN BOOLEAN Alertable, IN PLARGE_INTEGER TimeOut OPTIONAL ) { NTSTATUS NtStatus; LARGE_INTEGER StartTimeStamp; do { if (TimeOut) { Od2StartTimeout(&StartTimeStamp); } NtStatus = NtWaitForSingleObject(Semaphore, Alertable, TimeOut); #if DBG if (NtStatus == STATUS_USER_APC) { DbgPrint("[%d,%d] WARNING !!! Od2WaitForSingleObject was broken by APC\n", Od2Process->Pib.ProcessId, Od2CurrentThreadId() ); } #endif } while (NtStatus == STATUS_USER_APC && (NtStatus = Od2ContinueTimeout(&StartTimeStamp, TimeOut)) == STATUS_SUCCESS ); if (( !NT_SUCCESS(NtStatus) ) || (NtStatus == STATUS_TIMEOUT) || (NtStatus == STATUS_ABANDONED) || (NtStatus == STATUS_ALERTED)) { return ERROR_SEM_TIMEOUT; } return NO_ERROR; }