我正在使用winmm.dll
使用C#制作MP3播放器我的回卷功能现在有问题。
当Play功能启动时,我启动一个Timer。
当我启动FFW功能时,我希望它与当前的elapsedTime值相距5000毫秒。
例如,如果我开始播放歌曲并按下FFW 6秒进入歌曲,播放应该在6000ms + 5000ms(ffw5sec)继续播放。
但没有任何事情发生。这次我做错了什么?
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;
}
}
}
}
答案 0 :(得分:1)
在这行代码中:
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()
和{{ 1}}不包含带0个参数的构造函数,但我仍然不知道它是System.Threading.Timer
还是System.Timers.Timer
。
seek命令的字符串格式的语法是:
System.Windows.Forms.Timer
其中"seek {0} to {1}"
被要搜索的音频文件的路径和名称或别名替换,在您的情况下,{0}为{0}
。 MyMp3
被音频文件中的时间所取代,必须是整数
表达式:{1}
,不会返回一个可以解析为整数的字符串。
驱动程序无法执行此命令。
还建议使用(elapsedTime.ToString() + ffw5sec.ToString())
方法为String.Format
函数准备和制作mci字符串命令,而不是使用连接字符串方法,因为String.Format方法更易于使用且更方便比连接字符串的方法。这样你就不会感到困惑并犯错误。 String.Format格式化的mci字符串命令也比串联的mci字符串命令更具可读性。
你做的另一个错误是你首先将elapsedTime和ffw5sec转换为字符串,然后连接它们,然后将结果字符串连接到mci string命令
这样做是错误的。你应该首先添加表示时间的elapsedTime和ffw5sec的整数值,然后将结果转换为字符串并将其连接到mci string命令。
我想说的是你不应该两次调用ToString,但你可以使用它一次。
你制作mci string命令的错误方法是:
mciSendString
制作mci string命令的正确方法是:
"seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString())"
这仅在elapsedTime为整数的情况下有效,但如果不是,则应使用其中一个将时间作为整数返回的属性。
如果字符串形式的elapsedTime是可解析的,那么你的错误就是mci string命令是:"seek MyMp3 to " + (elapsedTime + ffw5sec).ToString()
,因为你连接" 5000"使用" 6000",结果为" 50006000"。
但是以正确的方式,mci string命令应该是:"seek MyMp3 to 50006000"
,因为你首先添加5000和6000,结果是11000作为整数。
你甚至根本不必使用"seek MyMp3 to 11000"
,因为你可以将字符串与整数连接起来,而不仅仅是字符串和字符串,无论如何都会产生字符串。例如,两种情况都有效:
ToString()
和
"seek MyMp3 to " + **"** 11000 **"** = "seek MyMp3 to 11000",
因此,有更好的方法来制作mci string命令:
"seek MyMp3 to " + 11000 = "seek MyMp3 to 11000"
但是括号仍然很重要,因为没有,5000与mci string命令连接,然后是ffw5sec。结果又是错误的:
"seek MyMp3 to " + (elapsedTime + ffw5sec)
也根本不使用Timer类,因为这个类用于在每个间隔时间调用回调方法,而你在定时器和回调方法之外做其他事情。
Timer类不用于测量经过的时间。您应该使用Stopwatch类,可以在System.Diagnostics命名空间中找到它。系统引用已添加到项目中非常重要,因此您可以在此命名空间中找到此类。
Stopwatch类也有Start方法,就像Timer类一样,但不同之处在于Timer类的Start方法开始执行Elapsed事件或Tick事件或构造函数中给出的回调函数,根据什么正如我之前提到的那样,你正在使用的计时器。
秒表类的实例与任何回调方法都没有联系。相反,它们具有私有时间数据字段,以及公共属性以某种形式返回该时间数据。
有"seek MyMp3 to " + elapsedTime + ffw5sec = "seek MyMp3 to 50006000"
属性返回时间长度(64位整数),而秒表运行的所有时间都是以毫秒为单位。
还有ElapsedMilliseconds
属性,与ElapsedTicks
相同,但返回的时间以刻度单位计算。
超过1000个刻度在一秒内通过而不是毫秒。
Elapsed属性与ElapsedMilliseconds和ElapsedTicks相同,但时间不作为长整数返回,而是作为TimeSpan结构返回,它将秒表实例的私有时间数据也存储为私有,也可以返回为或者int(32位整数),多个单位的long或double,它的属性,如Days,Hours,Milliseconds,Minutes,Seconds,Ticks等等。
无论如何,将elapsedTime的类型从ElapsedMilliseconds
更改为Timer
,并且不要忘记首先使用System.Diagnostics命名空间才能使用此类。您还需要在项目中引用系统参考。
现在终于可以修复你的命令了:
Stopwatch
这应该很好用,但有时候不要忘记使用重置或重启方法将经过时间重置为零。如果希望秒表在经过时间重置为零后处于运行状态,请使用重启方法。否则只需使用Reset方法。
如果仍有问题,那么你必须使用DllImport来外部mciGetErrorString函数,并在mciSendString不起作用时使用它来找出你的问题,因为你输入的参数不正确。
C#中mciGetErrorString的声明是:
command = String.Format("seek MyMp3 to {0}", elapsedTime.ElapsedMilliseconds + ffw5sec);
建议在其他声明的方法之间将上面的代码添加到C#程序中,无论在哪里,但是在声明入口点Main方法的Program类中。
每当mciSendString无法执行您输入的命令时,它会返回错误代码为整数。
您应该将该错误代码输入到mciGetErrorString中。 mciGetErrorString将修改StringBuilder实例并在其中写入错误字符串。
然后使用Object.ToString()或Console.Write或Console.WriteLine方法输出StringBuilder实例的字符串形式。
输出将描述错误,这就是mciSendString无法执行命令的原因。这将帮助您找出问题所在,并直接考虑您的解决方案。
我希望这一切对你有所帮助。祝你好运!