mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-23 03:50:30 +08:00
276 lines
8.6 KiB
C#
276 lines
8.6 KiB
C#
#region copyright
|
||
//------------------------------------------------------------------------------
|
||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||
// QQ群:605534569
|
||
//------------------------------------------------------------------------------
|
||
#endregion
|
||
|
||
using System.Runtime.InteropServices;
|
||
|
||
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
|
||
|
||
namespace ThingsGateway.Foundation.Adapter.OPCDA.Da;
|
||
#pragma warning disable CA1416 // 验证平台兼容性
|
||
|
||
internal class OpcServer : IDisposable
|
||
{
|
||
|
||
private bool disposedValue;
|
||
|
||
private IOPCServer m_OpcServer = null;
|
||
|
||
internal OpcServer(string name, string host = "localhost")
|
||
{
|
||
Name = name;
|
||
if (string.IsNullOrEmpty(host))
|
||
{
|
||
Host = "localhost";
|
||
}
|
||
else
|
||
{
|
||
Host = host;
|
||
}
|
||
}
|
||
|
||
internal string Host { get; private set; }
|
||
internal bool IsConnected { get; private set; } = false;
|
||
internal string Name { get; private set; }
|
||
internal List<OpcGroup> OpcGroups { get; private set; } = new List<OpcGroup>(10);
|
||
internal ServerStatus ServerStatus { get; private set; } = new ServerStatus();
|
||
|
||
public void Dispose()
|
||
{
|
||
Dispose(disposing: true);
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
|
||
internal OpcGroup AddGroup(string groupName)
|
||
{
|
||
return AddGroup(groupName, true, 1000, 0);
|
||
}
|
||
|
||
/// <returns></returns>
|
||
internal OpcGroup AddGroup(string groupName, bool active, int reqUpdateRate, float deadBand)
|
||
{
|
||
if (null == m_OpcServer || IsConnected == false)
|
||
throw new("未初始化连接!");
|
||
OpcGroup group = new(groupName, active, reqUpdateRate, deadBand);
|
||
Guid riid = typeof(IOPCItemMgt).GUID;
|
||
m_OpcServer?.AddGroup(group.Name,
|
||
group.IsActive ? 1 : 0,//IsActive
|
||
group.RequestUpdateRate,//RequestedUpdateRate 1000ms
|
||
group.ClientGroupHandle,
|
||
group.TimeBias.AddrOfPinnedObject(),
|
||
group.PercendDeadBand.AddrOfPinnedObject(),
|
||
group.LCID,
|
||
out group.serverGroupHandle,
|
||
out group.revisedUpdateRate,
|
||
ref riid,
|
||
out group.groupPointer);
|
||
if (group.groupPointer != null)
|
||
{
|
||
group.InitIoInterfaces(group.groupPointer);
|
||
OpcGroups.Add(group);
|
||
}
|
||
else
|
||
{
|
||
throw new("添加OPC组错误,OPC服务器返回null");
|
||
}
|
||
return group;
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取节点
|
||
/// </summary>
|
||
internal List<BrowseElement> Browse(string itemId = null)
|
||
{
|
||
lock (this)
|
||
{
|
||
if (null == m_OpcServer || IsConnected == false)
|
||
throw new("未初始化连接!");
|
||
|
||
var count = 0;
|
||
var moreElements = 0;
|
||
|
||
var pContinuationPoint = IntPtr.Zero;
|
||
var pElements = IntPtr.Zero;
|
||
var filterId = new PropertyID[]
|
||
{
|
||
new PropertyID(1),
|
||
new PropertyID(3),
|
||
new PropertyID(4),
|
||
new PropertyID(5),
|
||
new PropertyID(6),
|
||
new PropertyID(101),
|
||
};
|
||
|
||
|
||
var server = m_OpcServer as IOPCBrowse;
|
||
server.Browse(
|
||
string.IsNullOrEmpty(itemId) ? "" : itemId,
|
||
ref pContinuationPoint,
|
||
int.MaxValue,
|
||
OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL,
|
||
"",
|
||
"",
|
||
0,
|
||
1,
|
||
filterId.Length,
|
||
Interop.GetPropertyIDs(filterId),
|
||
out moreElements,
|
||
out count,
|
||
out pElements);
|
||
BrowseElement[] browseElements = Interop.GetBrowseElements(ref pElements, count, true);
|
||
string stringUni = Marshal.PtrToStringUni(pContinuationPoint);
|
||
Marshal.FreeCoTaskMem(pContinuationPoint);
|
||
this.ProcessResults(browseElements, filterId);
|
||
return browseElements?.ToList();
|
||
}
|
||
}
|
||
|
||
internal void Connect()
|
||
{
|
||
if (!string.IsNullOrEmpty(Host) && !string.IsNullOrEmpty(Name))
|
||
{
|
||
var info = Discovery.OpcDiscovery.GetOpcServer(Name, Host);
|
||
object o = Comn.ComInterop.CreateInstance(info.CLSID, Host);
|
||
if (o == null)
|
||
{
|
||
throw new(string.Format("{0}{1}无法创建com对象", info.CLSID, Host));
|
||
}
|
||
m_OpcServer = (IOPCServer)o;
|
||
IsConnected = true;
|
||
}
|
||
else
|
||
throw new("应初始化Host与Name");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 服务器状态
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
internal ServerStatus GetServerStatus()
|
||
{
|
||
ServerStatus serverStatus = null;
|
||
try
|
||
{
|
||
if (null == m_OpcServer || IsConnected == false)
|
||
throw new("未初始化连接!");
|
||
IntPtr statusPtr = IntPtr.Zero;
|
||
m_OpcServer?.GetStatus(out statusPtr);
|
||
OPCSERVERSTATUS status;
|
||
if (statusPtr != IntPtr.Zero)
|
||
{
|
||
|
||
object o = Marshal.PtrToStructure(statusPtr, typeof(OPCSERVERSTATUS));
|
||
|
||
Marshal.FreeCoTaskMem(statusPtr);
|
||
|
||
if (o != null)
|
||
{
|
||
status = (OPCSERVERSTATUS)o;
|
||
serverStatus = new();
|
||
serverStatus.Version = $"{status.wMajorVersion.ToString()}.{status.wMinorVersion.ToString()}.{status.wBuildNumber.ToString()}";
|
||
serverStatus.ServerState = status.dwServerState;
|
||
serverStatus.StartTime = Comn.Convert.FileTimeToDateTime(status.ftStartTime);
|
||
serverStatus.CurrentTime = Comn.Convert.FileTimeToDateTime(status.ftCurrentTime);
|
||
serverStatus.LastUpdateTime = Comn.Convert.FileTimeToDateTime(status.ftLastUpdateTime);
|
||
serverStatus.VendorInfo = status.szVendorInfo;
|
||
IsConnected = true;
|
||
|
||
return serverStatus;
|
||
}
|
||
else
|
||
{
|
||
IsConnected = false;
|
||
throw new("未知错误");
|
||
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
IsConnected = false;
|
||
throw new("未知错误");
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
if (serverStatus != null)
|
||
IsConnected = true;
|
||
else
|
||
IsConnected = false;
|
||
ServerStatus = serverStatus;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
internal void RemoveGroup(OpcGroup group)
|
||
{
|
||
if (OpcGroups.Contains(group))
|
||
{
|
||
m_OpcServer?.RemoveGroup(group.ServerGroupHandle, 1);
|
||
OpcGroups.Remove(group);
|
||
}
|
||
}
|
||
|
||
protected virtual void Dispose(bool disposing)
|
||
{
|
||
if (!disposedValue)
|
||
{
|
||
try
|
||
{
|
||
for (int i = 0; i < OpcGroups.Count; i++)
|
||
RemoveGroup(OpcGroups[i]);
|
||
}
|
||
catch
|
||
{
|
||
|
||
}
|
||
if (m_OpcServer != null)
|
||
{
|
||
Marshal.ReleaseComObject(m_OpcServer);
|
||
m_OpcServer = null;
|
||
}
|
||
if (disposing)
|
||
{
|
||
OpcGroups.Clear();
|
||
}
|
||
disposedValue = true;
|
||
}
|
||
}
|
||
|
||
private void ProcessResults(BrowseElement[] elements, PropertyID[] propertyIDs)
|
||
{
|
||
if (elements == null)
|
||
return;
|
||
foreach (BrowseElement element in elements)
|
||
{
|
||
if (element.Properties != null)
|
||
{
|
||
foreach (ItemProperty property in element.Properties)
|
||
{
|
||
if (propertyIDs != null)
|
||
{
|
||
foreach (PropertyID propertyId in propertyIDs)
|
||
{
|
||
if (property.ID.Code == propertyId.Code)
|
||
{
|
||
property.ID = propertyId;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|