5

I need to play a wav file from a C# application running as a Windows Service. I have tried both System.Media.SoundPlayer and a P/Invoke call to WinMM.dll (which is probably what SoundPlayer is doing).

[DllImport("WinMM.dll")]
private static extern bool PlaySound(string fname, int Mod, int flag); 

If I run my code as a console application, the sounds play. When I run it from a service, no luck, and I guess I'm not surprised.

So is there a way to play a sound from a windows service? Would something like DirectSound help? Or am I going to be stuck writing a console application and having the windows service app communicate with it as an intermediary?

Thanks in advance

LiraNuna
  • 64,916
  • 15
  • 117
  • 140
ASalvo
  • 408
  • 1
  • 4
  • 9
  • 2
    Why does the service itself need to play the sound (since the account it's running under most likely won't be logged in)? – Agent_9191 Jan 26 '10 at 23:28
  • 1
    Some more background. This application is for in-house use. We will be installing it on 4 machines to do some data aquisition, which I can interface with from my service application. I have been asked by management to play a wav file which will indicate the current state of the data aquisition (i.e. if it is running or not). The reason that I started this as a sevice, is that I want to run when windows starts and not require a user to be logged in. There are also the built in recovery options for a windows service. Visual indication via Digital IO works great, maybe I'll try to sell mgmt on it – ASalvo Jan 27 '10 at 04:46

4 Answers4

10

Playing a wav file from a service is definitely possible, at least on Windows 7 (and most likely Vista), by using the Windows Core Audio APIs. I recently verified this by making a small test service using NAudio. I just downloaded the NAudio sources and copied the "Wsapi" parts from their NAudioDemo project. This was on Windows 7 Enterprise 64bit, but I don't think that matters. The service was using the LocalSystem account.
For the record, playing sounds from a service is a perfectly legitimate thing to do in an embedded setting.

Rickard Lind
  • 116
  • 3
  • Thanks! I just tried this out on 32-bit Vista and it worked fine. I also tried the Wave Playback (did not work) and Directsound playback (worked) included in the library. There are 2 limitations that I have seen, both of which I can live with for my project. First, with Wasapi, I could only get it to work (even with the demo app) in exclusive mode, which means no other apps could play a sound. For DirectSound, I couldn't get it to play a sound as my service stopped. But I can live with this. – ASalvo Feb 04 '10 at 14:59
  • Is it possible that you provide some code? I tried to do what you said but I couldn't get the sound to play (even without the service). – elif Apr 08 '11 at 14:37
2

You can do this via the PlaySound API via winmm.dll, in Windows Vista or above. Microsoft added a seperate session for 'System Sounds' that can be used even from services, by merely adding a flag.

I've formatted this properly to avoid issues with the c# 2017 IDE throwing a wobbly over the DllImport not being in a class named 'NativeMethods'.

using System.Runtime.InteropServices;
namespace Audio
{
    internal static class NativeMethods
    {
        [DllImport("winmm.dll", EntryPoint = "PlaySound", SetLastError = true, CharSet = CharSet.Unicode, ThrowOnUnmappableChar = true)]
        public static extern bool PlaySound(
            string szSound,
            System.IntPtr hMod,
            PlaySoundFlags flags);

        [System.Flags]
        public enum PlaySoundFlags : int
        {
            SND_SYNC = 0x0000,/* play synchronously (default) */
            SND_ASYNC = 0x0001, /* play asynchronously */
            SND_NODEFAULT = 0x0002, /* silence (!default) if sound not found */
            SND_MEMORY = 0x0004, /* pszSound points to a memory file */
            SND_LOOP = 0x0008, /* loop the sound until next sndPlaySound */
            SND_NOSTOP = 0x0010, /* don't stop any currently playing sound */
            SND_NOWAIT = 0x00002000, /* don't wait if the driver is busy */
            SND_ALIAS = 0x00010000,/* name is a registry alias */
            SND_ALIAS_ID = 0x00110000, /* alias is a pre d ID */
            SND_FILENAME = 0x00020000, /* name is file name */
            SND_RESOURCE = 0x00040004, /* name is resource name or atom */
            SND_PURGE = 0x0040,  /* purge non-static events for task */
            SND_APPLICATION = 0x0080, /* look for application specific association */
            SND_SENTRY = 0x00080000, /* Generate a SoundSentry event with this sound */
            SND_RING = 0x00100000, /* Treat this as a "ring" from a communications app - don't duck me */
            SND_SYSTEM = 0x00200000 /* Treat this as a system sound */
        }
    }
    public static class Play
    {
        public static void PlaySound(string path, string file = "")
        {            
            NativeMethods.PlaySound(path + file, new System.IntPtr(), NativeMethods.PlaySoundFlags.SND_ASYNC | NativeMethods.PlaySoundFlags.SND_SYSTEM);
        }
    }
}
Miles Prower
  • 105
  • 9
1

Applied the NAudio to simply allow to play audio file.
http://bresleveloper.blogspot.co.il/2012/06/c-service-play-sound-with-naudio.html

Entwickler
  • 255
  • 2
  • 12
bresleveloper
  • 5,940
  • 3
  • 33
  • 47
-1

You've chosen the wrong application type. A windows service is for longer running applications that execute non-interactively, whether or not someone has logged into the computer. For example SQL Server, IIS etc.

You are also prevented in Windows Vista and later, from displaying user interface windows from a windows service. For Windows XP,2000 Server and you can display a MessageBox, however this is not recommended for most services.

So in general, services are not permitted to be "interactive", this includes playing sounds, multimedia etc.

You either need to change the application type to a normal Console/Windows Forms application, or live without playing sounds from your service.

For more information see this page on interactive services and related pages at MSDN.

Ash
  • 60,973
  • 31
  • 151
  • 169
  • From the link provided, an accpeted method of interacting with the user is to spawn a GUI application. I will explore this option more fully. – ASalvo Jan 27 '10 at 15:19
  • 1
    There are plenty of reasons why you may want to have a service interacting with audio. Think of a headless audio encoding server, for example. – Brad May 30 '12 at 22:57
  • 2
    I want to vote down because "wrong application type" is rather subjective. Use case: a build machine that runs otherwise headless, but gives an audible alert (and email alert) when a build fails, and must run without a user logged in. I want to upvote because you supply a link on how to deal with the desire to do this. I give you an upvote. – Mark Aug 13 '12 at 23:28
  • 1
    "wrong application type" is unhelpful, without more information about what he is trying to do or at least giving a generic better solution. There are many legitimate reasons to use a service, even if you want it to beep every once in a while – idanzalz Sep 10 '12 at 08:59