mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
5.6 KiB
282 lines
5.6 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winexcpt.cxx
|
|
|
|
Abstract:
|
|
|
|
Provides RPC exception handling support for Windows 3.x
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 4/16/92
|
|
|
|
--*/
|
|
|
|
#include "sysinc.h"
|
|
#include "rpc.h"
|
|
|
|
#undef NULL
|
|
#include "windows.h"
|
|
|
|
#include "rpcwin.h"
|
|
|
|
// For windows, the DLL data segment is shared amoung all processes
|
|
// we must maintain an exception record for each task that is using
|
|
// this DLL. Each active exception context has an owner. When an
|
|
// exception context is needed it is located by an associated search
|
|
// of the exception table.
|
|
|
|
typedef struct {
|
|
HTASK Task;
|
|
pExceptionBuff CurrentContext;
|
|
} EXCEPTION, *PEXCEPTION;
|
|
|
|
PEXCEPTION ExceptTable;
|
|
int TableSize;
|
|
|
|
// This should be small to keep down the linear search times.
|
|
|
|
#define TABLE_INCREMENT 2
|
|
|
|
|
|
int
|
|
InitializeWinExceptions (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the exception table.
|
|
|
|
Returns:
|
|
|
|
0 for success, 1 for failure due to out of memory.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
TableSize += TABLE_INCREMENT;
|
|
|
|
if (!(ExceptTable = (PEXCEPTION)
|
|
LocalAlloc(LMEM_FIXED, sizeof(EXCEPTION) * TableSize)))
|
|
return(1);
|
|
|
|
memset(ExceptTable, 0, sizeof(EXCEPTION) * TableSize);
|
|
return(0);
|
|
}
|
|
|
|
|
|
static void
|
|
SearchForContext(
|
|
IN HTASK TaskSelf
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do an associative search for an exception and bring it to the front
|
|
of the exception table.
|
|
|
|
Arguments:
|
|
|
|
TaskSelf - task that we are looking for
|
|
|
|
--*/
|
|
{
|
|
pExceptionBuff oldExcept;
|
|
int i;
|
|
|
|
// Scan the exception table for one owned by this task.
|
|
|
|
for (i = 0; i < TableSize && ExceptTable[i].Task != TaskSelf; i++) ;
|
|
|
|
// If there wasn't a prior exception record in the table,
|
|
// terminate the process.
|
|
|
|
if (i == TableSize)
|
|
{
|
|
MessageBox(0, "Application encountered unhandled exception.\n Application will be terminated.",
|
|
"Remote Procedure Call", MB_TASKMODAL | MB_OK | MB_ICONSTOP);
|
|
|
|
// Hammer the process dead, without all the windows cleanup.
|
|
|
|
_asm
|
|
{
|
|
mov ax, 4c01h
|
|
int 21h
|
|
};
|
|
}
|
|
|
|
// Now that we have table slot, swap it with the
|
|
// first slot so it is at the front of the list.
|
|
|
|
ExceptTable[i].Task = ExceptTable[0].Task;
|
|
ExceptTable[0].Task = TaskSelf;
|
|
|
|
oldExcept = ExceptTable[0].CurrentContext;
|
|
ExceptTable[0].CurrentContext = ExceptTable[i].CurrentContext;
|
|
ExceptTable[i].CurrentContext = oldExcept;
|
|
}
|
|
|
|
|
|
|
|
void CALLBACK
|
|
ExceptionCleanup(HTASK TaskSelf)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean-up the exception record for the current task (if it's still
|
|
there). Called at task-exit time.
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
|
|
// Scan the exception table for one owned by this task.
|
|
for (i = 0; i < TableSize && ExceptTable[i].Task != TaskSelf; i++) ;
|
|
|
|
if (i < TableSize)
|
|
ExceptTable[i].Task = 0;
|
|
}
|
|
|
|
|
|
|
|
void PAPI * RPC_ENTRY
|
|
RpcSetExceptionHandler (
|
|
IN pExceptionBuff newhandler
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the exception context to a given value. Each
|
|
process has its own exception context which must be maintained.
|
|
New contexts are created on demand for processes.
|
|
|
|
Arguments:
|
|
|
|
newhandler - new context value to association with this process
|
|
|
|
Returns:
|
|
|
|
The old handler.
|
|
|
|
--*/
|
|
{
|
|
HTASK TaskSelf = GetCurrentTask();
|
|
pExceptionBuff oldExcept;
|
|
|
|
if (ExceptTable->Task != TaskSelf)
|
|
{
|
|
int i, iFree;
|
|
|
|
// Scan the exception table for one owned by this task.
|
|
|
|
for (i = 0, iFree = -1;
|
|
i < TableSize && ExceptTable[i].Task != TaskSelf; i++)
|
|
{
|
|
// Keep track of a free slot to make allocation faster
|
|
|
|
if (ExceptTable[i].Task == 0 && iFree == -1)
|
|
iFree = i;
|
|
}
|
|
|
|
// If there wasn't a prior exception record in the table,
|
|
// allocate a new one.
|
|
|
|
if (i == TableSize)
|
|
{
|
|
if ((i = iFree) == -1)
|
|
{
|
|
// We are out of table entries, grow the table
|
|
// to be bigger.
|
|
|
|
PEXCEPTION LastExceptTable = ExceptTable;
|
|
|
|
if (InitializeWinExceptions())
|
|
|
|
// Can't allocate memory - get a context that will fail.
|
|
|
|
SearchForContext((HTASK) -1);
|
|
|
|
memcpy(ExceptTable, LastExceptTable,
|
|
sizeof(EXCEPTION) * (TableSize-TABLE_INCREMENT));
|
|
|
|
LocalFree((HLOCAL) LastExceptTable);
|
|
|
|
i = TableSize-TABLE_INCREMENT;
|
|
}
|
|
|
|
// Register an exit-time handler for this task
|
|
WinDLLAtExit(ExceptionCleanup);
|
|
}
|
|
|
|
// Now that we have table slot, swap it with the
|
|
// first slot so it is at the front of the list.
|
|
|
|
ExceptTable[i].Task = ExceptTable[0].Task;
|
|
ExceptTable[0].Task = TaskSelf;
|
|
|
|
oldExcept = ExceptTable[0].CurrentContext;
|
|
ExceptTable[0].CurrentContext = ExceptTable[i].CurrentContext;
|
|
ExceptTable[i].CurrentContext = oldExcept;
|
|
}
|
|
|
|
oldExcept = ExceptTable->CurrentContext;
|
|
ExceptTable->CurrentContext = newhandler;
|
|
|
|
return (oldExcept);
|
|
}
|
|
|
|
|
|
|
|
void PAPI * RPC_ENTRY
|
|
RpcGetExceptionHandler (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the current exception context for the current task.
|
|
|
|
Returns:
|
|
|
|
The exception record.
|
|
|
|
--*/
|
|
{
|
|
HTASK TaskSelf = GetCurrentTask();
|
|
|
|
if (ExceptTable->Task != TaskSelf)
|
|
SearchForContext(TaskSelf);
|
|
|
|
return(ExceptTable->CurrentContext);
|
|
}
|
|
|
|
|
|
|
|
void RPC_ENTRY
|
|
RpcLeaveException (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pop the exception stack one level. The back pointer to the previous
|
|
exception records becomes the current.
|
|
|
|
--*/
|
|
{
|
|
HTASK TaskSelf = GetCurrentTask();
|
|
|
|
if (ExceptTable->Task != TaskSelf)
|
|
SearchForContext(TaskSelf);
|
|
|
|
ExceptTable->CurrentContext = ExceptTable->CurrentContext->pExceptNext;
|
|
}
|