CommunityToolkit / Microsoft.Toolkit.Win32

ARCHIVE - This repository contained XAML Islands wrapper controls and tooling for XAML Islands with WinUI 2, see readme for more info about XAML Islands with WinUI 3 and the WindowsAppSDK.
https://aka.ms/windowsappsdk
Other
383 stars 89 forks source link

Child processes leak if the process is killed #146

Open AbeniMatteo opened 5 years ago

AbeniMatteo commented 5 years ago

I'm submitting a...

Current behavior

Child processes leak if the process is killed. (Win32WebViewHost.exe and WWAHost.exe)

Expected behavior

No child process left running.

Minimal reproduction of the problem with instructions

Environment

Nuget Package(s): 
- Microsoft.Toolkit.Wpf.UI.Controls.WebView

Package Version(s): 
- 5.1.1

Windows 10 Build Number:
- 18362

Device form factor:
- Desktop
verelpode commented 5 years ago

I was able to reproduce this bug when testing with package 6.0.0-preview7.1 and W10 version 1903 (build 18362.295). I noticed that the WWAHost process is only left running when the WPF app is terminated with the force option. Thus the command without force...

taskkill /IM TestApp.exe

...correctly triggers WWAHost to exit, whereas if you force termination....

taskkill /IM TestApp.exe /F

...then the WWAHost process is left running.

I think the applicable part of the source code is unavailable so I cannot look at it, but I guess WebViewControlProcess sends a termination message to WWAHost when the app exits, but this termination message cannot be sent when the app is forcibly terminated, thus WWAHost doesn't know that it should exit.

To make a more reliable solution, here's an idea: Maybe WWAHost should use the RegisterWaitForSingleObject function with a handle of the process where the corresponding WebView instance exists. For example, WWAHost could use code similar to this snippet:

void RegisterWaitForProcessExit(DWORD dwProcessID)
{
    HANDLE hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    HANDLE hNewHandle;
    RegisterWaitForSingleObject(&hNewHandle, hProcHandle, TestWaitCallback, NULL, INFINITE, WT_EXECUTEONLYONCE);
    // TO DO:  Use GetLastError to check for errors.
}

VOID CALLBACK TestWaitCallback(_In_ PVOID lpParameter, _In_ BOOLEAN TimerOrWaitFired)
{
    ...
}

I think the RegisterWaitForSingleObject technique works regardless of whether the monitored/awaited app is politely versus forcibly terminated, but admittedly I might be remembering this fact incorrectly.

This issue might also be partially related to the issue where WebView malfunctions when "explorer.exe" is not running. In the UWP (non-WPF) version of WebView, when you use the option Windows.UI.Xaml.Controls.WebViewExecutionMode.SeparateProcess, when you click the "X" to close/exit the app, the app fails to exit when explorer.exe is not running. I guess Windows.Web.UI.Interop.WebViewControlProcess tries to send a termination message to WWAHost, but this technique fails under either of these 2 circumstances:

  1. When the app (containing WebView) is forcibly terminated; or
  2. When "explorer.exe" is not running.
ndreisg commented 4 years ago

I am facing this issue in my Windows Forms application.

I wanted to note that this issue also appears when the application is killed by an MSI installer update.

Also I am using WebSockets in my WebView application and the WebSocket connections by the leaked processes stay opened which may cause unexpected issues.