API Proposal: Expose `System.Drawing.Graphics.NativeGraphics`.
- Dominant language
- C#
- Stars
- 4.9k
- Forks
- 1.1k
- Avg merge
- 1d 13m
- Merged PRs (30d)
- 85
Description
## Background and Motivation
In Windows Forms painting it would be helpful if we had the option to plug our own P/Invokes calls into existing GDI+ objects. We could, for example, have lighter-weight `GpPen` and `GpBrush` wrappers (structs perhaps) and invoke the GDI+ API directly with them via the exposed `Graphics` pointer.
While we could create our own `GpGraphics` object that usually isn't practical as we often have to interop via the System.Drawing types.
The form of the API here follows what `Icon` does (which is a GDI wrapper). Having a static construction method is necessary as we sometimes have derived types that we want to return (`SolidBrush`, `TextureBrush`, etc.).
## Proposed API
```diff
namespace System.Drawing
{
public class Graphics
{
+ public IntPtr Handle { get; }
+ public static Graphics FromHandle(IntPtr handle);
}
public abstract class Brush
{
+ public IntPtr Handle { get; }
+ public static Brush FromHandle(IntPtr handle);
}
public class Pen
{
+ public IntPtr Handle { get; }
+ public static Pen FromHandle(IntPtr handle);
}
public class Image
{
+ public IntPtr Handle { get; }
+ public static Image FromHandle(IntPtr handle);
}
public class Region
{
+ public IntPtr Handle { get; }
+ public static Region FromHandle(IntPtr handle);
}
}
namespace System.Drawing.Drawing2D
{
public class Matrix
{
+ public IntPtr Handle { get; }
+ public static Matrix FromHandle(IntPtr handle);
}
public class GraphicsPath
{
+ public IntPtr Handle { get; }
+ public static GraphicsPath FromHandle(IntPtr handle);
}
}
```
## Notes
- Like `Icon.FromHandle`, these `FromHandle` APIs will not take ownership and closing the handle is the caller's responsibility.
## Risks
No specific risks outside of what comes normally with accessing backing handles. You can delete the backing object or try to use the handle after the `Graphics` closes the native handle. Not much different than what you'd be running into using a disposed `Graphics`.
Note that we already expose `IDeviceContext` on `Graphics` which is much more risky as everything on `Graphics` throws when you're in-between `GetHDC()` and `ReleaseHDC()`. The throw there comes from GDI+ as it doesn't want to conflict with the usage of the backing HDC. GDI+ maintains and restores the state of the HDC outside of those calls.
Contributor guide
Assessment
This issue has not been assessed yet.