diaeros
diaeros

Reputation: 29

Windows SAPI error : 'GetVersionExA': was declared deprecated

So all I want in life is to have a program where I can say "Hey Computer" and it responds with "Hello". So I set myself upon the task and after some research produced the code below yet whenever I try to compile it through Visual Studio 2017 on Windows 10 I get this error: 'GetVersionExA': was declared deprecated but I don't understand because I don't call that function anywhere in my code.

#include <sphelper.h>
#include <sapi.h>
#include <iostream>
#include <string>
#include <vector>
#include <locale>

const ULONGLONG grammarId = 0;
const wchar_t* ruleName1 = L"ruleName1";

int start_listening(const std::string& word);
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command);
void get_text(ISpRecoContext* reco_context);
void check_result(const HRESULT& result);

ISpVoice * pVoice = NULL;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);

inline std::wstring s2w(const std::string &s, const std::locale &loc = std::locale())
{
    typedef std::ctype<wchar_t> wchar_facet;
    std::wstring return_value;
    if (s.empty())
    {
        return return_value;
    }
    if (std::has_facet<wchar_facet>(loc))
    {
        std::vector<wchar_t> to(s.size() + 2, 0);
        std::vector<wchar_t>::pointer toPtr = &to[0];
        const wchar_facet &facet = std::use_facet<wchar_facet>(loc);
        if (0 != facet.widen(s.c_str(), s.c_str() + s.size(), toPtr))
        {
            return_value = to.data();
        }
    }
    return return_value;
}

int main(int argc, char** argv)
{
    HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
    std::string hello = "hello";

    start_listening("Hey computer");
    hr = pVoice->Speak(s2w(hello).c_str(), 0, NULL);
    return EXIT_SUCCESS;
}

// This function exits when the word passed as parameter is said by the user
int start_listening(const std::string& word)
{
    // Initialize COM library
    if (FAILED(::CoInitialize(nullptr))) {
        return EXIT_FAILURE;
    }

    std::cout << "You should start Windows Recognition" << std::endl;
    std::cout << "Just say \"" << word << "\"" << std::endl;

    HRESULT hr;

    ISpRecognizer* recognizer;
    hr = CoCreateInstance(CLSID_SpSharedRecognizer,
        nullptr, CLSCTX_ALL, IID_ISpRecognizer,
        reinterpret_cast<void**>(&recognizer));
    check_result(hr);

    ISpRecoContext* recoContext;
    hr = recognizer->CreateRecoContext(&recoContext);
    check_result(hr);

    // Disable context
    hr = recoContext->Pause(0);
    check_result(hr);

    ISpRecoGrammar* recoGrammar = init_grammar(recoContext, word);

    hr = recoContext->SetNotifyWin32Event();
    check_result(hr);

    HANDLE handleEvent;
    handleEvent = recoContext->GetNotifyEventHandle();
    if (handleEvent == INVALID_HANDLE_VALUE) {
        check_result(E_FAIL);
    }

    ULONGLONG interest;
    interest = SPFEI(SPEI_RECOGNITION);
    hr = recoContext->SetInterest(interest, interest);
    check_result(hr);

    // Activate Grammar
    hr = recoGrammar->SetRuleState(ruleName1, 0, SPRS_ACTIVE);
    check_result(hr);

    // Enable context
    hr = recoContext->Resume(0);
    check_result(hr);

    // Wait for reco
    HANDLE handles[1];
    handles[0] = handleEvent;
    WaitForMultipleObjects(1, handles, FALSE, INFINITE);
    get_text(recoContext);

    std::cout << "Hello user" << std::endl;

    recoGrammar->Release();
    ::CoUninitialize();

    system("PAUSE");
    return EXIT_SUCCESS;
}

/**
* Create and initialize the Grammar.
* Create a rule for the grammar.
* Add word to the grammar.
*/
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command)
{
    HRESULT hr;
    SPSTATEHANDLE sate;

    ISpRecoGrammar* recoGrammar;
    hr = recoContext->CreateGrammar(grammarId, &recoGrammar);
    check_result(hr);

    WORD langId = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH);
    hr = recoGrammar->ResetGrammar(langId);
    check_result(hr);
    // TODO: Catch error and use default langId => GetUserDefaultUILanguage()

    // Create rules
    hr = recoGrammar->GetRule(ruleName1, 0, SPRAF_TopLevel | SPRAF_Active, true, &sate);
    check_result(hr);

    // Add a word
    const std::wstring commandWstr = std::wstring(command.begin(), command.end());
    hr = recoGrammar->AddWordTransition(sate, NULL, commandWstr.c_str(), L" ", SPWT_LEXICAL, 1, nullptr);
    check_result(hr);

    // Commit changes
    hr = recoGrammar->Commit(0);
    check_result(hr);

    return recoGrammar;
}

void get_text(ISpRecoContext* reco_context)
{
    const ULONG maxEvents = 10;
    SPEVENT events[maxEvents];

    ULONG eventCount;
    HRESULT hr;
    hr = reco_context->GetEvents(maxEvents, events, &eventCount);

    // Warning hr equal S_FALSE if everything is OK 
    // but eventCount < requestedEventCount
    if (!(hr == S_OK || hr == S_FALSE)) {
        check_result(hr);
    }

    ISpRecoResult* recoResult;
    recoResult = reinterpret_cast<ISpRecoResult*>(events[0].lParam);

    wchar_t* text;
    hr = recoResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, FALSE, &text, NULL);
    check_result(hr);

    CoTaskMemFree(text);
}

void check_result(const HRESULT& result)
{
    if (result == S_OK) {
        return;
    }

    std::string message;

    switch (result) {

    case E_INVALIDARG:
        message = "One or more arguments are invalids.";

    case E_ACCESSDENIED:
        message = "Acces Denied.";

    case E_NOINTERFACE:
        message = "Interface does not exist.";

    case E_NOTIMPL:
        message = "Not implemented method.";

    case E_OUTOFMEMORY:
        message = "Out of memory.";

    case E_POINTER:
        message = "Invalid pointer.";

    case E_UNEXPECTED:
        message = "Unexpecter error.";

    case E_FAIL:
        message = "Failure";

    default:
        message = "Unknown : " + std::to_string(result);
    }

    throw std::exception(message.c_str());
}

Upvotes: 1

Views: 3188

Answers (2)

ViH
ViH

Reputation: 447

It is suppressable with a pragma:

#pragma warning(disable:4996) 
#include <sphelper.h>
#pragma warning(default: 4996)

Upvotes: 1

Benj
Benj

Reputation: 32398

GetVersionEx is being used by the header sphelper.h which you're including. It's using it to check that the function SpGetDescription() is running on Vista or later. You could probably work around this issue by targeting the 8.1 SDK version instead of 10. However, it's bad that the shipped MS SAPI API in the Windows 10 SDK is using functions which are deprecated in Windows 10.. I'd say this is a MS issue.

Alternately this would work:

#define FKG_FORCED_USAGE 1
#include <sphelper.h>
#undef FKG_FORCED_USAGE

Upvotes: 1

Related Questions