从外部应用程序获取图标

时间:2019-12-29 13:47:20

标签: python python-3.x pyqt pyqt5

我正在尝试准备类似于“ Windows开始菜单搜索”的应用程序。

这就是为什么我需要每个应用程序都有自己的图标。

C:\ProgramData\Start Menu\Programs\文件路径中,将现有应用程序及其名称和路径添加到列表(QListWidget)

我得到这样的图标: https://forum.qt.io/topic/62866/getting-icon-from-external-applications

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

自然,结果是这样的: IMAGE 1

但是我不希望出现“快捷方式图标”。

enter image description here

然后,我在想,我得出了这个结论:

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

此解决方案有效。但是,它为某些应用程序创建了问题。 因此,我正在寻找一种替代解决方案。

1 个答案:

答案 0 :(得分:1)

你快到了。

浏览菜单目录树实际上是正确的路径,但是您还必须确保链接的图标实际上与目标的图标相同,或者可能与目标相同。
shortcut.iconlocation是一个字符串,表示包含图标路径和索引的“元组”(某种)(因为图标资源可能包含多个图标)。

>>> 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"

只要图标索引为0,就可以使用QFileIconProvider和targetPathiconLocation(如果逗号前有东西)来获取图标。

图标索引的值不同于0时会出现问题,因为Qt无法处理该值。

我整理了一个简单的函数(基于一些研究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))