我是C#的初学者,我想做以下事情:
Thread t = new Thread(new ThreadStart(this.play));
t.Start();
这是方法play
:
private void play()
{
playSong("path\\to\\song.mp3");
}
private static void playSong(String path)
{
mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
mciSendString("play MediaFile", null, 0, IntPtr.Zero);
}
[DllImport("winmm.dll")]
private static extern long mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);
当我执行这样的方法时:play();
,不使用线程,歌曲播放完美,但如果我喜欢在第一段代码摘录中,它就不会播放。
我怀疑它发生是因为我需要在主线程中调用mciSendString
方法。如果是这样,有人会告诉我该怎么做?或者告诉我如何使用线程使其工作?
感谢您的帮助。
- 从这里编辑 -
我不知道是否应该发布代码,因为它有点大,但我会减少它,以显示我想要做的事情:
我有一个Windows窗体应用程序,它启动一个套接字,当它开始时监听端口,它作为一个服务器。此服务器接收它将播放的歌曲的请求路径。如果我使用如下所示的play
方法,表单崩溃,但应用程序仍然监听我的请求。我知道我必须在后台执行此操作,以便表单控件不会崩溃,我只是不知道更好的方法。
//Constructor
public Main()
{
InitializeComponent();
play();
}
play()
是这样的:
private void play()
{
//Does the socket initialization
do
{
//...
while (true)
{
//Reads text from client
//The text contains a string, indicating the path to the song.
byte[] bytesFrom = new byte[10025];
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
string dataFromClient = System.Text.Encoding.Default.GetString(bytesFrom);
//Plays the song from the received path
playSong(dataFromClient);
//...Do other stuff
}
} while (_serverOn);
//Closes the socket connection
}
private static void playSong(String path)
{
mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
mciSendString("play MediaFile", null, 0, IntPtr.Zero);
}
答案 0 :(得分:1)
我有一段时间有类似的问题......痛苦的屁股。
您正在进行跨线程操作,这是不安全的。这就是崩溃的原因。你对问题所在的地方绝对正确。
这是关于此线程操作http://msdn.microsoft.com/en-us/library/ms171728.aspx
的msdn文档您需要为mciSendString =>添加委托定义mciSendStringCallBack
delegate void mciSendStringCallBack(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);
在 private static void playSong(String path)中,您需要检查 InvokeRequired ,如果是,则需要实例化回调并调用它。
mciSendStringCallBack method = new mciSendStringCallBack(....);
this.Invoke(method , new object[] { .....});
通过msdn网站上的示例,他们可以很好地演示它的工作原理。
-
您可能想尝试使用后台工作程序,它为您提供多线程的处理方式,更易于使用。
答案 1 :(得分:1)
我怀疑MCI功能可能需要运行消息循环。此外,MCI请求被解除阻塞,因此一旦调用MCI操作,您的线程就会死亡。您需要继续在该线程上运行消息循环(使用Application.Run)直到MCI完成(您将通过传递窗口句柄请求回调)。请参阅说明如何完成的this文章。
编辑:也许在新线程上启动的隐藏表单可以减少要完成的工作。但是你仍然需要从MCI接收回调来终止线程。
答案 2 :(得分:1)
上面接受的答案仍在UI线程上运行mciSendString
。我需要将它从UI线程移开,因为它花费的时间太长(保存文件的时间> 200ms),所以我提出了这个解决方案:
var t = new Thread(Dispatcher.Run);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
var d = Dispatcher.FromThread(t)
d.InvokeAsync(() => mciSendString(command, null, 0, IntPtr.Zero));