首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 使用 Shell32 讀取影音檔案屬性 (長度、標題、演唱者等) 完整指南

     編輯:關於C#

需讀取 MP3/WMA/WMV/MP4 等媒體檔案的詳細屬性 (播放長度、標題、演唱者、專輯、比特率、解析度等) 時,最輕量且無需額外解碼器的方案是呼叫 Windows Shell 命名空間 (Shell32.dll)。本文示範完整實作、跨版本索引差異處理與效能優化。

原理

Windows 檔案總管右鍵「內容」→「詳細資料」頁籤顯示的所有媒體中繼資料,均可透過 Shell32.Shell COM 介面取得。優點:

  • 零解碼:不載入媒體資料,極快 (ms 級)
  • 格式通用:支援所有系統已安裝解碼器的格式
  • 屬性完整:包含 EXIF、ID3、WMV 標籤等所有 Shell 可見屬性

實作步驟

1. 加入參考

  • 專案 → 加入參考 → COM → 搜尋「Microsoft Shell Controls And Automation」 (Shell32.dll)
  • Visual Studio 自動產生 Interop.Shell32.dll (注意:x86/x64 產出的 Interop 不同,建議專案設定 Prefer 32-bit 或明確對應平台)

2. 核心擴充方法


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; }
}

常用屬性索引對照表 (Windows 10/11 64-bit)

索引屬性名稱範例值
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)。

效能與部署注意

  • 單檔耗時:約 5-20ms (首次較慢,後續受 Shell 快取加速)
  • 批次處理:重複使用同一 Shell/Folder 物件處理同目錄下多檔案,避免重複建立 COM 物件
  • 64-bit 相容:目標平台勿勾選 Prefer 32-bit,需 64-bit Shell32;若必須 32-bit,確保目標機安裝 32-bit Property Handler
  • Server 核心版:Windows Server Core 未安裝 Shell 擴充,無法使用此方案,需改用 TagLib#、MediaToolkit 等純管理碼庫

現代替代方案

  • TagLib# (taglib-sharp):純 .NET 讀寫 ID3/APE/MP4 標籤,跨平台、無 COM 相依、支援寫入標籤
  • MediaToolkit / FFmpeg wrapper:解碼媒體取得精確長度、解析度、編碼資訊
  • Windows.Storage.FileProperties (UWP/WinRT):現代 API,支援 StorageFile 非同步讀取屬性,適合 UWP/WinUI 3/App SDK 專案
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved