speventq.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:19k
源码类别:

模拟服务器

开发平台:

C/C++

  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. //
  113. //=== Inlines =========================================================
  114. //
  115. //
  116. //  WARNING:  If this logic changes, you will need to change the logic in SetNotifyWin32Event also.
  117. //
  118. inline HRESULT CSpEventSource::_SetNotifySink(ISpNotifySink * pNotifySink)
  119. {
  120.     if (SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pNotifySink))
  121.     {
  122.         return E_INVALIDARG;
  123.     }
  124.     else
  125.     {
  126.         m_pParent->Lock();
  127.         m_NotifyObjChangeCrit.Lock();
  128.         m_cpEventTranslator.Release();
  129.         m_cpNotifySink = pNotifySink;
  130.         if (m_cpNotifySink && m_CompletedList.GetHead())
  131.         {
  132.             m_cpNotifySink->Notify();
  133.         }
  134.         m_NotifyObjChangeCrit.Unlock();
  135.         m_pParent->Unlock();
  136.         return S_OK;
  137.     }
  138. }
  139. /****************************************************************************
  140. * CSpEventSource::_SetNotifyWindowMessage *
  141. *-----------------------------------------*
  142. *   Description:
  143. *
  144. *   Returns:
  145. *
  146. ********************************************************************* RAL ***/
  147. inline HRESULT CSpEventSource::_SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  148. {
  149.     SPDBG_FUNC("CSpEventSource::_SetNotifyWindowMessage");
  150.     HRESULT hr = S_OK;
  151.     CComPtr<ISpNotifyTranslator> cpTranslator;
  152.     hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  153.     if (SUCCEEDED(hr))
  154.     {
  155.         hr = cpTranslator->InitWindowMessage(hWnd, Msg, wParam, lParam);
  156.     }
  157.     if (SUCCEEDED(hr))
  158.     {
  159.         hr = _SetNotifySink(cpTranslator);
  160.     }
  161.     return hr;
  162. }
  163. /****************************************************************************
  164. * CSpEventSource::_SetNotifyCallbackFunction *
  165. *--------------------------------------------*
  166. *   Description:
  167. *
  168. *   Returns:
  169. *
  170. ********************************************************************* RAL ***/
  171. inline HRESULT CSpEventSource::_SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam)
  172. {
  173.     SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackFunction");
  174.     HRESULT hr = S_OK;
  175.     CComPtr<ISpNotifyTranslator> cpTranslator;
  176.     hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  177.     if (SUCCEEDED(hr))
  178.     {
  179.         hr = cpTranslator->InitCallback(pfnCallback, wParam, lParam);
  180.     }
  181.     if (SUCCEEDED(hr))
  182.     {
  183.         hr = _SetNotifySink(cpTranslator);
  184.     }
  185.     return hr;
  186. }
  187. /****************************************************************************
  188. * CSpEventSource::_SetNotifyCallbackInterface *
  189. *---------------------------------------------*
  190. *   Description:
  191. *
  192. *   Returns:
  193. *
  194. ********************************************************************* RAL ***/
  195. inline HRESULT CSpEventSource::_SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam)
  196. {
  197.     SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackInterface");
  198.     HRESULT hr = S_OK;
  199.     CComPtr<ISpNotifyTranslator> cpTranslator;
  200.     hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  201.     if (SUCCEEDED(hr))
  202.     {
  203.         hr = cpTranslator->InitSpNotifyCallback(pSpCallback, wParam, lParam);
  204.     }
  205.     if (SUCCEEDED(hr))
  206.     {
  207.         hr = _SetNotifySink(cpTranslator);
  208.     }
  209.     return hr;
  210. }
  211. /****************************************************************************
  212. * CSpEventSource::_SetNotifyWin32Event *
  213. *--------------------------------------*
  214. *   Description:
  215. *
  216. *   Returns:
  217. *
  218. ********************************************************************* RAL ***/
  219. inline HRESULT CSpEventSource::_SetNotifyWin32Event(void)
  220. {
  221.     SPDBG_FUNC("CSpEventSource::_SetNotifyWin32Event");
  222.     HRESULT hr = S_OK;
  223.     CComPtr<ISpNotifyTranslator> cpTranslator;
  224.     hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
  225.     if (SUCCEEDED(hr))
  226.     {
  227.         hr = cpTranslator->InitWin32Event(NULL, TRUE);
  228.     }
  229.     if (SUCCEEDED(hr))
  230.     {
  231.         //
  232.         //  In this case we do NOT call _SetNotify sink since we want to set the cpEventTranslator
  233.         //
  234.         m_pParent->Lock();
  235.         m_NotifyObjChangeCrit.Lock();
  236.         m_cpEventTranslator = cpTranslator;
  237.         m_cpNotifySink = cpTranslator;
  238.         if (m_cpNotifySink && m_CompletedList.GetHead())
  239.         {
  240.             m_cpNotifySink->Notify();
  241.         }
  242.         m_NotifyObjChangeCrit.Unlock();
  243.         m_pParent->Unlock();
  244.     }
  245.     return hr;
  246. }
  247. /****************************************************************************
  248. * CSpEventSource::_WaitForNotifyEvent *
  249. *-------------------------------------*
  250. *   Description:
  251. *
  252. *   Returns:
  253. *
  254. ********************************************************************* RAL ***/
  255. inline HRESULT CSpEventSource::_WaitForNotifyEvent(DWORD dwMilliseconds)
  256. {
  257.     SPDBG_FUNC("CSpEventSource::_WaitForNotifyEvent");
  258.     HRESULT hr = S_OK;
  259.     m_NotifyObjChangeCrit.Lock();
  260.     if (m_cpEventTranslator)
  261.     {
  262.         hr = m_cpEventTranslator->Wait(dwMilliseconds);
  263.     }
  264.     else
  265.     {
  266.         if (m_cpNotifySink)
  267.         {
  268.             hr = SPERR_ALREADY_INITIALIZED;
  269.         }
  270.         else
  271.         {
  272.             hr = _SetNotifyWin32Event();
  273.             if (SUCCEEDED(hr))
  274.             {
  275.                 hr = m_cpEventTranslator->Wait(dwMilliseconds);
  276.             }
  277.         }
  278.     }
  279.     m_NotifyObjChangeCrit.Unlock();
  280.     return hr;
  281. }
  282. /****************************************************************************
  283. * CSpEventSource::_GetNotifyEventHandle *
  284. *---------------------------------------*
  285. *   Description:
  286. *
  287. *   Returns:
  288. *
  289. ********************************************************************* RAL ***/
  290. inline HANDLE CSpEventSource::_GetNotifyEventHandle()
  291. {
  292.     HANDLE h = NULL;
  293.     SPDBG_FUNC("CSpEventSource::_GetNotifyEventHandle");
  294.     m_NotifyObjChangeCrit.Lock();
  295.     if (!m_cpNotifySink)
  296.     {
  297.         _SetNotifyWin32Event();
  298.     }
  299.     if (m_cpEventTranslator)
  300.     {
  301.         h = m_cpEventTranslator->GetEventHandle();
  302.     }
  303.     m_NotifyObjChangeCrit.Unlock();
  304.     return h;
  305. }
  306. inline HRESULT CSpEventSource::_SetInterest( ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest )
  307. {
  308.     HRESULT hr = S_OK;
  309.     m_pParent->Lock();
  310.     if(ullEventInterest && SPFEI_FLAGCHECK != (ullEventInterest & SPFEI_FLAGCHECK))
  311.     {
  312.         hr = E_INVALIDARG;
  313.     }
  314.     else if(ullQueuedInterest && SPFEI_FLAGCHECK != (ullQueuedInterest & SPFEI_FLAGCHECK))
  315.     {
  316.         hr = E_INVALIDARG;
  317.     }
  318.     else if ((ullQueuedInterest | ullEventInterest) != ullEventInterest)
  319.     {
  320.         hr = E_INVALIDARG;
  321.     }
  322.     else
  323.     {
  324.         m_ullEventInterest = ullEventInterest;
  325.         m_ullQueuedInterest = ullQueuedInterest;
  326.     }
  327.     m_pParent->Unlock();
  328.     return hr;
  329. }
  330. //
  331. //  Same as AddEvents except:  No param validation, and caller must take the critical section
  332. //  prior to calling.
  333. //
  334. inline HRESULT CSpEventSource::_AddEvents( const SPEVENT* pEventArray, ULONG ulCount )
  335. {
  336.     HRESULT hr = S_OK;
  337.     for( ULONG i = 0; i < ulCount && SUCCEEDED(hr = _AddEvent(pEventArray[i])); ++i ) {}
  338.     return hr;
  339. }
  340. inline HRESULT CSpEventSource::_AddEvent(const SPEVENT & Event)
  341. {
  342.     SPDBG_ASSERT(Event.eEventId < 64);
  343.     SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_UNDEFINED ||
  344.                  Event.elParamType == SPET_LPARAM_IS_TOKEN ||
  345.                  Event.elParamType == SPET_LPARAM_IS_OBJECT ||
  346.                  Event.elParamType == SPET_LPARAM_IS_POINTER ||
  347.                  Event.elParamType == SPET_LPARAM_IS_STRING);
  348. #ifdef _DEBUG
  349.     if (Event.eEventId == SPEI_VOICE_CHANGE)
  350.     {
  351.         SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_TOKEN);
  352.     }
  353.     else if (Event.eEventId == SPEI_RECOGNITION || Event.eEventId == SPEI_FALSE_RECOGNITION || Event.eEventId == SPEI_HYPOTHESIS)
  354.     {
  355.         SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_OBJECT);
  356.     }
  357.     else if (Event.eEventId ==SPEI_REQUEST_UI || Event.eEventId == SPEI_TTS_BOOKMARK)
  358.     {
  359.         SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_STRING);
  360.     }
  361. #endif
  362.     if ( (1i64 << Event.eEventId) & m_ullEventInterest )
  363.     {
  364.         CSpEventNode *pNode = m_FreeList.RemoveHead();
  365.         if (pNode == NULL)
  366.         {
  367.             pNode = new CSpEventNode();
  368.             if (pNode == NULL)
  369.             {
  370.                 return E_OUTOFMEMORY;
  371.             }
  372.         }
  373.         pNode->CopyFrom(&Event);
  374.         m_PendingList.InsertSorted(pNode);
  375.     }
  376.     return S_OK;
  377. }
  378. inline HRESULT CSpEventSource::
  379.     _DeserializeAndAddEvent(const BYTE *pBuffer, ULONG * pcbUsed)
  380. {
  381.     HRESULT hr = S_OK;
  382.     const SPEVENT * pSrcEvent = (const SPEVENT *)pBuffer;
  383.     SPDBG_ASSERT(pSrcEvent->eEventId < 64);
  384.     if ( (1i64 << pSrcEvent->eEventId) & m_ullEventInterest )
  385.     {
  386.         CSpEventNode *pNode = m_FreeList.RemoveHead();
  387.         if (pNode == NULL)
  388.         {
  389.             pNode = new CSpEventNode();
  390.             if (pNode == NULL)
  391.             {
  392.                 hr = E_OUTOFMEMORY;
  393.             }
  394.         }
  395.         if (SUCCEEDED(hr))
  396.         {
  397.             hr = pNode->Deserialize(((const SPSERIALIZEDEVENT64 *)(pBuffer)), pcbUsed);
  398.             if (SUCCEEDED(hr))
  399.             {
  400.                 m_PendingList.InsertSorted(pNode);
  401.             }
  402.             else
  403.             {
  404.                 m_FreeList.InsertHead(pNode);
  405.             }
  406.         }
  407.     }
  408.     else
  409.     {
  410. // WCE compiler does not work propertly with template
  411. #ifndef _WIN32_WCE
  412.         *pcbUsed = SpEventSerializeSize<SPSERIALIZEDEVENT64>(pSrcEvent);
  413. #else
  414.         *pcbUsed = SpEventSerializeSize(pSrcEvent, sizeof(SPSERIALIZEDEVENT64));
  415. #endif
  416.     }
  417.     return hr;
  418. }
  419. inline HRESULT CSpEventSource::_GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG *pulFetched )
  420. {
  421.     HRESULT hr = S_OK;
  422.     m_pParent->Lock();
  423.     if( SPIsBadWritePtr( pEventArray, sizeof( SPEVENT ) * ulCount ) ||
  424.         SP_IS_BAD_OPTIONAL_WRITE_PTR(pulFetched) )
  425.     {
  426.         hr = E_INVALIDARG;
  427.     }
  428.     else 
  429.     {
  430.         ULONG ulCopied = 0;
  431.         ULONG ulRemaining = ulCount;
  432.         CSpEventNode * pCur = m_CompletedList.m_pHead;
  433.         CSpEventNode * pLastCopied = NULL;
  434.         while (ulRemaining && pCur)
  435.         {
  436.             pCur->Detach(pEventArray + ulCopied);
  437.             pLastCopied = pCur;
  438.             ulCopied++;
  439.             pCur = pCur->m_pNext;
  440.             ulRemaining--;
  441.         }
  442.         if (ulCopied)
  443.         {
  444.             if (m_FreeList.m_pHead == NULL)
  445.             {
  446.                 m_FreeList.m_pTail = pLastCopied;
  447.             }
  448.             pLastCopied->m_pNext = m_FreeList.m_pHead;
  449.             m_FreeList.m_pHead = m_CompletedList.m_pHead;
  450.             m_CompletedList.m_pHead = pCur;
  451.             m_CompletedList.m_cElements -= ulCopied;
  452.             m_FreeList.m_cElements += ulCopied;
  453.         }
  454.         if (ulCopied < ulCount)
  455.         {
  456.             hr = S_FALSE;
  457.         }
  458.         if (pulFetched) 
  459.         {
  460.             *pulFetched = ulCopied;
  461.         }
  462.     }
  463.     m_pParent->Unlock();
  464.     return hr;
  465. }
  466. inline HRESULT CSpEventSource::_GetInfo( SPEVENTSOURCEINFO * pInfo )
  467. {
  468.     HRESULT hr = S_OK;
  469.     m_pParent->Lock();    
  470.     if( SP_IS_BAD_WRITE_PTR( pInfo ) )
  471.     {
  472.         hr = E_POINTER;
  473.     }
  474.     else
  475.     {
  476.         pInfo->ulCount = m_CompletedList.GetCount();
  477.         pInfo->ullEventInterest = m_ullEventInterest;
  478.         pInfo->ullQueuedInterest= m_ullQueuedInterest;
  479.     }
  480.     m_pParent->Unlock();
  481.     return hr;
  482. }
  483. //
  484. //  The caller must call this function with the critical section owned
  485. //
  486. inline HRESULT CSpEventSource::_CompleteEvents( ULONGLONG ullPos )
  487. {
  488.     HRESULT hr = S_OK;
  489.     if (m_PendingList.m_pHead && m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
  490.     {
  491.         BOOL bNotify = FALSE;
  492.         while (m_PendingList.m_pHead &&
  493.                m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
  494.         {
  495.             CSpEventNode *pNode = m_PendingList.RemoveHead();
  496.             if(pNode->ulStreamNum != m_ulStreamNum)
  497.             {
  498.                 m_ulStreamNum = pNode->ulStreamNum;
  499.             }
  500.             if ( (1i64 << pNode->eEventId) & m_ullEventInterest )
  501.             {
  502.                 bNotify = TRUE;
  503.                 //
  504.                 //  NOTE:  If we're forwarding events to an event sink then we'll only
  505.                 //  pay attention to the Interest flags.  If we're going to notify, then
  506.                 //  we'll only queue completed events that the user has explicitly asked
  507.                 //  us to store as completed events.
  508.                 //
  509.                 if ( (1i64 << pNode->eEventId) & m_ullQueuedInterest )
  510.                 {
  511.                     m_CompletedList.InsertSorted(pNode);
  512.                 }
  513.                 else
  514.                 {
  515.                     pNode->Clear();
  516.                     m_FreeList.InsertHead(pNode);
  517.                 }
  518.             }
  519.             else
  520.             {
  521.                 pNode->Clear();
  522.                 m_FreeList.InsertHead(pNode);
  523.             }
  524.         }    
  525.         if (bNotify && m_cpNotifySink)
  526.         {
  527.             hr = m_cpNotifySink->Notify();
  528.         }
  529.     }
  530.     return hr;
  531. };
  532. inline void CSpEventSource::_MoveAllToFreeList(CSpEventList * pList)
  533. {
  534.     CSpEventNode * pNode;
  535.     while ((pNode = pList->RemoveHead()) != NULL)
  536.     {
  537.         pNode->Clear();
  538.         m_FreeList.InsertHead(pNode);
  539.     }
  540. }
  541. inline void CSpEventSource::_RemoveAllEvents( )
  542. {
  543.     m_pParent->Lock();
  544.     _MoveAllToFreeList(&m_CompletedList);
  545.     _MoveAllToFreeList(&m_PendingList);
  546.     m_pParent->Unlock();
  547. }
  548. inline HRESULT CSpEventSource::_GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum)
  549. {
  550.     CSpEventNode *pNode = m_PendingList.m_pHead;
  551.     *pulStreamNum = m_ulStreamNum;
  552.     for(;pNode && pNode->ullAudioStreamOffset <= ullAudioOffset; pNode = pNode->m_pNext)
  553.     {
  554.         *pulStreamNum = pNode->ulStreamNum;
  555.     }
  556.     return S_OK;
  557. }
  558. #endif //--- This must be the last line in this file