Managing un-managed Resources
Posted
Fri, Nov 24 2006 8:19
by
bill
DeclareFunction ReleaseDC Lib"user32" (ByVal hwnd As IntPtr, ByVal dc As IntPtr) As Int32
So Chuck's code on first iteration would then become:
Dim g As Graphics = Me.CreateGraphics()
'Get the Graphics context to blt into
Dim Desktop_Hwnd As IntPtr
Dim Desktop_HDC As IntPtr
Desktop_Hwnd = GetDesktopWindow()
Desktop_HDC = GetWindowDC(Desktop_Hwnd)
Debug.Print(StretchBlt(g.GetHdc, 0, 0, Me.Width, Me.Height, Desktop_HDC, 0, 0, Me.Height / 2, Me.Width / 2, SRCCOPY))
'Slam the super sized desktop into graphics context of your form.
ReleaseDC(Desktop_Hwnd, Desktop_HDC)
Okay so far we have released the unmanaged resource (DeviceContext). Problem two is the graphics object itself should be disposed of by calling Dispose on it rather than waiting for a GC collection to call its finalizer . So with the graphics object, we should probably use a Using block.
And with our DC, we probably want to ensure that Release gets called, so we'd need to wrap that in a Try Finalize block. We can't use a Using block for the DC as it doesn't implement IDisposable.
Using g As Graphics = Me.CreateGraphics()
'Get the Graphics context to blt into
Dim Desktop_Hwnd As IntPtr
Dim Desktop_HDC As IntPtr
Try
Desktop_Hwnd = GetDesktopWindow()
Desktop_HDC = GetWindowDC(Desktop_Hwnd)
Debug.Print(StretchBlt(g.GetHdc, 0, 0, Me.Width, Me.Height, Desktop_HDC, 0, 0, Me.Height / 2, Me.Width / 2, SRCCOPY))
'Slam the super sized desktop into graphics context of your form.
Finally
ReleaseDC(Desktop_Hwnd, Desktop_HDC)
End Try
End Using
Alternatively we can get all OO, and encapsulate the DC in a class that does implement IDisposable. Our code would then look like:
Using g As Graphics = Me.CreateGraphics(), _
nDC As NativeDC = NativeDC.GetDeskTopDC
Debug.Print(StretchBlt(g.GetHdc, 0, 0, Me.Width, Me.Height, nDC.DC, 0, 0, Me.Height / 2, Me.Width / 2, SRCCOPY))
End Using
We've now made the DC have a managed wrapper to make managing the unmanaged resource a lot easier and more in keeping with .NET memory resource management.
The next thing you might want to consider is moving the StretchBlt methods into the NativeDC class, allowing you to move all the win32 API calls into one class so as you can later easily look at adding declarative security assertions etc.
Public Class NativeDC
Implements IDisposable
Private m_DC As IntPtr
Private m_Hwnd As IntPtr
Private m_NeedsDispose As Boolean
Public Sub New(ByVal dc As IntPtr)
m_DC = dc
End Sub
Public ReadOnly Property DC() As IntPtr
Get
Return m_DC
End Get
End Property
Public Shared Function FromWindow(ByVal hwnd As IntPtr) As NativeDC
Dim nDC As New NativeDC(GetWindowDC(hwnd))
nDC.m_Hwnd = hwnd
nDC.m_NeedsDispose = True
Return nDC
End Function
Public Shared Function GetDesktopDC() As NativeDC
Return FromWindow(GetDesktopWindow())
End Function
#Region " IDisposable Support "
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose(True)
End Sub
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Me.m_NeedsDispose Then
ReleaseDC(Me.m_Hwnd, Me.m_DC)
End If
Me.m_NeedsDispose = False
End Sub
#End Region
#Region "win32 API"
Declare Function GetDesktopWindow Lib "user32" () As IntPtr
Declare Function GetWindowDC Lib "user32" (ByVal hwnd As IntPtr) As IntPtr
Declare Function ReleaseDC Lib "user32" (ByVal hwnd As IntPtr, ByVal dc As IntPtr) As Int32
#End Region
End Class