using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace Standard; internal sealed class SafeDC : SafeHandleZeroOrMinusOneIsInvalid { public IntPtr Hwnd { set { this._hwnd = new IntPtr?(value); } } private SafeDC() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { if (this._created) { return SafeDC.NativeMethods.DeleteDC(this.handle); } return this._hwnd == null || this._hwnd.Value == IntPtr.Zero || SafeDC.NativeMethods.ReleaseDC(this._hwnd.Value, this.handle) == 1; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] public static SafeDC CreateDC(string deviceName) { SafeDC safeDC = null; try { safeDC = SafeDC.NativeMethods.CreateDC(deviceName, null, IntPtr.Zero, IntPtr.Zero); } finally { if (safeDC != null) { safeDC._created = true; } } if (safeDC.IsInvalid) { safeDC.Dispose(); throw new SystemException("Unable to create a device context from the specified device information."); } return safeDC; } [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static SafeDC CreateCompatibleDC(SafeDC hdc) { SafeDC safeDC = null; try { IntPtr hdc2 = IntPtr.Zero; if (hdc != null) { hdc2 = hdc.handle; } safeDC = SafeDC.NativeMethods.CreateCompatibleDC(hdc2); if (safeDC == null) { HRESULT.ThrowLastError(); } } finally { if (safeDC != null) { safeDC._created = true; } } if (safeDC.IsInvalid) { safeDC.Dispose(); throw new SystemException("Unable to create a device context from the specified device information."); } return safeDC; } public static SafeDC GetDC(IntPtr hwnd) { SafeDC safeDC = null; try { safeDC = SafeDC.NativeMethods.GetDC(hwnd); } finally { if (safeDC != null) { safeDC.Hwnd = hwnd; } } if (safeDC.IsInvalid) { HRESULT.E_FAIL.ThrowIfFailed(); } return safeDC; } public static SafeDC GetDesktop() { return SafeDC.GetDC(IntPtr.Zero); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] public static SafeDC WrapDC(IntPtr hdc) { return new SafeDC { handle = hdc, _created = false, _hwnd = new IntPtr?(IntPtr.Zero) }; } private IntPtr? _hwnd; private bool _created; private static class NativeMethods { [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll")] public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll")] public static extern SafeDC GetDC(IntPtr hwnd); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] public static extern SafeDC CreateDC([MarshalAs(UnmanagedType.LPWStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPWStr)] string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern SafeDC CreateCompatibleDC(IntPtr hdc); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("gdi32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeleteDC(IntPtr hdc); } }