Managed Gdi Wrapper for Better Performance

The days of Avalon have not come yet and Gdi Plus is surely a nice API to create wonderfull UI whith transparency and gradients, but it has a plumbing caveats : It cannot benefit of graphic cards acceleration.

It is real problem since people user bigger screens with better pitch at higher resolution. Drawing all your controls using the CPU makes your UI slower. You'll tell me 'what else can I do...'

Often, only parts of you drawing actually need Gdi+. Filling the background (often the longuest part) with a solid color can be made with GDI, copying a image or icon without transparency can also be done faster using this good old API.

The problem then is to make all this boring API calls. We will classes that mimic System.Drawing but using Gdi to make all this interop easier.

The first step is to encapsulate the device context represented by its handle (hdc) in a class.

Code Copy HideScrollFull
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Cobra.Windows.Forms.Interop;

namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents a Gdi device context.
/// </summary>
public class DeviceContext : IDisposable
{
#region Fields

private IntPtr hdc;

#endregion

#region
Instance management

/// <summary>
/// Initializes a new instance of the <see cref="DeviceContext"/> class.
/// </summary>
/// <param name="hdc">The device context handle to wrap.</param>
protected DeviceContext(IntPtr hdc)
{
this.hdc = hdc;
}

/// <summary>
/// Creates a <see cref="DeviceContext"/> wrapper around specified HDC.
/// </summary>
/// <param name="hdc">The device context handler to wrap.</param>
/// <returns></returns>
public static DeviceContext Attach(IntPtr hdc)
{
return new DeviceContext(hdc);
}

/// <summary>
/// Creates a <see cref="DeviceContext"/> from a <see cref="Graphics"/> object.
/// </summary>
/// <param name="graphics">The <see cref="Graphics"/> object to wrap.</param>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext FromGraphics(Graphics graphics)
{
return new GraphicsDeviceContext(graphics);
}

/// <summary>
/// Creates a <see cref="DeviceContext"/> to paint a window.
/// </summary>
/// <param name="hwnd">The handle of the window.</param>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext FromHWnd(IntPtr hwnd)
{
return new WindowDeviceContext(hwnd, NativeGdi.GetWindowDC(hwnd));
}

/// <summary>
/// Creates a <see cref="DeviceContext"/> to paint a window.
/// </summary>
/// <param name="hwnd">The handle of the window.</param>
/// <param name="region">The handle of a region.</param>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext FromHWnd(IntPtr hwnd, IntPtr region)
{
return new WindowDeviceContext(hwnd, NativeGdi.GetDCEx(hwnd, region, NativeGdi.DCX_WINDOW | NativeGdi.DCX_INTERSECTRGN));
}

/// <summary>
/// Creates a new <see cref="DeviceContext"/> compatible width given device context.
/// </summary>
/// <param name="hdc">The handle of the device context.</param>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext CreateCompatible(IntPtr hdc)
{
IntPtr compatibleHdc = NativeGdi.CreateCompatibleDC(hdc);
return new CompatibleDeviceContext(compatibleHdc);
}

/// <summary>
/// Creates a new <see cref="DeviceContext"/> compatible width given device context.
/// </summary>
/// <param name="dc">The original <see cref="DeviceContext"/> object.</param>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext CreateCompatible(DeviceContext dc)
{
IntPtr compatibleHdc = NativeGdi.CreateCompatibleDC(dc.Handle);
return new CompatibleDeviceContext(compatibleHdc);
}

/// <summary>
/// Creates a screen device context.
/// </summary>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext FromScreen()
{
return FromHWnd(IntPtr.Zero);
}

/// <summary>
/// Creates a <see cref="DeviceContext"/> compatible with screen.
/// </summary>
/// <returns>A new <see cref="DeviceContext"/> object.</returns>
public static DeviceContext CreateScreenCompatible()
{
IntPtr screen = NativeGdi.GetDC(IntPtr.Zero);
try
{
return new CompatibleDeviceContext( NativeGdi.CreateCompatibleDC(screen) );
}
finally
{
NativeGdi.ReleaseDC(IntPtr.Zero, screen);
}
}

#endregion

#region
Dispose and finalization

/// <summary>
/// Releases internal resources.
/// </summary>
~DeviceContext()
{
Dispose(false);
}

/// <summary>
/// Releases internal resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
hdc = IntPtr.Zero;
}

#endregion

#region
Properties

/// <summary>
/// Gets device context handle.
/// </summary>
public IntPtr Handle
{
get { return hdc; }
}

#endregion

#region
Methods

/// <summary>
/// Creates a new clipping region that consists
/// of the existing clipping region minus the specified rectangle
/// </summary>
/// <param name="rect">The rectangle used to modify the clipping region.</param>
public void ExcludeClip(Rectangle rect)
{
NativeGdi.ExcludeClipRect(hdc, rect.Left, rect.Top, rect.Right, rect.Bottom);
GC.KeepAlive(this);
}

/// <summary>
/// Creates a new clipping region from the intersection
/// of the current clipping region and the specified rectangle.
/// </summary>
/// <param name="rect">The rectangle used to modify the clipping region.</param>
public void IntersectClip(Rectangle rect)
{
NativeGdi.IntersectClipRect(hdc, rect.Left, rect.Top, rect.Right, rect.Bottom);
GC.KeepAlive(this);
}

/// <summary>
/// fills a rectangle by using the specified brush.
/// This function includes the left and top borders,
/// but excludes the right and bottom borders of the rectangle.
/// </summary>
/// <param name="brush">The brush used to fill the rectangle.</param>
/// <param name="rect">The rectangle to be filled. </param>
public void FillRectangle(GdiBrush brush, Rectangle rect)
{
NativeGdi.FillRect(hdc, rect, brush.Handle);
GC.KeepAlive(this);
}

/// <summary>
/// Draws an image in the device context.
/// </summary>
/// <param name="image">The image to draw.</param>
/// <param name="point">The location where the image should be drawn.</param>
public void DrawImageUnscaled(GdiBitmap image, Point point)
{
DrawImageUnscaled(image, point.X, point.Y, image.Width, image.Height);
GC.KeepAlive(this);
}

/// <summary>
/// Draws an image in the device context.
/// </summary>
/// <param name="image">The image to draw.</param>
/// <param name="x">The x coordinate of the location
/// where the image should be drawn.</param>
/// <param name="y">The y coordinate of the location
/// where the image should be drawn.</param>
public void DrawImageUnscaled(GdiBitmap image, int x, int y)
{
DrawImageUnscaled(image, x, y, image.Width, image.Height);
GC.KeepAlive(this);
}

/// <summary>
/// Draws an image in the device context.
/// </summary>
/// <param name="image">The image to draw.</param>
/// <param name="rectangle">The rectangle where
/// the image should be drawn.</param>
public void DrawImageUnscaled(GdiBitmap image, Rectangle rectangle)
{
DrawImageUnscaled(image, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
GC.KeepAlive(this);
}

/// <summary>
/// Draws an image in the device context.
/// </summary>
/// <param name="image">The image to draw.</param>
/// <param name="x">The x coordinate of the rectangle
/// where the image should be drawn.</param>
/// <param name="y">The y coordinate of the rectangle
/// where the image should be drawn.</param>
/// <param name="width">The width of the rectangle
/// where the image should be drawn.</param>
/// <param name="height">The height of the rectangle
/// where the image should be drawn.</param>
public void DrawImageUnscaled(GdiBitmap image, int x, int y, int width, int height)
{
using (DeviceContext sourceContext = CreateCompatibleDeviceContext())
{
using (GdiSelect select = sourceContext.SelectObject(image))
NativeGdi.BitBlt(hdc, x, y, width, height, sourceContext.Handle, 0, 0, NativeGdi.SRCCOPY);
}
}

/// <summary>
/// Saves the state of the device context.
/// </summary>
/// <returns>A <see cref="DeviceContextState"/> object containing device state.</returns>
public DeviceContextState Save()
{
GC.KeepAlive(this);
return new DeviceContextState(NativeGdi.SaveDC(hdc));
}

/// <summary>
/// Restores the state of the device context.
/// </summary>
/// <param name="state">The <see cref="DeviceContextState"/>
/// object containing the device state.</param>
/// <remarks>The <see cref="DeviceContextState"/> is obtained
/// by calling <see cref="Save"/>.</remarks>
public void Restore(DeviceContextState state)
{
NativeGdi.RestoreDC(hdc, state.state);
GC.KeepAlive(this);
}

/// <summary>
/// Applies a translate transformation to the device context.
/// </summary>
/// <param name="x">The x coordinate of the offset.</param>
/// <param name="y">The y coordinate of the offset.</param>
public void TranslateTransform(int x, int y)
{
NativeGdi.OffsetWindowOrgEx(hdc, x, y, IntPtr.Zero);
GC.KeepAlive(this);
}

/// <summary>
/// Applies a translate transformation to the device context.
/// </summary>
/// <param name="point">The offset of the translation.</param>
public void TranslateTransform(Point point)
{
TranslateTransform(point.X, point.Y);
}

/// <summary>
/// Selects a <see cref="GdiObject"/> in the device context.
/// </summary>
/// <param name="gdiObject">The <see cref="GdiObject"/> to select.</param>
/// <returns>A <see cref="GdiSelect"/> disposable object
/// used to deselect from device context.</returns>
public GdiSelect SelectObject(GdiObject gdiObject)
{
GC.KeepAlive(this);
return new GdiSelect(NativeGdi.SelectObject( new HandleRef(this, hdc), new HandleRef(gdiObject, gdiObject.Handle)), hdc);
}

/// <summary>
/// Creates a compatible device context.
/// </summary>
/// <returns>The newly created device context.</returns>
public DeviceContext CreateCompatibleDeviceContext()
{
return new CompatibleDeviceContext(NativeGdi.CreateCompatibleDC(hdc));
}

#endregion

#region
Specialized inner classes

private class GraphicsDeviceContext : DeviceContext
{
private Graphics graphics;

internal GraphicsDeviceContext(Graphics graphics) : base(graphics.GetHdc())
{
this.graphics = graphics;
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (Handle != IntPtr.Zero)
graphics.ReleaseHdc(Handle);
}

base.Dispose(disposing);
}
}

private class CompatibleDeviceContext : DeviceContext
{
internal CompatibleDeviceContext(IntPtr hdc) : base(hdc)
{}

protected override void Dispose(bool disposing)
{
if (Handle != IntPtr.Zero)
NativeGdi.DeleteDC(Handle);
base.Dispose(disposing);
}
}

private class WindowDeviceContext : DeviceContext
{
private IntPtr hwnd;

internal WindowDeviceContext(IntPtr hwnd, IntPtr hdc) : base(hdc)
{
this.hwnd = hwnd;
}

protected override void Dispose(bool disposing)
{
if (Handle != IntPtr.Zero)
NativeGdi.ReleaseDC(hwnd, Handle);
base.Dispose(disposing);
}
}

#endregion
}
}
. . .

Here is the interop code :

Code Copy HideScrollFull
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Cobra.Windows.Forms.Interop
{
/// <summary>
/// Native interop for Gdi.
/// </summary>
internal sealed class NativeGdi
{
private NativeGdi(){}

#region Gdi structures

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;

public POINT(int x, int y)
{
this.x = x;
this.y = y;
}

public POINT(Point pt) : this(pt.X,pt.Y){}
}


[StructLayout(LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;

public SIZE(int width, int height)
{
this.cx = width;
this.cy = height;
}

public SIZE(Size sz) : this(sz.Width,sz.Height) {}
}


[StructLayout(LayoutKind.Sequential)]
public class RECT
{
public int l;
public int t;
public int r;
public int b;

public RECT(int l,int t,int r,int b)
{
this.l = l;
this.t = t;
this.r = r;
this.b = b;
}

public RECT() {}

public RECT(Rectangle rect) : this(rect.Left,rect.Top,rect.Right,rect.Bottom) {}

public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(l,t,r,b);
}

public static implicit operator Rectangle(RECT rect)
{
return rect.ToRectangle();
}

public static implicit operator RECT(Rectangle rect)
{
return new RECT(rect);
}
}

#endregion

#region
Create/delete DC

[DllImport("Gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(
IntPtr hdc   // handle to DC
);
[DllImport("Gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteDC(
IntPtr hdc   // handle to DC
);
#endregion

#region
Get/release DC

[DllImport("User32.dll")]
public static extern IntPtr GetWindowDC(
IntPtr hWnd   // handle to window
);
[DllImport("user32.dll", SetLastError=true)]
public static extern IntPtr GetDC(IntPtr hWnd);

public const int DCX_WINDOW           = 0x00000001;
public const int DCX_CACHE            = 0x00000002;
public const int DCX_NORESETATTRS     = 0x00000004;
public const int DCX_CLIPCHILDREN     = 0x00000008;
public const int DCX_CLIPSIBLINGS     = 0x00000010;
public const int DCX_PARENTCLIP       = 0x00000020;
public const int DCX_EXCLUDERGN       = 0x00000040;
public const int DCX_INTERSECTRGN     = 0x00000080;
public const int DCX_EXCLUDEUPDATE    = 0x00000100;
public const int DCX_INTERSECTUPDATE  = 0x00000200;
public const int DCX_LOCKWINDOWUPDATE = 0x00000400;
public const int DCX_VALIDATE         = 0x00200000;

[DllImport("user32.dll", SetLastError=true)]
public static extern IntPtr GetDCEx(
IntPtr hWnd,      // handle to window
IntPtr hrgnClip,  // handle to clipping region
int flags     // creation options
);

[DllImport("User32.dll")]
public static extern int ReleaseDC(
IntPtr hWnd,  // handle to window
IntPtr hDC     // handle to DC
);
#endregion

#region
Save/restore DC

[DllImport("Gdi32.dll")]
public static extern int SaveDC(
IntPtr hdc   // handle to DC
);
[DllImport("Gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RestoreDC(
IntPtr hdc,       // handle to DC
int nSavedDC   // restore state
);
#endregion

#region
Clipping

[DllImport("Gdi32.dll")]
public static extern int ExcludeClipRect(
IntPtr hdc,         // handle to DC
int nLeftRect,   // x-coord of upper-left corner
int nTopRect,    // y-coord of upper-left corner
int nRightRect,  // x-coord of lower-right corner
int nBottomRect  // y-coord of lower-right corner
);
[DllImport("Gdi32.dll")]
public static extern int IntersectClipRect(
IntPtr hdc,         // handle to DC
int nLeftRect,   // x-coord of upper-left corner
int nTopRect,    // y-coord of upper-left corner
int nRightRect,  // x-coord of lower-right corner
int nBottomRect  // y-coord of lower-right corner
);
#endregion

#region
Drawing

[DllImport("User32.dll")]
public static extern int FillRect(
IntPtr hDC,           // handle to DC
[MarshalAs(UnmanagedType.LPStruct)] RECT lprc,  // rectangle
IntPtr hbr         // handle to brush
);

[DllImport("Gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest,  // x-coord of destination upper-left corner
int nYDest,  // y-coord of destination upper-left corner
int nWidth,  // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc,  // handle to source DC
int nXSrc,   // x-coordinate of source upper-left corner
int nYSrc,   // y-coordinate of source upper-left corner
int dwRop  // raster operation code
);
public const int SRCCOPY            =0x00CC0020 /* dest = source                   */;

#endregion

#region
Transfoms

[DllImport("Gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OffsetWindowOrgEx(
IntPtr hdc,          // handle to device context
int nXOffset,     // horizontal offset
int nYOffset,     // vertical offset
IntPtr lpPoint   // original origin
);
#endregion

#region
Select

[DllImport("Gdi32.dll")]
public static extern IntPtr SelectObject(
HandleRef hdc,          // handle to DC
HandleRef hgdiobj   // handle to object
);
#endregion

#region
Brushes

[DllImport("Gdi32.dll")]
public static extern IntPtr CreateSolidBrush(
int crColor   // brush color value
);
#endregion

#region
Object Deletion

[DllImport("Gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject(
IntPtr hObject   // handle to graphic object
);
#endregion
}
}
. . .

There are several important parts in the DeviceContext class. First of all the instance management. The hard part is Disposing the context because it depends on how the hdc was acquiered. This is easily solved using private specialized inner classes for each management type.

The Attach static method is used to create a simple wrapper around a device context handle that has been created elsewhere. A DeviceContext object created with this method won't delete neither release the HDC, the caller is responsible for this. Internally, a DeviceContext object is created.

The FromHWnd static method gets a HDC for the window and release it when the DeviceContext object is disposed. Internally, a WindowDeviceContext object is created.

The FromGraphics static method uses the GetDC method from the Graphics object to gets its handle, and releases it when disposed. Internally a GraphicsDeviceContext object is created.

The CreateCompatible and FromScreen static methods create a device context compatible with specified DC or with the screen, and delete is when disposed. Internally, a CompatibleDeviceContext object is created.

The Save and Restore methods use the very simple DeviceContextState class:

Code Copy HideScrollFull
namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents a saved <see cref="DeviceContext"/> state.
/// </summary>
/// <remarks>This class is created by the <see cref="DeviceContext.Save"/> mehtod.</remarks>
public sealed class DeviceContextState
{
internal int state;

internal DeviceContextState(int state)
{
this.state = state;
}
}
}
. . .

I decided to use a IDisposable pattern for object selection to make things more straight forward :

Code Copy HideScrollFull
using System;
using System.Runtime.InteropServices;
using Cobra.Windows.Forms.Interop;

namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents information necessary to revert an object selection in a <see cref="DeviceContext"/>.
/// </summary>
/// <remarks>This object is created by the <see cref="DeviceContext.SelectObject"/> method.</remarks>
public sealed class GdiSelect : IDisposable
{
private IntPtr hObject;
private IntPtr hdc;

internal GdiSelect(IntPtr hObject,IntPtr hdc)
{
this.hObject = hObject;
this.hdc = hdc;
}


/// <summary>
/// Releases the internal resources.
/// </summary>
~GdiSelect()
{
InternalDispose();
}

/// <summary>
/// Revert the selection in the <see cref="DeviceContext"/>.
/// </summary>
public void Dispose()
{
InternalDispose();
GC.SuppressFinalize(this);
}

private void InternalDispose()
{
NativeGdi.SelectObject(new HandleRef(null, hdc),new HandleRef(null,hObject));
GC.KeepAlive(this);
}
}
}
. . .

The next part is about Gdi objects. They all inherit from the GdiObject abstract class to stay close to Gdi infrastructure :

Code Copy HideScrollFull
using System;

namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents a Gdi graphic object.
/// </summary>
public abstract class GdiObject : IDisposable
{
IntPtr handle;

/// <summary>
/// Initializes a new instance of the <see cref="GdiObject"/> class.
/// </summary>
/// <param name="handle">A native GDI handle to wrap into a <see cref="GdiObject"/> instance.</param>
protected GdiObject(IntPtr handle)
{
this.handle = handle;
}

/// <summary>
/// Finalizes <see cref="GdiObject"/>.
/// </summary>
~GdiObject()
{
Dispose(false);
}

/// <summary>
/// Releases internal resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}


/// <summary>
/// Override to release internal resources.
/// </summary>
/// <param name="disposing"><c>false</c> when called from Finalize.</param>
protected virtual void Dispose(bool disposing)
{
}

/// <summary>
/// Gets the handle of the Gdi object.
/// </summary>
public IntPtr Handle
{
get
{
return handle;
}
}

/// <summary>
/// Clears the handle of the Gdi object.
/// </summary>
protected void ClearHandle()
{
this.handle = IntPtr.Zero;
}
}
}
. . .

The GdiBrush class represents a Gdi solid brush :

Code Copy HideScrollFull
using System;
using System.Drawing;
using Cobra.Windows.Forms.Interop;

namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents a Gdi brush.
/// </summary>
public class GdiBrush : GdiObject
{
private bool immutable;

/// <summary>
/// Initializes a new instance of the <see cref="GdiBrush"/> class.
/// </summary>
/// <param name="color">The color of the brush.</param>
/// <remarks>The brush is deleted when disposed.</remarks>
public GdiBrush(Color color) : base(NativeGdi.CreateSolidBrush(ColorTranslator.ToWin32(color)))
{
}

/// <summary>
/// Initializes a new instance of the <see cref="GdiBrush"/> class.
/// </summary>
/// <param name="brush">The handle of the brush object.</param>
/// <param name="immutable"><c>true</c> if the object should not be deleted when released.</param>
public GdiBrush(IntPtr brush, bool immutable) : base(brush)
{
this.immutable = immutable;
}



/// <summary>
/// Releases internal resources.
/// </summary>
/// <param name="disposing"><c>false</c> if called from Finalize.</param>
protected override void Dispose(bool disposing)
{
if (!immutable && Handle != IntPtr.Zero)
{
NativeGdi.DeleteObject(Handle);
ClearHandle();
}
}
}
}
. . .

The GdiBitmap class :

Code Copy HideScrollFull
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Cobra.Windows.Forms.Interop;

namespace Cobra.Windows.Forms.Gdi
{
/// <summary>
/// Represents a Gdi bitmap object.
/// </summary>
public class GdiBitmap : GdiObject
{
private Size size;
private bool sizeAvailable;
/// <summary>
/// Initializes a new instance of the <see cref="GdiBitmap"/> class.
/// </summary>
/// <param name="bitmap">Handle of a native Gdi bitmap.</param>
public GdiBitmap(IntPtr bitmap) : base(bitmap){}

/// <summary>
/// Creates a <see cref="GdiBitmap"/> from a Gdi Plus <see cref="Bitmap"/>.
/// </summary>
/// <param name="bitmap">The bitmap to convert to Gdi.</param>
/// <returns>A new <see cref="GdiBitmap"/> object.</returns>
public static GdiBitmap FromBitmap(Bitmap bitmap)
{
return new GdiBitmap(bitmap.GetHbitmap());
}

/// <summary>
/// Creates a <see cref="GdiBitmap"/> from a Gdi Plus <see cref="Bitmap"/>.
/// </summary>
/// <param name="bitmap">The bitmap to convert to Gdi.</param>
/// <param name="color">The color used for transparent areas.</param>
/// <returns>A new <see cref="GdiBitmap"/> object.</returns>
public static GdiBitmap FromBitmap(Bitmap bitmap, Color color)
{
return new GdiBitmap(bitmap.GetHbitmap(color));
}


/// <summary>
/// Releases internal resources.
/// </summary>
/// <param name="disposing"><c>false</c> when called from Finalize.</param>
protected override void Dispose(bool disposing)
{
if (Handle != IntPtr.Zero)
{
NativeGdi.DeleteObject(Handle);
ClearHandle();
}
}


/// <summary>
/// Gets the size of the bitmap.
/// </summary>
public Size Size
{
get
{
if (!sizeAvailable)
LoadSize();
return size;
}
}

/// <summary>
/// Gets the width of the bitmap.
/// </summary>
public int Width
{
get
{
if (!sizeAvailable)
LoadSize();
return size.Width;
}
}

/// <summary>
/// Gets the height of the bitmap.
/// </summary>
public int Height
{
get
{
if (!sizeAvailable)
LoadSize();
return size.Height;
}
}

private void LoadSize()
{
NativeGdi.BITMAP info = new Cobra.Windows.Forms.Interop.NativeGdi.BITMAP();
NativeGdi.GetObject(Handle,Marshal.SizeOf(typeof(NativeGdi.BITMAP)),info);
size = new Size(info.bmWidth,info.bmHeight);

sizeAvailable = true;
}
}
}
. . .

There's finally a sample simple control base that clears its background using Gdi rather than Gdi+ to improve performance :

Code Copy HideScrollFull
using System.Windows.Forms;
using Cobra.Windows.Forms.Gdi;

namespace GdiDrawing
{
/// <summary>
/// A control that fill its background using Gdi rather than Gdi+.
/// </summary>
public class MyGdiCustomControl : Control
{
public MyGdiCustomControl()
{
}
protected override void OnPaintBackground(PaintEventArgs e)
{
using (DeviceContext dc = DeviceContext.FromGraphics(e.Graphics))
{
dc.IntersectClip(e.ClipRectangle);
using (GdiBrush brush = new GdiBrush(BackColor))
dc.FillRectangle(brush, ClientRectangle);
}
}
protected override void OnPaint(PaintEventArgs pe)
{
// make your painting here !
// you can mix Gdi and Gdi+ !!

// Calling the base class OnPaint
base.OnPaint(pe);
}
}
}
. . .

Of course, this class offers only a limited support for Gdi, but feel free to add what ever you need. The object model makes adding new features a glimps.

 

by Skup

posted on Tuesday, March 22, 2005 7:04 PM

Feedback

# re: Managed Gdi Wrapper for Better Performance 11/1/2005 4:52 AM andyk

Firstly, great work!

Secondly, the code listings seem to be missing definitions for NativeGdi.GetObject() and NativeGdi.BITMAP.

# re: Managed Gdi Wrapper for Better Performance 7/21/2008 9:19 AM Evgen

Can you re post interop code....

Thx

# re: Managed Gdi Wrapper for Better Performance 7/21/2008 9:20 AM Evgen

and what about NativeGdi.GetObject() and NativeGdi.BITMAP

# re: Managed Gdi Wrapper for Better Performance 3/15/2011 10:22 AM health articles

But, how can i create this empty jpg with an empty tag?

Or, is it possible to download it?

# re: Managed Gdi Wrapper for Better Performance 4/10/2011 6:05 PM newspaper articles

I am asking because I'm hacking an MetaDataEditor-Control, you can edit and view jpegs and it's ExifTags. Nevertheless, maybe anyone has an idea if the adding of ExifTags should be allowed? I'm not informed about IPTC metadata in tifs or jpegs, but with e.g. XNView they are editable in contrary to Exif. Does the PropertyItem concept support IPTC?

# nfl jerseys 7/29/2011 3:00 AM qwe0408@yahoo.com

<a href="http://www.nfljerseyscheapest.org/"><strong>Nfl jerseys</strong></a> wholesale is always concerned about the needs of the market, it helps them grasp the opportunity to produce more nfl jerseys wholesale.Buy <a href="http://www.jerseysonline.org/"><strong>wholesale jerseys</strong></a> and show the sole of them, the duck is the cost of the team. Sports Bars often lacking in ideas for decorating framed jerseys are ideal. Nothing makes a statement to the best sports bar the appearance of discount <a href="http://www.jerseysonline.org/"><strong>NFL jerseys</strong></a> autographed on the wall. Our wholesale NFL/NHL jerseys are selling in the near future.The name of the National Football League as we know it today began in 1922. Players usually wear <a href="http://www.nfljerseyscheapest.org/"><strong>cheap">http://www.nfljerseyscheapest.org/"><strong>cheap nfl jerseys</strong></a> in their training program.Each NFL season ends with prizes being awarded to players. For a good performance in the game, players must take more exercise to wear wholesale nfl jerseys in their daily walk. <a href="http://www.jerseysonline.org/"><strong>Cheap jerseys</strong></a> wholesale from China are almost no difference to the authentic. NFL jerseys wholesale this specific internet site concentrates exclusively on its one particular specialty which is Globe Cup nfl jerseys wholesale. NFL jerseys wholesale this specific internet site concentrates exclusively on its one particular specialty which is Globe Cup nfl jerseys wholesale.More and more people prefer online shopping goods. Including find the <a href="http://www.nfljerseyscheapest.org/"><strong>cheap">http://www.nfljerseyscheapest.org/"><strong>cheap mlb jerseys</strong></a> on the internet. It is becoming a new trend among the football lovers. Because it can provide a largr number of discount nfl jerseys.

# re: Managed Gdi Wrapper for Better Performance 9/28/2011 9:41 PM organic seo service

This site is excellent and so is how the subject matter was explained. I also like some of the comments too.Waiting for next post.

# re: Managed Gdi Wrapper for Better Performance 9/29/2011 8:30 PM the best seo company


I really enjoy simply reading all of your weblogs. Simply wanted to inform you that you have people like me who appreciate your work. Definitely a great post. Hats off to you! The information that you have provided is very helpful.

# Natural Supplements-healthy green 10/5/2011 10:10 AM Natural Supplements

I can not stop reading this. And 'so fresh, so full of information, I do not know. I'm glad that people actually write the smart way to show the different sides of him.

# Post Free Classified-geboon 10/7/2011 6:45 PM post free classified

This Blog is really Very Much authentic regarding the information...thanks for posting..........

# 3d ultrasounds 10/10/2011 12:22 PM 3d ultrasounds

I like the valuable information you provide in your articles. I’ll bookmark your weblog and check again here frequently. I am quite sure I will learn many new stuff right here! Best of luck for the next!

# Website Design Company-Custom Website Design Company-SuperbWebsiteDesign 10/19/2011 2:53 PM website design company

I enjoyed reading this kind of stuff. Thanks for sharing such an excellent information.SO much thanks!

# BAG 11/11/2011 7:33 AM Marc Jacobs

As an influx of people, rather bare, better than the tasteless. <a href="http://www.marcjacobs-">http://www.marcjacobs-handbags.org/">Marc">http://www.marcjacobs-">http://www.marcjacobs-handbags.org/">Marc

Jacobs</a> designed the product, especially the main and sub-brand bag brand <a href="http://www.marcjacobs-">http://www.marcjacobs-

handbags.org/">Marc by Marc Jacobs Bags</a>, is a unique mix of taste. <a href="http://www.marcjacobs-">http://www.marcjacobs-

handbags.org/">Marc Jacobs Handbag</a> used almost mature female, are to be highly it. Young people's favorite

handbag comes <a href="http://www.marcjacobs-">http://www.marcjacobs-handbags.org/">Marc">http://www.marcjacobs-">http://www.marcjacobs-handbags.org/">Marc by Marc Jacobs Handbag</a>. As long as you are

stylish, with a focus on people, then you have to have them.

# underwear 11/24/2011 6:30 AM calvin klein 365

The main function of underwear is more conducive to live and work. For men is to live in the root and eggs stretched, so as not to walk or do something random shaking, affecting work and life. For women, the menstrual period comes in an easy to absorbent pads good things, to avoid the outflow of blood affect the life and work. Then choose a suitable underwear becomes very important. <a href="http://www.underwear-sale.org">Calvin Klein Underwear</a> can help you do so. <a href="http://www.underwear-sale.org/womens-calvin-klein-c-48.html">calvin klein steel</a> and <a href="http://www.underwear-sale.org/mens-underwear-calvin-klein-underwear-c-42_46.html">calvin klein 365</a> series is especially good. We have <a href="http://www.underwear-sale.org">underwear sale</a>. In addition to these, this site also <a href="http://www.underwear-sale.org/aussiebum-retro-swimwear-c-44.html">aussieBum Swimwear</a> and so on. Welcome to win your favor. Thank you!

# seo 12/2/2011 4:25 PM buy lortab online

Thank you for for sharing so great thing to us. I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post nice post, thanks for sharing.

# re: Managed Gdi Wrapper for Better Performance 12/12/2011 6:08 PM buy addreall online

I'm still learning from you, but I try to reach my goals. Since then enjoy reading all the information that appears on your blog.Keep come. Loved it!

# Top Web Hosting Companies 12/13/2011 6:26 AM Top Web Hosting Companies

Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is extremely helpful for me.

# Mackenzie 12/29/2011 2:40 AM tall christian louboutin

Massachusetts http://www.varyshoes.com/christian-louboutin20100846-brown-sheepskin-short-boots-662-lady.html brown sheepskin short boots destroying properties flipping cars and leaving 4 people today lifeless and dozens hurt At the very least 3 tornadoes struck the town of Springfield Marriage ceremony Gowns Mass on your own http://www.varyshoes.com/tall-boots.html tall boots having a fourth unconfirmed twister probably touching down inside the town Mayor Dominic J Sarno stated A lot of of these storms also blasted the locations encompassing the town of much more than a hundred and fifty000 citizens ninety miles west of Boston The Massachusetts twisters hit as unstable climate Prom Attire threatened the whole Northeast bringing tornado watches to Philadelphia Ny and Boston An open up leading bus jostled having a retro camper van http://www.varyshoes.com/christian-louboutin-jeweled-platform-slingback-390-lady.html Jeweled platform slingback http://www.varyshoes.com/fashion-collection.html christian louboutin heels <img src="http://www.varyshoes.com/images/uploads/pumps/CLB-053-1.jpg" a gleaming American Kenworth truck Night Gowns classic cars and deluxe limos for area But anybody who understands her may well need to have to have a 2nd appear With her '50s era prom gown sizzling pink wig and

# Mackenzie 12/29/2011 2:41 AM replica watches for sale

normally the assemblage technique http://www.samewatches.com/Rolex-Daytona-18K-Gold-Case-Iced-Dial-Roman-Numerals-Hour-Marker-16109-gift.html">http://www.samewatches.com/Rolex-Daytona-18K-Gold-Case-Iced-Dial-Roman-Numerals-Hour-Marker-16109-gift.html GMT Master rolex Bvlgari encounter spiders are incredibly inspired http://www.samewatches.com/Stainless-Steel-Silver-Dial-Leather-band-1-26247-gift.html">http://www.samewatches.com/Stainless-Steel-Silver-Dial-Leather-band-1-26247-gift.html cartier wallet This indices are positioned beforehand talked about your swap as an option to with it http://www.samewatches.com/Stainless-Steel-Blue_Black-Dial-Diamond-Hour-markers-171326-gift.html">http://www.samewatches.com/Stainless-Steel-Blue_Black-Dial-Diamond-Hour-markers-171326-gift.html replica Jubilee Gents The subsequent will increase some top around the encounter http://www.samewatches.com/Rolex-Datejusts.html">http://www.samewatches.com/Rolex-Datejusts.html cheap rolex watches Offered which the listing is outlined previously talked about any swap http://www.samewatches.com cheap fake watches http://www.samewatches.com/Sarcar.html fake Sarcar an extremely skilled swap producer are detailed the appliance bodily Bulgari watches are usually equally as amazing through pattern simply because they're amazing for construction breitling colt Bvlgari wrist watches are genuinely in vogue precise watches They are this item in expert observe getting in addition to exceptional create A Bvlgari model title is typically trustworthy on the subject of pleasant bracelets ranges The company is correct the precise very same format magnificence within the watches exactly because it could integrated within the

# organic vitamins 12/30/2011 11:03 AM organic vitamins

Hi webmaster – This is by far the best looking site I’ve seen.It was completely easy to navigate and it was easy to look for the information I needed.
<a href="http://www.healthygreen.co/id73.html"> organic vitamins</a>

# maquinas de coser 12/30/2011 1:44 PM maquinas de coser

Brilliant post and useful information looking forward to future posts in this field thanks a very interesting article, interesting ideas and a lot of good questions posed Thanks for your insight for the great written piece.

# re: Managed Gdi Wrapper for Better Performance 1/3/2012 4:38 PM African Mango

I’ve seen progression in every post. Your newer posts are simply wonderful compared to your posts in the past. Keep up the good work

# Brake Parts 1/5/2012 12:50 PM torspar@yahoo.com

I don’t suppose I have read anything like this before. So nice to find somebody with some original thoughts on this subject

# re: Managed Gdi Wrapper for Better Performance 1/5/2012 7:37 PM t shirt printing

It is a very informative and useful post thanks it is good material to read this post increases my knowledge

# re: Managed Gdi Wrapper for Better Performance 1/6/2012 2:58 PM IT Support Bardsley

very informative post, thanks for sharing it with us

# re: Managed Gdi Wrapper for Better Performance 1/9/2012 3:07 PM custom tattoos

In fact your creative writing abilities has inspired me to start my own Blog

# re: Managed Gdi Wrapper for Better Performance 1/9/2012 10:23 PM engraved gifts

I am looking forward to another great article from you.

# solid wood worktops 1/10/2012 4:51 PM solid wood worktops

Thanks a lot for a bunch of good tips. I look forward to reading more on the topic in the future. Keep up the good work! This blog is going to be great resource

# re: Managed Gdi Wrapper for Better Performance 1/11/2012 7:27 AM canvas printing

Hi, the article is so wonderful, I am interested in it. I will pay attention to your articles.

# re: Managed Gdi Wrapper for Better Performance 1/12/2012 12:02 PM Brake Discs

Big thanks for the useful info i found on Puerta de Enlace .net

# re: Managed Gdi Wrapper for Better Performance 1/12/2012 1:47 PM Hyposis Nottingham

This information is very interesting, I really enjoyed, I would like get more information about this, because is very beautiful, thanks for sharing

# buy hydrocodone 1/25/2012 7:26 PM buy hydrocodone

You’ve written nice post, I am gonna bookmark this page, thanks for info. I actually appreciate your own position and I will be sure to come back here.

# louis vuitton sale 2/1/2012 3:30 AM louis vuitton sale

Bags of many different models, materials and colors at the
louis vuitton sale

outlet can be significant along with ample, nevertheless quite trendy, fantastic requirement.Here is a world of
louis vuitton outlet

where you can find all kinds of new style and fashion Louis Vuitton bags. We really want to lead the trend and let our customer in the pursuit of luxury and fashion, satisfied the needs of customers.

# coach factory outlet 2/1/2012 5:00 AM coach factory outlet

If you do not know design can be the most fashionable this fall, consider a glance on
coach factory outlet

! This summer, you have a wide range of options, because there are numerous designs, you can find from.
coach factory online

is actually a stylish Coach online store to sell perfect quality and discount Coach handbags, Coach bags, Coach wallets and Cheap Coach Purse.If you love Coach,you will like to get the best price on it.

# christian louboutin uk 2/1/2012 5:00 AM christian louboutin uk

If you have enough leisure time, you may go to the mall or go to the christian franchised store to have a good look at varieties of
christian louboutin uk

the diverse styles and rich colors of the purses with low cost will surely impress you a lot!You will always get surprised by the beautiful colors and perfect details of
christian louboutin

.So come on, do not hesitate.

# coach bags 2/1/2012 10:04 AM coach bags

coach bags

with fashion style and top quality succeed. In any occasions they are very suitable and appropriate for its precise and rich design.
coach outlet store

vision system is a visual enjoy, is a visual art. The particular design has been integrated function and the element of elegancy, then show you an exquisite and excellent product.

# coach outlet online 2/2/2012 1:39 AM coach outlet online

Becoming a regular member of
coach outlet online

, you can even buy wholesale purses, handbags, leather wallets at preferential prices. Why not have a try?
coach factory outlet

is famous for the discounts it offers. Latest coach purses and sunglasses can be purchased at discounted rates from this coach outlet store.
http://www.coachoutletonlinecoachdays.com

# coach outlet 2/2/2012 2:02 AM coach outlet

coach outlet

sells products which are excellent in quality and reasonable in price. All customers can easily pick up their favorite Coach briefcase, wallets, shoes, hats, scarf, jewelry and sunglasses.If you need to acquire the focus, you need to sustain the
coach outlet store online

, which with stylish components that will immediately concoct you appreciably more attracting and outstanding.
http://www.coachoutletcoachstore.com

# chanel uk 2/2/2012 2:02 AM chanel uk

Swarovski's Crystal is due to their commitment to consistency, precision and quality standards, and to the automatic cutting machine invented by the founder,
chanel bags

enjoy high reputation all over the world. They are designed for hand, elbow and shoulder carry thanks to comfortable flat leather handles.
http://www.chanel-outlet.org.uk

# coach factory outlet 2/2/2012 2:29 AM coach factory outlet

That experts claim coach factory outlet shopping is in the changes they are available in, which can make it well suited for benefit from to be a'luggage'bag. There are different kinds of crossbody bags within marketplace nowadays. Even so it is not possible to beat the timeless design jointly with traditional elegance of the Bags at the coach factory outlet online.
http://www.coachfactoryoutletonlinedays.com

# louis vuitton uk 2/2/2012 2:30 AM louis vuitton uk

More and more people can afford louis vuitton uk, not to say they are on sale. Price is not equivalent with value,they own classical style, fine materials, elaborate technique. If you want to catch up to the latest vogue, having Louis Vuitton Handbags of the latest styles can absolutely satisfy you.Just visit LV outlet webpage and select the most suitable products for yourself.
http://www.louisvuitton-full.org.uk

# christian louboutin 2/2/2012 2:30 AM christian louboutin

This elegant and discreet pair of rhodium-plated button christian louboutin will add sparkle to your outfit. They are covered in clear crystal pave and reflect the light in magical ways. christian Madison Handbags and christian Poppy Bags are viewed among probably the most newsworthy among the particular christian louboutin uk so far.
http://www.christian-louboutinshoes.co.uk

# coach outlet online 2/2/2012 2:34 AM coach outlet online

If you buy Coach items at the
coach outlet online

store, the goods will be sent out within 24 hours after confirming your payment and arrive to your door within 7 work days.
coach outlet

can provide the coach exactly the same is expected in a retail store. It can help you find bags of various colors, shapes and designs, which prove once again that the coach is actually a selection for the housekeeper.
http://www.coachoutletonlinecell.com

# chanel uk 2/2/2012 2:40 AM chanel uk

chanel uk have own characteristic designs. The beautiful crystals have added the magical finishing touch to countless bridal gowns. Just get some for yourself. I hope that I have helped you realize the potential for a breathtaking theme on your wedding day.Incorporating chanel handbags and pearls into your decor is a very fun and easy way to create a classic and warm setting.

http://www.chanel-bags.org.uk

# coach outlet store 2/2/2012 2:40 AM coach outlet store

Coach Outlet Store sells goods that are constructed to meet the highest standards of quality and functionality.You can trust it 100 percent. Wholesale coach outlet are even provided for VIP members. Haven't got your own Coach yet? Why not come to coach outlet store online outlet.

http://www.coachoutletstoreonlinegood.com

# coach outlet online 2/2/2012 2:41 AM coach outlet online

I got to know it from my elder sister who owns enviable luxury Coach bags. Coach Outlet Online Store is established to be your home shopping paradise. Coach New Signature BackPack Black Beige is a useful backpack for outdoors activities. It's convenient that you can freely take along with for travel,climbing and go for school.In our coach outlet,there are many graceful styles of Coach backpack for you.

http://www.coachoutletonlinefull.com

# louis vuitton uk 2/2/2012 4:02 AM louis vuitton uk

This
louis vuitton uk

for sale belongs to the sounding just what are termed as Louis Vuitton vintage best sellers, many other products and services for the reason that range appearing companies.I am so confused that I don,t even know where to buy the
louis vuitton

Handbags. Because I can prefer to chose the fashionable design, favorable price, top service .
http://www.louis-vuittonukoutlets.org.uk

# louboutin uk 2/2/2012 4:10 AM louboutin uk

Come by for dinner soon and check out the wine list for yourself. We are always here to help with selection. Cheers for the successful of christian
louboutin uk

.The christian Signature Hobo is from the latest release of
christian louboutin uk

. Its crisp, scribble material, leather handle, perfectly complements the relaxed shape of this stylish pouch.
http://www.christianlouboutinuk-sale.co.uk

Title
 
Name
 
Url
Comments   
Protected by Clearscreen.SharpHIPEnter the code you see: