When you get the recognition, the SPPHRASE data associated with the recognition contains the subrules and property data and where they occur in the recognition.
So, if you had a rule or property tag for 'Name', you could find the words associated with 'Name'.
For example, given your grammar
<GRAMMAR LANGID="409">
<RULE NAME="SOUNDLOG" TOPLEVEL="ACTIVE">
<OPT>
<DICTATION MAX="INF"/>
</OPT>
<L>
<P>name</P>
</L>
<OPT>
<DICTATION MAX="INF"/>
</OPT>
</RULE>
</GRAMMAR>
if you change it to
<GRAMMAR LANGID="409">
<RULE NAME="SOUNDLOG" TOPLEVEL="ACTIVE">
<OPT>
<DICTATION MAX="INF"/>
</OPT>
<L PROPNAME='name'>
<P VAL='name'>name</P>
</L>
<OPT>
<DICTATION MAX="INF"/>
</OPT>
</RULE>
</GRAMMAR>
you could find the words that correspond to 'name' like this:
HRESULT OnRecognition(ISpRecoResult* pResult)
{
SPPHRASE *pPhrase;
HRESULT hr = pResult->GetPhrase(&pPhrase);
if (SUCCEEDED(hr))
{
const SPPHRASEPROPERTY pProp = FindProperty(pPhrase->pProperty, L"name");
if (pRule)
{
LPWSTR text(NULL);
hr = pResult->GetText(pProp->ulFirstElement, pProp->ulCountOfElements, TRUE, &text, NULL);
if (SUCCEEDED(hr))
{
// do something with text
::CoTaskMemFree(text);
}
}
}
return hr;
}
const SPPHRASEPROPERTY* FindProperty(const SPPHRASEPROPERTY* pProp, LPCWSTR what) const
{
while (pProp!=NULL)
{
if (pProp->pFirstChild != NULL)
{
const SPPHRASEPROPERTY* pFoundProp = FindRule(pProp->pFirstChild, what);
if (pFoundProp)
{
return pFoundProp;
}
}
if (pProp->pszName != NULL && wcsstr(pProp->pszName, what) != NULL)
{
return pProp;
}
pProp = pProp->pNextSibling;
}
return NULL;
}
This code looks specifically for the text covered by the property. However, it's often better to use the val attributes to identify items without binding your code explicitly to the grammar. This allows you to tweak the grammar (or add equivalent values) without changing your code. To use the values, simply use the SPPHRASEPROPERTY.pszValue or vValue fields after fetching the property (instead of using ISpPhrase::GetText).