如何在事件触发时主动Dispose已初始化的WMPLib Player播放器实例
WMPLib Player 实例正确释放方案
仅调用Player.controls.stop()不是正确的释放方式:该方法仅会暂停当前播放任务,完全不会释放实例占用的COM组件资源、系统句柄和内存空间,反复创建实例不做正确释放极易出现内存泄漏,甚至后台残留WMP相关进程无法自动退出。
标准释放步骤
- 先将目标Player实例从你管理所有实例的存储容器(比如List、字典)中移除,避免后续其他逻辑误调用已销毁的实例触发异常
- 执行基础资源清空操作:
- 调用
Player.controls.stop()停止当前播放 - 调用
Player.close()关闭当前媒体会话 - 将
Player.URL赋值为空字符串,解除媒体资源引用
- 调用
- 调用
Marshal.ReleaseComObject(Player)释放WMPLib对应的COM组件资源,这一步是核心:因为WMPLib基于COM实现,.NET的GC无法自动回收这部分资源,必须手动调用释放 - 将实例变量置为
null,清除托管引用 - 如果是批量销毁多个实例,可以在全部处理完成后主动触发一次GC回收;单次销毁无需频繁调用GC,避免影响性能
事件触发时的主动销毁示例代码
using WMPLib; using System.Runtime.InteropServices; // 全局存储所有Player实例的容器,可根据自己的业务调整存储结构 private List<WindowsMediaPlayer> _playerPool = new List<WindowsMediaPlayer>(); // 销毁指令事件的处理逻辑 private void OnDestroyPlayerCommandReceived(object sender, DestroyPlayerEventArgs e) { // 匹配要销毁的目标实例,此处以自定义标识为例,可根据自己的业务标识逻辑调整匹配规则 var targetPlayer = _playerPool.FirstOrDefault(p => (string)p.Tag == e.TargetPlayerId); if (targetPlayer == null) return; // 先从存储容器移除,避免后续误调用 _playerPool.Remove(targetPlayer); // 执行完整释放流程 targetPlayer.controls.stop(); targetPlayer.close(); targetPlayer.URL = string.Empty; Marshal.ReleaseComObject(targetPlayer); targetPlayer = null; }
注意事项
- 不要在Player自身触发的事件回调(比如
PlayStateChange、OpenStateChange)中直接销毁当前触发事件的实例,会导致COM访问冲突报错。如果需要在这类场景触发销毁,先将实例加入待销毁队列,在UI主线程空闲或者独立的后台检查逻辑中统一处理销毁 - 要确保所有业务逻辑中没有留存该实例的其他引用,只要有一处引用未清除,资源就无法完全释放
内容的提问来源于stack exchange,提问作者Jack Rivera
相关产品推荐
相关产品推荐

