Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Icon Disappears or Displays Incorrectly When Target and Icon Files Differ in Shortcuts #1236

Open
undecV opened this issue Oct 24, 2024 · 2 comments

Comments

@undecV
Copy link

undecV commented Oct 24, 2024

Describe the bug
When the Target and Icon for a shortcut are not the same file, Ueli displays the icon from the Target instead of the one specified in the shortcut properties. This results in the icon either disappearing or showing incorrectly, as illustrated in the screenshots below.

To Reproduce
No additional steps are needed if you already have shortcuts where the Target and Icon files differ.
Otherwise, follow these steps:

  • Create a shortcut where the Target and Icon files are different. (Refer to Fig 2 and Fig 4)
  • In Ueli, go to Settings -> Extensions -> Application Search, and click Rescan.
  • Check the search results in Ueli. You’ll see that the wrong icon is displayed or the icon is missing. (Refer to Fig 1 and Fig 3)

Expected behavior
Ueli should correctly display the icon that is specified in the shortcut's properties, even when it points to a different file than the Target.

Screenshots
Fig 1: The icon disappears or is incorrectly displayed when the Target and Icon files are different.

Fig 1

Fig 2: Properties of two files—the native Discord icon on the left displays correctly, while the custom icon I created (right) does not. I used %LOCALAPPDATA% to anonymize the path.

Fig 2

Fig 3 shows search results in Ueli with an incorrect icon for the shortcut "LAV Video (MPC-HC internal)," where the Target is mpc-hc64.exe and the icon is lavvideo.ax.

Fig 3

Finally, Fig 4 shows the properties of this shortcut, confirming that the icon file is not the same as the Target:

Fig 4

Environment

  • OS: Windows 11 23H2 (22635.4371)
  • Ueli Version: 9.8.0 (tested on Zip versions only)

Additional context
This issue is inherited from [#1133].

@undecV
Copy link
Author

undecV commented Feb 15, 2025

I tried digging into this issue, but I have zero experience with JavaScript and PowerShell 😵‍💫.

I found some related code in the file powershellScripts.ts.

This method can extract the correct icon by following the existing code and looking up some documentation. Here’s what I found:

$ShortcutFilePath = $env:APPDATA + "\Microsoft\Windows\Start Menu\Programs\Discord Inc\Discord.lnk"
# The `Discord.lnk` shortcut actually call "%LOCALAPPDATA%\Discord\Update.exe --processStart Discord.exe"
# and the icon is pointing to "%LOCALAPPDATA%\Discord\app.ico"

$Shell = New-Object -ComObject WScript.Shell
$Shortcut = $Shell.CreateShortcut($ShortcutFilePath)
$TargetPath = $Shortcut.TargetPath
$IconLocation = $Shortcut.IconLocation

Write-Output $TargetPath
# > %LOCALAPPDATA%\Discord\Update.exe
# Which has no icon.

Write-Output $IconLocation
# > %LOCALAPPDATA%\Discord\app.ico,0
# Which are the real icon path and its ID that refers to the file.
# Reference: https://msdn.microsoft.com/en-us/library/xsy6k3ys(v=vs.84).aspx

# Split Icon Location
if ($IconLocation -match "^(.*?),(\d+)$") {
    $IconPath = $matches[1].Trim()
    $IconId = $matches[2].Trim()
}
else {
    $IconPath = $IconLocation.Trim()
    $IconId = 0
}

Add-Type -AssemblyName System.Drawing

$Icon = [System.Drawing.Icon]::ExtractIcon($IconPath, $IconID)
# In my test, it retun 16x16 icon, wether bool smallIcon is true or false.

$Icon = [System.Drawing.Icon]::ExtractIcon($IconPath, $IconID, 256)
# Reference: https://learn.microsoft.com/en-us/dotnet/api/system.drawing.icon.extracticon

$OutFilePath = "./out.png"
$Icon.ToBitmap().Save($OutFilePath, [System.Drawing.Imaging.ImageFormat]::Png)

@undecV
Copy link
Author

undecV commented Feb 15, 2025

Based on the above test,
I tried replacing the PowerShell part in powershellScripts.ts with the following code,
But it doesn't seem to be working :(
(But this code works directly in my PowerShell.)

I hope this information helps at least a little!

function Get-Shortcut-Icon {
    param([string]$ShortcutFilePath)

    try {
        $Shell = New-Object -ComObject WScript.Shell
        $Shortcut = $Shell.CreateShortcut($ShortcutFilePath)
        $TargetPath = $Shortcut.TargetPath
        $IconLocation = $Shortcut.IconLocation

        if ($IconLocation -match "^(.*?),(\d+)$") {
            $IconPath = $matches[1].Trim()
            $IconId = $matches[2].Trim()
        }
        else {
            $IconPath = $IconLocation.Trim()
            $IconId = 0
        }

        $IconPathAccessible = Test-Path -Path $IconPath -PathType Leaf
        $TargetPathAccessible = Test-Path -Path $TargetPath -PathType Leaf
        if ($IconPathAccessible) {
            $Icon = [System.Drawing.Icon]::ExtractIcon($IconPath, $IconID, 256)
        }
        elseif ($TargetPathAccessible) {
            $Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($TargetPath)
        }
        else {
            $Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($ShortcutFilePath)
        }

        return $Icon
    }
    catch {
        return $null
    }
}

function Get-Associated-Icon {
    param(
        [string]$InFilePath,
        [string]$OutFilePath
    )

    $ErrorActionPreference = "SilentlyContinue"
    Add-Type -AssemblyName System.Drawing

    if ($InFilePath.EndsWith(".lnk")) {
        $Icon = Get-Shortcut-Icon -ShortcutFilePath $InFilePath
    }
    else {
        $Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($InFilePath)
    }

    if ($null -ne $Icon) {
        $Icon.ToBitmap().Save($OutFilePath, [System.Drawing.Imaging.ImageFormat]::Png)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants