Added nullability to Magnification and tests

nullableenabled
David Hall 2023-10-06 19:35:05 -06:00
parent 163affe6ba
commit 3aa52d622f
3 changed files with 98 additions and 78 deletions

View File

@ -394,6 +394,38 @@ public static partial class Magnification
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MagSetColorEffect(HWND hwnd, in MAGCOLOREFFECT pEffect);
/// <summary>Sets the color transformation matrix for a magnifier control.</summary>
/// <param name="hwnd">
/// <para>Type: <c>HWND</c></para>
/// <para>The magnification window.</para>
/// </param>
/// <param name="pEffect">
/// <para>Type: <c>PMAGCOLOREFFECT</c></para>
/// <para>The color transformation matrix, or <c>NULL</c> to remove the current color effect, if any.</para>
/// </param>
/// <returns>
/// <para>Type: <c>BOOL</c></para>
/// <para>Returns <c>TRUE</c> if successful, or <c>FALSE</c> otherwise.</para>
/// </returns>
/// <remarks>
/// <para>
/// The magnifier control uses the color transformation matrix to apply a color effect to the entire magnifier window. If the
/// function is called multiple times, the most recent color transform is used.
/// </para>
/// <para>This function requires Windows Display Driver Model (WDDM)-capable video cards.</para>
/// <para>Examples</para>
/// <para>The following example sets a color transformation matrix that converts the colors displayed in the magnifier to grayscale.</para>
/// <para>
/// <code>// Description: // Converts the colors displayed in the magnifier window to grayscale, or // returns the colors to normal. // Parameters: // hwndMag - Handle of the magnifier control. // fInvert - TRUE to convert to grayscale, or FALSE for normal colors. // BOOL ConvertToGrayscale(HWND hwndMag, BOOL fConvert) { // Convert the screen colors in the magnifier window. if (fConvert) { MAGCOLOREFFECT magEffectGrayscale = {{ // MagEffectGrayscale { 0.3f, 0.3f, 0.3f, 0.0f, 0.0f }, { 0.6f, 0.6f, 0.6f, 0.0f, 0.0f }, { 0.1f, 0.1f, 0.1f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }}; return MagSetColorEffect(hwndMag, &amp;magEffectGrayscale); } // Return the colors to normal. else { return MagSetColorEffect(hwndMag, NULL); } }</code>
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/win32/api/magnification/nf-magnification-magsetcoloreffect BOOL MagSetColorEffect( HWND
// hwnd, PMAGCOLOREFFECT pEffect );
[DllImport(Lib_Magnification, SetLastError = false, ExactSpelling = true)]
[PInvokeData("magnification.h", MSDNShortId = "NF:magnification.MagSetColorEffect")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MagSetColorEffect(HWND hwnd, [In, Optional] IntPtr pEffect);
/// <summary>Changes the color transformation matrix associated with the full-screen magnifier.</summary>
/// <param name="pEffect">
/// <para>Type: <c>PMAGCOLOREFFECT</c></para>
@ -529,7 +561,7 @@ public static partial class Magnification
[DllImport(Lib_Magnification, SetLastError = false, ExactSpelling = true)]
[PInvokeData("magnification.h", MSDNShortId = "NF:magnification.MagSetImageScalingCallback")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MagSetImageScalingCallback(HWND hwnd, MagImageScalingCallback callback);
public static extern bool MagSetImageScalingCallback(HWND hwnd, MagImageScalingCallback? callback);
/// <summary>
/// Sets the current active input transformation for pen and touch input, represented as a source rectangle and a destination rectangle.
@ -579,7 +611,7 @@ public static partial class Magnification
[DllImport(Lib_Magnification, SetLastError = true, ExactSpelling = true)]
[PInvokeData("magnification.h", MSDNShortId = "NF:magnification.MagSetInputTransform")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MagSetInputTransform([MarshalAs(UnmanagedType.Bool)] bool fEnabled, [Optional] in RECT pRectSource, [Optional] in RECT pRectDest);
public static extern bool MagSetInputTransform([MarshalAs(UnmanagedType.Bool)] bool fEnabled, [In, Optional] PRECT? pRectSource, [In, Optional] PRECT? pRectDest);
/// <summary>Sets the list of windows to be magnified or the list of windows to be excluded from magnification.</summary>
/// <param name="hwnd">
@ -737,7 +769,7 @@ public static partial class Magnification
// { float transform[5][5]; } MAGCOLOREFFECT, *PMAGCOLOREFFECT;
[PInvokeData("magnification.h", MSDNShortId = "NS:magnification.tagMAGCOLOREFFECT")]
[StructLayout(LayoutKind.Sequential)]
public struct MAGCOLOREFFECT
public struct MAGCOLOREFFECT : IEquatable<MAGCOLOREFFECT>
{
private const int dimLen = 5;
@ -916,41 +948,6 @@ public static partial class Magnification
public static bool operator !=(MAGCOLOREFFECT lhs, MAGCOLOREFFECT rhs) => !(lhs == rhs);
/// <summary>An Identity Matrix for MAGCOLOREFFECT.</summary>
/* Unmerged change from project 'Vanara.PInvoke.Magnification (net48)'
Before:
public static readonly MAGCOLOREFFECT Identity = new MAGCOLOREFFECT { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
After:
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
*/
/* Unmerged change from project 'Vanara.PInvoke.Magnification (net7.0)'
Before:
public static readonly MAGCOLOREFFECT Identity = new MAGCOLOREFFECT { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
After:
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
*/
/* Unmerged change from project 'Vanara.PInvoke.Magnification (netcoreapp3.1)'
Before:
public static readonly MAGCOLOREFFECT Identity = new MAGCOLOREFFECT { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
After:
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
*/
/* Unmerged change from project 'Vanara.PInvoke.Magnification (netstandard2.0)'
Before:
public static readonly MAGCOLOREFFECT Identity = new MAGCOLOREFFECT { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
After:
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
*/
/* Unmerged change from project 'Vanara.PInvoke.Magnification (net45)'
Before:
public static readonly MAGCOLOREFFECT Identity = new MAGCOLOREFFECT { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
After:
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
*/
public static readonly MAGCOLOREFFECT Identity = new() { transform00 = 1, transform11 = 1, transform22 = 1, transform33 = 1, transform44 = 1 };
}

View File

@ -291,7 +291,7 @@ public class WindowBase : MarshalByRefObject, IDisposable, IWindowInstance, IWin
/// <summary>Performs an implicit conversion from <see cref="WindowBase"/> to <see cref="HWND"/>.</summary>
/// <param name="w">The <see cref="WindowBase"/> instance.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator HWND(WindowBase w) => w.Handle;
public static implicit operator HWND(WindowBase? w) => w?.Handle ?? HWND.NULL;
[DebuggerStepThrough]
private void CheckDetached()

View File

@ -1,6 +1,8 @@
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Diagnostics;
using static Vanara.PInvoke.Magnification;
using static Vanara.PInvoke.User32;
namespace Vanara.PInvoke.Tests;
@ -14,6 +16,13 @@ public class MagnificationTests
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }});
//static readonly MAGCOLOREFFECT invert = new(new[,] {
// { -1.0f, 0.0f, 0.0f, 0.0f, 0.0f },
// { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f },
// { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },
// { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f },
// { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }});
[OneTimeSetUp]
public void _Setup()
{
@ -26,6 +35,58 @@ public class MagnificationTests
Assert.IsTrue(MagUninitialize());
}
[Test]
public void GetSetMagEffect()
{
VisibleWindow? hwndHost = null;
HWND hwndMag = default;
new System.Threading.Thread(() =>
{
const string WindowClassName = "Magnification Test";
HINSTANCE hInst = Kernel32.GetModuleHandle().ReleaseOwnership();
hwndHost = new VisibleWindow(WindowClassName, hInst, WindowClassName, new SIZE(300, 200), exStyle: WindowStylesEx.WS_EX_TOPMOST | WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_TRANSPARENT);
Assert.False(hwndHost.Handle.IsNull);
// Make the window opaque.
SetLayeredWindowAttributes(hwndHost, 0, 255, LayeredWindowAttributes.LWA_ALPHA);
// Create a magnifier control that fills the client area.
var r = hwndHost.ClientRect;
var tmp = CreateWindow(WC_MAGNIFIER, "MagnifierWindow", WindowStyles.WS_CHILD | (WindowStyles)MagnifierStyles.MS_SHOWMAGNIFIEDCURSOR | WindowStyles.WS_VISIBLE,
0, 0, r.Width, r.Height, hwndHost, default, hInst);
if ((hwndMag = tmp.ReleaseOwnership()) != HWND.NULL)
{
hwndHost.Show();
new MessagePump().Run(hwndHost);
}
}).Start();
System.Threading.Thread.Yield();
System.Threading.Thread.Sleep(500);
try
{
Assert.That(hwndMag, ResultIs.ValidHandle);
Assert.That(MagGetColorEffect(GetDesktopWindow(), out var eff), ResultIs.FailureCode(Win32Error.ERROR_NOT_SUPPORTED));
Assert.That(MagSetColorEffect(GetDesktopWindow(), eff), ResultIs.FailureCode(Win32Error.ERROR_NOT_SUPPORTED));
MAGTRANSFORM matrix = new(2f);
Assert.That(MagSetWindowTransform(hwndMag, matrix), ResultIs.Successful);
Assert.That(MagGetWindowTransform(hwndMag, out var m2), ResultIs.Successful);
Assert.AreEqual(matrix, m2);
Assert.That(MagGetColorEffect(hwndMag, out eff), ResultIs.Successful);
Assert.True(eff.IsIdentity);
Assert.That(MagSetColorEffect(hwndMag, grayeff), ResultIs.Successful);
Assert.That(MagSetColorEffect(hwndMag), ResultIs.Successful);
}
finally
{
hwndHost?.Close();
}
}
[Test]
public void MagGetSetFullscreenTransformTest()
{
@ -47,7 +108,7 @@ public class MagnificationTests
{
Assert.That(MagSetFullscreenColorEffect(grayeff), ResultIs.Successful);
Assert.That(MagGetFullscreenColorEffect(out var grayeff_get), ResultIs.Successful);
Assert.That(grayeff.transform, Is.EquivalentTo(grayeff_get.transform));
Assert.AreEqual(grayeff, grayeff_get);
System.Threading.Thread.Sleep(1000);
Assert.That(MagSetFullscreenColorEffect(MAGCOLOREFFECT.Identity), ResultIs.Successful);
}
@ -110,42 +171,4 @@ public class MagnificationTests
Assert.AreEqual(11.2f, tfx[1, 2]);
Assert.AreEqual(12.2f, tfx[2, 2]);
}
/*
private static bool CreateMagnifier(HINSTANCE hInstance)
{
const string WindowClassName = "Magnification Test";
// Register the host window class.
var wcex = new WNDCLASSEX
{
cbSize = (uint)Marshal.SizeOf<WNDCLASSEX>(),
style = 0,
lpfnWndProc = HostWndProc,
hInstance = hInstance,
hCursor = LoadCursor(default, IDC_ARROW),
hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE),
lpszClassName = WindowClassName
};
if (RegisterClassEx(wcex) == 0)
return false;
// Create the host window.
hwndHost = CreateWindowEx(WindowStylesEx.WS_EX_TOPMOST | WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_TRANSPARENT,
WindowClassName, WindowClassName, WindowStyles.WS_CLIPCHILDREN, 0, 0, 0, 0, default, default, hInstance, default);
if (hwndHost.IsInvalid)
return false;
// Make the window opaque.
SetLayeredWindowAttributes(hwndHost, 0, 255, LayeredWindowAttributes.LWA_ALPHA);
// Create a magnifier control that fills the client area.
hwndMag = CreateWindow(WC_MAGNIFIER, "MagnifierWindow", WindowStyles.WS_CHILD | WindowStyles.MS_SHOWMAGNIFIEDCURSOR | WindowStyles.WS_VISIBLE,
0, 0, LENS_WIDTH, LENS_HEIGHT, hwndHost, NULL, hInstance, NULL);
return !hwndMag.IsInvalid;
}
private static IntPtr HostWndProc(HWND hwnd, uint uMsg, IntPtr wParam, IntPtr lParam) => throw new NotImplementedException();
*/
}