/// <devdoc> /// Saves the current state of the device context by copying data describing selected objects and graphic /// modes (such as the bitmap, brush, palette, font, pen, region, drawing mode, and mapping mode) to a /// context stack. /// The SaveDC function can be used any number of times to save any number of instances of the DC state. /// A saved state can be restored by using the RestoreHdc method. /// See MSDN for more details. /// </devdoc> public int SaveHdc() { HandleRef hdc = new HandleRef(this, this.Hdc); int state = IntUnsafeNativeMethods.SaveDC(hdc); if (contextStack == null) { contextStack = new Stack(); } GraphicsState g = new GraphicsState(); g.hBitmap = hCurrentBmp; g.hBrush = hCurrentBrush; g.hPen = hCurrentPen; g.hFont = hCurrentFont; #if !DRAWING_NAMESPACE g.font = new WeakReference(selectedFont); #endif contextStack.Push(g); #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("state[0]=DC.SaveHdc(hDc=0x{1:x8})", state, unchecked ((int)this.hDC)))); #endif return(state); }
/// <summary> /// Creates the font handle. /// </summary> private void CreateFont() { Debug.Assert(hFont == IntPtr.Zero, "hFont is not null, this will generate a handle leak."); Debug.Assert(logFont != null, "WindowsFont.logFont not initialized."); hFont = IntUnsafeNativeMethods.CreateFontIndirect(logFont); #if TRACK_HFONT Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int)this.hFont, this.logFont))); #endif if (hFont == IntPtr.Zero) { logFont.lfFaceName = defaultFaceName; logFont.lfOutPrecision = IntNativeMethods.OUT_TT_ONLY_PRECIS; // True Type only. hFont = IntUnsafeNativeMethods.CreateFontIndirect(logFont); #if TRACK_HFONT Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("HFONT[0x{0:x8}] = CreateFontIndirect( LOGFONT={1} )", (int)this.hFont, this.logFont))); #endif } // Update logFont height and other adjusted parameters. // IntUnsafeNativeMethods.GetObject(new HandleRef(this, hFont), logFont); // We created the hFont, we will delete it on dispose. ownHandle = true; }
internal void Dispose(bool disposing) { bool deletedHandle = false; if (ownHandle) { if (!ownedByCacheManager || !disposing) { // If we were ever owned by the CacheManger and we're being disposed // we can be sure that we're not in use by any DC's (otherwise Dispose() wouldn't have been called) // skip the check IsFontInUse check in this case. // Also skip the check if disposing == false, because the cache is thread-static // and that means we're being called from the finalizer. if (everOwnedByCacheManager || !disposing || !DeviceContexts.IsFontInUse(this)) { Debug.Assert(hFont != IntPtr.Zero, "Unexpected null hFont."); DbgUtil.AssertFinalization(this, disposing); IntUnsafeNativeMethods.DeleteObject(new HandleRef(this, hFont)); #if TRACK_HFONT Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("DeleteObject(HFONT[0x{0:x8}]))", (int)this.hFont))); #endif hFont = IntPtr.Zero; ownHandle = false; deletedHandle = true; } } } if (disposing && (deletedHandle || !ownHandle)) { GC.SuppressFinalize(this); } }
/// <devdoc> /// Dispose of cached memory dc. /// </devdoc> public static void ResetMeasurementGraphics() { if (measurementGraphics != null) { #if TRACK_HDC //Debug.WriteLine( DbgUtil.StackTraceToStr(string.Format("Disposing measurement DC and WG for thread: [0x{0:x8}]", Thread.CurrentThread.ManagedThreadId))); Debug.WriteLine(DbgUtil.StackTraceToStr("Disposing measurement DC and WG")); #endif measurementGraphics.Dispose(); measurementGraphics = null; } }
// // object construction API. Publicly constructable from static methods only. // /// <devdoc> /// Constructor to contruct a DeviceContext object from an window handle. /// </devdoc> private DeviceContext(IntPtr hWnd) { this.hWnd = hWnd; this.dcType = DeviceContextType.Display; DeviceContexts.AddDeviceContext(this); // the hDc will be created on demand. #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("DeviceContext( hWnd=0x{0:x8} )", unchecked ((int)hWnd)))); #endif }
/// <include file='doc\IDeviceContext.uex' path='docs/doc[@for="DeviceContext.ReleaseHdc"]/*' /> ///<devdoc> /// If the object was created from a DC, this object doesn't 'own' the dc so we just ignore /// this call. ///</devdoc> void IDeviceContext.ReleaseHdc() { if (this.hDC != IntPtr.Zero && this.dcType == DeviceContextType.Display) { #if TRACK_HDC int retVal = #endif IntUnsafeNativeMethods.ReleaseDC(new HandleRef(this, this.hWnd), new HandleRef(this, this.hDC)); // Note: retVal == 0 means it was not released but doesn't necessarily means an error; class or private DCs are never released. #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("[ret={0}]=DC.ReleaseDC(hDc=0x{1:x8}, hWnd=0x{2:x8})", retVal, unchecked ((int)this.hDC), unchecked ((int)this.hWnd)))); #endif this.hDC = IntPtr.Zero; } }
/// <include file='doc\IDeviceContext.uex' path='docs/doc[@for="DeviceContext.GetHdc"]/*' /> /// <devdoc> /// Explicit interface method implementation to hide them a bit for usability reasons so the object is seen /// as a wrapper around an hdc that is always available, and for performance reasons since it caches the hdc /// if used in this way. /// </devdoc> IntPtr IDeviceContext.GetHdc() { if (this.hDC == IntPtr.Zero) { Debug.Assert(this.dcType == DeviceContextType.Display, "Calling GetDC from a non display/window device."); // Note: for common DCs, GetDC assigns default attributes to the DC each time it is retrieved. // For example, the default font is System. this.hDC = IntUnsafeNativeMethods.GetDC(new HandleRef(this, this.hWnd)); #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("hdc[0x{0:x8}]=DC.GetHdc(hWnd=0x{1:x8})", unchecked ((int)this.hDC), unchecked ((int)this.hWnd)))); #endif } return(this.hDC); }
/// <devdoc> /// Constructor to contruct a DeviceContext object from an existing Win32 device context handle. /// </devdoc> private DeviceContext(IntPtr hDC, DeviceContextType dcType) { this.hDC = hDC; this.dcType = dcType; CacheInitialState(); DeviceContexts.AddDeviceContext(this); if (dcType == DeviceContextType.Display) { this.hWnd = IntUnsafeNativeMethods.WindowFromDC(new HandleRef(this, this.hDC)); } #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("DeviceContext( hDC=0x{0:X8}, Type={1} )", unchecked ((int)hDC), dcType))); #endif }
/// <devdoc> /// Restores the device context to the specified state. The DC is restored by popping state information off a /// stack created by earlier calls to the SaveHdc function. /// The stack can contain the state information for several instances of the DC. If the state specified by the /// specified parameter is not at the top of the stack, RestoreDC deletes all state information between the top /// of the stack and the specified instance. /// Specifies the saved state to be restored. If this parameter is positive, nSavedDC represents a specific /// instance of the state to be restored. If this parameter is negative, nSavedDC represents an instance relative /// to the current state. For example, -1 restores the most recently saved state. /// See MSDN for more info. /// </devdoc> public void RestoreHdc() { #if TRACK_HDC bool result = #endif // Note: Don't use the Hdc property here, it would force handle creation. IntUnsafeNativeMethods.RestoreDC(new HandleRef(this, this.hDC), -1); #if TRACK_HDC // Note: Winforms may call this method during app exit at which point the DC may have been finalized already causing this assert to popup. Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("ret[0]=DC.RestoreHdc(hDc=0x{1:x8})", result, unchecked ((int)this.hDC)))); #endif Debug.Assert(contextStack != null, "Someone is calling RestoreHdc() before SaveHdc()"); if (contextStack != null) { GraphicsState g = (GraphicsState)contextStack.Pop(); hCurrentBmp = g.hBitmap; hCurrentBrush = g.hBrush; hCurrentPen = g.hPen; hCurrentFont = g.hFont; #if !DRAWING_NAMESPACE if (g.font != null && g.font.IsAlive) { selectedFont = g.font.Target as WindowsFont; } else { WindowsFont previousFont = selectedFont; selectedFont = null; if (previousFont != null && MeasurementDCInfo.IsMeasurementDC(this)) { previousFont.Dispose(); } } #endif } #if OPTIMIZED_MEASUREMENTDC // in this case, GDI will copy back the previously saved font into the DC. // we dont actually know what the font is in our measurement DC so // we need to clear it off. MeasurementDCInfo.ResetIfIsMeasurementDC(this.hDC); #endif }
/// <include file='doc\IDeviceContext.uex' path='docs/doc[@for="DeviceContext.Dispose1"]/*' /> internal void Dispose(bool disposing) { if (disposed) { return; } if (this.Disposing != null) { this.Disposing(this, EventArgs.Empty); } this.disposed = true; #if !DRAWING_NAMESPACE DisposeFont(disposing); #endif switch (this.dcType) { case DeviceContextType.Display: Debug.Assert(disposing, "WARNING: Finalizing a Display DeviceContext.\r\nReleaseDC may fail when not called from the same thread GetDC was called from."); ((IDeviceContext)this).ReleaseHdc(); break; case DeviceContextType.Information: case DeviceContextType.NamedDevice: // CreateDC and CreateIC add an HDC handle to the HandleCollector; to remove it properly we need // to call DeleteHDC. #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("DC.DeleteHDC(hdc=0x{0:x8})", unchecked ((int)this.hDC)))); #endif IntUnsafeNativeMethods.DeleteHDC(new HandleRef(this, this.hDC)); this.hDC = IntPtr.Zero; break; case DeviceContextType.Memory: // CreatCompatibleDC adds a GDI handle to HandleCollector, to remove it properly we need to call // DeleteDC. #if TRACK_HDC Debug.WriteLine(DbgUtil.StackTraceToStr(String.Format("DC.DeleteDC(hdc=0x{0:x8})", unchecked ((int)this.hDC)))); #endif IntUnsafeNativeMethods.DeleteDC(new HandleRef(this, this.hDC)); this.hDC = IntPtr.Zero; break; // case DeviceContextType.Metafile: - not yet supported. #if WINFORMS_PUBLIC_GRAPHICS_LIBRARY case DeviceContextType.Metafile: IntUnsafeNativeMethods.CloseEnhMetaFile(new HandleRef(this, this.Hdc)); this.hDC = IntPtr.Zero; break; #endif case DeviceContextType.Unknown: default: return; // do nothing, the hdc is not owned by this object. // in this case it is ok if disposed throught finalization. } DbgUtil.AssertFinalization(this, disposing); }