diff --git a/.github/actions/winget-install/action.yml b/.github/actions/winget-install/action.yml deleted file mode 100644 index a10a986..0000000 --- a/.github/actions/winget-install/action.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "Install Winget" -description: "Install winget on windows runners since its not installed by default: https://github.com/actions/runner-images/issues/6472" -inputs: - GITHUB_TOKEN: - description: "GitHub token to execute authenticated Github API requests (for higher rate limit)" - required: true -runs: - using: "composite" - steps: - - name: Get URIs for Winget v1.8.1911 assets - shell: pwsh - run: | - $AuthenticatedHeaders = @{ "Authorization" = "Bearer ${{ inputs.GITHUB_TOKEN }}" } - - $ReleaseInfo = Invoke-RestMethod -Headers $AuthenticatedHeaders 'https://api.github.com/repos/microsoft/winget-cli/releases/164835566' - $WingetDownloadUri = $ReleaseInfo.assets.browser_download_url | Where-Object { $_.EndsWith('.msixbundle') } - $WingetLicenseDownloadUri = $ReleaseInfo.assets.browser_download_url | Where-Object { $_.EndsWith('License1.xml') } - - # Print to logs - Write-Host "WingetDownloadUri=$WingetDownloadUri" - Write-Host "WingetLicenseDownloadUri=$WingetLicenseDownloadUri" - - # Save output for next step - Write-Output "WingetDownloadUri=$WingetDownloadUri" >> $env:GITHUB_ENV - Write-Output "WingetLicenseDownloadUri=$WingetLicenseDownloadUri" >> $env:GITHUB_ENV - - - name: Download Winget Assets and Dependencies - shell: pwsh - run: | - New-Item -Type Directory $env:RUNNER_TEMP/winget-install - Invoke-WebRequest -Headers $AuthenticatedHeaders -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile $env:RUNNER_TEMP/winget-install/Microsoft.UI.Xaml.2.8.x64.appx - Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile $env:RUNNER_TEMP/winget-install/Microsoft.VCLibs.x64.14.00.Desktop.appx # Needed per https://github.com/microsoft/winget-cli/blob/21de1607ed5c90174e6bb931406975c18681a5dd/README.md?plain=1#L35C19-L35C19 - Invoke-WebRequest -Headers $AuthenticatedHeaders -Uri $env:WingetDownloadUri -OutFile $env:RUNNER_TEMP/winget-install/winget.msixbundle - Invoke-WebRequest -Headers $AuthenticatedHeaders -Uri $env:WingetLicenseDownloadUri -OutFile $env:RUNNER_TEMP/winget-install/license.xml - - - name: Start Winget Installation for all Users - shell: pwsh - run: | - Add-AppxProvisionedPackage -Online -PackagePath $env:RUNNER_TEMP/winget-install/winget.msixbundle -LicensePath $env:RUNNER_TEMP/winget-install/license.xml -DependencyPackagePath $env:RUNNER_TEMP/winget-install/Microsoft.UI.Xaml.2.8.x64.appx, $env:RUNNER_TEMP/winget-install/Microsoft.VCLibs.x64.14.00.Desktop.appx - - - name: Install Winget for Current User (for better install diagnostics) - shell: powershell - run: | - Add-AppxPackage $env:RUNNER_TEMP/winget-install/winget.msixbundle - - - name: Wait for Completion of Winget Installation - shell: pwsh - run: | - while ((Get-Command * | Select-String winget)?.ToString() -ne "winget.exe") { - Start-Sleep -Seconds 1 - } - Write-Output "Winget Version: $(winget --version)" - - - name: Install winget Powershell Module - shell: pwsh - run: Install-Module -Name Microsoft.WinGet.Client -Repository PSGallery -Force diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a97c3a7..372f896 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,6 +1,7 @@ on: push: - pull_request: + # Temporarily disable until new wdk-build version is ingested: https://github.com/microsoft/Windows-rust-driver-samples/pull/46 + # pull_request: merge_group: schedule: # Trigger a job on default branch at 4AM PST everyday - cron: "0 11 * * *" @@ -15,12 +16,12 @@ env: jobs: build: name: Build - runs-on: windows-latest + runs-on: windows-2025 strategy: fail-fast: false # Allow all matrix variants to complete even if some fail matrix: wdk: - - Microsoft.WindowsWDK.10.0.22621 # NI WDK + - 10.0.22621 # NI WDK llvm: - 17.0.6 @@ -44,30 +45,39 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 + - name: Checkout windows-drivers-rs actions + uses: actions/checkout@v4 + with: + repository: microsoft/windows-drivers-rs + ref: main + path: _temp/windows-drivers-rs + sparse-checkout: | + .github/actions + sparse-checkout-cone-mode: false + + - name: Copy actions to workspace + shell: pwsh + run: Copy-Item -Recurse -Force _temp/windows-drivers-rs/.github/actions .github/ + - name: Install Winget - uses: ./.github/actions/winget-install + uses: ./.github/actions/install-winget with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Winget PowerShell Module + shell: pwsh + run: Install-Module -Name Microsoft.WinGet.Client -Repository PSGallery -Force + - name: Install LLVM ${{ matrix.llvm }} - run: | - if ((Get-WinGetPackage -Id LLVM -Source winget -MatchOption Equals).InstalledVersion -eq '${{ matrix.llvm }}') { - Write-Host "LLVM ${{ matrix.llvm }} is already installed." - } else { - Write-Host "Installing LLVM ${{ matrix.llvm }}..." - Install-WinGetPackage -Id LLVM.LLVM -Version ${{ matrix.llvm }} -Source winget -MatchOption Equals -Mode Silent -Force - } - clang --version + uses: ./.github/actions/install-llvm + with: + version: ${{ matrix.llvm }} - name: Install WDK (${{ matrix.wdk }}) - run: | - if ((Get-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals).Id -eq '${{ matrix.wdk }}') { - Write-Host "${{ matrix.wdk }} is already installed. Attempting to update..." - Update-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } else { - Write-Host "Installing ${{ matrix.wdk }}..." - Install-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } + uses: ./.github/actions/install-wdk + with: + version: ${{ matrix.wdk }} + source: winget - name: Install Rust Toolchain (${{ matrix.rust_toolchain }}) uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/cargo-audit.yaml b/.github/workflows/cargo-audit.yaml index 63e7ff0..f55691b 100644 --- a/.github/workflows/cargo-audit.yaml +++ b/.github/workflows/cargo-audit.yaml @@ -12,7 +12,7 @@ on: jobs: cargo_audit: name: Cargo Audit - runs-on: windows-latest + runs-on: windows-2025 permissions: issues: write checks: write diff --git a/.github/workflows/code-formatting-check.yaml b/.github/workflows/code-formatting-check.yaml index fe4ff92..2245b68 100644 --- a/.github/workflows/code-formatting-check.yaml +++ b/.github/workflows/code-formatting-check.yaml @@ -6,11 +6,10 @@ on: schedule: # Trigger a job on default branch at 4AM PST everyday - cron: 0 11 * * * - jobs: cargo-fmt: name: .rs Formatting Check - runs-on: windows-latest + runs-on: windows-2025 steps: - name: Checkout Repository @@ -18,7 +17,7 @@ jobs: - name: Install Rust Toolchain (Nightly) uses: dtolnay/rust-toolchain@nightly - with: + with: components: rustfmt - name: Run Cargo Format @@ -26,7 +25,7 @@ jobs: taplo-fmt: name: .toml Formatting Check - runs-on: windows-latest + runs-on: windows-2025 steps: - name: Checkout Repository diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 56f9412..4ddfded 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -13,11 +13,11 @@ env: jobs: docs: name: Docs - runs-on: windows-latest + runs-on: windows-2025 strategy: matrix: wdk: - - Microsoft.WindowsWDK.10.0.22621 # NI WDK + - 10.0.22621 # NI WDK llvm: - 17.0.6 @@ -39,30 +39,39 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 + - name: Checkout windows-drivers-rs actions + uses: actions/checkout@v4 + with: + repository: microsoft/windows-drivers-rs + ref: main + path: _temp/windows-drivers-rs + sparse-checkout: | + .github/actions + sparse-checkout-cone-mode: false + + - name: Copy actions to workspace + shell: pwsh + run: Copy-Item -Recurse -Force _temp/windows-drivers-rs/.github/actions .github/ + - name: Install Winget - uses: ./.github/actions/winget-install + uses: ./.github/actions/install-winget with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Winget PowerShell Module + shell: pwsh + run: Install-Module -Name Microsoft.WinGet.Client -Repository PSGallery -Force + - name: Install LLVM ${{ matrix.llvm }} - run: | - if ((Get-WinGetPackage -Id LLVM -Source winget -MatchOption Equals).InstalledVersion -eq '${{ matrix.llvm }}') { - Write-Host "LLVM ${{ matrix.llvm }} is already installed." - } else { - Write-Host "Installing LLVM ${{ matrix.llvm }}..." - Install-WinGetPackage -Id LLVM.LLVM -Version ${{ matrix.llvm }} -Source winget -MatchOption Equals -Mode Silent -Force - } - clang --version + uses: ./.github/actions/install-llvm + with: + version: ${{ matrix.llvm }} - name: Install WDK (${{ matrix.wdk }}) - run: | - if ((Get-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals).Id -eq '${{ matrix.wdk }}') { - Write-Host "${{ matrix.wdk }} is already installed. Attempting to update..." - Update-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } else { - Write-Host "Installing ${{ matrix.wdk }}..." - Install-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } + uses: ./.github/actions/install-wdk + with: + version: ${{ matrix.wdk }} + source: winget - name: Install Rust Toolchain (${{ matrix.rust_toolchain }}) uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 9692d5e..e49d959 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,13 +10,13 @@ name: Lint jobs: clippy: name: Clippy - runs-on: windows-latest + runs-on: windows-2025 permissions: checks: write strategy: matrix: wdk: - - Microsoft.WindowsWDK.10.0.22621 # NI WDK + - 10.0.22621 # NI WDK llvm: - 17.0.6 @@ -38,30 +38,39 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 + - name: Checkout windows-drivers-rs actions + uses: actions/checkout@v4 + with: + repository: microsoft/windows-drivers-rs + ref: main + path: _temp/windows-drivers-rs + sparse-checkout: | + .github/actions + sparse-checkout-cone-mode: false + + - name: Copy actions to workspace + shell: pwsh + run: Copy-Item -Recurse -Force _temp/windows-drivers-rs/.github/actions .github/ + - name: Install Winget - uses: ./.github/actions/winget-install + uses: ./.github/actions/install-winget with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Winget PowerShell Module + shell: pwsh + run: Install-Module -Name Microsoft.WinGet.Client -Repository PSGallery -Force + - name: Install LLVM ${{ matrix.llvm }} - run: | - if ((Get-WinGetPackage -Id LLVM -Source winget -MatchOption Equals).InstalledVersion -eq '${{ matrix.llvm }}') { - Write-Host "LLVM ${{ matrix.llvm }} is already installed." - } else { - Write-Host "Installing LLVM ${{ matrix.llvm }}..." - Install-WinGetPackage -Id LLVM.LLVM -Version ${{ matrix.llvm }} -Source winget -MatchOption Equals -Mode Silent -Force - } - clang --version + uses: ./.github/actions/install-llvm + with: + version: ${{ matrix.llvm }} - name: Install WDK (${{ matrix.wdk }}) - run: | - if ((Get-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals).Id -eq '${{ matrix.wdk }}') { - Write-Host "${{ matrix.wdk }} is already installed. Attempting to update..." - Update-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } else { - Write-Host "Installing ${{ matrix.wdk }}..." - Install-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } + uses: ./.github/actions/install-wdk + with: + version: ${{ matrix.wdk }} + source: winget - name: Install Rust Toolchain (${{ matrix.rust_toolchain }}) uses: dtolnay/rust-toolchain@master @@ -79,30 +88,44 @@ jobs: machete: name: Detect Unused Cargo Dependencies - runs-on: windows-latest + runs-on: windows-2025 strategy: matrix: wdk: - - Microsoft.WindowsWDK.10.0.22621 # NI WDK + - 10.0.22621 # NI WDK steps: - name: Checkout Repository uses: actions/checkout@v4 + - name: Checkout windows-drivers-rs actions + uses: actions/checkout@v4 + with: + repository: microsoft/windows-drivers-rs + ref: main + path: _temp/windows-drivers-rs + sparse-checkout: | + .github/actions + sparse-checkout-cone-mode: false + + - name: Copy actions to workspace + shell: pwsh + run: Copy-Item -Recurse -Force _temp/windows-drivers-rs/.github/actions .github/ + - name: Install Winget - uses: ./.github/actions/winget-install + uses: ./.github/actions/install-winget with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install Winget PowerShell Module + shell: pwsh + run: Install-Module -Name Microsoft.WinGet.Client -Repository PSGallery -Force + - name: Install WDK (${{ matrix.wdk }}) - run: | - if ((Get-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals).Id -eq '${{ matrix.wdk }}') { - Write-Host "${{ matrix.wdk }} is already installed. Attempting to update..." - Update-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } else { - Write-Host "Installing ${{ matrix.wdk }}..." - Install-WinGetPackage -Id ${{ matrix.wdk }} -Source winget -MatchOption Equals -Mode Silent -Force - } + uses: ./.github/actions/install-wdk + with: + version: ${{ matrix.wdk }} + source: winget - name: Install Rust Toolchain uses: dtolnay/rust-toolchain@stable diff --git a/general/echo/kmdf/exe/src/main.rs b/general/echo/kmdf/exe/src/main.rs index bcdf6db..8b9d911 100644 --- a/general/echo/kmdf/exe/src/main.rs +++ b/general/echo/kmdf/exe/src/main.rs @@ -5,9 +5,6 @@ //! find a 1 to 1 mapping to the original C sample app code versus a full proper //! Rust implementation -//! Idiomatic Rust wrappers for the Windows Driver Kit (WDK) APIs. This crate is -//! built on top of the raw FFI bindings provided by [`wdk-sys`], and provides a -//! safe, idiomatic rust interface to the WDK. #![deny(missing_docs)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(clippy::all)] @@ -128,12 +125,17 @@ Exit the app anytime by pressing Ctrl-C ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors - unsafe { - if h_device == INVALID_HANDLE_VALUE { - return Err(format!("Failed to open device. Error {}", GetLastError()).into()); - } + if h_device == INVALID_HANDLE_VALUE { + return Err(format!( + "Failed to open device. Error {}", + // SAFETY: + // - FFI contract: Called immediately after CreateFileW failure before any intervening + // Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } println!("Opened device successfully"); @@ -207,16 +209,17 @@ fn perform_write_read_test(h_device: HANDLE, test_length: u32) -> Result<(), Box ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from WriteFile - unsafe { - if r == FALSE { - return Err(format!( - "PerformWriteReadTest: WriteFile failed: Error {}", - GetLastError() - ) - .into()); - } + if r == FALSE { + return Err(format!( + "PerformWriteReadTest: WriteFile failed: Error {}", + // SAFETY: + // - FFI contract: Called immediately after WriteFile failure before any intervening + // Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } if bytes_returned != test_length { @@ -242,16 +245,17 @@ fn perform_write_read_test(h_device: HANDLE, test_length: u32) -> Result<(), Box ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from ReadFile - unsafe { - if r == FALSE { - return Err(format!( - "PerformWriteReadTest: ReadFile failed: Error {}", - GetLastError() - ) - .into()); - } + if r == FALSE { + return Err(format!( + "PerformWriteReadTest: ReadFile failed: Error {}", + // SAFETY: + // - FFI contract: Called immediately after ReadFile failure before any intervening + // Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } // SAFETY: @@ -312,17 +316,18 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from CreateFileW - unsafe { - if h_device == INVALID_HANDLE_VALUE { - return Err(format!( - "Cannot open {} error {}", - globals.device_path, - GetLastError() - ) - .into()); - } + if h_device == INVALID_HANDLE_VALUE { + return Err(format!( + "Cannot open {} error {}", + globals.device_path, + // SAFETY: + // - FFI contract: Called immediately after CreateFileW failure before any intervening + // Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } // SAFETY: @@ -332,14 +337,18 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { h_completion_port = CreateIoCompletionPort(h_device, 0, 1, 0); } - // SAFETY: - // Call Win32 API FFI to check for CreateIoCompletionPort result from - // GetLastError() - unsafe { - // CreateIoCompletionPort returns NULL on failure, not INVALID_HANDLE_VALUE - if h_completion_port == 0 { - return Err(format!("Cannot open completion port {}", GetLastError()).into()); - } + // CreateIoCompletionPort returns NULL on failure, not INVALID_HANDLE_VALUE + if h_completion_port == 0 { + return Err(format!( + "Cannot open completion port {}", + // SAFETY: + // - FFI contract: Called immediately after CreateIoCompletionPort failure before any + // intervening Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } let mut remaining_requests_to_receive = 0; @@ -397,14 +406,15 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from ReadFile - unsafe { - if r == FALSE { - let error = GetLastError(); - if error != ERROR_IO_PENDING { - return Err(format!("{i}th Read failed {error}").into()); - } + if r == FALSE { + // SAFETY: + // - FFI contract: Called immediately after ReadFile failure before any + // intervening Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + let error = unsafe { GetLastError() }; + if error != ERROR_IO_PENDING { + return Err(format!("{i}th Read failed {error}",).into()); } } } else { @@ -422,14 +432,15 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from WriteFile - unsafe { - if r == FALSE { - let error = GetLastError(); - if error != ERROR_IO_PENDING { - return Err(format!("{i}th Write failed {error}").into()); - } + if r == FALSE { + // SAFETY: + // - FFI contract: Called immediately after WriteFile failure before any + // intervening Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + let error = unsafe { GetLastError() }; + if error != ERROR_IO_PENDING { + return Err(format!("{i}th Write failed {error}").into()); } } } @@ -453,13 +464,18 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from - // GetQueuedCompletionStatus - unsafe { - if r == FALSE { - return Err(format!("GetQueuedCompletionStatus failed {}", GetLastError()).into()); - } + if r == FALSE { + return Err(format!( + "GetQueuedCompletionStatus failed {}", + // SAFETY: + // - FFI contract: Called immediately after GetQueuedCompletionStatus failure + // before any intervening Win32/CRT calls that would overwrite thread-local error + // slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + unsafe { GetLastError() } + ) + .into()); } let i; @@ -511,14 +527,15 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from ReadFile - unsafe { - if r == FALSE { - let error = GetLastError(); - if error != ERROR_IO_PENDING { - return Err(format!("{i}th Read failed {error}").into()); - } + if r == FALSE { + // SAFETY: + // - FFI contract: Called immediately after ReadFile failure before any + // intervening Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + let error = unsafe { GetLastError() }; + if error != ERROR_IO_PENDING { + return Err(format!("{i}th Read failed {error}").into()); } } } else { @@ -562,14 +579,15 @@ fn async_io_work(io_type: u32) -> Result<(), Box> { ); } - // SAFETY: - // Call Win32 API FFI GetLastError() to check for any errors from WriteFile - unsafe { - if r == FALSE { - let error = GetLastError(); - if error != ERROR_IO_PENDING { - return Err(format!("{i}th write failed {error}").into()); - } + if r == FALSE { + // SAFETY: + // - FFI contract: Called immediately after WriteFile failure before any + // intervening Win32/CRT calls that would overwrite thread-local error slot + // - Concurrency: Reads thread-local storage only (no data races) + // - Memory safety: Returns u32 value (no pointer dereferences) + let error = unsafe { GetLastError() }; + if error != ERROR_IO_PENDING { + return Err(format!("{i}th write failed {error}").into()); } } }