/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
os2.c
Abstract:
This module contains the main of the session console process (OS2.EXE).
Author:
Avi Nathan (avin) 17-Jul-1991
Environment:
User Mode Only
Revision History:
--*/
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#define WIN32_ONLY
#include "os2ses.h"
#include "trans.h"
#include "os2res.h"
#include "os2win.h"
#include "conapi.h"
#ifdef PMNT
#define INCL_32BIT
#include "pmnt.h"
extern ULONG PMNTGetOurWindow(void);
extern ULONG PMSubprocSem32;
extern BOOLEAN Ow2WriteBackCloseEvent();
extern APIRET DosSemClear(ULONG hsem);
#endif
BOOLEAN fService = FALSE; // Are we running as a service ?
BOOLEAN fRootService = FALSE; // Directly invoked by the service
/*
* External prototypes
*/
#undef InitOs2SessionPort
DWORD InitOs2ssSessionPort();
DWORD
Ow2CommandLineWToCommandLineA(
IN LPWSTR CommandLineW,
OUT PSZ *CommandLineA
);
BOOLEAN
Od2DllInitialize(
IN PVOID DllHandle,
IN ULONG Reason,
IN PCONTEXT Context OPTIONAL
);
BOOLEAN
Od2ProcessIsDetached(VOID);
int
Loader_main(VOID);
VOID
Od2FinalProcessCleanup();
/*
* Internal prototypes
*/
UINT
GetPgmName(
int argc
);
UINT
InitStdConout();
#define OS2_VIO_MAX_ROW 100
WORD StartUpwAttributes = 0x7;
CONSOLE_SCREEN_BUFFER_INFO StartUpScreenInfo;
CONSOLE_CURSOR_INFO StartUpCursorInfo;
PVOID BASE_TILE;
HANDLE handOS2 = NULL;
//
// Environment related global variables
//
PSZ Od2CommandLinePtr; // to be used by dllinit.c
char Od2PgmFullPathBuf[MAX_PATH + 1];
ULONG Od2PgmFullPathBufLength;
PSZ Od2PgmFilePath;
DWORD Od2ForegroundWindow;
ULONG Od2DosExitIsDone = 0;
#if DBG
BYTE SetEventHandlerStr[] = "SetEventHandler";
BYTE InitStdConoutStr[] = "InitStdConout";
BYTE SesGrpInitStr[] = "SesGrpInit";
BYTE RestoreWin32ParmsBeforeTerminationStr[] = "RestoreWin32ParmsBeforeTermination";
BYTE CreateServerThreadsStr[] = "CreateServerThreads";
BYTE ResumeServerThreadsStr[] = "ResumeServerThreads";
#endif
extern BOOLEAN Od2ReceivedSignalAtInit;
extern DWORD Od2InitSignalType;
BOOL
EventHandlerRoutine (IN ULONG CtrlType);
extern PVOID Od2Process;
PVOID IsOs2Thread();
ULONG Od2ThreadId();
ULONG Od2ProcessId();
PSZ Od2ApplName();
PSZ Od2GetLastAPI();
// global variable to keep exception information
EXCEPTION_POINTERS ExPtrs;
EXCEPTION_RECORD ExRec;
WORD wSavedFpStatus = 0, wSavedFpCtrl = 0;
/*
* Os2ServiceThread:
* Created to allow the service who started this copy of OS2.EXE to terminate
* the process tree.
*/
VOID
Os2ServiceThread(
IN PVOID Parameter
)
{
CHAR SemName[MAX_PATH];
HANDLE hServiceEvent;
wsprintf(SemName, "OS2SSService-%d", GetCurrentProcessId());
//
// Create the service event for this process
//
hServiceEvent = CreateEventA(
NULL,
FALSE, // automatic reset
FALSE, // initial state = non-signaled
SemName);
if (hServiceEvent == NULL)
{
#if DBG
DbgPrint("OS2: Os2ServiceThread(), error at CreateEvent, error=%d\n",
GetLastError());
#endif
}
// Wait on the Service semaphore
if (WaitForSingleObject(
hServiceEvent,
INFINITE) == WAIT_FAILED)
{
#if DBG
DbgPrint("OS2: Os2ServiceThread(), failed to NtWaitForSingleObject PMShellEvent, error=%d\n",
GetLastError());
#endif
}
#if DBG
DbgPrint("OS2: Os2ServiceThread() - event signaled\n");
#endif
#if PMNT
//
// PM apps handling
//
if (ProcessIsPMProcess())
{
// Regular app (i.e. not PMShell)
if (!ProcessIsPMShell())
{
if (!Ow2WriteBackCloseEvent())
{
// We failed to write-back a close event:
// must be DosExecPgm proc; Pass event through semaphore
DosSemClear(PMSubprocSem32);
Sleep(7900L);
}
}
else // PMSHELL
{
#if DBG
DbgPrint("OS2: Os2ServiceThread(), ignoring signal - process is PMShell\n");
#endif
}
return;
}
#endif // PMNT
SendSignalToOs2Srv(XCPT_SIGNAL_KILLPROC);
}
DWORD Ow2FaultFilter(ULONG wFaultFilter, PEXCEPTION_POINTERS lpExP)
{
// copy the exception record to global variable
ExPtrs = *lpExP;
ExRec = *lpExP->ExceptionRecord;
_asm {
fnstcw wSavedFpCtrl
fnstsw wSavedFpStatus
}
return(wFaultFilter);
}
void Ow2DisplayExceptionInfo()
{
char ErrMsg[512];
wsprintf(ErrMsg,
"OS2: Internal Exception 0x%lx occured at %lx\nApplication Name=%s\nLast OS/2 API=%s\nTID=%d PID=%d\nFP: Ctrl=%lx, Status=%lx\nEAX=%lx EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\nESP=%lx EBP=%lx",
ExRec.ExceptionCode,
ExRec.ExceptionAddress,
Od2Process ? Od2ApplName() : "None",
(IsOs2Thread()) ? (Od2GetLastAPI()) : "None",
(IsOs2Thread()) ? (Od2ThreadId()) : 0,
Od2Process ? Od2ProcessId() : 0,
(DWORD) wSavedFpCtrl,
(DWORD) wSavedFpStatus,
(ExPtrs.ContextRecord)->Eax,
(ExPtrs.ContextRecord)->Ebx,
(ExPtrs.ContextRecord)->Ecx,
(ExPtrs.ContextRecord)->Edx,
(ExPtrs.ContextRecord)->Esi,
(ExPtrs.ContextRecord)->Edi,
(ExPtrs.ContextRecord)->Esp,
(ExPtrs.ContextRecord)->Ebp
);
MessageBox(NULL, ErrMsg, "Error", MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND);
}
void __cdecl
main (int argc,
char *argv[],
char *envp[])
{
UINT StringCode;
ULONG tmp, ConStringCode;
#if PMNT
HANDLE NewForegroundWindow;
#endif //PMNT
//
// Get the handle of the foreground window which is the window of the
// curent process.
// BUGBUG - This value is not neccessarily the right value because
// the user might immediately switch to another window which
// results in OS2.EXE having the handle of some other window
//
// Do not remove this statement without consulting with PM/NT team - the
// Ow2ForegroundWindow below is used by PM/NT call(s).
Ow2ForegroundWindow = GetForegroundWindow();
//
// Put the entire execution of the os/2 program inside a try/except.
// This way we ensure that we recover from 32 bit exceptions
//
// Note that the above is done only for RETAIL build. For DBG builds,
// it is better to let NTSD handle the exception so that we can debug
// the problem right away.
//
try {
timing = 0;
#if DBG
Os2Debug = 0;
fVerbose = FALSE;
fTrace = FALSE;
fBrkOnStart = FALSE;
#endif
//timing = GetTickCount();
//printf("Os2 main init time is %d\n", timing);
//Os2Debug = OS2_DEBUG_OS2_EXE;
Os2ReturnCode = 0;
Od2SignalEnabled = FALSE;
SetErrorMode(1);
/*
* get the full path of the program to execute
*/
if (timing)
{
printf("Os2 time before GetPgmName is %d\n", (GetTickCount()) - timing);
}
if (StringCode = GetPgmName(argc))
{
Ow2Exit(StringCode, Od2PgmFullPathBuf, 1);
}
if (!fService)
{
char TmpBuffer[256];
// OS/2 child processes of OS/2 apps started from a service don't
// have the /S switch but they should find a variable 'Os2SSService'
// in their environment
if (GetEnvironmentVariable(
"Os2SSService",
&TmpBuffer[0],
256))
{
// non-zero return code means variable was found
fService = TRUE;
}
}
else
{
if (!SetEnvironmentVariable(
"Os2SSService",
"1"))
{
#if DBG
KdPrint(("OS2: failed to SetEnvironment variable Os2SSService, error=%d\n",
GetLastError()));
#endif
}
}
#if DBG
if (fService)
KdPrint(("Os2: Loading %s (as a service)\n", Od2PgmFullPathBuf));
else
KdPrint(("Os2: Loading %s\n", Od2PgmFullPathBuf));
#endif
/*
* Set event handlers to handle Ctrl-C etc.
*/
if (timing)
{
printf("Os2 time before SetEventHandlers is %d\n", (GetTickCount()) - timing);
}
SetEventHandlers(TRUE);
/*
* Set Std-Handles and open CONOUT$
*/
if (timing)
{
printf("Os2 time before InitStdConout is %d\n", (GetTickCount()) - timing);
}
ConStringCode = InitStdConout();
/*
* Connect with OS2SS
*/
if (timing)
{
printf("Os2 time before InitOs2ssSessionPort is %d\n", (GetTickCount()) - timing);
}
tmp = InitOs2ssSessionPort();
//
// InitOs2ssSessionPort returns:
// 0L - problem with resources, like memory
// -1L - problem connecting to os2srv
// otherwise - OK
//
if (tmp == -1L)
{
Ow2Exit(IDS_OS2_NOCONNECT, NULL, 1);
}
else if (tmp == 0)
{
Ow2Exit(IDS_OS2_NOMEMORY, NULL, 1);
}
Sleep(2);
#if PMNT
NewForegroundWindow = (HANDLE)PMNTGetOurWindow();
if ((NewForegroundWindow != 0) &&
(NewForegroundWindow != Ow2ForegroundWindow))
{
#if DBG
DbgPrint("Os2:main(), warning Ow2ForeGroundWindow changed from %x to %x\n",
Ow2ForegroundWindow,
NewForegroundWindow);
#endif // DBG
Ow2ForegroundWindow = NewForegroundWindow;
}
#endif // PMNT
if (timing)
{
printf("Os2 time before calling Od2DllInitialize is %d\n", (GetTickCount()) - timing);
}
if (!Od2DllInitialize(NULL, DLL_PROCESS_ATTACH, NULL))
{
#if DBG
KdPrint(("OS2SES: Od2DllInitialize failed\n"));
#endif
Ow2Exit(IDS_OS2_INITFAIL, NULL, 1);
// Ow2Exit(0, NULL, 1);
}
if (Od2CommandLinePtr)
if (LocalFree(Od2CommandLinePtr) != NULL)
{
#if DBG
KdPrint(("OS2SES: Failed to free PsevdoArgv\n"));
#endif
}
if ( ConStringCode )
{
if (!Od2ProcessIsDetached())
{
#if DBG
KdPrint(("Os2: InitStdConout returned error %d\n", ConStringCode));
#endif
/**
For now, we do nothing, because the code below popup a window for a second.
if we find a better way, we'll use it, otherwise do nothing.
//
// Two cases - created with DETACH_PROCESS by non-OS/2 app
// OR
// failed somehow to create the console.
//
// No official way to test it, so we allocate console,
// if we succeed, this is the 1st case, free it and continue.
// if we fail, it means we already have one but can't access
// it somehow, fail the app.
//
if (AllocConsole())
{
FreeConsole();
}
else
Ow2Exit(ConStringCode, NULL, 1);
**/
}
}
if (fRootService)
{
HANDLE ThreadHandle;
ULONG Tid;
ThreadHandle = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)Os2ServiceThread,
NULL,
0,
&Tid);
if (!ThreadHandle)
{
#if DBG
DbgPrint("OS2: main(), fail to create service thread, error %d\n",
GetLastError());
#endif
}
else
{
if (!CloseHandle(ThreadHandle))
{
#if DBG
DbgPrint("OS2: main(), CloseHandle(service thread=%x) failed, error=%d\n",
ThreadHandle, GetLastError());
#endif // DBG
}
}
}
if (timing)
{
printf("Os2 time before calling loader_main is %d\n", (GetTickCount()) - timing);
}
Loader_main();
if (Od2ReceivedSignalAtInit) {
//
// OS2.EXE received a signal before complete loading,
// handle it now
//
EventHandlerRoutine(Od2InitSignalType);
}
}
//
// if Os2Debug is on, and ntsd is attached, it will get the second chance
//
#if DBG
except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
#else
except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
#endif
#if DBG
KdPrint(("OS2SES: Internal error - Exception occured in 32bit os2ss code\n"));
#endif
Ow2DisplayExceptionInfo();
//
// Cleanup client state, server will get notified
// via the exitprocess debug event
//
Od2FinalProcessCleanup();
Ow2Exit(IDS_OS2_INTERNAL_ERROR, NULL, 1);
}
}
VOID SetEventHandlers(IN BOOL fSet)
{
Or2WinSetConsoleCtrlHandler(
#if DBG
SetEventHandlerStr,
#endif
EventHandlerRoutine,
fSet
);
}
struct
{
LPTHREAD_START_ROUTINE lpStartAddress;
int Priority;
HANDLE *hServerThread;
} SERVER_THREAD_TABLE[] =
{
{
EventServerThread,
OS2_EVENT_THREAD_PRIORITY,
&EventServerThreadHandle
},
{
SessionRequestThread,
OS2_SERVER_THREAD_PRIORITY,
&Ow2hSessionRequestThread
},
{
NULL,
0,
NULL
}
};
DWORD
CreateServerThreads(VOID)
{
HANDLE tHandle;
DWORD Tid, i;
/*
* create 1 for getting Input Event and dispatch them to 2 seperate
* queues for Kbd & Mou
*/
for ( i = 0 ; SERVER_THREAD_TABLE[i].lpStartAddress ; i++ )
{
if((tHandle = Or2WinCreateThread(
#if DBG
CreateServerThreadsStr,
#endif
NULL,
0,
SERVER_THREAD_TABLE[i].lpStartAddress,
NULL,
CREATE_SUSPENDED,
&Tid
)) == NULL)
{
#if DBG
KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu CreateThread %u\n",
GetLastError(), i));
ASSERT( FALSE );
#endif
return(1L);
}
*SERVER_THREAD_TABLE[i].hServerThread = tHandle;
}
if(Or2WinResumeThread(
#if DBG
CreateServerThreadsStr,
#endif
Ow2hSessionRequestThread
) == -1)
{
#if DBG
KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu ResumeThread ServerRequest\n",
GetLastError()));
ASSERT( FALSE );
#endif
return(1L);
}
if (!Or2WinSetThreadPriority(
#if DBG
CreateServerThreadsStr,
#endif
Ow2hSessionRequestThread,
OS2_SERVER_THREAD_PRIORITY
))
{
#if DBG
IF_OD2_DEBUG( OS2_EXE )
KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu SetThreadPriority RequestThread\n",
GetLastError()));
#endif
}
return(0L);
}
DWORD
ResumeServerThreads(VOID)
{
HANDLE tHandle;
DWORD i;
for ( i = 0 ; SERVER_THREAD_TABLE[i].lpStartAddress ; i++ )
{
if ((tHandle = *SERVER_THREAD_TABLE[i].hServerThread) !=
Ow2hSessionRequestThread)
{
if(Or2WinResumeThread(
#if DBG
ResumeServerThreadsStr,
#endif
tHandle
) == -1)
{
#if DBG
KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu CreateThread %u\n",
GetLastError(), i));
ASSERT( FALSE );
#endif
return(1L);
}
if (!Or2WinSetThreadPriority(
#if DBG
ResumeServerThreadsStr,
#endif
tHandle,
SERVER_THREAD_TABLE[i].Priority
))
{
#if DBG
IF_OD2_DEBUG( OS2_EXE )
KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu SetThreadPriority %u\n",
GetLastError(), i));
#endif
}
}
}
return(0L);
}
#define SKIP_ARG( Ptr ) \
{ \
register char ch; \
argc --; \
while( ch = *Ptr++ ) \
{ \
if(( ch == ' ' ) || ( ch == '\t' )) \
{ \
break; \
} \
} \
} \
UINT
GetPgmName(
int argc
)
{
char *lpPgmName = NULL, CurChar, *ArgvPtr;
DWORD Rc;
int i;
CHAR ch;
/*
* Get the command line in OEM code page.
* Format is : "OS2 /P <full path> /C <original CommandLine>"
*/
Rc = Ow2CommandLineWToCommandLineA(
GetCommandLineW(),
&ArgvPtr
);
//RtlProcessHeap
if ( Rc )
{
return(IDS_OS2_NOMEMORY);
}
/*
* skip program name ("OS2.EXE")
*/
SKIP_ARG( ArgvPtr )
/*
* look for flags for os2 up to /C
*
*/
while ( argc )
{
if ( ArgvPtr[0] == '/' )
{
CurChar = ArgvPtr[1] | ('a'-'A');
ArgvPtr += 2;
if ( CurChar == 'c' )
{
/*
* Skip the /C and break from the while loop
*/
ArgvPtr++;
break;
} else switch ( CurChar )
{
case 'p':
SKIP_ARG(ArgvPtr);
lpPgmName = ArgvPtr;
break;
#if DBG
case 'b':
fBrkOnStart = TRUE;
KdPrint((
"OS2: Breakpoint caused by /B switch!\n"));
_asm int 3;
break;
case 'v':
fVerbose = TRUE;
break;
case 't':
fTrace = TRUE;
break;
#endif
case 's':
fService = TRUE;
#if PMNT
// Don't consider PMSHELL a root service, i.e. don't
// create a termination thread for it. We don't want
// PMSHELL to terminate even if the service which started it
// is stopped because there may be PM apps out there which
// weren't started by services.
if (!ProcessIsPMShell())
fRootService = TRUE;
#else
fRootService = TRUE;
#endif
break;
default:
strncpy(Od2PgmFullPathBuf, ArgvPtr, MAX_PATH);
Od2PgmFullPathBuf[MAX_PATH - 1] = '\0';
return(IDS_OS2_WHATFLAG);
}
} else
{
return(IDS_OS2_USAGE);
}
SKIP_ARG(ArgvPtr);
}
/*
* We exit the loop when "/C" was found or when "argc=0".
* Make sure "/C" was found and "/P <appl_full_path>" had been
* found.
*/
if (( CurChar != 'c' ) || !lpPgmName )
{
return(IDS_OS2_NOCMD);
}
/*
* The full path of the program to execute is pointed by lpPgmName
* but is space terminated. ArgvPtr points to the original command
* line.
*/
for ( i = 0 ;
( lpPgmName[i] != '\0' ) &&
( lpPgmName[i] != ' ' ) &&
( lpPgmName[i] != '\t' ) &&
( i < MAX_PATH )
; Od2PgmFullPathBuf[i] = lpPgmName[i], i++ );
if ( i == MAX_PATH )
{
return(IDS_OS2_NOMEMORY);
}
Od2PgmFullPathBuf[i] = '\0';
Od2PgmFullPathBufLength = i;
// Code below replaces the program name with the full-path. This caused
// the PM Deskpic screen-saver to GP because it looked for '\'
// (31-May-94, RAID bug#2932)
SKIP_ARG(ArgvPtr);
ch = lpPgmName[i];
if (argc > 1)
{
Od2CommandLinePtr =
(PSZ)LocalAlloc(0,
// Path + SPACE + arguments + /0
Od2PgmFullPathBufLength + 1 + strlen(ArgvPtr) + 1);
}
else
{
Od2CommandLinePtr =
(PSZ)LocalAlloc(0,
// Path + /0
Od2PgmFullPathBufLength + 1);
}
if (Od2CommandLinePtr == NULL)
{
return(IDS_OS2_NOMEMORY);
}
strcpy(Od2CommandLinePtr, Od2PgmFullPathBuf);
if (argc > 1)
{
strncat(Od2CommandLinePtr, &ch, 1); // Cat the argv0-1 seperating char
strcat(Od2CommandLinePtr, ArgvPtr); // Fill in all the rest (argvs)
}
// Find the program name by skipping up to (and include) '\', '/' and ':'
Od2PgmFilePath = &Od2PgmFullPathBuf[0];
for ( i = 0 ; ( Od2PgmFullPathBuf[i] != '\0' ) ; i++ )
{
if (( Od2PgmFullPathBuf[i] == ':' ) ||
( Od2PgmFullPathBuf[i] == '/' ) ||
( Od2PgmFullPathBuf[i] == '\\' ))
{
Od2PgmFilePath = &Od2PgmFullPathBuf[i+1];
}
}
return(0);
}
UINT
InitStdConout()
{
// SECURITY_ATTRIBUTES SecurityAttributes;
#if DBG
DWORD Status;
#endif
/*
* Get a handle to CONIN$ & CONOUT$ for KBD & VIO requests
*/
hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE);
hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE);
hStdInConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdIn) &&
VerifyConsoleIoHandle(hConsoleStdIn));
hStdOutConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdOut) &&
VerifyConsoleIoHandle(hConsoleStdOut));
hStdErrConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdErr) &&
VerifyConsoleIoHandle(hConsoleStdErr));
// SecurityAttributes.bInheritHandle = FALSE;
// SecurityAttributes.lpSecurityDescriptor = NULL;
// SecurityAttributes.nLength = sizeof (SECURITY_ATTRIBUTES);
/*
* Open CONOUT$ if StdOut id redirected
*/
if (hStdOutConsoleType)
{
hConsoleOutput = hConsoleStdOut;
} else
{
hConsoleOutput = Or2WinCreateFileW(
#if DBG
InitStdConoutStr,
#endif
L"CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, /* &SecurityAttributes, */
OPEN_EXISTING, /* CREATE_ALWAYS, */
0,
NULL
);
// hConsoleOutput = Or2WinCreateConsoleScreenBuffer(
// #if DBG
// InitStdConoutStr,
// #endif
// GENERIC_READ | GENERIC_WRITE,
// FILE_SHARE_READ|FILE_SHARE_WRITE,
// NULL, /* &SecurityAttributes */
// CONSOLE_TEXTMODE_BUFFER,
// NULL);
if (hConsoleOutput == INVALID_HANDLE_VALUE)
{
return (IDS_OS2_CREATECONOUT);
}
if (!Or2WinSetConsoleActiveScreenBuffer(
#if DBG
InitStdConoutStr,
#endif
hConsoleOutput
))
{
#if DBG
// return (IDS_OS2_ACTIVECONOUT);
Status = GetLastError();
IF_OD2_DEBUG( ANY )
{
KdPrint(("OS2SES(Os2-SetConsoleActiveScreenBuffer): can't activate CONOUT(%lu) in Full-Screen\n", Status));
}
#endif
}
}
hConOut = hConsoleOutput;
SetConsoleInputModeAgain = 0;
SetConsoleOutputModeAgain = 0;
return(0);
}
DWORD
SesGrpInit()
{
DWORD Type, Rc, i;
HANDLE *Handle;
USHORT *fType, FileType;
COORD Coord;
CONSOLE_FONT_INFO ConsoleCurrentFont;
#if DBG
UCHAR ErrBuff[ERROR_BUFFER_SIZE];
#endif
//SesGrp->WinProcessNumberInSession = 0;
//SesGrp->WinSyncProcessNumberInSession = 0;
SesGrp->hConsoleInput = hConsoleInput;
SesGrp->hConsoleOutput = hConsoleOutput;
SesGrp->StdIn = hConsoleStdIn;
SesGrp->StdOut = hConsoleStdOut;
SesGrp->StdErr = hConsoleStdErr;
SesGrp->StdInFlag = hStdInConsoleType;
SesGrp->StdOutFlag = hStdOutConsoleType;
SesGrp->StdErrFlag = hStdErrConsoleType;
//SesGrp->KbdInFocus = 0;
SesGrp->NoKbdFocus = TRUE;
SesGrp->FirstProcess = TRUE;
SesGrp->StdInHandleCount = 1;
SesGrp->StdOutHandleCount = 1;
SesGrp->StdErrHandleCount = 1;
//SesGrp->hConsolePopUp = NULL;
for ( i=0, Handle = &(SesGrp->StdIn),
fType = &(SesGrp->StdInFileType) ;
i<3 ; i++, Handle++, fType++ )
{
Type = GetFileType(*Handle);
// BUGBUG maybe call NtQueryVolumeInformationFile directly (base\client\filehops.h)
switch (Type)
{
case FILE_TYPE_DISK:
FileType = 0x0000; // FILE_TYPE_FILE
break;
case FILE_TYPE_CHAR:
FileType = 0x0001; // FILE_TYPE_DEV
break;
case FILE_TYPE_PIPE:
FileType = 0x0002; // FILE_TYPE_PIPE
break;
//case FILE_TYPE_UNKNOWN:
default:
#if DBG
IF_OD2_DEBUG( OS2_EXE )
{
DbgPrint("OS2SES(SesGrpInit): GetFileType(handle %lx) failed, LastError = %ld\n",
*Handle, GetLastError());
}
#endif
FileType = 0x0001; // FILE_TYPE_DEV - to be safety
break;
}
#if DBG
IF_OD2_DEBUG( OS2_EXE )
{
KdPrint(("OS2SES(HandlesTypes): Handle %lx(%lu), WinType %lx, Os2Type %lx\n",
*Handle, i, Type, FileType ));
}
#endif
*fType = FileType;
}
Or2WinGetConsoleScreenBufferInfo(
#if DBG
SesGrpInitStr,
#endif
hConsoleOutput,
&StartUpScreenInfo
);
SesGrp->ScreenColNum = StartUpScreenInfo.dwSize.X;
if ((SesGrp->ScreenRowNum = StartUpScreenInfo.dwSize.Y) > OS2_VIO_MAX_ROW)
{
#if DBG
IF_OD2_DEBUG( ANY )
{
KdPrint(("OS2SES: Screen size is bigger than the maximum for OS/2.\n"));
KdPrint((" OS2SS will use only first %d rows of the %d available\n",
OS2_VIO_MAX_ROW, StartUpScreenInfo.dwSize.Y));
}
#endif
SesGrp->ScreenRowNum = OS2_VIO_MAX_ROW;
}
SesGrp->CellVSize = SesGrp->CellHSize = 8;
if (!GetCurrentConsoleFont(hConsoleOutput,
TRUE, /* maximize window */
&ConsoleCurrentFont))
{
#if DBG
Rc = GetLastError();
if ( Rc == ERROR_FULLSCREEN_MODE )
{
IF_OD2_DEBUG( ANY )
{
KdPrint(("OS2SES(Os2-GetCurrentConsoleFont): can't query current font(%lu) in Full-Screen\n",
Rc));
}
} else
{
sprintf(ErrBuff, "OS2SES(Os2-GetCurrentConsoleFont): can't query current font(%lu)\n", Rc);
ASSERT1( ErrBuff, FALSE );
}
#endif
} else
{
Coord = GetConsoleFontSize(hConsoleOutput,
ConsoleCurrentFont.nFont);
#if DBG
if ((!Coord.X) && (!Coord.Y))
{
Rc = GetLastError();
sprintf(ErrBuff, "OS2SES(Os2-GetConsoelFontSize): can't query font Size(%lu)\n", Rc);
ASSERT1( ErrBuff, FALSE );
}
#endif
SesGrp->CellVSize = Coord.Y;
SesGrp->CellHSize = Coord.X;
}
StartUpwAttributes = StartUpScreenInfo.wAttributes;
if (!Or2WinGetConsoleMode(
#if DBG
SesGrpInitStr,
#endif
hConsoleOutput,
&SesGrp->DefaultWinOutputMode
))
{
Rc = GetLastError();
#if DBG
ASSERT1( "Can not get CONOUT for default Mode\n", FALSE );
#endif
SesGrp->DefaultWinOutputMode = WINDOW_DEFAULT_OUTPUT_MODE;
}
SesGrp->OutputModeFlags = WINDOW_DEFAULT_OUTPUT_MODE;
if (!Or2WinSetConsoleMode(
#if DBG
SesGrpInitStr,
#endif
hConsoleOutput,
OS2_DEFAULT_OUTPUT_MODE
))
{
Rc = GetLastError();
#if DBG
ASSERT1( "Can not set CONOUT for default Mode\n", FALSE );
#endif
}
else
SesGrp->OutputModeFlags = OS2_DEFAULT_OUTPUT_MODE;
SesGrp->MaxLVBsize =
(SesGrp->ScreenColNum * SesGrp->ScreenRowNum * 4 );
if (SesGrp->MaxLVBsize < 80 * 100 * 4) /* buffer for 100x80 window */
{
SesGrp->MaxLVBsize = 80 * 100 * 4;
}
if (SesGrp->MaxLVBsize > (64 * 1024)) /* more than 64K */
{
SesGrp->MaxLVBsize = 64 * 1024;
}
#if DBG
IF_OD2_DEBUG( OS2_EXE )
{
KdPrint(("OS2SES(Os2-Handles): hIn %lx, hOut %lx, StdIn %lx (%s), StdOut %lx(%s), StdErr %lx(%s)\n",
hConsoleInput, hConsoleOutput,
hConsoleStdIn, ((hStdInConsoleType) ? "Std" : "Rdr" ),
hConsoleStdOut, ((hStdOutConsoleType) ? "Std" : "Rdr" ),
hConsoleStdErr, ((hStdErrConsoleType) ? "Std" : "Rdr" )
));
}
#endif
#if DBG
// KdPrint(("OS2SES(Os2-ConInfo): Size %x:%x, Pos %x:%x, Attr %x, Win %x:%x-%x:%x, Max %x:%x\n",
// StartUpScreenInfo.dwSize.Y, StartUpScreenInfo.dwSize.X,
// StartUpScreenInfo.dwCursorPosition.Y, StartUpScreenInfo.dwCursorPosition.X,
// StartUpScreenInfo.wAttributes,
// StartUpScreenInfo.srWindow.Top, StartUpScreenInfo.srWindow.Left,
// StartUpScreenInfo.srWindow.Bottom, StartUpScreenInfo.srWindow.Right,
// StartUpScreenInfo.dwMaximumWindowSize.Y, StartUpScreenInfo.dwMaximumWindowSize.X ));
#endif
return(0L);
}
VOID
RestoreWin32ParmsBeforeTermination()
{
Or2WinSetConsoleMode(
#if DBG
RestoreWin32ParmsBeforeTerminationStr,
#endif
hConsoleInput,
DefaultWinInputMode
);
Or2WinSetConsoleMode(
#if DBG
RestoreWin32ParmsBeforeTerminationStr,
#endif
hConsoleOutput,
SesGrp->DefaultWinOutputMode
);
/*
* This is a workaround since the CMD doesn't restore its CurType
*
* Bug #4323 (OS2SS: CURSOR DISAPPEARS AFTER EXITING WORD5.0)
*/
Or2WinSetConsoleCursorInfo(
#if DBG
RestoreWin32ParmsBeforeTerminationStr,
#endif
hConsoleOutput,
&StartUpCursorInfo
);
}
VOID
Ow2Exit(
IN UINT StringCode,
IN PCHAR ErrorText,
IN int ExitCode
)
/*++
Routine Description:
This routine performs the exit from OS2.EXE for OS/2 application.
Arguments:
StringCode - A code to retrieve an error message from the string RC file
(os2.rc). It's printed to the stderr. If zero - no message will be
printed.
ErrorText - test to use in the error message (in place of %s, like
DLL name, ordinal number, etc.)
ExitCode - code to return to Win32 CRT
Return Value:
Note:
This routine calls CRT's exit() and doesn't return.
--*/
{
WCHAR ErrBuffW[ERROR_BUFFER_SIZE];
CHAR ErrBuff[ERROR_BUFFER_SIZE];
DWORD Count;
DWORD Rc;
//if ((handOS2 = GetModuleHandle("os2.exe")) == NULL)
if (StringCode)
{
if ((handOS2 == NULL) &&
((handOS2 = GetModuleHandle(NULL)) == NULL))
{
Rc = GetLastError();
#if DBG
KdPrint(("OS2 ended! (error %lu on GetModuleHandle for ExitCode %lu)\n",
Rc, StringCode));
#endif
} else
{
if ((Count = LoadStringW(handOS2,
StringCode,
ErrBuffW,
ERROR_BUFFER_SIZE)) == 0L)
{
Rc = GetLastError();
#if DBG
KdPrint(("OS2 ended! (error %lu on LoadStringW for ExitCode %lu)\n",
Rc, StringCode));
#endif
} else
{
Count = WideCharToMultiByte(
CP_OEMCP,
0L,
ErrBuffW,
Count,
ErrBuff,
ERROR_BUFFER_SIZE,
NULL,
NULL);
if (Count != 0) {
ErrBuff[Count] = '\0';
fprintf(stderr, ErrBuff, ErrorText);
#if DBG
KdPrint((ErrBuff, ErrorText));
#endif
} else {
Rc = GetLastError();
#if DBG
KdPrint(("OS2 ended! (error %lu on WideCharToMultiByte for ExitCode %lu)\n",
Rc, StringCode));
#endif
}
}
}
}
#if DBG
IF_OD2_DEBUG( ANY )
{
KdPrint(( "OS2 ended! (%lx)\n", ExitCode ));
}
#endif
ExitProcess(ExitCode);
}
#define CAP_BUFFER_SIZE 80
#define TEXT_BUFFER_SIZE 256
CHAR DefaultConfigSysAccessCap[] = "OS/2 Subsystem -- CONFIG.SYS Access";
CHAR DefaultConfigSysAccessText[] = "An OS/2 Application requested access to CONFIG.SYS - Read Only access is granted. In order to modify OS/2 CONFIG.SYS, logon as ADMINISTRATOR.\n";
CHAR DriveNotReadyDefaultMsg[] = "There is no disk in the drive.\nPlease insert a disk into drive%s.\n" ;
CHAR WriteProtectDefaultMsg[] = "The disk cannot be written to because it is write protected.\nPlease remove the write protection from the volume\nin drive%s.\n" ;
CHAR DriveNotReadyDefaultHdr[] = "%s.EXE - No Disk";
CHAR WriteProtectDefaultHdr[] = "%s.EXE - Write Protect Error";
CHAR DefaultBoundAppLoadCap[] = "%s - OS/2 Subsystem Bound Application Load Failure";
CHAR DefaultBoundAppLoadText[] =
"This application uses an unsupported OS/2 API, and therefore "
"cannot be executed by the OS/2 Subsystem. "
"After the application terminates, you may try re-running it "
"using forcedos, as the DOS Subsystem may be able to support it. "
"Press Enter to terminate the application.";
VOID
Ow2ConfigSysPopup(
VOID
)
/*++
Routine Description:
Pops up a window informing the user that s/he cannot update the registry due
to insufficient privilege.
The message is only popped up once per program.
Arguments:
None.
Return Value:
None.
--*/
{
static MessageAlreadyShown = FALSE;
CHAR TextBuff[TEXT_BUFFER_SIZE];
CHAR CapBuff[CAP_BUFFER_SIZE];
if (MessageAlreadyShown) {
return;
}
MessageAlreadyShown = TRUE;
if ((handOS2 == NULL) &&
((handOS2 = GetModuleHandle(NULL)) == NULL))
{
#if DBG
KdPrint(("Ow2ConfigSysPopup: error %lu on GetModuleHandle\n",
GetLastError()));
#endif
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
IDS_OS2_CONFIGSYS_ACCESS_TXT,
TextBuff,
TEXT_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2ConfigSysPopup: error %lu on LoadString1\n",
GetLastError()));
}
#endif
strncpy(TextBuff, DefaultConfigSysAccessText, TEXT_BUFFER_SIZE - 1);
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
IDS_OS2_CONFIGSYS_ACCESS_CAP,
CapBuff,
CAP_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2ConfigSysPopup: error %lu on LoadString2\n",
GetLastError()));
}
#endif
strncpy(CapBuff, DefaultConfigSysAccessCap, CAP_BUFFER_SIZE - 1);
}
MessageBoxEx( NULL,
TextBuff,
CapBuff,
MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK | MB_SETFOREGROUND,
0
);
}
int
Ow2DisplayHardErrorPopup(
IN int Drive,
IN BOOLEAN WriteProtectError,
IN PUCHAR AppName
)
{
int size;
char CaptionMessage[CAP_BUFFER_SIZE], TextMessage[TEXT_BUFFER_SIZE];
char CaptionBuffer[CAP_BUFFER_SIZE], TextBuffer[TEXT_BUFFER_SIZE];
char ApplNameBuff[OS2_MAX_APPL_NAME], DriveBuf[4];
char *ErrMsg, *ErrHdr;
UINT CapCode, TextCode;
strncpy(ApplNameBuff, AppName, OS2_MAX_APPL_NAME);
size = strlen(ApplNameBuff);
if ((size > 4 ) && !stricmp(&ApplNameBuff[size-4], ".exe")) {
ApplNameBuff[size-4] = '\0';
}
strupr(ApplNameBuff);
if (Drive != 0)
{
sprintf(DriveBuf, " %c:", ('A' - 1) + Drive );
} else
{
DriveBuf[0] = '\0';
}
if (WriteProtectError)
{
ErrMsg = WriteProtectDefaultMsg;
ErrHdr = WriteProtectDefaultHdr;
CapCode = IDS_OS2_WRITE_PROTECT_CAP;
TextCode = IDS_OS2_WRITE_PROTECT_TXT;
} else
{
ErrMsg = DriveNotReadyDefaultMsg;
ErrHdr = DriveNotReadyDefaultHdr;
CapCode = IDS_OS2_DEVIVE_NOT_READY_CAP;
TextCode = IDS_OS2_DEVIVE_NOT_READY_TXT;
}
if ((handOS2 == NULL) &&
((handOS2 = GetModuleHandle(NULL)) == NULL))
{
#if DBG
KdPrint(("Ow2DisplayHardErrorPopup: error %lu on GetModuleHandle\n",
GetLastError()));
#endif
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
TextCode,
TextMessage,
TEXT_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2DispalyardErrorPopup: error %lu on LoadString1\n",
GetLastError()));
}
#endif
strncpy(TextMessage, ErrMsg, TEXT_BUFFER_SIZE - 1);
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
CapCode,
CaptionMessage,
CAP_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2DispalyardErrorPopup: error %lu on LoadString2\n",
GetLastError()));
}
#endif
strncpy(CaptionMessage, ErrHdr, CAP_BUFFER_SIZE - 1);
}
sprintf(CaptionBuffer, CaptionMessage, ApplNameBuff);
sprintf(TextBuffer, TextMessage, DriveBuf);
return (MessageBox(
GetActiveWindow(),
TextBuffer,
CaptionBuffer,
MB_ABORTRETRYIGNORE | MB_DEFBUTTON2 | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND
));
}
VOID
Ow2BoundAppLoadPopup(
IN PSZ AppName
)
/*++
Routine Description:
Pops up a window informing the user that an attempt to load a bound app has
failed, and that s/he may try to use forcedos.
Arguments:
None.
Return Value:
None.
--*/
{
CHAR TextBuff[512];
CHAR CapBuff[CAP_BUFFER_SIZE];
CHAR CapBuff2[CAP_BUFFER_SIZE];
if ((handOS2 == NULL) &&
((handOS2 = GetModuleHandle(NULL)) == NULL))
{
#if DBG
KdPrint(("Ow2BoundAppLoadPopup: error %lu on GetModuleHandle\n",
GetLastError()));
#endif
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
IDS_OS2_BOUND_APP_LOAD_TXT,
TextBuff,
512))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2BoundAppLoadPopup: error %lu on LoadString1\n",
GetLastError()));
}
#endif
strncpy(TextBuff, DefaultBoundAppLoadText, 511);
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
IDS_OS2_BOUND_APP_LOAD_CAP,
CapBuff,
CAP_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2BoundAppLoadPopup: error %lu on LoadString2\n",
GetLastError()));
}
#endif
strncpy(CapBuff, DefaultBoundAppLoadCap, CAP_BUFFER_SIZE - 1);
}
sprintf(CapBuff2, CapBuff, AppName);
MessageBoxEx( NULL,
TextBuff,
CapBuff2,
MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND,
0
);
}
#ifdef PMNT
CHAR DefaultPMShellNotUpCap[] = "%s - PM Subsystem Application Load Failure";
CHAR DefaultPMShellNotUpText[] = "You are attempting to execute an application under the PM Subsystem. \
PM Shell needs to be running before this application. \
Click on OK, or press ENTER to terminate the application, \
then start PM Shell and re-try.";
CHAR Default2ndPMShellCap[] = "%s - PM Subsystem 2nd PM Shell Failure";
CHAR Default2ndPMShellText[] = "You are attempting to execute PM Shell. \
Another copy of PM shell is already running, and therefore \
this copy cannot be executed by the PM Subsystem.";
CHAR DefaultPMShellFullScreenCap[] = "%s - PM Subsystem PM Shell Load Failure";
CHAR DefaultPMShellFullScreenText[] = "PM Shell cannot be started from a full-screen CMD session. \
Please start it from the Program Manager or from a windowed CMD session.";
VOID
Ow2PMShellErrorPopup(
IN PSZ AppName,
IN int error_flag
)
/*++
Routine Description:
Pops up a window informing the user that:
1. an attempt to load a PM has failed because PM Shell is not up
2. an attemp to load PM Shelll has failed because another copy
of PM Shell is already up.
Arguments:
None.
Return Value:
None.
--*/
{
CHAR TextBuff[512];
CHAR CapBuff[CAP_BUFFER_SIZE];
CHAR CapBuff2[CAP_BUFFER_SIZE];
UINT ids_txt,ids_cap;
CHAR *default_txt,*default_cap;
if (error_flag == ERROR_PMSHELL_NOT_UP) {
ids_txt = IDS_OS2_PMSHELL_NOT_UP_TXT;
ids_cap = IDS_OS2_PMSHELL_NOT_UP_CAP;
default_txt = DefaultPMShellNotUpText;
default_cap = DefaultPMShellNotUpCap;
}
else if (error_flag == ERROR_PMSHELL_FULLSCREEN)
{
ids_txt = IDS_OS2_PMSHELL_FULLSCREEN_TXT;
ids_cap = IDS_OS2_PMSHELL_FULLSCREEN_CAP;
default_txt = DefaultPMShellFullScreenText;
default_cap = DefaultPMShellFullScreenCap;
}
else {
ids_txt = IDS_OS2_2ND_PMSHELL_TXT;
ids_cap = IDS_OS2_2ND_PMSHELL_CAP;
default_txt = Default2ndPMShellText;
default_cap = Default2ndPMShellCap;
}
if ((handOS2 == NULL) &&
((handOS2 = GetModuleHandle(NULL)) == NULL))
{
#if DBG
KdPrint(("Ow2PMShellErrorPopup: error %lu on GetModuleHandle\n",
GetLastError()));
#endif
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
ids_txt,
TextBuff,
512))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2PMShellErrorPopup: error %lu on LoadString1\n",
GetLastError()));
}
#endif
strncpy(TextBuff, default_txt, 511);
}
if (( handOS2 == NULL) ||
!LoadString(handOS2,
ids_cap,
CapBuff,
CAP_BUFFER_SIZE))
{
#if DBG
if ( handOS2 != NULL)
{
KdPrint(("Ow2PMShellErrorPopup: error %lu on LoadString2\n",
GetLastError()));
}
#endif
strncpy(CapBuff, default_cap, CAP_BUFFER_SIZE - 1);
}
sprintf(CapBuff2, CapBuff, AppName);
MessageBoxEx( NULL,
TextBuff,
CapBuff2,
MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND,
0
);
}
// PatrickQ: This function is called from another module (client\dllpmnt.c) and
// is here just because os2ses\os2.c has the right set of include files for
// WIN32 calls.
VOID PMNTRemoveCloseMenuItem()
{
HMENU SystemMenu;
DWORD rc;
SystemMenu = GetSystemMenu(Ow2ForegroundWindow, FALSE);
if (SystemMenu == 0)
{
#if DBG
DbgPrint("Failed to get system menu !\n");
#endif
return;
}
rc = DeleteMenu(
SystemMenu,
SC_CLOSE,
MF_BYCOMMAND);
#if DBG
if (!rc)
{
DbgPrint("Failed to delete menu - last error=%d\n",
GetLastError());
}
#endif
}
#endif //PMNT