dotnet/wpf · critical · DllNotFoundException

dwrite.dll

Error message

dwrite.dll

What it means

DWriteLoader.LoadDWrite loads dwrite.dll and locates DWriteCreateFactory. If the library cannot be loaded, it throws DllNotFoundException("dwrite.dll") wrapping the Win32 error. DirectWrite is a Windows system component that WPF's text stack requires, so its absence is fatal at text-stack initialization.

Solutions

  1. Run on a Windows installation that includes DirectWrite (dwrite.dll in System32) — install Desktop Experience on Server SKUs
  2. Run 'sfc /scannow' or 'DISM /Online /Cleanup-Image /RestoreHealth' to repair a corrupt system copy
  3. Check that no stray dwrite.dll in the app directory or PATH shadows the system one
  4. Verify the container/CI image is a full Windows base image (e.g. servercore with the right features), not a minimal one

Example fix

// before
// app starts text stack unconditionally on a minimal container
App.Main();
// after
try
{
    App.Main();
}
catch (DllNotFoundException ex) when (ex.Message.Contains("dwrite.dll"))
{
    Console.Error.WriteLine("DirectWrite is unavailable: install a Windows image with Desktop Experience. " + ex.Message);
    return 1;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify DirectWrite is available before starting the text stack
string sys32 = Environment.GetFolderPath(Environment.SpecialFolder.System);
if (!File.Exists(Path.Combine(sys32, "dwrite.dll")))
    throw new InvalidOperationException("dwrite.dll missing — install Windows with Desktop Experience");

Type guard

static bool DirectWriteAvailable() =>
    File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "dwrite.dll"));

Try / catch

try { textStack.Initialize(); }
catch (DllNotFoundException ex) when (ex.Message.Contains("dwrite.dll"))
{
    Log.Fatal("DirectWrite unavailable: {0}. Win32 error: {1}", ex.Message, new Win32Exception().Message);
    Environment.Exit(1);
}

Prevention

When it happens

Trigger: Constructing the DirectWrite loader on a system where dwrite.dll cannot be LoadLibrary'd — missing/corrupt system DLL, a broken Windows installation, or a sandbox/containers environment without DirectWrite.

Common situations: Running WPF apps on stripped-down Windows images or Server Core without the Desktop Experience; corrupted system files; CI containers missing Graphics/Text runtime features; DLL search-path hijacking placing a bad dwrite.dll earlier on the path.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/fd4b970b2ef6ad66. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs:21

using System.ComponentModel;
using System.Runtime.InteropServices;

namespace MS.Internal.Text.TextInterface
{
    internal static unsafe class DWriteLoader
    {
        private static IntPtr _dwrite;
        private static delegate* unmanaged<int, void*, void*, int> _dwriteCreateFactory;

        internal static void LoadDWrite()
        {
            // We load dwrite here because it's cleanup logic is different from the other native dlls
            // and don't want to abstract that
            _dwrite = LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged<int, void*, void*, int> dwriteCreateFactory);

            if (_dwrite == IntPtr.Zero)
                throw new DllNotFoundException("dwrite.dll", new Win32Exception());

            if (dwriteCreateFactory == null)
                throw new InvalidOperationException();

            _dwriteCreateFactory = dwriteCreateFactory;
        }

        internal static void UnloadDWrite()
        {
            ClearDWriteCreateFactoryFunctionPointer();
        
            if (_dwrite != IntPtr.Zero)
            {
                NativeLibrary.Free(_dwrite);

                _dwrite = IntPtr.Zero;
            }
        }

View on GitHub (pinned to 81131a70a4)