using System; using System.Runtime.InteropServices; using ArchestrA.MxAccess; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Backend.MxAccess; /// /// Concrete backed by a real LMXProxyServer COM object. /// Port of v1 MxProxyAdapter. Must only be constructed on an STA thread /// — the StaPump owns this instance. /// public sealed class MxProxyAdapter : IMxProxy, IDisposable { private LMXProxyServer? _lmxProxy; public event MxDataChangeHandler? OnDataChange; public event MxWriteCompleteHandler? OnWriteComplete; public int Register(string clientName) { _lmxProxy = new LMXProxyServer(); _lmxProxy.OnDataChange += ProxyOnDataChange; _lmxProxy.OnWriteComplete += ProxyOnWriteComplete; var handle = _lmxProxy.Register(clientName); if (handle <= 0) throw new InvalidOperationException($"LMXProxyServer.Register returned invalid handle: {handle}"); return handle; } public void Unregister(int handle) { if (_lmxProxy is null) return; try { _lmxProxy.OnDataChange -= ProxyOnDataChange; _lmxProxy.OnWriteComplete -= ProxyOnWriteComplete; _lmxProxy.Unregister(handle); } finally { // ReleaseComObject loop until refcount = 0 — the Tier C SafeHandle wraps this in // production; here the lifetime is owned by the surrounding MxAccessHandle. while (Marshal.IsComObject(_lmxProxy) && Marshal.ReleaseComObject(_lmxProxy) > 0) { } _lmxProxy = null; } } public int AddItem(int handle, string address) => _lmxProxy!.AddItem(handle, address); public void RemoveItem(int handle, int itemHandle) => _lmxProxy!.RemoveItem(handle, itemHandle); public void AdviseSupervisory(int handle, int itemHandle) => _lmxProxy!.AdviseSupervisory(handle, itemHandle); public void UnAdviseSupervisory(int handle, int itemHandle) => _lmxProxy!.UnAdvise(handle, itemHandle); public void Write(int handle, int itemHandle, object value, int securityClassification) => _lmxProxy!.Write(handle, itemHandle, value, securityClassification); private void ProxyOnDataChange(int hLMXServerHandle, int phItemHandle, object pvItemValue, int pwItemQuality, object pftItemTimeStamp, ref MXSTATUS_PROXY[] ItemStatus) => OnDataChange?.Invoke(hLMXServerHandle, phItemHandle, pvItemValue, pwItemQuality, pftItemTimeStamp, ref ItemStatus); private void ProxyOnWriteComplete(int hLMXServerHandle, int phItemHandle, ref MXSTATUS_PROXY[] ItemStatus) => OnWriteComplete?.Invoke(hLMXServerHandle, phItemHandle, ref ItemStatus); public void Dispose() => Unregister(0); }