Skip to content

Driver build fails with C1083 (ntddk.h not found) because WDKContentRoot defaults to C:\Program Files in 64-bit MSBuild #1430

Open

Description

@codagard

I ran into an issue where newly created driver projects (WindowsKernelModeDriver10.0) failed to build out of the box with fatal error C1083: Cannot open include file: 'ntddk.h': No such file or directory.

Along with the build error, the Driver Settings and Linker tabs were completely missing from the project property pages, and MSBuild was compiling main.c with user-mode flags (/MDd, /EHsc, /RTC1) instead of driver flags.

After digging into diagnostic MSBuild logs, I noticed that $(WDKContentRoot) was resolving to C:\Program Files\Windows Kits\10\ instead of C:\Program Files (x86)\....

What's happening

  1. On my machine (Windows 11, VS 2026 x64, WDK 10.0.28000), the WDK installer didn't populate the WDKContentRoot string under HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots. KitsRoot10 and WdkBinRootVersioned were there, but WDKContentRoot was missing.

  2. In WindowsKernelModeDriver10.0\Toolset.props, there's a fallback if that registry key isn't found:

    <WDKContentRoot Condition="'$(WDKContentRoot)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots@WDKContentRoot)</WDKContentRoot>
    <WDKContentRoot Condition="'$(WDKContentRoot)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots@WDKContentRoot)</WDKContentRoot>
    <WDKContentRoot Condition="'$(WDKContentRoot)' == ''">$(ProgramFiles)\Windows Kits\10\</WDKContentRoot>
  3. Because modern Visual Studio / MSBuild runs as a native 64-bit process, $(ProgramFiles) expands to C:\Program Files\.

  4. Later, when Toolset.targets tries to import WindowsDriver.common.targets:

    <Import Project="$(WDKContentRoot)\build\$(WDKBuildFolder)\WindowsDriver.common.targets" 
            Condition="Exists('$(WDKContentRoot)\build\$(WDKBuildFolder)\WindowsDriver.common.targets')"/>

    The Exists(...) check looks in C:\Program Files\..., fails silently, and skips importing the target file entirely. It doesn't warn or error out—it just treats the project like a regular console app and never sets up the kernel include paths.

Workaround

Setting WDKContentRoot as a system environment variable fixed the problem immediately:

[System.Environment]::SetEnvironmentVariable("WDKContentRoot", "C:\Program Files (x86)\Windows Kits\10\", [System.EnvironmentVariableTarget]::Machine)

Proposed fix

In Toolset.props, could the fallback be updated to use $(MSBuildProgramFiles32) instead of $(ProgramFiles)?

<WDKContentRoot Condition="'$(WDKContentRoot)' == ''">$(MSBuildProgramFiles32)\Windows Kits\10\</WDKContentRoot>

That way, if the installer fails to write the registry key, 64-bit MSBuild still looks in Program Files (x86) where the kits are actually installed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions