diff --git a/PInvoke/User32/BasicMessageWindow.cs b/PInvoke/User32/BasicMessageWindow.cs
index 39796a7d..7f8fab54 100644
--- a/PInvoke/User32/BasicMessageWindow.cs
+++ b/PInvoke/User32/BasicMessageWindow.cs
@@ -1,9 +1,5 @@
using System;
-using System.Collections.Generic;
using System.Runtime.InteropServices;
-using Vanara.Extensions;
-using Vanara.InteropServices;
-using static Vanara.PInvoke.Gdi32;
using static Vanara.PInvoke.Kernel32;
using static Vanara.PInvoke.User32;
@@ -15,13 +11,9 @@ namespace Vanara.PInvoke
///
public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle
{
- private static readonly Dictionary s_lookup = new Dictionary();
- private static readonly WindowProc s_WndProc = new WindowProc(WndProc);
+ private SafeHWND hwnd;
private bool isDisposed;
- /// The safe handle of the registered and created window.
- protected SafeHWND hWnd;
-
/// Initializes a new instance of the class.
///
/// Specifies the callback method to use to process messages. A value will just use DefWindowProc.
@@ -29,17 +21,13 @@ namespace Vanara.PInvoke
public BasicMessageWindow(WindowProc callback = null)
{
Callback = callback;
- ClassName = "MessageWindowBaseClass+" + Guid.NewGuid().ToString();
+ ClassName = $"MessageWindowBase+{Guid.NewGuid()}";
- CreateWindow();
+ hwnd = CreateWindow();
}
/// Finalizes an instance of the class.
- ~BasicMessageWindow()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: false);
- }
+ ~BasicMessageWindow() => Dispose(false);
/// Gets or sets the callback method used to filter window messages.
/// The callback method.
@@ -51,11 +39,7 @@ namespace Vanara.PInvoke
/// Gets the handle.
/// The handle.
- public HWND Handle => hWnd;
-
- /// Returns the value of the handle field.
- /// An IntPtr representing the value of the handle field.
- public IntPtr DangerousGetHandle() => ((IHandle)hWnd).DangerousGetHandle();
+ public HWND Handle => hwnd;
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
@@ -64,23 +48,18 @@ namespace Vanara.PInvoke
System.GC.SuppressFinalize(this);
}
+ /// Returns the value of the handle field.
+ /// An IntPtr representing the value of the handle field.
+ IntPtr IHandle.DangerousGetHandle() => (IntPtr)Handle;
+
///
/// Method used to create the window. When overriding, the hWnd field must be set to the handle of the created window.
///
- protected virtual void CreateWindow()
+ protected virtual SafeHWND CreateWindow()
{
- var wc = new WNDCLASSEX
- {
- cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)),
- lpfnWndProc = s_WndProc,
- hInstance = GetModuleHandle(),
- lpszClassName = ClassName,
- };
-
- RegisterClassEx(wc);
-
- using var pinnedThisPtr = new PinnedObject(this);
- hWnd = CreateWindowEx(lpClassName: ClassName, lpWindowName: "", hWndParent: HWND.HWND_MESSAGE, lpParam: pinnedThisPtr);
+ if (0 == RegisterClassEx(new WNDCLASSEX { cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)), lpfnWndProc = WndProc, hInstance = GetModuleHandle(), lpszClassName = ClassName }))
+ Win32Error.ThrowLastError();
+ return Win32Error.ThrowLastErrorIfInvalid(CreateWindowEx(lpClassName: ClassName, lpWindowName: ClassName, hWndParent: HWND.HWND_MESSAGE));
}
/// Releases unmanaged and - optionally - managed resources.
@@ -93,37 +72,19 @@ namespace Vanara.PInvoke
return;
isDisposed = true;
- hWnd.Dispose();
+
+ hwnd?.Dispose();
+
UnregisterClass(ClassName, GetModuleHandle());
ClassName = null;
}
- private static IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
+ private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
{
- BasicMessageWindow hwndWrapper = null;
-
- if (msg == (uint)WindowMessage.WM_CREATE)
- {
- var createStruct = lParam.ToStructure();
- GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams);
- hwndWrapper = (BasicMessageWindow)gcHandle.Target;
- s_lookup.Add(hwnd, hwndWrapper);
- }
- else if (!s_lookup.TryGetValue(hwnd, out hwndWrapper))
- {
- return DefWindowProc(hwnd, msg, wParam, lParam);
- }
-
- if (hwndWrapper is null)
- throw new InvalidOperationException();
-
- var ret = (hwndWrapper.Callback ?? DefWindowProc)(hwnd, msg, wParam, lParam);
+ var ret = (Callback ?? DefWindowProc).Invoke(hwnd, msg, wParam, lParam);
if (msg == (uint)WindowMessage.WM_NCDESTROY)
- {
- hwndWrapper.Dispose(true);
- System.GC.SuppressFinalize(hwndWrapper);
- }
+ Dispose(true);
return ret;
}
diff --git a/UnitTests/PInvoke/User32/User32Tests.cs b/UnitTests/PInvoke/User32/User32Tests.cs
index ceacdd81..1a17fb44 100644
--- a/UnitTests/PInvoke/User32/User32Tests.cs
+++ b/UnitTests/PInvoke/User32/User32Tests.cs
@@ -23,6 +23,27 @@ namespace Vanara.PInvoke.Tests
TestContext.WriteLine($"{array[i].dwID} = {array[i].dwWant} / {array[i].dwBlock}");
}
+ [Test]
+ public void WinTest()
+ {
+ var timer = System.Diagnostics.Stopwatch.StartNew();
+ var gotMsg = false;
+ using (var win = new Vanara.PInvoke.BasicMessageWindow(meth))
+ {
+ for (int i = 0; i < 100; i++)
+ System.Threading.Thread.Sleep(20);
+ }
+ timer.Stop();
+ Assert.True(gotMsg);
+
+ IntPtr meth(HWND hwnd, uint uMsg, IntPtr wParam, IntPtr lParam)
+ {
+ TestContext.WriteLine($"{timer.ElapsedMilliseconds} Message: {(WindowMessage)uMsg} ({uMsg})");
+ gotMsg = true;
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+ }
+
[Test()]
public void GetWindowLongTest()
{