diff --git a/README.md b/README.md index a5c69bc..6ffdc70 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,36 @@ It will scan your system for *OpenCL Installable Client Driver (ICD)* files by A - amdocl12cl64.dll - amdocl32.dll - amdocl64.dll +- versioned variants (e.g. amdocl_\*.dll, amdocl64_\*.dll) + +The scripts ensure proper detection and registration of the drivers, including handling SysWOW64, scanning the PATH safely, registering versioned DLLs and avoiding duplicate entries. +The PowerShell version additionally verifies DLL signatures, detects 32/64-bit bitness more reliably, safely cleans up or moves invalid entries, handles DriverStore and versioned DLLs intelligently and provides more detailed error reporting and status output. ## Usage +## Batch script 1. Make sure to have the latest [AMD drivers](https://www.amd.com/en/support) installed 2. Download and execute `amdocl.bat` 3. Run the file as **Administrator** (Right click file and select `Run as Administrator`) +## PowerShell script +1. Download `amdocl-fix.ps1` and place it in a folder of your choice. +2. Make sure to run it as **Administrator**: + - Right‑click the file → **Run with PowerShell** → confirm the UAC prompt. + - Alternatively, open PowerShell as Administrator and run: + ```powershell + cd "C:\path\to\folder" + .\amdocl-fix.ps1 + ``` + +## Compatibility +- Windows 10, 11: fully supported +- Windows 7, 8, 8.1: batch script fully supported; PowerShell script (`amdocl-fix.ps1`) requires PowerShell 5.1 or newer +- Windows XP / Vista: script runs safely, but OpenCL drivers may not be present + ## Notes Inspired by StackOverflow https://stackoverflow.com/a/28407851 --- -© 2023 [Patrick Trumpis](https://github.com/ptrumpis) +© 2023 [Patrick Trumpis](https://github.com/ptrumpis) +© 2025 [TantalusDrive](https://github.com/TantalusDrive) (Additional improvements and PowerShell version) diff --git a/amdocl-fix.ps1 b/amdocl-fix.ps1 new file mode 100644 index 0000000..3a7bb22 --- /dev/null +++ b/amdocl-fix.ps1 @@ -0,0 +1,168 @@ +# PowerShell script to manage and fix AMD OpenCL ICDs +# +# Original batch concept: Patrick Trumpis (https://github.com/ptrumpis/OpenCL-AMD-GPU) +# PowerShell implementation and extensions: TantalusDrive (https://github.com/TantalusDrive) +# +# Licensed under the MIT License. +# See LICENSE file in the repository root for full terms. +# +# This PowerShell script extends the original batch by safely cleaning up +# invalid or misplaced registry entries and coherently registering AMD +# OpenCL DLLs in the correct 32-bit or 64-bit hive, and providing detailed status output. +# By default, unsigned DLLs are allowed to prevent accidental removal. +# +# Tested on a couple of dated AMD GPUs (R5 M330, R5 M430), feedback and contributions are welcome. + +param( + [switch]$AllowUnsigned = $true +) + +$roots = @( + "HKLM:\SOFTWARE\Khronos\OpenCL\Vendors", + "HKLM:\SOFTWARE\WOW6432Node\Khronos\OpenCL\Vendors" +) + +$scanDirs = @( + "$env:WINDIR\System32", + "$env:WINDIR\SysWOW64", + "$env:WINDIR\System32\DriverStore\FileRepository" +) + +$hadErrors = $false + +function Get-DllBitness { + param([string]$Path) + try { + $fs = [System.IO.File]::Open($Path, 'Open', 'Read', 'Read') + $br = New-Object System.IO.BinaryReader($fs) + $fs.Seek(0x3C, 'Begin') | Out-Null + $peOffset = $br.ReadInt32() + $fs.Seek($peOffset + 4, 'Begin') | Out-Null + $machine = $br.ReadUInt16() + $br.Close(); $fs.Close() + switch ($machine) { + 0x8664 { return 64 } + 0x014C { return 32 } + default { return $null } + } + } catch { return $null } +} + +function Safe-Remove { + param($root,$name) + try { Remove-ItemProperty -Path $root -Name $name -Force } + catch { $global:hadErrors = $true } +} + +function Safe-Add { + param($root,$name) + try { New-ItemProperty -Path $root -Name $name -Value 0 -PropertyType DWord -Force | Out-Null } + catch { $global:hadErrors = $true } +} + +function Is-SignatureAcceptable { + param($sig, $AllowUnsigned) + if ($sig.Status -eq 'Valid') { return $true } + if ($AllowUnsigned -and ($sig.Status -eq 'NotSigned' -or $sig.Status -eq 'Unknown')) { + return $true + } + return $false +} + +function Register-OpenCLDLL { + param([string]$dllPath, [switch]$AllowUnsigned) + if (-not (Test-Path $dllPath)) { return } + $sig = Get-AuthenticodeSignature -FilePath $dllPath + if (-not (Is-SignatureAcceptable $sig $AllowUnsigned)) { return } + $bit = Get-DllBitness $dllPath + if ($bit -eq 64) { $root = $roots[0] } + elseif ($bit -eq 32) { $root = $roots[1] } + else { return } + $exists = (Get-ItemProperty -Path $root -ErrorAction SilentlyContinue).PSObject.Properties | + Where-Object { $_.Name -eq $dllPath } + if (-not $exists) { + Safe-Add $root $dllPath + Write-Host "[+ $bit bit] Added: $dllPath" -ForegroundColor Cyan + } +} + +# Registry cleanup: remove invalid, missing, or misplaced entries +foreach ($root in $roots) { + Write-Host "`nAnalyzing: $root" -ForegroundColor Cyan + $entries = Get-ItemProperty -Path $root -ErrorAction SilentlyContinue + if (-not $entries) { + Write-Host "No entries found or key missing." + continue + } + foreach ($prop in $entries.PSObject.Properties) { + $dll = $prop.Name + if ($dll -notlike "*amdocl*.dll") { continue } + if (-not (Test-Path $dll)) { + Write-Host "Removed: $dll (file not found)" -ForegroundColor Yellow + Safe-Remove $root $dll + continue + } + $sig = Get-AuthenticodeSignature -FilePath $dll + if (-not (Is-SignatureAcceptable $sig $AllowUnsigned)) { + Write-Host "Removed: $dll (invalid signature)" -ForegroundColor Yellow + Safe-Remove $root $dll + continue + } + $bit = Get-DllBitness $dll + if ($bit -eq $null) { + Write-Host "Removed: $dll (architecture not detected)" -ForegroundColor Yellow + Safe-Remove $root $dll + continue + } + $correctRoot = if ($bit -eq 64) { $roots[0] } else { $roots[1] } + if ($correctRoot -ne $root) { + Write-Host "Moved ($bit bit): $dll" -ForegroundColor Yellow + Safe-Remove $root $dll + $existsDest = (Get-ItemProperty -Path $correctRoot -ErrorAction SilentlyContinue).PSObject.Properties | + Where-Object { $_.Name -eq $dll } + if (-not $existsDest) { + Safe-Add $correctRoot $dll + } + continue + } + Write-Host "OK: $dll" -ForegroundColor Green + } +} + +# Register all valid DLLs found in each directory (no duplicates) +Write-Host "`nRegistering all valid AMD OpenCL DLLs from standard directories..." -ForegroundColor Cyan + +foreach ($dir in $scanDirs) { + if (-not (Test-Path $dir)) { continue } + Get-ChildItem -Path $dir -Filter "amdocl*.dll" -Recurse -ErrorAction SilentlyContinue | + Where-Object { $_.VersionInfo.FileVersionRaw } | + ForEach-Object { + Register-OpenCLDLL -dllPath $_.FullName -AllowUnsigned:$AllowUnsigned + } +} + +if ($hadErrors) { + Write-Host "`nCompleted with warnings." -ForegroundColor Yellow +} else { + Write-Host "`nCompleted." -ForegroundColor Green +} + +# Optional PATH scan +Write-Host "`nDo you want to include an extended scan of system PATH directories? (Recommended only for custom or unofficial DLLs)" -ForegroundColor Yellow +$input = Read-Host "Type Y to scan, anything else to skip" +if ($input -eq 'Y' -or $input -eq 'y') { + Write-Host "`nNote: DLLs found in PATH may be unofficial or obsolete." -ForegroundColor Magenta + $pathDirs = ($env:PATH -split ';' | Where-Object { Test-Path $_ }) + foreach ($dir in $pathDirs) { + Get-ChildItem -Path $dir -Filter "amdocl*.dll" -Recurse -ErrorAction SilentlyContinue | + Where-Object { $_.VersionInfo.FileVersionRaw } | + ForEach-Object { + Register-OpenCLDLL -dllPath $_.FullName -AllowUnsigned:$AllowUnsigned + } + } + Write-Host "`nPATH scan completed." -ForegroundColor Cyan +} else { + Write-Host "`nPATH scan skipped." +} + +Read-Host "Press Enter to exit" diff --git a/amdocl.bat b/amdocl.bat index 3849f61..749c183 100644 --- a/amdocl.bat +++ b/amdocl.bat @@ -1,59 +1,55 @@ @echo off cls -echo OpenCL Driver (ICD) Fix for AMD GPU's -echo By Patrick Trumpis (https://github.com/ptrumpis/OpenCL-AMD-GPU) +echo OpenCL Driver (ICD) Fix for AMD GPUs +echo Original work by Patrick Trumpis (https://github.com/ptrumpis/OpenCL-AMD-GPU) +echo Improvements by TantalusDrive (https://github.com/TantalusDrive) +REM SysWOW64 handling, PATH scan, versioned DLLs, duplicate prevention echo Inspired by https://stackoverflow.com/a/28407851 echo: echo: ->nul 2>&1 "%SYSTEMROOT%\System32\cacls.exe" "%SYSTEMROOT%\System32\config\system" && ( - goto :run -) || ( +REM ============================================================ +REM Privilege check +REM ============================================================ +net session >nul 2>&1 +if %errorlevel% neq 0 ( echo Execution stopped echo ================= echo This script requires administrator rights. echo Please run it again as administrator. echo You can right click the file and select 'Run as administrator' - echo: pause exit /b 1 ) -:run SETLOCAL EnableDelayedExpansion SET ROOTKEY64=HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenCL\Vendors SET ROOTKEY32=HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Khronos\OpenCL\Vendors -echo Currently installed OpenCL Client Driver's - 64bit +echo Currently installed OpenCL Client Drivers - 64bit echo ================================================== -for /f "tokens=1,*" %%A in ('reg query %ROOTKEY64%') do ( - echo %%A - %%B -) +reg query %ROOTKEY64% >nul 2>&1 && ( + for /f "tokens=1,*" %%A in ('reg query %ROOTKEY64%') do echo %%A - %%B +) || echo (none) echo: -echo Currently installed OpenCL Client Driver's - 32bit +echo Currently installed OpenCL Client Drivers - 32bit echo ================================================== -for /f "tokens=1,*" %%A in ('reg query %ROOTKEY32%') do ( - echo %%A - %%B -) -echo: - +reg query %ROOTKEY32% >nul 2>&1 && ( + for /f "tokens=1,*" %%A in ('reg query %ROOTKEY32%') do echo %%A - %%B +) || echo (none) echo: -echo This script will now attempt to find and install unregistered OpenCL AMD drivers from Windows (Fast Scan). -:askUserFastScan +echo This script will now attempt to find and install unregistered OpenCL AMD drivers (Fast Scan). set "INPUT=" set /P "INPUT=Do you want to continue? (Y/N): " -if /I "!INPUT!" == "Y" ( - echo: +if /I "!INPUT!"=="Y" ( echo: goto :scanFilesFast -) else if /I "!INPUT!" == "N" ( - goto :exit ) else ( - goto :askUserFastScan + goto :exit ) :scanFilesFast @@ -61,41 +57,41 @@ echo Running AMD OpenCL Driver Auto Detection echo ======================================== echo: -echo Scanning '%SYSTEMROOT%\system32' for 'amdocl*.dll' files, please wait... -echo: +echo Scanning '%SYSTEMROOT%\System32' for 'amdocl*.dll' files... +cd /d %SYSTEMROOT%\System32 +call :registerMissingClientDriver -cd /d %SYSTEMROOT%\system32 +echo: +echo Scanning '%SYSTEMROOT%\SysWOW64' for 'amdocl*.dll' files... +cd /d %SYSTEMROOT%\SysWOW64 call :registerMissingClientDriver echo: echo Fast Scan complete. echo: -echo: -echo This script will now attempt to find and install any unregistered OpenCL AMD drivers found on your computer (Full Scan). - -:askUserFullScan +echo This script will now attempt a Full Scan (PATH). set "INPUT=" set /P "INPUT=Do you want to continue? (Y/N): " -if /I "!INPUT!" == "Y" ( - echo: - echo: +if /I "!INPUT!"=="Y" ( goto :scanFilesFull -) else if /I "!INPUT!" == "N" ( - goto :complete ) else ( - goto :askUserFullScan + goto :complete ) - :scanFilesFull -echo Now scanning your PATH for 'amdocl*.dll' files, please wait... +echo Now scanning your PATH for 'amdocl*.dll' files... echo: for %%A in ("%path:;=";"%") do ( if "%%~A" neq "" ( - cd /d %%A - call :registerMissingClientDriver + if exist "%%~A\" ( + pushd "%%~A" >nul 2>&1 + if !ERRORLEVEL! == 0 ( + call :registerMissingClientDriver + popd + ) + ) ) ) @@ -104,50 +100,80 @@ echo Full Scan complete. echo: :complete -echo: echo Done. -echo: pause +goto :exit :exit exit /b 0 +REM ============================================================ +REM Register missing client drivers +REM ============================================================ :registerMissingClientDriver -for /r %%f in (amdocl*dll) do ( - set FILE="%%~dpnxf" +for /r %%f in (amdocl*.dll) do ( + set FILE=%%~dpnxf + set NAME=%%~nxf + + REM Accept fixed names and versioned variants (only real AMD files) + set "VALID=" + if /I "!NAME!"=="amdocl.dll" ( + set "VALID=1" + ) else if /I "!NAME!"=="amdocl64.dll" ( + set "VALID=1" + ) else if /I "!NAME!"=="amdocl12cl.dll" ( + set "VALID=1" + ) else if /I "!NAME!"=="amdocl12cl64.dll" ( + set "VALID=1" + ) else ( + REM Versioned variants used by AMD releases + echo !NAME! | findstr /C:"amdocl64_" >nul && set "VALID=1" + echo !NAME! | findstr /C:"amdocl_" >nul && set "VALID=1" + ) - for %%A in (amdocl.dll amdocl12cl.dll amdocl12cl64.dll amdocl32.dll amdocl64.dll) do ( - if "%%~nxf"=="%%A" ( - echo Found: !FILE! + if defined VALID ( + echo Found: !FILE! - echo !FILE! | findstr /C:"_amd64_" >nul + REM Bitness detection (prefer explicit 64, otherwise default to 32) + if /I "!NAME!"=="amdocl64.dll" ( + set "ROOTKEY=!ROOTKEY64!" + ) else if /I "!NAME!"=="amdocl12cl64.dll" ( + set "ROOTKEY=!ROOTKEY64!" + ) else ( + echo !NAME! | findstr /C:"amdocl64_" >nul if !ERRORLEVEL! == 0 ( set "ROOTKEY=!ROOTKEY64!" ) else ( - set FILE_BIT=!FILE:~-7,-5! - if !FILE_BIT! == 64 ( - set "ROOTKEY=!ROOTKEY64!" - ) else ( - set "ROOTKEY=!ROOTKEY32!" - ) + REM Default to 32-bit if not matched above + set "ROOTKEY=!ROOTKEY32!" ) + ) - reg query !ROOTKEY! >nul 2>&1 - if !ERRORLEVEL! neq 0 ( - reg add !ROOTKEY! /f + REM Ensure root key exists + reg query !ROOTKEY! >nul 2>&1 + if !ERRORLEVEL! neq 0 ( + reg add !ROOTKEY! /f >nul 2>&1 + if !ERRORLEVEL! == 0 ( echo Added Key: !ROOTKEY! + ) else ( + echo ERROR: Failed to add key !ROOTKEY! ) + ) - reg query !ROOTKEY! /v !FILE! >nul 2>&1 - - if !ERRORLEVEL! neq 0 ( - reg add !ROOTKEY! /v !FILE! /t REG_DWORD /d 0 /f >nul 2>&1 - - if !ERRORLEVEL! == 0 ( - echo Installed: !FILE! - ) + REM Register DLL if missing + reg query !ROOTKEY! /v "!FILE!" >nul 2>&1 + if !ERRORLEVEL! neq 0 ( + reg add !ROOTKEY! /v "!FILE!" /t REG_DWORD /d 0 /f >nul 2>&1 + if !ERRORLEVEL! == 0 ( + echo Registered: !FILE! + ) else ( + echo ERROR: Failed to register !FILE! ) + ) else ( + echo Already present: !FILE! ) ) + REM Reset VALID for next iteration + set "VALID=" ) goto :eof