Search code examples
c++sapi

Simple text to speech with SAPI in a Windows Service


Why does the following code fail after Speak() with error code 0x80045063 (SPERR_NOT_ACTIVE_SESSION) only when the process is running as a service?

ISpVoicePtr pVoice;
CoCreateInstance(
    CLSID_SpVoice,
    0,
    CLSCTX_INPROC_SERVER,
    IID_ISpVoice, ( LPVOID * ) &pVoice
);

pVoice->SetOutput( 0, TRUE );
pVoice->Speak( L"Hello", 0, NULL );

The only resources I can come up with talk about security changes to services interacting with desktop sessions. The following in .NET will work within a service so I'm just curious as to how it would be accomplished using plain C++ with or without SAPI.

System::Speech::Synthesis::SpeechSynthesizer synth;
synth.SetOutputToDefaultAudioDevice();
synth.Speak( "Hello" );

Solution

  • The SAPI documentation lists SPERR_NOT_ACTIVE_SESSION as

    Neither audio output nor input is supported for non-active console sessions.

    A service runs in a background session. Due to Session 0 Isolation introduced in Vista, a service does not have access to Interactive resources, which includes Text-To-Speech.

    Googling around, I found a couple of comments to back up that claim:

    http://www.ip-symcon.de/en/service/documentation/module-reference/text-to-speech/tts-speak/

    This function does not work under Windows __ Vista/2003__ or newer. This is because services such as IP-Symcon, for security reasons, can not access interactive components in the system. The Text To Speech output is such an interactive component. The problem manifests itself with the error message: __ OLE error 80045063__ extract MSDN: SPERR_NOT_ACTIVE_SESSION.

    http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.tapi/2009-06/msg00003.html

    Note that they broke ( deliberately I think ) this stuff beginning on Vista (and later). If you try to use SAPI's ISpMMSysAudio interface in a service (as they sketch in their bullet points in your link above), sooner or later you'll see a SPERR_NOT_ACTIVE_SESSION error.

    As for SpeechSynthesizer, my guess would be that it does not use SAPI internally. The source code for SpeechSynthesizer is available here:

    SpeechSynthesizer.cs

    VoiceSynthesis.cs