|
|
/*
* ADVISE.C * * HrAllocAdviseSink * * AdviseList helpers */
#include "_apipch.h"
#ifndef VTABLE_FILL
#define VTABLE_FILL
#endif
#if !defined(WIN32) || defined(MAC)
#ifndef InitializeCriticalSection
#define InitializeCriticalSection(cs)
#define DeleteCriticalSection(cs)
#define EnterCriticalSection(cs)
#define LeaveCriticalSection(cs)
#define CRITICAL_SECTION int
#endif
#endif
/*
* The next several routines implement an IMAPIAdviseSink object * based on a callback function and context pointers. */
#undef INTERFACE
#define INTERFACE struct _ADVS
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, ADVS_)
MAPI_IUNKNOWN_METHODS(IMPL) MAPI_IMAPIADVISESINK_METHODS(IMPL) #undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)
DECLARE_MAPI_INTERFACE(ADVS_) { BEGIN_INTERFACE MAPI_IUNKNOWN_METHODS(IMPL) MAPI_IMAPIADVISESINK_METHODS(IMPL) };
typedef struct _ADVS FAR *LPADVS;
typedef struct _ADVS { ADVS_Vtbl * lpVtbl; UINT cRef; LPVOID lpvContext; LPNOTIFCALLBACK lpfnCallback; } ADVS;
ADVS_Vtbl vtblADVS = { VTABLE_FILL ADVS_QueryInterface, ADVS_AddRef, ADVS_Release, ADVS_OnNotify };
#define VALIDATE_ADVS(m, p, v) \
if (IsBadWritePtr((p), sizeof(ADVS)) || \ IsBadReadPtr((p)->lpVtbl, sizeof(ADVS_Vtbl)) || \ (p)->lpVtbl != &vtblADVS) { \ DebugTraceArg(m, TEXT("Invalid object pointer")); \ return v; \ }
STDMETHODIMP ADVS_QueryInterface(LPADVS padvs, REFIID lpiid, LPVOID FAR *lppObject) { VALIDATE_ADVS(ADVS_QueryInterface, padvs, ResultFromScode(E_INVALIDARG)); if (IsBadReadPtr((LPIID)lpiid, sizeof(IID)) || IsBadWritePtr(lppObject, sizeof(LPVOID))) { DebugTraceArg(ADVS_QueryInterface, TEXT("fails address check")); return(ResultFromScode(E_INVALIDARG)); }
*lppObject = NULL; if (IsEqualMAPIUID((LPMAPIUID)lpiid, (LPMAPIUID)&IID_IUnknown) || IsEqualMAPIUID((LPMAPIUID)lpiid, (LPMAPIUID)&IID_IMAPIAdviseSink)) { ++(padvs->cRef); *lppObject = padvs; return(hrSuccess); }
return(ResultFromScode(E_NOINTERFACE)); }
STDMETHODIMP_(ULONG) ADVS_AddRef(LPADVS padvs) { VALIDATE_ADVS(ADVS_AddRef, padvs, 0L); return((ULONG)(++padvs->cRef)); }
STDMETHODIMP_(ULONG) ADVS_Release(LPADVS padvs) { HLH hlh;
VALIDATE_ADVS(ADVS_Release, padvs, 0xFFFFFFFF);
if (--(padvs->cRef) == 0) { if (hlh = HlhUtilities()) { LH_Free(hlh, padvs); } else { DebugTrace(TEXT("ADVS_Release: no heap left\n")); }
return(0L); }
return((ULONG)padvs->cRef); }
STDMETHODIMP_(ULONG) ADVS_OnNotify(LPADVS padvs, ULONG cNotif, LPNOTIFICATION lpNotif) { VALIDATE_ADVS(ADVS_OnNotify, padvs, 0L); //$ Enable when we put this in a DLL -- too many deps for the library
//$ if (FAILED(ScCountNotifications((int)cNotif, lpNotif, NULL))) {
//$ DebugTraceArg(ADVS_OnNotify, TEXT("lpNotif fails address check"));
//$ return 0L;
//$ }
return((*(padvs->lpfnCallback))(padvs->lpvContext, cNotif, lpNotif)); }
/*
- HrAllocAdviseSink - * Purpose: * Creates an IMAPIAdviseSink object based on an old-style * notification callback function and context pointer. * * Arguments: * lpfnCallback in the notification callback * lpvContext in arbitrary context for the * callback * lppAdviseSink out the returned AdviseSink object * * Returns: * HRESULT * * Errors: * out of memory * parameter validation */ STDAPI HrAllocAdviseSink(LPNOTIFCALLBACK lpfnCallback, LPVOID lpvContext, LPMAPIADVISESINK FAR *lppAdviseSink) { LPADVS padvs; HRESULT hr = hrSuccess; HLH hlh;
if (IsBadCodePtr((FARPROC)lpfnCallback) || IsBadWritePtr(lppAdviseSink, sizeof(LPMAPIADVISESINK))) { DebugTraceArg(HrAllocAdviseSink, TEXT("invalid parameter")); return(ResultFromScode(E_INVALIDARG)); }
*lppAdviseSink = NULL;
if (! (hlh = HlhUtilities())) { hr = ResultFromScode(MAPI_E_NOT_INITIALIZED); goto ret; }
padvs = LH_Alloc(hlh, sizeof(ADVS)); if (! padvs) { hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); goto ret; }
padvs->lpVtbl = &vtblADVS; padvs->cRef = 1; padvs->lpvContext = lpvContext; padvs->lpfnCallback = lpfnCallback;
*lppAdviseSink = (LPMAPIADVISESINK)padvs;
ret: DebugTraceResult(HrAllocAdviseSink, hr); return(hr); }
#ifdef SINGLE_THREAD_ADVISE_SINK
/*
* Single-thread advise sink wrapper. This object wrapper forces * OnNotify calls to happen on the thread in which it was created, * by forwarding stuff to a window proc on that thread. */ #if defined(WIN16) || defined(MAC)
STDAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpAdviseSink, LPMAPIADVISESINK FAR *lppAdviseSink) { //#ifdef PARAMETER_VALIDATION
if (FBadUnknown(lpAdviseSink)) { DebugTraceArg(HrThisThreadAdviseSink, TEXT("lpAdviseSink fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (IsBadWritePtr(lppAdviseSink, sizeof(LPMAPIADVISESINK))) { DebugTraceArg(HrThisThreadAdviseSink, TEXT("lppAdviseSink fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } //#endif
UlAddRef(lpAdviseSink); *lppAdviseSink = lpAdviseSink;
return(hrSuccess); }
#else
// Object goo
#undef INTERFACE
#define INTERFACE struct _SAS
#undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, SAS_)
MAPI_IUNKNOWN_METHODS(IMPL) MAPI_IMAPIADVISESINK_METHODS(IMPL) #undef MAPIMETHOD_
#define MAPIMETHOD_(type, method) STDMETHOD_(type, method)
DECLARE_MAPI_INTERFACE(SAS_) { BEGIN_INTERFACE MAPI_IUNKNOWN_METHODS(IMPL) MAPI_IMAPIADVISESINK_METHODS(IMPL) };
typedef struct _SAS FAR *LPSAS;
typedef struct _SAS { SAS_Vtbl * lpVtbl; ULONG cRef;
ULONG cActiveOnNotifies; LPMAPIADVISESINK pasOrig; HWND hwnd;
} SAS;
SAS_Vtbl vtblSAS = { // VTABLE_FILL // NI on the Mac
SAS_QueryInterface, SAS_AddRef, SAS_Release, SAS_OnNotify };
#define VALIDATE_SAS(m, p, v) \
if (IsBadWritePtr((p), sizeof(SAS)) || \ IsBadReadPtr((p)->lpVtbl, sizeof(SAS_Vtbl)) || \ (p)->lpVtbl != &vtblSAS) { \ DebugTraceArg(m, TEXT("Invalid object pointer")); \ return v; \ }
typedef struct { LPMAPIADVISESINK pas; LPSAS psas; ULONG cb; // maybe
ULONG cnotif; NOTIFICATION rgnotif[MAPI_DIM]; } FWDNOTIF, FAR *LPFWDNOTIF;
#define SizedFWDNOTIF(_c, _name) \
struct _FWDNOTIF_ ## name { \ LPMAPIADVISESINK pas; \ ULONG cb; \ ULONG cnotif; \ NOTIFICATION rgnotif[_c]; \ } _name
#define CbNewFWDNOTIF(_cnotif) \
(offsetof(FWDNOTIF, rgnotif) + ((_cnotif)*sizeof(NOTIFICATION))) #define CbFWDNOTIF(_pf) \
(offsetof(FWDNOTIF, rgnotif) + (((_pf)->cnotif)*sizeof(NOTIFICATION)))
// Window class globals
#define WND_FLAGS_KEY 0 // NYI
#define cbSTClsExtra 4
#define CLS_REFCOUNT_KEY 0
TCHAR szSTClassName[] = TEXT("WMS ST Notif Class");
// Window globals
#define cbSTWndExtra 4
#define WND_REFCOUNT_KEY GWL_USERDATA
#define wmSingleThreadNotif (WM_USER + 13)
TCHAR szSTWndFmt[] = TEXT("WMS ST Notif Window %08X %08X"); #define NameWindow(_s, cchSize) wnsprintf(_s, cchSize, szSTWndFmt, \
GetCurrentProcessId(), \ GetCurrentThreadId());
HRESULT HrWindowUp(HWND *phwnd); void WindowRelease(HWND); LRESULT CALLBACK STWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
STDAPI HrThisThreadAdviseSink(LPMAPIADVISESINK pas, LPMAPIADVISESINK FAR *ppas) { HRESULT hr; LPSAS psas = NULL;
//#ifdef PARAMETER_VALIDATION
if (FBadUnknown(pas)) { DebugTraceArg(HrThisThreadAdviseSink, TEXT("lpAdviseSink fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (IsBadWritePtr(ppas, sizeof(LPMAPIADVISESINK))) { DebugTraceArg(HrThisThreadAdviseSink, TEXT("lppAdviseSink fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } //#endif
if (HR_FAILED(hr = ResultFromScode((MAPIAllocateBuffer(sizeof(SAS), &psas))))) { goto ret; }
MAPISetBufferName(psas, TEXT("ST Advise Sink")); ZeroMemory(psas, sizeof(SAS)); psas->lpVtbl = &vtblSAS; psas->cRef = 1; psas->cActiveOnNotifies = 0;
if (hr = HrWindowUp(&psas->hwnd)) { goto ret; }
// All OK, return the new object
UlAddRef(pas); psas->pasOrig = pas; *ppas = (LPMAPIADVISESINK) psas;
ret: if (HR_FAILED(hr)) { MAPIFreeBuffer(psas); }
DebugTraceResult(HrThisThreadAdviseSink, hr); return(hr); }
HRESULT HrWindowUp(HWND * phwnd) { HRESULT hr = hrSuccess; CHAR szWndName[64]; WNDCLASSA wc; HWND hwnd; LONG cRef; HINSTANCE hinst;
// Find the window for this thread, if it exists
NameWindow(szWndName, ARRAYSIZE(szWndName)); hwnd = FindWindow(szSTClassName, szWndName);
if (hwnd) { // It already exists -- add a ref to it
cRef = GetWindowLong(hwnd, WND_REFCOUNT_KEY); Assert(cRef != 0L); SideAssert(SetWindowLong(hwnd, WND_REFCOUNT_KEY, cRef+1) == cRef); } else { // We have to create the window.
hinst = hinstMapiXWAB;
if (!GetClassInfo(hinst, szSTClassName, &wc)) { // We have to register the class too.
ZeroMemory(&wc, sizeof(WNDCLASSA)); wc.style = CS_GLOBALCLASS; wc.lpfnWndProc = STWndProc; wc.cbClsExtra = cbSTClsExtra; wc.cbWndExtra = cbSTWndExtra; wc.hInstance = hinst; wc.lpszClassName = szSTClassName;
RegisterClassA(&wc); }
hwnd = CreateWindowA(szSTClassName, szWndName, WS_POPUP, // bug 6111: pass on Win95 hotkey
0, 0, 0, 0, NULL, NULL, hinst, NULL); if (hwnd) { SetWindowLong(hwnd, WND_REFCOUNT_KEY, 1); cRef = (LONG) GetClassLong(hwnd, CLS_REFCOUNT_KEY); SideAssert((LONG) SetClassLong(hwnd, CLS_REFCOUNT_KEY, cRef+1) == cRef); } else { hr = ResultFromScode(MAPI_E_NOT_INITIALIZED); goto ret; } }
*phwnd = hwnd;
ret: DebugTraceResult(HrWindowUp, hr); return(hr); }
void WindowRelease(HWND hwnd) { CHAR szWndName[64]; LONG cRefWnd; LONG cRefCls;
// The thread-safeness of this call is not obvious to
// the casual observer, so it will NOT be left as an
// exercise at the end of the development cycle.
//
// Namely, you do not have access to a window's data
// from any thread other than the owning thread. This
// should not suprise anyone (although it did me...).
// So in debug builds, we will assert if we call this
// from any thread that is not the owning one. What
// this means is that we cannot release on a thread
// that does not own the SAS.
//
if (! hwnd) { // Find the window for this thread, if it exists
NameWindow(szWndName, ARRAYSIZE(szWndName)); hwnd = FindWindow(szSTClassName, szWndName); } #ifdef DEBUG
else { // Find the window for this thread, if it exists
NameWindow(szWndName, ARRAYSIZE(szWndName)); Assert (hwnd == FindWindow(szSTClassName, szWndName)); } #endif // DEBUG
if (! hwnd) { return; }
cRefWnd = GetWindowLong(hwnd, WND_REFCOUNT_KEY); cRefCls = (LONG) GetClassLong(hwnd, CLS_REFCOUNT_KEY); if (cRefWnd > 1) { // Just deref it
SideAssert(SetWindowLong(hwnd, WND_REFCOUNT_KEY, cRefWnd-1) == cRefWnd); } else { SideAssert((LONG) SetClassLong(hwnd, CLS_REFCOUNT_KEY, cRefCls-1) == cRefCls); DestroyWindow(hwnd); if (cRefCls == 1) { UnregisterClass(szSTClassName, hinstMapiXWAB); } } }
LRESULT CALLBACK STWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LPFWDNOTIF pfwd = NULL;
if (msg != wmSingleThreadNotif) { return(DefWindowProc(hwnd, msg, wParam, lParam)); } else { // The wparam should be 0.
// The lparam is the address of a forwarded notification.
// First, validate the structure.
pfwd = (LPFWDNOTIF)lParam; if (IsBadReadPtr(pfwd, CbNewFWDNOTIF(0))) { DebugTrace(TEXT("STWndProc: totally invalid FWDNOTIF\n")); pfwd = NULL; goto ret; } if (IsBadReadPtr(pfwd, (UINT) pfwd->cb)) { DebugTrace(TEXT("STWndProc: partially invalid FWDNOTIF\n")); pfwd = NULL; goto ret; } if (FBadUnknown(pfwd->pas)) { DebugTrace(TEXT("STWndProc: invalid advise sink\n")); goto ret; }
//
// Only call OnNotify if there are other references to the SAS other than
// those made specifically for the PostMessage in SAS_OnNotify.
//
if (pfwd->psas->cRef > pfwd->psas->cActiveOnNotifies) { // Forward the notification.
pfwd->pas->lpVtbl->OnNotify(pfwd->pas, pfwd->cnotif, pfwd->rgnotif); }
pfwd->psas->cActiveOnNotifies--;
// Release the contained advise object
//
UlRelease (pfwd->psas);
ret: MAPIFreeBuffer(pfwd); } return(0); }
STDMETHODIMP SAS_QueryInterface(LPSAS psas, REFIID lpiid, LPUNKNOWN FAR *ppunk) { // #ifdef PARAMETER_VALIDATION
VALIDATE_SAS(QueryInterface, psas, ResultFromScode(E_INVALIDARG)); if (IsBadWritePtr(ppunk, sizeof(LPUNKNOWN))) { DebugTraceArg(SAS_QueryInterface, TEXT("ppunk fails address check")); return(ResultFromScode(E_INVALIDARG)); } *ppunk = NULL; if (IsBadReadPtr((LPIID) lpiid, sizeof(IID))) { DebugTraceArg(SAS_QueryInterface, TEXT("lpiid fails address check")); return(ResultFromScode(E_INVALIDARG)); } // #endif /* PARAMETER_VALIDATION */
if (! memcmp(lpiid, &IID_IUnknown, sizeof(IID)) || ! memcmp(lpiid, &IID_IMAPIAdviseSink, sizeof(IID))) { InterlockedIncrement((LONG *)&psas->cRef); *ppunk = (LPUNKNOWN) psas; return(hrSuccess); }
return(ResultFromScode(E_NOINTERFACE)); }
STDMETHODIMP_(ULONG) SAS_AddRef(LPSAS psas) { VALIDATE_SAS(AddRef, psas, 1);
InterlockedIncrement((LONG *)&psas->cRef); }
STDMETHODIMP_(ULONG) SAS_Release(LPSAS psas) { VALIDATE_SAS(SAS_Release, psas, 1); InterlockedDecrement((LONG *)&psas->cRef);
if (psas->cRef) { return(psas->cRef); }
WindowRelease(NULL); if (! FBadUnknown(psas->pasOrig)) { UlRelease(psas->pasOrig); } else { DebugTrace(TEXT("SAS_Release: pasOrig expired\n")); } MAPIFreeBuffer(psas); return(0); }
STDMETHODIMP_(ULONG) SAS_OnNotify(LPSAS psas, ULONG cnotif, LPNOTIFICATION rgnotif) { ULONG cb; SCODE sc = S_OK; LPFWDNOTIF pfwd = NULL;
//#ifdef PARAMETER_VALIDATION
VALIDATE_SAS(SAS_OnNotify, psas, 0); // notifications validated below
//#endif
if (! IsWindow(psas->hwnd)) { DebugTrace(TEXT("SAS_OnNotify: my window is dead!\n")); goto ret; }
if (sc = ScCountNotifications((int) cnotif, rgnotif, &cb)) { DebugTrace(TEXT("SAS_OnNotify: ScCountNotifications returns %s\n"), SzDecodeScode(sc)); goto ret; } if (sc = MAPIAllocateBuffer(cb + offsetof(FWDNOTIF, rgnotif), &pfwd)) { DebugTrace(TEXT("SAS_OnNotify: MAPIAllocateBuffer returns %s\n"), SzDecodeScode(sc)); goto ret; } MAPISetBufferName(pfwd, TEXT("ST Notification copy")); UlAddRef (psas); pfwd->psas = psas; pfwd->pas = psas->pasOrig; pfwd->cnotif = cnotif; (void) ScCopyNotifications((int) cnotif, rgnotif, pfwd->rgnotif, NULL); pfwd->cb = cb + offsetof(FWDNOTIF, rgnotif); // used?
psas->cActiveOnNotifies++;
if (! PostMessage(psas->hwnd, wmSingleThreadNotif, 0, (LPARAM) pfwd)) { DebugTrace(TEXT("SAS_OnNotify: PostMessage failed with %ld\n"), GetLastError()); MAPIFreeBuffer(pfwd); }
ret: return(0); }
#endif /* WIN16 */
/*
* Advise list maintenance. * * These functions maintain a list of advise sink objects together * with the connection dwords used to get rid of them. Along with * those two basic items, an additional interface pointer and type * can be remembered; MAPIX uses these to forward Unadvise calls * where necessary. * * ScAddAdviseList * Creates or resizes the advise list as necessary, and adds a new * member. It fails if there is already an item in the list with the * same ulConnection. Takes an IMalloc interface for memory; uses * the standard one if none is supplied. * * ScDelAdviseList * Removes an item identified by its ulConnection from the advise * list. Does not resize the list. * * ScFindAdviseList * Given the ulConnection of an item, returns a pointer into * the advise list. * * DestroyAdviseList * What it says. */
#define cGrowItems 10
STDAPI_(SCODE) ScAddAdviseList(LPVOID lpvReserved, LPADVISELIST FAR *lppList, LPMAPIADVISESINK lpAdvise, ULONG ulConnection, ULONG ulType, LPUNKNOWN lpParent) { SCODE sc = S_OK; LPADVISELIST plist; LPADVISEITEM pitem; HLH hlh;
// parameter validation
#ifdef DEBUG
if (lpvReserved) { DebugTrace(TEXT("ScAddAdviseList: pmalloc is unused, now reserved, pass NULL\n")); } #endif
AssertSz(! IsBadWritePtr(lppList, sizeof(LPADVISELIST)), TEXT("lppList fails address check"));
AssertSz(! *lppList || ! IsBadReadPtr(*lppList, offsetof(ADVISELIST, rgItems)), TEXT("*lppList fails address check"));
AssertSz(! *lppList || ! IsBadReadPtr(*lppList, (UINT)CbADVISELIST(*lppList)), TEXT("*lppList fails address check"));
AssertSz(lpAdvise && ! FBadUnknown(lpAdvise), TEXT("lpAdvise fails address check"));
AssertSz(! lpParent || ! FBadUnknown(lpParent), TEXT("lpParent fails address check"));
if (! (hlh = HlhUtilities())) { sc = MAPI_E_NOT_INITIALIZED; goto ret; }
// Ensure space is available for new item
if (!(plist = *lppList)) { // Yup, =
if (!(plist = LH_Alloc(hlh, CbNewADVISELIST(cGrowItems)))) { goto oom; } LH_SetName (hlh, plist, TEXT("core: advise list"));
#if defined(WIN32) && !defined(MAC)
if (!(plist->lpcs = LH_Alloc (hlh, sizeof(CRITICAL_SECTION)))) { goto oom; } memset (plist->lpcs, 0, sizeof(CRITICAL_SECTION)); LH_SetName (hlh, plist, TEXT("core: advise list critical section")); #endif
plist->cItemsMac = 0; plist->cItemsMax = cGrowItems; InitializeCriticalSection(plist->lpcs); EnterCriticalSection(plist->lpcs); *lppList = plist; } else { EnterCriticalSection(plist->lpcs); }
if (plist->cItemsMac == plist->cItemsMax) { if (!(plist = LH_Realloc(hlh, plist, (UINT)CbNewADVISELIST(plist->cItemsMax + cGrowItems)))) { LeaveCriticalSection((*lppList)->lpcs); // plist is bad ptr
goto oom; } plist->cItemsMax += cGrowItems; *lppList = plist; }
// Check for duplicate key
for (pitem = &plist->rgItems[plist->cItemsMac - 1]; pitem >= plist->rgItems; --pitem) { if (pitem->ulConnection == ulConnection) { sc = MAPI_E_BAD_VALUE; LeaveCriticalSection(plist->lpcs); goto ret; } }
// Add the new item
pitem = &plist->rgItems[plist->cItemsMac++]; pitem->lpAdvise = lpAdvise; pitem->ulConnection = ulConnection; pitem->ulType = ulType; pitem->lpParent = lpParent;
LeaveCriticalSection(plist->lpcs);
UlAddRef(lpAdvise);
ret: // note: no LeaveCrit here because of error returns
DebugTraceSc(ScAddAdviseList, sc); return(sc);
oom: if (! (*lppList) && plist) { LH_Free (hlh, plist); }
sc = MAPI_E_NOT_ENOUGH_MEMORY; goto ret; }
STDAPI_(SCODE) ScDelAdviseList(LPADVISELIST lpList, ULONG ulConnection) { SCODE sc = S_OK; LPADVISEITEM pitem; LPMAPIADVISESINK padvise; #ifndef MAC
FARPROC FAR * pfp; #endif
AssertSz(!IsBadReadPtr(lpList, offsetof(ADVISELIST, rgItems)), TEXT("lpList fails address check")); AssertSz(!IsBadReadPtr(lpList, (UINT)CbADVISELIST(lpList)), TEXT("lpList fails address check"));
EnterCriticalSection(lpList->lpcs);
if (FAILED(sc = ScFindAdviseList(lpList, ulConnection, &pitem))) { goto ret; }
Assert(pitem >= lpList->rgItems); Assert(pitem < lpList->rgItems + lpList->cItemsMac); SideAssert(padvise = pitem->lpAdvise);
MoveMemory(pitem, pitem+1, sizeof(ADVISEITEM) * ((int)lpList->cItemsMac - (pitem + 1 - lpList->rgItems)));
--(lpList->cItemsMac);
if (!IsBadReadPtr(padvise, sizeof(LPVOID)) && !IsBadReadPtr((pfp=(FARPROC FAR *)padvise->lpVtbl), 3*sizeof(FARPROC)) && !IsBadCodePtr(pfp[2])) { LeaveCriticalSection(lpList->lpcs); UlRelease(padvise); EnterCriticalSection(lpList->lpcs); }
ret: LeaveCriticalSection(lpList->lpcs); DebugTraceSc(ScDelAdviseList, sc); return(sc); }
STDAPI_(SCODE) ScFindAdviseList(LPADVISELIST lpList, ULONG ulConnection, LPADVISEITEM FAR *lppItem) { SCODE sc = MAPI_E_NOT_FOUND; LPADVISEITEM pitem;
AssertSz(! IsBadReadPtr(lpList, offsetof(ADVISELIST, rgItems)), TEXT("lpList fails address check")); AssertSz(! IsBadReadPtr(lpList, (UINT)CbADVISELIST(lpList)), TEXT("lpList Failes addres check")); AssertSz(! IsBadWritePtr(lppItem, sizeof(LPADVISEITEM)), TEXT("lppItem fails address check"));
*lppItem = NULL;
EnterCriticalSection(lpList->lpcs);
for (pitem = lpList->rgItems + lpList->cItemsMac - 1; pitem >= lpList->rgItems; --pitem) { if (pitem->ulConnection == ulConnection) { *lppItem = pitem; sc = S_OK; break; } }
// Assert that there are no duplicates of the found key
#ifdef DEBUG
{ LPADVISEITEM pitemT;
for (pitemT = lpList->rgItems; pitemT < pitem; ++pitemT) { Assert(pitemT->ulConnection != ulConnection); } } #endif
LeaveCriticalSection(lpList->lpcs); DebugTraceSc(ScFindAdviseList, sc); return(sc); }
STDAPI_(void) DestroyAdviseList(LPADVISELIST FAR *lppList) { LPADVISELIST plist; HLH hlh;
AssertSz(! IsBadWritePtr(lppList, sizeof(LPADVISELIST)), TEXT("lppList fails address check"));
if (! *lppList) { return; }
AssertSz(! IsBadReadPtr(*lppList, offsetof(ADVISELIST, rgItems)), TEXT("*lppList fails address check")); AssertSz(! IsBadReadPtr(*lppList, (UINT)CbADVISELIST(*lppList)), TEXT("*lppList fails address check"));
if (! (hlh = HlhUtilities())) { DebugTrace(TEXT("DestroyAdviseList: no heap for me\n")DebugTrace(TEXT("); return; }
// First deref any advise sinks that didn't get freed up
plist = *lppList; EnterCriticalSection(plist->lpcs); *lppList = NULL;
while (plist->cItemsMac > 0) { (void)ScDelAdviseList(plist, plist->rgItems[0].ulConnection); }
LeaveCriticalSection(plist->lpcs);
// Now destroy the adviselist itself
DeleteCriticalSection(plist->lpcs); #if defined(WIN32) && !defined(MAC)
LH_Free(hlh, plist->lpcs); #endif
LH_Free(hlh, plist); }
STDAPI HrDispatchNotifications(ULONG ulFlags) { DrainFilteredNotifQueue(FALSE, 0, NULL);
return(ResultFromScode(S_OK)); }
STDAPI WrapProgress(LPMAPIPROGRESS lpProgress, ULONG ulMin, ULONG ulMax, ULONG ulFlags, LPMAPIPROGRESS FAR *lppProgress) { AssertSz(lpProgress && ! FBadUnknown(lpProgress), TEXT( TEXT("lpProgress fails address check")));
AssertSz(lppProgress && !IsBadWritePtr(lppProgress, sizeof(LPMAPIPROGRESS)), TEXT( TEXT("lppProgress fails address check")));
DebugTraceSc(WrapProgress, MAPI_E_NO_SUPPORT); return(ResultFromScode(MAPI_E_NO_SUPPORT)); }
#endif //#ifdef SINGLE_THREAD_ADVISE_SINK
|