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); }