FindWindow & FindWindowEx broken on Windows 11

RangerCD 36 Reputation points
2022-08-05T09:10:04.597+00:00

Several years ago, I was trying to find a window with specified class, so I chose FindWindow and it worked pretty well. Recently, I've received reports telling me the program grabs wrong window randomly. I realized that FindWindow seems to be unstable on Windows 11.

Here is a simple demo in C++, searching by class name(or searching a class doesn't exist by default):

   #ifndef UNICODE  
   #define UNICODE  
   #endif  
     
   #include <iostream>  
   #include <Windows.h>  
     
   int wmain(int argc, wchar_t* argv[])  
   {  
       LPCWSTR lpszClass;  
       if (argc > 1) {  
           lpszClass = argv[1];  
       }  
       else {  
           lpszClass = L"impossible class";  
       }  
       wchar_t buffer[1024];  
     
       std::wcout << L"Searching for: " << lpszClass << std::endl;  
     
       for (int64_t i = 0; true; i ++) {  
           HWND hWnd = FindWindowW(lpszClass, NULL);  
           //HWND hWnd = FindWindowEx(NULL, NULL, lpszClass, NULL);  
           if (hWnd != NULL) {  
               GetClassNameW(hWnd, buffer, 1024);  
               if (wcscmp(lpszClass, buffer) != 0) {  
                   std::wcout <<  
                       L"Loop: " << i << std::endl <<  
                       L"Unexpected handle: " << hWnd << std::endl <<  
                       L"Real class: " << buffer << std::endl;  
               }  
           }  
       }  
   }  

After random loops(might takes several seconds to have an hour), what I've got:

   Searching for: impossible class  
   Loop: 123157966  
   Unexpected handle: 0000000000010130  
   Real class: Shell_TrayWnd  
   Loop: 234530658  
   Unexpected handle: 0000000000010130  
   Real class: Shell_TrayWnd  
   Loop: 261192707  
   Unexpected handle: 0000000000010130  
   Real class: Shell_TrayWnd  

Additionally, the unexpected handle is not always consistent, sometimes another wrong handle with different class name returned. It might take up to an hour to experience this issue, if system doesn't have many processes(or windows/handles?). Also, moving mouse over windows or refreshing windows seems making it happens more frequently.

I've tested:

  • both FindWindow and FindWindowEx, broken
  • both W and A version API, broken
  • both x86 and x64 platform, broken
  • both Intel and AMD platform, broken
  • building with both MinGW/g++ and MSVC/cl, broken
  • call API with DllImport in a C# program, broken
  • both physical system and virtual machine, broken
  • binding process to only single/multiple P-Core/E-Core, broken

But when I test it on Windows 10, it works fine.

Here are some environments tested:

Broken:

  • Windows 11 Pro 21H2 22000.832, Intel Core i9 12900K
  • Windows 11 Pro 21H2 22000.832, Intel Core i9 12900H
  • Windows 11 Pro 21H2 22000.795, Intel Core i7 9700
  • Windows 11 Pro 21H2 22000.832, AMD Ryzen 9 5950X

OK:

  • Windows 10 Pro 21H2 19044.1826, Intel Core i9 12900K
  • Windows 10 Pro 21H2 19044.1826, AMD Ryzen 5 5600X
  • Windows 10 Enterprise 2009 19042.804, Intel Core i5 1135G7

======

Update 2022/08/08: my own user story

For my own purpose, I'm using FindWindow and FindWindowEx in a desktop utility.

There are 2 different use cases:

  • Find the window of a music player, grab its title
  • Find the window of another process, send message for interprocess communication

Case 1:

A music player process often shows the title and artist of current track in its window title. First, I need to figure out the class name this music player uses with spy++. Then, I can write something like FindWindow(className, NULL) in my program to find the proper window of music player.

Usually I would add more filters after FindWindow to make sure it's the correct one, but that's not the point since FindWindow didn't do its own job well at first.

Case 2:

Some music player supports plugins, it's possible to establish a connection between player process and my own process, and sending/posting messages is a common way to do so. In the player process, I've created a window with a class name like MyIPCWindowClass, added some custom messages after WM_USER. In my own process, I'm trying to find the window created in player process, with FindWindow(_T("MyIPCWindowClass"), NULL) of course.

I know there are other different ways for IPC, and I could use a special window name instead of a special window class, but that's not the point either.

Beside my own use cases, I have to say this issue is WAY MORE DESTRUCTIVE than what I've said before. FindWindow and FindWindowEx have 20+ years history, they have more important use cases, like IPC and daemon services etc.

Windows development | Windows API - Win32
Windows for business | Windows Client for IT Pros | User experience | Other
{count} votes

2 answers

Sort by: Most helpful
  1. Limitless Technology 39,921 Reputation points
    2022-08-08T10:03:26.07+00:00

    Hi there,

    FindWindow only finds the window if it has the exact specified title, not just a substring. If FindWindow has returned non-NULL, it means it has found a window. As your code works perfectly in Windows 10 I would suggest you to write this out in the feedback hub for the Microsoft team to take note of this.

    The Feedback Hub app lets you tell Microsoft about any problems you run into while using Windows 10. You can also send suggestions to help us improve your Windows experience. https://support.microsoft.com/en-us/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332

    ----------------------------------------------------------------------------------------------------------------------

    --If the reply is helpful, please Upvote and Accept it as an answer–


  2. Danilo L 1 Reputation point
    2022-11-28T08:25:52.703+00:00

    Does this new build fix your FindWindow / FindWindowEx issue?

    Build notes: "Fixed a rare issue where FindWindow and FindWindowEx might return an unexpected window."

    https://blogs.windows.com/windows-insider/2022/10/27/announcing-windows-11-insider-preview-build-25231/


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.