/*++ Copyright (c) 1989 Microsoft Corporation Module Name: util.c Abstract: This module contains the common utilities used in OS2SES module Author: Avi Nathan (avin) 17-Jul-1991 Environment: User Mode Only Revision History: --*/ #define WIN32_ONLY #include "os2ses.h" #include "os2win.h" #include #include #include #include #include #if PMNT #define INCL_32BIT #include "pmnt.h" #endif /* ExitReason values (from os2v12.h/os2v20.h) */ #define TC_EXIT 0 #define TC_HARDERROR 1 #define TC_TRAP 2 #define TC_KILLPROCESS 3 typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } STRING, *PSTRING; BOOL Or2CreateUnicodeStringFromMBz( OUT PUNICODE_STRING DestinationString, IN PSZ SourceString ); DWORD Or2MBStringToUnicodeString( PUNICODE_STRING DestinationString, PSTRING SourceString, BOOL AllocateDestinationString ); VOID RtlFreeUnicodeString( PUNICODE_STRING UnicodeString ); DWORD Ow2VioReadCurPos( ); DWORD Ow2VioReadCurType(); DWORD Ow2LvbUpdateLVBBuffer(); VOID SetSessionParameters( IN PVOID SessionStartData, OUT PDWORD pCreateFlags, IN PSZ ImageFileName, #if PMNT IN ULONG IsPMApp, #endif // PMNT OUT LPSTARTUPINFO pStartInfo ); int Ow2DisplayHardErrorPopup( IN int Drive, IN BOOLEAN WriteProtectError, IN PUCHAR AppName ); DWORD Ow2HardErrorPopup( IN int Drive, IN BOOLEAN WriteProtectError, OUT int * ReturnedAction, IN PUCHAR AppName ) { int RetVal; RetVal = Ow2DisplayHardErrorPopup( Drive, WriteProtectError, AppName ); switch (RetVal) { case IDABORT: *ReturnedAction = OS2SS_IDABORT; break; case IDRETRY: *ReturnedAction = OS2SS_IDRETRY; break; default: *ReturnedAction = OS2SS_IDIGNORE; break; } return (0L); } HANDLE Ow2GetNulDeviceHandle( VOID ) // // NULL is returned if there is some system error // and we can't open the nul device // { // // used to hold a handle to the win32 NUL device // this is needed to pass NUL redirections to win32 processes // static HANDLE Ow2NulDeviceHandle = NULL; HANDLE Hand; SECURITY_ATTRIBUTES Sa; if (Ow2NulDeviceHandle != NULL) { return(Ow2NulDeviceHandle); } Sa.nLength = sizeof(Sa); Sa.lpSecurityDescriptor = NULL; Sa.bInheritHandle = TRUE; Hand = CreateFileA("NUL", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &Sa, OPEN_EXISTING, 0L, NULL); if (Hand == INVALID_HANDLE_VALUE) { #if DBG KdPrint(("OS2SES: Ow2GetNulDeviceHandle -- can't open NUL device, Error = %lx\n", GetLastError())); #endif return(NULL); } else { Ow2NulDeviceHandle = Hand; return(Hand); } } // // Interface for a direct call from client\conrqust.c // DWORD Ow2ExecPgm( IN ULONG Flags, IN PSZ Arguments OPTIONAL, IN PSZ Variables OPTIONAL, IN PSZ ImageFileName, #if PMNT IN ULONG IsPMApp, #endif // PMNT IN PVOID SessionStartData OPTIONAL, IN POS2_STDHANDLES StdStruc, OUT HANDLE *pHandle, OUT HANDLE *tHandle, OUT ULONG *dwProcessId ) { STARTUPINFO StartInfo; STARTUPINFOW StartInfoW; PROCESS_INFORMATION ProcessInfo; BOOL b; DWORD dwCreateFlags, status = 0; UNICODE_STRING ImageString_U; UNICODE_STRING ArgString_U; UNICODE_STRING TitleString_U; RtlZeroMemory(&StartInfo, sizeof(STARTUPINFO)); StartInfo.cb = sizeof(STARTUPINFO); StartInfo.dwFlags = STARTF_USESHOWWINDOW; StartInfo.wShowWindow = SW_SHOWDEFAULT; dwCreateFlags = CREATE_SUSPENDED; if (Flags & EXEC_WINDOW_PROGRAM) { // This is a window program, so create it with CREATE_NEW_PROCESS_GROUP // (it will enable us to send CTRL_EVENT to all the group) // dwCreateFlags |= CREATE_NEW_PROCESS_GROUP; // // redirect standard handles if we need to // if (StdStruc->Flags & STDFLAG_ALL) { if (StdStruc->Flags & STDFLAG_IN) { StartInfo.hStdInput = StdStruc->StdIn; } else { StartInfo.hStdInput = SesGrp->StdIn; } if (StdStruc->Flags & STDFLAG_OUT) { StartInfo.hStdOutput = StdStruc->StdOut; } else { StartInfo.hStdOutput = SesGrp->StdOut; } if (StdStruc->Flags & STDFLAG_ERR) { StartInfo.hStdError = StdStruc->StdErr; } else { StartInfo.hStdError = SesGrp->StdErr; } StartInfo.dwFlags |= STARTF_USESTDHANDLES; } Flags &= ~EXEC_WINDOW_PROGRAM; } if (Flags == 4) { // EXEC_BACKGROUND == 4 dwCreateFlags |= DETACHED_PROCESS; } if (SessionStartData) { SetSessionParameters( SessionStartData, &dwCreateFlags, ImageFileName, #if PMNT IsPMApp, #endif // PMNT &StartInfo ); } #if DBG IF_OD2_DEBUG(TEMP) { KdPrint(("OS2SES(util-Ow2ExecPgm): CreateProcess %s\n Arg %s\n", ImageFileName, Arguments)); } #endif // // Translate all the OEM parameters (MB) to Unicode // // // ImageFileName // if (!(Or2CreateUnicodeStringFromMBz( &ImageString_U, ImageFileName ))) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate ImageFileName %s OEM to Unicode\n", ImageFileName)); #endif return(status); } // // Arguments // if (!(Or2CreateUnicodeStringFromMBz( &ArgString_U, Arguments ))) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate Arguments %s OEM to Unicode\n", Arguments)); #endif if (ImageFileName) RtlFreeUnicodeString(&ImageString_U); return(status); } // // StartupInfo // RtlMoveMemory(&StartInfoW, &StartInfo, sizeof(StartInfo)); TitleString_U.Buffer = NULL; if (!(Or2CreateUnicodeStringFromMBz( &TitleString_U, StartInfo.lpTitle ))) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate Title %s OEM to Unicode\n", StartInfo.lpTitle )); #endif if (ImageFileName) RtlFreeUnicodeString(&ImageString_U); if (Arguments) RtlFreeUnicodeString(&ArgString_U); return(status); } StartInfoW.lpTitle = TitleString_U.Buffer; b = CreateProcessW(ImageString_U.Buffer, ArgString_U.Buffer, NULL, NULL, TRUE, // inherit all handles dwCreateFlags, Variables, NULL, &StartInfoW, &ProcessInfo ); // // Free Unicode Strings // if (ImageFileName) RtlFreeUnicodeString(&ImageString_U); if (Arguments) RtlFreeUnicodeString(&ArgString_U); if (TitleString_U.Buffer) RtlFreeUnicodeString(&TitleString_U); // // check for error // if (!b) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-Ow2ExecPgm): CreateProcess of %s failed status = %x \n", ImageFileName, status)); #endif return(status); } *pHandle = ProcessInfo.hProcess; *tHandle = ProcessInfo.hThread; *dwProcessId = ProcessInfo.dwProcessId; return(status); } DWORD CreateOS2SRV( OUT PHANDLE hProcess ) { STARTUPINFOW StartInfo; PROCESS_INFORMATION ProcessInfo; BOOL b; DWORD status = 0; WCHAR Path[MAX_PATH]; UNICODE_STRING CdString_U; *hProcess = NULL; GetSystemDirectoryW((LPWSTR) &Path, MAX_PATH); if (!(Or2CreateUnicodeStringFromMBz( &CdString_U, getenv("SYSTEMROOT") ))) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-CreateOS2SRV): Fail to translate curdir %s to Unicode, status %lx\n", getenv("SYSTEMROOT"), status)); #endif return(status); } /* for ( i = 0 ; Path[i] ; i++ ) { Path[i] = toupper(Path[i]); } */ wcscat(Path, L"\\OS2SRV.EXE"); RtlZeroMemory(&StartInfo, sizeof(STARTUPINFOW)); StartInfo.cb = sizeof(STARTUPINFOW); StartInfo.wShowWindow = SW_SHOWDEFAULT; if (fService) b = CreateProcessW(Path, L"OS2SRV /S", NULL, NULL, FALSE, DETACHED_PROCESS, NULL, CdString_U.Buffer, //getenv("SYSTEMROOT"), &StartInfo, &ProcessInfo ); else b = CreateProcessW(Path, L"", NULL, NULL, FALSE, DETACHED_PROCESS, NULL, CdString_U.Buffer, //getenv("SYSTEMROOT"), &StartInfo, &ProcessInfo ); if (!b) { status = GetLastError(); #if DBG KdPrint(("OS2SES(util-CreateOS2SRV): CreateProcess of OS2SRV failed status = %x \n", status)); #endif return(status); } *hProcess = ProcessInfo.hProcess; SetPriorityClass(*hProcess, REALTIME_PRIORITY_CLASS); RtlFreeUnicodeString(&CdString_U); return(status); } BOOL ServeWinCreateProcess(PWINEXECPGM_MSG PReq, PVOID PStatus) { DWORD Rc = 0; #if DBG IF_OD2_DEBUG( TASKING ) { KdPrint(("OS2SES: ServeWinCreateProcess: Request: %u\n", PReq->Request)); } #endif switch (PReq->Request) { case RemoveConsoleThread: if ( SesGrp->WinSyncProcessNumberInSession == 0 ) { Rc = RemoveConForWinProcess(); } if (!Rc) { SesGrp->WinSyncProcessNumberInSession++ ; SesGrp->WinProcessNumberInSession++ ; } break; case RestartConsoleThread: // force CurPos, CurType and LVB to get updated Ow2VioReadCurPos(); Ow2VioReadCurType(); Ow2LvbUpdateLVBBuffer(); if(SesGrp->WinSyncProcessNumberInSession == 1) { Rc = AddConAfterWinProcess(); } SesGrp->WinSyncProcessNumberInSession--; SesGrp->WinProcessNumberInSession--; break; case AddWin32ChildProcess: SesGrp->WinProcessNumberInSession++; break; case RemWin32ChildProcess: // force CurPos, CurType and LVB to get updated Ow2VioReadCurPos(); Ow2VioReadCurType(); Ow2LvbUpdateLVBBuffer(); SesGrp->WinProcessNumberInSession--; break; default: Rc = (DWORD) -1; //STATUS_INVALID_PARAMETER; #if DBG KdPrint(("OS2SES(util-ServeWinCreateProcess): Unknown WinExec request = %X\n", PReq->Request)); #endif } if ( Rc == 1 ) { /* BUGBUG=> BUGBUG! error code and returned Status are wrong */ if (!(Rc = GetLastError())) { #if DBG KdPrint(("OS2SES(util-ServeWinCreateProcess): Unknown LastError\n")); #endif Rc = (DWORD) -1; } } *(PDWORD) PStatus = Rc; return(TRUE); // Continue } VOID Ow2WinExitCode2ResultCode( IN DWORD Status, OUT PDWORD pReturnCode, OUT PDWORD pExitReason) /*++ Routine Description: This routine translate the ExitCode from Win32's GetExitCodeProcess to the OS/2 structure RESULTCODES fields: ExitReason and ExitResult. Arguments: Status - the ExitCode from Win32 process. pReturnCode - where to put the translated ExitResult pExitReason - where to put the translated ExitReason Return Value: Note: --*/ { *pReturnCode = Status; *pExitReason = TC_EXIT; if (*pReturnCode == STATUS_WAIT_0) { /* Success: STATUS_WAIT_O 0x00000000L) 0 */ } else if (*pReturnCode == STATUS_CONTROL_C_EXIT) { /* STATUS_CONTROL_C_EXIT 0xC000013AL) 0 */ *pExitReason = TC_TRAP; *pReturnCode = 0; } else if (((ULONG)*pReturnCode >= (ULONG)STATUS_ARRAY_BOUNDS_EXCEEDED) && ((ULONG)*pReturnCode <= (ULONG)STATUS_PRIVILEGED_INSTRUCTION)) { /* STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008CL) 5 STATUS_FLOAT_DENORMAL_OPERAND 0xC000008DL) 16 STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008EL) 16 STATUS_FLOAT_INEXACT_RESULT 0xC000008FL) 16 STATUS_FLOAT_INVALID_OPERATION 0xC0000090L) 16 STATUS_FLOAT_OVERFLOW 0xC0000091L) 16 STATUS_FLOAT_STACK_CHECK 0xC0000092L) 16 STATUS_FLOAT_UNDERFLOW 0xC0000093L) 16 STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094L) 0 STATUS_INTEGER_OVERFLOW 0xC0000095L) 4 STATUS_PRIVILEGED_INSTRUCTION 0xC0000096L) 13 */ if (*pReturnCode == STATUS_INTEGER_DIVIDE_BY_ZERO) { *pReturnCode = 0; } else if (*pReturnCode == STATUS_INTEGER_OVERFLOW) { *pReturnCode = 4; } else if (*pReturnCode == STATUS_PRIVILEGED_INSTRUCTION) { *pReturnCode = 13; } else if (*pReturnCode == STATUS_ARRAY_BOUNDS_EXCEEDED) { *pReturnCode = 5; } else { *pReturnCode = 16; } *pExitReason = TC_TRAP; } else if (*pReturnCode == STATUS_STACK_OVERFLOW) { /* STATUS_STACK_OVERFLOW 0xC00000FDL) 12 */ *pExitReason = TC_TRAP; *pReturnCode = 12; } else if (*pReturnCode == STATUS_DATATYPE_MISALIGNMENT) { /* STATUS_DATATYPE_MISALIGNMENT 0x80000002L) 17 */ *pExitReason = TC_TRAP; *pReturnCode = 17; } else if (*pReturnCode == STATUS_BREAKPOINT) { /* STATUS_BREAKPOINT 0x80000003L) 3 */ *pExitReason = TC_TRAP; *pReturnCode = 3; } else if (*pReturnCode == STATUS_SINGLE_STEP) { /* STATUS_SINGLE_STEP 0x80000004L) 1 */ *pExitReason = TC_TRAP; *pReturnCode = 1; } else if (*pReturnCode == STATUS_ACCESS_VIOLATION) { /* STATUS_ACCESS_VIOLATION 0xC0000005L) 13 */ *pExitReason = TC_TRAP; *pReturnCode = 13; } else if (*pReturnCode == STATUS_ILLEGAL_INSTRUCTION) { /* STATUS_ILLEGAL_INSTRUCTION 0xC000001DL) 6 */ *pExitReason = TC_TRAP; *pReturnCode = 6; } else if ((*pReturnCode == STATUS_ABANDONED_WAIT_0) || (*pReturnCode == STATUS_USER_APC) || (*pReturnCode == STATUS_TIMEOUT) || (*pReturnCode == STATUS_PENDING) || (*pReturnCode == STATUS_NONCONTINUABLE_EXCEPTION) || (*pReturnCode == STATUS_INVALID_DISPOSITION)) { /* STATUS_WAIT_0 0x00000000L) ?? STATUS_ABANDONED_WAIT_0 0x00000080L) 255 STATUS_USER_APC 0x000000C0L) 255 STATUS_TIMEOUT 0x00000102L) 255 STATUS_PENDING 0x00000103L) 255 STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025L) 255 STATUS_INVALID_DISPOSITION 0xC0000026L) 255 */ *pExitReason = TC_TRAP; *pReturnCode = 255; } #if DBG IF_OD2_DEBUG3( OS2_EXE, TASKING, WIN ) { KdPrint(("Ow2WinExitCode2ResultCode: Status %lu => Result %lu, Reason %lu\n", Status, *pReturnCode, *pExitReason)); } #endif return; } typedef struct _STARTDATA { USHORT Length; USHORT Related; USHORT FgBg; USHORT TraceOpt; PSZ PgmTitle; PSZ PgmName; PBYTE PgmInputs; PBYTE TermQ; PBYTE Environment; USHORT InheritOpt; USHORT SessionType; PSZ IconFile; ULONG PgmHandle; USHORT PgmControl; USHORT InitXPos; USHORT InitYPos; USHORT InitXSize; USHORT InitYSize; USHORT Reserved; PSZ ObjectBuffer; ULONG ObjectBuffLen; } STARTDATA, *PSTARTDATA; VOID SetSessionParameters( IN PVOID SessionStartData, OUT PDWORD pCreateFlags, IN PSZ ImageFileName, #if PMNT IN ULONG IsPMApp, #endif // PMNT OUT LPSTARTUPINFO pStartInfo ) { PSTARTDATA pStartData = (PSTARTDATA)SessionStartData; ULONG Length = pStartData->Length, i; PUCHAR Title; #if PMNT // // Don't create console for PM process that is the child session of other PM // process. // if (!ProcessIsPMApp() || (!IsPMApp) || (!pStartData->Related)) { #endif *pCreateFlags |= CREATE_NEW_CONSOLE; #if PMNT } #endif Title = (pStartData->PgmTitle) ? pStartData->PgmTitle : ImageFileName; i = strlen(Title); if (i > 32) { Title += ( i - 32 ); i = 32; } if (!pStartData->PgmTitle) // // we give the pathname, strip out the last component // { #ifdef DBCS // MSKK Jun.16.1993 V-AkihiS { ULONG LastComponentPos = 0; ULONG j; for (j = 0; j < i; ) { if (Ow2NlsIsDBCSLeadByte(Title[j], SesGrp->DosCP)) { j++; if (j < i) { j++; } } else { if ((Title[j] == '\\' ) || (Title[j] == '/' ) || (Title[j] == ':' )) { LastComponentPos = j; } j++; } } Title += j + 1; } #else for ( ; i ; i-- ) { if ((Title[i - 1] == '\\' ) || (Title[i - 1] == '/' ) || (Title[i - 1] == ':' )) { Title += i; break; } } #endif } pStartInfo->lpTitle = Title; pStartInfo->dwXSize = (DWORD)SesGrp->ScreenColNum; pStartInfo->dwYSize = (DWORD)SesGrp->ScreenRowNum; if (Length > 40) { if (pStartData->PgmControl & 0x8000) // window position & size { if (Length > 42) { pStartInfo->dwX = (DWORD)(pStartData->InitXPos / SesGrp->CellHSize); } if (Length > 44) { pStartInfo->dwY = (DWORD)(pStartData->InitYPos / SesGrp->CellVSize); } if (Length > 46) { pStartInfo->dwXSize = (DWORD)(pStartData->InitXSize / SesGrp->CellHSize); } if (Length > 48) { pStartInfo->dwYSize = (DWORD)(pStartData->InitYSize / SesGrp->CellVSize); } pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION); } if (!pStartData->FgBg) // window ForeGround { if (pStartData->PgmControl == 0) // invisible { //pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION); } else { if (pStartData->PgmControl & 2) // maximize { pStartInfo->wShowWindow = SW_SHOWMAXIMIZED; } if (pStartData->PgmControl & 4) // minimize { pStartInfo->wShowWindow = SW_SHOWMINIMIZED; } } } else // window BackGround { if (pStartData->PgmControl == 0) // invisible { //pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION); } else { if (pStartData->PgmControl & 2) // maximize { pStartInfo->wShowWindow = SW_MAXIMIZE; } if (pStartData->PgmControl & 4) // minimize { pStartInfo->wShowWindow = SW_MINIMIZE; } } } } else { if (!pStartData->FgBg) // window ForeGround { //pStartInfo->wShowWindow |= STARTF_USESIZE; } } if (pStartInfo->wShowWindow) { pStartInfo->dwFlags |= STARTF_USESHOWWINDOW; } // ((Length > 30 ) ? pStartData->SessionType : 0); // TmpInheritOpt; }