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

104

J'essaie de savoir comment lire / écrire dans les propriétés de fichier étendues dans C #, par exemple, commentaire, débit binaire, 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 / ...)

David Hayes
la source
3
Cette question n'a clairement pas de réponse puisque la réponse acceptée montre uniquement comment obtenir les propriétés étendues et non comment les définir .
Dmitri Nesteruk
1
Pour définir les propriétés étendues, voir stackoverflow.com/questions/5337683/…
VoteCoffee

Réponses:

83

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)}");
        }
    }
}
csharptest.net
la source
3
comment fixerait-on l'une de ces valeurs? par exemple Auteur ou éditeur pour un fichier .txt. Je suis sur win 7 et utilisé ceci et il montre un auteur et un éditeur vierges et 282 autres propriétés
Vaibhav Garg
1
@Vainbhav - Vous ne pouvez pas les définir.
csharptest.net
26
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.
csharptest.net
2
Comment les définir est mieux couvert dans cette question: stackoverflow.com/questions/5337683/…
Nicolas Raoul
1
Dans Windows 10, il ne renvoie que 52 champs sans compter la fréquence d'images, la hauteur d'image, la largeur, ....?
Minh Nguyen
26

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 sur le bureau et que vous ne pouvez pas modifier une propriété, vous ne pourrez pas non plus le modifier 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é Authorou Title.
  • Ouvrez-le avec Word, modifiez-le et enregistrez-le. Maintenant vous pouvez.

Assurez-vous donc d'en utiliser try catch

Sujet supplémentaire: MSDN: implémentation de gestionnaires de propriétés

Martin Schneider
la source
Je ne vois aucun package portant ces noms de Microsoft
Jacob Brewer
1
@JacobBrewer C'est en fait celui qui a été téléchargé par "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . Dans Visual Studio NuGet-Package-Manager, il est indiqué comme "par Microsoft". Les autres paquets avec des noms similaires en sont des fourchettes et pourraient également fonctionner correctement ou même mieux. Je ne sais pas ...
Martin Schneider
25

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 la boîte de dialogue Références .

Dirk Vollmar
la source
2
Il convient de noter que sur Windows 7 (au moins), vous pouvez augmenter la taille des arrHeaders à un peu plus de 280 et récupérer de nombreuses méta-données supplémentaires. J'ai découvert cela lorsque je cherchais un moyen d'obtenir des méta-données à partir d'un fichier WTV (émission de télévision enregistrée Windows 7 Media Center).
Richard
1
La première boucle for i = 0 à 34 doit être pour i = 0 à Integer.MaxValue. Testez ensuite la valeur de retour de objFolder.GetDetailsOf (objFolder.Items, i). S'il renvoie un espace nul ou un espace blanc, vous avez tous les en-têtes.
Tim Murphy
@TimMurphy, malheureusement, ce n'est pas correct (du moins sous Windows 10 ou 7). Certains en-têtes sont vides, vous devez donc parcourir tous les index. (Bien sûr, comme il n'y en a pas des millions, vous pouvez limiter la boucle à
1000.
8

Merci les gars pour ce fil! Cela m'a aidé lorsque je voulais comprendre la version de fichier d'un exe. Cependant, j'avais besoin de comprendre moi-même la dernière partie de ce qu'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 dans le nom de la propriété, vous obtiendrez la valeur. Par exemple, File Version va FileVersion, et là vous l'avez.

J'espère que cela aide quelqu'un d'autre, j'ai juste pensé ajouter cette information à ce fil. À votre santé!

JERKER
la source
2
Cela garantit également que votre code fonctionnera (au moins principalement) sur des machines de langue autre que l'anglais.
Ed Norris
1
Une petite amélioration ici, FolderItem ne contient pas ExtendedProperty (). FolderItem2 le fait cependant.
Mixxiphoid
Cette réponse est un peu plus simple que d'autres. J'ai donné un exemple de code qui fonctionne ici: stackoverflow.com/a/46648086/661933
nawfal
8

GetDetailsOf()Méthode - 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 de la Windows-OSversion.

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);
 }
RajeshKdev
la source
J'ai copié et utilisé le même code ci-dessus. Mais, j'obtiens une exception COM au moment de l'exécution ici Folder rFolder = shell.NameSpace(_rootPath);. Pour info, j'utilise le système d'exploitation Windows 8.
DonMax
1
Quelle est cette erreur? Assurez-vous que vous utilisez la version correcte de Shell32.dll. Vérifiez ceci peut-être utile
RajeshKdev
1
+1 pour le lien ci-dessus. Le lien que vous avez suggéré fonctionne correctement. J'ai besoin d'une autre aide de votre part. c'est-à-dire, comment puis-je transmettre le fichier unique pour obtenir les métadonnées? depuis, il accepte de ne passer que le dossier.
DonMax
6
  • Après avoir examiné un certain nombre de solutions sur ce fil et ailleurs, le code suivant a été mis en place. Ceci est uniquement pour lire une propriété.
  • Je n'ai pas pu faire fonctionner la fonction Shell32.FolderItem2.ExtendedProperty, elle est censée prendre une valeur de chaîne et renvoyer la valeur et le type corrects pour cette propriété ... c'était toujours nul pour moi 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 apporte le code ci-dessous.

Utilisation:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Vous renverra la valeur de la propriété étendue souhaitée sous forme de chaîne pour le fichier et le nom de propriété donnés.
  2. Ne boucle que 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 de Windows comme Windows Server 2008 où vous obtiendrez l'erreur "Impossible de convertir l'objet COM de type 'System .__ ComObject' en type d'interface 'Shell32.Shell'" si vous essayez simplement de créer l'objet Shell32 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;
    }
Rohan
la source
1
Notez qu'au lieu d'utiliser InvokeMember () , vous pouvez effectuer un cast shellvers l'une des IShellDispatchinterfaces (1-6) et appeler le membre directement. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst
5

La réponse de Jerker est un peu plus simple. Voici un exemple de code qui fonctionne à partir 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 comme ceci:

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.
}
nawfal
la source
1

Je ne suis pas sûr des types de fichiers pour lesquels vous essayez d'écrire les propriétés, mais taglib-sharp est une excellente bibliothèque de balisage open source qui englobe bien toutes ces fonctionnalités. Il a beaucoup de support intégré pour la plupart des types de fichiers multimédias populaires, mais vous permet également de faire un marquage plus avancé avec à peu près n'importe quel fichier.

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

EDIT: Mise à jour du lien une fois de plus par commentaire de kzu.

maquette d'objet
la source
Cela semble très intéressant, je vais principalement regarder des fichiers vidéo (AVI, DIVX etc.). Merci pour le pointeur
David Hayes
Le lien taglib-sharp semble être mort :-( - ce qui est bizarre car le wiki à ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... pointe vers cette URL
SteveC
Merci, SteveC, au moment où j'ai posté ceci, les deux liens étaient valides et je n'étais pas sûr de l'endroit officiel où aller, on dirait que novell est le bon site pour cette bibliothèque maintenant.
mockobject
Merci pour le heads-up kzu, j'ai mis à jour le lien dans ma réponse originale pour pointer également vers l'emplacement github.
mockobject
1

Voici une solution pour lire - et non écrire - les propriétés étendues basées sur ce que j'ai trouvé sur cette page et à l' aide des objets shell32 .

Pour être clair, c'est un hack. Il semble que ce code fonctionnera toujours sous Windows 10 mais atteindra certaines propriétés vides. La version précédente de Windows doit utiliser:

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

Sur Windows 10, nous supposons qu'il y a environ 320 propriétés à lire et sautons 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 référencer l'assembly Com 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 de fichier

Je n'ai aucune idée de ce que seraient ces noms de propriétés sur un système étranger et je n'ai pas pu 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é.

BTW, c'est terriblement lent et - au moins sur Windows 10 - l'analyse des dates dans la chaîne récupérée serait un défi, donc utiliser cela semble être une mauvaise idée pour commencer.

Sur Windows 10, vous devez absolument utiliser la bibliothèque Windows.Storage qui contient les SystemPhotoProperties, SystemMusicProperties etc. https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

Et enfin, j'ai publié une bien meilleure solution qui utilise WindowsAPICodePack là-bas

pasx
la source