mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 07:33:58 +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;
 | ||
|                             }
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 | 
