Files
ThingsGateway/framework/Foundation/ThingsGateway.Foundation.Adapter.OPCDA/COM/Da/OpcServer.cs
2023-10-16 20:36:51 +08:00

276 lines
8.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}
}
}
}
}
}
}