#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
//-----------------------------------------------------------------------------
// Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
// Web: https://www.technosoftware.com
//
// The source code in this file is covered under a dual-license scenario:
// - Owner of a purchased license: SCLA 1.0
// - GPL V3: everybody else
//
// SCLA license terms accompanied with this source code.
// See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf
//
// GNU General Public License as published by the Free Software Foundation;
// version 3 of the License are accompanied with this source code.
// See https://technosoftware.com/license/GPLv3License.txt
//
// This source code is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
#endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved
#region Using Directives
using System;
using System.Collections;
using System.Runtime.InteropServices;
using Technosoftware.DaAeHdaClient.Ae;
using Technosoftware.OpcRcw.Comn;
using Technosoftware.OpcRcw.Ae;
#endregion
#pragma warning disable 0618
namespace Technosoftware.DaAeHdaClient.Com.Ae
{
///
/// A .NET wrapper for a COM server that implements the AE server interfaces.
///
[Serializable]
internal class Server : Technosoftware.DaAeHdaClient.Com.Server, ITsCAeServer
{
#region Constructors
///
/// Initializes the object with the specified OpcUrl and COM server.
///
internal Server(OpcUrl url, object server) : base(url, server)
{
m_supportsAE11 = true;
// check if the V1.1 interfaces are supported.
try
{
var server2 = (IOPCEventServer2)server;
}
catch
{
m_supportsAE11 = false;
}
}
#endregion
#region IDisposable Members
///
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
///
/// If true managed and unmanaged resources can be disposed. If false only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (!m_disposed)
{
lock (this)
{
if (disposing)
{
// Release managed resources.
// release the server.
if (server_ != null)
{
// release all subscriptions.
foreach (Subscription subscription in m_subscriptions.Values)
{
// dispose of the subscription object (disconnects all subscriptions connections).
subscription.Dispose();
}
// clear subscription table.
m_subscriptions.Clear();
}
}
// Release unmanaged resources.
// Set large fields to null.
// release the browser.
if (m_browser != null)
{
Technosoftware.DaAeHdaClient.Com.Interop.ReleaseServer(m_browser);
m_browser = null;
}
// release the server.
if (server_ != null)
{
Technosoftware.DaAeHdaClient.Com.Interop.ReleaseServer(server_);
server_ = null;
}
}
// Call Dispose on your base class.
m_disposed = true;
}
base.Dispose(disposing);
}
private bool m_disposed = false;
#endregion
#region Technosoftware.DaAeHdaClient.IOpcServer Members
//======================================================================
// Get Status
///
/// Returns the current server status.
///
/// The current server status.
public OpcServerStatus GetServerStatus()
{
lock (this)
{
if (server_ == null) throw new NotConnectedException();
var methodName = "IOPCServer.GetStatus";
// initialize arguments.
var pStatus = IntPtr.Zero;
// invoke COM method.
try
{
var server = BeginComCall(methodName, true);
((IOPCEventServer)server_).GetStatus(out pStatus);
}
catch (Exception e)
{
ComCallError(methodName, e);
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("Server.GetStatus", e);
}
finally
{
EndComCall(methodName);
}
// return results.
return Interop.GetServerStatus(ref pStatus, true);
}
}
//======================================================================
// Event Subscription
///
/// Creates a new event subscription.
///
/// The initial state for the subscription.
/// The new subscription object.
public ITsCAeSubscription CreateSubscription(TsCAeSubscriptionState state)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
if (state == null) throw new ArgumentNullException(nameof(state));
// initialize arguments.
object unknown = null;
var riid = typeof(IOPCEventSubscriptionMgt).GUID;
var bufferTime = 0;
var maxSize = 0;
// invoke COM method.
try
{
((IOPCEventServer)server_).CreateEventSubscription(
(state.Active)?1:0,
state.BufferTime,
state.MaxSize,
++m_handles,
ref riid,
out unknown,
out bufferTime,
out maxSize);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.CreateEventSubscription", e);
}
// save actual values.
state.BufferTime = bufferTime;
state.MaxSize = maxSize;
var subscription = new Subscription(state, unknown);
// set keep alive.
subscription.ModifyState((int)TsCAeStateMask.KeepAlive, state);
// save subscription.
m_subscriptions.Add(m_handles, subscription);
// return results.
return subscription;
}
}
//======================================================================
// QueryAvailableFilters
///
/// Returns the event filters supported by the server.
///
/// A bit mask of all event filters supported by the server.
public int QueryAvailableFilters()
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var filters = 0;
// invoke COM method.
try
{
((IOPCEventServer)server_).QueryAvailableFilters(out filters);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QueryAvailableFilters", e);
}
// return results.
return filters;
}
}
//======================================================================
// QueryEventCategories
///
/// Returns the event categories supported by the server for the specified event types.
///
/// A bit mask for the event types of interest.
/// A collection of event categories.
public TsCAeCategory[] QueryEventCategories(int eventType)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var count = 0;
var ppdwEventCategories = IntPtr.Zero;
var ppszEventCategoryDescs = IntPtr.Zero;
// invoke COM method.
try
{
((IOPCEventServer)server_).QueryEventCategories(
eventType,
out count,
out ppdwEventCategories,
out ppszEventCategoryDescs);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QueryEventCategories", e);
}
// check for empty list.
if (count == 0)
{
return new TsCAeCategory[0];
}
// unmarshal arguments.
var ids = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppdwEventCategories, count, true);
var names = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszEventCategoryDescs, count, true);
// build results.
var categories = new TsCAeCategory[count];
for (var ii = 0; ii < count; ii++)
{
categories[ii] = new TsCAeCategory();
categories[ii].ID = ids[ii];
categories[ii].Name = names[ii];
}
// return results.
return categories;
}
}
//======================================================================
// QueryConditionNames
///
/// Returns the condition names supported by the server for the specified event categories.
///
/// A bit mask for the event categories of interest.
/// A list of condition names.
public string[] QueryConditionNames(int eventCategory)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var count = 0;
var ppszConditionNames = IntPtr.Zero;
// invoke COM method.
try
{
((IOPCEventServer)server_).QueryConditionNames(
eventCategory,
out count,
out ppszConditionNames);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QueryConditionNames", e);
}
// check for empty list.
if (count == 0)
{
return new string[0];
}
// unmarshal arguments.
var names = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszConditionNames, count, true);
// return results.
return names;
}
}
//======================================================================
// QuerySubConditionNames
///
/// Returns the sub-condition names supported by the server for the specified event condition.
///
/// The name of the condition.
/// A list of sub-condition names.
public string[] QuerySubConditionNames(string conditionName)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var count = 0;
var ppszSubConditionNames = IntPtr.Zero;
// invoke COM method.
try
{
((IOPCEventServer)server_).QuerySubConditionNames(
conditionName,
out count,
out ppszSubConditionNames);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QuerySubConditionNames", e);
}
// check for empty list.
if (count == 0)
{
return new string[0];
}
// unmarshal arguments.
var names = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszSubConditionNames, count, true);
// return results.
return names;
}
}
//======================================================================
// QuerySourceConditions
///
/// Returns the condition names supported by the server for the specified event source.
///
/// The name of the event source.
/// A list of condition names.
public string[] QueryConditionNames(string sourceName)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var count = 0;
var ppszConditionNames = IntPtr.Zero;
// invoke COM method.
try
{
((IOPCEventServer)server_).QuerySourceConditions(
sourceName,
out count,
out ppszConditionNames);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QuerySourceConditions", e);
}
// check for empty list.
if (count == 0)
{
return new string[0];
}
// unmarshal arguments.
var names = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszConditionNames, count, true);
// return results.
return names;
}
}
//======================================================================
// QueryEventAttributes
///
/// Returns the event attributes supported by the server for the specified event categories.
///
/// A bit mask for the event categories of interest.
/// A collection of event attributes.
public TsCAeAttribute[] QueryEventAttributes(int eventCategory)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var count = 0;
var ppdwAttrIDs = IntPtr.Zero;
var ppszAttrDescs = IntPtr.Zero;
var ppvtAttrTypes = IntPtr.Zero;
// invoke COM method.
try
{
((IOPCEventServer)server_).QueryEventAttributes(
eventCategory,
out count,
out ppdwAttrIDs,
out ppszAttrDescs,
out ppvtAttrTypes);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.QueryEventAttributes", e);
}
// check for empty list.
if (count == 0)
{
return new TsCAeAttribute[0];
}
// unmarshal arguments.
var ids = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppdwAttrIDs, count, true);
var names = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszAttrDescs, count, true);
var types = Technosoftware.DaAeHdaClient.Com.Interop.GetInt16s(ref ppvtAttrTypes, count, true);
// build results.
var attributes = new TsCAeAttribute[count];
for (var ii = 0; ii < count; ii++)
{
attributes[ii] = new TsCAeAttribute();
attributes[ii].ID = ids[ii];
attributes[ii].Name = names[ii];
attributes[ii].DataType = Technosoftware.DaAeHdaClient.Com.Interop.GetType((VarEnum)types[ii]);
}
// return results.
return attributes;
}
}
//======================================================================
// TranslateToItemIDs
///
/// Returns the DA item ids for a set of attribute ids belonging to events which meet the specified filter criteria.
///
/// The event source of interest.
/// The id of the event category for the events of interest.
/// The name of a condition within the event category.
/// The name of a sub-condition within a multi-state condition.
/// The ids of the attributes to return item ids for.
/// A list of item urls for each specified attribute.
public TsCAeItemUrl[] TranslateToItemIDs(
string sourceName,
int eventCategory,
string conditionName,
string subConditionName,
int[] attributeIDs)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var ppszAttrItemIDs = IntPtr.Zero;
var ppszNodeNames = IntPtr.Zero;
var ppCLSIDs = IntPtr.Zero;
var count = (attributeIDs != null)?attributeIDs.Length:0;
// call server.
try
{
((IOPCEventServer)server_).TranslateToItemIDs(
(sourceName != null)?sourceName:"",
eventCategory,
(conditionName != null)?conditionName:"",
(subConditionName != null)?subConditionName:"",
count,
(count > 0)?attributeIDs:new int[0],
out ppszAttrItemIDs,
out ppszNodeNames,
out ppCLSIDs);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.TranslateToItemIDs", e);
}
// unmarshal results.
var itemIDs = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszAttrItemIDs, count, true);
var nodeNames = Technosoftware.DaAeHdaClient.Com.Interop.GetUnicodeStrings(ref ppszNodeNames, count, true);
var clsids = Technosoftware.DaAeHdaClient.Com.Interop.GetGUIDs(ref ppCLSIDs, count, true);
var itemUrls = new TsCAeItemUrl[count];
// fill in item urls.
for (var ii = 0; ii < count; ii++)
{
itemUrls[ii] = new TsCAeItemUrl();
itemUrls[ii].ItemName = itemIDs[ii];
itemUrls[ii].ItemPath = null;
itemUrls[ii].Url.Scheme = OpcUrlScheme.DA;
itemUrls[ii].Url.HostName = nodeNames[ii];
itemUrls[ii].Url.Path = string.Format("{{{0}}}", clsids[ii]);
}
// return results.
return itemUrls;
}
}
//======================================================================
// GetConditionState
///
/// Returns the current state information for the condition instance corresponding to the source and condition name.
///
/// The source name
/// A condition name for the source.
/// The list of attributes to return with the condition state.
/// The current state of the connection.
public TsCAeCondition GetConditionState(
string sourceName,
string conditionName,
int[] attributeIDs)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize arguments.
var ppConditionState = IntPtr.Zero;
// call server.
try
{
((IOPCEventServer)server_).GetConditionState(
(sourceName != null)?sourceName:"",
(conditionName != null)?conditionName:"",
(attributeIDs != null)?attributeIDs.Length:0,
(attributeIDs != null)?attributeIDs:new int[0],
out ppConditionState);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.GetConditionState", e);
}
// unmarshal results.
var conditions = Interop.GetConditions(ref ppConditionState, 1, true);
// fill in attribute ids.
for (var ii = 0; ii < conditions[0].Attributes.Count; ii++)
{
conditions[0].Attributes[ii].ID = attributeIDs[ii];
}
// return results.
return conditions[0];
}
}
//======================================================================
// EnableConditionByArea
///
/// Places the specified process areas into the enabled state.
///
/// A list of fully qualified area names.
/// The results of the operation for each area.
public OpcResult[] EnableConditionByArea(string[] areas)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (areas == null || areas.Length == 0)
{
return new OpcResult[0];
}
// initialize arguments.
var ppErrors = IntPtr.Zero;
int[] errors = null;
if (m_supportsAE11)
{
try
{
((IOPCEventServer2)server_).EnableConditionByArea2(
areas.Length,
areas,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.EnableConditionByArea2", e);
}
// unmarshal arguments.
errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, areas.Length, true);
}
else
{
try
{
((IOPCEventServer)server_).EnableConditionByArea(
areas.Length,
areas);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.EnableConditionByArea", e);
}
// create dummy error array (0 == S_OK).
errors = new int[areas.Length];
}
// build results.
var results = new OpcResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = Interop.GetResultID(errors[ii]);
}
// return results.
return results;
}
}
//======================================================================
// DisableConditionByArea
///
/// Places the specified process areas into the disabled state.
///
/// A list of fully qualified area names.
/// The results of the operation for each area.
public OpcResult[] DisableConditionByArea(string[] areas)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (areas == null || areas.Length == 0)
{
return new OpcResult[0];
}
// initialize arguments.
var ppErrors = IntPtr.Zero;
int[] errors = null;
if (m_supportsAE11)
{
try
{
((IOPCEventServer2)server_).DisableConditionByArea2(
areas.Length,
areas,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.DisableConditionByArea2", e);
}
// unmarshal arguments.
errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, areas.Length, true);
}
else
{
try
{
((IOPCEventServer)server_).DisableConditionByArea(
areas.Length,
areas);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.DisableConditionByArea", e);
}
// create dummy error array (0 == S_OK).
errors = new int[areas.Length];
}
// build results.
var results = new OpcResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = Interop.GetResultID(errors[ii]);
}
// return results.
return results;
}
}
//======================================================================
// EnableConditionBySource
///
/// Places the specified process areas into the enabled state.
///
/// A list of fully qualified source names.
/// The results of the operation for each area.
public OpcResult[] EnableConditionBySource(string[] sources)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (sources == null || sources.Length == 0)
{
return new OpcResult[0];
}
// initialize arguments.
var ppErrors = IntPtr.Zero;
int[] errors = null;
if (m_supportsAE11)
{
try
{
((IOPCEventServer2)server_).EnableConditionBySource2(
sources.Length,
sources,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.EnableConditionBySource2", e);
}
// unmarshal arguments.
errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, sources.Length, true);
}
else
{
try
{
((IOPCEventServer)server_).EnableConditionBySource(
sources.Length,
sources);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.EnableConditionBySource", e);
}
// create dummy error array (0 == S_OK).
errors = new int[sources.Length];
}
// build results.
var results = new OpcResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = Interop.GetResultID(errors[ii]);
}
// return results.
return results;
}
}
//======================================================================
// DisableConditionBySource
///
/// Places the specified process areas into the disabled state.
///
/// A list of fully qualified source names.
/// The results of the operation for each area.
public OpcResult[] DisableConditionBySource(string[] sources)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (sources == null || sources.Length == 0)
{
return new OpcResult[0];
}
// initialize arguments.
var ppErrors = IntPtr.Zero;
int[] errors = null;
if (m_supportsAE11)
{
try
{
((IOPCEventServer2)server_).DisableConditionBySource2(
sources.Length,
sources,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.DisableConditionBySource2", e);
}
// unmarshal arguments.
errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, sources.Length, true);
}
else
{
try
{
((IOPCEventServer)server_).DisableConditionBySource(
sources.Length,
sources);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.DisableConditionBySource", e);
}
// create dummy error array (0 == S_OK).
errors = new int[sources.Length];
}
// build results.
var results = new OpcResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = Interop.GetResultID(errors[ii]);
}
// return results.
return results;
}
}
//======================================================================
// GetEnableStateByArea
///
/// Returns the enabled state for the specified process areas.
///
/// A list of fully qualified area names.
public TsCAeEnabledStateResult[] GetEnableStateByArea(string[] areas)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (areas == null || areas.Length == 0)
{
return new TsCAeEnabledStateResult[0];
}
// return error code if AE 1.1 not supported.
if (!m_supportsAE11)
{
var failures = new TsCAeEnabledStateResult[areas.Length];
for (var ii = 0; ii < failures.Length; ii++)
{
failures[ii] = new TsCAeEnabledStateResult();
failures[ii].Enabled = false;
failures[ii].EffectivelyEnabled = false;
failures[ii].Result = OpcResult.E_FAIL;
}
return failures;
}
// initialize arguments.
var pbEnabled = IntPtr.Zero;
var pbEffectivelyEnabled = IntPtr.Zero;
var ppErrors = IntPtr.Zero;
try
{
((IOPCEventServer2)server_).GetEnableStateByArea(
areas.Length,
areas,
out pbEnabled,
out pbEffectivelyEnabled,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.GetEnableStateByArea", e);
}
// unmarshal arguments.
var enabled = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref pbEnabled, areas.Length, true);
var effectivelyEnabled = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref pbEffectivelyEnabled, areas.Length, true);
var errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, areas.Length, true);
// build results.
var results = new TsCAeEnabledStateResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = new TsCAeEnabledStateResult();
results[ii].Enabled = enabled[ii] != 0;
results[ii].EffectivelyEnabled = effectivelyEnabled[ii] != 0;
results[ii].Result = Interop.GetResultID(errors[ii]);
}
// return results
return results;
}
}
//======================================================================
// GetEnableStateBySource
///
/// Returns the enabled state for the specified event sources.
///
/// A list of fully qualified source names.
public TsCAeEnabledStateResult[] GetEnableStateBySource(string[] sources)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (sources == null || sources.Length == 0)
{
return new TsCAeEnabledStateResult[0];
}
// return error code if AE 1.1 not supported.
if (!m_supportsAE11)
{
var failures = new TsCAeEnabledStateResult[sources.Length];
for (var ii = 0; ii < failures.Length; ii++)
{
failures[ii] = new TsCAeEnabledStateResult();
failures[ii].Enabled = false;
failures[ii].EffectivelyEnabled = false;
failures[ii].Result = OpcResult.E_FAIL;
}
return failures;
}
// initialize arguments.
var pbEnabled = IntPtr.Zero;
var pbEffectivelyEnabled = IntPtr.Zero;
var ppErrors = IntPtr.Zero;
try
{
((IOPCEventServer2)server_).GetEnableStateBySource(
sources.Length,
sources,
out pbEnabled,
out pbEffectivelyEnabled,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer2.GetEnableStateBySource", e);
}
// unmarshal arguments.
var enabled = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref pbEnabled, sources.Length, true);
var effectivelyEnabled = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref pbEffectivelyEnabled, sources.Length, true);
var errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, sources.Length, true);
// build results.
var results = new TsCAeEnabledStateResult[errors.Length];
for (var ii = 0; ii < errors.Length; ii++)
{
results[ii] = new TsCAeEnabledStateResult();
results[ii].Enabled = enabled[ii] != 0;
results[ii].EffectivelyEnabled = effectivelyEnabled[ii] != 0;
results[ii].Result = Interop.GetResultID(errors[ii]);
}
// return results
return results;
}
}
//======================================================================
// AcknowledgeCondition
///
/// Used to acknowledge one or more conditions in the event server.
///
/// The identifier for who is acknowledging the condition.
/// A comment associated with the acknowledgment.
/// The conditions being acknowledged.
/// A list of result id indictaing whether each condition was successfully acknowledged.
public OpcResult[] AcknowledgeCondition(
string acknowledgerID,
string comment,
TsCAeEventAcknowledgement[] conditions)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// check for trivial case.
if (conditions == null || conditions.Length == 0)
{
return new OpcResult[0];
}
// initialize arguments.
var count = conditions.Length;
var pszSource = new string[count];
var pszConditionName = new string[count];
var pftActiveTime = new OpcRcw.Ae.FILETIME[count];
var pdwCookie = new int[count];
for (var ii = 0; ii < count; ii ++)
{
pszSource[ii] = conditions[ii].SourceName;
pszConditionName[ii] = conditions[ii].ConditionName;
pftActiveTime[ii] = Interop.Convert(Com.Interop.GetFILETIME(conditions[ii].ActiveTime));
pdwCookie[ii] = conditions[ii].Cookie;
}
var ppErrors = IntPtr.Zero;
// call server.
try
{
((IOPCEventServer)server_).AckCondition(
conditions.Length,
acknowledgerID,
comment,
pszSource,
pszConditionName,
pftActiveTime,
pdwCookie,
out ppErrors);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.AckCondition", e);
}
// unmarshal results.
var errors = Technosoftware.DaAeHdaClient.Com.Interop.GetInt32s(ref ppErrors, count, true);
// build results.
var results = new OpcResult[count];
for (var ii = 0; ii < count; ii++)
{
results[ii] = Interop.GetResultID(errors[ii]);
}
// return results.
return results;
}
}
//======================================================================
// Browse
///
/// Browses for all children of the specified area that meet the filter criteria.
///
/// The full-qualified id for the area.
/// The type of children to return.
/// The expression used to filter the names of children returned.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] Browse(
string areaID,
TsCAeBrowseType browseType,
string browseFilter)
{
lock (this)
{
// intialize arguments.
IOpcBrowsePosition position = null;
// browse for all elements at the current position.
var elements = Browse(areaID, browseType, browseFilter, 0, out position);
// free position object.
if (position != null)
{
position.Dispose();
}
// return results.
return elements;
}
}
///
/// Browses for all children of the specified area that meet the filter criteria.
///
/// The full-qualified id for the area.
/// The type of children to return.
/// The expression used to filter the names of children returned.
/// The maximum number of elements to return.
/// The object used to continue the browse if the number nodes exceeds the maximum specified.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] Browse(
string areaID,
TsCAeBrowseType browseType,
string browseFilter,
int maxElements,
out IOpcBrowsePosition position)
{
position = null;
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
// initialize browser.
InitializeBrowser();
// move to desired area.
ChangeBrowsePosition(areaID);
// create enumerator.
var enumerator = (System.Runtime.InteropServices.ComTypes.IEnumString)CreateEnumerator(browseType, browseFilter);
// fetch elements.
var elements = new ArrayList();
var result = FetchElements(browseType, maxElements, enumerator, elements);
// dispose of enumerator if all done.
if (result != 0)
{
Technosoftware.DaAeHdaClient.Com.Interop.ReleaseServer(enumerator);
}
// create continuation point.
else
{
position = new BrowsePosition(areaID, browseType, browseFilter, enumerator);
}
// return results.
return (TsCAeBrowseElement[])elements.ToArray(typeof(TsCAeBrowseElement));
}
}
//======================================================================
// BrowseNext
///
/// Continues browsing the server's address space at the specified position.
///
/// The maximum number of elements to return.
/// The position object used to continue a browse operation.
/// The set of elements that meet the filter criteria.
public TsCAeBrowseElement[] BrowseNext(int maxElements, ref IOpcBrowsePosition position)
{
lock (this)
{
// verify state and arguments.
if (server_ == null) throw new NotConnectedException();
if (position == null) throw new ArgumentNullException(nameof(position));
// initialize browser.
InitializeBrowser();
// move to desired area.
ChangeBrowsePosition(((BrowsePosition)position).AreaID);
// fetch enumerator from position object.
var enumerator = ((BrowsePosition)position).Enumerator;
// fetch elements.
var elements = new ArrayList();
var result = FetchElements(((BrowsePosition)position).BrowseType, maxElements, enumerator, elements);
// dispose of position object if all done.
if (result != 0)
{
position.Dispose();
position = null;
}
// return results.
return (TsCAeBrowseElement[])elements.ToArray(typeof(TsCAeBrowseElement));
}
}
#endregion
#region Private Methods
///
/// Creates an area browser object for use by all browse requests.
///
private void InitializeBrowser()
{
// do nothing if browser already exists.
if (m_browser != null)
{
return;
}
var riid = typeof(IOPCEventAreaBrowser).GUID;
// initialize arguments.
object unknown;
// invoke COM method.
try
{
((IOPCEventServer)server_).CreateAreaBrowser(
ref riid,
out unknown);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventServer.CreateAreaBrowser", e);
}
// verify object.
if (unknown == null)
{
throw new OpcResultException(new OpcResult( (int)OpcResult.E_FAIL.Code, OpcResult.FuncCallType.SysFuncCall, null ),"The response from the server was invalid or incomplete");
}
// save object.
m_browser = unknown;
}
///
/// Moves the browse position prior to executing a browse operation.
///
private void ChangeBrowsePosition(string areaID)
{
var targetID = (areaID != null)?areaID:"";
// invoke COM method.
try
{
((IOPCEventAreaBrowser)m_browser).ChangeBrowsePosition(
OPCAEBROWSEDIRECTION.OPCAE_BROWSE_TO,
targetID);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventAreaBrowser.ChangeBrowsePosition", e);
}
}
///
/// Creates an enumerator for the names at the current position.
///
private object CreateEnumerator(TsCAeBrowseType browseType, string browseFilter)
{
// initialize arguments.
var dwBrowseFilterType = Interop.GetBrowseType(browseType);
IEnumString enumerator;
// invoke COM method.
try
{
((IOPCEventAreaBrowser)m_browser).BrowseOPCAreas(
dwBrowseFilterType,
(browseFilter != null)?browseFilter:"",
out enumerator);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventAreaBrowser.BrowseOPCAreas", e);
}
// verify object.
if (enumerator == null)
{
throw new OpcResultException(new OpcResult( (int)OpcResult.E_FAIL.Code, OpcResult.FuncCallType.SysFuncCall, null ),"The response from the server was invalid or incomplete");
}
// return result.
return (System.Runtime.InteropServices.ComTypes.IEnumString)enumerator;
}
///
/// Returns the qualified name for the node at the current position.
///
private string GetQualifiedName(string name, TsCAeBrowseType browseType)
{
// initialize arguments.
string nodeID;
// fetch area qualified name.
if (browseType == TsCAeBrowseType.Area)
{
try
{
((IOPCEventAreaBrowser)m_browser).GetQualifiedAreaName(name, out nodeID);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventAreaBrowser.GetQualifiedAreaName", e);
}
}
// fetch source qualified name.
else
{
try
{
((IOPCEventAreaBrowser)m_browser).GetQualifiedSourceName(name, out nodeID);
}
catch (Exception e)
{
throw Technosoftware.DaAeHdaClient.Com.Interop.CreateException("IOPCEventAreaBrowser.GetQualifiedSourceName", e);
}
}
// return results.
return nodeID;
}
///
/// Fetches up to max elements and returns an flag indicating whether there are any elements left.
///
private int FetchElements(TsCAeBrowseType browseType, int maxElements, System.Runtime.InteropServices.ComTypes.IEnumString enumerator, ArrayList elements)
{
var buffer = new string[1];
// re-calculate buffer length.
var bufferLength = (maxElements > 0 && maxElements-elements.Count < buffer.Length)?maxElements-elements.Count:buffer.Length;
// fetch first batch of names.
var pFetched = Marshal.AllocCoTaskMem(sizeof(int));
try
{
var result = enumerator.Next(bufferLength, buffer, pFetched);
while (result == 0)
{
var fetched = Marshal.ReadInt32(pFetched);
// create elements.
for (var ii = 0; ii < fetched; ii++)
{
var element = new TsCAeBrowseElement();
element.Name = buffer[ii];
element.QualifiedName = GetQualifiedName(buffer[ii], browseType);
element.NodeType = browseType;
elements.Add(element);
}
// check for halt.
if (maxElements > 0 && elements.Count >= maxElements)
{
break;
}
// re-calculate buffer length.
bufferLength = (maxElements > 0 && maxElements-elements.Count < buffer.Length)?maxElements-elements.Count:buffer.Length;
// fetch next block.
result = enumerator.Next(bufferLength, buffer, pFetched);
}
// return final result.
return result;
}
finally
{
if (pFetched != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pFetched);
}
}
}
#endregion
#region Private Members
private bool m_supportsAE11 = true;
private object m_browser = null;
private int m_handles = 1;
private Hashtable m_subscriptions = new Hashtable();
#endregion
}
#region BrowsePosition Class
///
/// Stores the state of a browse operation.
///
[Serializable]
internal class BrowsePosition : TsCAeBrowsePosition
{
#region Constructors
///
/// Saves the parameters for an incomplete browse information.
///
public BrowsePosition(
string areaID,
TsCAeBrowseType browseType,
string browseFilter,
System.Runtime.InteropServices.ComTypes.IEnumString enumerator)
:
base (areaID, browseType, browseFilter)
{
m_enumerator = enumerator;
}
#endregion
#region IDisposable Members
///
/// Dispose(bool disposing) executes in two distinct scenarios.
/// If disposing equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.
/// If disposing equals false, the method has been called by the
/// runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.
///
/// If true managed and unmanaged resources can be disposed. If false only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
if (m_enumerator != null)
{
Technosoftware.DaAeHdaClient.Com.Interop.ReleaseServer(m_enumerator);
m_enumerator = null;
}
// Call Dispose on your base class.
m_disposed = true;
}
base.Dispose(disposing);
}
private bool m_disposed = false;
#endregion
#region Public Interface
///
/// Returns the enumerator stored in the object.
///
public System.Runtime.InteropServices.ComTypes.IEnumString Enumerator => m_enumerator;
#endregion
#region Private Members
System.Runtime.InteropServices.ComTypes.IEnumString m_enumerator = null;
#endregion
}
#endregion
}