在 BackgroundWorker 中 用mciSendString 打开Mp3并播放

sxldfang 2010-11-09 10:33:20
namespace Mp3Player
{
public partial class Form1 : Form
{
mciAudioPlay mp = new mciAudioPlay();
BackgroundWorker findAndPlay = new BackgroundWorker();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
findAndPlay.DoWork += new DoWorkEventHandler(findAndPlay_DoWork);
findAndPlay.RunWorkerAsync();
}

void findAndPlay_DoWork(object sender, DoWorkEventArgs e)
{
if (mp.Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
}

//private void btnPlayMp3_Click(object sender, EventArgs e)
//{
// if (mp.Open(@"e:\mp3\冲动的惩罚.mp3")) mp.Play();
//}
}
}


上面的代码用来播放Mp3,mciAudioPlay是播放Mp3的类。

被注释的代码是可以正常工作的但放在BackgroundWorker 中就老是出现266号错误,即:“指定的设备未打开,或不被MCI所识别。”,为什么会出现这样的情况呢?

我确实想在 BackgroundWorker 中打开Mp3并播放,该如何做呢?
...全文
1069 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
sxldfang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 wuyazhe 的回复:]
msdn的解释
If you attempt to set the apartment to STA, then .NET will override you and set the apartment to MTA because the thread is a pool thread and cannot be devoted to accessing a single object. In……
[/Quote]

好,就到这,谢谢逍遥的帮助,晚上结贴!
兔子-顾问 2010-11-10
  • 打赏
  • 举报
回复
msdn的解释
If you attempt to set the apartment to STA, then .NET will override you and set the apartment to MTA because the thread is a pool thread and cannot be devoted to accessing a single object. In this scenario we need to use the thread class to execute the asynchronous operation.

兔子-顾问 2010-11-10
  • 打赏
  • 举报
回复
应该不行。你为什么不可以用线程呢?
sxldfang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 wuyazhe 的回复:]
[STAThread]
是描述线程的,不是描述回调方法的。
[/Quote]

可能有“在 BackgroundWorker 中使用”的方案吗?
兔子-顾问 2010-11-10
  • 打赏
  • 举报
回复
[STAThread]
是描述线程的,不是描述回调方法的。
sxldfang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 wuyazhe 的回复:]
试了一下,只有STA的线程可以。你的Load事件中这样写试试。不用BackgroundWorker

C# code

Thread t = new Thread((ThreadStart)delegate
{
if (mp.Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
});
t.SetApartmentState(A……
[/Quote]

谢谢逍遥!如果能在 BackgroundWorker 中使用最好啦(上面的只是个模型),我用了[STAThread]为何不行呢?


[STAThread]
void findAndPlay_DoWork(object sender, DoWorkEventArgs e)
{
if (mp.Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
}
兔子-顾问 2010-11-10
  • 打赏
  • 举报
回复
试了一下,只有STA的线程可以。你的Load事件中这样写试试。不用BackgroundWorker

Thread t = new Thread((ThreadStart)delegate
{
if (mp.Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
兔子-顾问 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 sxldfang 的回复:]
引用 7 楼 wuyazhe 的回复:
先下载mp3再播放可以么?的确线程中不行。错误是266


实际上我说他不行的时候用的就是本地的MP3文件,但注释掉的却行。

最初,我写的是一个封装好的类,用backGroundWork自动搜索并播放,发现不行后,才又做的上面的模型,谁知仍然无解。
[/Quote]
如果是本地的mp3,加载还会慢么?
sxldfang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 gomoku 的回复:]
如果没有记错的话,mciSendString需要一个消息泵(Message Loop)才能工作。
也就是说你要把mciSendString放在UI线程来做。
[/Quote]
如果这样,哪真是一个悲剧啦,比如UI界面上有MP3的播放列表,用户双击其一进行播放,半天没出来,又双击第2个,不用说,程序很快死掉。如何解决这样的问题呢?

若不行,有无设置“ mciSendString的Open命令” 执行的时间长度限制,或者 能否及时强制结束BackgroundWorker线程的方法,当然,这里说的不是CancellationPending什么的标志检测。因为还没执行到检测的位置,程序已经死啦!
sxldfang 2010-11-10
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 wuyazhe 的回复:]
先下载mp3再播放可以么?的确线程中不行。错误是266
[/Quote]

实际上我说他不行的时候用的就是本地的MP3文件,但注释掉的却行。

最初,我写的是一个封装好的类,用backGroundWork自动搜索并播放,发现不行后,才又做的上面的模型,谁知仍然无解。
gomoku 2010-11-10
  • 打赏
  • 举报
回复
如果没有记错的话,mciSendString需要一个消息泵(Message Loop)才能工作。
也就是说你要把mciSendString放在UI线程来做。
dacan66 2010-11-09
  • 打赏
  • 举报
回复
学习。。。
兔子-顾问 2010-11-09
  • 打赏
  • 举报
回复
先下载mp3再播放可以么?的确线程中不行。错误是266
sxldfang 2010-11-09
  • 打赏
  • 举报
回复
其实我是搜索网络的Mp3音乐进行播放,有的网站的mp3在执行open 时会花费较长的时间而造成界面假死,所以希望将查找并播放的代吗放在BackgroundWorker中来进行。
sxldfang 2010-11-09
  • 打赏
  • 举报
回复
行,没问题:



using System;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;


namespace Mp3Player
{
class mciAudioPlay
{
[DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
public static extern int mciSendString(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback);

[DllImport("winmm.dll", EntryPoint = "mciGetErrorString", CharSet = CharSet.Auto)]
public static extern int mciGetErrorString(int errCode, string lpstrReturnString, int uReturnLength);

[DllImport("winmm.dll", EntryPoint = "waveOutSetVolume", CharSet = CharSet.Auto)]
public static extern int waveOutSetVolume(uint deviceID, uint Volume); //参数为uint

public enum PlayStatus // 播放状态
{
Playing, Paused, Stopped, NoPlayFile
}

private string Name = ""; // 存放播放的文件名
private string buff = "................................................................................................................................";
private int errCode; // 执行mciSendString返回的错误码
//private PlayStatus status = PlayStatus.NoPlayFile;


public string Message // 根据错误码返回错误信息字符串
{
get
{
mciGetErrorString(errCode, buff, buff.Length);
int p = buff.IndexOf('\0');
return buff.Substring(0, p);
}
}

public bool Open(string fileName) // 打开一个要播放的文件
{
bool b = false;
try
{
if (Status != PlayStatus.NoPlayFile) Close();
errCode = mciSendString("open \"" + fileName + "\" alias NetMp3", buff, buff.Length, 0);
b = errCode == 0;
}
finally
{
if (b) Name = fileName;
else Name = string.Empty;
}
return b;
}

public void Play() // 播放 - playing
{
errCode = mciSendString("play NetMp3", buff, buff.Length, 0); // play NetMp3 repeat 循环播放
}

public void Stop() // 停止 - stopped
{
Position = 0; // mciSendString("stop NetMp3", buff, buff.Length, 0);
}

public void Pause() // 状态将变为 - paused
{
errCode = mciSendString("pause NetMp3", buff, buff.Length, 0);
}

public void Continue() // 状态将变为 - playing
{
errCode = mciSendString("resume NetMp3", buff, buff.Length, 0);
}

public void Close() // 状态将变为 - 空
{
errCode = mciSendString("close NetMp3", buff, buff.Length, 0);
//errCode = mciSendString("close all", buff, buff.Length, 0);
}

public string FileName // 播放的文件
{
get
{
return Name;
}
set
{
Open(value);
}
}

public PlayStatus Status // 获取当前状态: playing / paused / stopped / 空
{
get
{
if(string.IsNullOrEmpty(Name))return PlayStatus.NoPlayFile;
PlayStatus status;
errCode = mciSendString("status NetMp3 mode", buff, buff.Length, 0);
int p = buff.IndexOf('\0');
string s = buff.Substring(0, p);
switch (s)
{
case "playing": status = PlayStatus.Playing; break;
case "paused": status = PlayStatus.Paused; break;
default: status = PlayStatus.Stopped; break;
}
return status;
}
}


public int Length // 歌曲总长度(毫秒)
{
get
{
errCode = mciSendString("status NetMp3 length", buff, buff.Length, 0);
int p = buff.IndexOf('\0');
string s = buff.Substring(0, p);
if (string.IsNullOrEmpty(s)) return 0;
return int.Parse(s);
}
}

public int Position // 播放位置(毫秒)
{
get
{
errCode = mciSendString("status NetMp3 position", buff, buff.Length, 0);
int p = buff.IndexOf('\0');
string s = buff.Substring(0, p);
if (string.IsNullOrEmpty(s)) return 0;
return int.Parse(s);
}
set
{
errCode = mciSendString("seek NetMp3 to " + value, buff, buff.Length, 0);
}
}

public int Volume // 音量 0 ~ 1000
{
get
{
errCode = mciSendString("status NetMp3 volume", buff, buff.Length, 0);
int p = buff.IndexOf('\0');
string s = buff.Substring(0, p);
if (string.IsNullOrEmpty(s)) return 0;
return int.Parse(s);
}
set
{
errCode = mciSendString("setaudio NetMp3 volume to " + value, buff, buff.Length, 0);
}
}

public uint LeftRightVolume // 分别控制左右声道的音量
{
set
{
waveOutSetVolume(0, value); // 0xffffffff,高2字节控制右声道,低2字节控制左声道。
}
}
}
}
兔子-顾问 2010-11-09
  • 打赏
  • 举报
回复
你那个类代码贴贴看?
sxldfang 2010-11-09
  • 打赏
  • 举报
回复

public bool Open(string fileName) // 打开一个要播放的文件
{
bool b = false;
try
{
if (Status != PlayStatus.NoPlayFile) Close();
errCode = mciSendString("open \"" + fileName + "\" alias NetMp3", buff, buff.Length, 0);
b = errCode == 0;
}
finally
{
if (b) Name = fileName;
else Name = string.Empty;
}
return b;
}


关键是我不觉得我的代码有错啊!为什么在BackgroundWorker会错呢?
sxldfang 2010-11-09
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 wuyazhe 的回复:]
改这样试试?

C# code
void findAndPlay_DoWork(object sender, DoWorkEventArgs e)
{
if (new BackgroundWorker().Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
}
[/Quote]
Open 是我在 mciAudioPlay 类中定义的方法啊!
兔子-顾问 2010-11-09
  • 打赏
  • 举报
回复
改这样试试?
void findAndPlay_DoWork(object sender, DoWorkEventArgs e)
{
if (new BackgroundWorker().Open(@"E:\mp3\我从草原来.mp3")) mp.Play();
}


110,578

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧