0

I am trying to prepare an application similar to 'Windows Start Menu Search'.

That's why I need each applications own icon.

From the C:\ProgramData\Start Menu\Programs\ file path, I add existing applications to a list (QListWidget) with their names and path.

And I get the icons like this: https://forum.qt.io/topic/62866/getting-icon-from-external-applications

provider = QFileIconProvider()
info = QFileInfo("program_path")
icon = QIcon(provider.icon(info))

And naturally the result is this: IMAGE 1

But I don't want this "shortcut icon" to appear.

enter image description here

Then, I am thinking and I came to this conclusion:

shell = win32com.client.Dispatch("WScript.Shell")
provider = QFileIconProvider()
shortcut = shell.CreateShortCut(programPath)
info = QFileInfo(shortcut.targetPath)
icon = QIcon(provider.icon(info))

This solution worked. But, It has created issue for some applications. So I am looking for an alternative solution.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Mustafa AHCI
  • 169
  • 2
  • 12

1 Answers1

1

You were almost there.

Browsing the menu directory tree is actually the right path, but you also have to ensure that the icon of the link is actually the same of the target, as it might not.
The shortcut.iconlocation is a string representing a "tuple" (sort of) including the icon path and the index (as icon resources might contain more than one icon).

>>> shortcut = shell.createShortCut(linkPath)
>>> print(shortcut.iconlocation)
# most links will return this:
> ",0"
# some might return this:
> ",4"
# or this:
> "C:\SomePath\SomeProgram\SomeExe.exe,5"

As long as the icon index is 0, you can get the icon using QFileIconProvider with the targetPath or iconLocation (if there's something before the comma).

The problem comes when there's a value different from 0 for the icon index, as Qt doesn't handle that.

I've put together a simple function (based on some research here on StackOverflow).

def getIcon(self, shortcut):
    iconPath, iconId = shortcut.iconLocation.split(',')
    iconId = int(iconId)
    if not iconPath:
        iconPath = shortcut.targetPath
    iconPath = os.path.expandvars(iconPath)
    if not iconId:
        return QICon(self.iconProvider.icon(QFileInfo(iconPath)))

    iconRes = win32gui.ExtractIconEx(iconPath, iconId)
    hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
    hbmp = win32ui.CreateBitmap()
    # I think there's a way to find available icon sizes, I'll leave it up to you
    hbmp.CreateCompatibleBitmap(hdc, 32, 32)
    hdc = hdc.CreateCompatibleDC()
    hdc.SelectObject(hbmp)
    hdc.DrawIcon((0, 0), iconRes[0][0])
    hdc.DeleteDC()
    # the original QtGui.QPixmap.fromWinHBITMAP is now part of the
    # QtWin sub-module
    return QtGui.QIcon(QtWin.fromWinHBITMAP(hbmp.GetHandle(), 2))
musicamante
  • 41,230
  • 6
  • 33
  • 58