Windows2003-3790/inetcore/outlookexpress/wabw/wabapi/imemx.c
2020-09-30 16:53:55 +02:00

1278 lines
30 KiB
C

/*
* IMEMX.C
*
* Per-instance global data for WINNT, WIN95 (trivial), WIN16, and Mac.
*
* Copyright 1993-1995 Microsoft Corporation. All Rights Reserved.
*/
#pragma warning(disable:4100) /* unreferenced formal parameter */
#pragma warning(disable:4201) /* nameless struct/union */
#pragma warning(disable:4209) /* benign typedef redefinition */
#pragma warning(disable:4214) /* bit field types other than int */
#pragma warning(disable:4001) /* single line comments */
#pragma warning(disable:4115) /* named type definition in parens */
#ifdef WIN32
#define INC_OLE2 /* Get the OLE2 stuff */
#define INC_RPC /* harmless on Windows NT; Windows 95 needs it */
#endif
#include "_apipch.h"
#ifdef DEBUG
#define STATIC
#else
#define STATIC static
#endif
#pragma warning (disable:4514) /* unreferenced inline function */
#ifdef WIN16
#pragma code_seg("IMAlloc")
#pragma warning(disable: 4005) /* redefines MAX_PATH */
#undef MAX_PATH
#include <toolhelp.h>
#pragma warning(default: 4005)
#pragma warning(disable: 4704) /* Inline assembler */
BOOL
FIsTask(HTASK hTask)
{
TASKENTRY teT;
BOOL fSucceed = FALSE;
teT.dwSize = sizeof(TASKENTRY);
fSucceed = TaskFirst(&teT);
while (fSucceed)
{
if (hTask == teT.hTask)
break;
fSucceed = TaskNext(&teT);
}
return fSucceed;
}
/*
* The InstList structure holds three parallel arrays.
* InstList.lprgwInstKey
* Holds the stack segment of each task that calls
* ScSetVerifyInstanceGlobals for the DLL we're in
* Since all Win16 tasks share the same x86 segment descriptor tables,
* no two tasks can have the same stack segment at the same time.
* InstList.lprglpvInst
* Holds a pointer to that task's instance globals in the slot with
* the same index as the task SS in lprgwInstKey.
* InstList.lprglpvInst
* Holds a task indentifier that is guaranteed unique to the task through
* the life (in memory) of the DLL. It is at the same index as the
* task SS in lprgwInstKey.
*/
/*
- IFindInstEx
-
* Purpose:
* Used to locate a particular task's instance pointer, and
* also to find a free slot in the table.
*
* Arguments:
* The value to look up. This is either a task's stack
* segment, or 0 (if an empty slot is being sought).
*
* Returns:
* Returns the index of the given value in rgwInstKey.
* If the value is not present, returns cInstEntries.
*
*/
#pragma warning(disable: 4035) /* function return value done in asm */
STATIC WORD
IFindInstEx(WORD w, WORD FAR * lprgwInstKey, WORD cInstEntries)
{
#ifdef USE_C_EQUIVALENT
WORD iInst, * pw = lprgwInstKey;
for (iInst = 0; iInst < cInstEntries; ++pw, ++iInst)
if (*pw == w)
break;
return(iInst);
#else
_asm
{
push es
push di
mov ax, w
mov cx, cInstEntries
mov bx, cx
jcxz done
les di, lprgwInstKey
cld
repne scasw
jnz done
sub bx, cx
dec bx
done: mov ax, bx
pop di
pop es
};
#endif
}
#pragma warning(default: 4035)
/*
- PvGetInstanceGlobalsEx
-
* Purpose:
* Returns a pointer to the instance global data structre for
* the current task.
*
* Returns:
* Pointer to the instance data structure, or NULL if no
* structure has yet been installed for this task.
*/
LPVOID
PvGetInstanceGlobalsInt(LPInstList lpInstList)
{
WORD iInst;
WORD wMe;
// get key for this process
_asm
{
mov wMe,ss
};
/* First check cached value */
if (lpInstList->wCachedKey == wMe)
return lpInstList->lpvCachedInst;
// Miss, do the lookup
iInst = IFindInstEx( wMe
, lpInstList->lprgwInstKey
, lpInstList->cInstEntries);
/* Cache and return the found value */
if (iInst != lpInstList->cInstEntries)
{
lpInstList->wCachedKey = wMe;
return (lpInstList->lpvCachedInst = lpInstList->lprglpvInst[iInst]);
}
/* If I get here then no instance was found
*/
return NULL;
}
#if 0
LPVOID
PvGetVerifyInstanceGlobalsInt(DWORD dwPid, LPInstList lpInstList)
{
WORD iInst;
WORD wMe;
// get key for this process
_asm
{
mov wMe,ss
};
// Always do the lookup
iInst = IFindInstEx( wMe
, lpInstList->lprgwInstKey
, lpInstList->cInstEntries);
/* If SS misses, return null right away */
if (iInst == lpInstList->cInstEntries)
return NULL;
/* SS hit, now check the OLE process ID */
if (dwPid != lpInstList->lprgdwPID[iInst])
{
/* Take no chances. Remove the entry and reset the cache. */
lpInstList->wCachedKey = 0;
lpInstList->lprgwInstKey[iInst] = 0;
lpInstList->lprglpvInst[iInst] = 0;
lpInstList->lprgdwPID[iInst] = 0;
return NULL;
}
/* Cache and return the found value.
*/
lpInstList->wCachedKey = wMe;
lpInstList->lpvCachedInst = lpInstList->lprglpvInst[iInst];
return lpInstList->lpvCachedInst;
}
#endif
LPVOID
PvSlowGetInstanceGlobalsInt(DWORD dwPid, LPInstList lpInstList)
{
WORD iInst;
WORD cInstEntries = lpInstList->cInstEntries;
/* Always do the lookup */
for (iInst = 0; iInst < cInstEntries; ++iInst)
{
if (lpInstList->lprgdwPID[iInst] == dwPid)
break;
}
/* If PID misses, return null */
if (iInst == cInstEntries)
return NULL;
/* Return the found value. Do not cache; this function is being
* called because SS is not what it "normally" is.
*/
return lpInstList->lprglpvInst[iInst];
}
/*
- ScSetVerifyInstanceGlobalsInt
-
* Purpose:
* Installs or deinstalls instance global data for the current task.
*
* Arguments:
* pv in Pointer to instance data structure (to
* install); NULL (to deinstall).
* dwPid in Zero or process ID, for better matching.
*
* Returns:
* MAPI_E_NOT_ENOUGH_MEMORY if no slot is available in the
* fixed-size table, else 0.
*/
LONG
ScSetVerifyInstanceGlobalsInt(LPVOID pv, DWORD dwPid, LPInstList lpInstList)
{
WORD iInst;
WORD wMe;
WORD cInstEntries = lpInstList->cInstEntries;
// get key for this process
_asm
{
mov wMe,ss
};
if (pv)
{
/* I am NOT supposed to be in the array at this time! */
Assert( IFindInstEx(wMe, lpInstList->lprgwInstKey, cInstEntries)
== cInstEntries);
/* Installing instance globals. Find a free slot and park there. */
Assert(cInstEntries || (lpInstList->dwInstFlags && INST_ALLOCATED));
if (!cInstEntries)
{
DWORD cbMem = cInstChunk
* (sizeof(WORD) + sizeof(LPVOID) + sizeof(DWORD)
+ sizeof(HTASK)); // raid 31090 lprghTask;
if (!(lpInstList->lprgwInstKey
= (WORD FAR *) GlobalAllocPtr( GPTR | GMEM_SHARE
, cbMem)))
{
#ifdef DEBUG
OutputDebugString("Instance list can't be allocated.\r\n");
#endif
return MAPI_E_NOT_ENOUGH_MEMORY;
}
ZeroMemory( lpInstList->lprgwInstKey, (size_t) cbMem);
lpInstList->cInstEntries = cInstEntries = cInstChunk;
lpInstList->lprglpvInst = (LPVOID FAR *) (lpInstList->lprgwInstKey + cInstEntries);
lpInstList->lprgdwPID = (DWORD FAR *) (lpInstList->lprglpvInst + cInstEntries);
lpInstList->lprghTask = (HTASK FAR *) (lpInstList->lprgdwPID + cInstEntries);
}
iInst = IFindInstEx(0, lpInstList->lprgwInstKey, cInstEntries);
if (iInst == cInstEntries)
{
UINT uidx;
// raid 31090: Time to do some scavanging. Find a HTASK that isn't
// valid and use that slot.
for ( uidx = 0; uidx < cInstEntries; uidx++ )
{
if ( !lpInstList->lprghTask[uidx] || !FIsTask( lpInstList->lprghTask[uidx] ) )
{
// found one
iInst = uidx;
break;
}
}
if ( uidx == cInstEntries )
{
DebugTrace( "MAPI: ScSetVerifyInstanceGlobalsInt maxed out instance data and tasks can't be scavanged\n" );
return MAPI_E_NOT_ENOUGH_MEMORY;
}
}
// set the instance data
lpInstList->lprglpvInst[iInst] = pv;
lpInstList->lprgwInstKey[iInst] = wMe;
lpInstList->lprgdwPID[iInst] = dwPid;
lpInstList->lprghTask[iInst] = GetCurrentTask();
/* Set the cache. */
lpInstList->wCachedKey = wMe;
lpInstList->lpvCachedInst = pv;
}
else
{
/* Deinstalling instance globals. Search and destroy. */
iInst = IFindInstEx(wMe, lpInstList->lprgwInstKey, cInstEntries);
if (iInst == cInstEntries)
{
#ifdef DEBUG
OutputDebugString("No instance globals to reset\r\n");
#endif
return MAPI_E_NOT_INITIALIZED;
}
lpInstList->lprglpvInst[iInst] = NULL;
lpInstList->lprgwInstKey[iInst] = 0;
lpInstList->lprgdwPID[iInst] = 0L;
/* Clear the cache. */
lpInstList->wCachedKey = 0;
lpInstList->lpvCachedInst = NULL;
}
return 0;
}
LONG
ScSetInstanceGlobalsInt(LPVOID pv, LPInstList lpInstList)
{
return ScSetVerifyInstanceGlobalsInt(pv, 0L, lpInstList);
}
BOOL __export FAR PASCAL
FCleanupInstanceGlobalsInt(LPInstList lpInstList)
{
/*
* The docs say don't make Windows calls from this callback.
* That means NO DEBUG TRACES
*/
/* This code belongs in the WEP */
/*
* First, double-check that the DLL's data segment is available.
* Code snitched from MSDN article "Loading, Initializing, and
* Terminating a DLL."
*/
/*
_asm
{
push cx
mov cx, ds ; get selector of interest
lar ax, cx ; get selector access rights
pop cx
jnz bail ; failed, segment is bad
test ax, 8000h ; if bit 8000 is clear, segment is not loaded
jz bail ; we're OK
};
*/
//$DEBUG Assert non-zero entries here
if ( (lpInstList->dwInstFlags & INST_ALLOCATED)
&& lpInstList->cInstEntries
&& lpInstList->lprgwInstKey)
{
GlobalFreePtr(lpInstList->lprgwInstKey);
lpInstList->cInstEntries = lpInstList->wCachedKey
= 0;
lpInstList->lprgwInstKey = NULL;
lpInstList->lprglpvInst = NULL;
lpInstList->lprgdwPID = NULL;
lpInstList->lpvCachedInst = NULL;
}
return 0; /* don't suppress further notifications */
}
#elif defined(MAC) /* !WIN16 */
/*
* The Mac implementation uses a linked list containing unique keys
* to the calling process and pointers to instance data. This linked
* list is n-dimensional because the Mac version often groups several
* dlls into one exe.
*
* The OLE code that TomSax wrote allows us to keep track of the caller's
* %a5 world when we call from another application. This code depends on
* on that.
*
*/
typedef struct tag_INSTDATA {
DWORD dwInstKey;
DWORD dwPid;
LPVOID lpvInst[kMaxSet];
struct tag_INSTDATA *next;
} INSTDATA, *LPINSTDATA, **HINSTDATA;
LPINSTDATA lpInstHead = NULL;
#define PvSlowGetInstanceGlobals(_dw, _dwId) PvGetVerifyInstanceGlobals(_dw, _dwId)
VOID
DisposeInstData(LPINSTDATA lpInstPrev, LPINSTDATA lpInst)
{
HINSTDATA hInstHead = &lpInstHead;
/* This better only happen when both elements are NULL! */
if (lpInst->lpvInst[kInstMAPIX] == lpInst->lpvInst[kInstMAPIU])
{
/* No inst data, remove element from linked list */
if (lpInst == *hInstHead)
*hInstHead = lpInst->next;
else
lpInstPrev->next = lpInst->next;
DisposePtr((Ptr)lpInst);
}
}
/*
- PvGetInstanceGlobalsMac
-
* Purpose:
* Returns a pointer to the instance global data structre for
* the current task.
*
* Returns:
* Pointer to the instance data structure, or NULL if no
* structure has yet been installed for this task.
*/
LPVOID FAR PASCAL
PvGetInstanceGlobalsMac(WORD wDataSet)
{
HINSTDATA hInstHead = &lpInstHead;
LPINSTDATA lpInst = *hInstHead;
#ifdef DEBUG
if (wDataSet >= kMaxSet)
{
DebugStr("\pPvGetInstanceGlobals : This data set has not been defined.");
return NULL;
}
#endif
while (lpInst)
{
if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
break;
lpInst = lpInst->next;
}
if (lpInst == NULL)
return NULL;
return(lpInst->lpvInst[wDataSet]);
}
LPVOID FAR PASCAL
PvGetVerifyInstanceGlobals(DWORD dwPid, DWORD wDataSet)
{
HINSTDATA hInstHead = &lpInstHead;
LPINSTDATA lpInst, lpInstPrev;
lpInst = lpInstPrev = *hInstHead;
/* Always do the lookup */
while (lpInst)
{
if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
break;
lpInstPrev = lpInst;
lpInst = lpInst->next;
}
/* If PvGetInstanceGlobals() misses, return NULL right away */
if ((lpInst == NULL) || (lpInst->lpvInst[wDataSet] == NULL))
return NULL;
/* Found a match, now check the OLE process ID */
if (dwPid != lpInst->dwPid)
{
DisposeInstData(lpInstPrev, lpInst);
return NULL;
}
/* Return the found value */
return lpInst->lpvInst[wDataSet];
}
/*
- ScSetVerifyInstanceGlobals
-
* Purpose:
* Installs or deinstalls instance global data for the current task.
*
* Arguments:
* pv in Pointer to instance data structure (to
* install); NULL (to deinstall).
* dwPid in Zero or process ID, for better matching.
* wDataSet in Inst data set to init or deinit (MAPIX or MAPIU)
*
* Returns:
* MAPI_E_NOT_ENOUGH_MEMORY if a pointer of INSTDATA size cannot be
* created, else 0.
*/
LONG FAR PASCAL
ScSetVerifyInstanceGlobals(LPVOID pv, DWORD dwPid, WORD wDataSet)
{
HINSTDATA hInstHead = &lpInstHead;
LPINSTDATA lpInst, lpInstPrev;
lpInst = lpInstPrev = *hInstHead;
Assert(wDataSet < kMaxSet);
/* Find our linked list element and the one before it */
while (lpInst)
{
if (lpInst->dwInstKey == (DWORD)LMGetCurrentA5())
break;
lpInstPrev = lpInst;
lpInst = lpInst->next;
}
if (pv)
{
if (lpInst)
{
/* I am NOT supposed to be in the array at this time! */
Assert(lpInst->lpvInst[wDataSet] == NULL);
lpInst->lpvInst[wDataSet] = pv;
}
else
{
/* Add a new linked list element and store <pv> there. */
lpInst = (LPVOID) NewPtrClear(sizeof(INSTDATA));
if (!lpInst)
{
#ifdef DEBUG
OutputDebugString("Instance globals maxed out\r");
#endif
return MAPI_E_NOT_ENOUGH_MEMORY;
}
if (lpInstPrev)
lpInstPrev->next = lpInst;
else
*hInstHead = lpInst;
lpInst->dwInstKey = (DWORD)LMGetCurrentA5();
lpInst->dwPid = dwPid;
lpInst->lpvInst[wDataSet] = pv;
}
}
else
{
/* Deinstalling instance globals. Search and destroy. */
if (lpInst == NULL || lpInst->lpvInst[wDataSet] == NULL)
{
#ifdef DEBUG
OutputDebugString("No instance globals to reset\r");
#endif
return MAPI_E_NOT_INITIALIZED;
}
/* The memory for <lpInst->lpvInst[wDataSet]> is disposed of */
/* elsewhere. just as it was allocated elsewhere. */
lpInst->lpvInst[wDataSet] = NULL;
DisposeInstData(lpInstPrev, lpInst);
}
return 0;
}
LONG FAR PASCAL
ScSetInstanceGlobalsMac(LPVOID pv, WORD wDataSet)
{
return ScSetVerifyInstanceGlobals(pv, 0L, wDataSet);
}
BOOL FAR PASCAL
FCleanupInstanceGlobals(WORD wID, DWORD dwData)
{
/*
* This is no longer used.
*
*/
#ifdef DEBUG
DebugStr("\pCalled FCleanupInstanceGlobals : Empty function");
#endif
return 0;
}
#elif defined(_WINNT)
/* NT implementation of instance list stuff goes here */
// A new instance list is defined using "DefineInst(instance_name)"
// A new instance list is declared using "DeclareInst(instance_name);"
//
// You then access them using the functions below (through macros
// in _imemx.h)
// Access to the instance lists must be serialized
CRITICAL_SECTION csInstance;
//
// Each security context has its own instance. So that we can find
// the right instance data for a particular security context at any
// time, we maintain a global mapping of security contexts to instances
// called the instance list. Entries in the instance list appear in no
// particular order. That is, the list must always be searched linearly.
// It is expected that the number of security contexts is sufficiently
// small that a linear search is not a performance problem.
//
// Each entry in the instance list is just a struct which identifies a
// security context and its associated instance.
//
typedef struct _MAPI_INSTANCE_DESCRIPTOR
{
ULARGE_INTEGER uliSecurity; // Security context identifier
LPVOID lpInstance; // Pointer to associated instance data
} MAPI_INSTANCE_DESCRIPTOR, *LPMAPI_INSTANCE_DESCRIPTOR;
typedef struct _MAPI_INSTANCE_LIST
{
UINT cDescriptorsMax; // How many descriptors are in the array
UINT cDescriptorsMac; // How many are currently in use
MAPI_INSTANCE_DESCRIPTOR rgDescriptors[0];
} MAPI_INSTANCE_LIST, *LPMAPI_INSTANCE_LIST;
enum { INSTANCE_LIST_CHUNKSIZE = 20 };
#define NEW_INSTANCE
#if defined(NEW_INSTANCE)
/*
- UlCrcSid
-
* Purpose:
* compute a CRC-32 based on a seed and value
*
* Ripped from runt.c because we don't want to introduce all of
* that files dependencies just for one function
*
* Arguments:
* cb size of data to hash
* pb data to hash
*
* Returns:
* new seed value
*
* Source:
* UlCrc() in \mapi\src\common\runt.c
*/
static ULONG
UlCrcSid(UINT cb, LPBYTE pb)
{
int iLoop;
int bit;
DWORD dwSeed = 0;
BYTE bValue;
Assert(!IsBadReadPtr(pb, cb));
while (cb--)
{
bValue = *pb++;
dwSeed ^= bValue;
for (iLoop = 0; iLoop < 8; iLoop++)
{
bit = (int)(dwSeed & 0x1);
dwSeed >>= 1;
if (bit)
dwSeed ^= 0xedb88320;
}
}
return dwSeed;
}
/*++
Routine Description:
Returns the size and CRC of the SID that this code is running in the
account of. Should make a pretty good 64-bit number to uniqify by.
Arguments:
None
Return Value:
BOOL - if everything worked. Call the systems GetLastError() if
it didn't.
*lpulSize - size of the SID
*lpulCRC - CRC-32 of the SID
!!! This function is duplicated in \mapi\src\glh\glglobal.c
!!! We really need to put it in a static LIB!
--*/
static
BOOL WINAPI GetAccountCRC( ULONG *lpulSize, ULONG *lpulCRC)
{
BOOL fHappen = FALSE; // Assume the function failed
HANDLE hTok = NULL;
// max size of sid + TOKEN_USER base
#define TOKENBUFFSIZE (256*6) + sizeof (TOKEN_USER)
BYTE tokenbuff[TOKENBUFFSIZE];
ULONG ulcbTok = TOKENBUFFSIZE;
TOKEN_USER *ptu = (TOKEN_USER *) tokenbuff;
// Open the process and the process token, and get out the
// security ID.
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_QUERY, TRUE, //$ TRUE for Process security!
&hTok))
{
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_QUERY, FALSE, // Sometimes process security doesn't work!
&hTok))
{
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY,
&hTok))
goto out;
}
}
fHappen = GetTokenInformation(hTok,
TokenUser,
ptu,
ulcbTok,
&ulcbTok);
#ifdef DEBUG
AssertSz1 (fHappen, "GetTokenInformation fails with error %lu", GetLastError());
if ( fHappen &&
GetPrivateProfileInt("General", "TraceInstContext", 0, "mapidbg.ini") )
{
DWORD dwAccount;
CHAR rgchAccount[MAX_PATH+1];
DWORD dwDomain;
CHAR rgchDomain[MAX_PATH+1];
SID_NAME_USE snu;
dwAccount = sizeof(rgchAccount);
dwDomain = sizeof(rgchDomain);
if ( LookupAccountSid( NULL,
ptu->User.Sid,
rgchAccount,
&dwAccount,
rgchDomain,
&dwDomain,
&snu ) )
{
DebugTrace( "Locating MAPI instance for %s:%s\n", rgchDomain, rgchAccount );
}
}
#endif
//
// We should have the TOKEN_USER data now. Get the size of the
// contained SID then calculate its CRC.
//
if (fHappen && ulcbTok != 0 && (ptu->User.Sid != NULL))
{
*lpulSize = GetLengthSid (ptu->User.Sid);
*lpulCRC = UlCrcSid(*lpulSize, (LPBYTE) ptu->User.Sid);
}
#ifdef DEBUG
else
AssertSz (FALSE, "GetAccountCRC failed to get the SID");
#endif
out:
if (hTok)
CloseHandle(hTok);
return fHappen;
}
/*
- ForeachInstance() [EXTERNAL]
-
* Purpose:
* Iterates over all instances in an instance list
* performing the specified action on each
*
* Arguments:
* pfnAction Action to do for each instance. Must be
* a void function taking a pointer to
* instance data as a parameter.
* lpInstList Instance list
*
* Returns:
* nothing
*/
VOID FAR PASCAL
ForeachInstance( INSTACTION * pfnAction,
LPVOID pvInstList )
{
UINT iDescriptor;
//
// If there's no descriptor list, then there are obviously
// no descriptors and hence no instances to which an
// action can be applied.
//
if ( pvInstList == NULL )
goto ret;
//
// Trundle down the descriptor list applying the
// specified action to each instance therein.
//
for ( iDescriptor = 0;
iDescriptor < ((LPMAPI_INSTANCE_LIST) pvInstList)->cDescriptorsMac;
iDescriptor++ )
{
pfnAction( ((LPMAPI_INSTANCE_LIST) pvInstList)->rgDescriptors[iDescriptor].lpInstance );
}
ret:
return;
}
/*
- LpFindInstanceDescriptor()
-
* Purpose:
* Looks in the instance descriptor list for an instance
* descriptor corresponding to the specified security
* context.
*
* Arguments:
* lpInstList Instance list
* uliSecurity CRC'd security context
*
* Returns:
* A pointer to the instance descriptor or NULL if there is
* no instance descriptor for the specified security context.
*/
LPMAPI_INSTANCE_DESCRIPTOR
LpFindInstanceDescriptor( LPMAPI_INSTANCE_LIST lpInstList,
ULARGE_INTEGER uliSecurity )
{
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptorFound = NULL;
UINT iDescriptor;
//
// If there's no descriptor list, then there are obviously
// no descriptors matching this security context.
//
if ( lpInstList == NULL )
goto ret;
//
// Trundle down the descriptor list looking for our context.
// If we find it, then return its associated descriptor.
//
for ( iDescriptor = 0;
iDescriptor < lpInstList->cDescriptorsMac;
iDescriptor++ )
{
if ( lpInstList->rgDescriptors[iDescriptor].uliSecurity.QuadPart ==
uliSecurity.QuadPart )
{
lpDescriptorFound = &lpInstList->rgDescriptors[iDescriptor];
break;
}
}
ret:
return lpDescriptorFound;
}
/*
- ScNewInstanceDescriptor()
-
* Purpose:
* Creates a new instance descriptor in the instance descriptor list,
* allocating or growing the list as necessary.
*
* Arguments:
* plpInstList Pointer to instance list
* uliSecurity CRC'd security context
* pvInstance Associated instance
* plpDescriptorNew Pointer to returned descriptor
*
* Returns:
* A pointer to a new 0-filled instance descriptor added to
* to the instance descriptor list.
*/
__inline UINT
CbNewInstanceList( UINT cDescriptors )
{
return offsetof(MAPI_INSTANCE_LIST, rgDescriptors) +
sizeof(MAPI_INSTANCE_DESCRIPTOR) * cDescriptors;
}
SCODE
ScNewInstanceDescriptor( LPMAPI_INSTANCE_LIST * plpInstList,
ULARGE_INTEGER uliSecurity,
LPVOID pvInstance,
LPMAPI_INSTANCE_DESCRIPTOR * plpDescriptorNew )
{
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptor = NULL;
SCODE sc = S_OK;
Assert( !IsBadWritePtr( plpInstList, sizeof(LPMAPI_INSTANCE_LIST) ) );
Assert( !IsBadWritePtr( plpDescriptorNew, sizeof(LPMAPI_INSTANCE_DESCRIPTOR) ) );
//
// Allocate/Grow the descriptor list if necessary.
//
if ( *plpInstList == NULL ||
(*plpInstList)->cDescriptorsMac == (*plpInstList)->cDescriptorsMax )
{
LPMAPI_INSTANCE_LIST lpInstListNew;
lpInstListNew = (*plpInstList == NULL) ?
HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
CbNewInstanceList( INSTANCE_LIST_CHUNKSIZE ) ) :
HeapReAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
*plpInstList,
CbNewInstanceList( INSTANCE_LIST_CHUNKSIZE +
(*plpInstList)->cDescriptorsMax ) );
if ( lpInstListNew == NULL )
{
DebugTrace( "ScNewInstanceDescriptor() - Error allocating/growing descriptor list (%d)\n", GetLastError() );
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto ret;
}
*plpInstList = lpInstListNew;
(*plpInstList)->cDescriptorsMax += INSTANCE_LIST_CHUNKSIZE;
}
//
// Grab the next available descriptor
//
*plpDescriptorNew = &(*plpInstList)->rgDescriptors[
(*plpInstList)->cDescriptorsMac];
++(*plpInstList)->cDescriptorsMac;
//
// Fill in its security context and instance
//
(*plpDescriptorNew)->uliSecurity = uliSecurity;
(*plpDescriptorNew)->lpInstance = pvInstance;
ret:
return sc;
}
/*
- DeleteInstanceDescriptor()
-
* Purpose:
* Removes the specified instance descriptor from the instance
* descriptor list. Frees and re-NULLs the list when the last
* descriptor is removed.
*
* Arguments:
* plpInstList Pointer to instance descriptor list
* lpDescriptor Descriptor to remove
*
* Returns:
* Nothing.
*/
VOID
DeleteInstanceDescriptor( LPMAPI_INSTANCE_LIST * plpInstList,
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptor )
{
Assert( !IsBadWritePtr(plpInstList, sizeof(LPMAPI_INSTANCE_LIST)) );
Assert( *plpInstList != NULL );
Assert( lpDescriptor >= (*plpInstList)->rgDescriptors );
Assert( lpDescriptor < (*plpInstList)->rgDescriptors + (*plpInstList)->cDescriptorsMac );
Assert( ((LPBYTE)lpDescriptor - (LPBYTE)(*plpInstList)->rgDescriptors) %
sizeof(MAPI_INSTANCE_DESCRIPTOR) == 0 );
MoveMemory( lpDescriptor,
lpDescriptor + 1,
sizeof(MAPI_INSTANCE_DESCRIPTOR) *
((*plpInstList)->cDescriptorsMac -
((lpDescriptor - (*plpInstList)->rgDescriptors) + 1) ) );
--(*plpInstList)->cDescriptorsMac;
if ( (*plpInstList)->cDescriptorsMac == 0 )
{
HeapFree( GetProcessHeap(), 0, *plpInstList );
*plpInstList = NULL;
}
}
/*
- PvGetInstanceGlobalsExInt() [EXTERNAL]
-
* Purpose:
* Fetch the instance globals for the current security context.
*
* Arguments:
* ppvInstList Transparent pointer to instance descriptor list
*
* Returns:
* Pointer to the instance globals.
*/
LPVOID FAR PASCAL
PvGetInstanceGlobalsExInt (LPVOID * ppvInstList)
{
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptor;
ULARGE_INTEGER uliSecurity;
LPVOID lpvInstanceRet = NULL;
EnterCriticalSection (&csInstance);
//
// Get our security context.
//
SideAssertSz1(
GetAccountCRC (&uliSecurity.LowPart, &uliSecurity.HighPart) != 0,
"PvGetInstanceGlobalsExInt: Failed to get account info (%d)",
GetLastError() );
//
// Look for a descriptor in the descriptor list
// with our security context.
//
lpDescriptor = LpFindInstanceDescriptor( *ppvInstList, uliSecurity );
//
// If we find one, then return its associated instance.
// Return NULL if we didn't find one.
//
if ( lpDescriptor != NULL )
lpvInstanceRet = lpDescriptor->lpInstance;
LeaveCriticalSection (&csInstance);
return lpvInstanceRet;
}
/*
- ScSetInstanceGlobalsExInt() [EXTERNAL]
-
* Purpose:
* Assigns (new) instance globals for the current security context.
*
* Arguments:
* pvInstNew Instance globals
* ppvInstList Transparent pointer to instance descriptor list
*
* Returns:
* Success or failure SCODE.
*/
SCODE FAR PASCAL
ScSetInstanceGlobalsExInt (LPVOID pvInstNew, LPVOID *ppvInstList)
{
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptor;
ULARGE_INTEGER uliSecurity;
SCODE sc = S_OK;
EnterCriticalSection (&csInstance);
//
// Get our security context.
//
SideAssertSz1(
GetAccountCRC (&uliSecurity.LowPart, &uliSecurity.HighPart) != 0,
"ScSetInstanceGlobalsExInt: Failed to get account info (%d)",
GetLastError() );
//
// Look for a descriptor in the descriptor list
// with our security context.
//
lpDescriptor = LpFindInstanceDescriptor( *ppvInstList, uliSecurity );
//
// If we find one then replace its instance
//
if ( lpDescriptor != NULL )
{
lpDescriptor->lpInstance = pvInstNew;
}
//
// If we don't find a descriptor then create a new one
// for this security context and instance
//
else
{
sc = ScNewInstanceDescriptor( (LPMAPI_INSTANCE_LIST *) ppvInstList,
uliSecurity,
pvInstNew,
&lpDescriptor );
if ( sc != S_OK )
{
DebugTrace( "Error creating new instance descriptor (%s)\n", SzDecodeScode(sc) );
goto ret;
}
}
ret:
LeaveCriticalSection (&csInstance);
return sc;
}
/*
- ScDeleteInstanceGlobalsExInt() [EXTERNAL]
-
* Purpose:
* Uninstalls instance globals for the current security context.
*
* Arguments:
* ppvInstList Transparent pointer to instance descriptor list
*
* Returns:
* S_OK
*/
SCODE FAR PASCAL
ScDeleteInstanceGlobalsExInt (LPVOID *ppvInstList)
{
LPMAPI_INSTANCE_DESCRIPTOR lpDescriptor;
ULARGE_INTEGER uliSecurity;
EnterCriticalSection (&csInstance);
//
// Get our security context.
//
SideAssertSz1(
GetAccountCRC (&uliSecurity.LowPart, &uliSecurity.HighPart) != 0,
"ScDeleteInstanceGlobalsExInt: Failed to get account info (%d)",
GetLastError() );
//
// Look for a descriptor in the descriptor list
// with our security context.
//
lpDescriptor = LpFindInstanceDescriptor( *ppvInstList, uliSecurity );
//
// If we find one, then remove it from the list. Don't worry if we
// don't find one. We may be cleaning up after a failed initialization.
//
if ( lpDescriptor != NULL )
DeleteInstanceDescriptor( (LPMAPI_INSTANCE_LIST *) ppvInstList,
lpDescriptor );
LeaveCriticalSection (&csInstance);
return S_OK;
}
#else // !defined(NEW_INSTANCE)
SCODE FAR PASCAL
ScSetInstanceGlobalsExInt (LPVOID pvInstNew, LPVOID *ppvInstList)
{
*ppvInstList = pvInstNew;
return S_OK;
}
LPVOID FAR PASCAL
PvGetInstanceGlobalsExInt (LPVOID *ppvInstList)
{
lpvReturn = *ppvInstList;
}
SCODE FAR PASCAL
ScDeleteInstanceGlobalsExInt (LPVOID *ppvInstList)
{
*ppvInstList = NULL;
return S_OK;
}
#endif // !defined(NEW_INSTANCE)
#elif defined(_WIN95)
/* There is nothing to do here for Win95.
* Using "DefineInst(pinstX)" to define your instance pointer
* and "DeclareInst(pinstX)" to declare external refs is enough.
*/
#endif