/// <summary> /// Encodes the object in binary /// </summary> public static byte[] EncodeBinary(IEncodeable encodeable, ServiceMessageContext context) { BinaryEncoder encoder = new BinaryEncoder(context); encoder.WriteEncodeable(null, encodeable, null); return(encoder.CloseAndReturnBuffer()); }
/// <summary> /// Perform event to message binary encoding /// </summary> /// <param name="messages"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsUadp( IEnumerable <DataSetMessageModel> messages) { var notifications = GetMonitoredItemMessages(messages, MessageEncoding.Uadp); if (notifications.Count() == 0) { yield break; } var encodingContext = messages.First().ServiceMessageContext; foreach (var networkMessage in notifications) { var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, false); // is not Batch encoder.WriteEncodeable(null, networkMessage); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaBinary, MessageSchema = MessageSchemaTypes.MonitoredItemMessageBinary }; yield return(encoded); } }
/// <summary> /// Perform event to message encoding /// </summary> /// <param name="message"></param> /// <returns></returns> public IEnumerable <NetworkMessageModel> EncodeAsUadp(DataSetMessageModel message) { foreach (var notification in message.Notifications) { using (var encoder = new BinaryEncoder(message.ServiceMessageContext)) { var value = new MonitoredItemMessage { MessageContentMask = (message.Writer?.MessageSettings? .DataSetMessageContentMask).ToMonitoredItemMessageMask( message.Writer?.DataSetFieldContentMask), ApplicationUri = message.ApplicationUri, SubscriptionId = message.SubscriptionId, EndpointUrl = message.EndpointUrl, ExtensionFields = message.Writer?.DataSet?.ExtensionFields, NodeId = notification.NodeId.ToExpandedNodeId(message.ServiceMessageContext.NamespaceUris), Timestamp = message.TimeStamp ?? DateTime.UtcNow, Value = notification.Value, DisplayName = notification.DisplayName }; value.Encode(encoder); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), ContentEncoding = "utf-8", Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaBinary, MessageId = message.SequenceNumber.ToString(), MessageSchema = MessageSchemaTypes.MonitoredItemMessageBinary }; yield return(encoded); } } }
/// <summary> /// Updates the base event. /// </summary> private void UpdateBaseEvent(BaseEventState instance, EventType eventType, ONEVENTSTRUCT e) { BinaryEncoder encoder = new BinaryEncoder(ServiceMessageContext.GlobalContext); encoder.WriteString(null, e.szSource); encoder.WriteString(null, e.szConditionName); encoder.WriteInt32(null, e.ftActiveTime.dwHighDateTime); encoder.WriteInt32(null, e.ftActiveTime.dwLowDateTime); encoder.WriteInt32(null, e.dwCookie); byte[] eventId = encoder.CloseAndReturnBuffer(); NodeId eventTypeId = AeParsedNodeId.Construct(e.dwEventType, e.dwEventCategory, e.szConditionName, m_namespaceIndex); NodeId sourceNode = AeModelUtils.ConstructIdForSource(e.szSource, null, m_namespaceIndex); string sourceName = e.szSource; DateTime time = ComUtils.GetDateTime(e.ftTime); DateTime receiveTime = DateTime.UtcNow; LocalizedText message = e.szMessage; ushort severity = (ushort)e.dwSeverity; instance.TypeDefinitionId = eventTypeId; instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventId, eventId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventType, eventTypeId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceNode, sourceNode, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceName, sourceName, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Time, time, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ReceiveTime, receiveTime, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Message, message, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Severity, severity, false); }
public static byte[] ToByte(this Variant variant) { BinaryEncoder be = new BinaryEncoder(new ServiceMessageContext() { MaxArrayLength = int.MaxValue, MaxByteStringLength = int.MaxValue, MaxMessageSize = int.MaxValue, MaxStringLength = int.MaxValue }); be.WriteVariant(null, variant); return(be.CloseAndReturnBuffer()); }
/// <summary> /// Perform DataSetMessageModel to batch NetworkMessageModel using binary encoding /// </summary> /// <param name="messages"></param> /// <param name="maxEncodedSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsUadp( IEnumerable <DataSetMessageModel> messages, int maxEncodedSize) { var notifications = GetMonitoredItemMessages(messages, MessageEncoding.Uadp); if (notifications.Count() == 0) { yield break; } // take the message context of the first element since is the same for all messages var encodingContext = messages.First().ServiceMessageContext; var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 4; // array length size maxEncodedSize -= 2048; // reserve 2k for header var chunk = new Collection <MonitoredItemMessage>(); while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperEncoder = new BinaryEncoder(encodingContext); helperEncoder.WriteEncodeable(null, notification); var notificationSize = helperEncoder.CloseAndReturnBuffer().Length; messageCompleted = maxEncodedSize < (messageSize + notificationSize); if (!messageCompleted) { chunk.Add(notification); processing = current.MoveNext(); messageSize += notificationSize; } } if (!processing || messageCompleted) { var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, true); // is Batch encoder.WriteEncodeableArray(null, chunk); chunk.Clear(); messageSize = 4; var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.UaBinary, MessageSchema = MessageSchemaTypes.MonitoredItemMessageBinary }; yield return(encoded); } } }
/// <summary> /// Perform uadp encoding /// </summary> /// <param name="message"></param> /// <returns></returns> public IEnumerable <NetworkMessageModel> EncodeAsUadp(DataSetMessageModel message) { foreach (var networkMessage in GetNetworkMessages(message.YieldReturn())) { using (var encoder = new BinaryEncoder(message.ServiceMessageContext)) { networkMessage.Encode(encoder); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Uadp, MessageId = message.SequenceNumber.ToString(), MessageSchema = MessageSchemaTypes.NetworkMessageUadp }; yield return(encoded); } } }
/// <summary> /// Perform uadp encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsUadp( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Uadp, encodingContext); if (!notifications.Any()) { yield break; } var routingInfo = messages.FirstOrDefault(m => m?.WriterGroup != null)?.WriterGroup.WriterGroupId; foreach (var networkMessage in notifications) { int notificationsPerMessage = networkMessage.Messages.Sum(m => m.Payload.Count); var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, false); // is not Batch encoder.WriteEncodeable(null, networkMessage); networkMessage.Encode(encoder); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Uadp, MessageSchema = MessageSchemaTypes.NetworkMessageUadp, RoutingInfo = _enableRoutingInfo ? routingInfo : null, }; if (encoded.Body.Length > maxMessageSize) { // Message too large, drop it. NotificationsDroppedCount += (uint)notificationsPerMessage; _logger.Warning("Message too large, dropped {notificationsPerMessage} values", notificationsPerMessage); continue; } NotificationsProcessedCount += (uint)notificationsPerMessage; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; yield return(encoded); } }
/// <summary> /// Perform uadp encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeAsUadp( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Uadp, encodingContext); if (notifications.Count() == 0) { yield break; } foreach (var networkMessage in notifications) { ulong notificationsPerMessage = (ulong)networkMessage.Messages.Sum(m => m.Payload.Count); var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, false); // is not Batch encoder.WriteEncodeable(null, networkMessage); networkMessage.Encode(encoder); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Uadp, MessageSchema = MessageSchemaTypes.NetworkMessageUadp }; if (encoded.Body.Length > maxMessageSize) { // this message is too large to be processed. Drop it // TODO Trace NotificationsDroppedCount++; yield break; } NotificationsProcessedCount++; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; yield return(encoded); } }
/// <summary> /// DataSetMessage to NetworkMessage binary batched encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsUadp( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { var notifications = GetNetworkMessages(messages, MessageEncoding.Uadp); if (notifications.Count() == 0) { yield break; } // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.First().ServiceMessageContext; var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 4; // array length size maxMessageSize -= 2048; // reserve 2k for header var chunk = new Collection <NetworkMessage>(); while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperEncoder = new BinaryEncoder(encodingContext); helperEncoder.WriteEncodeable(null, notification); var notificationSize = helperEncoder.CloseAndReturnBuffer().Length; if (notificationSize > maxMessageSize) { // we cannot handle this notification. Drop it. // TODO Trace NotificationsDroppedCount++; processing = current.MoveNext(); } else { messageCompleted = maxMessageSize < (messageSize + notificationSize); if (!messageCompleted) { chunk.Add(notification); NotificationsProcessedCount++; processing = current.MoveNext(); messageSize += notificationSize; } } } if (!processing || messageCompleted) { var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, true); // is Batch encoder.WriteEncodeableArray(null, chunk); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Uadp, MessageSchema = MessageSchemaTypes.NetworkMessageUadp }; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + chunk.Count) / (MessagesProcessedCount + 1); MessagesProcessedCount++; chunk.Clear(); messageSize = 4; yield return(encoded); } } }
/// <summary> /// DataSetMessage to NetworkMessage binary batched encoding /// </summary> /// <param name="messages"></param> /// <param name="maxMessageSize"></param> /// <returns></returns> private IEnumerable <NetworkMessageModel> EncodeBatchAsUadp( IEnumerable <DataSetMessageModel> messages, int maxMessageSize) { // by design all messages are generated in the same session context, // therefore it is safe to get the first message's context var encodingContext = messages.FirstOrDefault(m => m.ServiceMessageContext != null) ?.ServiceMessageContext; var notifications = GetNetworkMessages(messages, MessageEncoding.Uadp, encodingContext); if (notifications.Count() == 0) { yield break; } var current = notifications.GetEnumerator(); var processing = current.MoveNext(); var messageSize = 4; // array length size var chunk = new Collection <NetworkMessage>(); int notificationsPerMessage = 0; while (processing) { var notification = current.Current; var messageCompleted = false; if (notification != null) { var helperEncoder = new BinaryEncoder(encodingContext); helperEncoder.WriteEncodeable(null, notification); var notificationSize = helperEncoder.CloseAndReturnBuffer().Length; notificationsPerMessage = notification.Messages.Sum(m => m.Payload.Count); if (notificationSize > maxMessageSize) { // Message too large, drop it. NotificationsDroppedCount += (uint)notificationsPerMessage; _logger.Warning("Message too large, dropped {notificationsPerMessage} values"); processing = current.MoveNext(); } else { messageCompleted = maxMessageSize < (messageSize + notificationSize); if (!messageCompleted) { chunk.Add(notification); NotificationsProcessedCount += (ulong)notificationsPerMessage; processing = current.MoveNext(); messageSize += notificationSize; } } } if (!processing || messageCompleted) { var encoder = new BinaryEncoder(encodingContext); encoder.WriteBoolean(null, true); // is Batch encoder.WriteEncodeableArray(null, chunk); var encoded = new NetworkMessageModel { Body = encoder.CloseAndReturnBuffer(), Timestamp = DateTime.UtcNow, ContentType = ContentMimeType.Uadp, MessageSchema = MessageSchemaTypes.NetworkMessageUadp }; AvgMessageSize = (AvgMessageSize * MessagesProcessedCount + encoded.Body.Length) / (MessagesProcessedCount + 1); AvgNotificationsPerMessage = (AvgNotificationsPerMessage * MessagesProcessedCount + notificationsPerMessage) / (MessagesProcessedCount + 1); MessagesProcessedCount++; chunk.Clear(); messageSize = 4; notificationsPerMessage = 0; yield return(encoded); } } }
/// <summary> /// Converts an object into a value that can be marshalled to a VARIANT. /// </summary> /// <param name="source">The object to convert.</param> /// <param name="typeInfo">The type info.</param> /// <returns>The converted object.</returns> public static object GetVARIANT(object source, TypeInfo typeInfo) { // check for invalid args. if (source == null) { return null; } try { switch (typeInfo.BuiltInType) { case BuiltInType.Boolean: case BuiltInType.Byte: case BuiltInType.Int16: case BuiltInType.UInt16: case BuiltInType.Int32: case BuiltInType.UInt32: case BuiltInType.Int64: case BuiltInType.UInt64: case BuiltInType.Float: case BuiltInType.Double: case BuiltInType.String: case BuiltInType.DateTime: { return source; } case BuiltInType.ByteString: { if (typeInfo.ValueRank < 0) { return source; } return VariantToObjectArray((Array)source); } case BuiltInType.Guid: case BuiltInType.LocalizedText: case BuiltInType.QualifiedName: case BuiltInType.NodeId: case BuiltInType.ExpandedNodeId: case BuiltInType.XmlElement: { return TypeInfo.Cast(source, typeInfo, BuiltInType.String); } case BuiltInType.StatusCode: { return TypeInfo.Cast(source, typeInfo, BuiltInType.UInt32); } case BuiltInType.Variant: { if (typeInfo.ValueRank < 0) { return GetVARIANT(((Variant)source).Value); } return VariantToObjectArray((Array)source); } case BuiltInType.ExtensionObject: { if (typeInfo.ValueRank < 0) { byte[] body = null; ExtensionObject extension = (ExtensionObject)source; switch (extension.Encoding) { case ExtensionObjectEncoding.Binary: { body = (byte[])extension.Body; break; } case ExtensionObjectEncoding.Xml: { body = new UTF8Encoding().GetBytes(((XmlElement)extension.Body).OuterXml); break; } case ExtensionObjectEncoding.EncodeableObject: { BinaryEncoder encoder = new BinaryEncoder(ServiceMessageContext.GlobalContext); encoder.WriteEncodeable(null, (IEncodeable)extension.Body, null); body = encoder.CloseAndReturnBuffer(); break; } } return body; } return VariantToObjectArray((Array)source); } case BuiltInType.DataValue: case BuiltInType.DiagnosticInfo: { return "(unsupported)"; } } } catch (Exception e) { return e.Message; } // no conversion required. return source; }
/// <summary> /// Updates the base event. /// </summary> private void UpdateBaseEvent(BaseEventState instance, EventType eventType, ONEVENTSTRUCT e) { BinaryEncoder encoder = new BinaryEncoder(ServiceMessageContext.GlobalContext); encoder.WriteString(null, e.szSource); encoder.WriteString(null, e.szConditionName); encoder.WriteInt32(null, e.ftActiveTime.dwHighDateTime); encoder.WriteInt32(null, e.ftActiveTime.dwLowDateTime); encoder.WriteInt32(null, e.dwCookie); byte[] eventId = encoder.CloseAndReturnBuffer(); NodeId eventTypeId = AeParsedNodeId.Construct(e.dwEventType, e.dwEventCategory, e.szConditionName, m_namespaceIndex); NodeId sourceNode = AeModelUtils.ConstructIdForSource(e.szSource, null, m_namespaceIndex); string sourceName = e.szSource; DateTime time = ComUtils.GetDateTime(e.ftTime); DateTime receiveTime = DateTime.UtcNow; LocalizedText message = e.szMessage; ushort severity = (ushort)e.dwSeverity; instance.TypeDefinitionId = eventTypeId; instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventId, eventId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.EventType, eventTypeId, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceNode, sourceNode, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.SourceName, sourceName, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Time, time, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.ReceiveTime, receiveTime, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Message, message, false); instance.SetChildValue(m_defaultContext, Opc.Ua.BrowseNames.Severity, severity, false); }
/// <summary> /// Converts a remote value to a local value. /// </summary> /// <param name="srcValue">The remote value.</param> /// <param name="srcType">The data type of the remote value.</param> /// <param name="dstType">The data type of the local value.</param> /// <returns>The local value.</returns> private object ConvertRemoteToLocal(object srcValue, BuiltInType srcType, BuiltInType dstType) { // check for null. if (srcValue == null) { return(null); } // must determine the type from the source if the containing array is a variant. if (srcType == BuiltInType.Variant) { TypeInfo typeInfo = TypeInfo.Construct(srcValue); srcType = typeInfo.BuiltInType; if (typeInfo.ValueRank != ValueRanks.Scalar) { return(TypeInfo.CastArray((Array)srcValue, srcType, BuiltInType.Null, ConvertRemoteToLocal)); } } // no conversion by default. object dstValue = srcValue; // apply different conversions depending on the data type. switch (srcType) { case BuiltInType.Guid: { dstValue = ((Uuid)srcValue).ToString(); break; } case BuiltInType.XmlElement: { dstValue = ((XmlElement)srcValue).OuterXml; break; } case BuiltInType.NodeId: { dstValue = GetLocalItemId((NodeId)srcValue); break; } case BuiltInType.ExpandedNodeId: { ExpandedNodeId nodeId = GetLocaleExpandedNodeId((ExpandedNodeId)srcValue); dstValue = nodeId.ToString(); break; } case BuiltInType.QualifiedName: { dstValue = GetLocalBrowseName((QualifiedName)srcValue); break; } case BuiltInType.LocalizedText: { dstValue = ((LocalizedText)srcValue).Text; break; } case BuiltInType.StatusCode: { dstValue = ((StatusCode)srcValue).Code; break; } case BuiltInType.ExtensionObject: { BinaryEncoder encoder = new BinaryEncoder(m_localMessageContext); encoder.WriteExtensionObject(null, (ExtensionObject)srcValue); dstValue = encoder.CloseAndReturnBuffer(); break; } case BuiltInType.Variant: { dstValue = ((Variant)srcValue).Value; break; } default: { if (dstType != srcType && dstType != BuiltInType.Variant && dstType != BuiltInType.Null) { throw ComUtils.CreateComException(ResultIds.E_BADTYPE); } break; } } // all done. return(dstValue); }
/// <summary> /// Encodes the object in binary /// </summary> public static byte[] EncodeBinary(IEncodeable encodeable, ServiceMessageContext context) { BinaryEncoder encoder = new BinaryEncoder(context); encoder.WriteEncodeable(null, encodeable, null); return encoder.CloseAndReturnBuffer(); }
/// <summary> /// Converts a remote value to a local value. /// </summary> /// <param name="srcValue">The remote value.</param> /// <param name="srcType">The data type of the remote value.</param> /// <param name="dstType">The data type of the local value.</param> /// <returns>The local value.</returns> private object ConvertRemoteToLocal(object srcValue, BuiltInType srcType, BuiltInType dstType) { // check for null. if (srcValue == null) { return null; } // must determine the type from the source if the containing array is a variant. if (srcType == BuiltInType.Variant) { TypeInfo typeInfo = TypeInfo.Construct(srcValue); srcType = typeInfo.BuiltInType; if (typeInfo.ValueRank != ValueRanks.Scalar) { return TypeInfo.CastArray((Array)srcValue, srcType, BuiltInType.Null, ConvertRemoteToLocal); } } // no conversion by default. object dstValue = srcValue; // apply different conversions depending on the data type. switch (srcType) { case BuiltInType.Guid: { dstValue = ((Uuid)srcValue).ToString(); break; } case BuiltInType.XmlElement: { dstValue = ((XmlElement)srcValue).OuterXml; break; } case BuiltInType.NodeId: { dstValue = GetLocalItemId((NodeId)srcValue); break; } case BuiltInType.ExpandedNodeId: { ExpandedNodeId nodeId = GetLocaleExpandedNodeId((ExpandedNodeId)srcValue); dstValue = nodeId.ToString(); break; } case BuiltInType.QualifiedName: { dstValue = GetLocalBrowseName((QualifiedName)srcValue); break; } case BuiltInType.LocalizedText: { dstValue = ((LocalizedText)srcValue).Text; break; } case BuiltInType.StatusCode: { dstValue = ((StatusCode)srcValue).Code; break; } case BuiltInType.ExtensionObject: { BinaryEncoder encoder = new BinaryEncoder(m_localMessageContext); encoder.WriteExtensionObject(null, (ExtensionObject)srcValue); dstValue = encoder.CloseAndReturnBuffer(); break; } case BuiltInType.Variant: { dstValue = ((Variant)srcValue).Value; break; } default: { if (dstType != srcType && dstType != BuiltInType.Variant && dstType != BuiltInType.Null) { throw ComUtils.CreateComException(ResultIds.E_BADTYPE); } break; } } // all done. return dstValue; }