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