Opc.Ua.Com.ComUtils.ChangeTypeForCOM C# (CSharp) Method

ChangeTypeForCOM() public static method

Converts a value to the specified type using COM conversion rules.
public static ChangeTypeForCOM ( object source, VarEnum sourceType, VarEnum targetType, object &target ) : int
source object
sourceType VarEnum
targetType VarEnum
target object
return int
		public static int ChangeTypeForCOM(object source, VarEnum sourceType, VarEnum targetType, out object target)
		{
            target = source;
            
            // check for trivial case.
            if (sourceType == targetType)
            {
                return ResultIds.S_OK;
            }

			// check for conversions to date time from string.
            string stringValue = source as string;

			if (stringValue != null && targetType == VarEnum.VT_DATE)
			{
				try   
                { 
                    target = System.Convert.ToDateTime(stringValue);
                    return ResultIds.S_OK;
                }
				catch 
                {
                    target = null;
                    return ResultIds.DISP_E_OVERFLOW;
                }
			}

			// check for conversions from date time to boolean.
            if (sourceType == VarEnum.VT_DATE && targetType == VarEnum.VT_BOOL)
			{
				target = !(new DateTime(1899, 12, 30, 0, 0, 0).Equals((DateTime)source));
                return ResultIds.S_OK;
			}

			// check for conversions from float to double.
            if (sourceType == VarEnum.VT_R4 && targetType == VarEnum.VT_R8)
			{
				target = System.Convert.ToDouble((float)source);
                return ResultIds.S_OK;
			}

			// check for array conversion.
            Array array = source as Array;
            bool targetIsArray = ((targetType & VarEnum.VT_ARRAY) != 0);

			if (array != null && targetIsArray)
			{
                VarEnum elementType = (VarEnum)((short)targetType & ~(short)VarEnum.VT_ARRAY);

                Array convertedArray = Array.CreateInstance(GetSystemType((short)elementType), array.Length);

                for (int ii = 0; ii < array.Length; ii++)
                {
                    object elementValue = null;
                    int error = ChangeTypeForCOM(array.GetValue(ii), elementType, out elementValue);

                    if (error < 0)
                    {
                        target = null;
                        return ResultIds.DISP_E_OVERFLOW;
                    }
                        
                    convertedArray.SetValue(elementValue, ii);
                }

				target = convertedArray;
                return ResultIds.S_OK;
			}
			else if (array == null && !targetIsArray)
			{
				IntPtr pvargDest = Marshal.AllocCoTaskMem(16);
				IntPtr pvarSrc   = Marshal.AllocCoTaskMem(16);
				
				VariantInit(pvargDest);
				VariantInit(pvarSrc);

				Marshal.GetNativeVariantForObject(source, pvarSrc);

				try
				{
					// change type.
					int error = VariantChangeTypeEx(
						pvargDest, 
						pvarSrc, 
						Thread.CurrentThread.CurrentCulture.LCID, 
						VARIANT_NOVALUEPROP | VARIANT_ALPHABOOL, 
						(short)targetType);

					// check error code.
					if (error != 0)
					{
                        target = null;
                        return error;
					}

					// unmarshal result.
					object result = Marshal.GetObjectForNativeVariant(pvargDest);
					
					// check for invalid unsigned <=> signed conversions.
					switch (targetType)
					{
						case VarEnum.VT_I1:
						case VarEnum.VT_I2:
						case VarEnum.VT_I4:
						case VarEnum.VT_I8:
						case VarEnum.VT_UI1:
						case VarEnum.VT_UI2:
						case VarEnum.VT_UI4:
						case VarEnum.VT_UI8:
						{
							// ignore issue for conversions from boolean.
                            if (sourceType == VarEnum.VT_BOOL)
							{	
								break;					
							}

							decimal sourceAsDecimal = 0;
							decimal resultAsDecimal = System.Convert.ToDecimal(result);

							try   { sourceAsDecimal = System.Convert.ToDecimal(source); }
							catch { sourceAsDecimal = 0; }
							
							if ((sourceAsDecimal < 0 && resultAsDecimal > 0) || (sourceAsDecimal > 0 && resultAsDecimal < 0))
							{
                                target = null;
                                return ResultIds.E_RANGE;
							}
                            
							// conversion from datetime should have failed.
                            if (sourceType == VarEnum.VT_DATE)
							{	
                                if (resultAsDecimal == 0)
                                {
                                    target = null;
                                    return ResultIds.E_RANGE;
                                }
							}

							break;
						}		
							
						case VarEnum.VT_R8:
						{						
							// fix precision problem introduced with conversion from float to double.
                            if (sourceType == VarEnum.VT_R4)
							{	
								result = System.Convert.ToDouble(source.ToString());
							}

							break;			
						}
					}

					target = result;
                    return ResultIds.S_OK;
				}
				finally
				{
					VariantClear(pvargDest);
					VariantClear(pvarSrc);

					Marshal.FreeCoTaskMem(pvargDest);
					Marshal.FreeCoTaskMem(pvarSrc);
				}
			}
			else if (array != null && targetType == VarEnum.VT_BSTR)
			{
				int count = ((Array)source).Length;

				StringBuilder buffer = new StringBuilder();

				buffer.Append("{");

				foreach (object element in (Array)source)
				{
                    object elementValue = null;
               
                    int error = ChangeTypeForCOM(element, VarEnum.VT_BSTR, out elementValue);

                    if (error < 0)
                    {
                        target = null;
                        return error;
                    }
                    
					buffer.Append((string)elementValue);

					count--;

					if (count > 0)
					{
						buffer.Append(" | ");
					}
				}

				buffer.Append("}");

				target = buffer.ToString();
                return ResultIds.S_OK;
			}
            
			// no conversions between scalar and array types allowed.
            target = null;
            return ResultIds.E_BADTYPE;
		}
        

Same methods

ComUtils::ChangeTypeForCOM ( object source, VarEnum targetType, object &target ) : int