You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI C#音乐APP更新元数据时遇COMException异常求助

WinUI音乐应用MediaPlaybackItemChanged事件COMException解决思路

下面针对你遇到的System.Runtime.InteropServices.COMException问题,给出几个核心排查和修复方向:

1. 修复异步事件处理的异常捕获与空值判断

async void类型的事件处理方法无法被常规try/catch捕获异常,且e.NewItem可能为空,先做基础校验并添加异常捕获:

async private void MediaPlaybackList_CurrentItemChanged(object sender, CurrentMediaPlaybackItemChangedEventArgs e)
{
    if (e.NewItem == null) return;
    mediaPlaybackItem = e.NewItem;

    try
    {
        await setmetadata();
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"元数据更新失败: {ex.Message}");
    }
}

2. 确保UI操作在UI线程执行

WinUI控件只能在UI线程更新,异步方法执行过程中可能切换到后台线程,需要通过DispatcherQueue调度UI更新:

async private Task setmetadata()
{
    if (mediaPlaybackItem?.Source == null) return;
    
    if (mediaPlaybackItem.Source.CustomProperties.TryGetValue("FilePath", out var filePathObj) && filePathObj is string filePath)
    {
        try
        {
            var file = await StorageFile.GetFileFromPathAsync(filePath);
            if (file == null) return;

            Debug.WriteLine("Grabbed: " + filePath);
            MusicProperties fileAttrib = await file.Properties.GetMusicPropertiesAsync();

            // 处理元数据为空的情况
            var album = fileAttrib.Album ?? "未知专辑";
            var trackNumber = fileAttrib.TrackNumber > 0 ? fileAttrib.TrackNumber.ToString() : "0";
            var title = fileAttrib.Title ?? Path.GetFileNameWithoutExtension(filePath);

            // 调度到UI线程更新控件
            await DispatcherQueue.TryEnqueueAsync(() =>
            {
                attribTitle.Text = $"#{trackNumber} - {title}";
                attribAlbum.Text = album;
            });
        }
        catch (COMException comEx)
        {
            Debug.WriteLine($"COM异常详情: {comEx.Message} | 错误码: {comEx.HResult:X8}");
            // 常见错误码:0x80070005(拒绝访问),说明文件权限不足
            if (comEx.HResult == -2147024891)
            {
                Debug.WriteLine("提示:当前文件无访问权限,建议改用未来访问列表存储文件引用");
            }
        }
    }
}

3. 解决文件访问权限问题

WinUI应用受沙箱限制,直接通过路径访问非应用目录的文件会触发权限拒绝的COMException。建议使用StorageApplicationPermissions.FutureAccessList保留文件访问权限:

添加文件时存储访问Token

// 示例:通过文件夹选择器添加音乐文件
var folderPicker = new FolderPicker();
folderPicker.FileTypeFilter.Add(".mp3");
folderPicker.FileTypeFilter.Add(".flac");
var selectedFolder = await folderPicker.PickSingleFolderAsync();

if (selectedFolder != null)
{
    // 将文件夹加入未来访问列表,长期保留权限
    StorageApplicationPermissions.FutureAccessList.Add(selectedFolder);
    
    var musicFiles = await selectedFolder.GetFilesAsync();
    foreach (var file in musicFiles)
    {
        var playbackItem = new MediaPlaybackItem(MediaSource.CreateFromStorageFile(file));
        // 存储文件的访问Token而非路径
        var fileToken = StorageApplicationPermissions.FutureAccessList.Add(file);
        playbackItem.Source.CustomProperties.Add("FileToken", fileToken);
        
        mediaPlaybackList.Items.Add(playbackItem);
    }
}

读取元数据时通过Token获取文件

修改setmetadata中的文件获取逻辑:

if (mediaPlaybackItem.Source.CustomProperties.TryGetValue("FileToken", out var tokenObj) && tokenObj is string fileToken)
{
    try
    {
        var file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
        // 后续元数据读取和UI更新逻辑不变
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"获取文件失败: {ex.Message}");
    }
}

4. 排查元数据读取的潜在问题

部分音乐文件的元数据可能损坏,导致GetMusicPropertiesAsync抛出COMException。可以给该方法单独添加try/catch,避免整个流程中断。


内容的提问来源于stack exchange,提问作者baka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:51:01