web-dev-qa-db-fra.com

Propriétés de fichier 'Extended' en lecture / écriture (C #)

J'essaie de savoir comment lire/écrire dans les propriétés de fichier étendues en C #, par exemple. Commentaire, débit, date d'accès, catégorie, etc. que vous pouvez voir dans l'Explorateur Windows. Des idees pour faire cela? EDIT: Je vais principalement lire/écrire sur des fichiers vidéo (AVI/DIVX/...)

96
David Hayes

Pour ceux qui ne sont pas fous de VB, le voici en c #:

Notez que vous devez ajouter une référence à Microsoft Shell Controls and Automation à partir de l'onglet COM de la boîte de dialogue Références.

public static void Main(string[] args)
{
    List<string> arrHeaders = new List<string>();

    Shell32.Shell shell = new Shell32.Shell();
    Shell32.Folder objFolder;

    objFolder = Shell.NameSpace(@"C:\temp\testprop");

    for( int i = 0; i < short.MaxValue; i++ )
    {
        string header = objFolder.GetDetailsOf(null, i);
        if (String.IsNullOrEmpty(header))
            break;
        arrHeaders.Add(header);
    }

    foreach(Shell32.FolderItem2 item in objFolder.Items())
    {
        for (int i = 0; i < arrHeaders.Count; i++)
        {
            Console.WriteLine(
              $"{i}\t{arrHeaders[i]}: {objFolder.GetDetailsOf(item, i)}");
        }
    }
}
79
csharptest.net

Cet exemple dans VB.NET lit toutes les propriétés étendues:

Sub Main()
        Dim arrHeaders(35)

        Dim Shell As New Shell32.Shell
        Dim objFolder As Shell32.Folder

        objFolder = Shell.NameSpace("C:\tmp")

        For i = 0 To 34
            arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
        Next
        For Each strFileName In objfolder.Items
            For i = 0 To 34
                Console.WriteLine(i & vbTab & arrHeaders(i) & ": " & objfolder.GetDetailsOf(strFileName, i))
            Next
        Next

    End Sub

Vous devez ajouter une référence à Microsoft Shell Controls and Automation à partir de l'onglet COM de Références dialogue.

25
Dirk Vollmar

Solution 2016

Ajoutez les packages NuGet suivants à votre projet:

  • Microsoft.WindowsAPICodePack-Shell par Microsoft
  • Microsoft.WindowsAPICodePack-Core par Microsoft

Lire et écrire des propriétés

using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

string filePath = @"C:\temp\example.docx";
var file = ShellFile.FromFilePath(filePath);

// Read and Write:

string[] oldAuthors = file.Properties.System.Author.Value;
string oldTitle = file.Properties.System.Title.Value;

file.Properties.System.Author.Value = new string[] { "Author #1", "Author #2" };
file.Properties.System.Title.Value = "Example Title";

// Alternate way to Write:

ShellPropertyWriter propertyWriter =  file.Properties.GetPropertyWriter();
propertyWriter.WriteProperty(SystemProperties.System.Author, new string[] { "Author" });
propertyWriter.Close();

Important:

Le fichier doit être valide, créé par le logiciel spécifique attribué. Chaque type de fichier a des propriétés de fichier étendues spécifiques et toutes ne sont pas accessibles en écriture.

Si vous cliquez avec le bouton droit sur un fichier du bureau et que vous ne pouvez pas modifier une propriété, vous ne pourrez pas le modifier également dans le code.

Exemple:

  • Créez un fichier txt sur le bureau, renommez son extension en docx. Vous ne pouvez pas modifier sa propriété Author ou Title.
  • Ouvrez-le avec Word, modifiez-le et enregistrez-le. Maintenant vous pouvez.

Donc, assurez-vous d'utiliser trycatch

Sujet supplémentaire: MSDN: Implementing Property Handlers

23
Martin Schneider

Merci les gars pour ce fil! Cela m'a aidé lorsque je voulais comprendre la version du fichier d'un exe. Cependant, je devais trouver moi-même le dernier bit de ce que l'on appelle les propriétés étendues.

Si vous ouvrez les propriétés d'un fichier exe (ou dll) dans l'Explorateur Windows, vous obtenez un onglet Version et une vue des propriétés étendues de ce fichier. Je voulais accéder à l'une de ces valeurs.

La solution à cela est l'indexeur de propriété FolderItem.ExtendedProperty et si vous supprimez tous les espaces du nom de la propriété, vous obtiendrez la valeur. Par exemple. La version du fichier va FileVersion, et voilà.

J'espère que cela aidera quelqu'un d'autre, je me suis dit que j'ajouterais cette information à ce fil. À votre santé!

8
JERKER

GetDetailsOf() Method - Récupère les détails d'un élément dans un dossier. Par exemple, sa taille, son type ou l'heure de sa dernière modification. Les propriétés du fichier peuvent varier en fonction du Windows-OS version.

List<string> arrHeaders = new List<string>();

 Shell shell = new ShellClass();
 Folder rFolder = Shell.NameSpace(_rootPath);
 FolderItem rFiles = rFolder.ParseName(filename);

 for (int i = 0; i < short.MaxValue; i++)
 {
      string value = rFolder.GetDetailsOf(rFiles, i).Trim();
      arrHeaders.Add(value);
 }
8
RajeshKdev

Réponse de Jerker est un peu plus simple. Voici un exemple de code qui fonctionne de MS :

var folder = new Shell().NameSpace(folderPath);
foreach (FolderItem2 item in folder.Items())
{
    var company = item.ExtendedProperty("Company");
    var author = item.ExtendedProperty("Author");
    // Etc.
}

Pour ceux qui ne peuvent pas référencer Shell32 de manière statique, vous pouvez l'invoquer dynamiquement de la manière suivante:

var shellAppType = Type.GetTypeFromProgID("Shell.Application");
dynamic shellApp = Activator.CreateInstance(shellAppType);
var folder = shellApp.NameSpace(folderPath);
foreach (var item in folder.Items())
{
    var company = item.ExtendedProperty("Company");
    var author = item.ExtendedProperty("Author");
    // Etc.
}
5
nawfal
  • Après avoir examiné un certain nombre de solutions sur ce fil et ailleurs, le code suivant a été mis en place. Ceci est seulement pour lire une propriété.
  • Je ne pouvais pas faire fonctionner la fonction Shell32.FolderItem2.ExtendedProperty, elle est supposée prendre une valeur de chaîne et renvoyer la valeur et le type corrects pour cette propriété ... elle était toujours nulle et les ressources de référence du développeur étaient très minces.
  • Le WindowsApiCodePack semble avoir été abandonné par Microsoft, ce qui nous amène le code ci-dessous.

Utilisation:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Vous renverra la valeur de la propriété étendue que vous voulez en tant que chaîne pour le nom de fichier et de propriété donné.
  2. Boucle uniquement jusqu'à ce qu'il trouve la propriété spécifiée - pas avant que toutes les propriétés soient découvertes, comme un exemple de code
  3. Fonctionnera sur les versions Windows telles que Windows Server 2008 où vous obtiendrez l’erreur "Impossible de convertir un objet COM de type 'System .__ ComObject' en type d'interface 'Shell32.Shell'" si vous essayez simplement de créer le Shell32 Object normalement.

    public static string GetExtendedFileProperty(string filePath, string propertyName)
    {
        string value = string.Empty;
        string baseFolder = Path.GetDirectoryName(filePath);
        string fileName = Path.GetFileName(filePath);
    
        //Method to load and execute the Shell object for Windows server 8 environment otherwise you get "Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'"
        Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
        Object Shell = Activator.CreateInstance(shellAppType);
        Shell32.Folder shellFolder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, Shell, new object[] { baseFolder });
    
        //Parsename will find the specific file I'm looking for in the Shell32.Folder object
        Shell32.FolderItem folderitem = shellFolder.ParseName(fileName);
        if (folderitem != null)
        {
            for (int i = 0; i < short.MaxValue; i++)
            {
                //Get the property name for property index i
                string property = shellFolder.GetDetailsOf(null, i);
    
                //Will be empty when all possible properties has been looped through, break out of loop
                if (String.IsNullOrEmpty(property)) break;
    
                //Skip to next property if this is not the specified property
                if (property != propertyName) continue;    
    
                //Read value of property
                value = shellFolder.GetDetailsOf(folderitem, i);
            }
        }
        //returns string.Empty if no value was found for the specified property
        return value;
    }
    
4
Rohan

Je ne suis pas sûr du type de fichiers pour lequel vous essayez d'écrire les propriétés, mais taglib-sharp est une excellente bibliothèque de balisage open source qui englobe toutes ces fonctionnalités. Il prend en charge de manière intégrée la plupart des types de fichiers multimédias les plus courants, mais vous permet également d'effectuer un balisage plus avancé avec à peu près tous les fichiers.

EDIT: J'ai mis à jour le lien vers taglib sharp. L'ancien lien ne fonctionnait plus.

EDIT: Une fois de plus, le lien a été mis à jour par le commentaire de kzu.

1
mockobject

Voici une solution pour lire - et non pour écrire - les propriétés étendues en fonction de ce que j'ai trouvé sur cette page et sur aide sur les objets Shell32 .

Pour être clair c'est un bidouillage. Il semble que ce code fonctionnera toujours sous Windows 10 mais utilisera des propriétés vides. La version précédente de Windows devrait utiliser:

        var i = 0;
        while (true)
        {
            ...
            if (String.IsNullOrEmpty(header)) break;
            ...
            i++;

Sous Windows 10, nous supposons qu’il existe environ 320 propriétés à lire et ignore simplement les entrées vides:

    private Dictionary<string, string> GetExtendedProperties(string filePath)
    {
        var directory = Path.GetDirectoryName(filePath);
        var Shell = new Shell32.Shell();
        var shellFolder = Shell.NameSpace(directory);
        var fileName = Path.GetFileName(filePath);
        var folderitem = shellFolder.ParseName(fileName);
        var dictionary = new Dictionary<string, string>();
        var i = -1;
        while (++i < 320)
        {
            var header = shellFolder.GetDetailsOf(null, i);
            if (String.IsNullOrEmpty(header)) continue;
            var value = shellFolder.GetDetailsOf(folderitem, i);
            if (!dictionary.ContainsKey(header)) dictionary.Add(header, value);
            Console.WriteLine(header +": " + value);
        }
        Marshal.ReleaseComObject(Shell);
        Marshal.ReleaseComObject(shellFolder);
        return dictionary;
    }

Comme mentionné, vous devez faire référence à Com Assembly Interop.Shell32.

Si vous obtenez une exception liée à STA, vous trouverez la solution ici:

Exception lors de l'utilisation de Shell32 pour obtenir les propriétés étendues du fichier

Je n'ai aucune idée de ce que seraient ces noms de propriétés sur un système étranger et je ne pouvais pas trouver d'informations sur les constantes localisables à utiliser pour accéder au dictionnaire. J'ai également constaté que toutes les propriétés de la boîte de dialogue Propriétés n'étaient pas présentes dans le dictionnaire renvoyé.

En passant, cela est terriblement lent et - du moins sous Windows 10 - l’analyse des dates dans la chaîne extraite constituerait un défi; il semble donc que cette solution ne soit pas une bonne idée.

Sous Windows 10, vous devez absolument utiliser la bibliothèque Windows.Storage qui contient les propriétés SystemPhotoProperties, SystemMusicProperties, etc. https: //docs.Microsoft.com/en-us/windows/uwp/files/quickstart-getting-file- propriétés

Et enfin, j'ai posté une solution bien meilleure qui utilise WindowsAPICodePack

0
pasx