Exemple #1
0
        /// <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);
            }
        }
Exemple #2
0
        /// <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)
        {
            // Bail early if empty
            if (values is null || !values.Any())
            {
                bytesAllocated = prefixBytes + (packing == StringListPackMethod.Concatenated ? StringHelper.GetCharSize(charSet) : IntPtr.Size);
                var ret = memAlloc(bytesAllocated);
                ret.FillMemory(0, bytesAllocated);
                return(ret);
            }

            // Write to memory stream
            using (var ms = new NativeMemoryStream(1024, 1024)
            {
                CharSet = charSet
            })
            {
                ms.SetLength(ms.Position = prefixBytes);
                if (packing == StringListPackMethod.Packed)
                {
                    foreach (var s in values)
                    {
                        ms.WriteReference(s);
                    }
                    ms.WriteReference(null);
                }
                else
                {
                    foreach (var s in values)
                    {
                        if (string.IsNullOrEmpty(s))
                        {
                            throw new ArgumentException("Concatenated string arrays cannot contain empty or null strings.");
                        }
                        ms.Write(s);
                    }
                    ms.Write("");
                }
                ms.Flush();

                // Copy to newly allocated memory using memAlloc
                bytesAllocated = (int)ms.Length;
                var ret = memAlloc(bytesAllocated);
                ms.Pointer.CopyTo(ret, bytesAllocated);
                return(ret);
            }
        }
Exemple #3
0
 /// <summary>
 /// Marshals data from a managed array of strings to an unmanaged block of memory allocated by the <paramref name="memAlloc"/> method.
 /// </summary>
 /// <param name="values">The array 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 string[] values, StringListPackMethod packing, Func <int, IntPtr> memAlloc, out int bytesAllocated, CharSet charSet = CharSet.Auto, int prefixBytes = 0) =>
 MarshalToPtr((IEnumerable <string>)values, packing, memAlloc, out bytesAllocated, charSet, prefixBytes);
Exemple #4
0
 /// <summary>Allocates from unmanaged memory sufficient memory to hold an array of strings.</summary>
 /// <param name="values">The list of strings.</param>
 /// <param name="packing">The packing type for the strings.</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>
 /// <see cref="SafeMoveableHGlobalHandle"/> object to an native (unmanaged) array of strings stored using the <paramref
 /// name="packing"/> model and the character set defined by <paramref name="charSet"/>.
 /// </returns>
 public static SafeMoveableHGlobalHandle CreateFromStringList(IEnumerable <string> values, StringListPackMethod packing = StringListPackMethod.Concatenated,
                                                              CharSet charSet = CharSet.Auto, int prefixBytes = 0) => new(InteropExtensions.MarshalToPtr(values, packing, mm.AllocMem, out _, charSet, prefixBytes, mm.LockMem, mm.UnlockMem), true);