Skip to content

Instantly share code, notes, and snippets.

@nefarius
Created April 29, 2021 11:14
Show Gist options
  • Save nefarius/59ee8d8bccd1f97039fc2ed9b61f0aa9 to your computer and use it in GitHub Desktop.
Save nefarius/59ee8d8bccd1f97039fc2ed9b61f0aa9 to your computer and use it in GitHub Desktop.
String manipulation helper methods.
/// <summary>
/// String manipulation helper methods.
/// </summary>
internal static class StringHelperUtil
{
/// <summary>
/// Converts an array of <see cref="string" /> into a double-null-terminated multi-byte character memory block.
/// </summary>
/// <param name="instances">Source array of strings.</param>
/// <param name="length">The length of the resulting byte array.</param>
/// <returns>The allocated memory buffer.</returns>
public static IntPtr StringArrayToMultiSzPointer(this IEnumerable<string> instances, out int length)
{
// Temporary byte array
IEnumerable<byte> multiSz = new List<byte>();
// Convert each string into wide multi-byte and add NULL-terminator in between
multiSz = instances.Aggregate(multiSz,
(current, entry) => current.Concat(Encoding.Unicode.GetBytes(entry))
.Concat(Encoding.Unicode.GetBytes(new[] {char.MinValue})));
// Add another NULL-terminator to signal end of the list
multiSz = multiSz.Concat(Encoding.Unicode.GetBytes(new[] {char.MinValue}));
// Convert expression to array
var multiSzArray = multiSz.ToArray();
// Convert array to managed native buffer
var buffer = Marshal.AllocHGlobal(multiSzArray.Length);
Marshal.Copy(multiSzArray, 0, buffer, multiSzArray.Length);
length = multiSzArray.Length;
// Return usable buffer, don't forget to free!
return buffer;
}
/// <summary>
/// Converts a double-null-terminated multi-byte character memory block into a string array.
/// </summary>
/// <param name="buffer">The memory buffer.</param>
/// <param name="length">The size in bytes of the memory buffer.</param>
/// <returns>The extracted string array.</returns>
public static IEnumerable<string> MultiSzPointerToStringArray(this IntPtr buffer, int length)
{
// Temporary byte array
var rawBuffer = new byte[length];
// Grab data from buffer
Marshal.Copy(buffer, rawBuffer, 0, length);
// Trims away potential redundant NULL-characters and splits at NULL-terminator
return Encoding.Unicode.GetString(rawBuffer).TrimEnd(char.MinValue).Split(char.MinValue);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment