How do I get the class name length beforehand so I can pass it into nMaxCount
parameter in GetClassName()
function? something like WM_GETTEXTLENGTH
message which exists for Controls or does a window class name have a fixed size limit defined? if so, what's that value?
My goal is pass exact size rather do the reallocation approach (call GetClassName()
until it return size smaller than its buffer).
My current implementation (without the reallocation approach):
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
string GetWindowClass(IntPtr hWnd)
{
const int size = 256;
StringBuilder buffer = new StringBuilder(size + 1);
if (GetClassName(hWnd, buffer, size) == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return buffer.ToString();
}
There are three types of window classes: System Classes. Application Global Classes. Application Local Classes.
A window class is a set of attributes that the system uses as a template to create a window. Every window is a member of a window class. All window classes are process specific.
There is no way to change the class of an existing window. The only option is to destroy the original window and create a new window using a different class.
In the case of this particular function, the class name is limited to 256 characters. (See the documentation for the lpszClassName
member of the WNDCLASSEX
struct.) So just allocate a fixed buffer of that size and be done with it!
For completeness, let's look at the more general solution for calling functions where there is no fixed-size buffer. In this case we can apply a simple try-double-retry algorithm as follows:
You can see the algorithm in action with this code:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int GetClassNameW(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
string GetWindowClass(IntPtr hWnd)
{
string className = String.Empty;
int length = 10; // deliberately small so you can
// see the algorithm iterate several times.
StringBuilder sb = new StringBuilder(length);
while (length < 1024)
{
int cchClassNameLength = GetClassNameW(hWnd, sb, length);
if (cchClassNameLength == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else if (cchClassNameLength < length - 1) // -1 for null terminator
{
className = sb.ToString();
break;
}
else length *= 2;
}
return className;
}
(Set a breakpoint and step through to really see it in action.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With