Shell32を利用するには、参照にCOMの[Microsoft Shell Controls And Automation]を追加します。
[STAThread] static void Main() { string path = @"C:\sample.mp3"; string directoryName = Path.GetDirectoryName(path); string fileName = Path.GetFileName(path); Shell32.Shell shell = new Shell32.Shell(); Shell32.Folder folder = shell.NameSpace(directoryName); Shell32.FolderItem folderItem = folder.ParseName(fileName); // すべてのプロパティを列挙 for (int i = 0; i < 1000; i++) { Console.WriteLine("{0}:{1},{2}", i, folder.GetDetailsOf(null, i), folder.GetDetailsOf(folderItem, i)); } // 指定のプロパティを取得 string prop0 = folder.GetDetailsOf(folderItem, 0); string prop1 = folder.GetDetailsOf(folderItem, 1); }
アプリケーションのエントリポイントにSTAThread属性を指定しないと、「型 'System.__ComObject' の COM オブジェクトをインターフェイス型 'Shell32.Shell' にキャストできません。IID '{286E6F1B-7113-4355-9562-96B7E9D64C54}' が指定されたインターフェイスの COM コンポーネント上での QueryInterface 呼び出しのときに次のエラーが発生したため、この操作に失敗しました: インターフェイスがサポートされていません (HRESULT からの例外:0x80004002 (E_NOINTERFACE))。」としてSystem.InvalidCastException例外が発生します。
フォルダ内の項目の詳細を取得できます。
string GetDetailsOf( object vItem, // 取得対象のShell32.FolderItem int iColumn // 取得対象のインデックス )Folder.GetDetailsOf method (Windows) | MSDN
vItemをnullとすると、プロパティ名が返されます。
Microsoft.WindowsAPICodePackに含まれるMicrosoft.WindowsAPICodePack.Shell.ShellFileクラスから、プロパティを取得できます。
string path = "sample.mp3"; ShellFile shellFile = ShellFile.FromFilePath(path); ShellProperties shellProperties = shellFile.Properties; // すべてのプロパティを列挙 ShellPropertyCollection shellPropertyCollection = shellProperties.DefaultPropertyCollection; foreach (IShellProperty shellProperty in shellPropertyCollection) { Console.WriteLine("{0},{1}", shellProperty.CanonicalName, shellProperty.ValueAsObject ); } // 指定のプロパティを取得 ShellProperties.PropertySystem propertySystem = shellProperties.System; string title = propertySystem.Title.Value; string[] authors = propertySystem.Author.Value;
一方でプロパティへ設定するには、取得に用いたValueプロパティへ設定します。
propertySystem.Title.Value = "sample"; propertySystem.Author.Value = new[] { "sample1", "sample2" };
無効な設定をしても例外などは発生しないため、設定が反映されたかどうかは取得して確認します。設定できない原因についてはエクスプローラのプロパティから設定してみることで、「エラー 0xC00D3E8D: 要求されたプロパティは見つかりませんでした。」のように確認できます。
複数のプロパティへ一括して設定するならば、ShellPropertyWriter.WriteProperty()を用います。ただしこの方法だと、無効な設定が1つでも含まれていると、すべての設定に失敗します。
using (ShellPropertyWriter shellPropertyWriter = shellProperties.GetPropertyWriter())
{
shellPropertyWriter.WriteProperty(SystemProperties.System.Title, "Sample");
shellPropertyWriter.WriteProperty(SystemProperties.System.Author, new[] { "Sample1", "Sample2" });
} // shellPropertyWriter.Close()は、Dispose()から呼ばれる
Solution 2016 - c# - How to set extended file properties? - Stack Overflow
無効なファイルに設定しようとすると、GetPropertyWriter()の呼び出し時に「Unable to get writable property store for this property.」としてMicrosoft.WindowsAPICodePack.Shell.PropertySystem.PropertySystemExceptionが投げられます。そのときInnerExceptionは、
となります。
WriteProperty()では内部でIPropertyStore::SetValue()が呼ばれることで値が設定され、Close()ではIPropertyStore::Commit()により保存されます。
書き換えの処理ではファイルの内容が変更されるのではなく、実際には一時ファイルが作成された上でリネームされます。たとえばC:\sample.wmvのプロパティを書き換えると、次のように処理されます。
このうち工程3以降のファイルの置換の処理は、File.Replace()と同じです。