public VaList(bool unicode, params object[] args)
    {
        if (args == null)
        {
            throw new ArgumentNullException("args");
        }
        // The first handle is for the bytes array
        handles.Add(default(GCHandle));
        int total = 0;
        var bytes = new PrimitiveToBytes[args.Length];

        for (int i = 0; i < args.Length; i++)
        {
            int size = Convert(unicode, args[i], ref bytes[i]);
            bytes[i].Size = size;
            total        += size;
        }
        // Instead of a byte[] we use a IntPtr[], so copying elements
        // inside is faster (perhaps :-) )
        var buffer = new IntPtr[total / IntPtr.Size];

        handles[0] = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        for (int i = 0, j = 0; i < args.Length; i++)
        {
            buffer[j++] = bytes[i].IntPtr;
            // long or double with IntPtr == 4
            if (bytes[i].Size > IntPtr.Size)
            {
                buffer[j++] = (IntPtr)bytes[i].Int32High;
            }
        }
    }
    // Overload this to handle other types
    protected virtual int Convert(bool unicode, object arg, ref PrimitiveToBytes primitiveToBytes)
    {
        int size;

        if (arg == null)
        {
            primitiveToBytes.IntPtr = IntPtr.Zero;
            size = IntPtr.Size;
        }
        else
        {
            Type     type       = arg.GetType();
            TypeCode typeHandle = Type.GetTypeCode(type);
            switch (typeHandle)
            {
            case TypeCode.Boolean:
                // Boolean converted to Int32
                primitiveToBytes.Int32 = (bool)arg ? 1 : 0;
                size = IntPtr.Size;
                break;

            case TypeCode.SByte:
                primitiveToBytes.SByte = (sbyte)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.Byte:
                primitiveToBytes.Byte = (byte)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.Int16:
                primitiveToBytes.Int16 = (short)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.UInt16:
                primitiveToBytes.UInt16 = (ushort)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.Int32:
                primitiveToBytes.Int32 = (int)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.UInt32:
                primitiveToBytes.UInt32 = (uint)arg;
                size = IntPtr.Size;
                break;

            case TypeCode.Int64:
                primitiveToBytes.Int64 = (long)arg;
                size = sizeof(long);
                break;

            case TypeCode.UInt64:
                primitiveToBytes.UInt64 = (ulong)arg;
                size = sizeof(ulong);
                break;

            case TypeCode.Single:
                // Single converted to Double
                primitiveToBytes.Double = (double)(float)arg;
                size = sizeof(double);
                break;

            case TypeCode.Double:
                primitiveToBytes.Double = (double)arg;
                size = sizeof(double);
                break;

            case TypeCode.Char:
                if (unicode)
                {
                    primitiveToBytes.UInt16 = (char)arg;
                }
                else
                {
                    byte[] bytes = Encoding.Default.GetBytes(new[] { (char)arg });
                    if (bytes.Length > 0)
                    {
                        primitiveToBytes.B0 = bytes[0];
                        if (bytes.Length > 1)
                        {
                            primitiveToBytes.B1 = bytes[1];
                            if (bytes.Length > 2)
                            {
                                primitiveToBytes.B2 = bytes[2];
                                if (bytes.Length > 3)
                                {
                                    primitiveToBytes.B3 = bytes[3];
                                }
                            }
                        }
                    }
                }
                size = IntPtr.Size;
                break;

            case TypeCode.String:
            {
                string   str = (string)arg;
                GCHandle handle;
                if (unicode)
                {
                    handle = GCHandle.Alloc(str, GCHandleType.Pinned);
                }
                else
                {
                    byte[] bytes = new byte[Encoding.Default.GetByteCount(str) + 1];
                    Encoding.Default.GetBytes(str, 0, str.Length, bytes, 0);
                    handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
                }
                handles.Add(handle);
                primitiveToBytes.IntPtr = handle.AddrOfPinnedObject();
                size = IntPtr.Size;
            }
            break;

            case TypeCode.Object:
                if (type == typeof(IntPtr))
                {
                    primitiveToBytes.IntPtr = (IntPtr)arg;
                    size = IntPtr.Size;
                }
                else if (type == typeof(UIntPtr))
                {
                    primitiveToBytes.UIntPtr = (UIntPtr)arg;
                    size = UIntPtr.Size;
                }
                else if (!type.IsValueType)
                {
                    GCHandle handle = GCHandle.Alloc(arg, GCHandleType.Pinned);
                    primitiveToBytes.IntPtr = handle.AddrOfPinnedObject();
                    size = IntPtr.Size;
                }
                else
                {
                    throw new NotSupportedException();
                }
                break;

            default:
                throw new NotSupportedException();
            }
        }
        return(size);
    }