Jac*_*ack 5 .net c# windows winapi winforms
如何预先获取类名的长度,以便可以将其传递给函数中的nMaxCount参数GetClassName()?诸如WM_GETTEXTLENGTH控件中存在的消息之类的信息,还是窗口类名称是否定义了固定的大小限制?如果是这样,那有什么价值?
我的目标是传递确切的大小,而不要使用重新分配方法(调用GetClassName()直到返回的大小小于其缓冲区)。
我当前的实现(没有重新分配方法):
[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();
}
Run Code Online (Sandbox Code Playgroud)
对于此特定函数,类名限制为 256 个字符。(请参阅结构lpszClassName成员的文档WNDCLASSEX。)因此,只需分配一个该大小的固定缓冲区即可!
为了完整起见,让我们看一下在没有固定大小缓冲区的情况下调用函数的更通用的解决方案。在这种情况下,我们可以应用一个简单的 try-double-retry 算法,如下所示:
您可以使用以下代码查看算法的运行情况:
[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;
}
Run Code Online (Sandbox Code Playgroud)
(设置断点并逐步执行以真正看到它的运行情况。)