162 lines
5.5 KiB
C++
162 lines
5.5 KiB
C++
// 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<ISpPhraseBuilder> 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<ISampleSRExtension> 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;
|
|
}
|