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.

1097 lines
38 KiB

  1. /*
  2. * NOTIFY.C
  3. *
  4. * WAB Notification Engine
  5. *
  6. * Copyright 1996 Microsoft Corporation. All Rights Reserved.
  7. *
  8. *
  9. * Notification in the WAB works as follows:
  10. * Client apps call Advise to register their interest in particular
  11. * notifications. The wab maintains a local list of the notifications
  12. * that the client has advised in the processes heap. The wab also
  13. * maintains a thread while there are any active advise sessions. This
  14. * thread waits on the global notification event.
  15. *
  16. * When a notification event happens (through HrFireNotification)
  17. * the event is written into a shared memory list and the global
  18. * notification event is triggered.
  19. *
  20. * The client thread (one in each process) wakes when this event is
  21. * triggered and compares the shared memory list of events against
  22. * it's local list of advises. If a match is found, the thread calls
  23. * the advise's OnNotify callback.
  24. *
  25. * There is a reference count in the global notification list's records
  26. * so that the record can be cleaned up when all processes have had
  27. * a chance to see it.
  28. *
  29. */
  30. #include "_apipch.h"
  31. #define ADVISE_TIMEOUT 60000 // milliseconds
  32. // #define NEW_STUFF
  33. #ifdef NEW_STUFF
  34. #define NOTIFY_CREATE_TIMEOUT 60000 // milliseconds
  35. #define FIRE_NOTIFY_TIMEOUT 10000 // milliseconds
  36. #define ADVISE_THREAD_TIMEOUT ((ULONG)-1) // Forever
  37. #define NOTIFY_ADVISE_TIMEOUT 60000 // milliseconds
  38. // Per-process globals
  39. // 0 1 2
  40. // 012345678901234567890123
  41. const TCHAR szNotificationName[] = "_MICROSOFT_WAB_NOTIFY_";
  42. const TCHAR szMEM[] = "MEM"; // suffix for shared memory
  43. const TCHAR szEVT[] = "EVT"; // suffix for event
  44. const TCHAR szMTX[] = "MTX"; // suffix for mutex
  45. LPNOTIFICATION_LIST lpNotificationList = NULL;
  46. HANDLE hmemNotificationList = NULL;
  47. HANDLE hevNotificationList = NULL;
  48. HANDLE hmtxNotificationList = NULL;
  49. HANDLE hevNotificationUI = NULL;
  50. HANDLE hmtxAdviseList = NULL;
  51. ADVISE_LIST AdviseList = {0, NULL};
  52. HANDLE hevKillAdvise = NULL;
  53. ULONG ulMaxIdentifierSeen = 0;
  54. // Forward declarations
  55. DWORD AdviseThread(LPDWORD lpdwParam);
  56. /***************************************************************************
  57. Name : WaitForTwoObjects
  58. Purpose : Wait for one of two objects to be signalled
  59. Parameters: handle0 = first object handle
  60. handle1 = second object handle
  61. dwTimeout = timeout in milliseconds
  62. Returns : index of object or -1 on error (0, 1 or -1)
  63. Comment :
  64. ***************************************************************************/
  65. ULONG WaitForTwoObjects(HANDLE handle0, HANDLE handle1, DWORD dwTimeout) {
  66. HANDLE rgHandles[2] = {handle0, handle1};
  67. switch (WaitForMultipleObjects(2, rgHandles, FALSE, dwTimeout)) {
  68. case WAIT_ABANDONED_0:
  69. DebugTrace("WaitFoMultipleObjects got WAIT_ABANDONED_0\n");
  70. case WAIT_OBJECT_0:
  71. return(0);
  72. case WAIT_ABANDONED_0 + 1:
  73. DebugTrace("WaitFoMultipleObjects got WAIT_ABANDONED_1\n");
  74. case WAIT_OBJECT_0 + 1:
  75. return(1);
  76. case WAIT_FAILED:
  77. default:
  78. DebugTrace("WaitForMultipleObjects got WAIT_FAILED: %u\n", GetLastError());
  79. case WAIT_TIMEOUT:
  80. return((ULONG)-1);
  81. }
  82. }
  83. /***************************************************************************
  84. Name : CompareEntryIDs
  85. Purpose : Are the two entryID's the same?
  86. Parameters: cbEntryID1 = sizeof lpEntryID1
  87. lpEntryID1 = first EntryID
  88. cbEntryID2 = sizeof lpEntryID2
  89. lpEntryID2 = second EntryID
  90. Returns : TRUE if the entry IDs are the same
  91. Comment :
  92. ***************************************************************************/
  93. BOOL CompareEntryIDs(ULONG cbEntryID1,
  94. LPENTRYID lpEntryID1,
  95. ULONG cbEntryID2,
  96. LPENTRYID lpEntryID2)
  97. {
  98. BOOL fReturn = FALSE;
  99. if (cbEntryID1 == cbEntryID2) {
  100. if (cbEntryID1 && 0 == memcmp((LPVOID)lpEntryID1, (LPVOID)lpEntryID2,
  101. (size_t)cbEntryID1)) {
  102. fReturn = TRUE;
  103. }
  104. }
  105. return(fReturn);
  106. }
  107. /***************************************************************************
  108. Name : CreateNotifySession
  109. Purpose : Create/Open the notification lists and thread.
  110. Parameters: lpfExisted -> returned flag TRUE if the session
  111. was already setup for this process.
  112. Returns : HRESULT
  113. Comment : Fills in these globals:
  114. hmtxNotificationList
  115. hevNotificationList
  116. hmemNotificationList
  117. lpNotificationList
  118. ***************************************************************************/
  119. HRESULT CreateNotifySession(LPBOOL lpfExisted) {
  120. HRESULT hResult = hrSuccess;
  121. BOOL fMutex = FALSE;
  122. DWORD dwThreadId;
  123. DWORD dwThreadParam = 0;
  124. HANDLE hthrdAdvise = NULL;
  125. TCHAR szName[CharSizeOf(szNotificationName) + CharSizeOf(szMEM)];
  126. Assert(CharSizeOf(szMEM) == CharSizeOf(szEVT) && CharSizeOf(szEVT) == CharSizeOf(szMTX));
  127. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  128. StrCatBuff(szName, szMTX, ARRAYSIZE(szName));
  129. if (! (hmtxNotificationList = CreateMutex(NULL,
  130. FALSE,
  131. szName))) {
  132. DebugTrace("CreateNotifySession:CreateMutex(%s) -> %u\n", szName, GetLastError());
  133. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  134. goto exit;
  135. }
  136. if (hResult = HrWaitForObject(hmtxNotificationList, NOTIFY_CREATE_TIMEOUT)) {
  137. DebugTrace("CreateNotifySession:Mutex wait failed\n");
  138. goto exit;
  139. }
  140. fMutex = TRUE;
  141. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  142. StrCatBuff(szName, szMEM, ARRAYSIZE(szName));
  143. if ((hmemNotificationList = CreateFileMapping(INVALID_HANDLE_VALUE, // handle
  144. NULL, // security descriptor
  145. PAGE_READWRITE, // reserve more
  146. 0, // max size high
  147. MAX_NOTIFICATION_SPACE, // max size low
  148. szName)) == NULL) { // name
  149. DebugTrace("CreateNotifySession: CreateFileMapping(%s) --> %u\n",
  150. szName, GetLastError());
  151. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  152. goto exit;
  153. }
  154. *lpfExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
  155. if ((lpNotificationList = (LPNOTIFICATION_LIST)MapViewOfFile(hmemNotificationList,
  156. FILE_MAP_WRITE | FILE_MAP_READ,
  157. 0,
  158. 0,
  159. sizeof(NOTIFICATION_LIST))) == NULL) {
  160. DebugTrace("CreateNotifySession: CreateFileMapping --> %u\n",
  161. GetLastError());
  162. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  163. goto exit;
  164. }
  165. if (! *lpfExisted) {
  166. // Initialize global notification list
  167. lpNotificationList->cAdvises = 0; // Number of advise processes
  168. lpNotificationList->cEntries = 0; // Number of entries in the list
  169. lpNotificationList->lpNode = NULL; // First node in list or NULL if empty
  170. lpNotificationList->ulNextIdentifier = 1; // next value for a notification identifier
  171. }
  172. lpNotificationList->cAdvises++; // Number of advise processes
  173. // Notification Event
  174. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  175. StrCatBUff(szName, szEVT, ARRAYSIZE(szName));
  176. if (! (hevNotificationList = CreateEvent(NULL,
  177. TRUE, // Manual reset
  178. FALSE, // initial state (not triggered)
  179. szName))) {
  180. DebugTrace("CreateNotifySession:CreateEvent(%S) -> %u\n", szName, GetLastError());
  181. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  182. goto exit;
  183. }
  184. // Advise Kill Event
  185. if (! (hevKillAdvise = CreateEvent(NULL,
  186. TRUE, // Manual reset
  187. FALSE, // initial state (not triggered)
  188. NULL))) {
  189. DebugTrace("CreateNotifySession:CreateEvent(Kill Advise) -> %u\n", GetLastError());
  190. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  191. goto exit;
  192. }
  193. // Create the Local AdviseList
  194. if (! (hmtxAdviseList = CreateMutex(NULL,
  195. FALSE, // Not initially owned
  196. NULL))) { // no name
  197. DebugTrace("CreateNotifySession:CreateMutex(Advise List) -> %u\n", GetLastError());
  198. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  199. goto exit;
  200. }
  201. // Local AdviseList should be empty
  202. Assert(AdviseList.cAdvises == 0);
  203. Assert(AdviseList.lpNode == NULL);
  204. // Create the Advise thread for this process
  205. if (! (hthrdAdvise = CreateThread(NULL, // no security attributes
  206. 0, // default stack size: BUGBUG: Should be smaller
  207. (LPTHREAD_START_ROUTINE)AdviseThread, // thread function
  208. &dwThreadParam, // argument to thread
  209. 0, // flags
  210. &dwThreadId))) {
  211. DebugTrace("CreateNotifySession:CreateThread -> %u\n", GetLastError());
  212. // propbably out of memory?
  213. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  214. goto exit;
  215. }
  216. exit:
  217. if (fMutex) {
  218. ReleaseMutex(hmtxNotificationList);
  219. }
  220. if (hthrdAdvise) {
  221. CloseHandle(hthrdAdvise);
  222. }
  223. if (hResult) {
  224. // Failure, clean up
  225. if (lpNotificationList) {
  226. UnmapViewOfFile(lpNotificationList);
  227. lpNotificationList = NULL;
  228. }
  229. if (hmemNotificationList) {
  230. CloseHandle(hmemNotificationList);
  231. hmemNotificationList = NULL;
  232. }
  233. if (hmtxNotificationList) {
  234. CloseHandle(hmtxNotificationList);
  235. hmtxNotificationList = NULL;
  236. }
  237. if (hevNotificationList) {
  238. CloseHandle(hevNotificationList);
  239. hevNotificationList = NULL;
  240. }
  241. if (hevKillAdvise) {
  242. CloseHandle(hevKillAdvise);
  243. hevKillAdvise = NULL;
  244. }
  245. }
  246. return(hResult);
  247. }
  248. /***************************************************************************
  249. Name : OpenNotifySession
  250. Purpose : Open the global notification list, if it exists.
  251. Parameters: lppNotificationList -> returned notification list
  252. lphmemNotificationList -> returned shared memory handle
  253. lphmtxNotificationList -> returned Mutex handle
  254. lphevNotificationList -> returned event handle
  255. Returns : HRESULT
  256. Comment : This function does not effect the globals!
  257. ***************************************************************************/
  258. HRESULT OpenNotifySession(LPNOTIFICATION_LIST * lppNotificationList,
  259. LPHANDLE lphmemNotificationList,
  260. LPHANDLE lphmtxNotificationList,
  261. LPHANDLE lphevNotificationList) {
  262. HRESULT hResult = hrSuccess;
  263. BOOL fMutex = FALSE;
  264. TCHAR szName[CharSizeOf(szNotificationName) + CharSizeOf(szMEM)];
  265. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  266. StrCatBuff(szName, szMTX, ARRAYSIZE(szName));
  267. if (! (*lphmtxNotificationList = OpenMutex(SYNCHRONIZE,
  268. FALSE, // inherit handle?
  269. szName))) {
  270. DebugTrace("OpenNotifySession:OpenMutex(%s) -> %u\n", szName, GetLastError());
  271. // No Advise sessions exist, don't bother with this.
  272. hResult = ResultFromScode(WAB_W_NO_ADVISE);
  273. goto exit;
  274. }
  275. if (hResult = HrWaitForObject(*lphmtxNotificationList, NOTIFY_CREATE_TIMEOUT)) {
  276. DebugTrace("CreateNotifySession:Mutex wait failed\n");
  277. goto exit;
  278. }
  279. fMutex = TRUE;
  280. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  281. StrCatBuff(szName, szMEM, ARRAYSIZE(szName));
  282. if ((*lphmemNotificationList = CreateFileMapping(INVALID_HANDLE_VALUE, // handle
  283. NULL, // security descriptor
  284. PAGE_READWRITE | SEC_RESERVE, // reserve more
  285. 0, // max size high
  286. MAX_NOTIFICATION_SPACE, // max size low
  287. szName)) == NULL) { // name
  288. DebugTrace("CreateNotifySession: CreateFileMapping --> %u\n",
  289. GetLastError());
  290. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  291. goto exit;
  292. }
  293. if ((*lppNotificationList = (LPNOTIFICATION_LIST)MapViewOfFile(*lphmemNotificationList,
  294. FILE_MAP_WRITE | FILE_MAP_READ,
  295. 0,
  296. 0,
  297. sizeof(NOTIFICATION_LIST))) == NULL) {
  298. DebugTrace("CreateNotifySession: CreateFileMapping --> %u\n",
  299. GetLastError());
  300. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  301. goto exit;
  302. }
  303. // Initialize global notification list
  304. Assert((*lppNotificationList)->cAdvises != 0); // Number of advise processes
  305. // Notification Event
  306. StrCpyN(szName, szNotificationName, ARRAYSIZE(szName));
  307. StrCatBuff(szName, szEVT, ARRAYSIZE(szName));
  308. if (! (*lphevNotificationList = CreateEvent(NULL,
  309. TRUE, // Manual reset
  310. FALSE, // initial state (not triggered)
  311. szName))) {
  312. DebugTrace("OpenNotifySession:CreateEvent(%S) -> %u\n", szName, GetLastError());
  313. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  314. goto exit;
  315. }
  316. exit:
  317. if (fMutex) {
  318. ReleaseMutex(*lphmtxNotificationList);
  319. }
  320. if (hResult) {
  321. // Failure, clean up
  322. if (*lphmemNotificationList) {
  323. CloseHandle(*lphmemNotificationList);
  324. *lphmemNotificationList = NULL;
  325. }
  326. if (*lphmtxNotificationList) {
  327. CloseHandle(*lphmtxNotificationList);
  328. *lphmtxNotificationList = NULL;
  329. }
  330. if (*lphevNotificationList) {
  331. CloseHandle(*lphevNotificationList);
  332. *lphevNotificationList = NULL;
  333. }
  334. }
  335. return(hResult);
  336. }
  337. #endif // NEW_STUFF
  338. /***************************************************************************
  339. Name : HrWaitForObject
  340. Purpose : Wait for an object to be signalled
  341. Parameters: handle = object handle
  342. dwTimeout = timeout in milliseconds
  343. Returns : HRESULT
  344. Comment :
  345. ***************************************************************************/
  346. HRESULT HrWaitForObject(HANDLE handle, DWORD dwTimeout) {
  347. switch (WaitForSingleObject(handle, dwTimeout)) {
  348. case WAIT_ABANDONED:
  349. DebugTrace(TEXT("WARNING:HrWaitForObject got WAIT_ABANDONED\n"));
  350. // fall through to success
  351. case WAIT_OBJECT_0:
  352. return(hrSuccess);
  353. case WAIT_TIMEOUT:
  354. DebugTrace(TEXT("HrWaitForObject timed out\n"));
  355. return(ResultFromScode(MAPI_E_TIMEOUT));
  356. case WAIT_FAILED:
  357. default:
  358. DebugTrace(TEXT("HrWaitForObject failed -> %u\n"), GetLastError());
  359. return(ResultFromScode(MAPI_E_CALL_FAILED));
  360. }
  361. }
  362. /***************************************************************************
  363. Name : HrWABNotify
  364. Purpose : Scans registered clients and Notifies them of a store modification
  365. The first-cut at notifications is extremely simplistic. Any time
  366. the WAB store changes, we fire off a store notification. No attempt
  367. to check eventmasks or entryids etc
  368. Parameters: lpIAB = THIS object
  369. Returns : HRESULT
  370. Comment : What happens in here:
  371. ***************************************************************************/
  372. HRESULT HrWABNotify(LPIAB lpIAB)
  373. {
  374. HRESULT hResult = hrSuccess;
  375. LPADVISE_NODE lpAdviseNode = NULL;
  376. NOTIFICATION WABNotif = {0};
  377. EnterCriticalSection(&lpIAB->cs);
  378. if (!lpIAB->pWABAdviseList ||
  379. !lpIAB->pWABAdviseList->cAdvises)
  380. {
  381. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  382. goto exit;
  383. }
  384. // Since calling applications may have no idea of container/folder changes, but may
  385. // call container based methods ..
  386. // update the list of WAB containers for that applicaiton so that GetContentsTable etc
  387. // will work correctly ..
  388. if(bAreWABAPIProfileAware(lpIAB))
  389. HrGetWABProfiles(lpIAB);
  390. WABNotif.ulEventType = fnevObjectModified;
  391. WABNotif.info.obj.ulObjType = MAPI_ADDRBOOK;
  392. WABNotif.info.obj.cbEntryID = WABNotif.info.obj.cbParentID =
  393. WABNotif.info.obj.cbOldID = WABNotif.info.obj.cbOldParentID = 0;
  394. WABNotif.info.obj.lpEntryID = WABNotif.info.obj.lpParentID =
  395. WABNotif.info.obj.lpOldID = WABNotif.info.obj.lpOldParentID = NULL;
  396. WABNotif.info.obj.lpPropTagArray = NULL;
  397. lpAdviseNode = lpIAB->pWABAdviseList->lpNode;
  398. while(lpAdviseNode)
  399. {
  400. lpAdviseNode->lpAdviseSink->lpVtbl->OnNotify(lpAdviseNode->lpAdviseSink,
  401. 1,
  402. &WABNotif);
  403. lpAdviseNode = lpAdviseNode->lpNext;
  404. }
  405. exit:
  406. LeaveCriticalSection(&lpIAB->cs);
  407. return(hResult);
  408. }
  409. /***************************************************************************
  410. Name : HrAdvise
  411. Purpose : Performs client notification registration
  412. Parameters: lpIAB = THIS object
  413. cbEntryID = sizeof lpEntryID
  414. lpEntryID -> EntryID of object about which notifications
  415. should be generated.
  416. ulEventMask = events about which to generate notifications
  417. fnevObjectCreated
  418. fnevObjectDeleted
  419. fnevObjectModified
  420. fnevTableModified
  421. NOTE: WAB currently does not support fnevCriticalError,
  422. fnevObjectCopied or fnevObjectMoved.
  423. lpAdviseSink -> Client's advise sink object
  424. lpulConnection -> returned connection number (client should
  425. save to pass to Unadvise.)
  426. Returns : HRESULT
  427. Comment : What happens in here:
  428. Store the EventMask and AdviseSink in the local advise list.
  429. If there are no other Advise sessions open in this process:
  430. Make sure there is one and register it
  431. ***************************************************************************/
  432. HRESULT HrAdvise(LPIAB lpIAB,
  433. ULONG cbEntryID,
  434. LPENTRYID lpEntryID,
  435. ULONG ulEventMask,
  436. LPMAPIADVISESINK lpAdvise,
  437. ULONG FAR * lpulConnection)
  438. {
  439. HRESULT hResult = hrSuccess;
  440. BOOL fExisted = FALSE;
  441. LPADVISE_NODE lpAdviseNode = NULL, lpTemp = NULL;
  442. static ULONG ulNextConnection = 1;
  443. EnterCriticalSection(&lpIAB->cs);
  444. if(!lpIAB->pWABAdviseList)
  445. {
  446. lpIAB->pWABAdviseList = LocalAlloc(LMEM_ZEROINIT, sizeof(ADVISE_LIST));
  447. if(!lpIAB->pWABAdviseList)
  448. {
  449. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  450. goto exit;
  451. }
  452. lpIAB->pWABAdviseList->cAdvises = 0;
  453. lpIAB->pWABAdviseList->lpNode = NULL;
  454. }
  455. lpAdviseNode = LocalAlloc(LMEM_ZEROINIT, sizeof(ADVISE_NODE) + cbEntryID);
  456. if(!lpAdviseNode)
  457. {
  458. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  459. goto exit;
  460. }
  461. lpAdviseNode->ulConnection = ulNextConnection++;
  462. lpAdviseNode->ulEventMask = ulEventMask;
  463. lpAdviseNode->lpAdviseSink = lpAdvise;
  464. if(cbEntryID && lpEntryID)
  465. {
  466. CopyMemory(&lpAdviseNode->EntryID, lpEntryID, cbEntryID);
  467. }
  468. lpAdviseNode->lpPrev = NULL;
  469. lpAdviseNode->lpNext = lpIAB->pWABAdviseList->lpNode;
  470. if(lpIAB->pWABAdviseList->lpNode)
  471. lpIAB->pWABAdviseList->lpNode->lpPrev = lpAdviseNode;
  472. lpIAB->pWABAdviseList->lpNode = lpAdviseNode;
  473. lpIAB->pWABAdviseList->cAdvises++;
  474. // Addref the LPADVISESINK pointer so we have a handle on it ...
  475. //
  476. lpAdvise->lpVtbl->AddRef(lpAdvise);
  477. *lpulConnection = lpAdviseNode->ulConnection;
  478. exit:
  479. LeaveCriticalSection(&lpIAB->cs);
  480. return(hResult);
  481. #ifdef NEW_STUFF
  482. /*
  483. // Walk the advise list looking for the connection
  484. // Make sure we're safe to monkey with the list
  485. if (hResult = HrWaitForObject(hmtxAdviseList, ADVISE_TIMEOUT))
  486. {
  487. DebugTrace("HrUnadvise:Mutex wait failed\n");
  488. goto exit;
  489. }
  490. fMutex = TRUE;
  491. // Is there an open Advise session for this process?
  492. // If not, set up the advise session for this process.
  493. if (! lpNotificationList) {
  494. if (hResult = CreateNotifySession(&fExisted)) {
  495. DebugTraceResult( TEXT("HrAdvise:CreateNotifySession"), hResult);
  496. goto exit;
  497. }
  498. }
  499. // Add Advise info to Local Advise List.
  500. // Create the new node
  501. if (! (lpAdviseNode = LocalAlloc(LPTR, sizeof(ADVISE_NODE) + cbEntryID))) {
  502. DebugTrace("LocalAlloc(%u) AdviseNode -> %u\n", sizeof(ADVISE_NODE) + cbEntryID, GetLastError());
  503. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  504. goto exit;
  505. }
  506. lpAdviseNode->ulConnection = ulNextConnection++;
  507. lpAdviseNode->lpAdviseSink = lpAdvise;
  508. lpAdviseNode->ulEventMask = ulEventMask;
  509. lpAdviseNode->cbEntryID = cbEntryID;
  510. CopyMemory(&lpAdviseNode->EntryID, lpEntryID, cbEntryID);
  511. // Add the new node to front of the list
  512. // Make sure we're safe to monkey with the list
  513. if (hResult = HrWaitForObject(hmtxAdviseList, ADVISE_TIMEOUT)) {
  514. DebugTrace("HrAdvise:Mutex wait failed\n");
  515. goto exit;
  516. }
  517. fMutex = TRUE;
  518. lpAdviseNode->lpNext = AdviseList.lpNode;
  519. AdviseList.lpNode = lpAdviseNode;
  520. AdviseList.cAdvises++;
  521. *lpulConnection = lpAdviseNode->ulConnection;
  522. exit:
  523. if (fMutex) {
  524. ReleaseMutex(hmtxAdviseList);
  525. }
  526. #else
  527. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  528. */
  529. #endif
  530. }
  531. /***************************************************************************
  532. Name : HrUnadvise
  533. Purpose : Removes an Advise from the list
  534. Parameters: ulConnection = connection number to remove
  535. Returns : HRESULT
  536. Comment :
  537. ***************************************************************************/
  538. HRESULT HrUnadvise(LPIAB lpIAB, ULONG ulConnection) {
  539. HRESULT hResult = hrSuccess;
  540. BOOL fMutex = FALSE;
  541. LPADVISE_NODE lpAdviseNode = NULL;
  542. EnterCriticalSection(&lpIAB->cs);
  543. if (!lpIAB->pWABAdviseList ||
  544. !lpIAB->pWABAdviseList->cAdvises)
  545. {
  546. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  547. goto exit;
  548. }
  549. lpAdviseNode = lpIAB->pWABAdviseList->lpNode;
  550. while (lpAdviseNode)
  551. {
  552. if (lpAdviseNode->ulConnection == ulConnection)
  553. {
  554. if(lpIAB->pWABAdviseList->lpNode == lpAdviseNode)
  555. lpIAB->pWABAdviseList->lpNode = lpAdviseNode->lpNext;
  556. if(lpAdviseNode->lpPrev)
  557. lpAdviseNode->lpPrev->lpNext = lpAdviseNode->lpNext;
  558. if(lpAdviseNode->lpNext)
  559. lpAdviseNode->lpNext->lpPrev = lpAdviseNode->lpPrev;
  560. // Release the hold on this pointer ...
  561. lpAdviseNode->lpAdviseSink->lpVtbl->Release(lpAdviseNode->lpAdviseSink);
  562. LocalFreeAndNull(&lpAdviseNode);
  563. lpIAB->pWABAdviseList->cAdvises--;
  564. //Assert(lpIAB->pWABAdviseList->cAdvises == 0 && lpIAB->pWABAdviseList->lpNode == NULL);
  565. if(!lpIAB->pWABAdviseList->cAdvises && !lpIAB->pWABAdviseList->lpNode)
  566. {
  567. LocalFree(lpIAB->pWABAdviseList);
  568. lpIAB->pWABAdviseList = NULL;
  569. }
  570. goto exit;
  571. }
  572. lpAdviseNode = lpAdviseNode->lpNext;
  573. }
  574. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  575. exit:
  576. LeaveCriticalSection(&lpIAB->cs);
  577. return(hResult);
  578. /*
  579. #ifdef NEW_STUFF
  580. BOOL fMutex = FALSE;
  581. LPADVISE_NODE lpAdviseNode = NULL;
  582. LPADVISE_NODE * lppPrevNode = &(AdviseList.lpNode);
  583. if (hmtxAdviseList == NULL || AdviseList.cAdvises == 0) {
  584. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  585. goto exit;
  586. }
  587. // Walk the advise list looking for the connection
  588. // Make sure we're safe to monkey with the list
  589. if (hResult = HrWaitForObject(hmtxAdviseList, ADVISE_TIMEOUT)) {
  590. DebugTrace("HrUnadvise:Mutex wait failed\n");
  591. goto exit;
  592. }
  593. fMutex = TRUE;
  594. lpAdviseNode = AdviseList.lpNode;
  595. while (lpAdviseNode) {
  596. if (lpAdviseNode->ulConnection == ulConnection) {
  597. // Found it, remove from list
  598. *lppPrevNode = lpAdviseNode->lpNext;
  599. // BUGBUG: Don't forget to remove any notifications that haven't been
  600. // processed by this process yet.
  601. // Free the node
  602. LocalFreeAndNull(&lpAdviseNode);
  603. goto exit;
  604. }
  605. lppPrevNode = &(lpAdviseNode->lpNext);
  606. lpAdviseNode = lpAdviseNode->lpNext;
  607. }
  608. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  609. exit:
  610. if (fMutex) {
  611. ReleaseMutex(hmtxAdviseList);
  612. }
  613. #else
  614. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  615. #endif
  616. return(hResult);
  617. */
  618. }
  619. /***************************************************************************
  620. Name : HrFireNotification
  621. Purpose : Fire a notification
  622. Parameters: lpNotification -> NOTIFICATION structure
  623. Returns : HRESULT
  624. Comment : What happens in here:
  625. if shared memory exists
  626. Map in the shared memory
  627. Add the notification to the global Advise list
  628. Set the count on this notification to the global
  629. advise count.
  630. trigger the Global Advise Event.
  631. ***************************************************************************/
  632. HRESULT HrFireNotification(LPNOTIFICATION lpNotification) {
  633. HRESULT hResult = hrSuccess;
  634. #ifdef NEW_STUFF
  635. LPNOTIFICATION_LIST lpNotifyList = NULL;
  636. HANDLE hmemNotifyList = NULL;
  637. HANDLE hmtxNotifyList = NULL;
  638. HANDLE hevNotifyList = NULL;
  639. LPNOTIFICATION_NODE lpNewNode = NULL, lpTempNode, *lppPrevNode;
  640. BOOL fNotifyMutex = FALSE, fAdviseMutex = FALSE;
  641. BOOL fOpened = FALSE;
  642. Assert(lpNotification);
  643. // If there is an Advise session, use it, else create a temporary
  644. // Notification session
  645. if (lpNotificationList) {
  646. lpNotifyList = lpNotificationList;
  647. hmtxNotifyList = hmtxNotificationList;
  648. hevNotifyList = hevNotificationList;
  649. } else {
  650. if (hResult = OpenNotifySession(&lpNotifyList,
  651. &hmemNotifyList,
  652. &hmtxNotifyList,
  653. &hevNotifyList)) {
  654. DebugTraceResult( TEXT("HrAdvise:OpenNotifySession"), hResult);
  655. // No waiting advise sessions, there's no point in continuing
  656. goto exit;
  657. }
  658. fOpened = TRUE;
  659. }
  660. // Request access to the Global Notification List
  661. if (hResult = HrWaitForObject(hmtxNotifyList, FIRE_NOTIFY_TIMEOUT)) {
  662. DebugTrace("HrFireNotification:Mutex wait failed\n");
  663. goto exit;
  664. }
  665. fNotifyMutex = TRUE;
  666. // Add the notification to the beginning of the global notification list
  667. // create a new node for it
  668. if (! (lpNewNode = LocalAlloc(LPTR, sizeof(NOTIFICATION_NODE)))) {
  669. DebugTrace("LocalAlloc(%u) NotificationNode -> %u\n", sizeof(NOTIFICATION_NODE), GetLastError());
  670. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  671. goto exit;
  672. }
  673. lpNewNode->cbSize = sizeof(NOTIFICATION_NODE);
  674. // BUGBUG: This doesn't copy the stuff pointed to in the notification structure!
  675. CopyMemory(&lpNewNode->Notification, lpNotification, sizeof(NOTIFICATION));
  676. // Add the new node to END of the list. Note that it must go to the end
  677. // of the list so that the unique identifiers are kept in order.
  678. // Make sure we're safe to monkey with the Advise list
  679. if (hResult = HrWaitForObject(hmtxAdviseList, ADVISE_TIMEOUT)) {
  680. DebugTrace("HrAdvise:Mutex wait failed\n");
  681. goto exit;
  682. }
  683. fAdviseMutex = TRUE;
  684. lpNewNode->lpNext = NULL;
  685. lpTempNode = lpNotifyList->lpNode;
  686. lppPrevNode = &lpNotifyList->lpNode;
  687. while (lpTempNode) {
  688. lppPrevNode = &lpTempNode->lpNext;
  689. lpTempNode = lpTempNode->lpNext;
  690. }
  691. *lppPrevNode = lpNewNode;
  692. // Set the count on this notification to the global
  693. // advise count.
  694. lpNewNode->ulCount = lpNotificationList->cAdvises;
  695. // Set the unique identifier for this notification
  696. lpNewNode->ulIdentifier = lpNotifyList->ulNextIdentifier++;
  697. // trigger the Global Advise Event.
  698. if (! PulseEvent(hevNotifyList)) {
  699. DebugTrace("HrFireNotification:PulseEvent -> %u\n", GetLastError());
  700. // what are ya gonna do?
  701. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  702. goto exit;
  703. }
  704. exit:
  705. if (fNotifyMutex) {
  706. ReleaseMutex(hmtxNotifyList);
  707. }
  708. if (fAdviseMutex) {
  709. ReleaseMutex(hmtxAdviseList);
  710. }
  711. // Clean up the stuff if we opened it.
  712. if (fOpened) {
  713. if (lpNotifyList) {
  714. UnmapViewOfFile(lpNotifyList);
  715. }
  716. if (hmemNotifyList) {
  717. CloseHandle(hmemNotifyList);
  718. }
  719. if (hmtxNotifyList) {
  720. CloseHandle(hmtxNotifyList);
  721. }
  722. if (hevNotifyList) {
  723. CloseHandle(hevNotifyList);
  724. }
  725. }
  726. #else
  727. hResult = ResultFromScode(MAPI_E_CALL_FAILED);
  728. #endif
  729. return(hResult);
  730. }
  731. #ifdef NEW_STUFF
  732. /***************************************************************************
  733. Name : AdviseThread
  734. Purpose : Thread routine for advise
  735. Parameters: lpdwParam = Thread parameter
  736. Returns : DWORD return code.
  737. Comment : What happens in here:
  738. loop until Unadvise
  739. wait for trigger of the Global Advise Event or Unadvise event
  740. if Advise Event
  741. Loop through global advise list
  742. if we haven't already dealt with this notification
  743. check events in global advise list against local advise list
  744. if match
  745. call client's NotifCallback
  746. Decrement count in this notification
  747. if count == 0
  748. remove this item from the global advise list
  749. if Unadvise
  750. decrement global advise count
  751. exit thread
  752. ***************************************************************************/
  753. DWORD AdviseThread(LPDWORD lpdwParam) {
  754. BOOL fNotifyMutex = FALSE, fAdviseMutex = FALSE;
  755. LPNOTIFICATION_NODE lpNotifyNode = NULL, *lppNotifyPrev;
  756. LPADVISE_NODE lpAdviseNode = NULL;
  757. // loop until Unadvise
  758. while (TRUE) {
  759. // wait for trigger of the Global Advise Event or Unadvise event
  760. switch(WaitForTwoObjects(hevNotificationList, hevKillAdvise, ADVISE_THREAD_TIMEOUT)) {
  761. case 0:
  762. // New notification
  763. break;
  764. case (ULONG)-1:
  765. // error
  766. DebugTrace("AdviseThread:WaitForTwoObjects error\n");
  767. // fall through to kill
  768. case 1:
  769. // kill advise
  770. DebugTrace("Terminating AdviseThread\n");
  771. goto exit;
  772. }
  773. // New notification
  774. // Loop through global notification list
  775. // Gain access to list
  776. // wait for trigger of the Global Advise Event or Unadvise event
  777. switch(WaitForTwoObjects(hmtxNotificationList, hevKillAdvise, NOTIFY_ADVISE_TIMEOUT)) {
  778. case 0:
  779. // Got the List Mutex
  780. fNotifyMutex = TRUE;
  781. break;
  782. case (ULONG)-1:
  783. // error
  784. DebugTrace("AdviseThread:WaitForTwoObjects error\n");
  785. // fall through to kill
  786. case 1:
  787. // kill advise
  788. DebugTrace("Terminating AdviseThread\n");
  789. goto exit;
  790. }
  791. Assert(fNotifyMutex);
  792. // Also need to look at the local advise list
  793. switch(WaitForTwoObjects(hmtxAdviseList, hevKillAdvise, NOTIFY_ADVISE_TIMEOUT)) {
  794. case 0:
  795. // Got the List Mutex
  796. fAdviseMutex = TRUE;
  797. break;
  798. case (ULONG)-1:
  799. // error
  800. DebugTrace("AdviseThread:WaitForTwoObjects error\n");
  801. // fall through to kill
  802. case 1:
  803. // kill advise
  804. DebugTrace("Terminating AdviseThread\n");
  805. goto exit;
  806. }
  807. Assert(fAdviseMutex);
  808. lpNotifyNode = lpNotificationList->lpNode;
  809. lppNotifyPrev = &(lpNotificationList->lpNode);
  810. while (lpNotifyNode) {
  811. // if we haven't already dealt with this notification
  812. if (lpNotifyNode->ulIdentifier > ulMaxIdentifierSeen) {
  813. // We haven't seen this one yet. Process it.
  814. // NOTE: For this to work, new notification nodes must be added
  815. // at the END of the notification list!
  816. ulMaxIdentifierSeen = lpNotifyNode->ulIdentifier;
  817. // check this notification event against local advise list
  818. lpAdviseNode = AdviseList.lpNode;
  819. while (lpAdviseNode) {
  820. if (lpNotifyNode->Notification.ulEventType & lpAdviseNode->ulEventMask) {
  821. // Right event type, is it the right object?
  822. switch (lpNotifyNode->Notification.ulEventType) {
  823. case fnevCriticalError:
  824. // ERROR_NOTIFICATION
  825. if (CompareEntryIDs(lpAdviseNode->cbEntryID,
  826. (LPENTRYID)&lpAdviseNode->EntryID,
  827. lpNotifyNode->Notification.info.err.cbEntryID,
  828. lpNotifyNode->Notification.info.err.lpEntryID)) {
  829. // This is it!
  830. // Call the notification callback
  831. lpAdviseNode->lpAdviseSink->lpVtbl->OnNotify(lpAdviseNode->lpAdviseSink,
  832. 1,
  833. &lpNotifyNode->Notification);
  834. }
  835. break;
  836. case fnevObjectCreated:
  837. case fnevObjectDeleted:
  838. case fnevObjectModified:
  839. case fnevObjectCopied:
  840. case fnevObjectMoved:
  841. case fnevSearchComplete:
  842. // OBJECT_NOTIFICATION
  843. if (CompareEntryIDs(lpAdviseNode->cbEntryID,
  844. (LPENTRYID)&lpAdviseNode->EntryID,
  845. lpNotifyNode->Notification.info.obj.cbEntryID,
  846. lpNotifyNode->Notification.info.obj.lpEntryID)) {
  847. // This is it!
  848. // Call the notification callback
  849. lpAdviseNode->lpAdviseSink->lpVtbl->OnNotify(lpAdviseNode->lpAdviseSink,
  850. 1,
  851. &lpNotifyNode->Notification);
  852. }
  853. break;
  854. case fnevTableModified:
  855. // TABLE_NOTIFICATION
  856. // BUGBUG: NYI
  857. break;
  858. default:
  859. break;
  860. }
  861. }
  862. lpAdviseNode = lpAdviseNode->lpNext;
  863. }
  864. // Decrement count in this notification
  865. // if count == 0
  866. // remove this item from the global notification list
  867. if (--lpNotifyNode->ulCount == 0) {
  868. *lppNotifyPrev = lpNotifyNode->lpNext;
  869. LocalFree(lpNotifyNode);
  870. lpNotifyNode = *lppNotifyPrev;
  871. } else {
  872. lpNotifyNode = lpNotifyNode->lpNext;
  873. }
  874. }
  875. }
  876. if (fNotifyMutex) {
  877. fNotifyMutex = FALSE;
  878. ReleaseMutex(hmtxNotificationList);
  879. }
  880. if (fAdviseMutex) {
  881. fAdviseMutex = FALSE;
  882. ReleaseMutex(hmtxAdviseList);
  883. }
  884. }
  885. exit:
  886. // exit thread
  887. return(0);
  888. }
  889. #endif