we have an external video player to which i need to give a reference to a HwndHost, and then the external video player renders into it.
all works fine, but i cant find out why memory is leaked, as new HwndHosts are created.
here is my HwndHost implementation:
namespace WpfApp2
{
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Interop;
[SuppressUnmanagedCodeSecurity]
public class MediaFoundationVideoHost : HwndHost, IDisposable
{
internal const int WS_CHILD = 0x40000000;
internal const int WS_VISIBLE = 0x10000000;
internal const int LBS_NOTIFY = 0x00000001;
internal const int SS_NOTIFY = 0x00000100;
internal const int SS_BLACKFRAME = 0x00000007;
internal const int SS_WHITERECT = 0x00000006;
internal const int HostId = 0x00000002;
internal const int LISTBOX_ID = 0x00000001;
internal const int WS_VSCROLL = 0x00200000;
internal const int GC_ALLGESTURES = 0x00000001;
internal const int WS_BORDER = 0x00800000;
internal const int WS_DISABLED = 0x8000000;
private HandleRef handleRef;
private IntPtr hwndHost;
private IntPtr parentHandle = IntPtr.Zero;
private readonly object lockObj = new object();
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetParent(IntPtr child, IntPtr parent);
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int extendedWindowStyle,
string classname,
string windowname,
int style,
int x,
int y,
int width,
int height,
IntPtr hwndParent,
IntPtr menu,
IntPtr instance,
[MarshalAs(UnmanagedType.AsAny)] object param);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
protected override void Dispose(bool disposing)
{
lock (this.lockObj)
{
handleRef = new HandleRef(null, IntPtr.Zero);
parentHandle = IntPtr.Zero;
hwndHost = IntPtr.Zero;
base.Dispose(disposing);
}
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
this.hwndHost = IntPtr.Zero;
this.parentHandle = hwndParent.Handle;
int style = WS_CHILD | WS_VISIBLE | SS_BLACKFRAME | SS_WHITERECT;
style |= SS_NOTIFY;
this.hwndHost = CreateWindowEx(0,
"static",
string.Empty,
style,
0,
0,
(int)200,
(int)200,
hwndParent.Handle,
(IntPtr)HostId,
IntPtr.Zero,
0);
this.handleRef = new HandleRef(this, this.hwndHost);
return this.handleRef;
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
handled = false;
return IntPtr.Zero;
}
}
}
i create these 25 of HwndHosts in my MainWindow(wpf), and then i dispose them, hoping they get released and no memory leaks:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Input;
namespace WpfApp2
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler? PropertyChanged;
public ObservableCollection<MediaFoundationVideoHost> Items { get; set; } = new ObservableCollection<MediaFoundationVideoHost>();
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
while (true)
{
Thread.Sleep(200);
for (int i = 0; i < 25; i++)
{
var videoHost = new MediaFoundationVideoHost();
Items.Add(videoHost);
}
foreach (var item in Items)
{
item.Dispose();
}
Items.Clear();
}
}
}
}
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Background="Black" MouseDown="Grid_MouseDown">
<ItemsControl ItemsSource="{Binding Items}"></ItemsControl>
</Grid>
</Window>
my program goes from 50mb to 400mb in like 60 minutes, and i cant find anything useful while analyzing the dump of the process. BuildWindowCore is called, and DestroyWindowCore is called aswell.
thankies