Skip to content

Add WinML EP Catalog CMake sample with NuGet package integration - #593

Merged
Nick Eubanks (nieubank) merged 2 commits into
mainfrom
user/nieubank/winmlepcatalog_vcpkg
Mar 21, 2026
Merged

Nick Eubanks (nieubank) merged 2 commits into
mainfrom
user/nieubank/winmlepcatalog_vcpkg

Conversation

@nieubank

@nieubank Nick Eubanks (nieubank) commented Feb 7, 2026 •

Copy link
Copy Markdown
Contributor

Adds a CMake-based C++ sample demonstrating the WinML Execution Provider Catalog C API (WinMLEpCatalog*) for discovering and registering hardware-accelerated ML execution providers with ONNX Runtime.

What the sample shows:

  • Creating an EP catalog and enumerating registered execution providers
  • Inspecting provider metadata (name, version, certification status)
  • Preparing certified providers with WinMLEpEnsureReady and registering them with Ort::Env
  • Consuming the Microsoft.WindowsAppSDK.ML NuGet package from CMake with automatic .nupkg extraction at configure time
  • Deploying runtime DLLs via TARGET_RUNTIME_DLLS and an explicit WINML_DIRECTML_DLL copy for DirectML (which has no import library)

Build setup:

  • CMake 3.21+ with a single nuget preset; supports both Ninja and Visual Studio generators
  • build.ps1 helper script handles VS developer environment setup, prerequisite checks, and NuGet package resolution
  • The NuGet package is extracted directly by CMake's file(ARCHIVE_EXTRACT)

Validation:

  • Run .\build.ps1 from WinMLEpCatalog sample directory in PowerShell
  • Run output file \out\build\nuget\WinMLEpCatalogSample.exe
  • Example Output:
Windows ML Execution Provider Catalog Sample

Provider: OpenVINOExecutionProvider
  Library: C:\Program Files\WindowsApps\MicrosoftCorporationII.WinML.Intel.OpenVINO.EP.1.8_1.8.69.0_x64__8wekyb3d8bbwe\ExecutionProvider\onnxruntime_providers_openvino_plugin.dll
  Registered!

Provider: NvTensorRTRTXExecutionProvider
  Library: C:\Program Files\WindowsApps\MicrosoftCorporationII.WinML.NVIDIA.TRT-RTX.EP.1.8_1.8.24.0_x64__8wekyb3d8bbwe\ExecutionProvider\onnxruntime_providers_nv_tensorrt_rtx.dll
  Registered!

Available EP devices (8):
  - CPUExecutionProvider
  - DmlExecutionProvider
  - DmlExecutionProvider
  - OpenVINOExecutionProvider
  - OpenVINOExecutionProvider
  - OpenVINOExecutionProvider.AUTO
  - OpenVINOExecutionProvider.AUTO
  - NvTensorRTRTXExecutionProvider

Registered 2 certified provider(s).

@nieubank Nick Eubanks (nieubank) changed the title Add Windows ML EP Catalog Sample with CMake and vcpkg integration Add WinML EP Catalog CMake sample with NuGet package integration Feb 18, 2026

function Write-ErrorMessage {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor Red

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Write-Host "[ERROR] $Message" -ForegroundColor Red
Write-Error $Message

Send this to the error stream? Maybe get rid of this function and call Write-Error directly.

# Local NuGet package configuration
set(WINML_NUGET_PACKAGE "${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.WindowsAppSDK.ML.2.0.246-experimental.nupkg"
CACHE FILEPATH "Path to Microsoft.WindowsAppSDK.ML nupkg")
set(WINML_LOCAL_PACKAGES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/local_packages"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting somewhere under the CMAKE_CURRENT_BINARY_DIR or CMAKE_BINARY_DIR so that the source tree isn't touched.

if(NOT DEFINED microsoft.windows.ai.machinelearning_DIR)
if(EXISTS "${WINML_NUGET_PACKAGE}")
get_filename_component(_winml_nupkg_filename "${WINML_NUGET_PACKAGE}" NAME)
string(REGEX REPLACE "\\.nupkg$" "" _winml_nupkg_name "${_winml_nupkg_filename}")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmake_path(GET WINML_NUGET_PACKAGE STEM _winml_nupkg_filename) looks like it will handle getting just the filename without the extension. get_filename_component was superseded by the cmake_path() in 3.20 too.

if(EXISTS "${WINML_NUGET_PACKAGE}")
get_filename_component(_winml_nupkg_filename "${WINML_NUGET_PACKAGE}" NAME)
string(REGEX REPLACE "\\.nupkg$" "" _winml_nupkg_name "${_winml_nupkg_filename}")
set(_winml_extract_dir "${WINML_LOCAL_PACKAGES_DIR}/${_winml_nupkg_name}")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two could use cmake_Path(APPEND ...) to construct instead of string concatenation.

Comment on lines +63 to +68
if (FAILED(hr))
{
std::cout << " Failed to get library path\n\n";
return TRUE;
}
libraryPathUtf8.resize(used > 0 ? used - 1 : 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (FAILED(hr))
{
std::cout << " Failed to get library path\n\n";
return TRUE;
}
libraryPathUtf8.resize(used > 0 ? used - 1 : 0);
if (FAILED(hr) || used == 0)
{
std::cout << " Failed to get library path\n\n";
return TRUE;
}
libraryPathUtf8.resize(used - 1);

Minor: symmetry with the error check above and simplifies the resize call

}
}

WinMLEpCatalogRelease(catalog);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the catalog be released after the enumeration is done?


std::cout << std::format("\nRegistered {} certified provider(s).\n", ctx.registeredProviders.size());

// Unregister providers before env goes out of scope

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit more explanation about why this is needed would be helpful.
env is a C++ object, so I would expect it to automatically clean itself up.

@nieubank
Nick Eubanks (nieubank) force-pushed the user/nieubank/winmlepcatalog_vcpkg branch from ab023f5 to 94d7a15 Compare March 17, 2026 19:18
@nieubank
Nick Eubanks (nieubank) changed the base branch from release/experimental to main March 17, 2026 19:24
@nieubank
Nick Eubanks (nieubank) marked this pull request as ready for review March 19, 2026 18:45
Adds a standalone CMake sample that demonstrates the WinMLEpCatalog C API
for discovering and registering certified execution providers with ONNX
Runtime.

The build automatically restores the Microsoft.WindowsAppSDK.ML NuGet
package during CMake configure via nuget install. A local .nupkg in the
sample directory is used preferentially (for alternative version testing). All
required runtime DLLs (onnxruntime.dll, onnxruntime_providers_shared.dll,
DirectML.dll, Microsoft.Windows.AI.MachineLearning.dll) are copied to the
output directory.

The package version is controlled by a single WINML_NUGET_VERSION cache
variable (default: 1.8.2141).
@nieubank
Nick Eubanks (nieubank) force-pushed the user/nieubank/winmlepcatalog_vcpkg branch from 94d7a15 to 4576881 Compare March 20, 2026 15:46
}

if ($Generator -eq 'VisualStudio') {
$configureArgs += @('-G', 'Visual Studio 17 2022', '-A', $Platform)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this only works for VS 2022? If so, I would update the above error message to remove 'or later'.

@nieubank
Nick Eubanks (nieubank) merged commit 64eee70 into main Mar 21, 2026
4 checks passed
@nieubank
Nick Eubanks (nieubank) deleted the user/nieubank/winmlepcatalog_vcpkg branch March 21, 2026 12:25
shisan (qiutongMS) pushed a commit that referenced this pull request Aug 25, 2026
Import the CMake WinML C API sample introduced by main PR #593 and moved and stabilized by PR #643. Record its independent build boundary, provenance, and x64 validation in the reconciliation docs and matrix.

Source-commit: 64eee70
Source-commit: f37e15e

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants