我正在使用winmm.dll 开发带有C#的mp3播放器
我现在的倒带功能有问题。
当播放功能启动时,我会启动计时器。
当我启动FFW函数时,我希望它在经过时间的当前值后FFW 5000ms。
例如,如果我开始播放一首歌,并在歌曲中按FFW 6秒,则播放应在6000ms+5000ms(ffw5秒)时继续。
但什么都没有发生。这次我做错了什么?
namespace kTP
{
public class MusicPlayer
{
[DllImport("winmm.dll")]
private static extern long mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, int hwndCallback);
private bool isPlaying = false;
private int ffw5sec = 5000;
Timer elapsedTime = new Timer();
public void Open(string file)
{
string command = "open "" + file + "" type MPEGVideo alias MyMp3";
mciSendString(command, null, 0, 0);
}
public void Play()
{
isPlaying = true;
elapsedTime.Start();
elapsedTime.Interval = (1000);
string command = "play MyMp3";
mciSendString(command, null, 0, 0);
}
public void Pause()
{
isPlaying = false;
string command = "pause MyMp3";
mciSendString(command, null, 0, 0);
}
public void Stop()
{
isPlaying = false;
string command = "stop MyMp3";
mciSendString(command, null, 0, 0);
elapsedTime.Stop();
command = "close MyMp3";
mciSendString(command, null, 0, 0);
}
// return to start of song and resume playback
public void ReturnToStart()
{
isPlaying = true;
string command = "seek MyMp3 to start";
mciSendString(command, null, 0, 0);
command = "play MyMp3";
mciSendString(command, null, 0, 0);
}
// Fast Forward
// needs a better skip Implementation
public void FFW()
{
if (isPlaying == true)
{
string command = "set MyMp3 time format ms";
mciSendString(command, null, 0, 0);
command = "seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString());
mciSendString(command, null, 0, 0);
command = "play MyMp3";
mciSendString(command, null, 0, 0);
//ffw5sec += 5000;
}
}
}
}
在这行代码中:
command = "seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString());
您将elapsedTime和ffw5sec的字符串形式连接起来,而elapsedTime的字符串形式是不可解析的,即无法将其解析为整数。同样,在你的问题中,你没有告诉别人你到底在用哪个计时器。在C#中。NET框架中,Timer类有三种。
有:
System.Timers.Timer,
System.Threading.Timer, and
System.Windows.Forms.Timer
但是这些定时器类的字符串形式都不是可解析的。
System.Timers.Timer
的字符串形式为"System.Timers.Timer"
,System.Threading.Timer
的字符串形式是"System.Threading.Timer"
,而System.Windows.Forms.Timer
的字符串形式则为"System.Windows.Forms.Timer, Interval: {0}"
,其中{0}
被System.Windows.Forms.Timer.Interval
属性取代。
无论如何,我知道你不使用System.Threading.Timer
,因为在你在问题中发布的代码中,我看到你使用了一个空的构造函数来创建计时器Timer()
,而System.Threading.Timer
不包含一个接受0个参数的构造函数,但我仍然不知道它是System.Timers.Timer
还是System.Windows.Forms.Timer
。
查找命令的字符串格式的语法为:
"seek {0} to {1}"
其中{0}
替换为要查找的音频文件的路径和名称或别名,在您的情况下,{0}是MyMp3
。并且{1}
被音频文件中的时间所取代,该时间必须仅为整数
表达式(elapsedTime.ToString() + ffw5sec.ToString())
根本不返回可以解析为整数的字符串。
驾驶员无法执行此命令。
还建议使用String.Format
方法为mciSendString
函数准备和制作mci字符串命令,而不是使用串联字符串方法,因为string。Format方法比串联字符串的方法更容易使用,也更方便。这样你就不会感到困惑和犯错。也通过字符串格式化mci字符串命令。格式比串联的mci字符串命令更可读。
您所犯的另一个错误是,首先将elapsedTime和ffw5sec转换为字符串,然后将它们连接在一起,然后将结果字符串连接到mci字符串命令。
这样做是不对的。您应该首先将表示时间的整数值elapsedTime和ffw5sec相加,然后将结果转换为字符串并连接到mci-string命令。
我想说的是,你不应该调用ToString两次,但你可以使用它一次。
您制作mci字符串命令的错误方式是:
"seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString())"
制作mci字符串命令的正确方法是:
"seek MyMp3 to " + (elapsedTime + ffw5sec).ToString()
这只在elapsedTime为整数的情况下有效,但如果不是,则应该使用它的一个属性将时间返回为整数。
如果elapsedTime的字符串形式是可解析的,由于您的错误,mci字符串命令是:"seek MyMp3 to 50006000"
,因为您将"5000"与"6000"连接起来,结果是"50006000"。
但按照正确的方式,mci字符串命令应该是:"seek MyMp3 to 11000"
,因为您首先将5000和6000相加,结果是11000作为整数。
您甚至根本不必使用ToString()
,因为您可以将字符串与整数连接,而不仅仅是将字符串与字符串连接,这无论如何都会产生字符串。例如,两种情况都有效:
"seek MyMp3 to " + **"** 11000 **"** = "seek MyMp3 to 11000",
和
"seek MyMp3 to " + 11000 = "seek MyMp3 to 11000"
因此,还有更好的方法来制作mci字符串命令:
"seek MyMp3 to " + (elapsedTime + ffw5sec)
但括号仍然很重要,因为如果没有,5000与mci字符串命令连接,然后是ffw5sec。结果又是错误的:
"seek MyMp3 to " + elapsedTime + ffw5sec = "seek MyMp3 to 50006000"
另外,根本不要使用Timer类,因为当您在定时器和回调方法之外做其他事情时,该类用于在每个间隔时间调用回调方法。
Timer类不用于测量经过的时间。您应该使用Stopwatch类,该类可以在System中找到。诊断命名空间。系统引用已经添加到您的项目中,这一点非常重要,因此您可以在此命名空间中找到此类。
Stopwatch类也有Start方法,就像Timer类一样,但不同的是,Timer类的Start方法开始执行Elapsed事件、Tick事件或构造函数中给定的回调函数,具体取决于我前面提到的您使用的计时器。
Stopwatch类的实例与任何回调方法都没有联系。相反,它们有私有的时间数据字段,以及以某些形式返回时间数据的公共属性。
ElapsedMilliseconds
属性返回Stopwatch运行的所有时间(以毫秒为单位)所经过的时间(64位整数)。
还有ElapsedTicks
属性,与ElapsedMilliseconds
相同,但返回的时间是以节拍为单位测量的。
一秒钟内通过的蜱虫数量远远超过毫秒。
Elapsed属性与ElapsedMilliseconds和ElapsedTicks相同,但时间根本不是作为长整数返回的,而是作为TimeSpan结构返回的,该结构也将秒表实例的私有时间数据存储为私有数据,也可以通过其属性(如Days、Hours、Millisecond、Minutes、Seconds、,蜱虫等。
无论如何,将elapsedTime的类型从Timer
更改为Stopwatch
,不要忘记首先使用System.Diagnostics命名空间来使用此类。此外,您还需要在项目中引用System引用。
现在,你终于可以修复你的命令了:
command = String.Format("seek MyMp3 to {0}", elapsedTime.ElapsedMilliseconds + ffw5sec);
这应该很好,但有时不要忘记使用Reset或Restart方法将经过的时间重置为零。如果您希望Stopwatch在经过的时间重置为零后处于运行状态,请使用Restart方法。否则,只需使用Reset方法。
如果仍然存在问题,那么您将不得不使用DllImport来外部mciGetErrorString函数,并在mciSendString不起作用时使用它来找出您的问题,因为您在其中输入了不正确的参数。
mciGetErrorString在C#中的声明是:
[DllImport("winmm.dll")]
static extern Int32 mciGetErrorString(Int32 errorCode, StringBuilder errorText, Int32 errorTextSize);
建议将上面的代码段添加到您的C#程序中,无论在哪里,都可以在其他声明的方法之间,而是在声明入口点Main方法的program类中。
每当mciSendString无法执行您输入的命令时,它都会以整数形式返回错误代码。
您应该将该错误代码输入到mciGetErrorString中。mciGetErrorString将修改StringBuilder实例并在其中写入错误字符串。
然后使用Object.ToString()、Console.Write或Console.WriteLine方法输出StringBuilder实例的字符串形式。
输出将描述错误,这就是mciSendString无法执行该命令的原因。这将帮助你发现你的问题,并直接思考你的解决方案。
我希望这一切对你有帮助。祝你好运