Delphi: obtain list of file extensions by type

347 Views Asked by At

Is there a way to obtain a list of registered file extensions/types from Windows? Maybe GetExts('Video')?

1

There are 1 best solutions below

3
AmigoJack On

File formats

File formats by far not only belong to one category only - most formats which people call "video" are in fact containers (because they can carry more than video only, like: audio, subtitles, menus...). They are unbound to filenames, because filenames can have any form:

  • just because a file is named music.mp3 its actual content is not guaranteed to be MPEG-1 audio, and
  • an MPEG-4 container can have the filename extensions .mp4, .m4v, .m4a or even .co.uk.

How are filename extensions stored (in Windows)?

As per File Types the Registry stores them this way, which happens at least since Windows 95:

The general form of a file name extension subkey is as follows. All entry types are of the REG_SZ type.

HKEY_CLASSES_ROOT
   .ext
      (Default) = ProgID.ext.1
      Content Type = MIME content type
      PerceivedType = PerceivedType

...whereas:

Content Type: the file type's MIME content type

PerceivedType: to which the file belongs, if any. This string is not used by Windows versions prior to Windows Vista. For more information, see Perceived Types and Application Registration.

The latter eventually leads us to AssocGetPerceivedType(), but that function is only useful when we already know a filename extension. Most likely it's just a wrapper for reading the Registry keys and values.

So all we have to do is to:

  • enumerate the Registry's HKEY_CLASSES_ROOT key for all keys that start with a dot, and
  • per key examine the potential values
    • Content Type (can have something like video/mpeg) and/or
    • PerceivedType (can have video).

MIME database in Registry

As per Remy Lebeau and Is there a way to get an extension for a given content type? also this structure exists:

HKEY_CLASSES_ROOT
   MIME
      Database
         Content Type
            video/*
               Extension = .ext

This seems to be the Internet Explorer MIME Database as mentioned in Best Practices for File Associations. For every key that starts with video/ we could read its value with the name Extension to then know the filename extension. That should already exist as a key in the HKEY_CLASSES_ROOT root, tho, and not be something new that we'll find.

In Pascal

Delphi already comes with the wrapper class TRegistry for those not wanting to deal with the WinAPI functions directly.

uses
  Registry;

procedure TForm1.Button1Click(Sender: TObject);
const
  NAME_ContentType= 'Content Type';
  NAME_PerceivedType= 'PerceivedType';
  VALUE_video= 'video';
  KEY_MIME= 'MIME\Database\Content Type';  // Actually "HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MIME\Database" and "HKEY_CURRENT_USER\Software\Classes\MIME\DataBase" in one
  NAME_Extension= 'Extension';
var
  oReg: TRegistry;
  lKey: TStringList;  // Enumerating all keys of the Registry root key
  iKey: Integer;  // Iterating over the list
  sKey, sValue: String;  // Current key name, current value content

  // Used on both values - either can exist or be absent
  function _CheckValue( _sName: String ): Boolean;
  begin
    result:= oReg.ValueExists( _sName );  // Is the value even available?
    if result then begin
      sValue:= oReg.ReadString( _sName );
      result:= Copy( sValue, 1, 5 )= VALUE_video;  // Does the value begin with 'video'?
    end;
  end;

begin
  oReg:= TRegistry.Create( KEY_READ );  // No need to write to it
  oReg.RootKey:= HKEY_CLASSES_ROOT;  // Actually "HKEY_CURRENT_USER\Software\Classes" and "HKEY_LOCAL_MACHINE\Software\Classes" in one
  oReg.OpenKeyReadOnly( '' );  // The root key is not automatically opened

  lKey:= TStringList.Create;
  oReg.GetKeyNames( lKey );  // All keys of the root key
  oReg.CloseKey();  // The open root key is no longer needed
  for iKey:= 0 to lKey.Count- 1 do begin
    sKey:= lKey[iKey];
    if Copy( sKey, 1, 1 )= '.' then begin  // Does the key name begin with a dot? It's a filename extension definition.
      if oReg.OpenKeyReadOnly( sKey ) then begin  // Key opened successfully?
        if _CheckValue( NAME_ContentType )
        or _CheckValue( NAME_PerceivedType ) then Memo1.Lines.Add( sKey );  // If one is successful, list key name = filename extension
      end;
      oReg.CloseKey();  // Key is no longer needed
    end;
  end;

  oReg.OpenKeyReadOnly( KEY_MIME );  // Internet Explorer MIME database
  lKey.Clear();  // Empty the list
  oReg.GetKeyNames( lKey );
  oReg.CloseKey();
  for iKey:= 0 to lKey.Count- 1 do begin
    sKey:= lKey[iKey];
    if Copy( sKey, 1, 5 )= VALUE_video then begin  // Does the key start with 'video'?
      if oReg.OpenKeyReadOnly( KEY_MIME+ '\'+ sKey ) then begin
        if oReg.ValueExists( NAME_Extension ) then begin  // Does a value with this name exist?
          sValue:= oReg.ReadString( NAME_Extension );
          if Memo1.Lines.IndexOf( sValue )= -1 then Memo1.Lines.Add( sKey );  // Could have been found earlier already
        end;
      end;
      oReg.CloseKey();
    end;
  end;

  lKey.Free;
  oReg.Free;
end;

Results and completeness

For me this produces (excerpt):

  • .3gp
  • .asf
  • .avi
  • .DVR-MS
  • .M2TS
  • .mov
  • .mp4
  • .mpg
  • .MTS
  • .vob
  • .wmv

However, it won't list

This is because an individual Windows installation doesn't come with knowing all formats. Not few formats are defined by either doing that manually, or by installing player software which does that automatically for all the formats it supports. Hence, this code will produce different results for everyone.

Further reading

A complete list of formats doesn't exist, because also many proprietary formats exist which are only used on software products (such as animations and videos within games) without any intention to be used outside of that scope. And then there are edge cases when animations are still rather a picture than a video (such as .gif and .mng).