Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

943 lines
25 KiB

  1. /*
  2. * ADVISE.C
  3. *
  4. * HrAllocAdviseSink
  5. *
  6. * AdviseList helpers
  7. */
  8. #include "_apipch.h"
  9. #ifndef VTABLE_FILL
  10. #define VTABLE_FILL
  11. #endif
  12. #if !defined(WIN32) || defined(MAC)
  13. #ifndef InitializeCriticalSection
  14. #define InitializeCriticalSection(cs)
  15. #define DeleteCriticalSection(cs)
  16. #define EnterCriticalSection(cs)
  17. #define LeaveCriticalSection(cs)
  18. #define CRITICAL_SECTION int
  19. #endif
  20. #endif
  21. /*
  22. * The next several routines implement an IMAPIAdviseSink object
  23. * based on a callback function and context pointers.
  24. */
  25. #undef INTERFACE
  26. #define INTERFACE struct _ADVS
  27. #undef MAPIMETHOD_
  28. #define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, ADVS_)
  29. MAPI_IUNKNOWN_METHODS(IMPL)
  30. MAPI_IMAPIADVISESINK_METHODS(IMPL)
  31. #undef MAPIMETHOD_
  32. #define MAPIMETHOD_(type, method) STDMETHOD_(type, method)
  33. DECLARE_MAPI_INTERFACE(ADVS_) {
  34. BEGIN_INTERFACE
  35. MAPI_IUNKNOWN_METHODS(IMPL)
  36. MAPI_IMAPIADVISESINK_METHODS(IMPL)
  37. };
  38. typedef struct _ADVS FAR *LPADVS;
  39. typedef struct _ADVS {
  40. ADVS_Vtbl * lpVtbl;
  41. UINT cRef;
  42. LPVOID lpvContext;
  43. LPNOTIFCALLBACK lpfnCallback;
  44. } ADVS;
  45. ADVS_Vtbl vtblADVS = {
  46. VTABLE_FILL
  47. ADVS_QueryInterface,
  48. ADVS_AddRef,
  49. ADVS_Release,
  50. ADVS_OnNotify
  51. };
  52. #define VALIDATE_ADVS(m, p, v) \
  53. if (IsBadWritePtr((p), sizeof(ADVS)) || \
  54. IsBadReadPtr((p)->lpVtbl, sizeof(ADVS_Vtbl)) || \
  55. (p)->lpVtbl != &vtblADVS) { \
  56. DebugTraceArg(m, TEXT("Invalid object pointer")); \
  57. return v; \
  58. }
  59. STDMETHODIMP
  60. ADVS_QueryInterface(LPADVS padvs,
  61. REFIID lpiid,
  62. LPVOID FAR *lppObject)
  63. {
  64. VALIDATE_ADVS(ADVS_QueryInterface, padvs, ResultFromScode(E_INVALIDARG));
  65. if (IsBadReadPtr((LPIID)lpiid, sizeof(IID)) ||
  66. IsBadWritePtr(lppObject, sizeof(LPVOID))) {
  67. DebugTraceArg(ADVS_QueryInterface, TEXT("fails address check"));
  68. return(ResultFromScode(E_INVALIDARG));
  69. }
  70. *lppObject = NULL;
  71. if (IsEqualMAPIUID((LPMAPIUID)lpiid, (LPMAPIUID)&IID_IUnknown) ||
  72. IsEqualMAPIUID((LPMAPIUID)lpiid, (LPMAPIUID)&IID_IMAPIAdviseSink)) {
  73. ++(padvs->cRef);
  74. *lppObject = padvs;
  75. return(hrSuccess);
  76. }
  77. return(ResultFromScode(E_NOINTERFACE));
  78. }
  79. STDMETHODIMP_(ULONG)
  80. ADVS_AddRef(LPADVS padvs)
  81. {
  82. VALIDATE_ADVS(ADVS_AddRef, padvs, 0L);
  83. return((ULONG)(++padvs->cRef));
  84. }
  85. STDMETHODIMP_(ULONG)
  86. ADVS_Release(LPADVS padvs)
  87. {
  88. HLH hlh;
  89. VALIDATE_ADVS(ADVS_Release, padvs, 0xFFFFFFFF);
  90. if (--(padvs->cRef) == 0) {
  91. if (hlh = HlhUtilities()) {
  92. LH_Free(hlh, padvs);
  93. } else {
  94. DebugTrace(TEXT("ADVS_Release: no heap left\n"));
  95. }
  96. return(0L);
  97. }
  98. return((ULONG)padvs->cRef);
  99. }
  100. STDMETHODIMP_(ULONG)
  101. ADVS_OnNotify(LPADVS padvs,
  102. ULONG cNotif,
  103. LPNOTIFICATION lpNotif)
  104. {
  105. VALIDATE_ADVS(ADVS_OnNotify, padvs, 0L);
  106. //$ Enable when we put this in a DLL -- too many deps for the library
  107. //$ if (FAILED(ScCountNotifications((int)cNotif, lpNotif, NULL))) {
  108. //$ DebugTraceArg(ADVS_OnNotify, TEXT("lpNotif fails address check"));
  109. //$ return 0L;
  110. //$ }
  111. return((*(padvs->lpfnCallback))(padvs->lpvContext, cNotif, lpNotif));
  112. }
  113. /*
  114. - HrAllocAdviseSink
  115. -
  116. * Purpose:
  117. * Creates an IMAPIAdviseSink object based on an old-style
  118. * notification callback function and context pointer.
  119. *
  120. * Arguments:
  121. * lpfnCallback in the notification callback
  122. * lpvContext in arbitrary context for the
  123. * callback
  124. * lppAdviseSink out the returned AdviseSink object
  125. *
  126. * Returns:
  127. * HRESULT
  128. *
  129. * Errors:
  130. * out of memory
  131. * parameter validation
  132. */
  133. STDAPI
  134. HrAllocAdviseSink(LPNOTIFCALLBACK lpfnCallback,
  135. LPVOID lpvContext,
  136. LPMAPIADVISESINK FAR *lppAdviseSink)
  137. {
  138. LPADVS padvs;
  139. HRESULT hr = hrSuccess;
  140. HLH hlh;
  141. if (IsBadCodePtr((FARPROC)lpfnCallback) ||
  142. IsBadWritePtr(lppAdviseSink, sizeof(LPMAPIADVISESINK))) {
  143. DebugTraceArg(HrAllocAdviseSink, TEXT("invalid parameter"));
  144. return(ResultFromScode(E_INVALIDARG));
  145. }
  146. *lppAdviseSink = NULL;
  147. if (! (hlh = HlhUtilities())) {
  148. hr = ResultFromScode(MAPI_E_NOT_INITIALIZED);
  149. goto ret;
  150. }
  151. padvs = LH_Alloc(hlh, sizeof(ADVS));
  152. if (! padvs) {
  153. hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  154. goto ret;
  155. }
  156. padvs->lpVtbl = &vtblADVS;
  157. padvs->cRef = 1;
  158. padvs->lpvContext = lpvContext;
  159. padvs->lpfnCallback = lpfnCallback;
  160. *lppAdviseSink = (LPMAPIADVISESINK)padvs;
  161. ret:
  162. DebugTraceResult(HrAllocAdviseSink, hr);
  163. return(hr);
  164. }
  165. #ifdef SINGLE_THREAD_ADVISE_SINK
  166. /*
  167. * Single-thread advise sink wrapper. This object wrapper forces
  168. * OnNotify calls to happen on the thread in which it was created,
  169. * by forwarding stuff to a window proc on that thread.
  170. */
  171. #if defined(WIN16) || defined(MAC)
  172. STDAPI
  173. HrThisThreadAdviseSink(LPMAPIADVISESINK lpAdviseSink,
  174. LPMAPIADVISESINK FAR *lppAdviseSink)
  175. {
  176. //#ifdef PARAMETER_VALIDATION
  177. if (FBadUnknown(lpAdviseSink)) {
  178. DebugTraceArg(HrThisThreadAdviseSink, TEXT("lpAdviseSink fails address check"));
  179. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  180. }
  181. if (IsBadWritePtr(lppAdviseSink, sizeof(LPMAPIADVISESINK))) {
  182. DebugTraceArg(HrThisThreadAdviseSink, TEXT("lppAdviseSink fails address check"));
  183. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  184. }
  185. //#endif
  186. UlAddRef(lpAdviseSink);
  187. *lppAdviseSink = lpAdviseSink;
  188. return(hrSuccess);
  189. }
  190. #else
  191. // Object goo
  192. #undef INTERFACE
  193. #define INTERFACE struct _SAS
  194. #undef MAPIMETHOD_
  195. #define MAPIMETHOD_(type, method) MAPIMETHOD_DECLARE(type, method, SAS_)
  196. MAPI_IUNKNOWN_METHODS(IMPL)
  197. MAPI_IMAPIADVISESINK_METHODS(IMPL)
  198. #undef MAPIMETHOD_
  199. #define MAPIMETHOD_(type, method) STDMETHOD_(type, method)
  200. DECLARE_MAPI_INTERFACE(SAS_) {
  201. BEGIN_INTERFACE
  202. MAPI_IUNKNOWN_METHODS(IMPL)
  203. MAPI_IMAPIADVISESINK_METHODS(IMPL)
  204. };
  205. typedef struct _SAS FAR *LPSAS;
  206. typedef struct _SAS {
  207. SAS_Vtbl * lpVtbl;
  208. ULONG cRef;
  209. ULONG cActiveOnNotifies;
  210. LPMAPIADVISESINK pasOrig;
  211. HWND hwnd;
  212. } SAS;
  213. SAS_Vtbl vtblSAS =
  214. {
  215. // VTABLE_FILL // NI on the Mac
  216. SAS_QueryInterface,
  217. SAS_AddRef,
  218. SAS_Release,
  219. SAS_OnNotify
  220. };
  221. #define VALIDATE_SAS(m, p, v) \
  222. if (IsBadWritePtr((p), sizeof(SAS)) || \
  223. IsBadReadPtr((p)->lpVtbl, sizeof(SAS_Vtbl)) || \
  224. (p)->lpVtbl != &vtblSAS) { \
  225. DebugTraceArg(m, TEXT("Invalid object pointer")); \
  226. return v; \
  227. }
  228. typedef struct {
  229. LPMAPIADVISESINK pas;
  230. LPSAS psas;
  231. ULONG cb; // maybe
  232. ULONG cnotif;
  233. NOTIFICATION rgnotif[MAPI_DIM];
  234. } FWDNOTIF, FAR *LPFWDNOTIF;
  235. #define SizedFWDNOTIF(_c, _name) \
  236. struct _FWDNOTIF_ ## name { \
  237. LPMAPIADVISESINK pas; \
  238. ULONG cb; \
  239. ULONG cnotif; \
  240. NOTIFICATION rgnotif[_c]; \
  241. } _name
  242. #define CbNewFWDNOTIF(_cnotif) \
  243. (offsetof(FWDNOTIF, rgnotif) + ((_cnotif)*sizeof(NOTIFICATION)))
  244. #define CbFWDNOTIF(_pf) \
  245. (offsetof(FWDNOTIF, rgnotif) + (((_pf)->cnotif)*sizeof(NOTIFICATION)))
  246. // Window class globals
  247. #define WND_FLAGS_KEY 0 // NYI
  248. #define cbSTClsExtra 4
  249. #define CLS_REFCOUNT_KEY 0
  250. TCHAR szSTClassName[] = TEXT("WMS ST Notif Class");
  251. // Window globals
  252. #define cbSTWndExtra 4
  253. #define WND_REFCOUNT_KEY GWL_USERDATA
  254. #define wmSingleThreadNotif (WM_USER + 13)
  255. TCHAR szSTWndFmt[] = TEXT("WMS ST Notif Window %08X %08X");
  256. #define NameWindow(_s, cchSize) wnsprintf(_s, cchSize, szSTWndFmt, \
  257. GetCurrentProcessId(), \
  258. GetCurrentThreadId());
  259. HRESULT HrWindowUp(HWND *phwnd);
  260. void WindowRelease(HWND);
  261. LRESULT CALLBACK STWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  262. STDAPI
  263. HrThisThreadAdviseSink(LPMAPIADVISESINK pas,
  264. LPMAPIADVISESINK FAR *ppas)
  265. {
  266. HRESULT hr;
  267. LPSAS psas = NULL;
  268. //#ifdef PARAMETER_VALIDATION
  269. if (FBadUnknown(pas)) {
  270. DebugTraceArg(HrThisThreadAdviseSink, TEXT("lpAdviseSink fails address check"));
  271. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  272. }
  273. if (IsBadWritePtr(ppas, sizeof(LPMAPIADVISESINK))) {
  274. DebugTraceArg(HrThisThreadAdviseSink, TEXT("lppAdviseSink fails address check"));
  275. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  276. }
  277. //#endif
  278. if (HR_FAILED(hr = ResultFromScode((MAPIAllocateBuffer(sizeof(SAS), &psas))))) {
  279. goto ret;
  280. }
  281. MAPISetBufferName(psas, TEXT("ST Advise Sink"));
  282. ZeroMemory(psas, sizeof(SAS));
  283. psas->lpVtbl = &vtblSAS;
  284. psas->cRef = 1;
  285. psas->cActiveOnNotifies = 0;
  286. if (hr = HrWindowUp(&psas->hwnd)) {
  287. goto ret;
  288. }
  289. // All OK, return the new object
  290. UlAddRef(pas);
  291. psas->pasOrig = pas;
  292. *ppas = (LPMAPIADVISESINK) psas;
  293. ret:
  294. if (HR_FAILED(hr)) {
  295. MAPIFreeBuffer(psas);
  296. }
  297. DebugTraceResult(HrThisThreadAdviseSink, hr);
  298. return(hr);
  299. }
  300. HRESULT
  301. HrWindowUp(HWND * phwnd)
  302. {
  303. HRESULT hr = hrSuccess;
  304. CHAR szWndName[64];
  305. WNDCLASSA wc;
  306. HWND hwnd;
  307. LONG cRef;
  308. HINSTANCE hinst;
  309. // Find the window for this thread, if it exists
  310. NameWindow(szWndName, ARRAYSIZE(szWndName));
  311. hwnd = FindWindow(szSTClassName, szWndName);
  312. if (hwnd) {
  313. // It already exists -- add a ref to it
  314. cRef = GetWindowLong(hwnd, WND_REFCOUNT_KEY);
  315. Assert(cRef != 0L);
  316. SideAssert(SetWindowLong(hwnd, WND_REFCOUNT_KEY, cRef+1) == cRef);
  317. } else {
  318. // We have to create the window.
  319. hinst = hinstMapiXWAB;
  320. if (!GetClassInfo(hinst, szSTClassName, &wc)) {
  321. // We have to register the class too.
  322. ZeroMemory(&wc, sizeof(WNDCLASSA));
  323. wc.style = CS_GLOBALCLASS;
  324. wc.lpfnWndProc = STWndProc;
  325. wc.cbClsExtra = cbSTClsExtra;
  326. wc.cbWndExtra = cbSTWndExtra;
  327. wc.hInstance = hinst;
  328. wc.lpszClassName = szSTClassName;
  329. RegisterClassA(&wc);
  330. }
  331. hwnd = CreateWindowA(szSTClassName,
  332. szWndName,
  333. WS_POPUP, // bug 6111: pass on Win95 hotkey
  334. 0, 0, 0, 0,
  335. NULL, NULL, hinst, NULL);
  336. if (hwnd) {
  337. SetWindowLong(hwnd, WND_REFCOUNT_KEY, 1);
  338. cRef = (LONG) GetClassLong(hwnd, CLS_REFCOUNT_KEY);
  339. SideAssert((LONG) SetClassLong(hwnd, CLS_REFCOUNT_KEY, cRef+1) == cRef);
  340. } else {
  341. hr = ResultFromScode(MAPI_E_NOT_INITIALIZED);
  342. goto ret;
  343. }
  344. }
  345. *phwnd = hwnd;
  346. ret:
  347. DebugTraceResult(HrWindowUp, hr);
  348. return(hr);
  349. }
  350. void
  351. WindowRelease(HWND hwnd)
  352. {
  353. CHAR szWndName[64];
  354. LONG cRefWnd;
  355. LONG cRefCls;
  356. // The thread-safeness of this call is not obvious to
  357. // the casual observer, so it will NOT be left as an
  358. // exercise at the end of the development cycle.
  359. //
  360. // Namely, you do not have access to a window's data
  361. // from any thread other than the owning thread. This
  362. // should not suprise anyone (although it did me...).
  363. // So in debug builds, we will assert if we call this
  364. // from any thread that is not the owning one. What
  365. // this means is that we cannot release on a thread
  366. // that does not own the SAS.
  367. //
  368. if (! hwnd) {
  369. // Find the window for this thread, if it exists
  370. NameWindow(szWndName, ARRAYSIZE(szWndName));
  371. hwnd = FindWindow(szSTClassName, szWndName);
  372. }
  373. #ifdef DEBUG
  374. else {
  375. // Find the window for this thread, if it exists
  376. NameWindow(szWndName, ARRAYSIZE(szWndName));
  377. Assert (hwnd == FindWindow(szSTClassName, szWndName));
  378. }
  379. #endif // DEBUG
  380. if (! hwnd) {
  381. return;
  382. }
  383. cRefWnd = GetWindowLong(hwnd, WND_REFCOUNT_KEY);
  384. cRefCls = (LONG) GetClassLong(hwnd, CLS_REFCOUNT_KEY);
  385. if (cRefWnd > 1) {
  386. // Just deref it
  387. SideAssert(SetWindowLong(hwnd, WND_REFCOUNT_KEY, cRefWnd-1) == cRefWnd);
  388. } else {
  389. SideAssert((LONG) SetClassLong(hwnd, CLS_REFCOUNT_KEY, cRefCls-1) == cRefCls);
  390. DestroyWindow(hwnd);
  391. if (cRefCls == 1) {
  392. UnregisterClass(szSTClassName, hinstMapiXWAB);
  393. }
  394. }
  395. }
  396. LRESULT CALLBACK
  397. STWndProc(HWND hwnd,
  398. UINT msg,
  399. WPARAM wParam,
  400. LPARAM lParam)
  401. {
  402. LPFWDNOTIF pfwd = NULL;
  403. if (msg != wmSingleThreadNotif) {
  404. return(DefWindowProc(hwnd, msg, wParam, lParam));
  405. } else {
  406. // The wparam should be 0.
  407. // The lparam is the address of a forwarded notification.
  408. // First, validate the structure.
  409. pfwd = (LPFWDNOTIF)lParam;
  410. if (IsBadReadPtr(pfwd, CbNewFWDNOTIF(0))) {
  411. DebugTrace(TEXT("STWndProc: totally invalid FWDNOTIF\n"));
  412. pfwd = NULL;
  413. goto ret;
  414. }
  415. if (IsBadReadPtr(pfwd, (UINT) pfwd->cb)) {
  416. DebugTrace(TEXT("STWndProc: partially invalid FWDNOTIF\n"));
  417. pfwd = NULL;
  418. goto ret;
  419. }
  420. if (FBadUnknown(pfwd->pas)) {
  421. DebugTrace(TEXT("STWndProc: invalid advise sink\n"));
  422. goto ret;
  423. }
  424. //
  425. // Only call OnNotify if there are other references to the SAS other than
  426. // those made specifically for the PostMessage in SAS_OnNotify.
  427. //
  428. if (pfwd->psas->cRef > pfwd->psas->cActiveOnNotifies) {
  429. // Forward the notification.
  430. pfwd->pas->lpVtbl->OnNotify(pfwd->pas, pfwd->cnotif, pfwd->rgnotif);
  431. }
  432. pfwd->psas->cActiveOnNotifies--;
  433. // Release the contained advise object
  434. //
  435. UlRelease (pfwd->psas);
  436. ret:
  437. MAPIFreeBuffer(pfwd);
  438. }
  439. return(0);
  440. }
  441. STDMETHODIMP
  442. SAS_QueryInterface(LPSAS psas,
  443. REFIID lpiid,
  444. LPUNKNOWN FAR *ppunk)
  445. {
  446. // #ifdef PARAMETER_VALIDATION
  447. VALIDATE_SAS(QueryInterface, psas, ResultFromScode(E_INVALIDARG));
  448. if (IsBadWritePtr(ppunk, sizeof(LPUNKNOWN))) {
  449. DebugTraceArg(SAS_QueryInterface, TEXT("ppunk fails address check"));
  450. return(ResultFromScode(E_INVALIDARG));
  451. }
  452. *ppunk = NULL;
  453. if (IsBadReadPtr((LPIID) lpiid, sizeof(IID))) {
  454. DebugTraceArg(SAS_QueryInterface, TEXT("lpiid fails address check"));
  455. return(ResultFromScode(E_INVALIDARG));
  456. }
  457. // #endif /* PARAMETER_VALIDATION */
  458. if (! memcmp(lpiid, &IID_IUnknown, sizeof(IID)) ||
  459. ! memcmp(lpiid, &IID_IMAPIAdviseSink, sizeof(IID))) {
  460. InterlockedIncrement((LONG *)&psas->cRef);
  461. *ppunk = (LPUNKNOWN) psas;
  462. return(hrSuccess);
  463. }
  464. return(ResultFromScode(E_NOINTERFACE));
  465. }
  466. STDMETHODIMP_(ULONG)
  467. SAS_AddRef(LPSAS psas) {
  468. VALIDATE_SAS(AddRef, psas, 1);
  469. InterlockedIncrement((LONG *)&psas->cRef);
  470. }
  471. STDMETHODIMP_(ULONG)
  472. SAS_Release(LPSAS psas)
  473. {
  474. VALIDATE_SAS(SAS_Release, psas, 1);
  475. InterlockedDecrement((LONG *)&psas->cRef);
  476. if (psas->cRef) {
  477. return(psas->cRef);
  478. }
  479. WindowRelease(NULL);
  480. if (! FBadUnknown(psas->pasOrig)) {
  481. UlRelease(psas->pasOrig);
  482. } else {
  483. DebugTrace(TEXT("SAS_Release: pasOrig expired\n"));
  484. }
  485. MAPIFreeBuffer(psas);
  486. return(0);
  487. }
  488. STDMETHODIMP_(ULONG)
  489. SAS_OnNotify(LPSAS psas,
  490. ULONG cnotif,
  491. LPNOTIFICATION rgnotif)
  492. {
  493. ULONG cb;
  494. SCODE sc = S_OK;
  495. LPFWDNOTIF pfwd = NULL;
  496. //#ifdef PARAMETER_VALIDATION
  497. VALIDATE_SAS(SAS_OnNotify, psas, 0);
  498. // notifications validated below
  499. //#endif
  500. if (! IsWindow(psas->hwnd)) {
  501. DebugTrace(TEXT("SAS_OnNotify: my window is dead!\n"));
  502. goto ret;
  503. }
  504. if (sc = ScCountNotifications((int) cnotif, rgnotif, &cb)) {
  505. DebugTrace(TEXT("SAS_OnNotify: ScCountNotifications returns %s\n"), SzDecodeScode(sc));
  506. goto ret;
  507. }
  508. if (sc = MAPIAllocateBuffer(cb + offsetof(FWDNOTIF, rgnotif), &pfwd)) {
  509. DebugTrace(TEXT("SAS_OnNotify: MAPIAllocateBuffer returns %s\n"), SzDecodeScode(sc));
  510. goto ret;
  511. }
  512. MAPISetBufferName(pfwd, TEXT("ST Notification copy"));
  513. UlAddRef (psas);
  514. pfwd->psas = psas;
  515. pfwd->pas = psas->pasOrig;
  516. pfwd->cnotif = cnotif;
  517. (void) ScCopyNotifications((int) cnotif, rgnotif, pfwd->rgnotif, NULL);
  518. pfwd->cb = cb + offsetof(FWDNOTIF, rgnotif); // used?
  519. psas->cActiveOnNotifies++;
  520. if (! PostMessage(psas->hwnd, wmSingleThreadNotif, 0, (LPARAM) pfwd)) {
  521. DebugTrace(TEXT("SAS_OnNotify: PostMessage failed with %ld\n"), GetLastError());
  522. MAPIFreeBuffer(pfwd);
  523. }
  524. ret:
  525. return(0);
  526. }
  527. #endif /* WIN16 */
  528. /*
  529. * Advise list maintenance.
  530. *
  531. * These functions maintain a list of advise sink objects together
  532. * with the connection dwords used to get rid of them. Along with
  533. * those two basic items, an additional interface pointer and type
  534. * can be remembered; MAPIX uses these to forward Unadvise calls
  535. * where necessary.
  536. *
  537. * ScAddAdviseList
  538. * Creates or resizes the advise list as necessary, and adds a new
  539. * member. It fails if there is already an item in the list with the
  540. * same ulConnection. Takes an IMalloc interface for memory; uses
  541. * the standard one if none is supplied.
  542. *
  543. * ScDelAdviseList
  544. * Removes an item identified by its ulConnection from the advise
  545. * list. Does not resize the list.
  546. *
  547. * ScFindAdviseList
  548. * Given the ulConnection of an item, returns a pointer into
  549. * the advise list.
  550. *
  551. * DestroyAdviseList
  552. * What it says.
  553. */
  554. #define cGrowItems 10
  555. STDAPI_(SCODE)
  556. ScAddAdviseList(LPVOID lpvReserved,
  557. LPADVISELIST FAR *lppList,
  558. LPMAPIADVISESINK lpAdvise,
  559. ULONG ulConnection,
  560. ULONG ulType,
  561. LPUNKNOWN lpParent)
  562. {
  563. SCODE sc = S_OK;
  564. LPADVISELIST plist;
  565. LPADVISEITEM pitem;
  566. HLH hlh;
  567. // parameter validation
  568. #ifdef DEBUG
  569. if (lpvReserved) {
  570. DebugTrace(TEXT("ScAddAdviseList: pmalloc is unused, now reserved, pass NULL\n"));
  571. }
  572. #endif
  573. AssertSz(! IsBadWritePtr(lppList, sizeof(LPADVISELIST)),
  574. TEXT("lppList fails address check"));
  575. AssertSz(! *lppList || ! IsBadReadPtr(*lppList, offsetof(ADVISELIST, rgItems)),
  576. TEXT("*lppList fails address check"));
  577. AssertSz(! *lppList || ! IsBadReadPtr(*lppList, (UINT)CbADVISELIST(*lppList)),
  578. TEXT("*lppList fails address check"));
  579. AssertSz(lpAdvise && ! FBadUnknown(lpAdvise),
  580. TEXT("lpAdvise fails address check"));
  581. AssertSz(! lpParent || ! FBadUnknown(lpParent),
  582. TEXT("lpParent fails address check"));
  583. if (! (hlh = HlhUtilities())) {
  584. sc = MAPI_E_NOT_INITIALIZED;
  585. goto ret;
  586. }
  587. // Ensure space is available for new item
  588. if (!(plist = *lppList)) { // Yup, =
  589. if (!(plist = LH_Alloc(hlh, CbNewADVISELIST(cGrowItems)))) {
  590. goto oom;
  591. }
  592. LH_SetName (hlh, plist, TEXT("core: advise list"));
  593. #if defined(WIN32) && !defined(MAC)
  594. if (!(plist->lpcs = LH_Alloc (hlh, sizeof(CRITICAL_SECTION)))) {
  595. goto oom;
  596. }
  597. memset (plist->lpcs, 0, sizeof(CRITICAL_SECTION));
  598. LH_SetName (hlh, plist, TEXT("core: advise list critical section"));
  599. #endif
  600. plist->cItemsMac = 0;
  601. plist->cItemsMax = cGrowItems;
  602. InitializeCriticalSection(plist->lpcs);
  603. EnterCriticalSection(plist->lpcs);
  604. *lppList = plist;
  605. } else {
  606. EnterCriticalSection(plist->lpcs);
  607. }
  608. if (plist->cItemsMac == plist->cItemsMax) {
  609. if (!(plist = LH_Realloc(hlh, plist,
  610. (UINT)CbNewADVISELIST(plist->cItemsMax + cGrowItems)))) {
  611. LeaveCriticalSection((*lppList)->lpcs); // plist is bad ptr
  612. goto oom;
  613. }
  614. plist->cItemsMax += cGrowItems;
  615. *lppList = plist;
  616. }
  617. // Check for duplicate key
  618. for (pitem = &plist->rgItems[plist->cItemsMac - 1];
  619. pitem >= plist->rgItems;
  620. --pitem) {
  621. if (pitem->ulConnection == ulConnection) {
  622. sc = MAPI_E_BAD_VALUE;
  623. LeaveCriticalSection(plist->lpcs);
  624. goto ret;
  625. }
  626. }
  627. // Add the new item
  628. pitem = &plist->rgItems[plist->cItemsMac++];
  629. pitem->lpAdvise = lpAdvise;
  630. pitem->ulConnection = ulConnection;
  631. pitem->ulType = ulType;
  632. pitem->lpParent = lpParent;
  633. LeaveCriticalSection(plist->lpcs);
  634. UlAddRef(lpAdvise);
  635. ret:
  636. // note: no LeaveCrit here because of error returns
  637. DebugTraceSc(ScAddAdviseList, sc);
  638. return(sc);
  639. oom:
  640. if (! (*lppList) && plist) {
  641. LH_Free (hlh, plist);
  642. }
  643. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  644. goto ret;
  645. }
  646. STDAPI_(SCODE)
  647. ScDelAdviseList(LPADVISELIST lpList, ULONG ulConnection)
  648. {
  649. SCODE sc = S_OK;
  650. LPADVISEITEM pitem;
  651. LPMAPIADVISESINK padvise;
  652. #ifndef MAC
  653. FARPROC FAR * pfp;
  654. #endif
  655. AssertSz(!IsBadReadPtr(lpList, offsetof(ADVISELIST, rgItems)),
  656. TEXT("lpList fails address check"));
  657. AssertSz(!IsBadReadPtr(lpList, (UINT)CbADVISELIST(lpList)),
  658. TEXT("lpList fails address check"));
  659. EnterCriticalSection(lpList->lpcs);
  660. if (FAILED(sc = ScFindAdviseList(lpList, ulConnection, &pitem))) {
  661. goto ret;
  662. }
  663. Assert(pitem >= lpList->rgItems);
  664. Assert(pitem < lpList->rgItems + lpList->cItemsMac);
  665. SideAssert(padvise = pitem->lpAdvise);
  666. MoveMemory(pitem, pitem+1, sizeof(ADVISEITEM) *
  667. ((int)lpList->cItemsMac - (pitem + 1 - lpList->rgItems)));
  668. --(lpList->cItemsMac);
  669. if (!IsBadReadPtr(padvise, sizeof(LPVOID))
  670. && !IsBadReadPtr((pfp=(FARPROC FAR *)padvise->lpVtbl), 3*sizeof(FARPROC))
  671. && !IsBadCodePtr(pfp[2])) {
  672. LeaveCriticalSection(lpList->lpcs);
  673. UlRelease(padvise);
  674. EnterCriticalSection(lpList->lpcs);
  675. }
  676. ret:
  677. LeaveCriticalSection(lpList->lpcs);
  678. DebugTraceSc(ScDelAdviseList, sc);
  679. return(sc);
  680. }
  681. STDAPI_(SCODE)
  682. ScFindAdviseList(LPADVISELIST lpList,
  683. ULONG ulConnection,
  684. LPADVISEITEM FAR *lppItem)
  685. {
  686. SCODE sc = MAPI_E_NOT_FOUND;
  687. LPADVISEITEM pitem;
  688. AssertSz(! IsBadReadPtr(lpList, offsetof(ADVISELIST, rgItems)),
  689. TEXT("lpList fails address check"));
  690. AssertSz(! IsBadReadPtr(lpList, (UINT)CbADVISELIST(lpList)),
  691. TEXT("lpList Failes addres check"));
  692. AssertSz(! IsBadWritePtr(lppItem, sizeof(LPADVISEITEM)),
  693. TEXT("lppItem fails address check"));
  694. *lppItem = NULL;
  695. EnterCriticalSection(lpList->lpcs);
  696. for (pitem = lpList->rgItems + lpList->cItemsMac - 1;
  697. pitem >= lpList->rgItems;
  698. --pitem) {
  699. if (pitem->ulConnection == ulConnection) {
  700. *lppItem = pitem;
  701. sc = S_OK;
  702. break;
  703. }
  704. }
  705. // Assert that there are no duplicates of the found key
  706. #ifdef DEBUG
  707. {
  708. LPADVISEITEM pitemT;
  709. for (pitemT = lpList->rgItems; pitemT < pitem; ++pitemT) {
  710. Assert(pitemT->ulConnection != ulConnection);
  711. }
  712. }
  713. #endif
  714. LeaveCriticalSection(lpList->lpcs);
  715. DebugTraceSc(ScFindAdviseList, sc);
  716. return(sc);
  717. }
  718. STDAPI_(void)
  719. DestroyAdviseList(LPADVISELIST FAR *lppList)
  720. {
  721. LPADVISELIST plist;
  722. HLH hlh;
  723. AssertSz(! IsBadWritePtr(lppList, sizeof(LPADVISELIST)),
  724. TEXT("lppList fails address check"));
  725. if (! *lppList) {
  726. return;
  727. }
  728. AssertSz(! IsBadReadPtr(*lppList, offsetof(ADVISELIST, rgItems)),
  729. TEXT("*lppList fails address check"));
  730. AssertSz(! IsBadReadPtr(*lppList, (UINT)CbADVISELIST(*lppList)),
  731. TEXT("*lppList fails address check"));
  732. if (! (hlh = HlhUtilities())) {
  733. DebugTrace(TEXT("DestroyAdviseList: no heap for me\n")DebugTrace(TEXT(");
  734. return;
  735. }
  736. // First deref any advise sinks that didn't get freed up
  737. plist = *lppList;
  738. EnterCriticalSection(plist->lpcs);
  739. *lppList = NULL;
  740. while (plist->cItemsMac > 0) {
  741. (void)ScDelAdviseList(plist, plist->rgItems[0].ulConnection);
  742. }
  743. LeaveCriticalSection(plist->lpcs);
  744. // Now destroy the adviselist itself
  745. DeleteCriticalSection(plist->lpcs);
  746. #if defined(WIN32) && !defined(MAC)
  747. LH_Free(hlh, plist->lpcs);
  748. #endif
  749. LH_Free(hlh, plist);
  750. }
  751. STDAPI
  752. HrDispatchNotifications(ULONG ulFlags)
  753. {
  754. DrainFilteredNotifQueue(FALSE, 0, NULL);
  755. return(ResultFromScode(S_OK));
  756. }
  757. STDAPI
  758. WrapProgress(LPMAPIPROGRESS lpProgress,
  759. ULONG ulMin,
  760. ULONG ulMax,
  761. ULONG ulFlags,
  762. LPMAPIPROGRESS FAR *lppProgress)
  763. {
  764. AssertSz(lpProgress && ! FBadUnknown(lpProgress),
  765. TEXT( TEXT("lpProgress fails address check")));
  766. AssertSz(lppProgress && !IsBadWritePtr(lppProgress, sizeof(LPMAPIPROGRESS)),
  767. TEXT( TEXT("lppProgress fails address check")));
  768. DebugTraceSc(WrapProgress, MAPI_E_NO_SUPPORT);
  769. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  770. }
  771. #endif //#ifdef SINGLE_THREAD_ADVISE_SINK