Consider these two definitions for GetWindowText
. One uses a string
for the buffer, the other uses a StringBuilder
instead:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, string lpString, int nMaxCount);
Here's how you call them:
var windowTextLength = GetWindowTextLength(hWnd);
// You can use either of these as they both work
var buffer = new string('\0', windowTextLength);
//var buffer = new StringBuilder(windowTextLength);
// Add 1 to windowTextLength for the trailing null character
var readSize = GetWindowText(hWnd, buffer, windowTextLength + 1);
Console.WriteLine($"The title is '{buffer}'");
They both seem to work correctly whether I pass in a string
, or a StringBuilder
. However, all the examples I've seen use the StringBuilder
variant. Even PInvoke.net lists that one.
My guess is the thinking goes 'In C# strings are immutable, therefore use StringBuilder
', but since we're poking down to the Win32 API and messing with the memory locations directly, and that memory buffer is for all intents and purposes (pre)allocated (i.e. reserved for, and being currently used by the string) by the nature of it being assigned a value at its definition, that restriction doesn't actually apply, hence string
works just fine. But I'm wondering if that assumption is wrong.
I don't think so because if you test this by increasing the buffer by say 10, and change the character you're initializing it with to say 'A', then pass in that larger buffer size to GetWindowText, the string you get back is the actual title, right-padded with the ten extra 'A's that weren't overwritten, showing it did update that memory location of the earlier characters.
So provided you pre-initialize the strings, can't you do this? Could those strings ever 'move out from under you' while using them because the CLR is assuming they're immutable? That's what I'm trying to figure out.