GetWindowText在Windows 10

时间:2016-03-09 13:43:51

标签: c# windows winapi windows-10 hang

TL; DR:GetWindowText win32 api在Windows 10上改变了行为吗?

我有一些代码循环遍历桌面上的所有窗口,找到一个标题包含一些文本的窗口。

当此代码点击名为“”且带有“URL Moniker Notification Window”类的窗口时,它会挂起GetWindowText。

GetWindowText正在尝试发送消息,我的猜测是WM_GETTEXT。

此窗口是exe“SearchUI.exe”的一部分,该进程已暂停,无法处理消息。

阅读时:https://blogs.msdn.microsoft.com/oldnewthing/20030821-00/?p=42833/ 根据规则2,这不应该发生。

这段代码多年来一直运作良好。 (赢7,8,8.1)

GetWindowText在Windows 10中的更改行为是什么?

更新: 有问题的代码。

public static int HwndGet(string partialTitle, string klassenavn)
{
  partialTitle = partialTitle ?? "";
  var cTitleTemp = new StringBuilder(255);
  var hWndTemp = FindWindowEx((IntPtr)0, (IntPtr)0, null, null);
  var nypartialTitle = partialTitle.ToUpper();
  while (hWndTemp != (IntPtr)0)
  {
    GetWindowText(hWndTemp, cTitleTemp, cTitleTemp.Capacity);
    string sTitleTemp = cTitleTemp.ToString();
    sTitleTemp = sTitleTemp.ToUpper();

    if (sTitleTemp.StartsWith(nypartialTitle, StringComparison.CurrentCultureIgnoreCase))
    {
      var className = new StringBuilder(255);
      GetClassName(hWndTemp, className, 255);
      //sTitleTemp: " + sTitleTemp + " ClassName: " + ClassName);

      if (className.ToString().StartsWith(klassenavn, StringComparison.CurrentCultureIgnoreCase))
      {
        return (int)hWndTemp;
      }
    }

    hWndTemp = GetWindow(hWndTemp, GwHwndnext);
  }
  return 0; // does not find the window
}

堆栈追踪:

Stack trace

1 个答案:

答案 0 :(得分:1)

您使用的代码不是“安全”。无法保证在调用FindWindowsExGetWindow(GwHwndnext)之间窗口的顺序不会发生变化。出于这个原因,还有另一个API,EnumWindows,它是“安全的”。你可以尝试一下。

这里有一个示例程序(基于找到的here)。

public static class WndSearcher
{
    public static IntPtr SearchForWindow(string wndclass, string title)
    {
        var sd = new SearchData { Wndclass = wndclass, Title = title };

        EnumWindows(sd.EnumWindowsProc, IntPtr.Zero);
        return sd.hWndFound;
    }

    private class SearchData
    {
        // You can put any dicks or Doms in here...
        public string Wndclass;
        public string Title;

        public IntPtr hWndFound;

        public bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam)
        {
            // Check classname and title 
            var sb = new StringBuilder(1024);
            int res = GetClassName(hWnd, sb, sb.Capacity);

            if (res == 0)
            {
                throw new Win32Exception();
            }

            if (sb.ToString().StartsWith(Wndclass, StringComparison.CurrentCultureIgnoreCase))
            {
                sb.Clear();

                res = GetWindowText(hWnd, sb, sb.Capacity);

                if (res == 0)
                {
                    int error = Marshal.GetLastWin32Error();

                    if (error != 0) 
                    {
                        throw new Win32Exception(error);
                    }
                }

                if (sb.ToString().StartsWith(Title, StringComparison.CurrentCultureIgnoreCase))
                {
                    hWndFound = hWnd;
                    // Found the wnd, halt enumeration
                    return false;    
                }
            }

            return true;
        }
    }

    [return: MarshalAs(UnmanagedType.Bool)]
    private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
}

然后像

一样使用它
IntPtr ptr = WndSearcher.SearchForWindow("classname", "windowname");