|
|
/*
* 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
|