使用耳机启动/停止音乐播放器
插入耳机时启动音乐应用,拔出耳机时停止音乐应用的应用程序!
引言
我工作时经常听音乐。当然,我必须戴上耳机,以免同事揍我。最近我开始用手机作为音乐播放器。由于我现在需要时不时地在办公室里走动,我经常发现自己不断地拔插耳机。每次我拔掉耳机时,我首先必须停止音乐播放器,以免它播放出Iron Maiden的歌曲。当然,由于我之前已经停止了它,当我回到座位时,我需要再次启动它!我需要一种在插入耳机时启动音乐播放器,在拔出耳机时停止音乐播放器的方法。
因此,这个应用程序诞生了。
Using the Code
注意:这个项目使用OpenNETCF,或者现在称为Smart Device Framework。它很棒!你可以在 http://www.opennetcf.com/ 获取副本。
另一个说明:我不是一个应用程序开发者,而且对C#还很陌生。所以我的代码可能看起来不太专业。但这里的意图只是展示这个想法,而不是应用程序本身。
代码本身很简单。它执行以下操作:
- 启动时,检查是否已经运行了另一个实例。如果是,应用程序会与用户确认是否要停止该应用程序。
- 为属性
SystemProperty.HeadsetPresent
注册一个ChangeEventHandler
。 - 根据更改事件通知启动或停止音乐播放器应用程序
- 进入休眠状态很多次
using System;
using System.Windows.Forms;
using Microsoft.WindowsMobile.Status;
using System.Diagnostics;
using OpenNETCF.ToolHelp;
using System.Threading;
using System.Runtime.InteropServices;
using System.Reflection;
namespace AutoNitro
{
static class Program
{
static SystemState bHPState;
// Music application name and path. Change here if your music application
// is different
const string MUSIC_APP_EXE_NAME = "Nitrogen.exe";
const string MUSIC_APP_PROGRAM_FOLDER = "\\Program Files\\Nitrogen";
public const Int32 NATIVE_ERROR_ALREADY_EXISTS = 183;
// .NetCF does not export CreateMutex. We have to explicitly import it here
[DllImport("coredll.dll", EntryPoint = "CreateMutex", SetLastError = true)]
public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes,
bool InitialOwner,
string MutexName);
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
[MTAThread]
static void Main()
{
// The name of this application
String sThisApp = Assembly.GetExecutingAssembly().GetName().Name + ".exe";
// Check if an instance is already running by trying to create a mutex
// with a fixed name. If mutex already exists, we assume that this is
// because another instance is running!
IntPtr hMutex = CreateMutex(IntPtr.Zero, true, "AutoNitro");
if (Marshal.GetLastWin32Error() == NATIVE_ERROR_ALREADY_EXISTS)
{
if (DialogResult.Yes == MessageBox.Show(sThisApp +
" is already running. Do you want to close it?",
sThisApp,
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1))
{
// Kill 'em All!
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
sThisApp,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
process.Kill();
}
}
}
return;
}
// Register to be notified for any change to the HeadsetPreset property
bHPState = new SystemState(SystemProperty.HeadsetPresent);
bHPState.Changed += bState_Changed;
// Probably better to implement a message loop here instead of sleeping
// and DoEvents
while (true)
{
Application.DoEvents();
Thread.Sleep(1000);
}
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
// Returns true if the application with the name passed as parameter is
// currently running
static bool IsApplicationRunning(string pAppName)
{
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
pAppName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
return true;
}
}
return false;
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
// Shutsdown all running instances of the application pAppName
static void TerminateApplication(string pAppName)
{
ProcessEntry[] processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();
foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
if (String.Compare(process.ExeFile,
pAppName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
// We can directly kill the process here but it is not safe.
// I don't prefer killing because the music app will not remember your
// last played track and position if you kill it.
// Instead ask for a shutdown politely.
int iPID = (int)process.ProcessID
Process p = System.Diagnostics.Process.GetProcessById(iPID);
p.CloseMainWindow();
}
}
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
private static void LaunchApplication(string pAppName)
{
System.Diagnostics.Process.Start(pAppName, "");
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
static void bState_Changed(object sender, ChangeEventArgs args)
{
Boolean blNewHPState = Convert.ToBoolean(args.NewValue);
bool blAppRunState = IsApplicationRunning(MUSIC_APP_EXE_NAME);
if (!blNewHPState)
{
if (true == blAppRunState)
{
TerminateApplication(MUSIC_APP_EXE_NAME);
}
}
else
{
if (false == blAppRunState)
{
string sApp = MUSIC_APP_PROGRAM_FOLDER + "\\" + MUSIC_APP_EXE_NAME;
try
{
LaunchApplication(sApp);
}
catch
{
throw new Exception("Failed to start music player.\nPath was " + sApp);
}
}
}
}
}
}
我使用Nitrogen作为我的音乐播放器。这个应用程序中该应用程序的名称和路径是硬编码的,因为我有点懒。如果你使用不同的播放器,你可能需要更改它。
关注点
编写这个应用程序的棘手之处在于安全且正确地关闭应用程序。这个方面在.NET CF中似乎文档不足或支持不足。
我应该做的事情
- 允许用户选择音乐播放器,而不是硬编码它
- 消除
Sleep
和DoEvents
,并实现一个适当的主循环
历史
- 2010年4月8日:初始发布