#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved //----------------------------------------------------------------------------- // Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved // Web: https://www.technosoftware.com // // The source code in this file is covered under a dual-license scenario: // - Owner of a purchased license: SCLA 1.0 // - GPL V3: everybody else // // SCLA license terms accompanied with this source code. // See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf // // GNU General Public License as published by the Free Software Foundation; // version 3 of the License are accompanied with this source code. // See https://technosoftware.com/license/GPLv3License.txt // // This source code is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. //----------------------------------------------------------------------------- #endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved #region Using Directives using System; using System.Collections; using System.Runtime.InteropServices; using System.Reflection; using Technosoftware.DaAeHdaClient.Da; #endregion #pragma warning disable 0618 namespace Technosoftware.DaAeHdaClient.Com.Da { /// /// Contains state information for a single asynchronous Technosoftware.DaAeHdaClient.Com.Da.Interop. /// internal class Interop { /// /// Converts a standard FILETIME to an OpcRcw.Da.FILETIME structure. /// internal static OpcRcw.Da.FILETIME Convert(FILETIME input) { var output = new OpcRcw.Da.FILETIME(); output.dwLowDateTime = input.dwLowDateTime; output.dwHighDateTime = input.dwHighDateTime; return output; } /// /// Converts an OpcRcw.Da.FILETIME to a standard FILETIME structure. /// internal static FILETIME Convert(OpcRcw.Da.FILETIME input) { var output = new FILETIME(); output.dwLowDateTime = input.dwLowDateTime; output.dwHighDateTime = input.dwHighDateTime; return output; } /// /// Allocates and marshals a OPCSERVERSTATUS structure. /// internal static OpcRcw.Da.OPCSERVERSTATUS GetServerStatus(OpcServerStatus input, int groupCount) { var output = new OpcRcw.Da.OPCSERVERSTATUS(); if (input != null) { output.szVendorInfo = input.VendorInfo; output.wMajorVersion = 0; output.wMinorVersion = 0; output.wBuildNumber = 0; output.dwServerState = (OpcRcw.Da.OPCSERVERSTATE)input.ServerState; output.ftStartTime = Convert(Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(input.StartTime)); output.ftCurrentTime = Convert(Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(input.CurrentTime)); output.ftLastUpdateTime = Convert(Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(input.LastUpdateTime)); output.dwBandWidth = -1; output.dwGroupCount = groupCount; output.wReserved = 0; if (input.ProductVersion != null) { var versions = input.ProductVersion.Split(new char[] { '.' }); if (versions.Length > 0) { try { output.wMajorVersion = System.Convert.ToInt16(versions[0]); } catch { output.wMajorVersion = 0; } } if (versions.Length > 1) { try { output.wMinorVersion = System.Convert.ToInt16(versions[1]); } catch { output.wMinorVersion = 0; } } output.wBuildNumber = 0; for (var ii = 2; ii < versions.Length; ii++) { try { output.wBuildNumber = (short)(output.wBuildNumber * 100 + System.Convert.ToInt16(versions[ii])); } catch { output.wBuildNumber = 0; break; } } } } return output; } /// /// Unmarshals and deallocates a OPCSERVERSTATUS structure. /// internal static OpcServerStatus GetServerStatus(ref IntPtr pInput, bool deallocate) { OpcServerStatus output = null; if (pInput != IntPtr.Zero) { var status = (OpcRcw.Da.OPCSERVERSTATUS)Marshal.PtrToStructure(pInput, typeof(OpcRcw.Da.OPCSERVERSTATUS)); output = new OpcServerStatus(); output.VendorInfo = status.szVendorInfo; output.ProductVersion = string.Format("{0}.{1}.{2}", status.wMajorVersion, status.wMinorVersion, status.wBuildNumber); output.ServerState = (OpcServerState)status.dwServerState; output.StatusInfo = null; output.StartTime = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(status.ftStartTime)); output.CurrentTime = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(status.ftCurrentTime)); output.LastUpdateTime = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(status.ftLastUpdateTime)); if (deallocate) { Marshal.DestroyStructure(pInput, typeof(OpcRcw.Da.OPCSERVERSTATUS)); Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return output; } /// /// Converts a browseFilter values to the COM equivalent. /// internal static OpcRcw.Da.OPCBROWSEFILTER GetBrowseFilter(TsCDaBrowseFilter input) { switch (input) { case TsCDaBrowseFilter.All: return OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL; case TsCDaBrowseFilter.Branch: return OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_BRANCHES; case TsCDaBrowseFilter.Item: return OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_ITEMS; } return OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL; } /// /// Converts a browseFilter values from the COM equivalent. /// internal static TsCDaBrowseFilter GetBrowseFilter(OpcRcw.Da.OPCBROWSEFILTER input) { switch (input) { case OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_ALL: return TsCDaBrowseFilter.All; case OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_BRANCHES: return TsCDaBrowseFilter.Branch; case OpcRcw.Da.OPCBROWSEFILTER.OPC_BROWSE_FILTER_ITEMS: return TsCDaBrowseFilter.Item; } return TsCDaBrowseFilter.All; } /// /// Allocates and marshals an array of HRESULT codes. /// internal static IntPtr GetHRESULTs(IOpcResult[] results) { // extract error codes from results. var errors = new int[results.Length]; for (var ii = 0; ii < results.Length; ii++) { if (results[ii] != null) { errors[ii] = Technosoftware.DaAeHdaClient.Com.Interop.GetResultID(results[ii].Result); } else { errors[ii] = Result.E_INVALIDHANDLE; } } // marshal error codes. var pErrors = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)) * results.Length); Marshal.Copy(errors, 0, pErrors, results.Length); // return results. return pErrors; } /// /// Unmarshals and deallocates an array of OPCBROWSEELEMENT structures. /// internal static TsCDaBrowseElement[] GetBrowseElements(ref IntPtr pInput, int count, bool deallocate) { TsCDaBrowseElement[] output = null; if (pInput != IntPtr.Zero && count > 0) { output = new TsCDaBrowseElement[count]; var pos = pInput; for (var ii = 0; ii < count; ii++) { output[ii] = GetBrowseElement(pos, deallocate); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCBROWSEELEMENT))); } if (deallocate) { Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return output; } /// /// Allocates and marshals an array of OPCBROWSEELEMENT structures. /// internal static IntPtr GetBrowseElements(TsCDaBrowseElement[] input, bool propertiesRequested) { var output = IntPtr.Zero; if (input != null && input.Length > 0) { output = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(OpcRcw.Da.OPCBROWSEELEMENT)) * input.Length); var pos = output; for (var ii = 0; ii < input.Length; ii++) { var element = GetBrowseElement(input[ii], propertiesRequested); Marshal.StructureToPtr(element, pos, false); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCBROWSEELEMENT))); } } return output; } /// /// Unmarshals and deallocates a OPCBROWSEELEMENT structures. /// internal static TsCDaBrowseElement GetBrowseElement(IntPtr pInput, bool deallocate) { TsCDaBrowseElement output = null; if (pInput != IntPtr.Zero) { var element = (OpcRcw.Da.OPCBROWSEELEMENT)Marshal.PtrToStructure(pInput, typeof(OpcRcw.Da.OPCBROWSEELEMENT)); output = new TsCDaBrowseElement(); output.Name = element.szName; output.ItemPath = null; output.ItemName = element.szItemID; output.IsItem = ((element.dwFlagValue & OpcRcw.Da.Constants.OPC_BROWSE_ISITEM) != 0); output.HasChildren = ((element.dwFlagValue & OpcRcw.Da.Constants.OPC_BROWSE_HASCHILDREN) != 0); output.Properties = GetItemProperties(ref element.ItemProperties, deallocate); if (deallocate) { Marshal.DestroyStructure(pInput, typeof(OpcRcw.Da.OPCBROWSEELEMENT)); } } return output; } /// /// Allocates and marshals an OPCBROWSEELEMENT structure. /// internal static OpcRcw.Da.OPCBROWSEELEMENT GetBrowseElement(TsCDaBrowseElement input, bool propertiesRequested) { var output = new OpcRcw.Da.OPCBROWSEELEMENT(); if (input != null) { output.szName = input.Name; output.szItemID = input.ItemName; output.dwFlagValue = 0; output.ItemProperties = GetItemProperties(input.Properties); if (input.IsItem) { output.dwFlagValue |= OpcRcw.Da.Constants.OPC_BROWSE_ISITEM; } if (input.HasChildren) { output.dwFlagValue |= OpcRcw.Da.Constants.OPC_BROWSE_HASCHILDREN; } } return output; } /// /// Creates an array of property codes. /// internal static int[] GetPropertyIDs(TsDaPropertyID[] propertyIDs) { var output = new ArrayList(); if (propertyIDs != null) { foreach (var propertyID in propertyIDs) { output.Add(propertyID.Code); } } return (int[])output.ToArray(typeof(int)); } /// /// Creates an array of property codes. /// internal static TsDaPropertyID[] GetPropertyIDs(int[] propertyIDs) { var output = new ArrayList(); if (propertyIDs != null) { foreach (var propertyID in propertyIDs) { output.Add(GetPropertyID(propertyID)); } } return (TsDaPropertyID[])output.ToArray(typeof(TsDaPropertyID)); } /// /// Unmarshals and deallocates an array of OPCITEMPROPERTIES structures. /// internal static TsCDaItemPropertyCollection[] GetItemPropertyCollections(ref IntPtr pInput, int count, bool deallocate) { TsCDaItemPropertyCollection[] output = null; if (pInput != IntPtr.Zero && count > 0) { output = new TsCDaItemPropertyCollection[count]; var pos = pInput; for (var ii = 0; ii < count; ii++) { var list = (OpcRcw.Da.OPCITEMPROPERTIES)Marshal.PtrToStructure(pos, typeof(OpcRcw.Da.OPCITEMPROPERTIES)); output[ii] = new TsCDaItemPropertyCollection(); output[ii].ItemPath = null; output[ii].ItemName = null; output[ii].Result = Technosoftware.DaAeHdaClient.Com.Interop.GetResultID(list.hrErrorID); var properties = GetItemProperties(ref list, deallocate); if (properties != null) { output[ii].AddRange(properties); } if (deallocate) { Marshal.DestroyStructure(pos, typeof(OpcRcw.Da.OPCITEMPROPERTIES)); } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTIES))); } if (deallocate) { Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return output; } /// /// Allocates and marshals an array of OPCITEMPROPERTIES structures. /// internal static IntPtr GetItemPropertyCollections(TsCDaItemPropertyCollection[] input) { var output = IntPtr.Zero; if (input != null && input.Length > 0) { output = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTIES)) * input.Length); var pos = output; for (var ii = 0; ii < input.Length; ii++) { var properties = new OpcRcw.Da.OPCITEMPROPERTIES(); if (input[ii].Count > 0) { properties = GetItemProperties((TsCDaItemProperty[])input[ii].ToArray(typeof(TsCDaItemProperty))); } properties.hrErrorID = Technosoftware.DaAeHdaClient.Com.Interop.GetResultID(input[ii].Result); Marshal.StructureToPtr(properties, pos, false); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTIES))); } } return output; } /// /// Unmarshals and deallocates a OPCITEMPROPERTIES structures. /// internal static TsCDaItemProperty[] GetItemProperties(ref OpcRcw.Da.OPCITEMPROPERTIES input, bool deallocate) { TsCDaItemProperty[] output = null; if (input.dwNumProperties > 0) { output = new TsCDaItemProperty[input.dwNumProperties]; var pos = input.pItemProperties; for (var ii = 0; ii < output.Length; ii++) { try { output[ii] = GetItemProperty(pos, deallocate); } catch (Exception e) { output[ii] = new TsCDaItemProperty(); output[ii].Description = e.Message; output[ii].Result = OpcResult.E_FAIL; } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTY))); } if (deallocate) { Marshal.FreeCoTaskMem(input.pItemProperties); input.pItemProperties = IntPtr.Zero; } } return output; } /// /// Allocates and marshals an array of OPCITEMPROPERTIES structures. /// internal static OpcRcw.Da.OPCITEMPROPERTIES GetItemProperties(TsCDaItemProperty[] input) { var output = new OpcRcw.Da.OPCITEMPROPERTIES(); if (input != null && input.Length > 0) { output.hrErrorID = Result.S_OK; output.dwReserved = 0; output.dwNumProperties = input.Length; output.pItemProperties = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTY)) * input.Length); var error = false; var pos = output.pItemProperties; for (var ii = 0; ii < input.Length; ii++) { var property = GetItemProperty(input[ii]); Marshal.StructureToPtr(property, pos, false); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMPROPERTY))); if (input[ii].Result.Failed()) { error = true; } } // set flag indicating one or more properties contained errors. if (error) { output.hrErrorID = Result.S_FALSE; } } return output; } /// /// Unmarshals and deallocates a OPCITEMPROPERTY structures. /// internal static TsCDaItemProperty GetItemProperty(IntPtr pInput, bool deallocate) { TsCDaItemProperty output = null; if (pInput != IntPtr.Zero) { try { var property = (OpcRcw.Da.OPCITEMPROPERTY)Marshal.PtrToStructure(pInput, typeof(OpcRcw.Da.OPCITEMPROPERTY)); output = new TsCDaItemProperty(); output.ID = GetPropertyID(property.dwPropertyID); output.Description = property.szDescription; output.DataType = Technosoftware.DaAeHdaClient.Com.Interop.GetType((VarEnum)property.vtDataType); output.ItemPath = null; output.ItemName = property.szItemID; output.Value = UnmarshalPropertyValue(output.ID, property.vValue); output.Result = Technosoftware.DaAeHdaClient.Com.Interop.GetResultID(property.hrErrorID); // convert COM DA code to unified DA code. if (property.hrErrorID == Result.E_BADRIGHTS) output.Result = new OpcResult(OpcResult.Da.E_WRITEONLY, Result.E_BADRIGHTS); } catch (Exception) { } if (deallocate) { Marshal.DestroyStructure(pInput, typeof(OpcRcw.Da.OPCITEMPROPERTY)); } } return output; } /// /// Allocates and marshals an arary of OPCITEMPROPERTY structures. /// internal static OpcRcw.Da.OPCITEMPROPERTY GetItemProperty(TsCDaItemProperty input) { var output = new OpcRcw.Da.OPCITEMPROPERTY(); if (input != null) { output.dwPropertyID = input.ID.Code; output.szDescription = input.Description; output.vtDataType = (short)Technosoftware.DaAeHdaClient.Com.Interop.GetType(input.DataType); output.vValue = MarshalPropertyValue(input.ID, input.Value); output.wReserved = 0; output.hrErrorID = Technosoftware.DaAeHdaClient.Com.Interop.GetResultID(input.Result); // set the property data type. var description = TsDaPropertyDescription.Find(input.ID); if (description != null) { output.vtDataType = (short)Technosoftware.DaAeHdaClient.Com.Interop.GetType(description.Type); } // convert unified DA code to COM DA code. if (input.Result == OpcResult.Da.E_WRITEONLY) output.hrErrorID = Result.E_BADRIGHTS; } return output; } /// public static TsDaPropertyID GetPropertyID(int input) { var fields = typeof(TsDaProperty).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (var field in fields) { var property = (TsDaPropertyID)field.GetValue(typeof(TsDaPropertyID)); if (input == property.Code) { return property; } } return new TsDaPropertyID(input); } /// /// Converts the property value to a type supported by the unified interface. /// internal static object UnmarshalPropertyValue(TsDaPropertyID propertyID, object input) { if (input == null) return null; try { if (propertyID == TsDaProperty.DATATYPE) { return Technosoftware.DaAeHdaClient.Com.Interop.GetType((VarEnum)System.Convert.ToUInt16(input)); } if (propertyID == TsDaProperty.ACCESSRIGHTS) { switch (System.Convert.ToInt32(input)) { case OpcRcw.Da.Constants.OPC_READABLE: return TsDaAccessRights.Readable; case OpcRcw.Da.Constants.OPC_WRITEABLE: return TsDaAccessRights.Writable; case OpcRcw.Da.Constants.OPC_READABLE | OpcRcw.Da.Constants.OPC_WRITEABLE: { return TsDaAccessRights.ReadWritable; } } return null; } if (propertyID == TsDaProperty.EUTYPE) { switch ((OpcRcw.Da.OPCEUTYPE)input) { case OpcRcw.Da.OPCEUTYPE.OPC_NOENUM: return TsDaEuType.NoEnum; case OpcRcw.Da.OPCEUTYPE.OPC_ANALOG: return TsDaEuType.Analog; case OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED: return TsDaEuType.Enumerated; } return null; } if (propertyID == TsDaProperty.QUALITY) { return new TsCDaQuality(System.Convert.ToInt16(input)); } // convert UTC time in property to local time for the unified DA interface. if (propertyID == TsDaProperty.TIMESTAMP) { if (input.GetType() == typeof(DateTime)) { var dateTime = (DateTime)input; if (dateTime != DateTime.MinValue) { return dateTime.ToLocalTime(); } return dateTime; } } } catch { } return input; } /// /// Converts the property value to a type supported by COM-DA interface. /// internal static object MarshalPropertyValue(TsDaPropertyID propertyID, object input) { if (input == null) return null; try { if (propertyID == TsDaProperty.DATATYPE) { return (short)Technosoftware.DaAeHdaClient.Com.Interop.GetType((Type)input); } if (propertyID == TsDaProperty.ACCESSRIGHTS) { switch ((TsDaAccessRights)input) { case TsDaAccessRights.Readable: return OpcRcw.Da.Constants.OPC_READABLE; case TsDaAccessRights.Writable: return OpcRcw.Da.Constants.OPC_WRITEABLE; case TsDaAccessRights.ReadWritable: return OpcRcw.Da.Constants.OPC_READABLE | OpcRcw.Da.Constants.OPC_WRITEABLE; } return null; } if (propertyID == TsDaProperty.EUTYPE) { switch ((TsDaEuType)input) { case TsDaEuType.NoEnum: return OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; case TsDaEuType.Analog: return OpcRcw.Da.OPCEUTYPE.OPC_ANALOG; case TsDaEuType.Enumerated: return OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED; } return null; } if (propertyID == TsDaProperty.QUALITY) { return ((TsCDaQuality)input).GetCode(); } // convert local time in property to UTC time for the COM DA interface. if (propertyID == TsDaProperty.TIMESTAMP) { if (input.GetType() == typeof(DateTime)) { var dateTime = (DateTime)input; if (dateTime != DateTime.MinValue) { return dateTime.ToUniversalTime(); } return dateTime; } } } catch { } return input; } /// /// Converts an array of item values to an array of OPCITEMVQT objects. /// internal static OpcRcw.Da.OPCITEMVQT[] GetOPCITEMVQTs(TsCDaItemValue[] input) { OpcRcw.Da.OPCITEMVQT[] output = null; if (input != null) { output = new OpcRcw.Da.OPCITEMVQT[input.Length]; for (var ii = 0; ii < input.Length; ii++) { output[ii] = new OpcRcw.Da.OPCITEMVQT(); var timestamp = (input[ii].TimestampSpecified) ? input[ii].Timestamp : DateTime.MinValue; output[ii].vDataValue = Technosoftware.DaAeHdaClient.Com.Interop.GetVARIANT(input[ii].Value); output[ii].bQualitySpecified = (input[ii].QualitySpecified) ? 1 : 0; output[ii].wQuality = (input[ii].QualitySpecified) ? input[ii].Quality.GetCode() : (short)0; output[ii].bTimeStampSpecified = (input[ii].TimestampSpecified) ? 1 : 0; output[ii].ftTimeStamp = Convert(Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(timestamp)); } } return output; } /// /// Converts an array of item objects to an array of GetOPCITEMDEF objects. /// internal static OpcRcw.Da.OPCITEMDEF[] GetOPCITEMDEFs(TsCDaItem[] input) { OpcRcw.Da.OPCITEMDEF[] output = null; if (input != null) { output = new OpcRcw.Da.OPCITEMDEF[input.Length]; for (var ii = 0; ii < input.Length; ii++) { output[ii] = new OpcRcw.Da.OPCITEMDEF(); output[ii].szItemID = input[ii].ItemName; output[ii].szAccessPath = (input[ii].ItemPath == null) ? string.Empty : input[ii].ItemPath; output[ii].bActive = (input[ii].ActiveSpecified) ? ((input[ii].Active) ? 1 : 0) : 1; output[ii].vtRequestedDataType = (short)Technosoftware.DaAeHdaClient.Com.Interop.GetType(input[ii].ReqType); output[ii].hClient = 0; output[ii].dwBlobSize = 0; output[ii].pBlob = IntPtr.Zero; } } return output; } /// /// Unmarshals and deallocates a OPCITEMSTATE structures. /// internal static TsCDaItemValue[] GetItemValues(ref IntPtr pInput, int count, bool deallocate) { TsCDaItemValue[] output = null; if (pInput != IntPtr.Zero && count > 0) { output = new TsCDaItemValue[count]; var pos = pInput; for (var ii = 0; ii < count; ii++) { var result = (OpcRcw.Da.OPCITEMSTATE)Marshal.PtrToStructure(pos, typeof(OpcRcw.Da.OPCITEMSTATE)); output[ii] = new TsCDaItemValue(); output[ii].ClientHandle = result.hClient; output[ii].Value = result.vDataValue; output[ii].Quality = new TsCDaQuality(result.wQuality); output[ii].QualitySpecified = true; output[ii].Timestamp = Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(Convert(result.ftTimeStamp)); output[ii].TimestampSpecified = output[ii].Timestamp != DateTime.MinValue; if (deallocate) { Marshal.DestroyStructure(pos, typeof(OpcRcw.Da.OPCITEMSTATE)); } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMSTATE))); } if (deallocate) { Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return output; } /// /// Unmarshals and deallocates a OPCITEMRESULT structures. /// internal static int[] GetItemResults(ref IntPtr pInput, int count, bool deallocate) { int[] output = null; if (pInput != IntPtr.Zero && count > 0) { output = new int[count]; var pos = pInput; for (var ii = 0; ii < count; ii++) { var result = (OpcRcw.Da.OPCITEMRESULT)Marshal.PtrToStructure(pos, typeof(OpcRcw.Da.OPCITEMRESULT)); output[ii] = result.hServer; if (deallocate) { Marshal.FreeCoTaskMem(result.pBlob); result.pBlob = IntPtr.Zero; Marshal.DestroyStructure(pos, typeof(OpcRcw.Da.OPCITEMRESULT)); } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMRESULT))); } if (deallocate) { Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return output; } /// /// Allocates and marshals an array of OPCBROWSEELEMENT structures. /// internal static IntPtr GetItemStates(TsCDaItemValueResult[] input) { var output = IntPtr.Zero; if (input != null && input.Length > 0) { output = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMSTATE)) * input.Length); var pos = output; for (var ii = 0; ii < input.Length; ii++) { var item = new OpcRcw.Da.OPCITEMSTATE(); item.hClient = System.Convert.ToInt32(input[ii].ClientHandle); item.vDataValue = input[ii].Value; item.wQuality = (input[ii].QualitySpecified) ? input[ii].Quality.GetCode() : (short)0; item.ftTimeStamp = Convert(Technosoftware.DaAeHdaClient.Com.Interop.GetFILETIME(input[ii].Timestamp)); item.wReserved = 0; Marshal.StructureToPtr(item, pos, false); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCITEMSTATE))); } } return output; } } }