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; /// Convert a native integer that represent a color with an alpha channel into a Color struct. /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. /// A Color representation of the parameter. 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); } } /// /// Is this using WPF4? /// /// /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds /// when handling WM_NCCALCSIZE on the HWND. /// public static bool IsPresentationFrameworkVersionLessThan4 { get { return _presentationFrameworkVersion < new Version(4, 0); } } public static BitmapFrame GetBestMatch(IList 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 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; /// /// Critical : Calls critical methods to obtain desktop bits per pixel /// Safe : BPP is considered safe information in partial trust /// [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(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(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 } }