C# 开发 OPC Server 系列之二
继续C# OPC Server开发,本单节实现OPC标准接口IOPCServer里的AddGroup方法代码如下
/// <summary>
/// 新增一个 OPCGroup
/// </summary>
/// <param name="szName">组名。组名必须为UNICODE 码,不能是ASC码,而且不能和同一个客户程序创建的其它组的名字相同。如果没有定义组名,服务器会给它定义一个独有的名字。</param>
/// <param name="bActive">如果值为FALSE,那么组被定义为不活动的。如果为TRUE,组被定义为活动的。</param>
/// <param name="dwRequestedUpdateRate">客户程序定义的组最快的刷新速率,单位为毫秒,主要在OnDataChage 中使用。同样说明了要求CACHED DATA 的期望速率。如果此值为0,那么服务器必须以最快的实际速率刷新。</param>
/// <param name="hClientGroup">客户程序提供的组句柄。</param>
/// <param name="pTimeBias">时间戳指针。如果指针为空表示你希望使用系统默认时间戳。</param>
/// <param name="pPercentDeadband">定义了死区参数。这个参数仅仅对本组内的模拟量有效。当模拟量的值变化超出死区,必须产生一个回调给客户程序。NULL 值代表0.0,即没有死区。</param>
/// <param name="dwLCID">本组字符串操作时,服务器使用的语言。</param>
/// <param name="phServerGroup">服务器为新的组产生的句柄。客户程序将采用服务器提供的句柄来要求服务器对组进行其它的操作。</param>
/// <param name="pRevisedUpdateRate">服务器返回的实际刷新速率,这个值可能与客户程序要求的刷新速率不一样。注意:这个值可能也比服务器实际从设备获取数据和刷新CACHE 的速率要慢。</param>
/// <param name="riid">期望接口类型 (如 IID_IOPCItemMgt)</param>
/// <param name="ppUnk">返回接口指针,如果操作失败,返回NULL。</param>
/// <returns>操作代码</returns>
[PreserveSig]
public int AddGroup(string szName, bool bActive, int dwRequestedUpdateRate, int hClientGroup,
IntPtr pTimeBias, IntPtr pPercentDeadband, int dwLCID,
out int phServerGroup, out int pRevisedUpdateRate, ref Guid riid,
[MarshalAs(UnmanagedType.IUnknown), Out]out object ppUnk)
{
#region 数据准备 验证
phServerGroup = 0;
pRevisedUpdateRate = 0;
ppUnk = null;
if (OPCDAGlobal.ServerState == OpcServerState.Failed)
{
return HRESULTS.E_FAIL;
}
if (!string.IsNullOrEmpty(szName))
{
if (_opcDAGroups.Count(p => p.GroupName == szName) > 0)
{
return HRESULTS.OPC_E_DUPLICATENAME;
}
}
#endregion
#region 获得组名
if (string.IsNullOrEmpty(szName))
{
int groupindex = 0;
while (!string.IsNullOrEmpty(szName))
{
string nszName = "Group" + groupindex.ToString();
if (_opcDAGroups.Count(p => p.GroupName == nszName) == 0)
{
szName = nszName;
}
groupindex++;
}
}
#endregion
#region 实例化Group 对像
OPCDAGroup opcdagroup = new OPCDAGroup(this);
pRevisedUpdateRate = OPCDAGlobal.GetRevisedKeepAliveTime(dwRequestedUpdateRate);
opcdagroup.TimeBias = Marshal.ReadInt32(pTimeBias);
float[] pdb = new float[1];
Marshal.Copy(pPercentDeadband, pdb, 0, 1);
opcdagroup.LCID = dwLCID;
opcdagroup.Active = bActive;
opcdagroup.GroupName = szName;
opcdagroup.PercentDeadband = pdb[0];
opcdagroup.RevisedUpdateRate = pRevisedUpdateRate;
opcdagroup.ClientGroup = hClientGroup;
phServerGroup = opcdagroup.ServerGroup;
ppUnk = opcdagroup;
#endregion
_opcDAGroups.Add(opcdagroup);
//服务器实际使用的数据更新率与客户请求的更新率不同
if (pRevisedUpdateRate != dwRequestedUpdateRate)
{
return HRESULTS.OPC_S_UNSUPPORTEDRATE;
}
return HRESULTS.S_OK;
}
/// 新增一个 OPCGroup
/// </summary>
/// <param name="szName">组名。组名必须为UNICODE 码,不能是ASC码,而且不能和同一个客户程序创建的其它组的名字相同。如果没有定义组名,服务器会给它定义一个独有的名字。</param>
/// <param name="bActive">如果值为FALSE,那么组被定义为不活动的。如果为TRUE,组被定义为活动的。</param>
/// <param name="dwRequestedUpdateRate">客户程序定义的组最快的刷新速率,单位为毫秒,主要在OnDataChage 中使用。同样说明了要求CACHED DATA 的期望速率。如果此值为0,那么服务器必须以最快的实际速率刷新。</param>
/// <param name="hClientGroup">客户程序提供的组句柄。</param>
/// <param name="pTimeBias">时间戳指针。如果指针为空表示你希望使用系统默认时间戳。</param>
/// <param name="pPercentDeadband">定义了死区参数。这个参数仅仅对本组内的模拟量有效。当模拟量的值变化超出死区,必须产生一个回调给客户程序。NULL 值代表0.0,即没有死区。</param>
/// <param name="dwLCID">本组字符串操作时,服务器使用的语言。</param>
/// <param name="phServerGroup">服务器为新的组产生的句柄。客户程序将采用服务器提供的句柄来要求服务器对组进行其它的操作。</param>
/// <param name="pRevisedUpdateRate">服务器返回的实际刷新速率,这个值可能与客户程序要求的刷新速率不一样。注意:这个值可能也比服务器实际从设备获取数据和刷新CACHE 的速率要慢。</param>
/// <param name="riid">期望接口类型 (如 IID_IOPCItemMgt)</param>
/// <param name="ppUnk">返回接口指针,如果操作失败,返回NULL。</param>
/// <returns>操作代码</returns>
[PreserveSig]
public int AddGroup(string szName, bool bActive, int dwRequestedUpdateRate, int hClientGroup,
IntPtr pTimeBias, IntPtr pPercentDeadband, int dwLCID,
out int phServerGroup, out int pRevisedUpdateRate, ref Guid riid,
[MarshalAs(UnmanagedType.IUnknown), Out]out object ppUnk)
{
#region 数据准备 验证
phServerGroup = 0;
pRevisedUpdateRate = 0;
ppUnk = null;
if (OPCDAGlobal.ServerState == OpcServerState.Failed)
{
return HRESULTS.E_FAIL;
}
if (!string.IsNullOrEmpty(szName))
{
if (_opcDAGroups.Count(p => p.GroupName == szName) > 0)
{
return HRESULTS.OPC_E_DUPLICATENAME;
}
}
#endregion
#region 获得组名
if (string.IsNullOrEmpty(szName))
{
int groupindex = 0;
while (!string.IsNullOrEmpty(szName))
{
string nszName = "Group" + groupindex.ToString();
if (_opcDAGroups.Count(p => p.GroupName == nszName) == 0)
{
szName = nszName;
}
groupindex++;
}
}
#endregion
#region 实例化Group 对像
OPCDAGroup opcdagroup = new OPCDAGroup(this);
pRevisedUpdateRate = OPCDAGlobal.GetRevisedKeepAliveTime(dwRequestedUpdateRate);
opcdagroup.TimeBias = Marshal.ReadInt32(pTimeBias);
float[] pdb = new float[1];
Marshal.Copy(pPercentDeadband, pdb, 0, 1);
opcdagroup.LCID = dwLCID;
opcdagroup.Active = bActive;
opcdagroup.GroupName = szName;
opcdagroup.PercentDeadband = pdb[0];
opcdagroup.RevisedUpdateRate = pRevisedUpdateRate;
opcdagroup.ClientGroup = hClientGroup;
phServerGroup = opcdagroup.ServerGroup;
ppUnk = opcdagroup;
#endregion
_opcDAGroups.Add(opcdagroup);
//服务器实际使用的数据更新率与客户请求的更新率不同
if (pRevisedUpdateRate != dwRequestedUpdateRate)
{
return HRESULTS.OPC_S_UNSUPPORTEDRATE;
}
return HRESULTS.S_OK;
}