Files
KinginfoGateway/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/COM/Da/OpcServer.cs

276 lines
8.6 KiB
C#
Raw Normal View History

2023-05-23 23:54:28 +08:00
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
2023-07-16 17:48:22 +08:00
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
2023-05-23 23:54:28 +08:00
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
2023-07-16 17:48:22 +08:00
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
2023-05-23 23:54:28 +08:00
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
2023-03-09 11:19:48 +08:00
using System.Runtime.InteropServices;
using ThingsGateway.Foundation.Adapter.OPCDA.Rcw;
namespace ThingsGateway.Foundation.Adapter.OPCDA.Da;
2023-08-07 15:09:53 +08:00
#pragma warning disable CA1416 // 验证平台兼容性
2023-03-09 11:19:48 +08:00
internal class OpcServer : IDisposable
2023-03-09 11:19:48 +08:00
{
private bool disposedValue;
private IOPCServer m_OpcServer = null;
internal OpcServer(string name, string host = "localhost")
2023-03-09 11:19:48 +08:00
{
Name = name;
2023-08-07 15:09:53 +08:00
if (string.IsNullOrEmpty(host))
{
Host = "localhost";
}
else
{
Host = host;
}
}
2023-03-09 11:19:48 +08:00
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();
2023-03-09 11:19:48 +08:00
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
2023-09-30 23:05:53 +08:00
internal OpcGroup AddGroup(string groupName)
{
return AddGroup(groupName, true, 1000, 0);
}
2023-03-09 11:19:48 +08:00
/// <returns></returns>
2023-09-30 23:05:53 +08:00
internal OpcGroup AddGroup(string groupName, bool active, int reqUpdateRate, float deadBand)
{
if (null == m_OpcServer || IsConnected == false)
2023-09-30 23:05:53 +08:00
throw new("未初始化连接!");
2023-08-07 15:09:53 +08:00
OpcGroup group = new(groupName, active, reqUpdateRate, deadBand);
Guid riid = typeof(IOPCItemMgt).GUID;
2023-09-30 23:05:53 +08:00
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)
2023-03-09 11:19:48 +08:00
{
2023-09-30 23:05:53 +08:00
group.InitIoInterfaces(group.groupPointer);
OpcGroups.Add(group);
2023-03-09 11:19:48 +08:00
}
2023-09-30 23:05:53 +08:00
else
2023-03-09 11:19:48 +08:00
{
2023-09-30 23:05:53 +08:00
throw new("添加OPC组错误OPC服务器返回null");
2023-03-09 11:19:48 +08:00
}
2023-09-30 23:05:53 +08:00
return group;
}
2023-03-09 11:19:48 +08:00
/// <summary>
/// 获取节点
/// </summary>
2023-09-30 23:05:53 +08:00
internal List<BrowseElement> Browse(string itemId = null)
{
lock (this)
2023-03-09 11:19:48 +08:00
{
if (null == m_OpcServer || IsConnected == false)
2023-09-30 23:05:53 +08:00
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),
};
2023-09-30 23:05:53 +08:00
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);
2023-09-30 23:05:53 +08:00
return browseElements?.ToList();
2023-03-09 11:19:48 +08:00
}
}
2023-03-09 11:19:48 +08:00
2023-09-30 23:05:53 +08:00
internal void Connect()
{
if (!string.IsNullOrEmpty(Host) && !string.IsNullOrEmpty(Name))
2023-03-09 11:19:48 +08:00
{
var info = Discovery.OpcDiscovery.GetOpcServer(Name, Host);
2023-09-30 23:05:53 +08:00
object o = Comn.ComInterop.CreateInstance(info.CLSID, Host);
if (o == null)
{
2023-09-30 23:05:53 +08:00
throw new(string.Format("{0}{1}无法创建com对象", info.CLSID, Host));
}
m_OpcServer = (IOPCServer)o;
IsConnected = true;
2023-03-09 11:19:48 +08:00
}
2023-09-30 23:05:53 +08:00
else
throw new("应初始化Host与Name");
}
2023-09-30 23:05:53 +08:00
/// <summary>
/// 服务器状态
/// </summary>
/// <returns></returns>
2023-09-30 23:05:53 +08:00
internal ServerStatus GetServerStatus()
{
2023-09-30 23:05:53 +08:00
ServerStatus serverStatus = null;
try
{
2023-09-30 23:05:53 +08:00
if (null == m_OpcServer || IsConnected == false)
throw new("未初始化连接!");
IntPtr statusPtr = IntPtr.Zero;
m_OpcServer?.GetStatus(out statusPtr);
OPCSERVERSTATUS status;
if (statusPtr != IntPtr.Zero)
{
2023-09-30 23:05:53 +08:00
object o = Marshal.PtrToStructure(statusPtr, typeof(OPCSERVERSTATUS));
Marshal.FreeCoTaskMem(statusPtr);
if (o != null)
{
2023-09-30 23:05:53 +08:00
status = (OPCSERVERSTATUS)o;
serverStatus = new();
2023-10-16 20:36:51 +08:00
serverStatus.Version = $"{status.wMajorVersion.ToString()}.{status.wMinorVersion.ToString()}.{status.wBuildNumber.ToString()}";
2023-09-30 23:05:53 +08:00
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;
2023-09-30 23:05:53 +08:00
return serverStatus;
}
2023-09-30 23:05:53 +08:00
else
{
IsConnected = false;
2023-09-30 23:05:53 +08:00
throw new("未知错误");
}
}
else
{
IsConnected = false;
2023-09-30 23:05:53 +08:00
throw new("未知错误");
}
}
2023-09-30 23:05:53 +08:00
finally
{
2023-09-30 23:05:53 +08:00
if (serverStatus != null)
IsConnected = true;
else
IsConnected = false;
ServerStatus = serverStatus;
}
2023-09-30 23:05:53 +08:00
}
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)
2023-03-09 11:19:48 +08:00
{
try
{
for (int i = 0; i < OpcGroups.Count; i++)
RemoveGroup(OpcGroups[i]);
}
catch
{
2023-03-09 11:19:48 +08:00
}
if (m_OpcServer != null)
2023-03-09 11:19:48 +08:00
{
Marshal.ReleaseComObject(m_OpcServer);
m_OpcServer = null;
2023-03-09 11:19:48 +08:00
}
if (disposing)
2023-03-09 11:19:48 +08:00
{
OpcGroups.Clear();
2023-03-09 11:19:48 +08:00
}
disposedValue = true;
2023-03-09 11:19:48 +08:00
}
}
2023-03-09 11:19:48 +08:00
private void ProcessResults(BrowseElement[] elements, PropertyID[] propertyIDs)
{
if (elements == null)
return;
foreach (BrowseElement element in elements)
2023-03-09 11:19:48 +08:00
{
if (element.Properties != null)
2023-03-09 11:19:48 +08:00
{
foreach (ItemProperty property in element.Properties)
2023-03-09 11:19:48 +08:00
{
if (propertyIDs != null)
{
foreach (PropertyID propertyId in propertyIDs)
{
if (property.ID.Code == propertyId.Code)
{
property.ID = propertyId;
break;
}
}
}
2023-03-09 11:19:48 +08:00
}
}
}
}
}