需讀取 MP3/WMA/WMV/MP4 等媒體檔案的詳細屬性 (播放長度、標題、演唱者、專輯、比特率、解析度等) 時,最輕量且無需額外解碼器的方案是呼叫 Windows Shell 命名空間 (Shell32.dll)。本文示範完整實作、跨版本索引差異處理與效能優化。
Windows 檔案總管右鍵「內容」→「詳細資料」頁籤顯示的所有媒體中繼資料,均可透過 Shell32.Shell COM 介面取得。優點:
Interop.Shell32.dll (注意:x86/x64 產出的 Interop 不同,建議專案設定 Prefer 32-bit 或明確對應平台)
using System;
using System.Runtime.InteropServices;
using Shell32; // Interop.Shell32
public static class MediaFileExtensions
{
///
/// 取得媒體檔案指定屬性值
///
/// 完整檔案路徑
/// Shell 屬性索引 (見下表)
/// 屬性字串,失敗回傳 null
public static string GetShellProperty(this string filePath, int propertyIndex)
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) return null;
Shell shell = null;
Folder folder = null;
FolderItem item = null;
try
{
shell = new ShellClass();
string dir = Path.GetDirectoryName(filePath);
string name = Path.GetFileName(filePath);
folder = shell.NameSpace(dir);
item = folder.ParseName(name);
if (item == null) return null;
object val = folder.GetDetailsOf(item, propertyIndex);
return val?.ToString();
}
catch (COMException)
{
return null;
}
finally
{
// 釋放 COM 物件
if (item != null) Marshal.ReleaseComObject(item);
if (folder != null) Marshal.ReleaseComObject(folder);
if (shell != null) Marshal.ReleaseComObject(shell);
}
}
///
/// 取得播放長度 (格式: HH:MM:SS)
///
public static string GetDuration(this string filePath)
{
// 索引在不同 OS 版本不同:Win2003/XP=21, Vista/Win7/8/10/11=27
// 建議動態偵測或嘗試多個索引
return GetShellProperty(filePath, 27) ?? GetShellProperty(filePath, 21);
}
///
/// 批次取得常用屬性
///
public static MediaMetadata GetMetadata(this string filePath)
{
if (!File.Exists(filePath)) return null;
var meta = new MediaMetadata();
var indices = new Dictionary
{
["Title"] = 21, // 標題
["Duration"] = 27, // 長度
["Artist"] = 13, // 演唱者/藝術家
["Album"] = 14, // 專輯
["Year"] = 15, // 年份
["Genre"] = 16, // 風格
["BitRate"] = 28, // 比特率
["Width"] = 162, // 影片寬度
["Height"] = 163, // 影片高度
["FrameRate"] = 164, // 幀率
};
Shell shell = null;
Folder folder = null;
FolderItem item = null;
try
{
shell = new ShellClass();
folder = shell.NameSpace(Path.GetDirectoryName(filePath));
item = folder.ParseName(Path.GetFileName(filePath));
if (item == null) return null;
foreach (var kvp in indices)
{
string val = folder.GetDetailsOf(item, kvp.Value)?.ToString();
typeof(MediaMetadata).GetProperty(kvp.Key)?.SetValue(meta, val);
}
}
finally
{
if (item != null) Marshal.ReleaseComObject(item);
if (folder != null) Marshal.ReleaseComObject(folder);
if (shell != null) Marshal.ReleaseComObject(shell);
}
return meta;
}
}
public class MediaMetadata
{
public string Title { get; set; }
public string Duration { get; set; }
public string Artist { get; set; }
public string Album { get; set; }
public string Year { get; set; }
public string Genre { get; set; }
public string BitRate { get; set; }
public string Width { get; set; }
public string Height { get; set; }
public string FrameRate { get; set; }
}
| 索引 | 屬性名稱 | 範例值 |
|---|---|---|
| 0 | 名稱 | song.mp3 |
| 1 | 大小 | 4.2 MB |
| 2 | 項目類型 | MP3 音訊檔案 |
| 13 | 演唱者 | 周杰倫 |
| 14 | 專輯 | 葉惠美 |
| 15 | 年份 | 2003 |
| 16 | 風格 | 流行 |
| 21 | 標題 | 東風破 |
| 27 | 長度 | 00:04:32 |
| 28 | 比特率 | 192 kbps |
| 162 | 影片寬度 | 1920 |
| 163 | 影片高度 | 1080 |
| 164 | 幀率 | 30 fps |
注意:索引在不同 Windows 版本、語系、安裝的屬性處理器 (Property Handler) 下可能不同。最穩健做法是**啟動時掃描 0~300 索引建立名稱→索引字典**,或嘗試多個已知索引 (如長度同時試 21, 27)。
Shell/Folder 物件處理同目錄下多檔案,避免重複建立 COM 物件