2025-11-28 00:35:46 +09:00

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;
}