From 52d3e66c9a9fa79cb4172fcdee7ec99f190a5e05 Mon Sep 17 00:00:00 2001 From: Alexander Winnen Date: Mon, 10 Aug 2026 11:24:33 +0200 Subject: [PATCH 1/5] Create main.yml --- .github/workflows/main.yml | 156 +++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..5303c69e --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,156 @@ +name: CapFrameX CI + +on: + push: + + +permissions: + contents: read + +jobs: + build-and-publish: + runs-on: windows-latest + + env: + CONFIGURATION: Release + PLATFORM: x64 + VS_VERSION: 18.0 + AZURE_STORAGE_CONTAINER: builds + REF_NAME: ${{ github.head_ref || github.ref_name }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.0.x + + - name: Setup NuGet + uses: nuget/setup-nuget@v2 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Install WiX Toolset v3.14.1 + shell: pwsh + run: | + $wixInstaller = Join-Path $env:RUNNER_TEMP "wix314.exe" + Invoke-WebRequest ` + -Uri "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe" ` + -OutFile $wixInstaller + + Start-Process ` + -FilePath $wixInstaller ` + -ArgumentList "/quiet", "/norestart" ` + -Wait + + $wixBin = "${env:ProgramFiles(x86)}\WiX Toolset v3.14\bin" + if (-not (Test-Path $wixBin)) { + throw "WiX Toolset v3.14.1 installation failed; expected path not found: $wixBin" + } + + "WIX=$wixBin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - name: Restore + shell: cmd + run: | + dotnet restore CapFrameX.sln + nuget restore -SolutionDirectory "%GITHUB_WORKSPACE%" source\CapFrameX.CustomInstallerActions\CapFrameX.CustomInstallerActions.csproj + + - name: Build CX + shell: cmd + run: | + msbuild source\CapFrameX\CapFrameX.csproj /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Build HWInfo + shell: cmd + run: | + msbuild source\CapFrameX.Hwinfo\CapFrameX.Hwinfo.vcxproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Build IGCL + shell: cmd + run: | + msbuild source\CapFrameX.IGCL\CapFrameX.IGCL.vcxproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Build ADLX + shell: cmd + run: | + msbuild source\CapFrameX.ADLX\CapFrameX.ADLX.vcxproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Stage native DLLs + shell: cmd + run: | + copy /y source\CapFrameX\bin\x64\Release\CapFrameX.Hwinfo.dll source\CapFrameX\bin\x64\Release\net9.0-windows\ + copy /y source\CapFrameX\bin\x64\Release\CapFrameX.IGCL.dll source\CapFrameX\bin\x64\Release\net9.0-windows\ + copy /y source\CapFrameX\bin\x64\Release\CapFrameX.ADLX.dll source\CapFrameX\bin\x64\Release\net9.0-windows\ + + - name: Build Installer + shell: cmd + run: | + msbuild source\CapFrameXInstaller\CapFrameXInstaller.wixproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Build Bootstrapper + shell: cmd + run: | + msbuild source\CapFrameXBootstrapper\CapFrameXBootstrapper.wixproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% + + - name: Prepare portable config + shell: cmd + run: | + copy portable.json.sample source\CapFrameX\bin\x64\Release\net9.0-windows\portable.json + + - name: Compute archive metadata + id: vars + shell: pwsh + run: | + if ("${{ github.ref }}".StartsWith("refs/tags/v")) { + $filename = "${{ github.ref_name }}" + } else { + $filename = "${{ github.sha }}" + } + + "filename=$filename" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 + "branch=$env:REF_NAME" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8 + + - name: Create archives + shell: pwsh + run: | + $filename = "${{ steps.vars.outputs.filename }}" + + Compress-Archive ` + -Path "source\CapFrameXBootstrapper\bin\x64\Release\CapFrameXBootstrapper.exe" ` + -DestinationPath "${filename}_installer.zip" ` + -Force + + Compress-Archive ` + -Path "source\CapFrameX\bin\x64\Release\net9.0-windows\*" ` + -DestinationPath "${filename}_portable.zip" ` + -Force + + - name: Upload workflow artifacts + uses: actions/upload-artifact@v4 + with: + name: capframex-${{ steps.vars.outputs.filename }} + path: | + *.zip + + - name: Upload archives to Azure Blob Storage + if: ${{ secrets.AZURE_STORAGE_ACCOUNT != '' && secrets.AZURE_STORAGE_KEY != '' }} + shell: pwsh + env: + AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }} + AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }} + run: | + if (-not (Get-Command az -ErrorAction SilentlyContinue)) { + throw "Azure CLI is not available on this runner." + } + + az storage blob upload-batch ` + --account-name "$env:AZURE_STORAGE_ACCOUNT" ` + --destination "$env:AZURE_STORAGE_CONTAINER" ` + --source "." ` + --pattern "*.zip" ` + --destination-path "${{ steps.vars.outputs.branch }}/${{ github.run_number }}" ` + --account-key "$env:AZURE_STORAGE_KEY" From 213725b6daec56501cdf14fe2b67b4d43c1fc4eb Mon Sep 17 00:00:00 2001 From: Alexander Winnen Date: Mon, 10 Aug 2026 11:31:32 +0200 Subject: [PATCH 2/5] update credentials --- .github/workflows/main.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5303c69e..9e7fcc58 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -137,12 +137,16 @@ jobs: *.zip - name: Upload archives to Azure Blob Storage - if: ${{ secrets.AZURE_STORAGE_ACCOUNT != '' && secrets.AZURE_STORAGE_KEY != '' }} shell: pwsh env: AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }} AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }} run: | + if ([string]::IsNullOrWhiteSpace($env:AZURE_STORAGE_ACCOUNT) -or [string]::IsNullOrWhiteSpace($env:AZURE_STORAGE_KEY)) { + Write-Host "Skipping Azure Blob upload because AZURE_STORAGE_ACCOUNT or AZURE_STORAGE_KEY is not set." + exit 0 + } + if (-not (Get-Command az -ErrorAction SilentlyContinue)) { throw "Azure CLI is not available on this runner." } From 4ecc5e0a95bab4afc7349b986af01a3214c45bb2 Mon Sep 17 00:00:00 2001 From: Alexander Winnen Date: Mon, 10 Aug 2026 11:36:03 +0200 Subject: [PATCH 3/5] update pipeine --- .github/workflows/main.yml | 133 +++++++++++++++++- source/CapFrameX.ADLX/CapFrameX.ADLX.vcxproj | 8 +- .../CapFrameX.CXServicex86.vcxproj | 8 +- .../CapFrameX.Hwinfo/CapFrameX.Hwinfo.vcxproj | 8 +- source/CapFrameX.IGCL/CapFrameX.IGCL.vcxproj | 8 +- .../CapFrameX.RTSSInterface.vcxproj | 8 +- 6 files changed, 152 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9e7fcc58..46a700c9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,6 +32,137 @@ jobs: - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 + with: + vs-version: '[18.0, 19.0)' + + - name: Install Visual Studio Native Desktop + MFC + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + Write-Host "Starting VS native dependency setup..." + + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vsInstaller = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vs_installer.exe" + + Write-Host "vswhere path: $vswhere" + Write-Host "vs_installer path: $vsInstaller" + + if (-not (Test-Path $vswhere)) { + throw "vswhere.exe not found at $vswhere" + } + if (-not (Test-Path $vsInstaller)) { + throw "vs_installer.exe not found at $vsInstaller" + } + + $instanceJson = & $vswhere -latest -products * -version "[18.0, 19.0)" -requires Microsoft.Component.MSBuild -format json + $instance = ($instanceJson | ConvertFrom-Json | Select-Object -First 1) + if ($null -eq $instance) { + throw "No Visual Studio installation found on runner." + } + + $installPath = $instance.installationPath + $productId = $instance.productId + + if ([string]::IsNullOrWhiteSpace($installPath) -or [string]::IsNullOrWhiteSpace($productId)) { + throw "Could not resolve Visual Studio installPath/productId." + } + + Write-Host "Visual Studio installPath: $installPath" + Write-Host "Visual Studio productId: $productId" + "VS_INSTALL_PATH=$installPath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + $beforeMfcInstance = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.ATLMFC -property installationPath + if ([string]::IsNullOrWhiteSpace($beforeMfcInstance)) { + Write-Host "MFC component not detected before install." + } else { + Write-Host "MFC component already detected before install at: $beforeMfcInstance" + } + + $net472TargetingPack = Join-Path "${env:ProgramFiles(x86)}" "Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll" + $needsNet472Install = -not (Test-Path $net472TargetingPack) + if ($needsNet472Install) { + Write-Host ".NET Framework 4.7.2 targeting pack not found at: $net472TargetingPack" + } else { + Write-Host ".NET Framework 4.7.2 targeting pack found at: $net472TargetingPack" + } + + $netFxRelease = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue).Release + if ($null -eq $netFxRelease) { + Write-Host ".NET Framework v4 Full Release key not found in registry." + } else { + Write-Host ".NET Framework v4 Full Release key: $netFxRelease" + } + + $atlmfcDirsBefore = Get-ChildItem -Path (Join-Path $installPath "VC\Tools\MSVC") -Directory -ErrorAction SilentlyContinue | + ForEach-Object { Join-Path $_.FullName "atlmfc\lib\x64" } | + Where-Object { Test-Path $_ } + $mfcLibsBefore = @() + if ($atlmfcDirsBefore) { + $mfcLibsBefore = @(Get-ChildItem -Path $atlmfcDirsBefore -Filter "mfc*.lib" -ErrorAction SilentlyContinue) + } + + $needsInstall = [string]::IsNullOrWhiteSpace($beforeMfcInstance) -or ($mfcLibsBefore.Count -eq 0) -or $needsNet472Install + if ($needsInstall) { + $installArgs = @( + "modify", + "--installPath", "$installPath", + "--add", "Microsoft.VisualStudio.Workload.NativeDesktop", + "--add", "Microsoft.VisualStudio.Component.VC.ATLMFC", + "--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "--add", "Microsoft.Net.Component.4.7.2.TargetingPack", + "--add", "Microsoft.Net.Component.4.7.2.SDK", + "--passive", + "--norestart", + "--wait" + ) + + Write-Host "Running vs_installer with args: $($installArgs -join ' ')" + $proc = Start-Process -FilePath $vsInstaller -ArgumentList $installArgs -Wait -PassThru -NoNewWindow + Write-Host "vs_installer exit code: $($proc.ExitCode)" + + if (($proc.ExitCode -ne 0) -and ($proc.ExitCode -ne 3010)) { + throw "Failed to install Native Desktop/MFC components. Exit code: $($proc.ExitCode)" + } + } else { + Write-Host "Skipping vs_installer modify because MFC libraries are already present." + } + + $afterMfcInstance = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.ATLMFC -property installationPath + if ([string]::IsNullOrWhiteSpace($afterMfcInstance)) { + throw "MFC component is still not detected by vswhere after installation." + } + + Write-Host "MFC component detected after install at: $afterMfcInstance" + + $atlmfcDirs = Get-ChildItem -Path (Join-Path $installPath "VC\Tools\MSVC") -Directory -ErrorAction SilentlyContinue | + ForEach-Object { Join-Path $_.FullName "atlmfc\lib\x64" } | + Where-Object { Test-Path $_ } + + if (-not $atlmfcDirs) { + throw "No atlmfc\\lib\\x64 directories found under $installPath\\VC\\Tools\\MSVC" + } + + Write-Host "Detected ATL/MFC library directories:" + $atlmfcDirs | ForEach-Object { Write-Host " - $_" } + + $mfcLibs = Get-ChildItem -Path $atlmfcDirs -Filter "mfc*.lib" -ErrorAction SilentlyContinue + if (-not $mfcLibs) { + throw "No mfc*.lib files found in ATL/MFC x64 library directories." + } + + Write-Host "Detected MFC library files (sample):" + $mfcLibs | Select-Object -First 10 | ForEach-Object { Write-Host " - $($_.FullName)" } + + if (-not (Test-Path $net472TargetingPack)) { + throw ".NET Framework 4.7.2 targeting pack is missing after installation: $net472TargetingPack" + } + + $netFxReleaseAfter = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue).Release + if (($null -eq $netFxReleaseAfter) -or ($netFxReleaseAfter -lt 461808)) { + throw ".NET Framework runtime 4.7.2 or newer is not installed (Release key: $netFxReleaseAfter)." + } + + Write-Host ".NET Framework 4.7.2+ runtime and targeting pack are available." - name: Install WiX Toolset v3.14.1 shell: pwsh @@ -56,7 +187,7 @@ jobs: - name: Restore shell: cmd run: | - dotnet restore CapFrameX.sln + nuget restore CapFrameX.sln nuget restore -SolutionDirectory "%GITHUB_WORKSPACE%" source\CapFrameX.CustomInstallerActions\CapFrameX.CustomInstallerActions.csproj - name: Build CX diff --git a/source/CapFrameX.ADLX/CapFrameX.ADLX.vcxproj b/source/CapFrameX.ADLX/CapFrameX.ADLX.vcxproj index 61971d03..815f50c7 100644 --- a/source/CapFrameX.ADLX/CapFrameX.ADLX.vcxproj +++ b/source/CapFrameX.ADLX/CapFrameX.ADLX.vcxproj @@ -29,26 +29,26 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode diff --git a/source/CapFrameX.CXServicex86/CapFrameX.CXServicex86.vcxproj b/source/CapFrameX.CXServicex86/CapFrameX.CXServicex86.vcxproj index ec7e460b..77def619 100644 --- a/source/CapFrameX.CXServicex86/CapFrameX.CXServicex86.vcxproj +++ b/source/CapFrameX.CXServicex86/CapFrameX.CXServicex86.vcxproj @@ -30,7 +30,7 @@ Application true - v143 + v145 MultiByte Dynamic true @@ -38,20 +38,20 @@ Application false - v143 + v145 true Unicode Application true - v143 + v145 Unicode Application false - v143 + v145 true Unicode diff --git a/source/CapFrameX.Hwinfo/CapFrameX.Hwinfo.vcxproj b/source/CapFrameX.Hwinfo/CapFrameX.Hwinfo.vcxproj index b5cb6e37..0f7d5e42 100644 --- a/source/CapFrameX.Hwinfo/CapFrameX.Hwinfo.vcxproj +++ b/source/CapFrameX.Hwinfo/CapFrameX.Hwinfo.vcxproj @@ -29,26 +29,26 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode diff --git a/source/CapFrameX.IGCL/CapFrameX.IGCL.vcxproj b/source/CapFrameX.IGCL/CapFrameX.IGCL.vcxproj index f4fb467c..f9e8b138 100644 --- a/source/CapFrameX.IGCL/CapFrameX.IGCL.vcxproj +++ b/source/CapFrameX.IGCL/CapFrameX.IGCL.vcxproj @@ -29,26 +29,26 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode diff --git a/source/CapFrameX.RTSSInterface/CapFrameX.RTSSInterface.vcxproj b/source/CapFrameX.RTSSInterface/CapFrameX.RTSSInterface.vcxproj index 198c52f6..16990d6b 100644 --- a/source/CapFrameX.RTSSInterface/CapFrameX.RTSSInterface.vcxproj +++ b/source/CapFrameX.RTSSInterface/CapFrameX.RTSSInterface.vcxproj @@ -30,7 +30,7 @@ DynamicLibrary true - v143 + v145 MultiByte false Dynamic @@ -39,7 +39,7 @@ DynamicLibrary false - v143 + v145 true MultiByte Dynamic @@ -48,7 +48,7 @@ DynamicLibrary true - v143 + v145 MultiByte true Dynamic @@ -56,7 +56,7 @@ DynamicLibrary false - v143 + v145 true MultiByte Dynamic From 30a5c34074c22cfb359e8517d01c557b52da1592 Mon Sep 17 00:00:00 2001 From: Alexander Winnen Date: Mon, 10 Aug 2026 14:16:03 +0200 Subject: [PATCH 4/5] attempt --- .github/workflows/main.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d17bd00e..a4dd7c59 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -226,25 +226,6 @@ jobs: - name: Build Installer shell: cmd run: | - if not defined WIX set "WIX=%ProgramFiles(x86)%\WiX Toolset v3.14" - echo Using WIX=%WIX% - - if not exist "%WIX%\bin\heat.exe" ( - echo Missing heat.exe at %WIX%\bin\heat.exe - exit /b 1 - ) - - if not exist "source\CapFrameX\bin\x64\Release\net9.0-windows" ( - echo Missing installer input directory: source\CapFrameX\bin\x64\Release\net9.0-windows - dir "source\CapFrameX\bin\x64\Release" - exit /b 1 - ) - - if not exist "source\CapFrameXInstaller\filter.xslt" ( - echo Missing filter.xslt at source\CapFrameXInstaller\filter.xslt - exit /b 1 - ) - msbuild source\CapFrameXInstaller\CapFrameXInstaller.wixproj /p:SolutionDir="%GITHUB_WORKSPACE%\\" /p:Configuration=%CONFIGURATION% /p:Platform=%PLATFORM% /p:DeployOnBuild=true /p:VisualStudioVersion=%VS_VERSION% - name: Build Bootstrapper From 3e57763b4141fdde81b1c1e283626109c774fbfb Mon Sep 17 00:00:00 2001 From: Alexander Winnen Date: Mon, 10 Aug 2026 14:47:08 +0200 Subject: [PATCH 5/5] extract publish step as job --- .github/workflows/main.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a4dd7c59..2e123625 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ permissions: contents: read jobs: - build-and-publish: + build: runs-on: windows-latest env: @@ -273,6 +273,20 @@ jobs: path: | *.zip + publish: + runs-on: windows-latest + needs: build + + env: + AZURE_STORAGE_CONTAINER: builds + REF_NAME: ${{ github.head_ref || github.ref_name }} + + steps: + - name: Download workflow artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + - name: Upload archives to Azure Blob Storage shell: pwsh env: @@ -291,7 +305,7 @@ jobs: az storage blob upload-batch ` --account-name "$env:AZURE_STORAGE_ACCOUNT" ` --destination "$env:AZURE_STORAGE_CONTAINER" ` - --source "." ` + --source "artifacts" ` --pattern "*.zip" ` - --destination-path "${{ steps.vars.outputs.branch }}/${{ github.run_number }}" ` + --destination-path "$env:REF_NAME/${{ github.run_number }}" ` --account-key "$env:AZURE_STORAGE_KEY"