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.ini
must be markedSystem
and the parent directory must be markedReadOnly
(System
may work there as well, but I knowReadOnly
definitely 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 removingReadOnly
and keeping the other attributes the same. You want to ensureReadOnly
is 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 aFileStream
to 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 theStreamWriter
for you.Desktop.ini
files, 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 isHidden
orReadOnly
. 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
File
toFileInfo
since that makes this a little easier.