Reputation: 313
I need to extract the environment strings from a call to CreateEnvironmentBlock( out IntPtr lpEnvironment, IntPtr hToken, bool bInherit )
, so as to put them in dictionary based on the variable name and its value.
When this function returns,
lpEnvironment
receives a pointer to the new environment block. The environment block is an array of null-terminated Unicode strings. The list ends with two nulls (\0\0
).
I cannot easily use Marshal.Copy
as I do not know the block's length. I'm wondering if there is an easy way to move along it or determine what to copy to something I can then convert more easily. One thought was to pass the out IntPtr lpEnvironment
as out char [] lpEnvironment
.
Any suggestions?
Upvotes: 5
Views: 704
Reputation: 304
You dont know the whole length for Marshal.Copy()
, however you know the length of the first string if you perform Marshal.PtrToString()
. With that knowledge you can advance to the next string and so on, until you read an empty string, that indicates only \0
was present at that address, which is the end of the multi string.
Note that the following code assumes Unicode charset is available and uses it.
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment,IntPtr hToken,bool bInherit);
static IEnumerable<string> ExtractMultiString(IntPtr ptr)
{
while (true)
{
string str = Marshal.PtrToStringUni(ptr);
if (str.Length == 0)
break;
yield return str;
ptr = new IntPtr(ptr.ToInt64() + (str.Length + 1 /* char \0 */) * sizeof(char));
}
}
Upvotes: 4