mirror of https://github.com/dahall/Vanara.git
More work and tests for BasicMessageWindow
parent
ddfad23ac1
commit
6aa6d3fd70
|
@ -1,9 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Vanara.Extensions;
|
|
||||||
using Vanara.InteropServices;
|
|
||||||
using static Vanara.PInvoke.Gdi32;
|
|
||||||
using static Vanara.PInvoke.Kernel32;
|
using static Vanara.PInvoke.Kernel32;
|
||||||
using static Vanara.PInvoke.User32;
|
using static Vanara.PInvoke.User32;
|
||||||
|
|
||||||
|
@ -15,13 +11,9 @@ namespace Vanara.PInvoke
|
||||||
/// <seealso cref="Vanara.PInvoke.IHandle"/>
|
/// <seealso cref="Vanara.PInvoke.IHandle"/>
|
||||||
public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle
|
public class BasicMessageWindow : MarshalByRefObject, IDisposable, IHandle
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<HWND, BasicMessageWindow> s_lookup = new Dictionary<HWND, BasicMessageWindow>();
|
private SafeHWND hwnd;
|
||||||
private static readonly WindowProc s_WndProc = new WindowProc(WndProc);
|
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
|
||||||
/// <summary>The safe handle of the registered and created window.</summary>
|
|
||||||
protected SafeHWND hWnd;
|
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the <see cref="BasicMessageWindow"/> class.</summary>
|
/// <summary>Initializes a new instance of the <see cref="BasicMessageWindow"/> class.</summary>
|
||||||
/// <param name="callback">
|
/// <param name="callback">
|
||||||
/// Specifies the callback method to use to process messages. A <see langword="null"/> value will just use <c>DefWindowProc</c>.
|
/// Specifies the callback method to use to process messages. A <see langword="null"/> value will just use <c>DefWindowProc</c>.
|
||||||
|
@ -29,17 +21,13 @@ namespace Vanara.PInvoke
|
||||||
public BasicMessageWindow(WindowProc callback = null)
|
public BasicMessageWindow(WindowProc callback = null)
|
||||||
{
|
{
|
||||||
Callback = callback;
|
Callback = callback;
|
||||||
ClassName = "MessageWindowBaseClass+" + Guid.NewGuid().ToString();
|
ClassName = $"MessageWindowBase+{Guid.NewGuid()}";
|
||||||
|
|
||||||
CreateWindow();
|
hwnd = CreateWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Finalizes an instance of the <see cref="BasicMessageWindow"/> class.</summary>
|
/// <summary>Finalizes an instance of the <see cref="BasicMessageWindow"/> class.</summary>
|
||||||
~BasicMessageWindow()
|
~BasicMessageWindow() => Dispose(false);
|
||||||
{
|
|
||||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
||||||
Dispose(disposing: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets or sets the callback method used to filter window messages.</summary>
|
/// <summary>Gets or sets the callback method used to filter window messages.</summary>
|
||||||
/// <value>The callback method.</value>
|
/// <value>The callback method.</value>
|
||||||
|
@ -51,11 +39,7 @@ namespace Vanara.PInvoke
|
||||||
|
|
||||||
/// <summary>Gets the handle.</summary>
|
/// <summary>Gets the handle.</summary>
|
||||||
/// <value>The handle.</value>
|
/// <value>The handle.</value>
|
||||||
public HWND Handle => hWnd;
|
public HWND Handle => hwnd;
|
||||||
|
|
||||||
/// <summary>Returns the value of the handle field.</summary>
|
|
||||||
/// <returns>An IntPtr representing the value of the handle field.</returns>
|
|
||||||
public IntPtr DangerousGetHandle() => ((IHandle)hWnd).DangerousGetHandle();
|
|
||||||
|
|
||||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -64,23 +48,18 @@ namespace Vanara.PInvoke
|
||||||
System.GC.SuppressFinalize(this);
|
System.GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns the value of the handle field.</summary>
|
||||||
|
/// <returns>An IntPtr representing the value of the handle field.</returns>
|
||||||
|
IntPtr IHandle.DangerousGetHandle() => (IntPtr)Handle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method used to create the window. When overriding, the <c>hWnd</c> field must be set to the handle of the created window.
|
/// Method used to create the window. When overriding, the <c>hWnd</c> field must be set to the handle of the created window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void CreateWindow()
|
protected virtual SafeHWND CreateWindow()
|
||||||
{
|
{
|
||||||
var wc = new WNDCLASSEX
|
if (0 == RegisterClassEx(new WNDCLASSEX { cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)), lpfnWndProc = WndProc, hInstance = GetModuleHandle(), lpszClassName = ClassName }))
|
||||||
{
|
Win32Error.ThrowLastError();
|
||||||
cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)),
|
return Win32Error.ThrowLastErrorIfInvalid(CreateWindowEx(lpClassName: ClassName, lpWindowName: ClassName, hWndParent: HWND.HWND_MESSAGE));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
|
/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
|
||||||
|
@ -93,37 +72,19 @@ namespace Vanara.PInvoke
|
||||||
return;
|
return;
|
||||||
|
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
hWnd.Dispose();
|
|
||||||
|
hwnd?.Dispose();
|
||||||
|
|
||||||
UnregisterClass(ClassName, GetModuleHandle());
|
UnregisterClass(ClassName, GetModuleHandle());
|
||||||
ClassName = null;
|
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;
|
var ret = (Callback ?? DefWindowProc).Invoke(hwnd, msg, wParam, lParam);
|
||||||
|
|
||||||
if (msg == (uint)WindowMessage.WM_CREATE)
|
|
||||||
{
|
|
||||||
var createStruct = lParam.ToStructure<CREATESTRUCT>();
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (msg == (uint)WindowMessage.WM_NCDESTROY)
|
if (msg == (uint)WindowMessage.WM_NCDESTROY)
|
||||||
{
|
Dispose(true);
|
||||||
hwndWrapper.Dispose(true);
|
|
||||||
System.GC.SuppressFinalize(hwndWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,27 @@ namespace Vanara.PInvoke.Tests
|
||||||
TestContext.WriteLine($"{array[i].dwID} = {array[i].dwWant} / {array[i].dwBlock}");
|
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()]
|
[Test()]
|
||||||
public void GetWindowLongTest()
|
public void GetWindowLongTest()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue