﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Interop;
using WindowsDesktop.Interop;

namespace WindowsDesktop.Internal
{
	internal abstract class RawWindow
	{
		public string Name { get; set; }

		public HwndSource Source { get; private set; }

		public IntPtr Handle => this.Source?.Handle ?? IntPtr.Zero;

		public virtual void Show()
		{
			this.Show(new HwndSourceParameters(this.Name));
		}

		protected void Show(HwndSourceParameters parameters)
		{
			this.Source = new HwndSource(parameters);
			this.Source.AddHook(this.WndProc);
		}

		public virtual void Close()
		{
			this.Source?.RemoveHook(this.WndProc);
			this.Source?.Dispose();
			this.Source = null;

			NativeMethods.CloseWindow(this.Handle);
		}

		protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
		{
			return IntPtr.Zero;
		}
	}
}

﻿using System;
using System.Windows.Interop;
using System.Windows.Threading;
using WindowsDesktop.Interop;

namespace WindowsDesktop.Internal
{
	internal abstract class RawWindow
	{
		public string Name { get; set; }

		public HwndSource Source { get; private set; }

		public IntPtr Handle => this.Source?.Handle ?? IntPtr.Zero;

		public virtual void Show()
		{
			this.Show(new HwndSourceParameters(this.Name));
		}

		protected void Show(HwndSourceParameters parameters)
		{
			this.Source = new HwndSource(parameters);
			this.Source.AddHook(this.WndProc);
		}

		public virtual void Close()
		{
			this.Source?.RemoveHook(this.WndProc);
			// Source could have been created on a different thread, which means we 
			// have to Dispose of it on the UI thread or it will crash.
			this.Source?.Dispatcher?.BeginInvoke(DispatcherPriority.Send, (Action)(() => this.Source?.Dispose()));
			this.Source = null;

			NativeMethods.CloseWindow(this.Handle);
		}

		protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
		{
			return IntPtr.Zero;
		}
	}
}

Fix crash when multiple threads may exist.
Fix crash when multiple threads may exist.

Based on a crash I experienced in an app I am developing, it appears that sometimes when the app is shutting down, the disposal will not happen from the UI thread, and Dispose() on the HwndSource causes an InvalidOperationException.

By running the Dispose on the UI thread immediately, disposal happens, and no crash is seen.

See https://github.com/Grabacr07/VirtualDesktop/pull/28/commits/e9ec9185d866ea6b75b2f6572870599ba690ea92
