Playing voice over modem from a Windows service

2019-07-20 20:23发布

I'm developing a VB.NET Windows service which is costantly checking a BMS database for new alarms and making phone calls to warn operators remotely. I'm currently using a .NET TAPI wrapper and the SAPI 5.3 interop assembly, and the steps I'm taking to speak over the phone are:

  1. Initialize TAPI interface;
  2. Make the call to the operator's number;
  3. Take the voice modem waveOut device id
  4. Set the voice output to that device id;
  5. Let SAPI do the magic.

This is all working fine if I compile the code as a Windows console or forms application, but as soon as I compile and run it as a Windows Service, step 5 never occurs - voice modem calls but stays silent; everything else works, even digit monitoring. Now I know windows services are not supposed to interact with the desktop, so things like UI elements and playing sounds are a no-no, but I'm struggling to find an alternative which doesn't involve using the wave API and can be developed in a reasonable timeframe. Any ideas?

2条回答
在下西门庆
2楼-- · 2019-07-20 20:32

SAPI typically needs some sort of message pump and a window handle, which Windows services typically don't have. You could create a message-only window to handle the messages in a slightly safer manner (note that any hwnd in a service will open you up to a shatter attack, so make sure you're running your service as a user, and not as SYSTEM or LocalMachine to reduce the attack surface). You'll also need to pump the messages (via Application.Run or Application.DoEvents or the like) as well.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-07-20 20:39

I ended up referencing the windows forms project in my Windows Service project, and creating the form in the OnStart sub:

Protected Overrides Sub OnStart(ByVal args() As String)
        HelperThread = New Threading.Thread(AddressOf CreateMOWindow)
        HelperThread.TrySetApartmentState(Threading.ApartmentState.STA)
        HelperThread.Start()
End Sub 

Private Sub CreateMOWindow()
        Dim frm As New AlarmVoiceTest.AlarmVoiceTest
        Windows.Forms.Application.Run(frm)
End Sub

The form isn't showing up of course (but I don't need it to), and SAPI is working as expected. I reckon this is not the cleanest way to accomplish that, but I'm kinda running out of time :)

查看更多
登录 后发表回答