0

I am changing the tag of a folder my either creating or modifying the desktop.ini file in Windows 10.

Without notifying the OS that it needs to refresh in some way, the tag takes an indeterminate amount of time to reflect as changed within Windows Explorer.

I am trying to use a Windows API function to notify the OS that an attribute on the folder has changed but it does not cause Windows Explorer to update. The following combinations have been tried:

        [DllImport("shell32.dll")]
    static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
                               HChangeNotifyFlags uFlags,
                               IntPtr dwItem1,
                               IntPtr dwItem2);


    public static void Refresh1()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_ATTRIBUTES, HChangeNotifyFlags.SHCNF_PATHW, ptr, IntPtr.Zero);
        Marshal.FreeHGlobal(ptr);   
    }

    public static void Refresh2()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test\desktop.ini");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_DELETE, HChangeNotifyFlags.SHCNF_PATHW, ptr, IntPtr.Zero);
        Marshal.FreeHGlobal(ptr);
    }

    public static void Refresh3()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test\desktop.ini");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM, HChangeNotifyFlags.SHCNF_PATHW, ptr, IntPtr.Zero);
        Marshal.FreeHGlobal(ptr);
    }

    public static void Refresh4()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM, HChangeNotifyFlags.SHCNF_PATHW, ptr, IntPtr.Zero);
        Marshal.FreeHGlobal(ptr);
    }

    public static void Refresh5()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_RENAMEFOLDER, HChangeNotifyFlags.SHCNF_PATHW, ptr, IntPtr.Zero);
        Marshal.FreeHGlobal(ptr);
    }

    public static void Refresh6()
    {
        var ptr = Marshal.StringToHGlobalUni(@"C:\tmp\test");
        SHChangeNotify(HChangeNotifyEventID.SHCNE_RENAMEFOLDER, HChangeNotifyFlags.SHCNF_PATHW, ptr, ptr);
        Marshal.FreeHGlobal(ptr);
    }

Based on the comments below I tried a different approach to Marshaling and the many permutations...

    [DllImport("shell32.dll")]
    static extern void SHChangeNotify(HChangeNotifyEventID wEventId, HChangeNotifyFlags uFlags, [MarshalAs(UnmanagedType.LPWStr)] string dwItem1, [MarshalAs(UnmanagedType.LPWStr)] string dwItem2);

    public static void Refresh1()
    {
        var str = @"C:\tmp\test";
        SHChangeNotify(HChangeNotifyEventID.SHCNE_ATTRIBUTES, HChangeNotifyFlags.SHCNF_PATHW, str, str);
    }


    public static void Refresh2()
    {
        var str = @"C:\tmp\test";
        SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM, HChangeNotifyFlags.SHCNF_PATHW, str, "");
    }


    public static void Refresh3()
    {
        var str = @"C:\tmp\test";
        SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM, HChangeNotifyFlags.SHCNF_PATHW, str, str);
    }

    public static void Refresh4()
    {
        var str = @"C:\tmp\test";
        SHChangeNotify(HChangeNotifyEventID.SHCNE_ATTRIBUTES, HChangeNotifyFlags.SHCNF_PATHW, str, "");
    }

I have also tried HChangeNotifyEventID.SHCNE_UPDATEDIR as an option for the first parameter but that also has not succesfully updated Windows Explorer.

How can I change the tag of a folder in such a manner that it automatically refreshes in Windows Explorer?

  1. Is their a way to modify the code above to do that?
  2. Is their another windows API function that I should call to refresh Windows Explorer after a change to desktop.ini (even though the naming of this one implies that it should do the job...)?
  3. Should I be using a specific Windows API call just to change the tag directly that has a built in notification to the OS?
Sam
  • 2,745
  • 3
  • 20
  • 42
  • 2
    You are marshalling a Unicode string, so why are you using `SHCNF_PATHA` (0x0001) instead of `SHCNF_PATHW` (0x0005)? – Remy Lebeau Apr 14 '21 at 21:15
  • @RemyLebeau thanks, I wasn't sure of the difference between those 2 path options but you have clarified for me. I have changed this in my question above AND code but it still does not update the Windows Explorer. – Sam Apr 14 '21 at 21:24
  • According to [this post](https://social.msdn.microsoft.com/Forums/sqlserver/en-US/745ef0ff-9659-4dea-8715-012f90836a9a/), you should use [`SHGetSetFolderCustomSettings()`](https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetsetfoldercustomsettings) instead of modifying `desktop.ini` directly: "*This function ... sends all necessary notification by itself.*" Though, I don't think this supports tags. – Remy Lebeau Apr 14 '21 at 21:39
  • According to [this post](https://stackoverflow.com/a/31642517/65863), try sending `SHCNE_DELETE` instead, specifying the path to the `desktop.ini` file itself. – Remy Lebeau Apr 14 '21 at 21:41
  • Or [this post](https://social.msdn.microsoft.com/Forums/en-US/dc6dc362-b2db-4aa5-87bd-97e45e1d7a65/), which suggests sending `SHCNE_RENAMEFOLDER` with both paths set to the same folder path – Remy Lebeau Apr 14 '21 at 21:46
  • Or [this post](https://stackoverflow.com/a/45922397/65863), which suggests sending `SHCNE_UPDATEITEM` with the folder path. – Remy Lebeau Apr 14 '21 at 21:46
  • 1
    You can define the function like this, it's easier, no allocation: `void SHChangeNotify(SHCNE wEventId, SHCNF uFlags, [MarshalAs(UnmanagedType.LPWStr)] string dwItem1, [MarshalAs(UnmanagedType.LPWStr)] string dwItem2)` I would use SHCNE_UPDATEITEM and SHCNF_PATHW on the desktop.ini file – Simon Mourier Apr 14 '21 at 21:47
  • @RemyLebeau I tried using SHCNE_DELETE and it did not work - results reported in edited question – Sam Apr 14 '21 at 21:50
  • @SimonMourier tried `SHCNE_UPDATEITEM` and `SHCNF_PATHW` on the desktop.ini file but it not force the update - added to my question of attempts – Sam Apr 14 '21 at 21:58
  • @RemyLebeau `SHCNE_UPDATEITEM` with folder path also not forcing the update – Sam Apr 14 '21 at 22:00
  • @RemyLebeau `SHCNE_RENAMEFOLDER` also didn't force the update. Question updated. – Sam Apr 14 '21 at 22:06
  • @Sam for `SHCNE_RENAMEFOLDER`, try passing in the folder path for *both* input paths, like I mentioned earlier: `SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATHW, ptr, ptr)` And have you tried removing `Marshal.StringToHGlobalUni()` like Simon suggested? – Remy Lebeau Apr 14 '21 at 22:10
  • @RemyLebeau I just tried using both input paths but also no-luck. Will have at removing the Marshalling now... – Sam Apr 14 '21 at 22:16
  • @Sam have you done any tests using `SHCNF_IDLIST` instead of `SHCNF_PATHW`? You can use `SHParseDisplayName()` or similar function to convert a path string into an `ITEMIDLIST`. – Remy Lebeau Apr 14 '21 at 22:22
  • @SimonMourier I tried your alternate definition of the API function in C# and it didn't cause any errors but none of the various redone permutations managed to update the Windows Folder. Question updated with further attempts – Sam Apr 14 '21 at 22:44
  • Have you tried [`SHGetSetFolderCustomSettings`](https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetsetfoldercustomsettings) api. Reference: [Custom folder icons with desktop.ini & instant refreshing](https://stackoverflow.com/questions/16945892/custom-folder-icons-with-desktop-ini-instant-refreshing/19440996#19440996) – Zeus Apr 15 '21 at 05:45
  • @SongZhu-MSFT (1) I am not sure where/how to set the tag in the related data structure `SHFOLDERCUSTOMSETTINGS` (2) even then I would prob need a small C# example to help me get started - I have never understood all those C++ pointers – Sam Apr 15 '21 at 06:34
  • I'm 100% sure what I gave you works for standard shell items, so it may be due to to what you expect from SHChangeNotify on a change to desktop.ini file which is a special file. – Simon Mourier Apr 15 '21 at 06:41
  • @Sam You can refer to this [link](https://social.msdn.microsoft.com/Forums/en-US/ba2fef7b-6733-4e1e-b8b9-f93ebf8725f0/pinvoke-into-shgetsetfoldercustomsettings?forum=clr) to learn how to call `SHGetSetFolderCustomSettings` in C# – Zeus Apr 15 '21 at 06:42
  • @SongZhu-MSFT i have the `SHGetSetFolderCustomSetting` working as per example but don't know what combination of the Settings will change the tag of the folder - most prior interest & examples relate to the file icon – Sam Apr 15 '21 at 20:21
  • @SongZhu-MSFT I can't see where I would actually put the `string` of the tag that I want for the folder within the data structure of `SHFOLDERCUSTOMSETTINGS` – Sam Apr 15 '21 at 20:45
  • As Simon said, I think the solution provided to you can be applied, perhaps because you have different expectations for the change of `desktop.ini`. – Zeus Apr 16 '21 at 02:55
  • What are you calling the `tag` of a folder? Folders don't support tags. – Keith Miller Jan 17 '22 at 06:02

0 Answers0