Introduction
I tend to listen to music quite a lot while I work. And, of course, I have to use headphones to keep my colleagues from beating me up. Recently I started using my mobile phone as my music player. Since I have to move around the office now and then, I constantly found myself unplugging and plugging in my headphones. And every time I had to unplug the headphones, I would first have to stop the music player to stop it from blaring out Maiden tracks. And of course, since I had stopped it earlier, I would need to start it again when I returned to my seat! I needed a way of starting the music player when I plugged in the headphones and stopping it when I unplugged it.
And thus was born this application.
Using the Code
Note: This project uses OpenNETCF or Smart Device Framework as it is called now. It’s great! You can get a copy from http://www.opennetcf.com/.
Another note: I'm not an applications developer and am quite new to C#. So my code probably does not look very professional. But the intention here is only to present the idea and not the application itself.
The code itself is pretty simple. It does the following;
- On startup, checks if another instance is running. If yes, the app checks with the user to determine if he/she wants to stop the application.
- Registers a
ChangeEventHandler
for the property SystemProperty.HeadsetPresent
.
- Starts or Stops the music player application based on the change event notification
- Goes to sleep a lot
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;
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;
[DllImport("coredll.dll", EntryPoint = "CreateMutex", SetLastError = true)]
public static extern IntPtr CreateMutex(IntPtr lpMutexAttributes,
bool InitialOwner,
string MutexName);
[MTAThread]
static void Main()
{
String sThisApp = Assembly.GetExecutingAssembly().GetName().Name + ".exe";
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))
{
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;
}
bHPState = new SystemState(SystemProperty.HeadsetPresent);
bHPState.Changed += bState_Changed;
while (true)
{
Application.DoEvents();
Thread.Sleep(1000);
}
}
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;
}
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)
{
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);
}
}
}
}
}
}
I use Nitrogen as my music player. The name and path of this application is hard coded in this app because I'm pretty lazy. You might want to change this if you use a different player.
Points of Interest
The tricky part of writing this application was to do with shutting down the application safely and in the right way. This aspect seems to be poorly documented or is poorly supported in .NET CF.
Things I Should Probably Do
- Allow user to select the music player instead of hard-coding it
- Get rid of the
Sleep
and DoEvents
business and implement a proper main loop
History
- 8th April, 2010: Initial post