Click here to Skip to main content
15,884,176 members
Articles / Programming Languages / C#

Editor for Folder Metadata in C#

Rate me:
Please Sign up or sign in to vote.
4.81/5 (30 votes)
23 Feb 2024CPOL6 min read 35.5K   1.2K   57   24
Edit Metadata for folders by using desktop.ini features
This article describes the methods used for development of the folder metadata editor.

Introduction

The need for a folder metadata editor arose when I wanted to manage a bunch of folders without organizing them in sub-directories. When searching online, I found that desktop.ini (and thus Windows Explorer) supports what I am looking for - just Microsoft did not provide a user interface for it. So this is where the folder metadata editor comes in. It provides a simple method to edit these metadata.

Image 1

Background

Desktop.ini supports metadata for a folder if it contains the following:

Shell
[{F29F85E0-4FF9-1068-AB91-08002B27B3D9}]
Prop2=31,Title
Prop3=31,Subject
Prop4=31,Author
Prop5=31,Tag
Prop6=31,Comment

For reading and writing, the API functions GetPrivateProfileString and WritePrivateProfileString are used.

The folder metadata editor also supports simple argument parsing as well as localization.

Using the Code

The code is divided into these sub-name spaces:

  • Configuration
    • Argument parsing
    • Localization
    • Registration
  • Dialogs
    • Dialog forms
    • Extended ListBox control
    • Form helper classes and icon extraction from resources
  • Extensions
    • Extension of string and StringCollection classes
  • Generic
    • Loading/Writing of desktop.ini
    • Generic helper classes

Configuration

Argument Parsing

Argument parsing is done by the ArgParser class which makes use of the ParameterNames class.

The ParameterNames.cs file contains the ParameterNames class and the ParamConstants enumeration.

The ParseParamConstants function of the ParameterNames class converts a command line argument like /dir into the proper ParamConstants value ParamConstants.Dir.

The actual argument parsing is done in the ArgParser class. As this is a Windows.Forms application, we do not have a string[] args parameter in the main function. So the ArgParser class has a parameterless constructor and retrieves the command line arguments by using System.Environment.GetCommandLineArgs().

Registration

As the application is supposed to be used with folders, we need to register it in the Windows registry under HKEY_CLASSES_ROOT\Folder\shell. For this purpose, we create a new registry key FolderMetaData. The default value of this key represents the text in the shortcut menu (when right-clicking a folder in Windows Explorer). Underneath this registry key, we create another registry key command. The default value of the command key then contains the full path to the application along with the path of the folder, e.g., C:\Program Files\FolderMetadata\FolderMetadata.exe /dir "%1".

To allow the application to be used when right-clicking the background of a folder, we create another registry entry under HKEY_CLASSES_ROOT\Directory\Background\shell. The procedure is identical to before. Only difference here is that we do not use %1 as parameter, but %V.

When unregistering, the registry keys are identified by checking the default value of the command registry key. This allows to remove the registry key even if has been created with a different language.

Registration and unregistration is done by the Registrator class. You require administrative rights for these operations to succeed.

On the command line, use these commands to register or unregister:

  • FolderMetadata.exe /register
  • FolderMetadata.exe /unregister

Localization

Localization is handled by the LanguageConfigurator class. In most cases, it will just use the language of the environment it is running on. You can, however, also change the language either by specifying the /lang command line parameter (e.g., /lang ja for Japanese) or by selecting it by specifying command line parameter /lang select. In order to allow the language selection dialog to display a list of all supported languages, the GetSupportedLanguages function of the SupportedLanguages class must include it.

Localization of a Windows.Forms application is quite simple, if you deal with alphabetic languages. When dealing with non-alphabetic languages (e.g., Chinese and Japanese), this gets a little bit more of a challenge.

  1. Mnemonic support (the keyboard shortcut for a button, e.g., &Save) would not be present
  2. Handling simplified and traditional Chinese localization

As I wanted to keep the localization process simple, I leave most of it to the .NET Framework. So I set the Neutral language property for the FolderMetadata project to "English (United States)". and created a separate resource file Strings.resx. This file contains all translations + the value ForceMnemonics, which represents a bool value and must be either true or false. The parsed result is accessible in the ForceShowMnemonics property of the LanguageConfigurator class.

For the Chinese localization, I created two resource files:

  • Strings.zh.resx
  • Strings.zh-TW.resx

This means that all users except those with a Taiwan Windows setting would see simplified Chinese characters. This, however, does not work for users from Hong Kong and Macao. So I added the function GetLanguageZH that checks if it the language setting requires traditional Chinese display. If it does, it will change the language setting to zh-TW. Now the user can also see traditional Chinese characters.

Dialogs

Translating Dialogs

When having complex forms, it may be a good method to set the Localizable and Language properties of the forms. This allows to re-arrange controls for each language for example. This however makes editing the dialogs more difficult if you have many languages. This is why I decided against that approach and use a more hands-on approach: The use of TableLayoutPanel and the support class ButtonAdjustor to make the buttons have the same width.

Each form has a WndProc override. In this overridden function, we check if the ForceShowMnemonics property of the LanguageConfigurator class is true. If it is, it will call the ShowMnemonics method of the WndProcOverrides class, which ensures that the mnemonics are visible.

Help

The form FrmHelp contains help in HTML format. It is also translated into the various languages and opens when the user does one of these things:

  • Start the application without specifying any supported parameters (e.g., by double-click in Windows Explorer)
  • Specifies the /? command line parameter

Controls

The ListBoxEx control inherits from the ListBox of Windows.Forms. It provides some functions for loading values (which is used on the FrmMain form) and moving selected items (which is used on the FrmManage form).

Extensions

If you have not used extensions before, you missed out a very helpful .NET feature. Extensions allow you to add your own functions to classes. There is just one downside: You can only add instance functions, but not static functions à la string.IsNullOrEmpty.

Definition

C#
public static class String
{
    public static bool IsEmpty(this string s)
    {
        return (s.Length == 0);
    }
}

Usage

C#
using HKS.FolderMetadata.Extensions; //Add this on top of your class file,
                                     //preceding the name space definition.

//In your method, use something like this:

string s = "Hello";

if (s.IsEmpty())
{
  //Do something
}

Generic

Reading and Writing Desktop.ini

The functionality for reading and writing desktop.ini is in the Metadata class. As this program is intended for the Windows platform, we can use the API functions GetPrivateProfileString and WritePrivateProfileString for reading and writing.

In desktop.ini, all metadata properties are single line texts. As there may be more than one person who is the author (e.g., the Beatles songs were always written by John Lennon and Paul McCartney), or you want to set more than one tag, we have to convert a single line into a list and vice versa.

The constructor of the Metadata class expects the full path to the directory you want to edit the metadata. It will then assemble the full path to desktop.ini. The class has properties which are filled by the Load method and written to the file by the Save method.

History

  • 3rd January, 2021
    • First release
  • 15th July, 2021
    • v 1.0.1
      • Fixed memory exception
  • 24th February, 2024
    • v 2.0.0
      • Allow right-click on folder background to start application
      • Added icon to shortcut menu

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
Kamran Saeedi21-Jul-21 15:51
Kamran Saeedi21-Jul-21 15:51 
QuestionNice article Pin
Mou_kol21-Jul-21 8:07
Mou_kol21-Jul-21 8:07 
GeneralMy vote of 5 Pin
BillWoodruff18-Jul-21 13:33
professionalBillWoodruff18-Jul-21 13:33 
BugGetPrivateProfileString throwing System.AccessViolationException Pin
Rasqual Twilight13-Jul-21 12:42
Rasqual Twilight13-Jul-21 12:42 
GeneralRe: GetPrivateProfileString throwing System.AccessViolationException Pin
Martin Henke (1971)14-Jul-21 9:21
Martin Henke (1971)14-Jul-21 9:21 
Questionediting the metadata on files Pin
Daszbin31-May-21 18:29
professionalDaszbin31-May-21 18:29 
AnswerRe: editing the metadata on files Pin
Martin Henke (1971)31-May-21 21:10
Martin Henke (1971)31-May-21 21:10 
QuestionThank you for sharing Pin
Rudolf Jan10-Jan-21 23:24
Rudolf Jan10-Jan-21 23:24 
GeneralWorks once Pin
DavidPendleton9-Jan-21 10:25
DavidPendleton9-Jan-21 10:25 
GeneralRe: Works once Pin
Martin Henke (1971)9-Jan-21 23:57
Martin Henke (1971)9-Jan-21 23:57 
GeneralRe: Works once Pin
Peter Adam29-Feb-24 4:14
professionalPeter Adam29-Feb-24 4:14 
PraiseNeat and Clean ^5 Pin
Member 109506216-Jan-21 19:41
Member 109506216-Jan-21 19:41 
QuestionMy vote of 5 Pin
g_p_l5-Jan-21 10:48
g_p_l5-Jan-21 10:48 
GeneralMy vote of 3 Pin
Member 148962695-Jan-21 1:48
Member 148962695-Jan-21 1:48 
GeneralMy vote of 1 Pin
Vincent Radio4-Jan-21 13:55
professionalVincent Radio4-Jan-21 13:55 
Questionthoughts Pin
Nelek4-Jan-21 8:30
protectorNelek4-Jan-21 8:30 
AnswerRe: thoughts Pin
Martin Henke (1971)5-Jan-21 7:43
Martin Henke (1971)5-Jan-21 7:43 
QuestionScreenshot would be nice Pin
Sacha Barber3-Jan-21 23:56
Sacha Barber3-Jan-21 23:56 
AnswerRe: Screenshot would be nice Pin
Martin Henke (1971)4-Jan-21 7:30
Martin Henke (1971)4-Jan-21 7:30 
QuestionGood Job Pin
FredyAlfredo3-Jan-21 22:50
FredyAlfredo3-Jan-21 22:50 
AnswerRe: Good Job Pin
Martin Henke (1971)4-Jan-21 7:32
Martin Henke (1971)4-Jan-21 7:32 
GeneralRe: Good Job Pin
FredyAlfredo4-Jan-21 23:49
FredyAlfredo4-Jan-21 23:49 
GeneralRe: Good Job. how about posting an executable Pin
coderz25-Jan-21 13:09
coderz25-Jan-21 13:09 
GeneralRe: Good Job. how about posting an executable Pin
Martin Henke (1971)6-Jan-21 8:38
Martin Henke (1971)6-Jan-21 8:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.