// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright © Microsoft Corporation. All rights reserved /****************************************************************************** * srengalt.h * This file contains the implementation of the CSrEngineAlternates class. * This implements the interface ISpSRAlternates. * When an app calls GetAlternates or Commit on a result, SAPI will * look for the AlternatesCLSID field in the engine object token, and * create this object. * It will then call the methods here, passing the relevant results information. * This includes any serialized data the main engine has returned with * the results to allow alternates to be generated off-line. ******************************************************************************/ #include "stdafx.h" #include "srengalt.h" /**************************************************************************** * CSrEngineAlternates::GetAlternates * *---------------------------* * Description: * This method generates alternate phrases when SAPI requests them. * The method reads the extra information returned from the SR engine * inside the results object. This gets returned * as alternates phrases to SAPI. In addition this method can find a private interface to engine * from the context and query the engine for additional result information. * * The engine must have returned info serialised within the results object * allowing us to produce alternatives. This is the case in the sample engine. * * Return: * S_OK * FAILED(hr) *****************************************************************************/ STDMETHODIMP CSrEngineAlternates::GetAlternates(SPPHRASEALTREQUEST *pAltRequest, SPPHRASEALT **ppAlts, ULONG *pcAlts) { HRESULT hr = S_OK; // We will just produce one alternate // This will replace the words in the original phrase on a one-to-one basis // Real alternates may have different numbers of words to original, // and replace only parts of the original. *pcAlts = 1; *ppAlts = (SPPHRASEALT *)::CoTaskMemAlloc(sizeof(SPPHRASEALT)); if( *ppAlts == NULL) { return E_OUTOFMEMORY; } (*ppAlts)[0].ulStartElementInParent = pAltRequest->ulStartElement; (*ppAlts)[0].cElementsInParent = pAltRequest->cElements; (*ppAlts)[0].cElementsInAlternate = pAltRequest->cElements; (*ppAlts)[0].pvAltExtra = NULL; (*ppAlts)[0].cbAltExtra = 0; // Create and fill an SPPHRASE structure SPPHRASE phrase; memset(&phrase, 0, sizeof(phrase)); phrase.cbSize = sizeof(phrase); // An alternates analyzer should really query its SR engine to find it's lang id. // For the sample engine we will just hard-code this phrase.LangID = 1033; WCHAR *pAlts = (WCHAR *) pAltRequest->pvResultExtra; ULONG nAltChars = pAltRequest->cbResultExtra / sizeof(WCHAR); ULONG nWord = 0; // Count words in alternate data ULONG i; for(i = 0; i < nAltChars; i++) { if(iswspace(pAlts[i]) || pAlts[i] == '\0') { nWord++; } } // Allocate elements SPPHRASEELEMENT* pElements = (SPPHRASEELEMENT*)_malloca(sizeof(SPPHRASEELEMENT) * nWord); memset(pElements, 0, sizeof(SPPHRASEELEMENT)*nWord); // Add words in alternate to elements ULONG cW = 0; ULONG cWord = 0; for(i = 0; i < nAltChars && cWord < nWord; i++) { if(iswspace(pAlts[i]) || pAlts[i] == '\0') { pElements[cWord].bDisplayAttributes = SPAF_ONE_TRAILING_SPACE; WCHAR *pszWord = (WCHAR *)_malloca(sizeof(WCHAR) * (i - cW + 1)); wcsncpy_s(pszWord, i - cW + 1, &pAlts[cW], i - cW); pszWord[i - cW] = '\0'; pElements[cWord].pszDisplayText = pszWord; cW = i + 1; cWord++; } } // Add elements to phrase phrase.Rule.ulCountOfElements = cWord; phrase.pElements = pElements; // Make phrase builder and add phrase info CComPtr cpBuilder; hr = cpBuilder.CoCreateInstance(CLSID_SpPhraseBuilder); if(SUCCEEDED(hr)) { hr = cpBuilder->InitFromPhrase(&phrase); } if(SUCCEEDED(hr)) { (*ppAlts)[0].pPhrase = cpBuilder; (*ppAlts)[0].pPhrase->AddRef(); } // Alternates class can also query enginethrough private interface CComPtr m_cpExt; hr = pAltRequest->pRecoContext->QueryInterface(&m_cpExt); if(SUCCEEDED(hr)) { hr = m_cpExt->ExamplePrivateEngineCall(); } for(i = 0; i < cWord; i++) { _freea((void*)pElements[i].pszDisplayText); } _freea(pElements); if (FAILED(hr)) { ::CoTaskMemFree(*ppAlts); } return hr; } /**************************************************************************** * CSrEngineAlternates::Commit * *---------------------------* * Description: * Here the engine could use the information from the application * about which was the correct alternate in order to do supervised * adaptation. * In this sample we do nothing here. * Return: * S_OK *****************************************************************************/ STDMETHODIMP CSrEngineAlternates::Commit(SPPHRASEALTREQUEST *pAltRequest, SPPHRASEALT *pAlt, void **ppvResultExtra, ULONG *pcbResultExtra) { return S_OK; }