From e35351e62f9df5e7babcde2120c9bf78730da800 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:56:28 -0400 Subject: [PATCH] build(windows): Package Windows driver validation tools Enable BUILD_EXAMPLES for Windows driver CI/docs and build the catalog together with `gamepad_adapter` so packaging always includes the validation binary. Update Windows packaging to install reviewer-facing test scripts plus `tools/windows/gamepad_adapter.exe`, and fail configuration if examples are disabled during driver packaging. Also set MSVC static runtime on the core library and example adapters when building the Windows driver to keep runtime linkage consistent for installer artifacts. --- .github/workflows/ci.yml | 4 +- README.md | 33 ++++++++----- cmake/packaging/windows.cmake | 12 +++++ docs/store-review-validation.md | 88 +++++++++++++++++++++++++++++++++ examples/CMakeLists.txt | 5 ++ src/CMakeLists.txt | 4 ++ 6 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 docs/store-review-validation.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a7185c..dd8cb1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -454,7 +454,7 @@ jobs: $certificatePath = Join-Path $env:GITHUB_WORKSPACE "cmake-build-driver\certificates\libvirtualhid-ci-test.cer" cmake ` -DBUILD_DOCS=OFF ` - -DBUILD_EXAMPLES=OFF ` + -DBUILD_EXAMPLES=ON ` -DBUILD_TESTS=OFF ` -DLIBVIRTUALHID_BUILD_WINDOWS_DRIVER=ON ` -DLIBVIRTUALHID_ENABLE_PACKAGING=ON ` @@ -469,7 +469,7 @@ jobs: run: >- cmake --build cmake-build-driver --config ${{ env.DRIVER_BUILD_CONFIG }} - --target libvirtualhid_windows_catalog + --target libvirtualhid_windows_catalog gamepad_adapter --parallel 2 - name: Validate Azure signing configuration diff --git a/README.md b/README.md index ec98ee1..316cc02 100644 --- a/README.md +++ b/README.md @@ -176,9 +176,9 @@ Build the UMDF package separately with the Microsoft driver toolchain: ```powershell cmake -S . -B cmake-build-windows-driver -G "Visual Studio 17 2022" -A x64 ` -DLIBVIRTUALHID_BUILD_WINDOWS_DRIVER=ON -DLIBVIRTUALHID_ENABLE_PACKAGING=ON ` - -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF -cmake --build cmake-build-windows-driver --config Release --target libvirtualhid_umdf -cmake --build cmake-build-windows-driver --config Release --target libvirtualhid_windows_catalog + -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=ON +cmake --build cmake-build-windows-driver --config Release ` + --target libvirtualhid_windows_catalog gamepad_adapter cpack -G WIX -C Release --config .\cmake-build-windows-driver\CPackConfig.cmake ``` @@ -189,15 +189,22 @@ powershell -ExecutionPolicy Bypass -File .\scripts\windows\install-driver.ps1 ` -InfPath .\cmake-build-windows-driver\src\platform\windows\driver\package\Release\libvirtualhid.inf ` -LogPath .\cmake-build-windows-driver\install-driver.log powershell -ExecutionPolicy Bypass -File .\scripts\windows\test-installed-driver.ps1 ` - -GamepadAdapterPath .\cmake-build-ci\examples\Debug\gamepad_adapter.exe ` + -GamepadAdapterPath .\cmake-build-windows-driver\examples\Release\gamepad_adapter.exe ` -GamepadProfile xseries powershell -ExecutionPolicy Bypass -File .\scripts\windows\test-browser-gamepad.ps1 ` - -GamepadAdapterPath .\cmake-build-ci\examples\Debug\gamepad_adapter.exe ` + -GamepadAdapterPath .\cmake-build-windows-driver\examples\Release\gamepad_adapter.exe ` -GamepadProfile xseries powershell -ExecutionPolicy Bypass -File .\scripts\windows\uninstall-driver.ps1 ` -Force -RemoveCertificateSubject "CN=libvirtualhid CI Test Driver Signing" ``` +The WiX driver installer also installs validation files under the default +install root, `C:\Program Files\libvirtualhid`: + +- `scripts\windows\test-installed-driver.ps1` +- `scripts\windows\test-browser-gamepad.ps1` +- `tools\windows\gamepad_adapter.exe` + The helper stages the INF with `pnputil`, updates an existing `ROOT\LIBVIRTUALHID` device when present, and creates that root-enumerated device when it is missing. It uses SetupAPI/NewDev directly so MSI installs do @@ -213,22 +220,22 @@ if `\\.\LibVirtualHid` cannot be opened, or if a held gamepad adapter instance does not produce a started HID child device such as `HID\VID_045E&PID_0B12&IG_00` or an Xbox Series-compatible HID child such as `HID\VID_045E&PID_02FF&IG_00`. That check is also run by the Windows CI legs -for every Windows UMDF/VHF-supported `gamepad_adapter` profile -after installing the Windows Driver Installer artifact. The browser helper is for manual +for every Windows UMDF/VHF-supported `gamepad_adapter` profile after installing +the Windows Driver Installer artifact. The browser helper is for manual diagnostics: it launches a normal desktop Edge or Chrome instance at `https://hardwaretester.com/gamepad`, holds a virtual gamepad, and fails if the browser Gamepad API does not report a controller matching the selected profile or does not observe changing button and axis input. For manual browser validation, run the browser helper with `-KeepBrowserOpen`, or run -`examples/gamepad_adapter xseries --hold-seconds 60`, then open +`tools\windows\gamepad_adapter.exe xseries --hold-seconds 60`, then open `https://hardwaretester.com/gamepad` in a normal desktop browser and press one of the held virtual buttons if the browser needs a gamepad activation event. -The driver binary is a UMDF DLL installed through the Windows Driver Store, not -a libvirtualhid `.sys` copied into `C:\Windows\System32\drivers`. Windows still -uses its built-in `WUDFRd.sys` and VHF components under `System32\drivers`; the -libvirtualhid-specific sign that installation completed is the -`ROOT\LIBVIRTUALHID` device and the `\\.\LibVirtualHid` control device. The INF +The driver binary is a user-mode UMDF DLL installed through the Windows Driver +Store, not a libvirtualhid `.sys` copied into `C:\Windows\System32\drivers`. +Windows still uses its built-in `WUDFRd.sys` and VHF components under +`System32\drivers`; the libvirtualhid-specific sign that installation completed +is the `ROOT\LIBVIRTUALHID` device and the `\\.\LibVirtualHid` control device. The INF includes the built-in `WUDFRd` install sections for the root `System` control device, appends the VHF lower filter, sets `VhfMode=1` for the UMDF VHF source stack, grants non-admin user-mode clients read/write access to the control diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake index 197889a..d828f31 100644 --- a/cmake/packaging/windows.cmake +++ b/cmake/packaging/windows.cmake @@ -16,10 +16,22 @@ set(LIBVIRTUALHID_DRIVER_TEST_CERTIFICATE "" CACHE FILEPATH install(FILES "${PROJECT_SOURCE_DIR}/scripts/windows/libvirtualhid-driver-common.ps1" "${PROJECT_SOURCE_DIR}/scripts/windows/install-driver.ps1" + "${PROJECT_SOURCE_DIR}/scripts/windows/test-browser-gamepad.ps1" + "${PROJECT_SOURCE_DIR}/scripts/windows/test-installed-driver.ps1" "${PROJECT_SOURCE_DIR}/scripts/windows/uninstall-driver.ps1" DESTINATION "scripts/windows" COMPONENT driver) +if(NOT TARGET gamepad_adapter) + message(FATAL_ERROR + "The Windows driver installer requires BUILD_EXAMPLES=ON so the " + "gamepad_adapter validation tool can be packaged.") +endif() + +install(TARGETS gamepad_adapter + RUNTIME DESTINATION "tools/windows" + COMPONENT driver) + if(LIBVIRTUALHID_DRIVER_TEST_CERTIFICATE) install(FILES "${LIBVIRTUALHID_DRIVER_TEST_CERTIFICATE}" DESTINATION "certificates" diff --git a/docs/store-review-validation.md b/docs/store-review-validation.md new file mode 100644 index 0000000..14a9a04 --- /dev/null +++ b/docs/store-review-validation.md @@ -0,0 +1,88 @@ +# Microsoft Store Review Validation + +These instructions are intended for Microsoft Store certification review of the +libvirtualhid Windows driver installer. The reviewer does not need to build the +project, install the Windows SDK/WDK, or write a consumer application. + +The Windows package installs a user-mode UMDF/VHF virtual HID driver. The +libvirtualhid-specific driver binary is a UMDF DLL installed through the Windows +Driver Store. It is not a kernel-mode `.sys` driver. + +## Submission Notes + +Paste this into the Partner Center certification notes field: + +```text +This package installs the libvirtualhid Windows user-mode UMDF/VHF virtual HID +driver. It has no standalone end-user UI; applications consume it through the +libvirtualhid client API. + +A prebuilt validation tool and PowerShell validation scripts are installed by +the MSI so no programming, SDK setup, or driver build environment is required. +Please install the released, production-signed MSI, then run the validation +commands below from PowerShell. + +Default install root: +C:\Program Files\libvirtualhid + +Installed validation files: +C:\Program Files\libvirtualhid\scripts\windows\test-installed-driver.ps1 +C:\Program Files\libvirtualhid\scripts\windows\test-browser-gamepad.ps1 +C:\Program Files\libvirtualhid\tools\windows\gamepad_adapter.exe + +Required validation: +$installRoot = Join-Path $env:ProgramFiles "libvirtualhid" +powershell -ExecutionPolicy Bypass -File "$installRoot\scripts\windows\test-installed-driver.ps1" ` + -GamepadAdapterPath "$installRoot\tools\windows\gamepad_adapter.exe" ` + -GamepadProfile xseries ` + -Verbose + +Expected result: +- The command exits successfully. +- The ROOT\LIBVIRTUALHID control device reports Status: Started. +- The \\.\LibVirtualHid control device opens successfully. +- A virtual HID gamepad child device starts, matching either + HID\VID_045E&PID_0B12&IG_00 or HID\VID_045E&PID_02FF&IG_00. + +Optional browser validation: +$installRoot = Join-Path $env:ProgramFiles "libvirtualhid" +powershell -ExecutionPolicy Bypass -File "$installRoot\scripts\windows\test-browser-gamepad.ps1" ` + -GamepadAdapterPath "$installRoot\tools\windows\gamepad_adapter.exe" ` + -GamepadProfile xseries ` + -KeepBrowserOpen + +Expected result: +- Microsoft Edge or Google Chrome opens a gamepad test page. +- The browser Gamepad API sees an Xbox-compatible controller. +- Button and axis values change while the validation adapter is running. + +The installed gamepad_adapter.exe is built with the static MSVC runtime, so it +does not require the Visual C++ Redistributable to be installed separately. +``` + +## Manual Review Steps + +1. Install the released, production-signed + `libvirtualhid-Windows-Driver-installer.msi`. +2. Reboot only if Windows reports that a reboot is required. +3. Open PowerShell. +4. Run the required validation command from the submission notes. +5. Optionally run the browser validation command. + +If the default install location was changed during MSI installation, replace +`$env:ProgramFiles\libvirtualhid` with the selected install directory. + +The MSI writes the driver-install transcript to: + +```text +C:\ProgramData\libvirtualhid\install-driver.log +``` + +## Scope Notes + +The `x360` profile is not used for Store review. The Windows UMDF/VHF backend is +HID-only and intentionally does not emulate the Xbox 360 XUSB stack. + +The reviewer-visible success signal is the installed `ROOT\LIBVIRTUALHID` +control device, the `\\.\LibVirtualHid` control path, and a started HID gamepad +child device while `gamepad_adapter.exe` is running. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b560a9f..a17e05b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,5 +12,10 @@ target_link_libraries(keyboard_mouse_adapter PRIVATE libvirtualhid::libvirtualhid) +if(MSVC AND LIBVIRTUALHID_BUILD_WINDOWS_DRIVER) + set_target_properties(gamepad_adapter keyboard_mouse_adapter PROPERTIES + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() + libvirtualhid_copy_mingw_runtime(gamepad_adapter) libvirtualhid_copy_mingw_runtime(keyboard_mouse_adapter) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index acccf7f..ca21f0e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,6 +78,10 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) set_target_properties(${PROJECT_NAME} PROPERTIES EXPORT_NAME libvirtualhid OUTPUT_NAME virtualhid) +if(MSVC AND LIBVIRTUALHID_BUILD_WINDOWS_DRIVER) + set_property(TARGET ${PROJECT_NAME} PROPERTY + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +endif() if(MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /W4)