I am attempting to change the icon of a folder. The code below does all what I found online says to do but the icon never changes. Am I maybe not "Applying" the change?
string createdFile = Path.Combine(@"C:\Users\np\Desktop\PUTEST", "desktop.ini");
if (File.Exists(createdFile))
{
var di = new DirectoryInfo(createdFile);
di.Attributes &= ~FileAttributes.ReadOnly;
File.Delete(createdFile);
File.Create(createdFile).Dispose();
}
else
{
File.Create(createdFile).Dispose();
}
//string iconPath = @"%SystemRoot%\system32\SHELL32.dll";
string iconPath = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\SHELL32.dll");
string iconIndex = "-183";
using (TextWriter tw = new StreamWriter(createdFile))
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
File.SetAttributes(createdFile, System.IO.FileAttributes.ReadOnly);
File.SetAttributes(createdFile, System.IO.FileAttributes.System);
File.SetAttributes(createdFile, System.IO.FileAttributes.Hidden);
When crafting a file like this it's always good to do so using Explorer or Notepad first, then write/adjust your code to match whatever was produced. Otherwise, it's harder to figure out if the problem is with your file or your code.
I believe the minimum requirements to make this work is
Desktop.inimust be markedSystemand the parent directory must be markedReadOnly(Systemmay work there as well, but I knowReadOnlydefinitely does). So, your code is working with the right attributes, but there are still a few problems.Your
if ... else ...block is saying "If a file exists at this path, create a directory at that path, then delete the file at that path, then create a file at that path." Of course, the directory should not and cannot have the same path as the file. I assume you are deleting and recreating the file to clear the contents when it already exists, howeverFile.Create()overwrites (truncates) existing files, making the calls to bothFile.Delete()andFile.Exists()unnecessary.More importantly is this line...
...with which there are two problems. First, you are ANDing the directory's attributes with the negation of
ReadOnly, which has the effect of removingReadOnlyand keeping the other attributes the same. You want to ensureReadOnlyis set on the directory, so you want to do the opposite of the code you used: OR the directory's attributes withReadOnly(not negated)...Also, you need that attribute set regardless of whether you created the directory or not, so that line should be moved outside of the
if ... else ....Another issue is the successive calls to
File.SetAttributes(). After those three calls the file's attributes will be onlyHidden, since that was the value of the last call. Instead, you need to combine (bitwise OR) those attributes in a single call.A couple of other minor tweaks...
Dispose()on it,File.Create()returns aFileStreamto that file. Instead of throwing it away, you could use it to create yourStreamWriter, which will have to create one, anyways, under the covers. Better yet, callFile.CreateText()instead and it will create theStreamWriterfor you.Desktop.inifiles, so you don't have to expand them yourself. This would make the file portable between systems if, say, you copied it from one system to another, or the directory is on a network share accessed by multiple systems with different%SystemRoot%values.Incorporating all of the above changes your code becomes...
One catch is that the above code throws an exception if you run it twice in succession. This is because the
File.Create*()methods fail if the input file isHiddenorReadOnly. We could usenew FileStream()as an alternative, but that still throws an exception if the file isReadOnly. Instead, we'll just have to remove those attributes from any existing input file before opening it...I changed from using
FiletoFileInfosince that makes this a little easier.