[Problem/Bug]: A window hierarchy problem introduced by WebView2
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:
Then we found the following problems:
- Call SetWindowPos putting a pop-up window on top of A will cause B's main window switch to the foreground.
- 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
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:
- The first time, the unit test window jumped to the foreground because the Dev Tool window was in the foreground (not the expected behavior).
- 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.
@zprettytext What you're describing makes sense. When both process A and process B share the same WebView2 Environment settings, they end up sharing the same msedgewebview2.exe process. Child HWNDs across a thread or process boundary results in attached input queues. So having process A and process B share a WebView2 process, results in all 3 processes now having attached input queues. This gives all processes foreground permission to change the active window.
I believe that you can resolve the issue above by adding SWP_NOOWNERZORDER .-,SWP_NOOWNERZORDER,-0x0200) to your SetWindowPos flags. This should prevent the owner window from changing z-order when you change the owned popup window to be HWND_TOP.