<# Сборка «Переводчика экрана». .NET SDK не нужен: используется Roslyn из VS Build Tools и сборки .NET Framework 4.8, которые уже есть в Windows. На выходе — один самодостаточный exe. Использование: .\build.ps1 собрать в .\dist .\build.ps1 -Run собрать и запустить #> [CmdletBinding()] param( [switch]$Run, [switch]$Test, # дополнительно собрать RenderTest.exe — прогон конвейера без окна, результат в PNG [string]$OutDir = "$PSScriptRoot\dist" ) $ErrorActionPreference = 'Stop' function Find-Csc { $candidates = @( "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\Roslyn\csc.exe", "C:\Program Files\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\Roslyn\csc.exe", "C:\Program Files (x86)\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\Roslyn\csc.exe", "C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe" ) foreach ($c in $candidates) { $hit = Get-Item $c -ErrorAction SilentlyContinue | Select-Object -First 1 if ($hit) { return $hit.FullName } } # запасной вариант — компилятор из самой Windows (старый C#, но соберёт) $fw = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe" if (Test-Path $fw) { return $fw } throw "Не найден компилятор C#. Поставьте Visual Studio Build Tools 2022." } function Find-WinMd { $root = "C:\Program Files (x86)\Windows Kits\10\UnionMetadata" if (-not (Test-Path $root)) { throw "Не найден Windows SDK (UnionMetadata) — без него нет доступа к Windows OCR." } # рядом лежит папка Facade с заглушкой — берём только версионные каталоги (10.0.x) $ver = Get-ChildItem $root -Directory | Where-Object { $_.Name -match '^\d+\.' -and (Test-Path (Join-Path $_.FullName 'Windows.winmd')) } | Sort-Object { [version]$_.Name } -Descending | Select-Object -First 1 if (-not $ver) { throw "В Windows SDK нет версионного Windows.winmd." } return (Join-Path $ver.FullName 'Windows.winmd') } $csc = Find-Csc $winmd = Find-WinMd $fw = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319" $gac = "C:\Windows\Microsoft.NET\assembly\GAC_MSIL" function Gac($name) { $hit = Get-ChildItem (Join-Path $gac $name) -Recurse -Filter "$name.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $hit) { throw "Нет сборки $name в GAC." } return $hit.FullName } $refs = @( "$fw\mscorlib.dll" "$fw\System.dll" "$fw\System.Core.dll" "$fw\System.Drawing.dll" "$fw\System.Windows.Forms.dll" "$fw\System.Runtime.dll" "$fw\System.Web.dll" (Gac 'System.Web.Extensions') (Gac 'System.Runtime.WindowsRuntime') $winmd ) New-Item -ItemType Directory -Force -Path $OutDir | Out-Null $exe = Join-Path $OutDir 'ScreenTranslator.exe' # запущенная копия держит файл, и линковка падает с невнятной ошибкой $running = Get-Process ScreenTranslator -ErrorAction SilentlyContinue if ($running) { Write-Host "Останавливаю запущенный ScreenTranslator (PID $($running.Id))…" $running | Stop-Process -Force Start-Sleep -Milliseconds 400 } $sources = Get-ChildItem "$PSScriptRoot\src" -Filter *.cs | ForEach-Object { $_.FullName } Write-Host "csc : $csc" Write-Host "winmd : $winmd" Write-Host "исходники: $($sources.Count) файлов" Write-Host "выход : $exe" Write-Host '' $cscArgs = @( '/nologo' '/target:winexe' '/platform:x64' '/optimize+' '/langversion:latest' "/out:$exe" "/win32manifest:$PSScriptRoot\app.manifest" ) + ($refs | ForEach-Object { "/r:$_" }) + $sources & $csc @cscArgs if ($LASTEXITCODE -ne 0) { throw "Сборка не удалась (код $LASTEXITCODE)." } Write-Host ("`nГотово: {0} ({1:N0} КБ)" -f $exe, ((Get-Item $exe).Length / 1KB)) if ($Test) { $testExe = Join-Path $OutDir 'RenderTest.exe' # тот же код, но с консольной точкой входа вместо трея $testSources = ($sources | Where-Object { $_ -notlike '*\Program.cs' }) + "$PSScriptRoot\tools\RenderTest.cs" $testArgs = @( '/nologo', '/target:exe', '/platform:x64', '/optimize+', '/langversion:latest' "/out:$testExe" "/win32manifest:$PSScriptRoot\app.manifest" # без него захват придёт в логических пикселях ) + ($refs | ForEach-Object { "/r:$_" }) + $testSources & $csc @testArgs if ($LASTEXITCODE -ne 0) { throw "Сборка теста не удалась (код $LASTEXITCODE)." } Write-Host ("Готово: {0} ({1:N0} КБ)" -f $testExe, ((Get-Item $testExe).Length / 1KB)) } if ($Run) { Get-Process ScreenTranslator -ErrorAction SilentlyContinue | Stop-Process -Force Start-Sleep -Milliseconds 300 Start-Process $exe Write-Host "Запущен. Значок в трее." }