GetWindowText hangs on Windows 10

喜夏-厌秋 提交于 2021-02-08 05:15:40

问题


TL;DR: Did GetWindowText win32 api change behavior on windows 10?

I have some code that loops through all windows on the desktop to find a window where the title contains some text.

When this code hits a window named "" with class "URL Moniker Notification Window" it hangs on GetWindowText.

GetWindowText is trying to send a message, my guess is WM_GETTEXT.

This window is part of the exe "SearchUI.exe", the process is suspended and can't process messages.

When reading: https://blogs.msdn.microsoft.com/oldnewthing/20030821-00/?p=42833/ according to rule 2, this should not happen.

This code has been working fine for years. (win 7, 8, 8.1)

So did GetWindowText change behavior in Windows 10?

Update: The code in question.

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:


The code you are using isn't "safe". There is no guarantee that the order of the windows won't change between calls to FindWindowsEx and GetWindow(GwHwndnext). For this reason there is another API, EnumWindows, that is "safe". You could try with it.

Here there is a sample program (based on the one found 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);
}

and then use it like

IntPtr ptr = WndSearcher.SearchForWindow("classname", "windowname");


来源:https://stackoverflow.com/questions/35893314/getwindowtext-hangs-on-windows-10

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!