/// <summary> /// Marshals data from a managed list of strings to an unmanaged block of memory allocated by the <paramref name="memAlloc"/> method. /// </summary> /// <param name="values">The enumerated list of strings to marshal.</param> /// <param name="packing">The packing type for the strings.</param> /// <param name="memAlloc"> /// The function that allocates the memory for the block of strings (typically <see cref="Marshal.AllocCoTaskMem(int)"/> or <see cref="Marshal.AllocHGlobal(int)"/>. /// </param> /// <param name="bytesAllocated">The bytes allocated by the <paramref name="memAlloc"/> method.</param> /// <param name="charSet">The character set to use for the strings.</param> /// <param name="prefixBytes">Number of bytes preceding the trailing strings.</param> /// <returns> /// Pointer to the allocated native (unmanaged) array of strings stored using the <paramref name="packing"/> model and the character /// set defined by <paramref name="charSet"/>. /// </returns> public static IntPtr MarshalToPtr(this IEnumerable <string> values, StringListPackMethod packing, Func <int, IntPtr> memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0) { // Convert to list to avoid multiple iterations var list = values as IList <string> ?? (values != null ? new List <string>(values) : null); // Look at count and bail early if 0 var count = values?.Count() ?? 0; var chSz = StringHelper.GetCharSize(charSet); bytesAllocated = prefixBytes + (packing == StringListPackMethod.Concatenated ? chSz : IntPtr.Size); if (count == 0) { var ret = memAlloc(bytesAllocated); Marshal.Copy(new byte[bytesAllocated], 0, ret, bytesAllocated); return(ret); } // Check for empty and/or null strings if (packing == StringListPackMethod.Concatenated && list.Any(s => string.IsNullOrEmpty(s))) { throw new ArgumentException("Concatenated string arrays cannot contain empty or null strings."); } // Get size of output var sumStrLen = list.Sum(s => s == null ? 0 : s.Length + 1); bytesAllocated += sumStrLen * chSz; if (packing == StringListPackMethod.Packed) { bytesAllocated += (IntPtr.Size * count); } using (var ms = new MarshalingStream(memAlloc(bytesAllocated), bytesAllocated) { Position = prefixBytes, CharSet = charSet }) { if (packing == StringListPackMethod.Packed) { ms.Position += (count + 1) * IntPtr.Size; for (var i = 0; i < list.Count; i++) { ms.Poke(list[i] == null ? IntPtr.Zero : ms.Pointer.Offset(ms.Position), prefixBytes + (i * IntPtr.Size)); ms.Write(list[i]); } ms.Poke(IntPtr.Zero, prefixBytes + (count * IntPtr.Size)); } else { foreach (var s in list) { ms.Write(s); } ms.Write(""); } return(ms.Pointer); } }
public void PokeTest() { using SafeHGlobalHandle m = new SafeHGlobalHandle(10); using MarshalingStream ms = new MarshalingStream(m, m.Size); Assert.That(() => ms.Write(0x000001FF), Throws.Nothing); Assert.That(ms.Position, Is.EqualTo(sizeof(int))); ms.Seek(0, SeekOrigin.Begin); byte[] ba = new byte[] { 0x2 }; Assert.That(() => ms.Poke(null, 0), Throws.ArgumentNullException); Assert.That(() => ms.Poke(ba, 1000), Throws.ArgumentException); Assert.That(() => ms.Poke(ba, -1), Throws.TypeOf <ArgumentOutOfRangeException>()); ms.Poke(ba, 1); Assert.That(ms.Read <int>(), Is.EqualTo(0x00000102)); Assert.That(() => ms.Read <ulong>(), Throws.TypeOf <ArgumentOutOfRangeException>()); }
public void PokeTest() { using (var m = new SafeHGlobalHandle(10)) using (var ms = new MarshalingStream((IntPtr)m, m.Size)) { Assert.That(() => ms.Write(0x000001FF), Throws.Nothing); Assert.That(ms.Position, Is.EqualTo(sizeof(int))); ms.Seek(0, SeekOrigin.Begin); var ba = new byte[] { 0x2 }; Assert.That(() => ms.Poke(null, 0), Throws.ArgumentNullException); Assert.That(() => ms.Poke(ba, 1000), Throws.ArgumentException); Assert.That(() => ms.Poke(ba, -1), Throws.TypeOf <ArgumentOutOfRangeException>()); ms.Poke(ba, 1); Assert.That(ms.Read <int>(), Is.EqualTo(0x00000102)); Assert.That(() => ms.Read <Vanara.PInvoke.User32_Gdi.ICONINFO>(), Throws.TypeOf <ArgumentOutOfRangeException>()); } }
public void PokeTest1() { using SafeHGlobalHandle m = new SafeHGlobalHandle(100); using MarshalingStream ms = new MarshalingStream(m, m.Size); Assert.That(ms.Position, Is.Zero); Assert.That(() => ms.Write(new[] { 1L, 2L }), Throws.Nothing); byte[] bytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 3 }; ms.Write(bytes, 0, bytes.Length); Assert.That(ms.Position, Is.EqualTo(sizeof(long) * 2 + 8)); ms.Seek(0, SeekOrigin.Begin); Assert.That(() => ms.Poke(IntPtr.Zero, 1002), Throws.ArgumentException); Assert.That(() => ms.Poke(IntPtr.Zero, -1), Throws.TypeOf <ArgumentOutOfRangeException>()); ms.Poke(IntPtr.Zero, sizeof(long)); byte[] buf = new byte[24]; ms.Read(buf, 0, buf.Length); Assert.That(buf, Is.EquivalentTo(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 })); Assert.That(() => ms.Read(null, 0, 0), Throws.ArgumentNullException); Assert.That(() => ms.Read(buf, 0, 30), Throws.ArgumentException); Assert.That(() => ms.Read(buf, -1, 0), Throws.TypeOf <ArgumentOutOfRangeException>()); ms.Position = m.Size - 10; Assert.That(() => ms.Read(buf, 0, buf.Length), Throws.Nothing); }