Render to a GDI Surface

In some cases, you may want to be able to display DirectWrite text on a GDI surface. The IDWriteBitmapRenderTarget interface encapsulates a bitmap and device context to render text onto. You create an IDWriteBitmapRenderTarget by using the IDWriteGdiInterop::CreateBitmapRenderTarget method, as shown in the following code.

if (SUCCEEDED(hr))
{
    hr = g_pGdiInterop->CreateBitmapRenderTarget(hdc, r.right, r.bottom, &g_pBitmapRenderTarget);
}

To render with an IDWriteBitmapRenderTarget, you must implement a custom text renderer callback interface derived from the IDWriteTextRenderer interface. You must implement methods for drawing a glyph run, underline, strikethrough, inline objects, and so on. For a complete list of the methods, see the IDWriteTextRenderer reference page. Not every method must be implemented, they can just return E_NOTIMPL, and drawing will continue.

You can then draw the text by using the IDWriteTextLayout::Draw method and passing the callback interface that you implemented as a parameter. The IDWriteTextLayout::Draw method calls the methods of the custom renderer callback you provide. The DrawGlyphRun, DrawUnderline, DrawInlineObject, and DrawStrikethrough methods perform the drawing functions.

In your implementation of DrawGlyphRun, call the IDWriteBitmapRenderTarget::DrawGlyphRun method to draw the glyphs. The rendering of the underline, strikethrough and inline objects must be done by your custom renderer.

IDWriteBitmapRenderTarget::DrawGlyphRun has an optional RECT out parameter that contains the bounds of the area where the text was drawn. You can use this information to set the bounding rectangle for the device context with the SetBoundsRect function that is provided by GDI. The following code is an example implementation of the DrawGlyphRun method of a custom renderer.

STDMETHODIMP GdiTextRenderer::DrawGlyphRun(
    __maybenull void* clientDrawingContext,
    FLOAT baselineOriginX,
    FLOAT baselineOriginY,
    DWRITE_MEASURING_MODE measuringMode,
    __in DWRITE_GLYPH_RUN const* glyphRun,
    __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
    IUnknown* clientDrawingEffect
    )
{
    HRESULT hr = S_OK;

    // Pass on the drawing call to the render target to do the real work.
    RECT dirtyRect = {0};

    hr = pRenderTarget_->DrawGlyphRun(
        baselineOriginX,
        baselineOriginY,
        measuringMode,
        glyphRun,
        pRenderingParams_,
        RGB(0,200,255),
        &dirtyRect
        );
    

    return hr;
}

The IDWriteBitmapRenderTarget interface renders to a device context (DC) in memory. You get a handle to this DC by using the IDWriteBitmapRenderTarget::GetMemoryDC method. As soon as the drawing has been performed, the memory DC of the IDWriteBitmapRenderTarget object must be copied to the destination GDI surface.

You can retrieve the bounding rectangle by using the GetBoundsRect function, then use the bounding rectangle with the BitBlt function to copy the rendered DirectWrite text from the memory DC to the GDI surface as shown in the following code.

// Transfer from DWrite's rendering target to the window.
BitBlt(
    hdc,
    0, 0,
    size.cx, size.cy,
    memoryHdc,
    0, 0, 
    SRCCOPY | NOMIRRORBITMAP
    );