更新
This commit is contained in:
357
AntdWpf/Microsoft.Windows.Shell/Standard/Utilities.cs
Normal file
357
AntdWpf/Microsoft.Windows.Shell/Standard/Utilities.cs
Normal file
@@ -0,0 +1,357 @@
|
||||
using Standard;
|
||||
// This file contains general utilities to aid in development.
|
||||
// Classes here generally shouldn't be exposed publicly since
|
||||
// they're not particular to any library functionality.
|
||||
// Because the classes here are internal, it's likely this file
|
||||
// might be included in multiple assemblies.
|
||||
#pragma warning disable 1591, 618
|
||||
namespace AntdWpf.Microsoft.Windows.Shell.Standard
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
internal static partial class Utility
|
||||
{
|
||||
private static readonly Version _osVersion = Environment.OSVersion.Version;
|
||||
private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version;
|
||||
|
||||
/// <summary>Convert a native integer that represent a color with an alpha channel into a Color struct.</summary>
|
||||
/// <param name="color">The integer that represents the color. Its bits are of the format 0xAARRGGBB.</param>
|
||||
/// <returns>A Color representation of the parameter.</returns>
|
||||
public static Color ColorFromArgbDword(uint color)
|
||||
{
|
||||
return Color.FromArgb(
|
||||
(byte)((color & 0xFF000000) >> 24),
|
||||
(byte)((color & 0x00FF0000) >> 16),
|
||||
(byte)((color & 0x0000FF00) >> 8),
|
||||
(byte)((color & 0x000000FF) >> 0));
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static int GET_X_LPARAM(IntPtr lParam)
|
||||
{
|
||||
return LOWORD(lParam.ToInt32());
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static int GET_Y_LPARAM(IntPtr lParam)
|
||||
{
|
||||
return HIWORD(lParam.ToInt32());
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static int HIWORD(int i)
|
||||
{
|
||||
return (short)(i >> 16);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static int LOWORD(int i)
|
||||
{
|
||||
return (short)(i & 0xFFFF);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsFlagSet(int value, int mask)
|
||||
{
|
||||
return 0 != (value & mask);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsFlagSet(uint value, uint mask)
|
||||
{
|
||||
return 0 != (value & mask);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsFlagSet(long value, long mask)
|
||||
{
|
||||
return 0 != (value & mask);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsFlagSet(ulong value, ulong mask)
|
||||
{
|
||||
return 0 != (value & mask);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsOSVistaOrNewer
|
||||
{
|
||||
get { return _osVersion >= new Version(6, 0); }
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static bool IsOSWindows7OrNewer
|
||||
{
|
||||
get { return _osVersion >= new Version(6, 1); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is this using WPF4?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds
|
||||
/// when handling WM_NCCALCSIZE on the HWND.
|
||||
/// </remarks>
|
||||
public static bool IsPresentationFrameworkVersionLessThan4
|
||||
{
|
||||
get { return _presentationFrameworkVersion < new Version(4, 0); }
|
||||
}
|
||||
|
||||
public static BitmapFrame GetBestMatch(IList<BitmapFrame> frames, int width, int height)
|
||||
{
|
||||
return _GetBestMatch(frames, _GetBitDepth(), width, height);
|
||||
}
|
||||
|
||||
private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp)
|
||||
{
|
||||
int score = 2 * _WeightedAbs(bpp, bitDepth, false) +
|
||||
_WeightedAbs(frame.PixelWidth, width, true) +
|
||||
_WeightedAbs(frame.PixelHeight, height, true);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish)
|
||||
{
|
||||
int diff = (valueHave - valueWant);
|
||||
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = (fPunish ? -2 : -1) * diff;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
/// From a list of BitmapFrames find the one that best matches the requested dimensions.
|
||||
/// The methods used here are copied from Win32 sources. We want to be consistent with
|
||||
/// system behaviors.
|
||||
private static BitmapFrame _GetBestMatch(IList<BitmapFrame> frames, int bitDepth, int width, int height)
|
||||
{
|
||||
int bestScore = int.MaxValue;
|
||||
int bestBpp = 0;
|
||||
int bestIndex = 0;
|
||||
|
||||
bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder;
|
||||
|
||||
for (int i = 0; i < frames.Count && bestScore != 0; ++i)
|
||||
{
|
||||
int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel;
|
||||
|
||||
if (currentIconBitDepth == 0)
|
||||
{
|
||||
currentIconBitDepth = 8;
|
||||
}
|
||||
|
||||
int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
bestScore = score;
|
||||
}
|
||||
else if (score == bestScore)
|
||||
{
|
||||
// Tie breaker: choose the higher color depth. If that fails, choose first one.
|
||||
if (bestBpp < currentIconBitDepth)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames[bestIndex];
|
||||
}
|
||||
|
||||
// This can be cached. It's not going to change under reasonable circumstances.
|
||||
private static int s_bitDepth; // = 0;
|
||||
|
||||
/// <SecurityNote>
|
||||
/// Critical : Calls critical methods to obtain desktop bits per pixel
|
||||
/// Safe : BPP is considered safe information in partial trust
|
||||
/// </SecurityNote>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
private static int _GetBitDepth()
|
||||
{
|
||||
if (s_bitDepth == 0)
|
||||
{
|
||||
using (SafeDC dc = SafeDC.GetDesktop())
|
||||
{
|
||||
s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES);
|
||||
}
|
||||
}
|
||||
return s_bitDepth;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static void SafeDeleteObject(ref IntPtr gdiObject)
|
||||
{
|
||||
IntPtr p = gdiObject;
|
||||
gdiObject = IntPtr.Zero;
|
||||
if (IntPtr.Zero != p)
|
||||
{
|
||||
NativeMethods.DeleteObject(p);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static void SafeDestroyWindow(ref IntPtr hwnd)
|
||||
{
|
||||
IntPtr p = hwnd;
|
||||
hwnd = IntPtr.Zero;
|
||||
if (NativeMethods.IsWindow(p))
|
||||
{
|
||||
NativeMethods.DestroyWindow(p);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
|
||||
public static void SafeRelease<T>(ref T comObject) where T : class
|
||||
{
|
||||
T t = comObject;
|
||||
comObject = default(T);
|
||||
if (null != t)
|
||||
{
|
||||
Assert.IsTrue(Marshal.IsComObject(t));
|
||||
Marshal.ReleaseComObject(t);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Assert.IsNotNull(property);
|
||||
Assert.IsNotNull(listener);
|
||||
|
||||
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType());
|
||||
dpd.AddValueChanged(component, listener);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Assert.IsNotNull(property);
|
||||
Assert.IsNotNull(listener);
|
||||
|
||||
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType());
|
||||
dpd.RemoveValueChanged(component, listener);
|
||||
}
|
||||
|
||||
#region Extension Methods
|
||||
|
||||
public static bool IsThicknessNonNegative(Thickness thickness)
|
||||
{
|
||||
if (!IsDoubleFiniteAndNonNegative(thickness.Top))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(thickness.Left))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(thickness.Bottom))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(thickness.Right))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsCornerRadiusValid(CornerRadius cornerRadius)
|
||||
{
|
||||
if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsDoubleFiniteAndNonNegative(double d)
|
||||
{
|
||||
if (double.IsNaN(d) || double.IsInfinity(d) || d < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
|
||||
public static void SafeFreeHGlobal(ref IntPtr hglobal)
|
||||
{
|
||||
IntPtr p = hglobal;
|
||||
hglobal = IntPtr.Zero;
|
||||
if (IntPtr.Zero != p)
|
||||
{
|
||||
Marshal.FreeHGlobal(p);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static void SafeDispose<T>(ref T disposable) where T : IDisposable
|
||||
{
|
||||
// Dispose can safely be called on an object multiple times.
|
||||
IDisposable t = disposable;
|
||||
disposable = default(T);
|
||||
if (null != t)
|
||||
{
|
||||
t.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// See: http://stackoverflow.com/questions/7913325/win-api-in-c-get-hi-and-low-word-from-intptr/7913393#7913393
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
public static System.Windows.Point GetPoint(IntPtr ptr)
|
||||
{
|
||||
var xy = unchecked(Environment.Is64BitProcess ? (uint)ptr.ToInt64() : (uint)ptr.ToInt32());
|
||||
var x = unchecked((short)xy);
|
||||
var y = unchecked((short)(xy >> 16));
|
||||
return new System.Windows.Point(x, y);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user