# GdiPlus Objects

In Microsoft documentation, GDI+ objects—such as GpGraphics, GpBitmap, GpBrush, GpPen, etc.—are described as abstract “objects” manipulated via Flat API functions. However, these are not true objects in the object-oriented sense. They are actually opaque pointers to undocumented C-style structures.

Each GDI+ object is a pointer to a structure with a well-defined memory layout. These structures contain fields for internal state, handles, flags, and configuration data. The Flat API functions (e.g. GdipSetPenWidth, GdipGetImageBounds) are essentially accessors and mutators—they read or write values to these internal fields.

For example, the GpCustomLineCap “object”, is a pointer to the following structure:

    typedef struct {
        CustomLineCapType type;
        GpPathData pathdata;
        BOOL fill;
        GpLineCap cap;
        REAL inset;
        GpLineJoin join;
        REAL scale;
    } GpCustomLineCap;

So when you call:

    GdipSetCustomLineCapWidthScale(cap, 1.5)

…it’s just setting cap->scale = 1.5.

Big APIs like the Windows GDI+ flat API—tend to expose enormous functionality through low‑level procedural calls. They are powerful, but also verbose, error‑prone, and difficult to use safely. Every object must be created manually, destroyed manually, passed as a pointer, and handled with strict lifetime discipline. A single missing cleanup call or an incorrect pointer cast can destabilize an entire application.

`AfxNova` takes a different approach. Instead of building a heavy framework with deep inheritance trees, virtual methods, and opaque abstractions, `AfxNova` wraps these large APIs using tiny, lightweight classes—each one focused on a single GDI+ object.

The philosophy is simple:

1. Wrap the object, not the API

Each GDI+ object—GpGraphics, GpBitmap, GpPen, GpBrush, etc.—is represented by a small class whose only job is to manage: * creation * destruction * ownership * pointer access

The class does not attempt to replace the API. It simply makes the API safe and pleasant to use.

2. Automatic lifetime management

Every class uses RAII semantics: * the constructor creates the underlying GDI+ object * the destructor frees it automatically * This eliminates leaks, double frees, and forgotten cleanup calls—problems that plague raw GDI+ code.

3. Full transparency and zero lock‑in

`AfxNova` never hides the underlying pointer. Every class exposes: * object → the raw GDI+ pointer @object → the address of the pointer (for functions that require GpObject**)

This means the developer can always call the flat API directly whenever needed. Nothing is trapped behind an abstraction.

4. No inheritance, no frameworks, no ceremony

Each class is self‑contained. There is no base class, no virtual destructor, no hierarchy, no “framework rules” to follow.

This keeps the system: * predictable * easy to read * easy to maintain * easy to extend

And it avoids the complexity that often appears in Microsoft’s own wrappers.

5. A consistent, minimal interface

All classes follow the same pattern: * a constructor that initializes the object * a destructor that frees it * an operator to expose the pointer * optional helper methods for convenience

This uniformity makes the entire API intuitive. Once you learn one class, you understand them all.

6. 100% compatibility with the flat API

Because the classes are thin wrappers, they remain fully compatible with: * all GDI+ functions * all Win32 functions * mixed GDI/GDI+ rendering + custom drawing pipelines + user‑defined message loops + any external library that expects raw pointers

This is not a framework—it is a safety layer.

The result is a system that preserves the full power of the underlying API while eliminating its friction. Developers get: * the safety of RAII * the clarity of object‑oriented syntax * the transparency of raw pointers * the flexibility of procedural APIs * the simplicity of tiny, focused classes

`AfxNova` does not try to redesign GDI+. It simply makes GDI+ usable.

The file `AfxGdipObjects.inc`, contains the complete set of these tiny classes for all major GDI+ objects. Each class is small, predictable, and easy to understand—yet together they form a robust, safe, and modern interface to a large and complex graphics subsystem.

The following table lists all lightweight RAII wrappers provided by `AfxNova` for opaque GDI+ objects (raw pointers to hidden internal structures).

AfxNova Class | GDI+ Object | Purpose/Description
--- | --- | ---
GdiPlusAdjustableArrowCap | GpAdjustableArrowCap | Builds a line cap that looks like an arrow.
GdiPlusBitmap | GpBitmap | Expands on the capabilities of the Image functions by providing additional methods for creating and manipulating raster images.
GdiPlusBrush | GpBrush | Base wrapper for all brush types.
GdiPlusCustomLineCap | GpCustomLineCap | Wraps custom line caps defined by paths.
GdiPlusEffect | GpEffect | Wraps GDI+ effects.
GdiPlusFont | GpFont | Font wrapper for text rendering.
GdiPlusGraphics | GpGraphics | Wraps a GDI+ graphics context.
GdiPlusGraphicsPath | GpPath | Wraps a graphics path; building, modifying, and disposing paths.
GdiPlusHatchBrush | GpHatchBrush | Hatch-style brush.
GdiPlusImage | GpImage | Loads, clones, and manages images from files, streams, and resources.
GdiPlusImageAttributes | GpImageAttributes | Image attributes (color adjustments, gamma, color matrices).
GdiPlusLinearGradientBrush | GpLinearGradientBrush | Linear gradient brush.
GdiPlusMatrix | GpMatrix | Transformation matrix; translation, rotation, scaling, etc.
GdiPlusObjects | GDI+ Startup/Shutdown | RAII wrapper for GDI+ initialization and shutdown.
GdiPlusPathGradientBrush | GpPathGradientBrush | Gradient brush that interpolates from boundary path to center color.
GdiPlusPathIterator | GpPathIterator | Iterates over path subpaths, types, and markers.
GdiPlusPen | GpPen | Wraps a pen for drawing lines and outlines.
GdiPlusRegion | GpRegion | Region wrapper for clipping and hit-testing.
GdiPlusSolidBrush | GpSolidBrush | Solid color brush.
GdiPlusStringFormat | GpStringFormat | Text layout and formatting options
GdiPlusTextureBrush | GpTextureBrush | Brush that fills using an image.

### GdiPlusObjects

Initializes and shutdowns GDI+.

    ' ========================================================================================
    ' Constructor - Initializes GDI+
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusObjects
       DIM StartupInput AS GdiplusStartupInput
       StartupInput.GdiplusVersion = 1   ' Version must be 1
       GdiplusStartup(@m_token, @StartupInput, NULL)
    END CONSTRUCTOR
    ' ========================================================================================

    ' ========================================================================================
    ' Dstructor - Shutdowns GDI+
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusObjects
       IF m_token THEN GdiplusShutdown(m_token)
    END DESTRUCTOR
    ' ========================================================================================

#### Example

    ' ########################################################################################
    ' Microsoft Windows
    ' File: Gdip_CreateAdjustableArrowCap.bas
    ' Contents: GDI+ Flat API - Gdip_CreateAdjustableArrowCap example
    ' Compiler: FreeBasic 32 & 64 bit
    ' Copyright (c) 2025 José Roca. Freeware. Use at your own risk.
    ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
    ' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
    ' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
    ' ########################################################################################

    #define _WIN32_WINNT &h0602
    '#define _GDIP_DEBUG_ 1
    #INCLUDE ONCE "AfxNova/AfxGdipObjects.inc"
    #INCLUDE ONCE "AfxNova/CGraphCtx.inc"
    USING AfxNova

    CONST IDC_GRCTX = 1001

    DECLARE FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                               BYVAL hPrevInstance AS HINSTANCE, _
                               BYVAL pwszCmdLine AS WSTRING PTR, _
                               BYVAL nCmdShow AS LONG) AS LONG

       END wWinMain(GetModuleHandleW(NULL), NULL, wCOMMAND(), SW_NORMAL)

    ' // Forward declaration
    DECLARE FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

    ' ========================================================================================
    ' The following example creates two AdjustableArrowCap objects, arrowCapStart and
    ' arrowCapEnd, and sets the fill mode to TRUE. The code then creates a Pen object and
    ' assigns arrowCapStart as the starting line cap for this Pen object and arrowCapEnd as
    ' the ending line cap. Next, draws a line.
    ' ========================================================================================
    SUB Example_CreateAdjustableArrowCap (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       DIM dpiRatio AS SINGLE = graphics.DpiRatio
       graphics.ScaleTransform(dpiRatio)

       ' // Create an AdjustableArrowCap that is filled.
       DIM arrowCapStart AS GdiPlusAdjustableArrowCap = GdiPlusAdjustableArrowCap(10, 10, TRUE)
       ' // Adjust to DPI by setting the scale width
       GdipSetCustomLineCapWidthScale(arrowCapStart, dpiRatio)

       ' // Create an AdjustableArrowCap that is not filled.
       DIM arrowCapEnd AS GdiPlusAdjustableArrowCap = GdiPlusAdjustableArrowCap(15, 15, FALSE)
       ' // Adjust to DPI by setting the scale width
       GdipSetCustomLineCapWidthScale(arrowCapEnd, dpiRatio)

       ' // Get the type of CustomLineCap
       ' // It will return 1 (CustomLineCapTypeAdjustableArrow)
       DIM nType AS CustomLineCapType
       GdipGetCustomLineCapType(arrowCapEnd, @nType)

       ' // Create a Pen
       DIM arrowPen AS GdiPlusPen = GdiPlusPen(ARGB_Violet, 1)

       ' // Assign arrowCapStart as the start cap.
       GdipSetPenCustomStartCap(arrowPen, arrowCapStart)
       ' // Assign arrowCapEnd as the end cap.
       GdipSetPenCustomEndCap(arrowPen, arrowCapEnd)

       ' // Draw a line using arrowPen.
       GdipDrawLine(graphics, arrowPen, 0, 0, 100, 100)

    END SUB
    ' ========================================================================================

    ' ========================================================================================
    ' Main
    ' ========================================================================================
    FUNCTION wWinMain (BYVAL hInstance AS HINSTANCE, _
                       BYVAL hPrevInstance AS HINSTANCE, _
                       BYVAL pwszCmdLine AS WSTRING PTR, _
                       BYVAL nCmdShow AS LONG) AS LONG

       ' // Set process DPI aware
       SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
       ' // Enable visual styles without including a manifest file
       AfxEnableVisualStyles

       ' // Create the main window
       DIM pWindow AS CWindow = "MyClassName"
       pWindow.Create(NULL, "GDI+ Gdip_CreateAdjustableArrowCap", @WndProc)
       ' // Size it by setting the wanted width and height of its client area
       pWindow.SetClientSize(400, 250)
       ' // Center the window
       pWindow.Center

       ' // Add a graphic control
       DIM pGraphCtx AS CGraphCtx = CGraphCtx(@pWindow, IDC_GRCTX, "", 0, 0, pWindow.ClientWidth, pWindow.ClientHeight)
       pGraphCtx.Clear RGB_FLORALWHITE
       ' // Anchor the control
       pWindow.AnchorControl(pGraphCtx.hWindow, AFX_ANCHOR_HEIGHT_WIDTH)

       ' // Get the memory device context of the graphic control
       DIM hdc AS HDC = pGraphCtx.GetMemDc

       ' // Initialize GDI+
       DIM pGdiPlusObjects AS GdiPlusObjects

       ' // Draw the graphics
       Example_CreateAdjustableArrowCap(hdc)

       ' // Displays the window and dispatches the Windows messages
       FUNCTION = pWindow.DoEvents(nCmdShow)

    END FUNCTION
    ' ========================================================================================

    ' ========================================================================================
    ' Main window procedure
    ' ========================================================================================
    FUNCTION WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

       SELECT CASE uMsg

          ' // If an application processes this message, it should return zero to continue
          ' // creation of the window. If the application returns –1, the window is destroyed
          ' // and the CreateWindowExW function returns a NULL handle.
          CASE WM_CREATE
             AfxEnableDarkModeForWindow(hwnd)
             RETURN 0

          ' // Theme has changed
          CASE WM_THEMECHANGED
             AfxEnableDarkModeForWindow(hwnd)
             RETURN 0

          CASE WM_COMMAND
             SELECT CASE CBCTL(wParam, lParam)
                CASE IDCANCEL
                   ' // If ESC key pressed, close the application by sending an WM_CLOSE message
                   IF CBCTLMSG(wParam, lParam) = BN_CLICKED THEN
                      SendMessageW hwnd, WM_CLOSE, 0, 0
                      RETURN 0
                   END IF
             END SELECT

            CASE WM_DESTROY
             ' // Ends the application by sending a WM_QUIT message
             PostQuitMessage(0)
             RETURN 0

       END SELECT

       ' // Default processing of Windows messages
       FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

    END FUNCTION
    ' ========================================================================================

### GdiPlusCustomLineCap

A line cap defines the style of graphic used to draw the ends of a line. It can be various shapes, such as a square, circle, or diamond. A custom line cap is defined by the path that draws it. The path is drawn by using a Pen object to draw the outline of a shape or by using a Brush object to fill the interior. The cap can be used on either or both ends of the line. Spacing can be adjusted between the end caps and the line.

    ' ========================================================================================
    TYPE GdiPlusCustomLineCap
    Public:
       m_CustomLineCap AS GpCustomLineCap PTR
       DECLARE CONSTRUCTOR (BYVAL customCap AS GpPath PTR)
       DECLARE CONSTRUCTOR (BYVAL fillPath AS GpPath PTR, BYVAL strokePath AS GpPath PTR, _
               BYVAL baseCap AS GpLineCap = LinecapFlat, BYVAL baseInset AS SINGLE = 0.0)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpCustomLineCap PTR PTR
       DECLARE OPERATOR CAST () AS GpCustomLineCap PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates a CustomLineCap
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusCustomLineCap (BYVAL customCap AS GpPath PTR)
       IF customCap THEN SetLastError(GdipCloneCustomLineCap(customCap, @m_CustomLineCap))
    END CONSTRUCTOR
    ' ========================================================================================

    ' =====================================================================================
    ' Creates a CustomLineCap object from a fill path and a stroke path.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusCustomLineCap (BYVAL fillPath AS GpPath PTR, BYVAL strokePath AS GpPath PTR, _
    BYVAL baseCap AS GpLineCap = LinecapFlat, BYVAL baseInset AS SINGLE = 0.0)
       SetLastError(GdipCreateCustomLineCap(fillPath, strokePath, baseCap, baseinset, @m_CustomLineCap))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusCustomLineCap
       IF m_CustomLineCap THEN SetLastError(GdipDeleteCustomLineCap(m_CustomLineCap))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpCustomLineCap object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF cap AS GdiPlusCustomLineCap) AS GpCustomLineCap PTR
       RETURN cap.m_CustomLineCap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpCustomLineCap object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusCustomLineCap.@ () AS GpCustomLineCap PTR PTR
       RETURN @m_CustomLineCap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusCustomLineCap.CAST () AS GpCustomLineCap PTR
       RETURN m_CustomLineCap
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a CustomLineCap object, sets its base cap, and then gets
    ' the base cap and assigns it to a Pen object. It then uses the Pen object to draw a line.
    ' ========================================================================================
    SUB Example_GetBaseCap (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create an empty Path object for the custom cap
       DIM capPath AS GdiPlusGraphicsPath = FillModeAlternate

       ' // Create a CustomLineCap using the empty path
       DIM customCap AS GdiPlusCustomLineCap = GdiPlusCustomLineCap(NULL, *capPath)

       ' // Create a red Pen with width 10
       DIM pen AS GdiPlusPen = GdiPlusPen(ARGB_RED, 10)

       ' // Assign the custom cap as the end cap of the pen
       GdipSetPenCustomEndCap(pen, customCap)

       ' // Draw a line using the pen and graphics object
       GdipDrawLine(graphics, pen, 0, 0, 100, 100)

    END SUB
    ' ========================================================================================

### GdiPlusAdjustableArrowCap

Builds a line cap that looks like an arrow.

    ' ========================================================================================
    TYPE GdiPlusAdjustableArrowCap
    Public:
       m_AdjustableArrowCap AS GpAdjustableArrowCap PTR
       DECLARE CONSTRUCTOR (BYVAL cap AS GpAdjustableArrowCap PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL nHeight AS SINGLE, BYVAL nWidth AS SINGLE, BYVAL bIsFilled AS BOOL = CTRUE)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpAdjustableArrowCap PTR PTR
       DECLARE OPERATOR CAST () AS GpAdjustableArrowCap PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates a AdjustableArrowCap
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusAdjustableArrowCap (BYVAL cap AS GpAdjustableArrowCap PTR = NULL)
       IF cap THEN SetLastError(GdipCloneCustomLineCap(cap, @m_AdjustableArrowCap))
    END CONSTRUCTOR
    ' ========================================================================================

    ' =====================================================================================
    ' Creates an adjustable arrow line cap with the specified height and width. The arrow
    ' line cap can be filled or nonfilled. The middle inset defaults to zero.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusAdjustableArrowCap (BYVAL nHeight AS SINGLE, BYVAL nWidth AS SINGLE, BYVAL bIsFilled AS BOOL = CTRUE)
       SetLastError(GdipCreateAdjustableArrowCap(nHeight, nWidth, bIsFilled, @m_AdjustableArrowCap))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusAdjustableArrowCap
       IF m_AdjustableArrowCap THEN SetLastError(GdipDeleteCustomLineCap(m_AdjustableArrowCap))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpAdjustableArrowCap object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF cap AS GdiPlusAdjustableArrowCap) AS GpAdjustableArrowCap PTR
       RETURN cap.m_AdjustableArrowCap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpAdjustableArrowCap object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusAdjustableArrowCap.@ () AS GpAdjustableArrowCap PTR PTR
       RETURN @m_AdjustableArrowCap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusAdjustableArrowCap.CAST () AS GpAdjustableArrowCap PTR
       RETURN m_AdjustableArrowCap
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates an AdjustableArrowCap object, myArrow, and sets the fill
    ' mode to TRUE. The code then creates a Pen object and assigns myArrow as the ending line
    ' cap for this Pen object. Next, the code tests whether myArrow is filled and, if it is,
    ' draws a line.
    ' ========================================================================================
    SUB Example_IsFilled (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       DIM dpiRatio AS SINGLE = graphics.DpiRatio
       graphics.ScaleTransform(dpiRatio)

       ' // Create an AdjustableArrowCap that is filled.
       DIM myArrow AS GdiPlusAdjustableArrowCap = GdiPlusAdjustableArrowCap(10, 10, TRUE)
       ' // Adjust to DPI by setting the scale width
       GdipSetCustomLineCapWidthScale(myArrow, dpiRatio)

       ' // Create a Pen, and assign myArrow as the end cap.
       DIM arrowPen AS GdiPlusPen = GdiPlusPen(ARGB_Violet, 1)
       ' // Assign myArrow as the end cap.
       GdipSetPenCustomEndCap(arrowPen, myArrow)

       ' // If the cap is filled, draw a line using arrowPen.
       DIM isFilled AS BOOL
       GdipGetAdjustableArrowCapFillState(myArrow, @isFilled)
       IF isFilled THEN GdipDrawLine(graphics, arrowPen, 0, 0, 100, 100)

    END SUB
    ' ========================================================================================

### GdiPlusBrush

A Brush object is used to paint the interior of graphics shapes, such as rectangles, ellipses, pies, polygons, and paths.

    ' ========================================================================================
    TYPE GdiPlusBrush
    Public:
       m_Brush AS GpBrush PTR
       DECLARE CONSTRUCTOR (BYVAL brush AS GpBrush PTR = NULL)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpBrush PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBrush (BYVAL brush AS GpBrush PTR = NULL)
       IF brush THEN SetLastError(GdipCloneBrush(brush, @m_brush))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusBrush
       IF m_Brush THEN GdipDeleteBrush(m_Brush)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF brush AS GdiPlusBrush) AS GpBrush PTR
       RETURN brush.m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusBrush.@ () AS GpBrush PTR PTR
       RETURN @m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusBrush.CAST () AS GpBrush PTR
       RETURN m_Brush
    END OPERATOR
    ' ========================================================================================

### GdiPlusSolidBrush

Defines a solid color Brush object. A Brush object is used to fill in shapes similar to the way a paint brush can paint the inside of a shape.

    ' ========================================================================================
    TYPE GdiPlusSolidBrush
    Public:
       m_Brush AS GpSolidBrush PTR
       DECLARE CONSTRUCTOR (BYVAL brush AS GpSolidBrush PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL colour AS ARGB = &hFF000000)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpSolidBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpSolidBrush PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates a brush from another brush.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusSolidBrush (BYVAL brush AS GpSolidBrush PTR = NULL)
       IF brush THEN SetLastError(GdipCloneBrush(brush, @m_brush))
    END CONSTRUCTOR
    ' ========================================================================================

    ' ========================================================================================
    ' Creates a solid brush filled with the specified color.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusSolidBrush (BYVAL colour AS ARGB = &hFF000000)
       SetLastError(GdipCreateSolidFill(colour, @m_Brush))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusSolidBrush
       IF m_Brush THEN GdipDeleteBrush(m_Brush)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpSolidBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF brush AS GdiPlusSolidBrush) AS GpSolidBrush PTR
       RETURN brush.m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusSolidBrush.@ () AS GpSolidBrush PTR PTR
       RETURN @m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusSolidBrush.CAST () AS GpSolidBrush PTR
       RETURN m_Brush
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a SolidBrush object, clones it, and then uses the clone
    ' to fill a rectangle.
    ' ========================================================================================
    SUB Example_CloneBrush (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a SolidBrush
       DIM brush AS GdiPlusSolidBrush = ARGB_RED

       ' // Create a clone of the SolidBrush
       DIM cloneBrush AS GdiPlusSolidBrush = *brush

       ' // Use the clone brush to fill a rectagle
       GdipFillRectangle(graphics, cloneBrush, 0, 0, 100, 100)

    END SUB
    ' ========================================================================================

### GdiPlusHatchBrush

An HatchBrush defines a rectangular brush with a hatch style, a foreground color, and a background color. There are six hatch styles. The foreground color defines the color of the hatch lines; the background color defines the color over which the hatch lines are drawn

    ' ========================================================================================
    TYPE GdiPlusHatchBrush
    Public:
       m_Brush AS GpHatchBrush PTR
       DECLARE CONSTRUCTOR (BYVAL brush AS GpHatchBrush PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL nHatchStyle AS HatchStyle, BYVAL foreColor AS ARGB, BYVAL backColor AS ARGB = &HFF000000)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpHatchBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpHatchBrush PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates a brush from another brush.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusHatchBrush (BYVAL brush AS GpHatchBrush PTR = NULL)
       IF brush THEN SetLastError(GdipCloneBrush(brush, @m_brush))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a HatchBrush object based on a hatch style, a foreground color, and a background color.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusHatchBrush (BYVAL nHatchStyle AS HatchStyle, BYVAL foreColor AS ARGB, BYVAL backColor AS ARGB = &HFF000000)
       SetLastError(GdipCreateHatchBrush(nHatchStyle, foreColor, backColor, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusHatchBrush
       IF m_Brush THEN GdipDeleteBrush(m_Brush)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpHatchBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF brush AS GdiPlusHatchBrush) AS GpHatchBrush PTR
       RETURN brush.m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpHatchBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusHatchBrush.@ () AS GpHatchBrush PTR PTR
       RETURN @m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusHatchBrush.CAST () AS GpHatchBrush PTR
       RETURN m_Brush
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example draws six of the available hatch styles.
    ' ========================================================================================
    SUB Example_CreateHatchBrush (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Set and then draw the first hatch style.
       DIM brush AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleHorizontal, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush, 20, 20, 115, 50)

       ' // Set and then draw the second hatch style.
       DIM brush1 AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleVertical, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush1, 145, 20, 115, 50)

       ' // Set and then draw the third hatch style.
       DIM brush2 AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleForwardDiagonal, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush2, 270, 20, 115, 50)

       ' // Set and then draw the fourth hatch style.
       DIM brush3 AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleBackwardDiagonal, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush3, 20, 100, 115, 50)

       ' // Set and then draw the fifth hatch style.
       DIM brush4 AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleCross, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush4, 145, 100, 115, 50)

       ' // Set and then draw the sixth hatch style.
       DIM brush5 AS GdiPlusHatchBrush = GdiPlusHatchBrush(HatchStyleDiagonalCross, ARGB_BLACK, ARGB_WHITE)
       GdipFillRectangle(graphics, brush5, 270, 100, 115, 50)

    END SUB
    ' ========================================================================================

### GdiPlusLinearGradientBrush

The LinearGradientBrush functions allow to paint a color gradient in which the color changes evenly from the starting boundary line of the linear gradient brush to the ending boundary line of the linear gradient brush. The boundary lines of a linear gradient brush are two parallel straight lines. The color gradient is perpendicular to the boundary lines of the linear gradient brush, changing gradually across the stroke from the starting boundary line to the ending boundary line. The color gradient has one color at the starting boundary line and another color at the ending boundary line.

    ' ========================================================================================
    TYPE GdiPlusLinearGradientBrush
    Public:
       m_Brush AS GpLinearGradientBrush PTR
       DECLARE CONSTRUCTOR (BYVAL point1 AS GpPointF PTR, BYVAL point2 AS GpPointF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL point1 AS GpPoint PTR, BYVAL point2 AS GpPoint PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRectF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL nMode AS LinearGradientMode, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRect PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL nMode AS LinearGradientMode, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRectF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL angle AS SINGLE, BYVAL isAngleScalable AS BOOL, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRect PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL angle AS SINGLE, BYVAL isAngleScalable AS BOOL, BYVAL wrap AS WrapMode = WrapModeTile)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpLinearGradientBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpLinearGradientBrush PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Creates a LinearGradientBrush object from a set of boundary points and boundary colors.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL point1 AS GpPointF PTR, BYVAL point2 AS GpPointF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrush(point1, point2, color1, color2, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL point1 AS GpPoint PTR, BYVAL point2 AS GpPoint PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrushI(point1, point2, color1, color2, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a LinearGradientBrush object from a set of boundary points and boundary colors.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL rc AS GpRectF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL nMode AS LinearGradientMode, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrushFromRect(rc, color1, color2, nMode, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL rc AS GpRect PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL nMode AS LinearGradientMode, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrushFromRectI(rc, color1, color2, nMode, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a LinearGradientBrush object from a set of boundary points and boundary colors.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL rc AS GpRectF PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL angle AS SINGLE, BYVAL isAngleScalable AS BOOL, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrushFromRectWithAngle(rc, color1, color2, angle, isAngleScalable, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusLinearGradientBrush (BYVAL rc AS GpRect PTR, BYVAL color1 AS ARGB, BYVAL color2 AS ARGB, BYVAL angle AS SINGLE, BYVAL isAngleScalable AS BOOL, BYVAL wrap AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateLineBrushFromRectWithAngleI(rc, color1, color2, angle, isAngleScalable, wrap, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusLinearGradientBrush
       IF m_Brush THEN GdipDeleteBrush(m_Brush)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpLinearGradientBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF brush AS GdiPlusLinearGradientBrush) AS GpLinearGradientBrush PTR
       RETURN brush.m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpLinearGradientBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusLinearGradientBrush.@ () AS GpLinearGradientBrush PTR PTR
       RETURN @m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusLinearGradientBrush.CAST () AS GpLinearGradientBrush PTR
       RETURN m_Brush
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' Creates a LinearGradientBrush object from a set of boundary points and boundary colors.
    ' This function is ideal for creating gradients aligned to rectangular UI elements or backgrounds.
    ' ========================================================================================
    SUB Example_CreateLineBrushFromRect (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Define gradient rectangle
       DIM rcf AS GpRectF = (0, 0, 200, 100)

       ' // Create brush with horizontal gradient
       DIM brush AS GdiPlusLinearGradientBrush = GdiPlusLinearGradientBrush(@rcf, ARGB_RED, ARGB_BLUE, LinearGradientModeHorizontal)

       ' // Fill rectangle
       GdipFillRectangle(graphics, brush, rcf.x, rcf.y, rcf.Width, rcf.Height)

    END SUB
    ' ========================================================================================

### GdiPlusPathGradientBrush

The PathGradientBrush functions allow to set the attributes of a color gradient that you can use to fill the interior of a path with a gradually changing color. A path gradient brush has a boundary path, a boundary color, a center point, and a center color. When you paint an area with a path gradient brush, the color changes gradually from the boundary color to the center color as you move from the boundary path to the center point.

    ' ========================================================================================
    TYPE GdiPlusPathGradientBrush
    Public:
       m_Brush AS GpPathGradientBrush PTR
       DECLARE CONSTRUCTOR (BYVAL path AS GpPath PTR)
       DECLARE CONSTRUCTOR (BYVAL points AS CONST GpPointF PTR, BYVAL count AS INT_, BYVAL wrapMode AS GpWrapMode = WrapModeClamp)
       DECLARE CONSTRUCTOR (BYVAL points AS CONST GpPoint PTR, BYVAL count AS INT_, BYVAL wrapMode AS GpWrapMode = WrapModeClamp)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpPathGradientBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpPathGradientBrush PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Creates a path gradient brush from a path
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPathGradientBrush (BYVAL path AS GpPath PTR)
       SetLastError(GdipCreatePathGradientFromPath(path, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a path gradient brush
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPathGradientBrush (BYVAL points AS CONST GpPointF PTR, BYVAL count AS INT_, BYVAL wrapMode AS GpWrapMode = WrapModeClamp)
       SetLastError(GdipCreatePathGradient(points, count, wrapMode, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPathGradientBrush (BYVAL points AS CONST GpPoint PTR, BYVAL count AS INT_, BYVAL wrapMode AS GpWrapMode = WrapModeClamp)
       SetLastError(GdipCreatePathGradientI(points, count, wrapMode, @m_brush))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusPathGradientBrush
       IF m_Brush THEN GdipDeleteBrush(m_Brush)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpPathGradientBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF brush AS GdiPlusPathGradientBrush) AS GpPathGradientBrush PTR
       RETURN brush.m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpPathGradientBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPathGradientBrush.@ () AS GpPathGradientBrush PTR PTR
       RETURN @m_Brush
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPathGradientBrush.CAST () AS GpPathGradientBrush PTR
       RETURN m_Brush
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example draws a star-shaped GraphicsPath.
    ' Creates a star-shaped GraphicsPath and fills it using a PathGradientBrush constructed
    ' from that path. The gradient transitions from a red center to a set of surround colors
    ' defined at each vertex of the star. DPI scaling is applied globally to ensure consistent
    ' rendering across high-resolution displays.
    ' ========================================================================================
    SUB Example_CreatePathGradientFromPath (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a GraphicsPath object and initializes the fill mode.
       DIM path AS GdiPlusGraphicsPath = FillModeAlternate

       ' // Fill the array of points.
       DIM pts(0 TO 9) AS GpPointF
       pts(0).x = 75  : pts(0).y = 0
       pts(1).x = 100 : pts(1).y = 50
       pts(2).x = 150 : pts(2).y = 50
       pts(3).x = 112 : pts(3).y = 75
       pts(4).x = 150 : pts(4).y = 150
       pts(5).x = 75  : pts(5).y = 100
       pts(6).x = 0   : pts(6).y = 150
       pts(7).x = 37  : pts(7).y = 75
       pts(8).x = 0   : pts(8).y = 50
       pts(9).x = 50  : pts(9).y = 50

       ' // Construct the path with the array of points.
       GdipAddPathLine2(path, @pts(0), 10)

       ' // Use the path to construct a path gradient brush.
       DIM brush AS GdiPlusPathGradientBrush = *path

       ' // Set the color at the center of the path to red.
       GdipSetPathGradientCenterColor(brush, ARGB_RED)

       ' // Set the colors of the points in the array.
       DIM Colors(9) AS ARGB
       Colors(0) = ARGB_BLACK
       Colors(1) = ARGB_LIGHTGREEN
       Colors(2) = ARGB_BLUE
       Colors(3) = ARGB_WHITE
       Colors(4) = ARGB_BLACK
       Colors(5) = ARGB_LIGHTGREEN
       Colors(6) = ARGB_BLUE
       Colors(7) = ARGB_WHITE
       Colors(8) = ARGB_BLACK
       Colors(9) = ARGB_LIGHTGREEN
       DIM count AS LONG = 10
       GdipSetPathGradientSurroundColorsWithCount(brush, @Colors(0), @count)

       ' // Fill the path with the path gradient brush.
       GdipFillPath(graphics, brush, path)

    END SUB
    ' ========================================================================================

### GdiPlusTextureBrush

The TextureBrush object is a Brush object that contains an Image object that is used for the fill. The fill image can be transformed by using the local Matrix object contained in the Brush object.

    ' ========================================================================================
    TYPE GdiPlusTextureBrush
    Public:
       m_Texture AS GpTextureBrush PTR
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode = WrapModeTile)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL dstRect AS GpRectF PTR, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL dstRect AS GpRect PTR, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL dstX AS SINGLE, BYVAL dstY AS SINGLE, BYVAL dstWidth AS SINGLE, BYVAL dstHeight AS SINGLE, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL dstX AS INT_, BYVAL dstY AS INT_, BYVAL dstWidth AS INT_, BYVAL dstHeight AS INT_, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstRect AS GpRect PTR)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstRect AS GpRectF PTR)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstX AS SINGLE, BYVAL dstY AS SINGLE, BYVAL dstWidth AS SINGLE, BYVAL dstHeight AS SINGLE)
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstX AS INT_, BYVAL dstY AS INT_, BYVAL dstWidth AS INT_, BYVAL dstHeight AS INT_)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpTextureBrush PTR PTR
       DECLARE OPERATOR CAST () AS GpTextureBrush PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Creates a TextureBrush object based on an image and a wrap mode. The size of the brush
    ' defaults to the size of the image, so the entire image is used by the brush.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode = WrapModeTile)
       SetLastError(GdipCreateTexture(image, nWrapmode, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a TextureBrush object based on an image, a defining set of coordinates, and
    ' a set of image properties.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL dstRect AS GpRectF PTR, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       SetLastError(GdipCreateTextureIA(image, imageAttributes, dstRect->x, dstRect->y, dstRect->Width, dstRect->Height, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL dstRect AS GpRect PTR, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       SetLastError(GdipCreateTextureIAI(image, imageAttributes, dstRect->x, dstRect->y, dstRect->Width, dstRect->Height, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL dstX AS SINGLE, BYVAL dstY AS SINGLE, BYVAL dstWidth AS SINGLE, BYVAL dstHeight AS SINGLE, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       SetLastError(GdipCreateTextureIA(image, imageAttributes, dstX, dstY, dstWidth, dstHeight, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL dstX AS INT_, BYVAL dstY AS INT_, BYVAL dstWidth AS INT_, BYVAL dstHeight AS INT_, BYVAL imageAttributes AS GpImageAttributes PTR = NULL)
       SetLastError(GdipCreateTextureIA(image, imageAttributes, dstX, dstY, dstWidth, dstHeight, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a TextureBrush object based on an image, a wrap mode, and a defining set of coordinates.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstRect AS GpRect PTR)
       SetLastError(GdipCreateTexture2I(image, nWrapMode, dstRect->x, dstRect->y, dstRect->Width, dstRect->Height, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstRect AS GpRectF PTR)
       SetLastError(GdipCreateTexture2(image, nWrapMode, dstRect->x, dstRect->y, dstRect->Width, dstRect->Height, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstX AS SINGLE, BYVAL dstY AS SINGLE, BYVAL dstWidth AS SINGLE, BYVAL dstHeight AS SINGLE)
       SetLastError(GdipCreateTexture2(image, nWrapMode, dstX, dstY, dstWidth, dstHeight, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusTextureBrush (BYVAL image AS GpImage PTR, BYVAL nWrapMode AS WrapMode, BYVAL dstX AS INT_, BYVAL dstY AS INT_, BYVAL dstWidth AS INT_, BYVAL dstHeight AS INT_)
       SetLastError(GdipCreateTexture2I(image, nWrapMode, dstX, dstY, dstWidth, dstHeight, @m_Texture))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusTextureBrush
       IF m_Texture THEN GdipDeleteBrush(m_Texture)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpTextureBrush object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF texture AS GdiPlusTextureBrush) AS GpTextureBrush PTR
       RETURN texture.m_Texture
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpTextureBrush object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusTextureBrush.@ () AS GpTextureBrush PTR PTR
       RETURN @m_Texture
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusTextureBrush.CAST () AS GpTextureBrush PTR
       RETURN m_Texture
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a texture brush and fills a rectangle.
    ' ========================================================================================
    SUB Example_CreateTexture (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Load the image and set the dpi resolution
       DIM image AS GdiPlusImage = "HouseAndTree.gif"
       image.SetResolution(graphics)

       ' // Create a texture brush, and set its wrap mode.
       DIM textureBrush AS GdiPlusTextureBrush = *image
       ' // Fill a rectangle with the texture brush
       GdipFillRectangle(graphics, textureBrush, 20, 20, 360, 210)

    END SUB
    ' ========================================================================================

### GdiPlusImage

The Image functions allow loading and saving raster images (bitmaps) and vector images (metafiles). An Image object encapsulates a bitmap or a metafile and stores attributes that you can retrieve by calling various Get functions. You can construct Image objects from a variety of file types including BMP, ICON, GIF, JPEG, Exif, PNG, TIFF, WMF, and EMF.

    ' ========================================================================================
    TYPE GdiPlusImage
    Public:
       m_Image AS GpImage PTR
       DECLARE CONSTRUCTOR (BYVAL image AS GpImage PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL pwszFileName AS WSTRING PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       DECLARE CONSTRUCTOR (BYVAL stream AS IStream PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       DECLARE CONSTRUCTOR (BYVAL hInst AS HINSTANCE, BYREF wszImageName AS WSTRING)
       DECLARE OPERATOR CAST () AS GpImage PTR
       DECLARE OPERATOR @ () AS GpImage PTR PTR
       DECLARE DESTRUCTOR
       DECLARE SUB SetResolution (BYVAL graphics AS GpGraphics PTR, BYVAL dpiX AS SINGLE = 0, BYVAL dpiY AS SINGLE = 0)
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates and initializes an Image object from another Image object.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusImage (BYVAL image AS GpImage PTR)
       IF image THEN SetLastError(GdipCloneImage(image, @m_Image))
    END CONSTRUCTOR
    ' ========================================================================================

    ' ========================================================================================
    ' Creates an Image object based on a file.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusImage (BYVAL pwszFileName AS WSTRING PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       IF useEmbeddedColorManagement THEN
          SetLastError(GdipLoadImageFromFileICM(pwszFileName, @m_Image))
       ELSE
          SetLastError(GdipLoadImageFromFile(pwszFileName, @m_Image))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates an Image object based on a stream.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusImage (BYVAL stream AS IStream PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       IF useEmbeddedColorManagement THEN
          SetLastError(GdipLoadImageFromStreamICM(stream, @m_Image))
       ELSE
          SetLastError(GdipLoadImageFromStream(stream, @m_Image))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates an Image object from a resource file.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusImage (BYVAL hInst AS HINSTANCE, BYREF wszImageName AS WSTRING)
       DIM stream AS IStream PTR = AfxImageStreamFromRes(hInst, wszImageName)
       IF stream = NULL THEN SetLastError(InvalidParameter): EXIT CONSTRUCTOR
       SetLastError(GdipLoadImageFromStream(stream, @m_Image))
       stream->lpVtbl->Release(stream)
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusImage
       IF m_Image THEN SetLastError(GdipDisposeImage(m_Image))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpImage object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF img AS GdiPlusImage) AS GpImage PTR
       RETURN img.m_Image
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusImage.CAST () AS GpImage PTR
       RETURN m_Image
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpImage object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusImage.@ () AS GpImage PTR PTR
       RETURN @m_Image
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE SUB GdiPlusImage.SetResolution (BYVAL graphics AS GpGraphics PTR, BYVAL dpiX AS SINGLE = 0, BYVAL dpiY AS SINGLE = 0)
       IF dpiX = 0 AND dpiY = 0 THEN
          GdipGetDpiX(graphics, @dpiX)
          GdipGetDpiY(graphics, @dpiY)
       END IF
       SetLastError(GdipBitmapSetResolution(m_Image, dpiX, dpiY))
    END SUB
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates an Image object based on a JPEG file. The code creates a
    ' second Image object by cloning the first. Then the code calls the DrawImage method twice
    ' to draw the two images.
    ' ========================================================================================
    SUB Example_CloneImage (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Load the original image from file
       DIM image1 AS GdiPlusImage = "climber.jpg"
       ' // Set the resolution of this Image object to the user's DPI settings
       image1.SetResolution(graphics)

       ' // Clone the image
       DIM image2 AS GdiPlusImage = image1

       ' // Draw the original image
       GdipDrawImage(graphics, image1, 10, 10)

       ' // Draw the cloned image
       GdipDrawImage(graphics, image2, 210, 10)

    END SUB
    ' ========================================================================================

### GdiPlusBitmap

The Bitmap functions expands on the capabilities of the Image functions by providing additional methods for creating and manipulating raster images.

    ' ========================================================================================
    TYPE GdiPlusBitmap
    Public:
       m_Bitmap AS GpBitmap PTR
       DECLARE CONSTRUCTOR (BYVAL bmp AS GpBitmap PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL x AS REAL, BYVAL y AS REAL, BYVAL nWidth AS REAL, BYVAL nHeight AS REAL, _
               BYVAL pxFormat AS PixelFormat, BYVAL srcBitmap AS GpBitmap PTR)
       DECLARE CONSTRUCTOR (BYVAL rcf AS GpRectF PTR, BYVAL pxFormat AS PixelFormat, BYVAL srcBitmap AS GpBitmap PTR)
       DECLARE CONSTRUCTOR (BYVAL pwszFileName AS WSTRING PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       DECLARE CONSTRUCTOR (BYVAL stream AS IStream PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       DECLARE CONSTRUCTOR (BYVAL nWidth AS INT_, BYVAL nHeight AS INT_, BYVAL stride AS INT_, BYVAL pxFormat AS PixelFormat, BYVAL scan0 AS UBYTE PTR)
       DECLARE CONSTRUCTOR (BYVAL nWidth AS INT_, BYVAL nHeight AS INT_, BYVAL pxFormat AS PixelFormat)
       DECLARE CONSTRUCTOR (BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL pTarget AS GpGraphics PTR)
       #ifdef IDirectDrawSurface7
       DECLARE CONSTRUCTOR (BYVAL surface AS IDirectDrawSurface7 PTR)
       #endif
       DECLARE CONSTRUCTOR (BYVAL gdiBitmapInfo AS BITMAPINFO PTR, BYVAL gdiBitmapData AS ANY PTR)
       DECLARE CONSTRUCTOR (BYVAL hbm AS HBITMAP, BYVAL hPal AS HPALETTE)
       DECLARE CONSTRUCTOR (BYVAL hicon AS HICON)
       DECLARE CONSTRUCTOR (BYVAL hInstance AS HINSTANCE, BYVAL pwszBitmapName AS WSTRING PTR)
       DECLARE CONSTRUCTOR (BYVAL inputBitmap AS GpBitmap PTR, BYVAL effect AS GpEffect PTR)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpBitmap PTR PTR
       DECLARE OPERATOR CAST () AS GpBitmap PTR
       DECLARE SUB SetResolution (BYVAL graphics AS GpGraphics PTR, BYVAL dpiX AS SINGLE = 0, BYVAL dpiY AS SINGLE = 0)
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates and initializes a Bitmap object from another Bitmap object.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL bmp AS GpBitmap PTR = NULL)
       IF bmp THEN SetLastError(GdipCloneImage(bmp, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a new Bitmap object by copying a portion of the specified bitmap.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL x AS REAL, BYVAL y AS REAL, BYVAL nWidth AS REAL, BYVAL nHeight AS REAL, _
    BYVAL pxFormat AS PixelFormat, BYVAL srcBitmap AS GpBitmap PTR)
       SetLastError(GdipCloneBitmapArea(x, y, nWidth, nHeight, pxFormat, srcBitmap, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a new Bitmap object by copying a portion of the specified bitmap.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL rcf AS GpRectF PTR, BYVAL pxFormat AS PixelFormat, BYVAL srcBitmap AS GpBitmap PTR)
       SetLastError(GdipCloneBitmapArea(rcf->x, rcf->y, rcf->Width, rcf->Height, pxFormat, srcBitmap, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates an Bitmap object based on a file.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL pwszFileName AS WSTRING PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       IF useEmbeddedColorManagement THEN
          SetLastError(GdipCreateBitmapFromFileICM(pwszFileName, @m_Bitmap))
       ELSE
          SetLastError(GdipCreateBitmapFromFile(pwszFileName, @m_Bitmap))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates an Image object based on a stream.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL stream AS IStream PTR, BYVAL useEmbeddedColorManagement AS BOOLEAN = FALSE)
       IF useEmbeddedColorManagement THEN
          SetLastError(GdipCreateBitmapFromStream(stream, @m_Bitmap))
       ELSE
          SetLastError(GdipCreateBitmapFromStream(stream, @m_Bitmap))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on an array of bytes along with size and format information.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL nWidth AS INT_, BYVAL nHeight AS INT_, BYVAL stride AS INT_, BYVAL pxFormat AS PixelFormat, BYVAL scan0 AS UBYTE PTR)
       SetLastError(GdipCreateBitmapFromScan0(nWidth, nHeight, stride, pxFormat, scan0, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on size and format information.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL nWidth AS INT_, BYVAL nHeight AS INT_, BYVAL pxFormat AS PixelFormat)
       SetLastError(GdipCreateBitmapFromScan0(nWidth, nHeight, 0, pxFormat, NULL, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on a Graphics object, a width, and a height.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL pTarget AS GpGraphics PTR)
       SetLastError(GdipCreateBitmapFromGraphics(nWidth, nHeight, pTarget, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on a DirectDraw surface. The Bitmap object maintains a
    ' reference to the DirectDraw surface until the Bitmap object is deleted or goes out of scope.
    ' ========================================================================================
    #ifdef IDirectDrawSurface7
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL surface AS IDirectDrawSurface7 PTR)
       SetLastError(GdipCreateBitmapFromDirectDrawSurface(surface, @m_Bitmap))
    END CONSTRUCTOR
    #endif
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on a BITMAPINFO structure and an array of pixel data.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL gdiBitmapInfo AS BITMAPINFO PTR, BYVAL gdiBitmapData AS ANY PTR)
       SetLastError(GdipCreateBitmapFromGdiDib(gdiBitmapInfo, gdiBitmapData, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on a handle to a Windows Windows Graphics Device
    ' Interface (GDI) bitmap and a handle to a GDI palette.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL hbm AS HBITMAP, BYVAL hPal AS HPALETTE)
       SetLastError(GdipCreateBitmapFromHBITMAP(hbm, hpal, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on an icon.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL hicon AS HICON)
       SetLastError(GdipCreateBitmapFromHICON(hicon, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Bitmap object based on an application or DLL instance handle and the name of a bitmap.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL hInstance AS HINSTANCE, BYVAL pwszBitmapName AS WSTRING PTR)
       SetLastError(GdipCreateBitmapFromResource(hInstance, pwszBitmapName, @m_Bitmap))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a new Bitmap object by applying a specified effect to an existing Bitmap object.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusBitmap (BYVAL inputBitmap AS GpBitmap PTR, BYVAL effect AS GpEffect PTR)
       SetLastError(GdipBitmapCreateApplyEffect(@inputBitmap, 1, effect, NULL, NULL, @m_Bitmap, FALSE, NULL, NULL))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusBitmap
       IF m_Bitmap THEN SetLastError(GdipDisposeImage(m_Bitmap))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpBitmap object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF bmp AS GdiPlusBitmap) AS GpBitmap PTR
       RETURN bmp.m_Bitmap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpBitmap object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusBitmap.@ () AS GpBitmap PTR PTR
       RETURN @m_Bitmap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusBitmap.CAST () AS GpBitmap PTR
       RETURN m_Bitmap
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE SUB GdiPlusBitmap.SetResolution (BYVAL graphics AS GpGraphics PTR, BYVAL dpiX AS SINGLE = 0, BYVAL dpiY AS SINGLE = 0)
       IF dpiX = 0 AND dpiY = 0 THEN
          GdipGetDpiX(graphics, @dpiX)
          GdipGetDpiY(graphics, @dpiY)
       END IF
       SetLastError(GdipBitmapSetResolution(m_Bitmap, dpiX, dpiY))
    END SUB
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a Bitmap object based on a JPEG file and draws it.
    ' ========================================================================================
    SUB Example_CreateBitmap (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a bitmap object from a .jpg file
       DIM myBitmap AS GdiPlusBitmap = "climber.jpg"
       ' // Set the resolution of this Bitmap object to the user's DPI settings
       myBitmap.SetResolution(graphics)

       ' // Draw the bitmap.
       GdipDrawImage(graphics, myBitmap, 0, 0)

    END SUB
    ' ========================================================================================

### GdiPlusImageAttributes

An ImageAttributes object contains information about how bitmap and metafile colors are manipulated during rendering. An ImageAttributes object maintains several color-adjustment settings, including color-adjustment matrices, grayscale-adjustment matrices, gamma-correction values, color-map tables, and color-threshold values.

    ' ========================================================================================
    TYPE GdiPlusImageAttributes
    Public:
       m_ImgAttr AS GpImageAttributes PTR
       DECLARE CONSTRUCTOR (BYVAL imgAttr AS GpImageAttributes PTR = NULL)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpImageAttributes PTR PTR
       DECLARE OPERATOR CAST () AS GpImageAttributes PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Default constructor
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusImageAttributes (BYVAL imgAttr AS GpImageAttributes PTR = NULL)
       IF imgAttr THEN
          SetLastError(GdipCloneImageAttributes(imgAttr, @m_ImgAttr))
       ELSE
          SetLastError(GdipCreateImageAttributes(@m_ImgAttr))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================

    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusImageAttributes
       IF m_ImgAttr THEN GdipDisposeImageAttributes(m_ImgAttr)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpImageAttributes object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF imgAttr AS GdiPlusImageAttributes) AS GpImageAttributes PTR
       RETURN imgAttr.m_ImgAttr
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpImageAttributes object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusImageAttributes.@ () AS GpImageAttributes PTR PTR
       RETURN @m_ImgAttr
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusImageAttributes.CAST () AS GpImageAttributes PTR
       RETURN m_ImgAttr
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates an Image object loading an image from file, creates an
    ' ImageAttributes object, sets the wrap mode to WrapModeTile and draws the specified
    ' source rectangle to the destination rectangle, which is four times as large as the
    ' image itself.
    ' ========================================================================================
    SUB Example_CreateImageAttributes (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Load an image from file
       DIM image AS GdiPlusImage = "climber.jpg"
       ' // Set the resolution of this image object to the user's DPI settings
       image.SetResolution(graphics)

       ' // Get the width and height of the image
       DIM AS LONG nWidth, nHeight
       GdipGetImageWidth(image, @nWidth)
       GdipGetImageHeight(image, @nHeight)

       ' // Create an ImageAttributes object
       DIM imgAttr AS GdiPlusImageAttributes

       ' // Set the wrap mode to WrapModeTile
       GdipSetImageAttributesWrapMode(imgAttr, WrapModeTile, ARGB_BLUE, FALSE)

       ' // Draw the image
       GdipDrawImageRectRect(graphics, image, _
                10, 10, nWidth, nHeight, _         ' dest rect
                0, 0, 2 * nWidth, 2 * nHeight, _   ' source dest
                UnitPixel, imgAttr, NULL, NULL)

    END SUB
    ' ========================================================================================

### GdiPlusEffect

Allows to apply effects and adjustments to bitmaps.

    ' ========================================================================================
    TYPE GdiPlusEffect
    Public:
       m_Effect AS GpEffect PTR
       m_auxDataSize AS INT_
       m_auxData AS ANY PTR
       m_useAuxData AS BOOLEAN
       DECLARE CONSTRUCTOR (BYVAL gd AS GUID)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpEffect PTR PTR
       DECLARE OPERATOR CAST () AS GpEffect PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Default constructor
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusEffect (BYVAL gd AS GUID)
       SetLastError GdipCreateEffect(gd, @m_Effect)
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusEffect
       ' // auxData is allocated by ApplyEffect.
       IF m_auxData THEN GdipFree(m_auxData)
       ' // Delete the Effect object
       IF m_Effect THEN GdipDeleteEffect(m_Effect)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the CGpEffect object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF effect AS GdiPlusEffect) AS GpEffect PTR
       RETURN effect.m_Effect
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpEffect object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusEffect.@ () AS GpEffect PTR PTR
       RETURN @m_Effect
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusEffect.CAST () AS GpEffect PTR
       RETURN m_Effect
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' This example loads an image from disk and applies a blur effect using GDI+ 1.1.
    ' ========================================================================================
    SUB Example_BlurEffect (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a bitmap object from a .jpg file
       DIM bmp AS GdiPlusBitmap = "climber.jpg"
       ' // Set the resolution of this Bitmap object to the user's DPI settings
       bmp.SetResolution(graphics)

       ' // Create a blur effect
       DIM effect AS GdiPlusEffect = BlurEffectGuid

       ' // Set parameters: radius = 6.0, expandEdge = FALSE
       DIM blurParams(0 TO 1) AS SINGLE = {6.0, FALSE}
       DIM array_size AS GpUnit = (UBOUND(blurParams) - LBOUND(blurParams) + 1) * SIZEOF(SINGLE)
       GdipSetEffectParameters(effect, @blurParams(0), array_size)

       ' // Apply effects to the whole image
       GdipBitmapApplyEffect(bmp, effect, NULL, FALSE, NULL, NULL)

       ' // Draw the image
       GdipDrawImage(graphics, bmp, 0, 0)

    END SUB
    ' ========================================================================================

### GdiPlusGraphics

The Graphics functions provide methods for drawing lines, curves, figures, images, and text. A Graphics object stores attributes of the display device and attributes of the items to be drawn.

    ' ========================================================================================
    TYPE GdiPlusGraphics
    Public:
       m_Graphics AS GpGraphics PTR
       DECLARE CONSTRUCTOR (BYVAL hdc AS HDC)
       DECLARE CONSTRUCTOR (BYVAL hdc AS HDC, BYVAL hDevice AS HANDLE)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpGraphics PTR PTR
       DECLARE OPERATOR CAST () AS GpGraphics PTR
       DECLARE FUNCTION DpiX () AS SINGLE
       DECLARE FUNCTION DpiY () AS SINGLE
       DECLARE FUNCTION DpiRatio () AS SINGLE
       DECLARE FUNCTION DpiRatioX () AS SINGLE
       DECLARE FUNCTION DpiRatioY () AS SINGLE
       DECLARE FUNCTION ScaleTransform (BYVAL sx AS SINGLE, BYVAL sy AS SINGLE, BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
       DECLARE FUNCTION ScaleTransform (BYVAL dpiRatio_ AS SINGLE, BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
       DECLARE FUNCTION ScaleTransform (BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' * Creates a Graphics object that is associated with a specified device context.
    ' When you use these constructors to create a Graphics object, make sure that the Graphics
    ' object is deleted or goes out of scope before the device context is released.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphics (BYVAL hdc AS HDC)
       SetLastError(GdipCreateFromHDC(hdc, @m_Graphics))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphics (BYVAL hdc AS HDC, BYVAL hDevice AS HANDLE)
       SetLastError(GdipCreateFromHDC2(hdc, hDevice, @m_Graphics))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusGraphics
       IF m_Graphics THEN SetLastError(GdipDeleteGraphics(m_Graphics))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpGraphics object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF graphics AS GdiPlusGraphics) AS GpGraphics PTR
       RETURN graphics.m_Graphics
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpGraphics object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusGraphics.@ () AS GpGraphics PTR PTR
       RETURN @m_Graphics
    END OPERATOR
    ' ========================================================================================

    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusGraphics.CAST () AS GpGraphics PTR
       RETURN m_Graphics
    END OPERATOR
    ' ========================================================================================

    ' ========================================================================================
    ' Get the DPI scaling
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.DpiX () AS SINGLE
       DIM _dpiX AS SINGLE
       SetLastError(GdipGetDpiX(m_Graphics, @_dpiX))
       RETURN _dpiX
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.DpiY () AS SINGLE
       DIM _dpiY AS SINGLE
       SetLastError(GdipGetDpiX(m_Graphics, @_dpiY))
       RETURN _dpiY
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    ' Get the DPI scaling ratio
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.DpiRatio () AS SINGLE
       DIM _dpiX AS SINGLE
       SetLastError(GdipGetDpiX(m_Graphics, @_dpiX))
       DIM rxRatio AS SINGLE = _dpiX / 96
       RETURN rxRatio
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.DpiRatioX () AS SINGLE
       DIM _dpiX AS SINGLE
       SetLastError(GdipGetDpiX(m_Graphics, @_dpiX))
       DIM rxRatio AS SINGLE = _dpiX / 96
       RETURN rxRatio
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.DpiRatioY () AS SINGLE
       DIM _dpiY AS SINGLE
       SetLastError(GdipGetDpiY(m_Graphics, @_dpiY))
       DIM ryRatio AS SINGLE = _dpiY / 96
       RETURN ryRatio
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    ' Updates this Graphic object's current transformation matrix with the product of itself
    ' and a scaling matrix.
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.ScaleTransform (BYVAL sx AS SINGLE, BYVAL sy AS SINGLE, BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
       RETURN GdipScaleWorldTransform(m_Graphics, sx, sy, order)
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.ScaleTransform (BYVAL dpiRatio_ AS SINGLE, BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
       RETURN GdipScaleWorldTransform(m_Graphics, dpiRatio, dpiRatio_, order)
    END FUNCTION
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE FUNCTION GdiPlusGraphics.ScaleTransform (BYVAL order AS MatrixOrder = MatrixOrderPrepend) AS GpStatus
       DIM _dpiX AS SINGLE
       GdipGetDpiX(m_Graphics, @_dpiX)
       DIM rxRatio AS SINGLE = _dpiX / 96
       DIM _dpiY AS SINGLE
       GdipGetDpiY(m_Graphics, @_dpiY)
       DIM ryRatio AS SINGLE = _dpiY / 96
       RETURN GdipScaleWorldTransform(m_Graphics, rxRatio, ryRatio, order)
    END FUNCTION
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example draws an image with its upper-left corner at (10, 10).
    ' ========================================================================================
    SUB Example_DrawImage (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create the Image object
       DIM image AS GdiPlusImage = "climber.jpg"
       image.SetResolution(graphics)

       ' // Draw the image
       GdipDrawImage(graphics, image, 10, 10)

    END SUB
    ' ========================================================================================

### GdiPlusFont

A Font object is used when drawing strings.

    ' ========================================================================================
    TYPE GdiPlusFont
    Public:
       m_Font AS GpFont PTR
       DECLARE CONSTRUCTOR (BYVAL font AS GpFont PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL hdc AS HDC)
       DECLARE CONSTRUCTOR (BYVAL hdc AS HDC, BYVAL plogfont AS LOGFONTA PTR)
       DECLARE CONSTRUCTOR (BYVAL hdc AS HDC, BYVAL plogfont AS LOGFONTW PTR)
       DECLARE CONSTRUCTOR (BYVAL fontFamily AS GpFontFamily PTR, BYVAL emSize AS SINGLE, BYVAL nStyle AS INT_ = 0, BYVAL nUnit AS GpUnit = 0)
       DECLARE CONSTRUCTOR (BYVAL pwszFamilyName AS WSTRING PTR, BYVAL emSize AS SINGLE, BYVAL nStyle AS INT_ = 0, BYVAL nUnit AS GpUnit = 0, BYVAL fontCollection AS GpFontCollection PTR = NULL)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpFont PTR PTR
       DECLARE OPERATOR CAST () AS GpFont PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates and initializes a Font object from another Font object.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL font AS GpFont PTR = NULL)
       IF font THEN GdipCloneFont(font, @m_Font)
    END CONSTRUCTOR
    ' =====================================================================================

    ' ========================================================================================
    ' Creates a Font object based on the GDI font object that is currently selected into a
    ' specified device context. This constructor is provided for compatibility with GDI.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL hdc AS HDC)
       SetLastError(GdipCreateFontFromDC(hdc, @m_Font))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Font object directly from a Windows Graphics Device Interface (GDI) logical
    ' font. The GDI logical font is a LOGFONTA structure, which is the one-byte character
    ' version of a logical font. This constructor is provided for compatibility with GDI.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL hdc AS HDC, BYVAL plogfont AS LOGFONTA PTR)
       IF plogfont <> NULL THEN
          SetLastError(GdipCreateFontFromLogfontA(hdc, plogfont, @m_Font))
       ELSE
          SetLastError(GdipCreateFontFromDC(hdc, @m_Font))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Font object directly from a Windows Graphics Device Interface (GDI) logical
    ' font. The GDI logical font is a LOGFONTW structure, which is the one-byte character
    ' version of a logical font. This constructor is provided for compatibility with GDI.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL hdc AS HDC, BYVAL plogfont AS LOGFONTW PTR)
       IF plogfont <> NULL THEN
          SetLastError(GdipCreateFontFromLogfontW(hdc, plogfont, @m_Font))
       ELSE
          SetLastError(GdipCreateFontFromDC(hdc, @m_Font))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Font object based on a FontFamily object, a size, a font style, and a unit of measurement.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL fontFamily AS GpFontFamily PTR, BYVAL emSize AS SINGLE, BYVAL nStyle AS INT_ = 0, BYVAL nUnit AS GpUnit = 0)
       SetLastError(GdipCreateFont(fontFamily, emSize, nStyle, nUnit, @m_Font))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates a Font object based on a font family, a size, a font style, a unit of
    ' measurement, and a FontCollection object.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFont (BYVAL pwszFamilyName AS WSTRING PTR, BYVAL emSize AS SINGLE, BYVAL nStyle AS INT_ = 0, BYVAL nUnit AS GpUnit = 0, BYVAL fontCollection AS GpFontCollection PTR = NULL)
       DIM fontFamily AS GpFontFamily PTR
       SetLastError(GdipCreateFontFamilyFromName(pwszFamilyName, fontCollection, @fontFamily))
       IF fontFamily THEN
          SetLastError GdipCreateFont(fontFamily, emSize, nStyle, nUnit, @m_Font)
       ELSE
          SetLastError(GdipGetGenericFontFamilySansSerif(@fontFamily))
          SetLastError(GdipCreateFont(fontFamily, emSize, nStyle, nUnit, @m_Font))
       END IF
       IF fontFamily THEN GdipDeleteFontFamily(fontFamily)
    END CONSTRUCTOR
    ' ========================================================================================
    ' ===========================================================================================
    ' Cleanup
    ' ===========================================================================================
    PRIVATE DESTRUCTOR GdiPlusFont
       IF m_Font THEN GdipDeleteFont(m_Font)
    END DESTRUCTOR
    ' ===========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpFont object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF font AS GdiPlusFont) AS GpFont PTR
       RETURN font.m_Font
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpFont object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusFont.@ () AS GpFont PTR PTR
       RETURN @m_Font
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusFont.CAST () AS GpFont PTR
       RETURN m_Font
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a Font object and then uses it to draw text.
    ' ========================================================================================
    SUB Example_CreateFont (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create the font
       DIM fontFamily AS GdiPlusFontFamily = "Arial"
       DIM font AS GdiPlusFont = GdiPlusFont(*fontFamily, AfxGdipPointsToPixels(18, TRUE), FontStyleRegular, UnitPixel)

       ' // Create a solid brush
       DIM solidBrush AS GdiPlusSolidBrush = ARGB_BLUE

       ' // Draw a string
       DIM rcf AS GpRectF = (30, 30, 0, 0)
       DIM wszText AS WSTRING * 64 = "Text drawn using an Arial font"
       GdipDrawString(graphics, wszText, LEN(wszText), font, @rcf, NULL, solidBrush)

    END SUB
    ' ========================================================================================

### GdiPlusFontFamily

A font family is a group of fonts that have the same typeface but different styles.

    ' ========================================================================================
    TYPE GdiPlusFontFamily
    Public:
       m_FontFamily AS GpFontFamily PTR
       DECLARE CONSTRUCTOR (BYVAL fontFamily AS GpFontFamily PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL pwszName AS WSTRING PTR, BYVAL fontCollection AS GpFontCollection PTR = NULL)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpFontFamily PTR PTR
       DECLARE OPERATOR CAST () AS GpFontFamily PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Creates and initializes a FontFamily object from another FontFamily object.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFontFamily (BYVAL fontFamily AS GpFontFamily PTR = NULL)
       IF fontFamily THEN SetLastError(GdipCloneFontFamily(fontFamily, @m_FontFamily))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Creates a FontFamily object based on a specified font collection.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusFontFamily (BYVAL pwszName AS WSTRING PTR, BYVAL fontCollection AS GpFontCollection PTR = NULL)
       SetLastError(GdipCreateFontFamilyFromName(pwszName, fontCollection, @m_FontFamily))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Cleanup
    ' =====================================================================================
    PRIVATE DESTRUCTOR GdiPlusFontFamily
       IF m_FontFamily THEN GdipDeleteFontFamily(m_FontFamily)
    END DESTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpFontFamily object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF fontFamily AS GdiPlusFontFamily) AS GpFontFamily PTR
       RETURN fontFamily.m_FontFamily
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpFontFamily object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusFontFamily.@ () AS GpFontFamily PTR PTR
       RETURN @m_FontFamily
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusFontFamily.CAST () AS GpFontFamily PTR
       RETURN m_FontFamily
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a Font object from a font family and then uses it to draw text.
    ' ========================================================================================
    SUB Example_CreateFontFromFamily (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create the font
       DIM fontFamily AS GdiPlusFontFamily = "Arial"
       DIM font AS GdiPlusFont = GdiPlusFont(*fontFamily, AfxGdipPointsToPixels(14, TRUE), FontStyleRegular, UnitPixel)

       ' // Create a solid brush
       DIM solidBrush AS GdiPlusSolidBrush = ARGB_BLUE

       ' // Draw a string
       DIM rcf AS GpRectF = (30, 30, 0, 0)
       DIM wszText AS WSTRING * 64 = "This is a Font created from a FontFamily"
       GdipDrawString(graphics, wszText, LEN(wszText), font, @rcf, NULL, solidBrush)

    END SUB
    ' ========================================================================================

### GdiPlusGraphicsPath

A GraphicsPath object stores a sequence of lines, curves, and shapes. You can draw the entire sequence by calling the GdipDrawPath function. You can partition the sequence of lines, curves, and shapes into figures, and with the help of the PathIterator functions, you can draw selected figures. You can also place markers in the sequence, so that you can draw selected portions of the path.

    ' ========================================================================================
    TYPE GdiPlusGraphicsPath
    Public:
       m_Path AS GpPath PTR
       DECLARE CONSTRUCTOR (BYVAL path AS GpPath PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL nFillMode AS FillMode)
       DECLARE CONSTRUCTOR (BYVAL pts AS GpPointF PTR, BYVAL types AS BYTE PTR, BYVAL nCount AS LONG, BYVAL nFillMode AS FillMode = FillModeAlternate)
       DECLARE CONSTRUCTOR (BYVAL pts AS GpPoint PTR, BYVAL types AS BYTE PTR, BYVAL nCount AS LONG, BYVAL nFillMode AS FillMode = FillModeAlternate)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpPath PTR PTR
       DECLARE OPERATOR CAST () AS GpPath PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Constructors
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphicsPath (BYVAL path AS GpPath PTR = NULL)
       IF path THEN SetLastError(GdipClonePath(path, @m_Path))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphicsPath (BYVAL nFillMode AS FillMode)
       SetLastError(GdipCreatePath(nFillMode, @m_Path))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a GraphicsPath object based on an array of points, an array of types, and a fill mode.
    ' Default value for fillMode: FillModeAlternate(0).
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphicsPath (BYVAL pts AS GpPointF PTR, BYVAL types AS BYTE PTR, BYVAL nCount AS LONG, BYVAL nFillMode AS FillMode = FillModeAlternate)
       SetLastError(GdipCreatePath2(pts, types, nCount, nFillmode, @m_Path))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusGraphicsPath (BYVAL pts AS GpPoint PTR, BYVAL types AS BYTE PTR, BYVAL nCount AS LONG, BYVAL nFillMode AS FillMode = FillModeAlternate)
       SetLastError(GdipCreatePath2I(pts, types, nCount, nFillmode, @m_Path))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Cleanup
    ' =====================================================================================
    PRIVATE DESTRUCTOR GdiPlusGraphicsPath
       IF m_Path THEN GdipDeletePath(m_Path)
    END DESTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpGraphicsPath object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF path AS GdiPlusGraphicsPath) AS GpPath PTR
       RETURN path.m_Path
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpGraphicsPath object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusGraphicsPath.@ () AS GpPath PTR PTR
       RETURN @m_Path
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusGraphicsPath.CAST () AS GpPath PTR
       RETURN m_Path
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' This example creates a GraphicsPath and adds a shape to it.
    ' ========================================================================================
    SUB Example_CreatePath (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create GraphicsPath
       DIM path AS GdiPlusGraphicsPath = FillModeAlternate

       ' // Add a shape to the path
       GdipAddPathEllipse(path, 120, 80, 150, 100)

       ' // Create pen
       DIM pen AS GdiPlusPen = GdiPlusPen(ARGB_MIDNIGHTBLUE, 2, UnitWorld)

       ' // Draw path
       GdipDrawPath(graphics, pen, path)

    END SUB
    ' ========================================================================================

### GdiPlusMatrix

A Matrix object represents a 3 ×3 matrix that, in turn, represents an affine transformation. A Matrix object stores only six of the 9 numbers in a 3 ×3 matrix because all 3 ×3 matrices that represent affine transformations have the same third column (0, 0, 1).

    ' ========================================================================================
    TYPE GdiPlusMatrix
    Public:
       m_Matrix AS GpMatrix PTR
       DECLARE CONSTRUCTOR (BYVAL matrix AS GpMatrix PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL m11 AS SINGLE, BYVAL m12 AS SINGLE, BYVAL m21 AS SINGLE, BYVAL m22 AS SINGLE, BYVAL dx AS SINGLE, BYVAL dy AS SINGLE)
       DECLARE CONSTRUCTOR (BYVAL rcf AS GpRectF PTR, BYVAL dstplg AS GpPointF PTR)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRect PTR, BYVAL dstplg AS GpPoint PTR)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR CAST () AS GpMatrix PTR
       DECLARE OPERATOR @ () AS GpMatrix PTR PTR
    END TYPE
    ' ========================================================================================

    ' ========================================================================================
    ' Constructors
    ' ========================================================================================
    ' ========================================================================================
    ' Creates and initializes a Matrix object from another Matrix object
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusMatrix (BYVAL matrix AS GpMatrix PTR = NULL)
       IF matrix THEN
          SetLastError(GdipCloneMatrix(matrix, @m_Matrix))
       ELSE
          SetLastError(GdipCreateMatrix(@m_Matrix))
       END IF
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Creates and initializes a Matrix object based on six numbers that define an affine transformation.
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusMatrix (BYVAL m11 AS SINGLE, BYVAL m12 AS SINGLE, BYVAL m21 AS SINGLE, BYVAL m22 AS SINGLE, BYVAL dx AS SINGLE, BYVAL dy AS SINGLE)
       SetLastError(GdipCreateMatrix2(m11, m12, m21, m22, dx, dy, @m_Matrix))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a Matrix object based on a rectangle and a point.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusMatrix (BYVAL rcf AS GpRectF PTR, BYVAL dstplg AS GpPointF PTR)
       SetLastError(GdipCreateMatrix3(rcf, dstplg, @m_Matrix))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a Matrix object based on a rectangle and a point.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusMatrix (BYVAL rc AS GpRect PTR, BYVAL dstplg AS GpPoint PTR)
       SetLastError(GdipCreateMatrix3I(rc, dstplg, @m_Matrix))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusMatrix
       IF m_Matrix THEN GdipDeleteMatrix(m_Matrix)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpMatrix object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF matrix AS GdiPlusMatrix) AS GpMatrix PTR
       RETURN matrix.m_Matrix
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusMatrix.CAST () AS GpMatrix PTR
       RETURN m_Matrix
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpMatrix object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusMatrix.@ () AS GpMatrix PTR PTR
       RETURN @m_Matrix
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' Creates a transformation matrix based on a source rectangle and a destination parallelogram.
    ' This is especially useful for mapping one shape onto another—like skewing, rotating, or
    ' stretching a rectangle into a custom shape.
    ' ========================================================================================
    SUB Example_CreateMatrix3 (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Define source rectangle
       DIM srcRect AS GpRectF = (0, 0, 100, 60)

       ' // Define destination parallelogram points
       DIM destPoints(0 TO 2) AS GpPointF
       destPoints(0).x = 50  : destPoints(0).y = 50      ' Top-left
       destPoints(1).x = 160 : destPoints(1).y = 40      ' Top-right
       destPoints(2).x = 60  : destPoints(2).y = 120     ' Bottom-left

       ' // Create matrix to map srcRect to dstPoints
       DIM matrix AS GdiPlusMatrix = GdiPlusMatrix(@srcRect, @destPoints(0))

       ' // Apply matrix to graphics
       GdipSetWorldTransform(graphics, matrix)

       ' // Create pen
       DIM pen AS GdiPlusPen = GdiPlusPen(ARGB_RED, 2 * graphics.dpiRatio, UnitPixel)

       ' // Draw transformed rectangle
       GdipScaleWorldTransform(graphics, graphics.dpiRatioX, graphics.dpiRatioY, MatrixOrderPrepend)
       GdipDrawRectangle(graphics, pen, 0, 0, 100, 60)

    END SUB
    ' ========================================================================================

### GdiPlusPathIterator

The PathIterator functions allow to isolate selected subsets of the path stored in a GraphicsPath object. A path consists of one or more figures. You can use a GraphicsPathIterator to isolate one or more of those figures. A path can also have markers that divide the path into sections. You can use a GraphicsPathIterator object to isolate one or more of those sections.

    ' ========================================================================================
    TYPE GdiPlusPathIterator
    Public:
       m_PathIretator AS GpPathIterator PTR
       DECLARE CONSTRUCTOR (BYVAL path AS GpPath PTR)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpPathIterator PTR PTR
       DECLARE OPERATOR CAST () AS GpPathIterator PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Creates a new CGpGraphicsPathIterator object and associates it with a CGpGraphicsPath object.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPathIterator (BYVAL path AS GpPath PTR)
       SetLasTError(GdipCreatePathIter(@m_pathIretator, path))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusPathIterator
       IF m_PathIretator THEN GdipDeletePathIter(m_PathIretator)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpPathIterator object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF pathIterator AS GdiPlusPathIterator) AS GpPathIterator PTR
       RETURN pathIterator.m_PathIretator
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpPathIterator object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPathIterator.@ () AS GpPathIterator PTR PTR
       RETURN @m_PathIretator
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPathIterator.CAST () AS GpPathIterator PTR
       RETURN m_PathIretator
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' This example demonstrates
    ' How to build a path with multiple figures.
    ' How to use PathIterator to inspect each figure’s bounds and closure status.
    ' ========================================================================================
    SUB Example_CreatePathIter (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' Create a GraphicsPath with two figures
       DIM path AS GdiPlusGraphicsPath = FillModeAlternate

       ' First figure: triangle (closed)
       GdipAddPathLine(path, 10, 10, 100, 10)
       GdipAddPathLine(path, 100, 10, 55, 80)
       GdipClosePathFigure(path)

       ' Second figure: open zigzag
       GdipStartPathFigure(path)
       GdipAddPathLine(path, 120, 10, 180, 50)
       GdipAddPathLine(path, 180, 50, 120, 90)

       ' Create PathIterator
       DIM iterator AS GdiPlusPathIterator = *path

       ' Get subpath count
       DIM subpathCount AS LONG
       GdipPathIterGetSubpathCount(iterator, @subpathCount)

       ' Create font and brush for drawing text
       DIM fontFamily AS GdiPlusFontFamily ="Arial"
       DIM font AS GdiPlusFont = GdiPlusFont(*fontFamily, AfxGdipPointsToPixels(12, TRUE), FontStyleRegular, UnitPixel)
       DIM brush AS GdiPlusSolidBrush = ARGB_BLACK

       ' Iterate through subpaths and draw info
       DIM resultCount AS LONG, startIdx AS LONG, endIdx AS LONG
       DIM isClosed AS BOOL
       DIM yOffset AS SINGLE = 10.0

       FOR i AS LONG = 1 TO subpathCount
          GdipPathIterNextSubpath(iterator, @resultCount, @startIdx, @endIdx, @isClosed)
          DIM info AS STRING
          info = "Subpath " & i & ": Start=" & startIdx & ", End=" & endIdx & ", Closed=" & IIF(isClosed, "True", "False")
          DIM layout AS GpRectF = (10 * graphics.dpiRatioX, yOffset * graphics.dpiRatioY, 300 * graphics.dpiRatioX, 20 * graphics.dpiRatioY)
          GdipDrawString(graphics, info, -1, font, @layout, NULL, brush)
          yOffset += 20.0
       NEXT

    END SUB
    ' ========================================================================================

### GdiPlusPen

A Pen object is a Microsoft Windows GDI+ object used to draw lines and curves.

    ' ========================================================================================
    TYPE GdiPlusPen
    Public:
       m_Pen AS GpPen PTR
       DECLARE CONSTRUCTOR (BYVAL pen AS GpPen PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL colour AS ARGB, BYVAL nWidth AS SINGLE = 1.0, BYVAL unit AS GpUnit = UnitWorld)
       DECLARE CONSTRUCTOR (BYVAL brush AS GpBrush PTR, BYVAL nWidth AS SINGLE, BYVAL unit AS GpUnit = UnitWorld)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpPen PTR PTR
       DECLARE OPERATOR CAST () AS GpPen PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPen (BYVAL pen AS GpPen PTR = NULL)
       IF pen THEN SetLastError(GdipClonePen(pen, @m_Pen))
    END CONSTRUCTOR
    ' =====================================================================================

    ' =====================================================================================
    ' * Creates a Pen object that uses a specified color and width.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPen (BYVAL colour AS ARGB, BYVAL nWidth AS SINGLE = 1.0, BYVAL unit AS GpUnit = UnitWorld)
       SetLastError(GdipCreatePen1(colour, nWidth, unit, @m_Pen))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a Pen object that uses the attributes of a brush and a real number to set the
    ' width of this Pen object.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusPen (BYVAL brush AS GpBrush PTR, BYVAL nWidth AS SINGLE, BYVAL unit AS GpUnit = UnitWorld)
       SetLastError(GdipCreatePen2(brush, nWidth, unit, @m_Pen))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' * Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusPen
       IF m_Pen THEN SetLastError(GdipDeletePen(m_Pen))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpPen object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF pen AS GdiPlusPen) AS GpPen PTR
       RETURN pen.m_Pen
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpPen object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPen.@ () AS GpPen PTR PTR
       RETURN @m_Pen
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusPen.CAST () AS GpPen PTR
       RETURN m_Pen
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example creates a Pen object, creates a copy of the Pen object, and then
    ' draws an ellipse using the cloned Pen object.
    ' ========================================================================================
    SUB Example_ClonePen (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a Pen
       DIM pen AS GdiPlusPen = GdiPlusPen(ARGB_RED, 4, UnitWorld)
       ' // Clone it
       DIM clonedPen AS GdiPlusPen = *pen

       ' // Draw a rectangle using the cloned Pen object.
       GdipDrawRectangleI(graphics, clonedPen, 10, 10, 100, 50)

    END SUB
    ' ========================================================================================

### GdiPlusRegion

A Region describes an area of the display surface. The area can be any shape. In other words, the boundary of the area can be a combination of curved and straight lines. Regions can also be created from the interiors of rectangles, paths, or a combination of these. Regions are used in clipping and hit-testing operations.

    ' ========================================================================================
    TYPE GdiPlusRegion
    Public:
       m_Region AS GpRegion PTR
       DECLARE CONSTRUCTOR (BYVAL region AS GpRegion PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL rcf AS GpRectF PTR)
       DECLARE CONSTRUCTOR (BYVAL rc AS GpRect PTR)
       DECLARE CONSTRUCTOR (BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL nWidth AS SINGLE, BYVAL nHeight AS SINGLE)
       DECLARE CONSTRUCTOR (BYVAL x AS INT_, BYVAL y AS INT_, BYVAL nWidth AS INT_, BYVAL nHeight AS INT_)
       DECLARE CONSTRUCTOR (BYVAL regionData AS BYTE PTR, BYVAL nSize AS LONG)
       DECLARE CONSTRUCTOR (BYVAL hRgn AS HRGN)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpRegion PTR PTR
       DECLARE OPERATOR CAST () AS GpRegion PTR
       DECLARE SUB FromPath (BYVAL pah AS GpPath PTR)
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Default constructor
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL region AS GpRegion PTR = NULL)
       IF region THEN
          SetLastError(GdipCloneRegion(region, @m_Region))
       ELSE
          SetLastError(GdipCreateRegion(@m_Region))
       END IF
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL rcf AS GpRectF PTR)
       SetLastError(GdipCreateRegionRect(rcf, @m_Region))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL rc AS GpRect PTR)
       SetLastError(GdipCreateRegionRectI(rc, @m_Region))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL x AS SINGLE, BYVAL y AS SINGLE, BYVAL nWidth AS SINGLE, BYVAL nHeight AS SINGLE)
       DIM rcf AS GpRectF : rcf.x = x : rcf.y = y : rcf.Width = nwidth : rcf.Height = nHeight
       SetLastError(GdipCreateRegionRect(@rcf, @m_Region))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL x AS INT_, BYVAL y AS INT_, BYVAL nWidth AS INT_, BYVAL nHeight AS INT_)
       DIM rc AS GpRect : rc.x = x : rc.y = y : rc.Width = nwidth : rc.Height = nHeight
       SetLastError(GdipCreateRegionRectI(@rc, @m_Region))
    END CONSTRUCTOR
    ' ========================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL regionData AS BYTE PTR, BYVAL nSize AS LONG)
       SetLastError(GdipCreateRegionRgnData(regionData, nSize, @m_Region))
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusRegion (BYVAL hRgn AS HRGN)
       SetLastError(GdipCreateRegionHrgn(hRgn, @m_Region))
    END CONSTRUCTOR
    ' =====================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusRegion
       IF m_Region THEN GdipDeleteRegion(m_Region)
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpRegion object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF region AS GdiPlusRegion) AS GpRegion PTR
       RETURN region.m_Region
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpRegion object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusRegion.@ () AS GpRegion PTR PTR
       RETURN @m_Region
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusRegion.CAST () AS GpRegion PTR
       RETURN m_Region
    END OPERATOR
    ' ========================================================================================
    ' =====================================================================================
    ' Creates a region from a path
    ' A separate function is needed because using a constructor conflicts with the default one.
    ' =====================================================================================
    PRIVATE SUB GdiPlusRegion.FromPath (BYVAL path AS GpPath PTR)
       SetLastError(GdipCreateRegionPath(path, @m_Region))
    END SUB
    ' =====================================================================================

#### Example

    ' ========================================================================================
    ' Creates a region that is identical to the region that is specified by a handle to a
    ' Microsoft Windows Graphics Device Interface (GDI) region.
    ' ========================================================================================
    SUB Example_CreateRegionHrgn (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create a simple GDI region (an ellipse)
       DIM hRgn AS HRGN = CreateEllipticRgn(50, 50, 200, 150)

       ' // Convert the GDI region to a GDI+ region
       DIM gdipRegion AS GdiPlusRegion = hRgn

       ' // Fill the GDI+ region with a brush
       DIM brush AS GdiPlusSolidBrush = ARGB_GREEN
       GdipFillRegion(graphics, brush, gdipRegion)

       ' // Cleanup
       IF hRgn THEN DeleteObject(hRgn)

    END SUB
    ' ========================================================================================

### GdiPlusStringFormat

The StringFormat functions allow to set and get text layout information (such as alignment, orientation, tab stops, and clipping) and display manipulations (such as trimming, font substitution for characters that are not supported by the requested font, and digit substitution for languages that do not use Western European digits). A StringFormat object can be passed to the GdipDrawString function to format a string.

    ' ========================================================================================
    TYPE GdiPlusStringFormat
    Public:
       m_StringFormat AS GpStringFormat PTR
       DECLARE CONSTRUCTOR (BYVAL stringFormat AS GpStringFormat PTR = NULL)
       DECLARE CONSTRUCTOR (BYVAL formatAttributes AS INT_, BYVAL language AS LANGID)
       DECLARE DESTRUCTOR
       DECLARE OPERATOR @ () AS GpStringFormat PTR PTR
       DECLARE OPERATOR CAST () AS GpStringFormat PTR
    END TYPE
    ' ========================================================================================

    ' =====================================================================================
    ' Creates and initializes a default StringFormat object or clones it from another StringFormat object.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusStringFormat (BYVAL stringFormat AS GpStringFormat PTR = NULL)
       IF stringFormat THEN
          SetLastError(GdipCloneStringFormat(stringFormat, @m_StringFormat))
       ELSE
          SetLastError(GdipCreateStringFormat(0, LANG_NEUTRAL, @m_StringFormat))
       END IF
    END CONSTRUCTOR
    ' =====================================================================================
    ' =====================================================================================
    ' Creates a StringFormat object based on string format flags and a language.
    ' =====================================================================================
    PRIVATE CONSTRUCTOR GdiPlusStringFormat (BYVAL formatFlags AS INT_ = 0, BYVAL language AS LANGID = LANG_NEUTRAL)
       SetLastError(GdipCreateStringFormat(formatFlags, language, @m_StringFormat))
    END CONSTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Cleanup
    ' ========================================================================================
    PRIVATE DESTRUCTOR GdiPlusStringFormat
       IF m_StringFormat THEN SetLastError(GdipDeleteStringFormat(m_StringFormat))
    END DESTRUCTOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns a pointer to the GpStringFormat object
    ' ========================================================================================
    PRIVATE OPERATOR * (BYREF fmt AS GdiPlusStringFormat) AS GpStringFormat PTR
       RETURN fmt.m_StringFormat
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    ' Returns the address of a pointer to the GpStringFormat object
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusStringFormat.@ () AS GpStringFormat PTR PTR
       RETURN @m_StringFormat
    END OPERATOR
    ' ========================================================================================
    ' ========================================================================================
    PRIVATE OPERATOR GdiPlusStringFormat.CAST () AS GpStringFormat PTR
       RETURN m_StringFormat
    END OPERATOR
    ' ========================================================================================

#### Example

    ' ========================================================================================
    ' The following example uses the specified formatting to draw a string in a layout rectangle.
    ' ========================================================================================
    SUB Example_CreateStringFormat (BYVAL hdc AS HDC)

       ' // Create a graphics object from the device context
       DIM graphics AS GdiPlusGraphics = hdc
       ' // Set the scale transform
       graphics.ScaleTransform

       ' // Create the font
       DIM fontFamily AS GdiPlusFontFamily ="Times New Roman"
       DIM font AS GdiPlusFont = GdiPlusFont(*fontFamily, AfxGdipPointsToPixels(16, TRUE), FontStyleRegular, UnitPixel)

       ' // Create a StringFormat object
       DIM format AS GdiPlusStringFormat = GdiPlusStringFormat(0, LANG_NEUTRAL)
       GdipSetStringFormatAlign(format, StringAlignmentCenter)

       ' // Create a solid brush
       DIM solidBrush AS GdiPlusSolidBrush = ARGB_BLACK

       ' // Draw the string
       DIM wszText AS WSTRING * 64 = "Sample text"
       DIM rcf AS GpRectF = (30, 30, 200, 25)
       GdipDrawString(graphics, wszText, LEN(wszText), font, @rcf, format, solidBrush)

       ' // Create a Pen
       DIM pen AS GdiPlusPen = GdiPlusPen(ARGB_BLACK, 3, UnitPixel)
       GdipScalePenTransform(pen, graphics.dpiRatioX, graphics.dpiRatioY, MatrixOrderPrepend)

       ' // Draw a rectangle
       GdipDrawRectangle(graphics, *pen, rcf.x, rcf.y, rcf.Width, rcf.Height)

    END SUB
    ' ========================================================================================