MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
441 stars 52 forks source link

[Problem/Bug]: A window hierarchy problem introduced by WebView2 #4787

Open zprettytext opened 2 weeks ago

zprettytext commented 2 weeks ago

What happened?

background

The background of the problem is this: we have two processes A and B that reuse the same WebView2 Run Environment. The process model is as follows: image

Then we found the following problems:

  1. Call SetWindowPos putting a pop-up window on top of A will cause B's main window switch to the foreground.
  2. Call SetWindowPos putting a pop-up window on top of B will also cause A's main window switch to the foreground.

Cause analysis:

This problem only occurs when WebView is loaded in both A and B. We speculate that it is probably because when WebView is loaded in both A and B, A and B contain child windows (WebView window handles) belonging to the same process (Microsoft Edge WebView2), which leads to a problem that the Z order of A and B windows is mixed together.

conclusion

We need A and B to share the same WebView permission environment so that WebView can share cache data. However, we don't want to cause window Z order problems due to sharing the same Microsoft Edge WebView2 process. We want a perfect solution.

Importance

Important. My app's user experience is significantly compromised.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

122.0.2365.80

SDK Version

1.0221

Framework

Win32

Operating System

Windows 10, Windows 11

OS Version

No response

Repro steps

Please refer to the above description.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

No, this never worked

Last working version (if regression)

No response

zprettytext commented 2 weeks ago

To prove what I said, I implemented a unit test. The steps are as follows: step 1. Create a unit test window and load a WebView. step 2. Open the Dev Tool window. step 3. Call the timer in the Dev Tool console, delay 10s to execute chrome.webview.postMessage('[CreatePopWindow]') to send a message to the WebView. setTimeout(function() { chrome.webview.postMessage('[pop]') }, 10000);

step 4. Switch the unit test window to the background. step 5. After the unit test WebView receives the Web message, the window pops up and calls SetWindowPos to set the window. step 6. There are two situations: 6.1. If the Dev Tool window is in the foreground, the unit test window will be switched to the foreground, which is not the expected behavior. 6.2. If the Dev Tool window is not in the foreground, the unit test window will not be switched to the foreground, which is in line with the expected behavior. Now the key question is: why does the Dev Tool window in the foreground cause the unit test window to be picked to the foreground?

After unit test window webview receives the message, the window pop-up window related code is as follows

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
        switch (uMsg) {
        case WM_DESTROY:
            return 0;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        }
    }

    void RegisterWindowClass() {
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = nullptr;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.lpszClassName = TEXT("MyPopupWindowClass");

        RegisterClassEx(&wc);
    }

    void CreatePopupWindow(HWND ancestorWindow) {
        RegisterWindowClass();
        HWND hWnd = CreateWindowEx(
            0,
            TEXT("MyPopupWindowClass"),     
            TEXT("My Popup Window"),          
            WS_POPUP | WS_VISIBLE | WS_OVERLAPPEDWINDOW,           
            CW_USEDEFAULT, CW_USEDEFAULT,    
            300, 200,                        
            ancestorWindow,                 
            NULL,                            
            NULL,                            
            NULL
        );

        if (hWnd) {
            SetWindowPos(hWnd, HWND_TOP, 0, 0, 300, 200, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
            ShowWindow(hWnd, SW_SHOW);
        }
    }

 EXPECT_CALL(sinkWin, OnRecvWebMessage(testing::_, testing::_, testing::_))
        .Times(::testing::AnyNumber())
        .WillRepeatedly(::testing::Invoke([webViewControl](IUnifyWebViewInst* inst, const Cmm::CString& message, bool& handled) {

            if (L"[pop]" == message)
            {
                HWND ancestorWindow = ::GetAncestor(webViewControl->GetWebViewWindow(), GA_ROOT);
                CreatePopupWindow(ancestorWindow);
            }
         }));

The screen recording information is as follows:

  1. The first time, the unit test window jumped to the foreground because the Dev Tool window was in the foreground (not the expected behavior).
  2. The second time, the Dev Tool window was not in the foreground. The conclusion is that whether the unit test window is in the foreground affects the behavior of the unit test window. gifrec_20240905-18_32_02