1

I am making a project involving the icons of the folders on my windows desktop. When I change the icon with python, the change doesn't occur immediately. You have to refresh it somehow (for example restart your laptop). And to counter this I searched the internet and found this piece of code from this github page: https://github.com/sunshowers/iconrefresher/blob/master/refresh-icons.py

def update_folder_icon():
    # !/usr/bin/env python

    # Released to the public domain.
    # http://creativecommons.org/publicdomain/zero/1.0/

    import ctypes
    from ctypes import wintypes

    # http://msdn.microsoft.com/en-us/library/ms644950
    SendMessageTimeout = ctypes.windll.user32.SendMessageTimeoutA
    SendMessageTimeout.restype = wintypes.LPARAM  # aka LRESULT
    SendMessageTimeout.argtypes = [wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM,
                                   wintypes.UINT, wintypes.UINT, ctypes.c_void_p]

    # http://msdn.microsoft.com/en-us/library/bb762118
    SHChangeNotify = ctypes.windll.shell32.SHChangeNotify
    SHChangeNotify.restype = None
    SHChangeNotify.argtypes = [wintypes.LONG, wintypes.UINT, wintypes.LPCVOID, wintypes.LPCVOID]

    HWND_BROADCAST = 0xFFFF
    WM_SETTINGCHANGE = 0x001A
    SMTO_ABORTIFHUNG = 0x0002
    SHCNE_ASSOCCHANGED = 0x08000000

    SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_ABORTIFHUNG, 5000, None)
    SHChangeNotify(SHCNE_ASSOCCHANGED, 0, None, None)

Everytime I use this code all of the folder icons refresh and blink. I need to use this code very often in my project (as often as every 3 seconds) so it would be nice to not see the blinking effect every single time. So my question is: Is there a way for me to only update one specific folder by for example passing the folder path as a parameter to the update_folder_icon() function?


Here is the code I use to change the icons of folder:

def set_folder_icon(folder_path, icon_path):
    if not os.path.isdir(folder_path):
        print("Folder Required To Set The Icon!")
        return

    shell32 = ctypes.windll.shell32

    folder_path = os.path.abspath(folder_path)
    icon_path = os.path.abspath(icon_path)

    fcs = SHFOLDERCUSTOMSETTINGS()
    fcs.dwSize = sizeof(fcs)
    fcs.dwMask = FCSM_ICONFILE
    fcs.pszIconFile = icon_path
    fcs.cchIconFile = 0
    fcs.iIconIndex = 0

    hr = shell32.SHGetSetFolderCustomSettings(byref(fcs), folder_path, FCS_FORCEWRITE)
    if hr:
        raise WindowsError(win32api.FormatMessage(hr))

    sfi = SHFILEINFO()
    hr = shell32.SHGetFileInfoW(folder_path, 0, byref(sfi), sizeof(sfi),
                                SHGFI_ICONLOCATION)

    if hr == 0:
        raise WindowsError(win32api.FormatMessage(hr))

    shell32.SHUpdateImageW(sfi.szDisplayName, sfi.iIcon, 0, 0)

Other possibly useful information:

  • Windows Version: Windows 11
  • Python version: 3.8
  • IDE: Pycharm
Progrix
  • 36
  • 5
  • SHCNE_ASSOCCHANGED is too agressive and a bit of a lie – Anders Apr 23 '22 at 17:32
  • 1
    Could you elaborate a little? – Progrix Apr 23 '22 at 17:36
  • I assume you are changing Desktop.ini and not real a file association – Anders Apr 23 '22 at 17:40
  • I doubt the last parameter to SHUpdateImageW can be 0. I can't even reproduce your issue, calling SHGetSetFolderCustomSettings by itself updates the icon correctly for me. And it works correctly on XP, 8 and 10 (I don't have 11 though). – Anders Apr 23 '22 at 23:50
  • @Anders The problem is not, that it does not work, it simply is too distracting when it is working. The folder icons blink and then change, but not only the folder's that have a different icon every single folder blinks. And since I do this process every 3 seconds, the blinking becomes a bit annoying. – Progrix Apr 24 '22 at 00:09
  • 1
    SHCNE_ASSOCCHANGED is probably causing the blink since it might invalidate the entire icon cache. If you claim SHGetSetFolderCustomSettings works for you, what is the point of the other update code? – Anders Apr 24 '22 at 00:11
  • @Anders When I change the icon of a folder with python, it works fine but then I change the icon again in the same python script the change does not occur at least not visually. If you open the folder you can see that the icon has changed in the corner, but the icon of the folder on the desktop still remains the same. – Progrix Apr 24 '22 at 01:04
  • My (C++) code is just `SetFolderIcon(L"c:\\users\\anders\\desktop\\dummy", L"c:\\windows\\system32\\shell32.dll", 10+(GetTickCount()%10));` and SetFolderIcon just calls SHGetSetFolderCustomSettings (and no other functions). The icon changes every time I run it, no flickering. – Anders Apr 24 '22 at 01:11

1 Answers1

0

I managed to solve the issue. The issue wasn't really the code itself, it was more like a windows bug. When you set the icon of a folder the first time it works, but when you change the icon again, but the icon file has the same name then the change doesn't happen. So to counter this you either have to do something aggressive like SHCNE_ASSOCCHANGED or simply use a different icon file name.

Progrix
  • 36
  • 5