/// <summary> /// Initializes a COM-patible ONEVENTSTRUCT ready to be sent to subscribing clients /// </summary> /// <param name="oes"></param> /// <param name="pOnEventClass"></param> private void CopyToOnEventStruct(ref ONEVENTSTRUCT oes, OnEventClass pOnEventClass) { try { oes = pOnEventClass.InternalOES; ReturnedAttributeList attrIds; if (m_ReturnedAttributes.TryGetValue(oes.dwEventCategory, out attrIds) == true) { int retAttrCount = attrIds.Count; int i = 0; object[] attrVals = new object[retAttrCount]; foreach (int attrId in attrIds) { attrVals[i++] = pOnEventClass.EventAttributes[attrId]; } oes.dwNumEventAttrs = retAttrCount; oes.pEventAttributes = ComUtils.GetVARIANTs(attrVals, false); } } catch (Exception e) { Utils.Trace(e, "Unexpected error in CopyToOnEventStruct"); } }
/// <summary> /// Called during incoming event processing and as a result of a client-initiated Refresh. /// Forwards to each server instance for further processing. /// </summary> /// <param name="Source"></param> /// <param name="Condition"></param> /// <param name="cond"></param> public void NotifyClients(string Source, string Condition, OPCCondition cond) { OnEventClass OEClass = new OnEventClass(Source, Condition, cond); foreach (ComAeProxy s in m_EvServerSet) { s.ProcessNewEvent(OEClass); } }
/// <summary> /// Determines whether the newly received event matches the filter applied to this /// subscription. /// </summary> /// <param name="pOnEventClass"></param> /// <returns></returns> private bool MatchesFilter(OnEventClass pOnEventClass) { bool FilterMatches = true; try { if (System.Convert.ToBoolean(m_dwEventType & pOnEventClass.InternalOES.dwEventType) == false) { FilterMatches = false; } if (m_EventCategoryVector.Count != 0) { if (m_EventCategoryVector.Contains(pOnEventClass.InternalOES.dwEventCategory) == false) { FilterMatches = false; } } if (pOnEventClass.InternalOES.dwSeverity <m_dwLowSeverity | pOnEventClass.InternalOES.dwSeverity> m_dwHighSeverity) { FilterMatches = false; } if (m_AreaVector.Count != 0) { if (pOnEventClass.EventAttributes.Count > 0) { string[] areas = (string[])pOnEventClass.EventAttributes[1]; foreach (string area in areas) { if (m_AreaVector.Contains(area) == true) { FilterMatches = true; break; } FilterMatches = false; } } } if (m_SourceVector.Count != 0) { if (m_SourceVector.Contains(pOnEventClass.InternalOES.szSource) == false) { FilterMatches = false; } } } catch (Exception e) { Utils.Trace(e, "Unexpected error in MatchesFilter"); FilterMatches = false; } return(FilterMatches); }
/// <summary> /// If the subscription filter allows the event then enqueue the event /// and assign a threadpool worker to handle the subscription callback /// </summary> /// <param name="pOnEventClass"></param> public void ProcessNewEvent(OnEventClass pOnEventClass) { lock (m_csData) { try { if (m_bActive == true) { // compare to my filter, if it matches if (MatchesFilter(pOnEventClass)) { m_OnEventQ.Enqueue(pOnEventClass); } // Just a keep-alive event? else if ((pOnEventClass.InternalOES.szSource == null) && (pOnEventClass.InternalOES.szConditionName == null)) { m_KeepAliveQ.EnqueueIfEmpty(pOnEventClass); } // Even if this event was filtered out, check to see if it // is time to send anything that is already in my queue. if (m_OnEventQ.Count > 0) { TimeSpan bufferTime = TimeSpan.FromMilliseconds(m_dwBufferTime); DateTime lastUpdate = m_LastUpdateTime; DateTime nextUpdate = lastUpdate + bufferTime; if (m_OnEventQ.Count >= m_dwMaxSize || nextUpdate <= DateTime.Now) { ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWork), null); } } // No "real events" to send ... is it time to send a keep alive (keepalive of 0 means disabled) ? else if ((m_KeepAliveQ.Count > 0) && (m_KeepAliveTime != 0)) { TimeSpan bufferTime = TimeSpan.FromMilliseconds(m_KeepAliveTime); DateTime lastUpdate = m_LastUpdateTime; if (DateTime.Now >= (lastUpdate + bufferTime)) { ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWork), null); } } } } catch (Exception e) { Utils.Trace(e, "Unexpected error in ProcessNewEvent"); } } }
/// <summary> /// Force a refresh for all active conditions and inactive, unacknowledged conditions whose event notifications match the filter of the event subscription. /// </summary> /// <param name="dwConnection">The OLE Connection number returned from IConnectionPoint::Advise. This is passed to help the server determine which OPC event sink to call when the request completes.</param> public void Refresh(int dwConnection) { try { if (m_RefreshID != 0 || m_RefreshQ.Count != 0) { throw ComUtils.CreateComException("Refresh", ResultIds.E_BUSY); } m_RefreshID = dwConnection; // Foe each source walk through all associated conditions. If the condition is "refreshable", i.e. Active or // inactive/unacknowledged, then create an event and push it on to the subscription's refresh queue SourceMap sourceMap = SourceMap.TheSourceMap; foreach (KeyValuePair <string, ConditionMap> kvp in sourceMap) { string sourceName = kvp.Key; ConditionMap conditionMap = kvp.Value; foreach (KeyValuePair <string, OPCCondition> kvpCond in conditionMap) { string conditionName = kvpCond.Key; OPCCondition cond = kvpCond.Value; if (cond.IsEnabled() && (cond.IsActive() || !cond.IsAcked())) { OnEventClass OEClass = new OnEventClass(sourceName, conditionName, cond); if (MatchesFilter(OEClass)) { m_RefreshQ.Enqueue(OEClass); } } } } if (m_RefreshQ.Count > 0) { ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWork), null); } else { CancelRefresh(dwConnection); } } catch (Exception e) { Utils.Trace(e, "Unexpected error in Refresh"); throw ComUtils.CreateComException(e); } }