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.

605 lines
19 KiB

  1. /*******************************************************************************
  2. * SPEventQ.h *
  3. *------------*
  4. * Description:
  5. * This is the header file for the SAPI5 event queue implementation.
  6. *-------------------------------------------------------------------------------
  7. * Copyright (c) Microsoft Corporation. All rights reserved.
  8. *******************************************************************************/
  9. #ifndef SPEventQ_h
  10. #define SPEventQ_h
  11. #ifndef SPHelper_h
  12. #include <SPHelper.h>
  13. #endif
  14. #ifndef SPCollec_h
  15. #include <SPCollec.h>
  16. #endif
  17. //=== Inline helpers for copying and deleting events ============================
  18. //=== Class definition ==========================================================
  19. class CSpEventNode : public CSpEvent
  20. {
  21. public:
  22. CSpEventNode * m_pNext;
  23. static LONG Compare(const CSpEventNode * p1, const CSpEventNode *p2)
  24. {
  25. // Assumes offsets DO or DO NOT reset when stream number changes
  26. if (p1->ulStreamNum < p2->ulStreamNum)
  27. {
  28. return -1;
  29. }
  30. else if (p1->ulStreamNum > p2->ulStreamNum)
  31. {
  32. return 1;
  33. }
  34. else if (p1->ullAudioStreamOffset < p2->ullAudioStreamOffset)
  35. {
  36. return -1;
  37. }
  38. else if (p1->ullAudioStreamOffset > p2->ullAudioStreamOffset)
  39. {
  40. return 1;
  41. }
  42. return 0;
  43. }
  44. };
  45. typedef CSpBasicQueue<CSpEventNode, TRUE, TRUE> CSpEventList;
  46. #define DECLARE_SPNOTIFYSOURCE_METHODS(T) \
  47. STDMETHODIMP SetNotifySink(ISpNotifySink * pNotifySink) \
  48. { return T._SetNotifySink(pNotifySink); } \
  49. STDMETHODIMP SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) \
  50. { return T._SetNotifyWindowMessage(hWnd, Msg, wParam, lParam); } \
  51. STDMETHODIMP SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam) \
  52. { return T._SetNotifyCallbackFunction(pfnCallback, wParam, lParam); } \
  53. STDMETHODIMP SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam) \
  54. { return T._SetNotifyCallbackInterface(pSpCallback, wParam, lParam); } \
  55. STDMETHODIMP SetNotifyWin32Event() \
  56. { return T._SetNotifyWin32Event(); } \
  57. STDMETHODIMP WaitForNotifyEvent(DWORD dwMilliseconds) \
  58. { return T._WaitForNotifyEvent(dwMilliseconds); } \
  59. STDMETHODIMP_(HANDLE) GetNotifyEventHandle() \
  60. { return T._GetNotifyEventHandle(); }
  61. #define DECLARE_SPEVENTSOURCE_METHODS(T) \
  62. DECLARE_SPNOTIFYSOURCE_METHODS(T) \
  63. STDMETHODIMP SetInterest(ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest) \
  64. { return T._SetInterest(ullEventInterest, ullQueuedInterest); } \
  65. STDMETHODIMP GetEvents(ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched) \
  66. { return T._GetEvents(ulCount, pEventArray, pulFetched); } \
  67. STDMETHODIMP GetInfo(SPEVENTSOURCEINFO *pInfo) \
  68. { return T._GetInfo(pInfo); }
  69. class CSpEventSource
  70. {
  71. public:
  72. CSpEventSource(CComObjectRootEx<CComMultiThreadModel> * pParent) :
  73. m_pParent(pParent)
  74. {
  75. m_ullEventInterest = 0; m_ullQueuedInterest = 0;
  76. m_ulStreamNum = 0;
  77. }
  78. HRESULT _SetNotifySink(ISpNotifySink * pNotifySink);
  79. HRESULT _SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  80. HRESULT _SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam);
  81. HRESULT _SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam);
  82. HRESULT _SetNotifyWin32Event();
  83. HRESULT _WaitForNotifyEvent(DWORD dwMilliseconds);
  84. HANDLE _GetNotifyEventHandle();
  85. HRESULT _SetInterest(ULONGLONG ullEventInterest , ULONGLONG ullQueuedInterest);
  86. HRESULT _GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched );
  87. HRESULT _GetInfo(SPEVENTSOURCEINFO *pInfo );
  88. /*--- Non interface methods ---*/
  89. HRESULT _CompleteEvents( ULONGLONG ullPos = 0xFFFFFFFFFFFFFFFF );
  90. inline void _MoveAllToFreeList(CSpEventList * pList);
  91. inline void _RemoveAllEvents();
  92. inline HRESULT _AddEvent(const SPEVENT & Event);
  93. inline HRESULT _AddEvents(const SPEVENT* pEventArray, ULONG ulCount);
  94. inline HRESULT _DeserializeAndAddEvent(const BYTE * pBuffer, ULONG * pcbUsed);
  95. inline HRESULT _GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum);
  96. //=== Data members ==============================
  97. public:
  98. ULONGLONG m_ullEventInterest;
  99. ULONGLONG m_ullQueuedInterest;
  100. ULONG m_ulStreamNum;
  101. CSpEventList m_PendingList;
  102. CSpEventList m_CompletedList;
  103. CSpEventList m_FreeList;
  104. CComPtr<ISpNotifySink> m_cpNotifySink;
  105. CComPtr<ISpNotifyTranslator> m_cpEventTranslator; // If non-NULL then Win32 events being used
  106. CComObjectRootEx<CComMultiThreadModel> * m_pParent;
  107. CComAutoCriticalSection m_NotifyObjChangeCrit; // Critical section used to make sure that
  108. // the notify object (m_cpNotifySink) not changed
  109. // while waiting on it.
  110. };
  111. //
  112. //=== Inlines =========================================================
  113. //
  114. //
  115. // WARNING: If this logic changes, you will need to change the logic in SetNotifyWin32Event also.
  116. //
  117. inline HRESULT CSpEventSource::_SetNotifySink(ISpNotifySink * pNotifySink)
  118. {
  119. if (SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pNotifySink))
  120. {
  121. return E_INVALIDARG;
  122. }
  123. else
  124. {
  125. m_pParent->Lock();
  126. m_NotifyObjChangeCrit.Lock();
  127. m_cpEventTranslator.Release();
  128. m_cpNotifySink = pNotifySink;
  129. if (m_cpNotifySink && m_CompletedList.GetHead())
  130. {
  131. m_cpNotifySink->Notify();
  132. }
  133. m_NotifyObjChangeCrit.Unlock();
  134. m_pParent->Unlock();
  135. return S_OK;
  136. }
  137. }
  138. /****************************************************************************
  139. * CSpEventSource::_SetNotifyWindowMessage *
  140. *-----------------------------------------*
  141. * Description:
  142. *
  143. * Returns:
  144. *
  145. ********************************************************************* RAL ***/
  146. inline HRESULT CSpEventSource::_SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  147. {
  148. SPDBG_FUNC("CSpEventSource::_SetNotifyWindowMessage");
  149. HRESULT hr = S_OK;
  150. CComPtr<ISpNotifyTranslator> cpTranslator;
  151. hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  152. if (SUCCEEDED(hr))
  153. {
  154. hr = cpTranslator->InitWindowMessage(hWnd, Msg, wParam, lParam);
  155. }
  156. if (SUCCEEDED(hr))
  157. {
  158. hr = _SetNotifySink(cpTranslator);
  159. }
  160. return hr;
  161. }
  162. /****************************************************************************
  163. * CSpEventSource::_SetNotifyCallbackFunction *
  164. *--------------------------------------------*
  165. * Description:
  166. *
  167. * Returns:
  168. *
  169. ********************************************************************* RAL ***/
  170. inline HRESULT CSpEventSource::_SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam)
  171. {
  172. SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackFunction");
  173. HRESULT hr = S_OK;
  174. CComPtr<ISpNotifyTranslator> cpTranslator;
  175. hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  176. if (SUCCEEDED(hr))
  177. {
  178. hr = cpTranslator->InitCallback(pfnCallback, wParam, lParam);
  179. }
  180. if (SUCCEEDED(hr))
  181. {
  182. hr = _SetNotifySink(cpTranslator);
  183. }
  184. return hr;
  185. }
  186. /****************************************************************************
  187. * CSpEventSource::_SetNotifyCallbackInterface *
  188. *---------------------------------------------*
  189. * Description:
  190. *
  191. * Returns:
  192. *
  193. ********************************************************************* RAL ***/
  194. inline HRESULT CSpEventSource::_SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam)
  195. {
  196. SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackInterface");
  197. HRESULT hr = S_OK;
  198. CComPtr<ISpNotifyTranslator> cpTranslator;
  199. hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = cpTranslator->InitSpNotifyCallback(pSpCallback, wParam, lParam);
  203. }
  204. if (SUCCEEDED(hr))
  205. {
  206. hr = _SetNotifySink(cpTranslator);
  207. }
  208. return hr;
  209. }
  210. /****************************************************************************
  211. * CSpEventSource::_SetNotifyWin32Event *
  212. *--------------------------------------*
  213. * Description:
  214. *
  215. * Returns:
  216. *
  217. ********************************************************************* RAL ***/
  218. inline HRESULT CSpEventSource::_SetNotifyWin32Event(void)
  219. {
  220. SPDBG_FUNC("CSpEventSource::_SetNotifyWin32Event");
  221. HRESULT hr = S_OK;
  222. CComPtr<ISpNotifyTranslator> cpTranslator;
  223. hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  224. if (SUCCEEDED(hr))
  225. {
  226. hr = cpTranslator->InitWin32Event(NULL, TRUE);
  227. }
  228. if (SUCCEEDED(hr))
  229. {
  230. //
  231. // In this case we do NOT call _SetNotify sink since we want to set the cpEventTranslator
  232. //
  233. m_pParent->Lock();
  234. m_NotifyObjChangeCrit.Lock();
  235. m_cpEventTranslator = cpTranslator;
  236. m_cpNotifySink = cpTranslator;
  237. if (m_cpNotifySink && m_CompletedList.GetHead())
  238. {
  239. m_cpNotifySink->Notify();
  240. }
  241. m_NotifyObjChangeCrit.Unlock();
  242. m_pParent->Unlock();
  243. }
  244. return hr;
  245. }
  246. /****************************************************************************
  247. * CSpEventSource::_WaitForNotifyEvent *
  248. *-------------------------------------*
  249. * Description:
  250. *
  251. * Returns:
  252. *
  253. ********************************************************************* RAL ***/
  254. inline HRESULT CSpEventSource::_WaitForNotifyEvent(DWORD dwMilliseconds)
  255. {
  256. SPDBG_FUNC("CSpEventSource::_WaitForNotifyEvent");
  257. HRESULT hr = S_OK;
  258. m_NotifyObjChangeCrit.Lock();
  259. if (m_cpEventTranslator)
  260. {
  261. hr = m_cpEventTranslator->Wait(dwMilliseconds);
  262. }
  263. else
  264. {
  265. if (m_cpNotifySink)
  266. {
  267. hr = SPERR_ALREADY_INITIALIZED;
  268. }
  269. else
  270. {
  271. hr = _SetNotifyWin32Event();
  272. if (SUCCEEDED(hr))
  273. {
  274. hr = m_cpEventTranslator->Wait(dwMilliseconds);
  275. }
  276. }
  277. }
  278. m_NotifyObjChangeCrit.Unlock();
  279. return hr;
  280. }
  281. /****************************************************************************
  282. * CSpEventSource::_GetNotifyEventHandle *
  283. *---------------------------------------*
  284. * Description:
  285. *
  286. * Returns:
  287. *
  288. ********************************************************************* RAL ***/
  289. inline HANDLE CSpEventSource::_GetNotifyEventHandle()
  290. {
  291. HANDLE h = NULL;
  292. SPDBG_FUNC("CSpEventSource::_GetNotifyEventHandle");
  293. m_NotifyObjChangeCrit.Lock();
  294. if (!m_cpNotifySink)
  295. {
  296. _SetNotifyWin32Event();
  297. }
  298. if (m_cpEventTranslator)
  299. {
  300. h = m_cpEventTranslator->GetEventHandle();
  301. }
  302. m_NotifyObjChangeCrit.Unlock();
  303. return h;
  304. }
  305. inline HRESULT CSpEventSource::_SetInterest( ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest )
  306. {
  307. HRESULT hr = S_OK;
  308. m_pParent->Lock();
  309. if(ullEventInterest && SPFEI_FLAGCHECK != (ullEventInterest & SPFEI_FLAGCHECK))
  310. {
  311. hr = E_INVALIDARG;
  312. }
  313. else if(ullQueuedInterest && SPFEI_FLAGCHECK != (ullQueuedInterest & SPFEI_FLAGCHECK))
  314. {
  315. hr = E_INVALIDARG;
  316. }
  317. else if ((ullQueuedInterest | ullEventInterest) != ullEventInterest)
  318. {
  319. hr = E_INVALIDARG;
  320. }
  321. else
  322. {
  323. m_ullEventInterest = ullEventInterest;
  324. m_ullQueuedInterest = ullQueuedInterest;
  325. }
  326. m_pParent->Unlock();
  327. return hr;
  328. }
  329. //
  330. // Same as AddEvents except: No param validation, and caller must take the critical section
  331. // prior to calling.
  332. //
  333. inline HRESULT CSpEventSource::_AddEvents( const SPEVENT* pEventArray, ULONG ulCount )
  334. {
  335. HRESULT hr = S_OK;
  336. for( ULONG i = 0; i < ulCount && SUCCEEDED(hr = _AddEvent(pEventArray[i])); ++i ) {}
  337. return hr;
  338. }
  339. inline HRESULT CSpEventSource::_AddEvent(const SPEVENT & Event)
  340. {
  341. SPDBG_ASSERT(Event.eEventId < 64);
  342. SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_UNDEFINED ||
  343. Event.elParamType == SPET_LPARAM_IS_TOKEN ||
  344. Event.elParamType == SPET_LPARAM_IS_OBJECT ||
  345. Event.elParamType == SPET_LPARAM_IS_POINTER ||
  346. Event.elParamType == SPET_LPARAM_IS_STRING);
  347. #ifdef _DEBUG
  348. if (Event.eEventId == SPEI_VOICE_CHANGE)
  349. {
  350. SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_TOKEN);
  351. }
  352. else if (Event.eEventId == SPEI_RECOGNITION || Event.eEventId == SPEI_FALSE_RECOGNITION || Event.eEventId == SPEI_HYPOTHESIS)
  353. {
  354. SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_OBJECT);
  355. }
  356. else if (Event.eEventId ==SPEI_REQUEST_UI || Event.eEventId == SPEI_TTS_BOOKMARK)
  357. {
  358. SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_STRING);
  359. }
  360. #endif
  361. if ( (1i64 << Event.eEventId) & m_ullEventInterest )
  362. {
  363. CSpEventNode *pNode = m_FreeList.RemoveHead();
  364. if (pNode == NULL)
  365. {
  366. pNode = new CSpEventNode();
  367. if (pNode == NULL)
  368. {
  369. return E_OUTOFMEMORY;
  370. }
  371. }
  372. pNode->CopyFrom(&Event);
  373. m_PendingList.InsertSorted(pNode);
  374. }
  375. return S_OK;
  376. }
  377. inline HRESULT CSpEventSource::
  378. _DeserializeAndAddEvent(const BYTE *pBuffer, ULONG * pcbUsed)
  379. {
  380. HRESULT hr = S_OK;
  381. const SPEVENT * pSrcEvent = (const SPEVENT *)pBuffer;
  382. SPDBG_ASSERT(pSrcEvent->eEventId < 64);
  383. if ( (1i64 << pSrcEvent->eEventId) & m_ullEventInterest )
  384. {
  385. CSpEventNode *pNode = m_FreeList.RemoveHead();
  386. if (pNode == NULL)
  387. {
  388. pNode = new CSpEventNode();
  389. if (pNode == NULL)
  390. {
  391. hr = E_OUTOFMEMORY;
  392. }
  393. }
  394. if (SUCCEEDED(hr))
  395. {
  396. hr = pNode->Deserialize(((const SPSERIALIZEDEVENT64 *)(pBuffer)), pcbUsed);
  397. if (SUCCEEDED(hr))
  398. {
  399. m_PendingList.InsertSorted(pNode);
  400. }
  401. else
  402. {
  403. m_FreeList.InsertHead(pNode);
  404. }
  405. }
  406. }
  407. else
  408. {
  409. // WCE compiler does not work propertly with template
  410. #ifndef _WIN32_WCE
  411. *pcbUsed = SpEventSerializeSize<SPSERIALIZEDEVENT64>(pSrcEvent);
  412. #else
  413. *pcbUsed = SpEventSerializeSize(pSrcEvent, sizeof(SPSERIALIZEDEVENT64));
  414. #endif
  415. }
  416. return hr;
  417. }
  418. inline HRESULT CSpEventSource::_GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG *pulFetched )
  419. {
  420. HRESULT hr = S_OK;
  421. m_pParent->Lock();
  422. if( SPIsBadWritePtr( pEventArray, sizeof( SPEVENT ) * ulCount ) ||
  423. SP_IS_BAD_OPTIONAL_WRITE_PTR(pulFetched) )
  424. {
  425. hr = E_INVALIDARG;
  426. }
  427. else
  428. {
  429. ULONG ulCopied = 0;
  430. ULONG ulRemaining = ulCount;
  431. CSpEventNode * pCur = m_CompletedList.m_pHead;
  432. CSpEventNode * pLastCopied = NULL;
  433. while (ulRemaining && pCur)
  434. {
  435. pCur->Detach(pEventArray + ulCopied);
  436. pLastCopied = pCur;
  437. ulCopied++;
  438. pCur = pCur->m_pNext;
  439. ulRemaining--;
  440. }
  441. if (ulCopied)
  442. {
  443. if (m_FreeList.m_pHead == NULL)
  444. {
  445. m_FreeList.m_pTail = pLastCopied;
  446. }
  447. pLastCopied->m_pNext = m_FreeList.m_pHead;
  448. m_FreeList.m_pHead = m_CompletedList.m_pHead;
  449. m_CompletedList.m_pHead = pCur;
  450. m_CompletedList.m_cElements -= ulCopied;
  451. m_FreeList.m_cElements += ulCopied;
  452. }
  453. if (ulCopied < ulCount)
  454. {
  455. hr = S_FALSE;
  456. }
  457. if (pulFetched)
  458. {
  459. *pulFetched = ulCopied;
  460. }
  461. }
  462. m_pParent->Unlock();
  463. return hr;
  464. }
  465. inline HRESULT CSpEventSource::_GetInfo( SPEVENTSOURCEINFO * pInfo )
  466. {
  467. HRESULT hr = S_OK;
  468. m_pParent->Lock();
  469. if( SP_IS_BAD_WRITE_PTR( pInfo ) )
  470. {
  471. hr = E_POINTER;
  472. }
  473. else
  474. {
  475. pInfo->ulCount = m_CompletedList.GetCount();
  476. pInfo->ullEventInterest = m_ullEventInterest;
  477. pInfo->ullQueuedInterest= m_ullQueuedInterest;
  478. }
  479. m_pParent->Unlock();
  480. return hr;
  481. }
  482. //
  483. // The caller must call this function with the critical section owned
  484. //
  485. inline HRESULT CSpEventSource::_CompleteEvents( ULONGLONG ullPos )
  486. {
  487. HRESULT hr = S_OK;
  488. if (m_PendingList.m_pHead && m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
  489. {
  490. BOOL bNotify = FALSE;
  491. while (m_PendingList.m_pHead &&
  492. m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
  493. {
  494. CSpEventNode *pNode = m_PendingList.RemoveHead();
  495. if(pNode->ulStreamNum != m_ulStreamNum)
  496. {
  497. m_ulStreamNum = pNode->ulStreamNum;
  498. }
  499. if ( (1i64 << pNode->eEventId) & m_ullEventInterest )
  500. {
  501. bNotify = TRUE;
  502. //
  503. // NOTE: If we're forwarding events to an event sink then we'll only
  504. // pay attention to the Interest flags. If we're going to notify, then
  505. // we'll only queue completed events that the user has explicitly asked
  506. // us to store as completed events.
  507. //
  508. if ( (1i64 << pNode->eEventId) & m_ullQueuedInterest )
  509. {
  510. m_CompletedList.InsertSorted(pNode);
  511. }
  512. else
  513. {
  514. pNode->Clear();
  515. m_FreeList.InsertHead(pNode);
  516. }
  517. }
  518. else
  519. {
  520. pNode->Clear();
  521. m_FreeList.InsertHead(pNode);
  522. }
  523. }
  524. if (bNotify && m_cpNotifySink)
  525. {
  526. hr = m_cpNotifySink->Notify();
  527. }
  528. }
  529. return hr;
  530. };
  531. inline void CSpEventSource::_MoveAllToFreeList(CSpEventList * pList)
  532. {
  533. CSpEventNode * pNode;
  534. while ((pNode = pList->RemoveHead()) != NULL)
  535. {
  536. pNode->Clear();
  537. m_FreeList.InsertHead(pNode);
  538. }
  539. }
  540. inline void CSpEventSource::_RemoveAllEvents( )
  541. {
  542. m_pParent->Lock();
  543. _MoveAllToFreeList(&m_CompletedList);
  544. _MoveAllToFreeList(&m_PendingList);
  545. m_pParent->Unlock();
  546. }
  547. inline HRESULT CSpEventSource::_GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum)
  548. {
  549. CSpEventNode *pNode = m_PendingList.m_pHead;
  550. *pulStreamNum = m_ulStreamNum;
  551. for(;pNode && pNode->ullAudioStreamOffset <= ullAudioOffset; pNode = pNode->m_pNext)
  552. {
  553. *pulStreamNum = pNode->ulStreamNum;
  554. }
  555. return S_OK;
  556. }
  557. #endif //--- This must be the last line in this file