0

Looks like SHGetSetFolderCustomSettings allows you to set an icon, a tooltip, a web view template and stuff, but I could not find how to set the LocalizedResourceName in the associated desktop.ini (see SHFOLDERCUSTOMSETTINGS structure).

Therefore I am currently writing to desktop.ini directly, however this comes with a caveat: Explorer does not properly update its views even when you tell it to refresh with F5 or Ctrl+R.

This is what I want to write, using Python (though non-Python code should be less of an issue):

[.ShellClassInfo]
LocalizedResourceName=My Folder Name
InfoTip=A customized folder

Any ideas how to set the folder name and have Explorer properly update it ?

I have tried with SHChangeNotify(SHCNE_ALLEVENTS, SHCNF_PATH, path, path), but this does not seem to update the display name (and also with SHCNE_RENAMEFOLDER, SHCNE_RENAMEITEM, SHCNE_UPDATEDIR, SHCNE_UPDATEITEM).

(The worst approach would probably be to edit the desktop.ini twice... once directly, then with that API function... rather not what I want).

About the why (I guess at least one of you will ask):

I am storing project data using GUIDs as folder names.

The user should however see a friendly name that can also be used for sorting (and maybe even be able to edit it without interfering with the internal name). Furthermore, the low-level file system layout should be backwards-compatible with older versions of the software.

Arc
  • 11,143
  • 4
  • 52
  • 75

1 Answers1

1

Use simple call of IShellFolder.SetNameOf:

procedure UpdateLocalizedResourceName(const ADirectory, ANewResourceName: UnicodeString);
var
  Desktop: IShellFolder;
  Eaten: DWORD;
  DirIDList1, Child, NewChild: PItemIDList;
  Attr: DWORD;
  Folder: IShellFolder;
begin
  OleCheck(SHGetDesktopFolder(Desktop));
  try
    Attr := 0;
    OleCheck(Desktop.ParseDisplayName(0, nil, PWideChar(ADirectory), Eaten, DirIDList1, Attr));
    try
      OleCheck(SHBindToParent(DirIDList1, IShellFolder, Pointer(Folder), Child));
      try
        OleCheck(Folder.SetNameOf(0, Child, PWideChar(ANewResourceName), SHGDN_INFOLDER, NewChild));
        CoTaskMemFree(NewChild);
      finally
        Folder := nil;
      end;
    finally
      CoTaskMemFree(DirIDList1);
    end;
  finally
    Desktop := nil;
  end;
end;

UPDATE

Important notice! LocalizedResourceName parameter must exists in desktop.ini before you call UpdateLocalizedResourceName. Otherwise SetNameOf function fails.

Denis Anisimov
  • 3,297
  • 1
  • 10
  • 18
  • Hm, looks more complicated than I had hoped for... I also want to set an info tip, so would I have to use some combo of `desktop.ini` handling, `IShellFolder.SetNameOf()` and/or `SHGetSetFolderCustomSettings()`, or is there some more efficient way to accomplish my goal ? For a little bit more context: I am working on a Python solution interfacing with Windows APIs, so everything is possible but a bit more cumbersome than in Windows languages. – Arc Nov 29 '14 at 06:56
  • @Archimedix As I understand you must use combination of SHGetSetFolderCustomSettings and IShellFolder.SetNameOf. – Denis Anisimov Nov 29 '14 at 09:35
  • 2
    SHSetLocalizsedName does this at one shot. – Raymond Chen Nov 29 '14 at 14:48
  • @RaymondChen, how would I call [`SHSetLocalizedName()`](http://msdn.microsoft.com/en-us/library/windows/desktop/bb762250%28v=vs.85%29.aspx) to set an arbitrary string ? The documentation says that it is called with the path whose display name should be set, a resource file with the localized string and a resource ID. According to the documentation, the function will also persist the text in the registry, rather than in `desktop.ini`, which is a bit confusing. – Arc Dec 01 '14 at 08:32
  • Looks like `SHSetLocalizedName()` does not support arbitrary strings but only references to resource files like DLLs. – Arc Dec 01 '14 at 08:49
  • True, SHSetLocalizedName requires a DLL and resource. Using the LocalizedResourceName to set a non-localized resource name is not really the intent of LocalizedResourceName. – Raymond Chen Dec 01 '14 at 18:57