C# How to set folder icon?
Asked Answered
L

5

5

I use FilePathDialog.SelectedPath get folder's path I also know icon's path but i don't know how to set that folder's icon

Lefty answered 30/6, 2011 at 8:16 Comment(0)
V
5

It seems important to set some file attributes.

Based on https://github.com/dimuththarindu/FIC-Folder-Icon-Changer here is the slimmed down version.

Within the folder, whose attribute you want to set, create three files:

  • MyIcon.ico

  • The icon you want to display. You may use a different file name.

  • desktop.ini - Containing the below text

    [.ShellClassInfo]

    IconResource=MyIcon.ico,0

    [ViewState]

    Mode=

    Vid=

    FolderType=Generic

  • .hidden- Containing the below text

    desktop.ini

    MyIcon.ico

File types in my case were UTF-8 with BOM.

Then you need to set attributes for all three files to

  • hidden

  • readonly

Finally, you need to notify the system that a change occurred

SHChangeNotify(0x08000000, 0x0000, (IntPtr)null, (IntPtr)null);

Assuming you created a Visual Studio solution with a folder named Resources holding your three files, here's the code to set the icon:

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace SetFolderIcon
{
    class Program
    {
        [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern void SHChangeNotify(
            int wEventId, int uFlags, IntPtr dwItem1, IntPtr dwItem2);

        static void Main(string[] args)
        {
            string location = $"C:\\Users\\Balint\\Desktop";
            string folderPath = Path.Combine(location, "My Folder");

            string desktopIniPath = Path.Combine(folderPath, "desktop.ini");
            string iconPath = Path.Combine(folderPath, "MyIcon.ico");
            string hiddenPath = Path.Combine(folderPath, ".hidden");

            Directory.CreateDirectory(folderPath);

            File.Copy($"Resources\\desktop.ini", desktopIniPath);
            File.Copy($"Resources\\Klinng.ico", iconPath);
            File.Copy($"Resources\\.hidden", hiddenPath);

            File.SetAttributes(desktopIniPath,
                File.GetAttributes(desktopIniPath)
                | FileAttributes.Hidden
                | FileAttributes.ReadOnly);
            File.SetAttributes(iconPath,
                File.GetAttributes(iconPath)
                | FileAttributes.Hidden
                | FileAttributes.ReadOnly);
            File.SetAttributes(hiddenPath,
                File.GetAttributes(hiddenPath)
                | FileAttributes.Hidden
                | FileAttributes.ReadOnly);
            File.SetAttributes(folderPath,
                File.GetAttributes(folderPath)
                | FileAttributes.ReadOnly);

            SHChangeNotify(0x08000000, 0x0000, (IntPtr)null, (IntPtr)null);
        }
    }
}
Venereal answered 29/3, 2020 at 17:44 Comment(2)
No need for [ViewState] section in desktop.ini woth those values, because it is possible you overwrite an existing desktop.ini which has different values, anyways, its not need for setting a folder icon. Also why make the .hidden file? I observed no change if I don't make it. Also no need for SHChangeNotify really, Explorer automatically shows iconKnightly
or you may use the nuget package[windows Icon Changer] [Disclaimer- I'm the author nuget.org/packages/Nakshatra.Windows.IconChangerStokeontrent
H
3

You have to write the desktop.ini file.

[.ShellClassInfo]
IconResource=Icon.ico,0
IconFile=Icon.ico
IconIndex=0
[ViewState]
Mode=
Vid=
FolderType=Pictures

C# code

string dir = "Folder Path";   
string[] lines = { "[.ShellClassInfo]", "IconResource=Icon.ico,0", "[ViewState]", "Mode=", "Vid=", "FolderType=Pictures" };
File.WriteAllLines(dir + @"\desktop.ini", lines);

IconResource: {Icon Path},0
FolderTypes: Generic, Documents, Pictures, Music, Videos

If you need more information, check this GitHub project: https://github.com/FIC-Folder-Icon-Changer

Henriquez answered 21/8, 2018 at 5:12 Comment(0)
M
1

There is a GitHub project Vanara, which wraps Windows P/Invoke Methods in very nice and well maintained nuget packages.

For your purpose I would suggest Vanara.PInvoke.Shell32.

I tested it in Visual Studio 2022 with .NET 8 with nuget Vanara.PInvoke.Shell32 v3.4.17 with a Command Line tool.

using Vanara.PInvoke;

using static Vanara.PInvoke.Shell32;

SetIconToFolder(@"C:\my folder", @"C:\my folder\my icon.ico");

static void SetIconToFolder(string folder, string? fullFilenameToIcon = null)
{
    if (string.IsNullOrWhiteSpace(fullFilenameToIcon)) return;

    HRESULT result;

    SHFOLDERCUSTOMSETTINGS folderSettings = default;
    result = Shell32.SHGetSetFolderCustomSettings(ref folderSettings, folder, FCS.FCS_READ);
    if (result == HRESULT.S_OK)
    {
        folderSettings.dwMask = FOLDERCUSTOMSETTINGSMASK.FCSM_ICONFILE;

        folderSettings.pszIconFile = fullFilenameToIcon;

        result = Shell32.SHGetSetFolderCustomSettings(ref folderSettings, folder, FCS.FCS_WRITE);
        if (result != HRESULT.S_OK)
        {
            throw new Exception($"Error with {result}");
        }
    }
}

Important: Don't forget to set folderSettings.dwMask = FOLDERCUSTOMSETTINGSMASK.FCSM_ICONFILE; :-) This took me a while to figure that missing value out,

I was trying to use, also this notation "shell32.dll,-44" to get a yellow star from the Windows Icons, but I failed. Just as an info for you.

...
- folderSettings.pszIconFile = fullFilenameToIcon;
+ folderSettings.pszIconFile = "shell32.dll";
+ folderSettings.iIconIndex = -44; // 44;
...
Minnow answered 25/3 at 16:53 Comment(0)
A
0

There are basically two steps involved in assigning an icon to a folder (or possibly three steps, if you count creating the folder):

Create a desktop.ini file inside the folder for which to create the icon (the "Target Folder"). Set the Target Folder's attribute to "System".

more :

Create Icons for Folders in Windows Explorer, Using C#

Apiece answered 9/10, 2020 at 12:25 Comment(0)
O
0

If you want the folder icon to change immediately, every time (and of course you do), you need to add a "zero width" space to the folder name too. This will trigger an instant refresh of the folder. You can do this like this:

string tempFolderPath = folderPath + "\u200B"; 
Directory.Move(folderPath, tempFolderPath);
Overuse answered 25/3 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.