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.

2693 lines
66 KiB

  1. /*
  2. * NTFY.C
  3. *
  4. * MAPI cross-process notification engine.
  5. */
  6. #include "_apipch.h"
  7. #ifdef OLD_STUFF
  8. #include "_mapipch.h"
  9. #include <stddef.h>
  10. #ifdef MAC
  11. #include <utilmac.h>
  12. #define PvGetInstanceGlobals() PvGetInstanceGlobalsMac(kInstMAPIX)
  13. #define PvGetInstanceGlobalsEx(_x) PvGetInstanceGlobalsMac(kInstMAPIX)
  14. #endif
  15. #pragma SEGMENT(Notify)
  16. #endif // OLD_STUFF
  17. /*
  18. * Un-comment this line to exercise HrThisThreadAdviseSink
  19. * thoroughly. (It will be used to wrap all advise sinks except
  20. * those registered for synchronous notifications.)
  21. */
  22. //#define WRAPTEST 1
  23. /* Event and flags validation for subscribe and notify */
  24. #define fnevReserved 0x3FFFFC00
  25. #define fnevReservedInternal 0x7FFFFC00
  26. #define ulSubscribeReservedFlags 0xBFFFFFFF
  27. #define ulNotifyReservedFlags 0xFFFFFFFF
  28. /* Additional stuff for SREG.ulFlagsAndRefcount */
  29. #define SREG_DELETING 0x10000
  30. #define AddRefCallback(_psreg) ++((_psreg)->ulFlagsAndRefcount)
  31. #define ReleaseCallback(_psreg) --((_psreg)->ulFlagsAndRefcount)
  32. #define IsRefCallback(_psreg) ((((_psreg)->ulFlagsAndRefcount) & 0xffff) != 0)
  33. #ifdef WIN16
  34. #define GetClassInfoA GetClassInfo
  35. #define WNDCLASSA WNDCLASS
  36. #define StrCpyNA StrCpyN
  37. #endif
  38. /* special spooler handling */
  39. #define hwndNoSpooler ((HWND) 0)
  40. #define FIsKeyOlaf(pkey) \
  41. (pkey->cb == ((LPNOTIFKEY) &notifkeyOlaf)->cb && \
  42. memcmp(pkey->ab, ((LPNOTIFKEY) &notifkeyOlaf)->ab, \
  43. (UINT) ((LPNOTIFKEY) &notifkeyOlaf)->cb) == 0)
  44. extern CHAR szSpoolerCmd[];
  45. #ifdef OLD_STUFF
  46. CHAR szSpoolerCmd[] = "MAPISP" szMAPIDLLSuffix ".EXE";
  47. #else
  48. CHAR szSpoolerCmd[] = "MAPISP32.EXE";
  49. #endif // OLD_STUFF
  50. SizedNOTIFKEY (5,notifkeyOlaf) = {5, "Olaf"}; // no TEXT!
  51. /*
  52. * Notification window message.
  53. *
  54. * It is sent to a specific window handle, not broadcast. We could
  55. * use the WM_USER range, but instead we use a registered window
  56. * message; this will make it easier for special MAPI apps (such as
  57. * test scripting) to handle notify messages.
  58. *
  59. * The WPARAM is set to 1 if the notification is synchronous, and 0
  60. * if it is asynchronous.
  61. *
  62. * The LPARAM is unused for asynchronous notifications.
  63. * For synchronous notifications, the LPARAM is the offset of the
  64. * notification parameters in the shared memory area.
  65. */
  66. /*
  67. * Name and message number for our notification window message.
  68. */
  69. UINT wmNotify = 0;
  70. #pragma SHARED_BEGIN
  71. CHAR szNotifyMsgName[] = szMAPINotificationMsg;
  72. /*
  73. * SKEY
  74. *
  75. * Stores a notification key and associated information in shared
  76. * memory.
  77. *
  78. * The key has a reference count and a list of registrations
  79. * (SREG structures) attached to it.
  80. */
  81. typedef struct
  82. {
  83. int cRef;
  84. GHID ghidRegs; // first registration in chain (SREG)
  85. NOTIFKEY key; // copy of key from Subscribe()
  86. } SKEY, FAR *LPSKEY;
  87. /*
  88. * SREG
  89. *
  90. * Shared information about a registration. Lives in a list hung
  91. * off the key for which it was registered.
  92. */
  93. typedef struct
  94. {
  95. GHID ghidRegNext; // next registration in chain (SREG)
  96. GHID ghidKey; // the key that owns this registration
  97. HWND hwnd; // process's notification window handle
  98. // parameters copied from Subscribe...
  99. ULONG ulEventMask;
  100. LPMAPIADVISESINK lpAdvise;
  101. ULONG ulConnection;
  102. ULONG ulFlagsAndRefcount; // ulFlags parameter + callback refcount
  103. } SREG, FAR *LPSREG;
  104. /*
  105. * SPARMS
  106. *
  107. * Stores notification parameters from Notify() in shared memory.
  108. *
  109. * Includes a reference to the key being notified, so the callback
  110. * addresses can be looked up in the target process.
  111. *
  112. * Includes the original shared memory offset, so that pointers
  113. * within the notification parameters can be relocated in the
  114. * target process (yecch!).
  115. *
  116. * The offset of this structure in shared memory is passed as the
  117. * LPARAM of the notification window message.
  118. */
  119. #pragma warning(disable:4200) // zero length byte array
  120. typedef struct
  121. {
  122. int cRef; // # of unprocessed messages
  123. GHID ghidKey; // smem offset of parent key
  124. ULONG cNotifications; // # of NOTIFICATION structures in ab
  125. LPVOID pvRef; // original shared memory offset
  126. ULONG cb; // size of ab
  127. #if defined (_AMD64_) || defined(_IA64_)
  128. ULONG ulPadThisSillyThingForRisc;
  129. #endif
  130. BYTE ab[]; // Actual notification parameters
  131. } SPARMS, FAR *LPSPARMS;
  132. #pragma warning(default:4200) // zero length byte array
  133. /*
  134. * Temporary placeholder for notification. Remembers the window
  135. * handle, task queue, and whether it's synchronous or not.
  136. */
  137. typedef struct
  138. {
  139. HWND hwnd;
  140. int fSync;
  141. GHID ghidTask;
  142. } TREG, FAR *LPTREG;
  143. // Notification window cruft.
  144. char szNotifClassName[] = "WMS notif engine";
  145. char szNotifWinName[] = "WMS notif window";
  146. #pragma SHARED_END
  147. #ifdef DEBUG
  148. BOOL fAlwaysValidateKeys = FALSE;
  149. #endif
  150. // Local functions
  151. //$MAC - Bad Prototype
  152. #ifndef MAC
  153. LRESULT STDAPICALLTYPE LNotifWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  154. #else
  155. LRESULT CALLBACK LNotifWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  156. #endif
  157. LRESULT STDAPICALLTYPE DrainNotifQueue(BOOL fSync, ULONG ibParms);
  158. BOOL FBadIUnknownComplete(LPVOID lpv);
  159. SCODE ScFindKey(LPNOTIFKEY pkey, HGH hgh, LPSHDR pshdr, ULONG FAR *pikey);
  160. void Unregister(LPINST pinst, GHID ghidKey, GHID ghidReg,
  161. LPMAPIADVISESINK FAR *ppadvise);
  162. void ReleaseKey(LPINST pinst, ULONG ibKey);
  163. SCODE ScFindTask(LPINST pinst, HWND hwndNotify, HGH hgh,
  164. PGHID pghidTask, PGHID pghidTaskPrev);
  165. void CleanupTask(LPINST pinst, HWND hwndNotify, BOOL fGripe);
  166. BOOL IsValidTask( HWND hwnd, LPINST pinst );
  167. SCODE ScEnqueueParms(LPINST pinst, HGH hgh, GHID ghidTask, GHID ghidParms);
  168. SCODE ScDequeueParms(HGH hgh, LPSTASK pstask,
  169. LPNOTIFKEY lpskeyFilter, PGHID pghidParms);
  170. BOOL FValidReg(HGH hgh, LPSHDR pshdr, GHID ghidReg);
  171. BOOL FValidKey(HGH hgh, LPSHDR pshdr, GHID ghidKey);
  172. BOOL FValidParms(HGH hgh, LPSHDR pshdr, GHID ghidParms);
  173. BOOL FValidRgkey(HGH hgh, LPSHDR pshdr);
  174. BOOL FSortedRgkey(HGH hgh, LPSHDR pshdr);
  175. #ifdef WIN16
  176. void CheckTimezone(SYSTEMTIME FAR *pst); // in DT.C
  177. SCODE ScGetInstRetry(LPINST FAR *ppinst);
  178. #else
  179. #define ScGetInstRetry(ppi) ScGetInst(ppi)
  180. #endif
  181. SCODE ScNewStask(HWND hwnd, LPSTR szTask, ULONG ulFlags, HGH hgh,
  182. LPSHDR pshdr);
  183. SCODE ScNewStubReg(LPINST pinst, LPSHDR pshdr, HGH hgh);
  184. VOID DeleteStubReg(LPINST pinst, LPSHDR pshdr, HGH hgh);
  185. SCODE ScSubscribe(LPINST pinst, HGH hgh, LPSHDR pshdr,
  186. LPADVISELIST FAR *lppList, LPNOTIFKEY lpKey, ULONG ulEventMask,
  187. LPMAPIADVISESINK lpAdvise, ULONG ulFlags, ULONG FAR *lpulConnection);
  188. #ifdef OLD_STUFF
  189. /* MAPI support object methods */
  190. STDMETHODIMP
  191. MAPISUP_Subscribe(
  192. LPSUPPORT lpsupport,
  193. LPNOTIFKEY lpKey,
  194. ULONG ulEventMask,
  195. ULONG ulFlags,
  196. LPMAPIADVISESINK lpAdvise,
  197. ULONG FAR *lpulConnection)
  198. {
  199. HRESULT hr;
  200. #ifdef PARAMETER_VALIDATION
  201. if (IsBadWritePtr(lpsupport, sizeof(SUPPORT)))
  202. {
  203. DebugTraceArg(MAPISUP_Subscribe, "lpsupport fails address check");
  204. goto badArg;
  205. }
  206. if (IsBadReadPtr(lpsupport->lpVtbl, sizeof(MAPISUP_Vtbl)))
  207. {
  208. DebugTraceArg(MAPISUP_Subscribe, "lpsupport->lpVtbl fails address check");
  209. goto badArg;
  210. }
  211. if (ulEventMask & fnevReservedInternal)
  212. {
  213. DebugTraceArg(MAPISUP_Subscribe, "reserved event flag used");
  214. goto badArg;
  215. }
  216. // Remainder of parameters checked in HrSubscribe
  217. #endif /* PARAMETER_VALIDATION */
  218. // The notification object listhead lives in the support object
  219. hr = HrSubscribe(&lpsupport->lpAdviseList, lpKey, ulEventMask,
  220. lpAdvise, ulFlags, lpulConnection);
  221. if (hr != hrSuccess)
  222. {
  223. UINT ids;
  224. SCODE sc = GetScode(hr);
  225. ULONG ulContext = CONT_SUPP_SUBSCRIBE_1;
  226. if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
  227. ids = IDS_NOT_ENOUGH_MEMORY;
  228. else if (sc == MAPI_E_NOT_INITIALIZED)
  229. ids = IDS_MAPI_NOT_INITIALIZED;
  230. else
  231. ids = IDS_CALL_FAILED;
  232. SetMAPIError(lpsupport, hr, ids, NULL, ulContext, 0, 0, NULL);
  233. }
  234. DebugTraceResult(MAPISUP_Subscribe, hr);
  235. return hr;
  236. #ifdef PARAMETER_VALIDATION
  237. badArg:
  238. #endif
  239. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  240. }
  241. STDMETHODIMP
  242. MAPISUP_Unsubscribe(LPSUPPORT lpsupport, ULONG ulConnection)
  243. {
  244. HRESULT hr;
  245. #ifdef PARAMETER_VALIDATION
  246. if (IsBadWritePtr(lpsupport, sizeof(SUPPORT)))
  247. {
  248. DebugTraceArg(MAPISUP_Subscribe, "lpsupport fails address check");
  249. goto badArg;
  250. }
  251. if (IsBadReadPtr(lpsupport->lpVtbl, sizeof(MAPISUP_Vtbl)))
  252. {
  253. DebugTraceArg(MAPISUP_Subscribe, "lpsupport->lpVtbl fails address check");
  254. goto badArg;
  255. }
  256. #endif
  257. hr = HrUnsubscribe(&lpsupport->lpAdviseList, ulConnection);
  258. if (hr != hrSuccess)
  259. {
  260. UINT ids;
  261. SCODE sc = GetScode(hr);
  262. ULONG ulContext = CONT_SUPP_UNSUBSCRIBE_1;
  263. if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
  264. ids = IDS_NOT_ENOUGH_MEMORY;
  265. else if (sc == MAPI_E_NOT_FOUND)
  266. ids = IDS_NO_CONNECTION;
  267. else if (sc == MAPI_E_NOT_INITIALIZED)
  268. ids = IDS_MAPI_NOT_INITIALIZED;
  269. else
  270. ids = IDS_CALL_FAILED;
  271. SetMAPIError(lpsupport, hr, ids, NULL, ulContext, 0, 0, NULL);
  272. }
  273. DebugTraceResult(MAPISUP_Unsubscribe, hr);
  274. return hr;
  275. #ifdef PARAMETER_VALIDATION
  276. badArg:
  277. #endif
  278. return ResultFromScode(E_INVALIDARG);
  279. }
  280. STDMETHODIMP
  281. MAPISUP_Notify(
  282. LPSUPPORT lpsupport,
  283. LPNOTIFKEY lpKey,
  284. ULONG cNotification,
  285. LPNOTIFICATION lpNotification,
  286. ULONG * lpulFlags)
  287. {
  288. HRESULT hr;
  289. #ifdef PARAMETER_VALIDATION
  290. if (IsBadWritePtr(lpsupport, sizeof(SUPPORT)))
  291. {
  292. DebugTraceArg(MAPISUP_Notify, "lpsupport fails address check");
  293. goto badArg;
  294. }
  295. if (IsBadReadPtr(lpsupport->lpVtbl, sizeof(MAPISUP_Vtbl)))
  296. {
  297. DebugTraceArg(MAPISUP_Notify, "lpsupport->lpVtbl fails address check");
  298. goto badArg;
  299. }
  300. // Remainder of parameters checked in HrNotify
  301. #endif /* PARAMETER_VALIDATION */
  302. // The notification object listhead lives in the support object
  303. hr = HrNotify(lpKey, cNotification, lpNotification, lpulFlags);
  304. if (hr != hrSuccess)
  305. {
  306. UINT ids;
  307. SCODE sc = GetScode(hr);
  308. ULONG ulContext = CONT_SUPP_NOTIFY_1;
  309. if (sc == MAPI_E_NOT_ENOUGH_MEMORY)
  310. ids = IDS_NOT_ENOUGH_MEMORY;
  311. else if (sc == MAPI_E_NOT_INITIALIZED)
  312. ids = IDS_MAPI_NOT_INITIALIZED;
  313. else
  314. ids = IDS_CALL_FAILED;
  315. SetMAPIError(lpsupport, hr, ids, NULL, ulContext, 0, 0, NULL);
  316. }
  317. DebugTraceResult(MAPISUP_Notify, hr);
  318. return hr;
  319. #ifdef PARAMETER_VALIDATION
  320. badArg:
  321. #endif
  322. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  323. }
  324. /* End of support object methods */
  325. #endif // OLD_STUFF
  326. /* Notification engine exported functions */
  327. /*
  328. * ScInitNotify
  329. *
  330. * Initialize the cross-process notification engine.
  331. *
  332. * Note: reference counting is handled by the top-level routine
  333. * ScInitMapiX; it is not necessary here.
  334. */
  335. SCODE
  336. ScInitNotify( LPINST pinst )
  337. {
  338. SCODE sc = S_OK;
  339. HGH hgh = NULL;
  340. GHID ghidstask = 0;
  341. LPSTASK pstask = NULL;
  342. LPSHDR pshdr;
  343. HINSTANCE hinst = HinstMapi();
  344. WNDCLASSA wc;
  345. HWND hwnd = NULL;
  346. #ifdef DEBUG
  347. fAlwaysValidateKeys = GetPrivateProfileInt("MAPIX", "CheckNotifKeysOften", 0, "mapidbg.ini");
  348. #endif
  349. // Register the window class. Ignore any failures; handle those
  350. // when the window is created.
  351. if (!GetClassInfoA(hinst, szNotifClassName, &wc))
  352. {
  353. ZeroMemory(&wc, sizeof(WNDCLASSA));
  354. wc.style = CS_GLOBALCLASS;
  355. wc.hInstance = hinst;
  356. wc.lpfnWndProc = LNotifWndProc;
  357. wc.lpszClassName = szNotifClassName;
  358. (void)RegisterClassA(&wc);
  359. }
  360. // Create the window.
  361. hwnd = CreateWindowA(szNotifClassName, szNotifWinName,
  362. WS_POPUP, // bug 6111: pass on Win95 hotkey
  363. 0, 0, 0, 0,
  364. NULL, NULL,
  365. hinst,
  366. NULL);
  367. if (!hwnd)
  368. {
  369. DebugTrace("ScInitNotify: failure creating notification window (0x%lx)\n", GetLastError());
  370. sc = MAPI_E_NOT_INITIALIZED;
  371. goto ret;
  372. }
  373. // Register the window message
  374. if (!(wmNotify = RegisterWindowMessageA(szNotifyMsgName)))
  375. {
  376. DebugTrace("ScInitNotify: failure registering notification window message\n");
  377. sc = MAPI_E_NOT_INITIALIZED;
  378. goto ret;
  379. }
  380. pinst->hwndNotify = hwnd;
  381. // The caller of this function should have already gotten
  382. // the Global Heap Mutex.
  383. hgh = pinst->hghShared;
  384. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  385. // If we're the first one in and not the spooler, create the stub
  386. // spooler information.
  387. if (!(pinst->ulInitFlags & MAPI_SPOOLER_INIT) &&
  388. !pshdr->ghidTaskList)
  389. {
  390. if (sc = ScNewStask(hwndNoSpooler, szSpoolerCmd, MAPI_SPOOLER_INIT,
  391. hgh, pshdr))
  392. goto ret;
  393. if (sc = ScNewStubReg(pinst, pshdr, hgh))
  394. goto ret;
  395. }
  396. // If we're the spooler and not the first one in, update the stub
  397. // spooler information.
  398. if ((pinst->ulInitFlags & MAPI_SPOOLER_INIT) &&
  399. pshdr->ghidTaskList)
  400. {
  401. // Spin through and find the spooler.
  402. for (ghidstask = pshdr->ghidTaskList; ghidstask; )
  403. {
  404. pstask = (LPSTASK) GH_GetPv(hgh, ghidstask);
  405. if (pstask->uFlags & MAPI_TASK_SPOOLER)
  406. break;
  407. ghidstask = pstask->ghidTaskNext;
  408. pstask = NULL;
  409. }
  410. Assert(ghidstask && pstask);
  411. if (pstask)
  412. {
  413. DebugTrace("ScInitNotify: flipping stub spooler task\n");
  414. pstask->hwndNotify = hwnd;
  415. }
  416. }
  417. else
  418. {
  419. // Initialize the shared memory information for this task.
  420. if (sc = ScNewStask(hwnd, pinst->szModName, pinst->ulInitFlags,
  421. hgh, pshdr))
  422. goto ret;
  423. }
  424. ret:
  425. if (sc)
  426. {
  427. if (hwnd)
  428. {
  429. DestroyWindow(hwnd);
  430. pinst->hwndNotify = (HWND) 0;
  431. }
  432. if (ghidstask)
  433. GH_Free(hgh, ghidstask);
  434. }
  435. DebugTraceSc(ScInitNotify, sc);
  436. return sc;
  437. }
  438. /*
  439. * DeinitNotify
  440. *
  441. * Shut down the cross-process notification engine.
  442. *
  443. * Note: reference counting is handled by the top-level routine
  444. * DeinitInstance; it is not necessary here.
  445. */
  446. void
  447. DeinitNotify()
  448. {
  449. LPINST pinst;
  450. #ifdef WIN32
  451. HINSTANCE hinst;
  452. WNDCLASSA wc;
  453. #endif
  454. SCODE sc;
  455. HGH hgh;
  456. LPSHDR pshdr;
  457. // SNEAKY: we're only called when it's safe to party on the INST,
  458. // so we evade the lock.
  459. pinst = (LPINST) PvGetInstanceGlobals();
  460. if (!pinst || !pinst->hwndNotify)
  461. return;
  462. hgh = pinst->hghShared;
  463. if (GH_WaitForMutex(hgh, INFINITE))
  464. {
  465. pshdr = (LPSHDR) GH_GetPv(hgh, pinst->ghidshdr);
  466. CleanupTask(pinst, pinst->hwndNotify, FALSE);
  467. // If it's the spooler who is exiting, recreate the stub structures
  468. if (pinst->ulInitFlags & MAPI_SPOOLER_INIT)
  469. {
  470. sc = ScNewStask(hwndNoSpooler, szSpoolerCmd, MAPI_SPOOLER_INIT,
  471. hgh, pshdr);
  472. DebugTraceSc(DeinitNotify: recreate stub task, sc);
  473. sc = ScNewStubReg(pinst, pshdr, hgh);
  474. DebugTraceSc(DeinitNotify: recreate stub reg, sc);
  475. }
  476. GH_ReleaseMutex(hgh);
  477. }
  478. // else shared memory is toast
  479. Assert(IsWindow(pinst->hwndNotify));
  480. DestroyWindow(pinst->hwndNotify);
  481. #ifdef WIN32
  482. hinst = hinstMapiXWAB;
  483. if (GetClassInfoA(hinst, szNotifClassName, &wc))
  484. UnregisterClassA(szNotifClassName, hinst);
  485. #endif
  486. }
  487. /*
  488. * HrSubscribe
  489. *
  490. * Creates a notification object, and records all the parameters
  491. * for use when Notify() is later called. All the parameters are
  492. * stored in shared memory, where Notify() will later find them.
  493. *
  494. * lppHead Head of linked list of notification objects,
  495. * used for invalidation
  496. * lpKey Unique key for the object for which
  497. * callbacks are desired
  498. * ulEventMask Bitmask of events for which callback is
  499. * desired
  500. * lpAdvise the advise sink for callbacks
  501. * ulFlags Callback handling flags
  502. * lppNotify Address of the new object is placed
  503. * here
  504. *
  505. */
  506. STDMETHODIMP
  507. HrSubscribe(LPADVISELIST FAR *lppList, LPNOTIFKEY lpKey, ULONG ulEventMask,
  508. LPMAPIADVISESINK lpAdvise, ULONG ulFlags, ULONG FAR *lpulConnection)
  509. {
  510. SCODE sc;
  511. LPINST pinst = NULL;
  512. HGH hgh = NULL;
  513. LPSHDR pshdr = NULL;
  514. #ifdef WRAPTEST
  515. LPMAPIADVISESINK padviseOrig = NULL;
  516. #endif
  517. #ifdef PARAMETER_VALIDATION
  518. if (lppList)
  519. {
  520. if (IsBadWritePtr(lppList, sizeof(LPADVISELIST)))
  521. {
  522. DebugTraceArg(HrSubscribe, "lppList fails address check");
  523. goto badArg;
  524. }
  525. if (*lppList && IsBadWritePtr(*lppList, offsetof(ADVISELIST, rgItems)))
  526. {
  527. DebugTraceArg(HrSubscribe, "*lppList fails address check");
  528. goto badArg;
  529. }
  530. }
  531. if (IsBadReadPtr(lpKey, (size_t)CbNewNOTIFKEY(0)) ||
  532. IsBadReadPtr(lpKey, (size_t)CbNOTIFKEY(lpKey)))
  533. {
  534. DebugTraceArg(HrSubscribe, "lpKey fails address check");
  535. goto badArg;
  536. }
  537. if (ulEventMask & fnevReserved)
  538. {
  539. DebugTraceArg(HrSubscribe, "reserved event flag used");
  540. goto badArg;
  541. }
  542. if (FBadIUnknownComplete(lpAdvise))
  543. {
  544. DebugTraceArg(HrSubscribe, "lpAdvise fails address check");
  545. goto badArg;
  546. }
  547. if (ulFlags & ulSubscribeReservedFlags)
  548. {
  549. DebugTraceArg(HrSubscribe, "reserved flags used");
  550. return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  551. }
  552. if (IsBadWritePtr(lpulConnection, sizeof(ULONG)))
  553. {
  554. DebugTraceArg(HrSubscribe, "lpulConnection fails address check");
  555. goto badArg;
  556. }
  557. #endif /* PARAMETER_VALIDATION */
  558. #ifdef WRAPTEST
  559. {
  560. HRESULT hr;
  561. if (!(ulFlags & NOTIFY_SYNC))
  562. {
  563. if (lpAdvise)
  564. {
  565. padviseOrig = lpAdvise;
  566. if (HR_FAILED(hr = HrThisThreadAdviseSink(padviseOrig, &lpAdvise)))
  567. {
  568. DebugTraceResult(HrSubscribe: WRAPTEST failed, hr);
  569. return hr;
  570. }
  571. }
  572. else
  573. padviseOrig = NULL;
  574. }
  575. }
  576. #endif /* WRAPTEST */
  577. if (sc = ScGetInst(&pinst))
  578. goto ret;
  579. Assert(pinst->hwndNotify);
  580. Assert(IsWindow(pinst->hwndNotify));
  581. hgh = pinst->hghShared;
  582. // Lock shared memory
  583. if (!GH_WaitForMutex(hgh, INFINITE))
  584. {
  585. sc = MAPI_E_TIMEOUT;
  586. goto ret;
  587. }
  588. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  589. sc = ScSubscribe(pinst, hgh, pshdr, lppList, lpKey,
  590. ulEventMask, lpAdvise, ulFlags, lpulConnection);
  591. // fall through to ret;
  592. ret:
  593. if (pshdr)
  594. GH_ReleaseMutex(hgh);
  595. ReleaseInst(&pinst);
  596. if (!sc && lpAdvise)
  597. UlAddRef(lpAdvise);
  598. #ifdef WRAPTEST
  599. if (padviseOrig)
  600. {
  601. // Drop the ref we created for the purpose of wrapping
  602. Assert(padviseOrig != lpAdvise);
  603. UlRelease(lpAdvise);
  604. }
  605. #endif
  606. DebugTraceSc(HrSubscribe, sc);
  607. return ResultFromScode(sc);
  608. #ifdef PARAMETER_VALIDATION
  609. badArg:
  610. #endif
  611. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  612. }
  613. SCODE
  614. ScSubscribe(LPINST pinst, HGH hgh, LPSHDR pshdr,
  615. LPADVISELIST FAR *lppList, LPNOTIFKEY lpKey, ULONG ulEventMask,
  616. LPMAPIADVISESINK lpAdvise, ULONG ulFlags, ULONG FAR *lpulConnection)
  617. {
  618. SCODE sc;
  619. LPSKEY pskey = NULL;
  620. LPSREG psreg = NULL;
  621. PGHID pghidskey = NULL;
  622. ULONG ikey;
  623. int ckey;
  624. GHID ghidsreg = 0;
  625. BOOL fCleanupAdviseList = FALSE;
  626. // Very, very special case: if this is spooler registering for
  627. // client connection, get rid of the stub registration
  628. if ((pinst->ulInitFlags & MAPI_SPOOLER_INIT) && FIsKeyOlaf(lpKey))
  629. {
  630. DeleteStubReg(pinst, pshdr, hgh);
  631. }
  632. // Copy other reg info to shared memory.
  633. // Don't hook to key until everything that can fail is done.
  634. if (!(ghidsreg = GH_Alloc(hgh, sizeof(SREG))))
  635. goto oom;
  636. psreg = (LPSREG)GH_GetPv(hgh, ghidsreg);
  637. psreg->hwnd = pinst->hwndNotify;
  638. psreg->ulEventMask = ulEventMask;
  639. psreg->lpAdvise = lpAdvise;
  640. psreg->ulFlagsAndRefcount = ulFlags;
  641. // Hook advise sink to caller's list. The release key is the
  642. // shared memory offset of the registration.
  643. if (lppList && lpAdvise)
  644. {
  645. // AddRef happens in the subroutine for the AdviseList copy.
  646. // The reference should be released by ScDelAdviseList()
  647. //
  648. if (FAILED(sc = ScAddAdviseList(NULL, lppList,
  649. lpAdvise, (ULONG)ghidsreg, 0, NULL)))
  650. goto ret;
  651. fCleanupAdviseList = TRUE;
  652. }
  653. // Copy key to shared memory, if it's not already there
  654. #ifdef DEBUG
  655. if (fAlwaysValidateKeys)
  656. Assert(FValidRgkey(hgh, pshdr));
  657. #endif
  658. sc = ScFindKey(lpKey, hgh, pshdr, &ikey);
  659. if (sc == S_FALSE)
  660. {
  661. GHID ghidskey;
  662. // Key was not found, we need to make a copy.
  663. // Create key structure with null regs list
  664. if (!(ghidskey = GH_Alloc(hgh, (UINT)(offsetof(SKEY, key.ab[0]) + lpKey->cb))))
  665. goto oom;
  666. pskey = (LPSKEY)GH_GetPv(hgh, ghidskey);
  667. MemCopy(&pskey->key, lpKey, offsetof(NOTIFKEY,ab[0]) + (UINT)lpKey->cb);
  668. pskey->ghidRegs = 0;
  669. pskey->cRef = 0;
  670. // Add new key to sorted list of offsets
  671. // First ensure there is room in the list
  672. if (!pshdr->ghidKeyList)
  673. {
  674. // There is no list at all, create empty
  675. Assert(pshdr->cKeyMac == 0);
  676. Assert(pshdr->cKeyMax == 0);
  677. if (!(ghidskey = GH_Alloc(hgh, cKeyIncr*sizeof(GHID))))
  678. goto oom;
  679. pghidskey = (PGHID)GH_GetPv(hgh, ghidskey);
  680. ZeroMemory(pghidskey, cKeyIncr*sizeof(GHID));
  681. pshdr->cKeyMax = cKeyIncr;
  682. pshdr->ghidKeyList = ghidskey;
  683. }
  684. else if (pshdr->cKeyMac >= pshdr->cKeyMax)
  685. {
  686. // List is full, grow it
  687. Assert(pshdr->cKeyMax);
  688. Assert(pshdr->ghidKeyList);
  689. if (!(ghidskey = GH_Realloc(hgh,
  690. pshdr->ghidKeyList,
  691. (pshdr->cKeyMax + cKeyIncr) * sizeof(GHID))))
  692. {
  693. DebugTrace( "ScSubscribe: ghidskey can't grow.\n");
  694. goto oom;
  695. }
  696. pghidskey = (PGHID)GH_GetPv(hgh, ghidskey);
  697. pshdr->cKeyMax += cKeyIncr;
  698. pshdr->ghidKeyList = ghidskey;
  699. }
  700. else
  701. {
  702. // There's room
  703. pghidskey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  704. }
  705. //
  706. // BEYOND THIS POINT, NOTHING IS ALLOWED TO FAIL.
  707. // The error recovery code assumes this; specifically, it only
  708. // undoes allocations, not modifications to data structures.
  709. //
  710. // Shift any elements after the insertion point up by one,
  711. // and insert the new key. We compute the ghid because we've
  712. // been reusing the ghidskey thing for other allocations.
  713. ckey = (int)(pshdr->cKeyMac - ikey);
  714. Assert(pghidskey);
  715. if (ckey)
  716. memmove((LPBYTE)pghidskey + (ikey+1)*sizeof(GHID),
  717. (LPBYTE)pghidskey + ikey*sizeof(GHID),
  718. ckey*sizeof(GHID));
  719. pghidskey[ikey] = GH_GetId(hgh, pskey);
  720. ++(pshdr->cKeyMac);
  721. }
  722. else
  723. {
  724. // The key already exists.
  725. // Chain the new reg onto it.
  726. pghidskey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  727. pskey = (LPSKEY)GH_GetPv(hgh, pghidskey[ikey]);
  728. }
  729. sc = S_OK;
  730. // Hook reg info to key, and place back pointer to the key in
  731. // the reg info.
  732. psreg->ghidRegNext = pskey->ghidRegs;
  733. pskey->ghidRegs = ghidsreg;
  734. ++(pskey->cRef);
  735. psreg->ghidKey = GH_GetId(hgh, pskey);
  736. #ifdef DEBUG
  737. if (fAlwaysValidateKeys)
  738. Assert(FValidRgkey(hgh, pshdr));
  739. #endif
  740. *lpulConnection = (ULONG)ghidsreg;
  741. ret:
  742. if (sc)
  743. {
  744. if (pskey && !pskey->cRef)
  745. GH_Free(hgh, GH_GetId(hgh, pskey));
  746. if (psreg)
  747. GH_Free(hgh, ghidsreg);
  748. if (fCleanupAdviseList)
  749. (void) ScDelAdviseList(*lppList, (ULONG)ghidsreg);
  750. }
  751. DebugTraceSc(ScSubscribe, sc);
  752. return sc;
  753. oom:
  754. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  755. goto ret;
  756. }
  757. STDMETHODIMP
  758. HrUnsubscribe(LPADVISELIST FAR *lppList, ULONG ulConnection)
  759. {
  760. SCODE sc;
  761. LPINST pinst = NULL;
  762. HGH hgh = NULL;
  763. LPSREG psreg;
  764. LPSHDR pshdr = NULL;
  765. LPMAPIADVISESINK padvise = NULL;
  766. BOOL fSinkBusy;
  767. #ifdef PARAMETER_VALIDATION
  768. if (IsBadWritePtr(lppList, sizeof(LPADVISELIST)))
  769. {
  770. DebugTraceArg(HrUnsubscribe, "lppList fails address check");
  771. return ResultFromScode(E_INVALIDARG);
  772. }
  773. if (*lppList && IsBadWritePtr(*lppList, offsetof(ADVISELIST, rgItems)))
  774. {
  775. DebugTraceArg(HrUnsubscribe, "*lppList fails address check");
  776. return ResultFromScode(E_INVALIDARG);
  777. }
  778. #endif /* PARAMETER_VALIDATION */
  779. if (sc = ScGetInst(&pinst))
  780. goto ret;
  781. hgh = pinst->hghShared;
  782. if (!GH_WaitForMutex(hgh, INFINITE))
  783. {
  784. sc = MAPI_E_TIMEOUT;
  785. goto ret;
  786. }
  787. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  788. if (!FValidReg(hgh, pshdr, (GHID)ulConnection))
  789. {
  790. DebugTraceArg(HrUnsubscribe, "ulConnection refers to invalid memory");
  791. goto badReg;
  792. }
  793. psreg = (LPSREG)GH_GetPv(hgh, (GHID)ulConnection);
  794. #ifdef DEBUG
  795. if (fAlwaysValidateKeys)
  796. Assert(FValidRgkey(hgh, pshdr));
  797. #endif
  798. psreg->ulFlagsAndRefcount |= SREG_DELETING;
  799. fSinkBusy = IsRefCallback(psreg);
  800. if (!fSinkBusy)
  801. Unregister(pinst, psreg->ghidKey, (GHID)ulConnection, &padvise);
  802. #ifdef DEBUG
  803. if (fAlwaysValidateKeys)
  804. Assert(FValidRgkey(hgh, pshdr));
  805. #endif
  806. // The advise sink should be released with nothing else held.
  807. GH_ReleaseMutex(hgh);
  808. pshdr = NULL;
  809. ReleaseInst(&pinst);
  810. // Drop our reference to the advise sink
  811. if (padvise &&
  812. !fSinkBusy &&
  813. !FBadIUnknownComplete(padvise))
  814. {
  815. UlRelease(padvise);
  816. }
  817. if (!*lppList)
  818. {
  819. sc = MAPI_E_NOT_FOUND;
  820. goto ret;
  821. }
  822. sc = ScDelAdviseList(*lppList, ulConnection);
  823. ret:
  824. if (pshdr)
  825. GH_ReleaseMutex(hgh);
  826. ReleaseInst(&pinst);
  827. DebugTraceSc(HrUnsubscribe, sc);
  828. return ResultFromScode(sc);
  829. badReg:
  830. sc = MAPI_E_INVALID_PARAMETER;
  831. goto ret;
  832. }
  833. /*
  834. * HrNotify
  835. *
  836. * Issues a callback for each event specified, if anyone has registered
  837. * for the key and event specified.
  838. *
  839. * This is really only the front half of Notify; the rest,
  840. * including the actual callback, happens in the notification
  841. * window procedure LNotifWndProc. This function uses information
  842. * stored in shared memory to determine what processes are interested
  843. * in the callback.
  844. *
  845. * lpKey Uniquely identifies the object in which
  846. * interest was registered. Both the key
  847. * and the event in the notification itself
  848. * must match in order for the callback to
  849. * fire.
  850. * cNotification Count of structures at rgNotifications
  851. * rgNotification Array of NOTIFICATION structures. Each
  852. * contains an event ID and parameters.
  853. * lpulFlags No input values defined. Output may be
  854. * NOTIFY_CANCEL, if Subscribe's caller
  855. * requested synchronous callback and the
  856. * callback function returned
  857. * CALLBACK_DISCONTINUE.
  858. *
  859. * Note that the output flags are ambiguous if more than one
  860. * notification was passed in -- you can't tell which callback
  861. * canceled.
  862. */
  863. STDMETHODIMP
  864. HrNotify(LPNOTIFKEY lpKey, ULONG cNotification,
  865. LPNOTIFICATION rgNotification, ULONG FAR *lpulFlags)
  866. {
  867. SCODE sc;
  868. LPINST pinst;
  869. HGH hgh = NULL;
  870. LPSHDR pshdr = NULL;
  871. ULONG ikey;
  872. GHID ghidkey;
  873. LPTREG rgtreg = NULL;
  874. int itreg;
  875. int ctreg;
  876. LPSKEY pskey;
  877. LPSREG psreg;
  878. GHID ghidReg;
  879. int inotif;
  880. LRESULT lResult;
  881. GHID ghidParms = 0;
  882. LPSPARMS pparms = NULL;
  883. LPSTASK pstaskT;
  884. ULONG cb;
  885. LPBYTE pb;
  886. ULONG ul;
  887. #ifdef PARAMETER_VALIDATION
  888. if (IsBadReadPtr(lpKey, (size_t)CbNewNOTIFKEY(0)) ||
  889. IsBadReadPtr(lpKey, (size_t)CbNOTIFKEY(lpKey)))
  890. {
  891. DebugTraceArg(HrNotify, "lpKey fails address check");
  892. goto badArg;
  893. }
  894. if (IsBadReadPtr(rgNotification, (UINT)cNotification*sizeof(NOTIFICATION)))
  895. {
  896. DebugTraceArg(HrNotify, "rgNotification fails address check");
  897. goto badArg;
  898. }
  899. // N.B. the NOTIFICATION structures are validated within this
  900. // function, during the copy step.
  901. if (IsBadWritePtr(lpulFlags, sizeof(ULONG)))
  902. {
  903. DebugTraceArg(HrNotify, "lpulFlags fails address check");
  904. goto badArg;
  905. }
  906. if (*lpulFlags & ulNotifyReservedFlags)
  907. {
  908. DebugTraceArg(HrNotify, "reserved flags used");
  909. return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  910. }
  911. #endif /* PARAMETER_VALIDATION */
  912. if (sc = ScGetInst(&pinst))
  913. goto ret;
  914. Assert(pinst->hwndNotify);
  915. Assert(IsWindow(pinst->hwndNotify));
  916. hgh = pinst->hghShared;
  917. *lpulFlags = 0L;
  918. // Validate the notification parameters.
  919. // Also calculate their total size, so we know how big a block
  920. // to get from shared memory.
  921. if (sc = ScCountNotifications((int)cNotification, rgNotification, &cb))
  922. goto ret;
  923. // Lock shared memory
  924. if (!GH_WaitForMutex(hgh, INFINITE))
  925. {
  926. sc = MAPI_E_TIMEOUT;
  927. goto ret;
  928. }
  929. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  930. // Locate the key we're told to notify on.
  931. sc = ScFindKey(lpKey, hgh, pshdr, &ikey);
  932. if (sc == S_FALSE)
  933. {
  934. // Nobody is registered for this key. All done.
  935. sc = S_OK;
  936. goto ret;
  937. }
  938. ghidkey = ((PGHID)GH_GetPv(hgh, pshdr->ghidKeyList))[ikey];
  939. pskey = (LPSKEY)GH_GetPv(hgh, ghidkey);
  940. // Form the logical OR of all the events we were passed. Use it
  941. // as a shortcut to determine whether a particular registration
  942. // triggers.
  943. ul = 0;
  944. for (inotif = 0; inotif < (int)cNotification; ++inotif)
  945. ul |= rgNotification[inotif].ulEventType;
  946. // Walk list of registrations and build a set of window
  947. // handles that need to be notified. Also remember which ones
  948. // want sync notification.
  949. // The list of registrations may be empty if some notification messages
  950. // are still waiting to be handled.
  951. if (sc = STACK_ALLOC(pskey->cRef * sizeof(TREG), rgtreg))
  952. goto ret;
  953. itreg = 0;
  954. for (ghidReg = pskey->ghidRegs; ghidReg; )
  955. {
  956. GHID ghidTask;
  957. HWND hwnd;
  958. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  959. hwnd = psreg->hwnd;
  960. if (!IsValidTask( hwnd, pinst ))
  961. {
  962. // The task for which we created this window has died.
  963. // Continue loop first 'cause our link is about to go away.
  964. do {
  965. ghidReg = psreg->ghidRegNext;
  966. } while (ghidReg &&
  967. (psreg = ((LPSREG)GH_GetPv(hgh, ghidReg)))->hwnd == hwnd);
  968. // Blow away everything associated with the dead task.
  969. CleanupTask(pinst, hwnd, TRUE);
  970. continue;
  971. }
  972. if (ul & psreg->ulEventMask)
  973. {
  974. // Caller wants this event. Add it to temporary list.
  975. //
  976. if (psreg->ulFlagsAndRefcount & SREG_DELETING)
  977. {
  978. DebugTrace("Skipping notify to reg pending deletion\n");
  979. }
  980. else if (!ScFindTask(pinst, hwnd, hgh, &ghidTask, NULL))
  981. {
  982. pstaskT = (LPSTASK) GH_GetPv(hgh, ghidTask);
  983. rgtreg[itreg].hwnd = hwnd;
  984. rgtreg[itreg].fSync =
  985. ((psreg->ulFlagsAndRefcount & NOTIFY_SYNC) != 0) &&
  986. ((pstaskT->uFlags & MAPI_TASK_PENDING) == 0);
  987. #ifdef DEBUG
  988. if (((psreg->ulFlagsAndRefcount & NOTIFY_SYNC) != 0) &&
  989. ((pstaskT->uFlags & MAPI_TASK_PENDING) != 0))
  990. {
  991. DebugTrace("HrNotify: deferring sync spooler notification\n");
  992. }
  993. #endif
  994. rgtreg[itreg].ghidTask = ghidTask;
  995. ++itreg;
  996. pstaskT = NULL;
  997. }
  998. else
  999. TrapSz1("WARNING: %s trying to notify to a non-task", pinst->szModName);
  1000. }
  1001. ghidReg = psreg->ghidRegNext;
  1002. }
  1003. if (itreg == 0)
  1004. {
  1005. // Nobody is registered for this event. All done.
  1006. sc = S_OK;
  1007. goto ret;
  1008. }
  1009. ctreg = itreg;
  1010. // Create the parms structure in shared memory.
  1011. if (!(ghidParms = GH_Alloc(hgh, (UINT)(cb + offsetof(SPARMS,ab[0])))))
  1012. goto oom;
  1013. pparms = (LPSPARMS)GH_GetPv(hgh, ghidParms);
  1014. // Now copy the notification parameters.
  1015. pb = pparms->ab;
  1016. if (sc = ScCopyNotifications((int)cNotification, rgNotification, (LPVOID)pb, &cb))
  1017. goto ret;
  1018. // Fill in the rest of the parms structure.
  1019. pparms->cRef = 0;
  1020. pparms->ghidKey = ghidkey;
  1021. pparms->cNotifications = cNotification;
  1022. pparms->pvRef = (LPVOID)(pparms->ab);
  1023. pparms->cb = cb;
  1024. // Queue async notification to each task that's getting it.
  1025. // Sync notifications are handled separately.
  1026. for (itreg = 0; itreg < ctreg; ++itreg)
  1027. {
  1028. if (!rgtreg[itreg].fSync)
  1029. {
  1030. sc = ScEnqueueParms(pinst, hgh, rgtreg[itreg].ghidTask, ghidParms);
  1031. if (FAILED(sc))
  1032. goto ret;
  1033. if (sc == S_FALSE)
  1034. continue;
  1035. }
  1036. pparms->cRef++;
  1037. }
  1038. sc = S_OK;
  1039. // Bump the reference count on the SKEY by the number of notifications
  1040. // we're going to issue.
  1041. // The registration list may change between issuance and handling of
  1042. // notifications; we handle registrations disappearing, and new ones
  1043. // appearing is not a problem.
  1044. pskey->cRef += pparms->cRef;
  1045. // Loop through the registrations. If the caller requested a
  1046. // synchronous notification, use SendMessage to invoke the callback
  1047. // and record the result. Otherwise, use PostMessage for an
  1048. // asynchronous notification.
  1049. lResult = 0;
  1050. for (itreg = 0; itreg < ctreg; ++itreg)
  1051. {
  1052. pstaskT = (LPSTASK)GH_GetPv(hgh, rgtreg[itreg].ghidTask);
  1053. if (rgtreg[itreg].hwnd == hwndNoSpooler)
  1054. {
  1055. Assert(pstaskT->uFlags & MAPI_TASK_PENDING);
  1056. Assert(pstaskT->uFlags & MAPI_TASK_SPOOLER);
  1057. continue;
  1058. }
  1059. if (rgtreg[itreg].fSync)
  1060. {
  1061. // Unlock shared memory. A sync callback function
  1062. // will need to access it. This invalidates 'pstaskT'.
  1063. GH_ReleaseMutex(hgh);
  1064. ReleaseInst(&pinst);
  1065. pshdr = NULL;
  1066. pstaskT = NULL;
  1067. // Issue synchronous notification.
  1068. // Merge the results if there are multiple registrands.
  1069. lResult |= SendMessage(rgtreg[itreg].hwnd, wmNotify, (WPARAM)1,
  1070. (LPARAM)ghidParms);
  1071. if ((sc = ScGetInst(&pinst)) || !GH_WaitForMutex(hgh, INFINITE))
  1072. {
  1073. lResult |= CALLBACK_DISCONTINUE;
  1074. break;
  1075. }
  1076. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1077. }
  1078. else
  1079. {
  1080. if (!pstaskT->fSignalled)
  1081. {
  1082. // Post asynchronous notification message.
  1083. pstaskT->fSignalled =
  1084. PostMessage(rgtreg[itreg].hwnd, wmNotify, (WPARAM)0, (LPARAM)0);
  1085. #ifdef DEBUG
  1086. if (!pstaskT->fSignalled)
  1087. {
  1088. // Queue is full. They'll just have to wait until
  1089. // a later notification.
  1090. DebugTrace("Failed to post notification message to %s\n", pstaskT->szModName);
  1091. }
  1092. #endif /* DEBUG */
  1093. }
  1094. }
  1095. // else a message has already been queued
  1096. }
  1097. if (lResult & CALLBACK_DISCONTINUE)
  1098. *lpulFlags = NOTIFY_CANCELED;
  1099. ret:
  1100. if (sc)
  1101. {
  1102. if (pparms && !pparms->cRef)
  1103. GH_Free(hgh, ghidParms);
  1104. }
  1105. if (pshdr)
  1106. GH_ReleaseMutex(hgh);
  1107. ReleaseInst(&pinst);
  1108. STACK_FREE(rgtreg);
  1109. DebugTraceSc(HrNotify, sc);
  1110. return ResultFromScode(sc);
  1111. oom:
  1112. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  1113. goto ret;
  1114. #ifdef PARAMETER_VALIDATION
  1115. badArg:
  1116. #endif
  1117. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1118. }
  1119. /* End of notification engine exported functions */
  1120. /*
  1121. * LNotifWndProc
  1122. *
  1123. * Notification window procedure, the back half of Notify().
  1124. *
  1125. * The shared-memory offset of the notification parameter structure
  1126. * (SPARM) is passed as the LPARAM of wmNotify.
  1127. */
  1128. #ifndef MAC
  1129. LRESULT STDAPICALLTYPE
  1130. #else
  1131. LRESULT CALLBACK
  1132. #endif
  1133. LNotifWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1134. {
  1135. extern int fDaylight; // Defined in ..\common\dt.c
  1136. // Handle normal window messages.
  1137. if (msg != wmNotify)
  1138. {
  1139. #ifdef WIN16
  1140. if (msg == WM_TIMECHANGE)
  1141. {
  1142. // Reload the timezone information from WIN.INI.
  1143. fDaylight = -1;
  1144. CheckTimezone(NULL);
  1145. }
  1146. #endif /* WIN16 */
  1147. return DefWindowProc(hwnd, msg, wParam, lParam);
  1148. }
  1149. return DrainFilteredNotifQueue((BOOL)wParam, (GHID)lParam, NULL);
  1150. }
  1151. LRESULT STDAPICALLTYPE
  1152. DrainNotifQueue(BOOL fSync, ULONG ghidParms)
  1153. {
  1154. return DrainFilteredNotifQueue(fSync, (GHID)ghidParms, NULL);
  1155. }
  1156. LRESULT STDAPICALLTYPE
  1157. DrainFilteredNotifQueue(BOOL fSync, GHID ghidParms, LPNOTIFKEY pkeyFilter)
  1158. {
  1159. SCODE sc;
  1160. LRESULT l = 0L;
  1161. LRESULT lT;
  1162. LPINST pinst;
  1163. HGH hgh = NULL;
  1164. LPSHDR pshdr = NULL;
  1165. LPSKEY pskey;
  1166. GHID ghidReg;
  1167. int ireg;
  1168. int creg;
  1169. LPSREG rgsreg = NULL;
  1170. LPSREG psreg;
  1171. LPSPARMS pparmsS;
  1172. LPSPARMS pparms = NULL;
  1173. int intf;
  1174. LPNOTIFICATION pntf;
  1175. #ifndef GH_POINTERS_VALID
  1176. ULONG cb;
  1177. #endif
  1178. ULONG ulEvents;
  1179. LPSTASK pstask = NULL;
  1180. GHID ghidTask;
  1181. HWND hwndNotify;
  1182. HLH hlh = NULL;
  1183. #ifdef DEBUG
  1184. int sum1;
  1185. int sum2;
  1186. LPBYTE pb;
  1187. #endif
  1188. if (sc = ScGetInstRetry(&pinst))
  1189. goto ret;
  1190. hgh = pinst->hghShared;
  1191. hwndNotify = pinst->hwndNotify;
  1192. hlh = pinst->hlhInternal;
  1193. // Lock shared memory. It is locked here and at the bottom of the
  1194. // main loop, and unlocked in the middle of the main loop.
  1195. //$ Review: using an infinite timeout is not good.
  1196. //$ We should use a fairly short timeout (say, .2 seconds) and re-post
  1197. //$ the message if the timeout expires.
  1198. if (!GH_WaitForMutex(hgh, INFINITE))
  1199. {
  1200. sc = MAPI_E_TIMEOUT;
  1201. goto ret;
  1202. }
  1203. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1204. for (;;)
  1205. {
  1206. pstask = NULL;
  1207. if (fSync)
  1208. {
  1209. // Synchronous notification. Caller gave us parameters.
  1210. // Check them minimally.
  1211. #ifdef DEBUG
  1212. AssertSz(FValidParms(hgh, pshdr, ghidParms), "DrainFilteredNotif with fSync");
  1213. #endif /* DEBUG */
  1214. }
  1215. else
  1216. {
  1217. // Async notification. Find our task queue and pull off the
  1218. // first parameter set.
  1219. if (ScFindTask(pinst, hwndNotify, hgh, &ghidTask, NULL))
  1220. {
  1221. // No queue. Perhaps the message came in late. Just bail.
  1222. sc = S_OK;
  1223. goto ret;
  1224. }
  1225. pstask = (LPSTASK)GH_GetPv(hgh, ghidTask);
  1226. if (ScDequeueParms(hgh, pstask, pkeyFilter, &ghidParms))
  1227. // Queue is empty. All finished.
  1228. break;
  1229. }
  1230. // Copy registrations to local memory. We need at most
  1231. // the number of registrations on the key, so we count them.
  1232. pparmsS = (LPSPARMS)GH_GetPv(hgh, ghidParms);
  1233. pskey = (LPSKEY)GH_GetPv(hgh, pparmsS->ghidKey);
  1234. for (ghidReg = pskey->ghidRegs, creg = 0; ghidReg; )
  1235. {
  1236. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  1237. ghidReg = psreg->ghidRegNext;
  1238. ++creg;
  1239. }
  1240. if (creg != 0)
  1241. {
  1242. rgsreg = LH_Alloc(hlh, creg * sizeof(SREG));
  1243. if (!rgsreg)
  1244. goto oom;
  1245. LH_SetName(hlh, rgsreg, "Copy of notification registrations");
  1246. // Copy notification parameters to local memory IF they
  1247. // need to be relocated. This is true only on NT; on other
  1248. // platforms, the global heap manager maps shared memory to
  1249. // the same address on all processes.
  1250. #ifndef GH_POINTERS_VALID
  1251. pparms = LH_Alloc(hlh, pparmsS->cb + offsetof(SPARMS, ab[0]));
  1252. if (!pparms)
  1253. goto oom;
  1254. LH_SetName(hlh, pparms, "Copy of notification parameters");
  1255. MemCopy(pparms, pparmsS, (UINT)pparmsS->cb + offsetof(SPARMS,ab[0]));
  1256. #else
  1257. pparms = pparmsS;
  1258. #endif
  1259. ghidReg = pskey->ghidRegs;
  1260. ireg = 0;
  1261. while (ghidReg)
  1262. {
  1263. Assert(ireg < creg);
  1264. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  1265. if (psreg->hwnd == hwndNotify)
  1266. {
  1267. // It's for this process, use it.
  1268. // AddRef the advise sink (sorta). The registration may
  1269. // go away after we let go of the mutexes.
  1270. if (FBadIUnknownComplete(psreg->lpAdvise) ||
  1271. IsBadCodePtr((FARPROC)psreg->lpAdvise->lpVtbl->OnNotify))
  1272. {
  1273. DebugTrace("Notif callback 0x%lx went bad on me (1)!\n", psreg->lpAdvise);
  1274. }
  1275. else if (psreg->ulFlagsAndRefcount & SREG_DELETING)
  1276. {
  1277. DebugTrace("Skipping notif callback on disappearing advise sink\n");
  1278. }
  1279. else
  1280. {
  1281. // Keep a reference alive to the advise sink, BUT
  1282. // without calling AddRef with stuff locked.
  1283. // UlAddRef(psreg->lpAdvise);
  1284. AddRefCallback(psreg);
  1285. MemCopy(rgsreg + ireg, psreg, sizeof(SREG));
  1286. // Keep a reference to the shared SREG.
  1287. // The callback refcount will keep it alive for us.
  1288. rgsreg[ireg].ghidRegNext = GH_GetId(hgh, psreg);
  1289. ++ireg;
  1290. }
  1291. }
  1292. ghidReg = psreg->ghidRegNext;
  1293. }
  1294. creg = ireg;
  1295. }
  1296. // Unlock shared memory. After this point, references into
  1297. // shared memory should no longer be used, so we null them out.
  1298. GH_ReleaseMutex(hgh);
  1299. pshdr = NULL;
  1300. psreg = NULL;
  1301. pparmsS = NULL;
  1302. pstask = NULL;
  1303. ReleaseInst(&pinst);
  1304. if (creg == 0)
  1305. goto cleanup; // Nothing to do for this notification
  1306. pntf = (LPNOTIFICATION)pparms->ab;
  1307. ulEvents = 0;
  1308. for (intf = 0; (ULONG)intf < pparms->cNotifications; ++intf)
  1309. {
  1310. ulEvents |= pntf[intf].ulEventType;
  1311. }
  1312. #ifndef GH_POINTERS_VALID
  1313. // Adjust the pointers within the notification parameters. Yeech.
  1314. if (sc = ScRelocNotifications((int)pparms->cNotifications,
  1315. (LPNOTIFICATION)pparms->ab, pparms->pvRef, pparms->ab, &cb))
  1316. goto ret;
  1317. #endif
  1318. #ifdef DEBUG
  1319. // Checksum the notification. We'll assert if the callback
  1320. // function modifies it.
  1321. sum1 = 0;
  1322. for (pb = pparms->ab + pparms->cb - 1; pb >= pparms->ab; --pb)
  1323. sum1 += *pb;
  1324. #endif
  1325. // Loop through the list of registrations. For each one,
  1326. // issue the callback if it is of interest.
  1327. // Remember the result for synchronous callbacks.
  1328. pntf = (LPNOTIFICATION)pparms->ab;
  1329. #if defined (_AMD64_) || defined(_IA64_)
  1330. AssertSz (FIsAligned (pparms->ab), "DrainFilteredNotifyQueue: unaligned reloceated notif");
  1331. #endif
  1332. for (ireg = creg, psreg = rgsreg; ireg--; ++psreg)
  1333. {
  1334. if ((ulEvents & psreg->ulEventMask))
  1335. {
  1336. if (FBadIUnknownComplete(psreg->lpAdvise) ||
  1337. IsBadCodePtr((FARPROC)psreg->lpAdvise->lpVtbl->OnNotify))
  1338. {
  1339. DebugTrace("Notif callback 0x%lx went bad on me (2)!\n", psreg->lpAdvise);
  1340. continue;
  1341. }
  1342. // Issue the callback
  1343. lT = psreg->lpAdvise->lpVtbl->OnNotify(psreg->lpAdvise,
  1344. pparms->cNotifications, pntf);
  1345. // Record the result. Stop issuing notifications if so asked.
  1346. // Note that this does not stop handling of other events,
  1347. // i.e. we do not break the outer loop.
  1348. if (psreg->ulFlagsAndRefcount & NOTIFY_SYNC)
  1349. {
  1350. // Assert(fSync);
  1351. // or the task is still marked pending
  1352. l |= lT;
  1353. if (lT == CALLBACK_DISCONTINUE)
  1354. break;
  1355. #ifdef DEBUG
  1356. else if (lT)
  1357. DebugTrace("DrainNotifQueue: callback function returns garbage 0x%lx\n", lT);
  1358. #endif
  1359. }
  1360. #ifdef DEBUG
  1361. // Checksum the notification again, and assert if the
  1362. // callback function has modified it.
  1363. sum2 = 0;
  1364. for (pb = pparms->ab + pparms->cb - 1;
  1365. pb >= pparms->ab;
  1366. --pb)
  1367. sum2 += *pb;
  1368. AssertSz(sum1 == sum2, "Notification callback modified its parameters");
  1369. #endif
  1370. }
  1371. }
  1372. cleanup:
  1373. Assert(ghidParms);
  1374. // Lock shared memory
  1375. if (sc = ScGetInstRetry(&pinst))
  1376. goto ret;
  1377. if (!GH_WaitForMutex(hgh, INFINITE))
  1378. {
  1379. sc = MAPI_E_TIMEOUT;
  1380. goto ret;
  1381. }
  1382. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1383. // Deref the callback and see if we need to release any
  1384. // advise sinks. If somebody unadvised while we were calling back,
  1385. // the SREG_DELETING flag is now on.
  1386. for (ireg = creg, psreg = rgsreg; ireg--; ++psreg)
  1387. {
  1388. LPSREG psregT;
  1389. Assert(FValidReg(hgh, pshdr, psreg->ghidRegNext));
  1390. psregT = (LPSREG) GH_GetPv(hgh, psreg->ghidRegNext);
  1391. // Deref the callback in lieu of actually releasing
  1392. // the advise sink.
  1393. ReleaseCallback(psregT);
  1394. if ((psregT->ulFlagsAndRefcount & SREG_DELETING) &&
  1395. !IsRefCallback(psregT))
  1396. {
  1397. DebugTrace("Unadvise happened during my callback\n");
  1398. psreg->ulFlagsAndRefcount |= SREG_DELETING;
  1399. Unregister(pinst, psregT->ghidKey, psreg->ghidRegNext, NULL);
  1400. }
  1401. // if (FBadIUnknownComplete(psreg->lpAdvise) ||
  1402. // IsBadCodePtr((FARPROC)psreg->lpAdvise->lpVtbl->OnNotify))
  1403. // {
  1404. // DebugTrace("Notif callback 0x%lx went bad on me (3)!\n", psreg->lpAdvise);
  1405. // continue;
  1406. // }
  1407. //
  1408. // UlRelease(psreg->lpAdvise);
  1409. }
  1410. // Verify that the parms pointer is still good. It may have
  1411. // been cleaned up when we let go of everything.
  1412. //$ That should only happen if the whole engine goes away.
  1413. if (FValidParms(hgh, pshdr, ghidParms))
  1414. {
  1415. // Note: pparms may be NULL at this point
  1416. pparmsS = (LPSPARMS)GH_GetPv(hgh, ghidParms);
  1417. // Let go of the key. If the parms are still valid,
  1418. // so should the key be -- it's validated in FValidParms.
  1419. pskey = (LPSKEY)GH_GetPv(hgh, pparmsS->ghidKey);
  1420. Assert(!pparms || pparms->ghidKey == pparmsS->ghidKey);
  1421. ReleaseKey(pinst, pparmsS->ghidKey);
  1422. // Let go of the parameters
  1423. if (--(pparmsS->cRef) == 0)
  1424. GH_Free(hgh, ghidParms);
  1425. }
  1426. #ifdef DEBUG
  1427. else
  1428. DebugTrace("DrainFilteredNotif cleanup: parms %08lx are gone\n", ghidParms);
  1429. #endif
  1430. pparmsS = NULL;
  1431. ghidParms = 0;
  1432. #ifndef GH_POINTERS_VALID
  1433. if (pparms)
  1434. LH_Free(hlh, pparms);
  1435. #endif
  1436. pparms = NULL;
  1437. // Let go of resources again, and release any advise sinks that
  1438. // may need to be released.
  1439. GH_ReleaseMutex(hgh);
  1440. pshdr = NULL;
  1441. ReleaseInst(&pinst);
  1442. for (ireg = creg, psreg = rgsreg; ireg--; ++psreg)
  1443. {
  1444. if (psreg->ulFlagsAndRefcount & SREG_DELETING)
  1445. {
  1446. if (FBadIUnknownComplete(psreg->lpAdvise) ||
  1447. IsBadCodePtr((FARPROC)psreg->lpAdvise->lpVtbl->OnNotify))
  1448. {
  1449. DebugTrace("Notif callback 0x%lx went bad on me (3)!\n", psreg->lpAdvise);
  1450. continue;
  1451. }
  1452. UlRelease(psreg->lpAdvise);
  1453. }
  1454. }
  1455. if (rgsreg)
  1456. LH_Free(hlh, rgsreg);
  1457. rgsreg = NULL;
  1458. // If we handled a sync notification, do not loop back.
  1459. if (fSync)
  1460. break;
  1461. // Lock shared memory for next iteration of the loop
  1462. if (sc = ScGetInstRetry(&pinst))
  1463. goto ret;
  1464. if (!GH_WaitForMutex(hgh, INFINITE))
  1465. {
  1466. sc = MAPI_E_TIMEOUT;
  1467. goto ret;
  1468. }
  1469. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1470. }
  1471. ret:
  1472. // Decrement the reference counter on the notification parameters.
  1473. // Free them if it drops to 0.
  1474. if (ghidParms)
  1475. {
  1476. // Lock instance and shared memory
  1477. if (pinst || !(sc = ScGetInstRetry(&pinst)))
  1478. {
  1479. if (pshdr || GH_WaitForMutex(hgh, INFINITE))
  1480. {
  1481. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1482. // Verify that the parms are still there
  1483. pparmsS = (LPSPARMS)GH_GetPv(hgh, ghidParms);
  1484. // Let go of the key
  1485. pskey = (LPSKEY)GH_GetPv(hgh, pparmsS->ghidKey);
  1486. Assert(!pparms || pparms->ghidKey == pparmsS->ghidKey);
  1487. ReleaseKey(pinst, pparmsS->ghidKey);
  1488. // Let go of the parameters
  1489. if (--(pparmsS->cRef) == 0)
  1490. GH_Free(hgh, ghidParms);
  1491. }
  1492. }
  1493. }
  1494. if (pshdr)
  1495. GH_ReleaseMutex(hgh);
  1496. #ifndef GH_POINTERS_VALID
  1497. if (pparms)
  1498. LH_Free(hlh, pparms);
  1499. #endif
  1500. if (rgsreg)
  1501. LH_Free(hlh, rgsreg);
  1502. ReleaseInst(&pinst);
  1503. #ifdef DEBUG
  1504. if (sc)
  1505. {
  1506. DebugTrace("DrainNotifQueue failed to handle notification (%s)\n", SzDecodeScode(sc));
  1507. }
  1508. #endif
  1509. return l;
  1510. oom:
  1511. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  1512. goto ret;
  1513. }
  1514. // See mapidbg.h for similar macros.
  1515. #define TraceIfSz(t,psz) IFTRACE((t) ? DebugTraceFn("~" psz) : 0)
  1516. BOOL FBadIUnknownComplete(LPVOID lpv)
  1517. {
  1518. BOOL fBad;
  1519. LPUNKNOWN lpObj = (LPUNKNOWN) lpv;
  1520. fBad = IsBadReadPtr(lpObj, sizeof(LPVOID));
  1521. TraceIfSz(fBad, "FBadIUnknownComplete: object bad");
  1522. if (!fBad)
  1523. {
  1524. fBad = IsBadReadPtr(lpObj->lpVtbl, 3 * sizeof(LPUNKNOWN));
  1525. TraceIfSz(fBad, "FBadIUnknownComplete: vtbl bad");
  1526. }
  1527. if (!fBad)
  1528. {
  1529. fBad = IsBadCodePtr((FARPROC)lpObj->lpVtbl->QueryInterface);
  1530. TraceIfSz(fBad, "FBadIUnknownComplete: QI bad");
  1531. }
  1532. if (!fBad)
  1533. {
  1534. fBad = IsBadCodePtr((FARPROC)lpObj->lpVtbl->AddRef);
  1535. TraceIfSz(fBad, "FBadIUnknownComplete: AddRef bad");
  1536. }
  1537. if (!fBad)
  1538. {
  1539. fBad = IsBadCodePtr((FARPROC)lpObj->lpVtbl->Release);
  1540. TraceIfSz(fBad, "FBadIUnknownComplete: Release bad");
  1541. }
  1542. return fBad;
  1543. }
  1544. #undef TraceIfSz
  1545. #ifdef WIN16
  1546. SCODE
  1547. ScGetInstRetry(LPINST FAR *ppinst)
  1548. {
  1549. LPINST pinst = (LPINST)PvGetInstanceGlobals();
  1550. DWORD dwPid;
  1551. Assert(ppinst);
  1552. *ppinst = NULL;
  1553. if (!pinst)
  1554. {
  1555. // We may have gotten called with an unusual value of SS,
  1556. // which is normally our search key for instance globals.
  1557. // Retry using the OLE process ID.
  1558. dwPid = CoGetCurrentProcess();
  1559. pinst = PvSlowGetInstanceGlobals(dwPid);
  1560. if (!pinst)
  1561. {
  1562. DebugTraceSc(ScGetInst, MAPI_E_NOT_INITIALIZED);
  1563. return MAPI_E_NOT_INITIALIZED;
  1564. }
  1565. }
  1566. if (!pinst->cRef)
  1567. {
  1568. DebugTrace("ScGetInst: race! cRef == 0 before EnterCriticalSection\r\n");
  1569. return MAPI_E_NOT_INITIALIZED;
  1570. }
  1571. EnterCriticalSection(&pinst->cs);
  1572. if (!pinst->cRef)
  1573. {
  1574. DebugTrace("ScGetInst: race! cRef == 0 after EnterCriticalSection\r\n");
  1575. LeaveCriticalSection(&pinst->cs);
  1576. return MAPI_E_NOT_INITIALIZED;
  1577. }
  1578. *ppinst = pinst;
  1579. return S_OK;
  1580. }
  1581. #endif /* WIN16 */
  1582. /*
  1583. * ScFindKey
  1584. *
  1585. * Searches for a notification key in the shared memory list.
  1586. * The list is sorted descending by notification key.
  1587. *
  1588. * Returns:
  1589. * S_OK: key was found
  1590. * S_FALSE: key was not found
  1591. * in EITHER case, *pikey is an index into the key list, which points
  1592. * to the first entry >= lpKey.
  1593. */
  1594. SCODE
  1595. ScFindKey(LPNOTIFKEY pkey, HGH hgh, LPSHDR pshdr, ULONG FAR *pikey)
  1596. {
  1597. ULONG ikey;
  1598. PGHID pghidKey;
  1599. int ckey;
  1600. UINT cbT;
  1601. int n = -1;
  1602. LPNOTIFKEY pkeyT;
  1603. Assert(pkey->cb <= 0xFFFF);
  1604. //$ SPEED try binary search ?
  1605. ikey = 0;
  1606. ckey = pshdr->cKeyMac;
  1607. if (pshdr->ghidKeyList)
  1608. {
  1609. pghidKey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1610. while (ckey--)
  1611. {
  1612. pkeyT = &((LPSKEY)GH_GetPv(hgh, pghidKey[ikey]))->key;
  1613. cbT = min((UINT)pkey->cb, (UINT)pkeyT->cb);
  1614. n = memcmp(pkey->ab, pkeyT->ab, cbT);
  1615. if (n == 0 && pkey->cb != pkeyT->cb)
  1616. n = pkey->cb > pkeyT->cb ? 1 : -1;
  1617. if (n >= 0)
  1618. break;
  1619. ++ikey;
  1620. }
  1621. }
  1622. *pikey = ikey;
  1623. return n == 0 ? S_OK : S_FALSE;
  1624. }
  1625. /*
  1626. * Unregister
  1627. *
  1628. * Removes a registration structure (SREG) from shared memory. If
  1629. * that was the last registration for its key, also removes the
  1630. * key.
  1631. *
  1632. * Hooked to notification object release and invalidation.
  1633. */
  1634. void
  1635. Unregister(LPINST pinst, GHID ghidKey, GHID ghidReg,
  1636. LPMAPIADVISESINK FAR *ppadvise)
  1637. {
  1638. HGH hgh = pinst->hghShared;
  1639. LPSHDR pshdr;
  1640. LPSKEY pskey;
  1641. LPSREG psreg;
  1642. GHID ghid;
  1643. GHID ghidPrev;
  1644. pshdr = GH_GetPv(hgh, pinst->ghidshdr);
  1645. // Note: validation of the SREG and SKEY structures is assumed to
  1646. // have been done before calling this routine. We just assert it.
  1647. pskey = (LPSKEY)GH_GetPv(hgh, ghidKey);
  1648. Assert(FValidKey(hgh, pshdr, ghidKey));
  1649. // Remove the SREG structure from the list and free it
  1650. for (ghid = pskey->ghidRegs, ghidPrev = 0; ghid;
  1651. ghidPrev = ghid, ghid = ((LPSREG)GH_GetPv(hgh, ghid))->ghidRegNext)
  1652. {
  1653. if (ghid == ghidReg)
  1654. {
  1655. psreg = (LPSREG)GH_GetPv(hgh, ghid);
  1656. if (ghidPrev)
  1657. ((LPSREG)GH_GetPv(hgh, ghidPrev))->ghidRegNext = psreg->ghidRegNext;
  1658. else
  1659. pskey->ghidRegs = psreg->ghidRegNext;
  1660. if (ppadvise)
  1661. *ppadvise = psreg->lpAdvise;
  1662. GH_Free(hgh, ghid);
  1663. break;
  1664. }
  1665. }
  1666. ReleaseKey(pinst, ghidKey);
  1667. }
  1668. void
  1669. ReleaseKey(LPINST pinst, GHID ghidKey)
  1670. {
  1671. HGH hgh;
  1672. LPSHDR pshdr;
  1673. LPSKEY pskey;
  1674. PGHID pghid;
  1675. int cghid;
  1676. Assert(ghidKey);
  1677. hgh = pinst->hghShared;
  1678. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1679. pskey = (LPSKEY)GH_GetPv(hgh, ghidKey);
  1680. // Decrement the key's refcount, and free the key if it's now 0
  1681. if (--(pskey->cRef) == 0)
  1682. {
  1683. Assert(pskey->ghidRegs == 0);
  1684. pghid = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1685. cghid = pshdr->cKeyMac;
  1686. for ( ; cghid--; ++pghid)
  1687. {
  1688. if (*pghid == ghidKey)
  1689. {
  1690. // tricky: cghid already decremented in the loop test
  1691. MemCopy(pghid, (LPBYTE)pghid + sizeof(GHID), cghid*sizeof(GHID));
  1692. --(pshdr->cKeyMac);
  1693. GH_Free(hgh, ghidKey);
  1694. break;
  1695. }
  1696. }
  1697. }
  1698. }
  1699. BOOL
  1700. FValidKey(HGH hgh, LPSHDR pshdr, GHID ghidKey)
  1701. {
  1702. int cKey;
  1703. GHID * pghidKey;
  1704. LPSREG psreg;
  1705. LPSKEY pskey;
  1706. GHID ghidregT;
  1707. int creg;
  1708. // Check for accessible memory.
  1709. // GH doesn't expose the ability to check whether it's a
  1710. // valid block in the heap.
  1711. if (IsBadWritePtr(GH_GetPv(hgh, ghidKey), sizeof(SKEY)))
  1712. {
  1713. DebugTraceArg(FValidKey, "key is not valid memory");
  1714. return FALSE;
  1715. }
  1716. // Verify that the key is in the list of all keys.
  1717. Assert(pshdr->cKeyMac < 0x10000);
  1718. cKey = (int) pshdr->cKeyMac;
  1719. pghidKey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1720. for ( ; cKey > 0; --cKey, ++pghidKey)
  1721. {
  1722. if (ghidKey == *pghidKey)
  1723. break;
  1724. }
  1725. // If we fell off the loop, the key is missing
  1726. if (cKey <= 0)
  1727. {
  1728. DebugTraceArg(FValidKey, "key not found in shared header list");
  1729. return FALSE;
  1730. }
  1731. // Validate the registration chain.
  1732. pskey = (LPSKEY)GH_GetPv(hgh, ghidKey);
  1733. creg = 0;
  1734. for (ghidregT = pskey->ghidRegs; ghidregT; )
  1735. {
  1736. ++creg;
  1737. psreg = (LPSREG) GH_GetPv(hgh, ghidregT);
  1738. if (IsBadWritePtr(psreg, sizeof(SREG)))
  1739. {
  1740. DebugTraceArg(FValidReg, "key has broken reg chain");
  1741. return FALSE;
  1742. }
  1743. if (psreg->ghidKey != ghidKey)
  1744. {
  1745. DebugTraceArg(FValidReg, "key has broken or crossed reg chains");
  1746. return FALSE;
  1747. }
  1748. if (creg > pskey->cRef)
  1749. {
  1750. // FWIW, this will also catch a cycle
  1751. DebugTraceArg(FValidReg, "ghidReg's key chain length exceeds refcount");
  1752. return FALSE;
  1753. }
  1754. ghidregT = psreg->ghidRegNext;
  1755. }
  1756. return TRUE;
  1757. }
  1758. BOOL
  1759. FValidReg(HGH hgh, LPSHDR pshdr, GHID ghidReg)
  1760. {
  1761. LPSREG psreg;
  1762. LPSKEY pskey;
  1763. GHID ghidregT;
  1764. GHID ghidKey;
  1765. UINT creg = 0;
  1766. // Check for accessible memory.
  1767. // GH does not expose the ability to check whether it's a
  1768. // valid block in the heap.
  1769. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  1770. if ( IsBadWritePtr(psreg, sizeof(SREG))
  1771. #if defined (_AMD64_) || defined(_IA64_)
  1772. || !FIsAligned(psreg)
  1773. #endif
  1774. )
  1775. {
  1776. DebugTraceArg(FValidReg, "ghidReg refers to invalid memory");
  1777. return FALSE;
  1778. }
  1779. // Validate the key.
  1780. ghidKey = psreg->ghidKey;
  1781. if (!FValidKey(hgh, pshdr, ghidKey))
  1782. {
  1783. DebugTraceArg(FValidReg, "ghidReg contains an invalid key");
  1784. return FALSE;
  1785. }
  1786. // FValidKey validated the key's registration chain, so we can
  1787. // now safely loop through and check for this registration.
  1788. pskey = (LPSKEY)GH_GetPv(hgh, ghidKey);
  1789. for (ghidregT = pskey->ghidRegs; ghidregT; )
  1790. {
  1791. if (ghidReg == ghidregT)
  1792. return TRUE;
  1793. psreg = (LPSREG) GH_GetPv(hgh, ghidregT);
  1794. ghidregT = psreg->ghidRegNext;
  1795. }
  1796. // If we fell off the loop, the registration is missing
  1797. DebugTraceArg(FValidReg, "ghidReg is not linked to its key");
  1798. return FALSE;
  1799. }
  1800. BOOL
  1801. FValidParms(HGH hgh, LPSHDR pshdr, GHID ghidParms)
  1802. {
  1803. LPSPARMS pparms;
  1804. pparms = (LPSPARMS)GH_GetPv(hgh, ghidParms);
  1805. if (IsBadWritePtr(pparms, offsetof(SPARMS, ab)) ||
  1806. IsBadWritePtr(pparms, (UINT) (offsetof(SPARMS, ab) + pparms->cb)))
  1807. {
  1808. DebugTraceArg(FValidParms, "ghidParms refers to invalid memory");
  1809. return FALSE;
  1810. }
  1811. if (!FValidKey(hgh, pshdr, pparms->ghidKey))
  1812. {
  1813. DebugTraceArg(FValidParms, "ghidParms does not contain a valid key");
  1814. return FALSE;
  1815. }
  1816. //$ Notification parameters not checked
  1817. return TRUE;
  1818. }
  1819. BOOL
  1820. FValidRgkey(HGH hgh, LPSHDR pshdr)
  1821. {
  1822. PGHID pghidKey;
  1823. UINT cKey;
  1824. cKey = (UINT) pshdr->cKeyMac;
  1825. pghidKey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1826. if (cKey == 0)
  1827. return TRUE;
  1828. // Address-check the list of keys
  1829. if (IsBadWritePtr(pghidKey, cKey*sizeof(GHID)))
  1830. {
  1831. DebugTraceArg(FValidRgkey, "key list is toast");
  1832. return FALSE;
  1833. }
  1834. // Validate each key in the list
  1835. for ( ; cKey; --cKey, ++pghidKey)
  1836. {
  1837. if (!FValidKey(hgh, pshdr, *pghidKey))
  1838. {
  1839. DebugTrace("FValidRgkey: element %d of %d (value 0x%08lx) is bad\n",
  1840. (UINT)pshdr->cKeyMac - cKey, (UINT)pshdr->cKeyMac, *pghidKey);
  1841. return FALSE;
  1842. }
  1843. }
  1844. // Verify that the NOTIFKEYs are in the right order
  1845. if (!FSortedRgkey(hgh, pshdr))
  1846. {
  1847. DebugTraceArg(FValidRgkey, "key list is out of order");
  1848. return FALSE;
  1849. }
  1850. return TRUE;
  1851. }
  1852. BOOL
  1853. FSortedRgkey(HGH hgh, LPSHDR pshdr)
  1854. {
  1855. PGHID pghidKey;
  1856. UINT cKey;
  1857. LPSKEY pskey1;
  1858. LPSKEY pskey2;
  1859. UINT cb;
  1860. int n;
  1861. cKey = (UINT) pshdr->cKeyMac;
  1862. if (cKey < 1)
  1863. return TRUE;
  1864. pghidKey = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1865. for (--cKey; cKey > 0; --cKey, ++pghidKey)
  1866. {
  1867. pskey1 = (LPSKEY)GH_GetPv(hgh, pghidKey[0]);
  1868. pskey2 = (LPSKEY)GH_GetPv(hgh, pghidKey[1]);
  1869. cb = (UINT) min(pskey1->key.cb, pskey2->key.cb);
  1870. n = memcmp(pskey1->key.ab, pskey2->key.ab, cb);
  1871. if (n < 0 || (n == 0 && pskey1->key.cb < pskey2->key.cb))
  1872. return FALSE;
  1873. }
  1874. return TRUE;
  1875. }
  1876. SCODE
  1877. ScFindTask(LPINST pinst, HWND hwndNotify, HGH hgh,
  1878. PGHID pghidTask, PGHID pghidTaskPrev)
  1879. {
  1880. LPSHDR pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1881. GHID ghidTask;
  1882. GHID ghidTaskPrev = 0;
  1883. LPSTASK pstask;
  1884. for (ghidTask = pshdr->ghidTaskList; ghidTask; ghidTask = pstask->ghidTaskNext)
  1885. {
  1886. pstask = (LPSTASK)GH_GetPv(hgh, ghidTask);
  1887. if (pstask->hwndNotify == hwndNotify)
  1888. goto found;
  1889. else if (hwndNotify == hwndNoSpooler &&
  1890. (pstask->uFlags & MAPI_TASK_SPOOLER))
  1891. {
  1892. Assert(pstask->uFlags & MAPI_TASK_PENDING);
  1893. TraceSz1("ScFindTask: %s hit spooler startup window", pinst->szModName);
  1894. goto found;
  1895. }
  1896. ghidTaskPrev = ghidTask;
  1897. }
  1898. DebugTraceSc(ScFindTask, S_FALSE);
  1899. return S_FALSE;
  1900. found:
  1901. *pghidTask = ghidTask;
  1902. if (pghidTaskPrev)
  1903. *pghidTaskPrev = ghidTaskPrev;
  1904. return S_OK;
  1905. }
  1906. /*
  1907. * All necessary locks must be acquired before calling this function.
  1908. */
  1909. void
  1910. CleanupTask(LPINST pinst, HWND hwndNotify, BOOL fGripe)
  1911. {
  1912. HGH hgh = pinst->hghShared;
  1913. LPSHDR pshdr;
  1914. GHID ghidTask;
  1915. GHID ghidTaskPrev;
  1916. LPSTASK pstask;
  1917. PGHID rgghid;
  1918. UINT ighid;
  1919. GHID ghidKey;
  1920. LPSKEY pskey;
  1921. LPSPARMS pparms;
  1922. GHID ghidReg;
  1923. GHID ghidRegNext;
  1924. LPSREG psreg;
  1925. USHORT ckey;
  1926. pshdr = (LPSHDR)GH_GetPv(hgh, pinst->ghidshdr);
  1927. // Locate task
  1928. if (ScFindTask(pinst, hwndNotify, hgh, &ghidTask, &ghidTaskPrev))
  1929. return;
  1930. pstask = (LPSTASK)GH_GetPv(hgh, ghidTask);
  1931. #ifdef DEBUG
  1932. #if 1
  1933. // The message box will now give us problems internally -- since
  1934. // we're holding the shared memory mutex and other callers will now
  1935. // time out and error instead of waiting indefinitely.
  1936. if (fGripe)
  1937. DebugTrace("Notification client \'%s\' exited without cleaning up\n", pstask->szModName);
  1938. #else
  1939. // Note: system modal box rather than assert -- prevents race condition
  1940. // that kills EMS notification distribution.
  1941. if (fGripe)
  1942. {
  1943. CHAR szErr[128];
  1944. HWND hwnd = NULL;
  1945. #ifdef WIN32
  1946. hwnd = GetActiveWindow();
  1947. #endif
  1948. wnsprintfA(szErr, ARRAYSIZE(szErr), "Notification client \'%s\' exited without cleaning up\n",
  1949. pstask->szModName);
  1950. MessageBoxA(hwnd, szErr, "MAPI 1.0",
  1951. MB_SYSTEMMODAL | MB_ICONHAND | MB_OK);
  1952. }
  1953. #endif
  1954. #endif
  1955. // Clean up notification parameters
  1956. if (pstask->cparmsMac)
  1957. {
  1958. rgghid = (PGHID)GH_GetPv(hgh, pstask->ghidparms);
  1959. for (ighid = 0; ighid < (UINT)pstask->cparmsMac; ++ighid)
  1960. {
  1961. // Free each parameter structure, and deref its key
  1962. pparms = (LPSPARMS)GH_GetPv(hgh, rgghid[ighid]);
  1963. ghidKey = pparms->ghidKey;
  1964. if (--(pparms->cRef) == 0)
  1965. GH_Free(hgh, rgghid[ighid]);
  1966. ReleaseKey(pinst, ghidKey);
  1967. }
  1968. }
  1969. // Clean up registrations
  1970. rgghid = (PGHID)GH_GetPv(hgh, pshdr->ghidKeyList);
  1971. for (ighid = 0; ighid < (UINT)pshdr->cKeyMac; )
  1972. {
  1973. ckey = pshdr->cKeyMac;
  1974. pskey = (LPSKEY)GH_GetPv(hgh, rgghid[ighid]);
  1975. Assert(!IsBadWritePtr(pskey, sizeof(SKEY)));
  1976. for (ghidReg = pskey->ghidRegs; ghidReg; ghidReg = ghidRegNext)
  1977. {
  1978. LPMAPIADVISESINK padvise = NULL;
  1979. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  1980. if (IsBadWritePtr(psreg, sizeof(SREG)))
  1981. {
  1982. TrapSz1("Bad psreg == %08lX", psreg);
  1983. break;
  1984. }
  1985. ghidRegNext = psreg->ghidRegNext;
  1986. if (psreg->hwnd == hwndNotify)
  1987. // Release the registration's advise sink
  1988. // only if we're in the same process.
  1989. Unregister(pinst, rgghid[ighid], ghidReg,
  1990. pinst->hwndNotify == hwndNotify ? &padvise : NULL);
  1991. if (padvise && !FBadIUnknownComplete(padvise))
  1992. UlRelease(padvise);
  1993. }
  1994. // Bump index iff the key we just iterated on was not deleted
  1995. if (ckey == pshdr->cKeyMac)
  1996. ++ighid;
  1997. }
  1998. // Unhook and destroy the task structure
  1999. if (ghidTaskPrev)
  2000. ((LPSTASK)GH_GetPv(hgh, ghidTaskPrev))->ghidTaskNext = pstask->ghidTaskNext;
  2001. else
  2002. pshdr->ghidTaskList = pstask->ghidTaskNext;
  2003. if (pstask->ghidparms)
  2004. GH_Free(hgh, pstask->ghidparms);
  2005. GH_Free(hgh, ghidTask);
  2006. }
  2007. /*
  2008. * Adds a parameter block index to the queue for a task. If the
  2009. * parameter block is already in the queue, does not add it again.
  2010. * Returns:
  2011. * S_OK the item was added
  2012. * S_FALSE the item was duplicate; not added
  2013. * other out of memory
  2014. */
  2015. SCODE
  2016. ScEnqueueParms(LPINST pinst, HGH hgh, GHID ghidTask, GHID ghidParms)
  2017. {
  2018. SCODE sc = S_OK;
  2019. int ighid;
  2020. GHID ghid;
  2021. PGHID rgghid;
  2022. LPSTASK pstask = (LPSTASK)GH_GetPv(hgh, ghidTask);
  2023. // Make sure there's room to accommodate the new entry
  2024. if (!pstask->cparmsMax)
  2025. {
  2026. ghid = GH_Alloc(hgh, 8*sizeof(GHID));
  2027. if (!ghid)
  2028. goto oom;
  2029. pstask->cparmsMax = 8;
  2030. pstask->cparmsMac = 0;
  2031. pstask->ghidparms = ghid;
  2032. }
  2033. else if (pstask->cparmsMac == pstask->cparmsMax)
  2034. {
  2035. ghid = GH_Realloc(hgh, pstask->ghidparms,
  2036. (pstask->cparmsMax+8) * sizeof(GHID));
  2037. if (!ghid)
  2038. {
  2039. DebugTrace( "ScEnqueueParms: ghidparms can't grow.\n");
  2040. goto oom;
  2041. }
  2042. pstask->cparmsMax += 8;
  2043. pstask->ghidparms = ghid;
  2044. }
  2045. else
  2046. ghid = pstask->ghidparms;
  2047. rgghid = (PGHID)GH_GetPv(hgh, ghid);
  2048. // Mark the task as needing to be signalled
  2049. if (pstask->cparmsMac == 0)
  2050. pstask->fSignalled = FALSE;
  2051. // Scan for duplicates. If this entry is already in the queue,
  2052. // don't add it again; we'll scan for registrations and distribute
  2053. // the notifications on the receiving side.
  2054. for (ighid = (int)pstask->cparmsMac; ighid > 0; )
  2055. {
  2056. if (rgghid[--ighid] == ghidParms)
  2057. return S_FALSE; // don't trace this
  2058. }
  2059. // Add the new entry
  2060. rgghid[pstask->cparmsMac++] = ghidParms;
  2061. ret:
  2062. DebugTraceSc(ScEnqueueParms, sc);
  2063. return sc;
  2064. oom:
  2065. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  2066. goto ret;
  2067. }
  2068. SCODE
  2069. ScDequeueParms(HGH hgh,
  2070. LPSTASK pstask,
  2071. LPNOTIFKEY pkeyFilter,
  2072. PGHID pghidParms)
  2073. {
  2074. PGHID rgghid;
  2075. UINT ighid;
  2076. LPSKEY pskey;
  2077. LPSPARMS pparmsS;
  2078. *pghidParms = 0;
  2079. if (pstask->cparmsMac == 0)
  2080. {
  2081. pstask->fSignalled = FALSE;
  2082. if (pstask->cparmsMax > 8)
  2083. {
  2084. GH_Free(hgh, pstask->ghidparms);
  2085. pstask->ghidparms = 0;
  2086. pstask->cparmsMax = pstask->cparmsMac = 0;
  2087. }
  2088. return S_FALSE;
  2089. }
  2090. Assert(pstask->ghidparms);
  2091. rgghid = (PGHID)GH_GetPv(hgh, pstask->ghidparms);
  2092. for (ighid = 0; ighid < pstask->cparmsMac; ighid++)
  2093. {
  2094. pparmsS = (LPSPARMS)GH_GetPv(hgh, rgghid[ighid]);
  2095. pskey = (LPSKEY)GH_GetPv(hgh, pparmsS->ghidKey);
  2096. if (!pkeyFilter ||
  2097. ((pkeyFilter->cb == pskey->key.cb) &&
  2098. (!memcmp (pkeyFilter->ab, pskey->key.ab, (UINT)pskey->key.cb))))
  2099. {
  2100. *pghidParms = rgghid[ighid];
  2101. MemCopy (&rgghid[ighid], &rgghid[ighid+1],
  2102. (--(pstask->cparmsMac) - ighid) * sizeof(GHID));
  2103. // If we've drained the queue of pending notifications,
  2104. // flip over to normal
  2105. if ((pstask->uFlags & MAPI_TASK_PENDING) && pstask->cparmsMac == 0)
  2106. {
  2107. DebugTrace("ScDequeueParms: spooler is no longer pending\n");
  2108. pstask->uFlags &= ~MAPI_TASK_PENDING;
  2109. }
  2110. return S_OK;
  2111. }
  2112. }
  2113. pstask->fSignalled = FALSE;
  2114. return S_FALSE;
  2115. }
  2116. #if defined(WIN32) && !defined(MAC)
  2117. /*
  2118. * On NT and Windows 95, the message pump for the notification window runs
  2119. * in its own thread. This is it.
  2120. */
  2121. DWORD WINAPI
  2122. NotifyThreadFn(DWORD dw)
  2123. {
  2124. MSG msg;
  2125. SCODE sc;
  2126. SCODE scCo;
  2127. LPINST pinst = (LPINST) dw;
  2128. // SNEAKY: When ScInitMapiX spawns us, it has the pinst (but not the
  2129. // shared memory block) locked. Immediately afterward, it blocks
  2130. // until we release it. This makes it safe for us to use the pinst
  2131. // that it gives us.
  2132. scCo = CoInitialize(NULL);
  2133. if (scCo)
  2134. DebugTrace("NotifyThreadFn: CoInitializeEx returns %s\n", SzDecodeScode(scCo));
  2135. Assert(!IsBadWritePtr(pinst, sizeof(INST)));
  2136. if (!GH_WaitForMutex(pinst->hghShared, INFINITE))
  2137. {
  2138. sc = MAPI_E_TIMEOUT;
  2139. DebugTrace("NotifyThreadFn: Failed to get Global Heap Mutex.\n");
  2140. goto fail;
  2141. }
  2142. sc = ScInitNotify( pinst );
  2143. if (FAILED(sc))
  2144. {
  2145. GH_ReleaseMutex(pinst->hghShared);
  2146. DebugTrace("NotifyThreadFn: Failed to ScInitNotify.\n");
  2147. goto fail;
  2148. }
  2149. // Indicate success and unblock the spawning thread
  2150. GH_ReleaseMutex(pinst->hghShared);
  2151. pinst->scInitNotify = S_OK;
  2152. SetEvent(pinst->heventNotify);
  2153. // NOTE!! pinst cannot be used beyond this point.
  2154. // Run the message pump for notification.
  2155. //$ Note: this can easily be converted to waiting on an event
  2156. // or other cross-process synchronization mechanism.
  2157. while (GetMessage(&msg, NULL, 0, 0))
  2158. {
  2159. // TranslateMessage() is unnecessary since we never process
  2160. // the keyboard.
  2161. DispatchMessage(&msg);
  2162. }
  2163. // DeinitNotify() handles its own locking chores.
  2164. DeinitNotify();
  2165. if (SUCCEEDED(scCo))
  2166. CoUninitialize();
  2167. return 0L;
  2168. fail:
  2169. // Indicate failure and unblock the spawning thread
  2170. pinst->scInitNotify = sc;
  2171. SetEvent(pinst->heventNotify);
  2172. if (SUCCEEDED(scCo))
  2173. CoUninitialize();
  2174. DebugTraceSc(NotifyThreadFn, sc);
  2175. return (DWORD) sc;
  2176. }
  2177. #endif /* WIN32 && !MAC */
  2178. //---------------------------------------------------------------------------
  2179. // Name: IsValidTask()
  2180. // Description:
  2181. // Parameters:
  2182. // Returns:
  2183. // Effects:
  2184. // Notes:
  2185. // Revision:
  2186. //---------------------------------------------------------------------------
  2187. BOOL IsValidTask( HWND hwnd, LPINST pinst )
  2188. {
  2189. #ifdef NT
  2190. GHID ghidTask;
  2191. LPSTASK pstask;
  2192. if ( !ScFindTask( pinst, hwnd, pinst->hghShared, &ghidTask, NULL ) )
  2193. {
  2194. pstask = (LPSTASK)GH_GetPv( pinst->hghShared, ghidTask );
  2195. if ( pstask->uFlags & MAPI_TASK_SERVICE )
  2196. {
  2197. HANDLE hProc;
  2198. Assert( pstask->dwPID );
  2199. hProc = OpenProcess( PROCESS_ALL_ACCESS, 0, pstask->dwPID );
  2200. if ( hProc )
  2201. {
  2202. CloseHandle( hProc );
  2203. return TRUE ;
  2204. }
  2205. return FALSE ;
  2206. }
  2207. else if ( pstask->uFlags & MAPI_TASK_PENDING )
  2208. {
  2209. // Assert( hwnd == hwndNoSpooler );
  2210. return TRUE;
  2211. }
  2212. else
  2213. {
  2214. return IsWindow( hwnd );
  2215. }
  2216. }
  2217. else
  2218. {
  2219. return FALSE;
  2220. }
  2221. #else
  2222. return IsWindow( hwnd ) || hwnd == hwndNoSpooler;
  2223. #endif
  2224. }
  2225. SCODE
  2226. ScNewStask(HWND hwnd, LPSTR szTask, ULONG ulFlags, HGH hgh, LPSHDR pshdr)
  2227. {
  2228. SCODE sc = S_OK;
  2229. GHID ghidstask;
  2230. LPSTASK pstask;
  2231. if (!(ghidstask = GH_Alloc(hgh, sizeof(STASK))))
  2232. {
  2233. sc = MAPI_E_NOT_ENOUGH_MEMORY;
  2234. goto ret;
  2235. }
  2236. pstask = (LPSTASK)GH_GetPv(hgh, ghidstask);
  2237. ZeroMemory(pstask, sizeof(STASK));
  2238. pstask->hwndNotify = hwnd;
  2239. StrCpyNA(pstask->szModName, szTask, sizeof(pstask->szModName));
  2240. // Set task flags
  2241. if (ulFlags & MAPI_SPOOLER_INIT)
  2242. pstask->uFlags |= MAPI_TASK_SPOOLER;
  2243. if (hwnd == hwndNoSpooler)
  2244. pstask->uFlags |= MAPI_TASK_PENDING;
  2245. #ifdef _WINNT
  2246. if ( ulFlags & MAPI_NT_SERVICE )
  2247. {
  2248. pstask->uFlags |= MAPI_TASK_SERVICE;
  2249. pstask->dwPID = GetCurrentProcessId();
  2250. }
  2251. #endif
  2252. // Hook to task list
  2253. pstask->ghidTaskNext = pshdr->ghidTaskList;
  2254. pshdr->ghidTaskList = ghidstask;
  2255. ret:
  2256. DebugTraceSc(ScNewStask, sc);
  2257. return sc;
  2258. }
  2259. SCODE
  2260. ScNewStubReg(LPINST pinst, LPSHDR pshdr, HGH hgh)
  2261. {
  2262. SCODE sc;
  2263. ULONG ulCon;
  2264. LPSREG psreg;
  2265. if (pshdr->ulConnectStub != 0)
  2266. {
  2267. DebugTrace("ScNewStubReg: that was fast!\n");
  2268. return S_OK;
  2269. }
  2270. sc = ScSubscribe(pinst, hgh, pshdr, NULL,
  2271. (LPNOTIFKEY) &notifkeyOlaf, fnevSpooler, NULL, 0, &ulCon);
  2272. if (sc)
  2273. goto ret;
  2274. pshdr->ulConnectStub = ulCon;
  2275. psreg = (LPSREG) GH_GetPv(hgh, (GHID) ulCon);
  2276. psreg->hwnd = hwndNoSpooler;
  2277. ret:
  2278. DebugTraceSc(ScNewStubReg, sc);
  2279. return sc;
  2280. }
  2281. VOID
  2282. DeleteStubReg(LPINST pinst, LPSHDR pshdr, HGH hgh)
  2283. {
  2284. LPMAPIADVISESINK padvise;
  2285. GHID ghidReg;
  2286. LPSREG psreg;
  2287. ghidReg = (GHID) pshdr->ulConnectStub;
  2288. if (!ghidReg)
  2289. return;
  2290. psreg = (LPSREG)GH_GetPv(hgh, ghidReg);
  2291. if (!FValidReg(hgh, pshdr, ghidReg))
  2292. {
  2293. AssertSz(FALSE, "DeleteStubReg: bogus pshdr->ulConnectStub");
  2294. return;
  2295. }
  2296. DebugTrace("DeleteStubReg: removing stub spooler registration\n");
  2297. Unregister(pinst, psreg->ghidKey, ghidReg, &padvise);
  2298. pshdr->ulConnectStub = 0;
  2299. Assert(!padvise);
  2300. }