1. 程式人生 > >IBM Voice CMDMenu語音命令控制技術 適用於Emmbbed IBM Viavoice的語音菜單,語音撥號

IBM Voice CMDMenu語音命令控制技術 適用於Emmbbed IBM Viavoice的語音菜單,語音撥號

hat framework remove inpu delete nim cdata fyi actions

class CVCmdMenuDlg;

class CIVCmdNotifySink: public IVCmdNotifySink
{
private:
DWORD m_dwRefCnt; /* count how many people our using us (the object)*/
CVCmdMenuDlg *pDlg; /* used to send notifications back to demo dialog object */

public:
CIVCmdNotifySink (void); /* obligatory constructor*/
~CIVCmdNotifySink (void); /* obligatory destructory*/
CIVCmdNotifySink( CVCmdMenuDlg *pDlgInit ); /* overloaded constructor for this demo */

/* IUnknown */
STDMETHODIMP QueryInterface (REFIID, LPVOID FAR*);
STDMETHODIMP_(ULONG)AddRef(void); /* increment count*/
STDMETHODIMP_(ULONG)Release(void); /* decrements count*/

/* IVCCmdNotifySink member functions */
STDMETHODIMP CommandRecognize (DWORD, PVCMDNAME, DWORD, DWORD, PVOID, DWORD, PSTR, PSTR);
STDMETHODIMP CommandOther (PVCMDNAME, PTSTR);
STDMETHODIMP CommandStart (void);
STDMETHODIMP MenuActivate (PVCMDNAME, BOOL);
STDMETHODIMP UtteranceBegin (void);
STDMETHODIMP UtteranceEnd (void);
STDMETHODIMP VUMeter (WORD);
STDMETHODIMP AttribChanged (DWORD);
STDMETHODIMP Interference (DWORD);
};

typedef CIVCmdNotifySink* PCIVCmdNotifySink;


#include "stdafx.h"
#include "winreg.h" // supports reading the registry
#include "speech.h" // defines SAPI structures, interfaces
#include "VCmdNfy.h"
#include "VCmdMenu.h"
#include "VCmdDlg.h"
#include "initguid.h" // required by references to GUIDs
#include "SrWrapEn.h" // defines IBM speech engine GUIDs

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// external for accessing the application object
extern CVCmdMenuApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
CAboutDlg();

// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVCmdMenuDlg dialog

CVCmdMenuDlg::CVCmdMenuDlg(CWnd* pParent /*=NULL*/)
: CDialog(CVCmdMenuDlg::IDD, pParent)
{
// don‘t forget to init pointers being tested later on !!! 11/05/96 pwa
gpIVCmdMenu=NULL;
gpIVoiceCommand=NULL;

//{{AFX_DATA_INIT(CVCmdMenuDlg)
m_strRecoEcho = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CVCmdMenuDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CVCmdMenuDlg)
DDX_Control(pDX, IDC_STOP, m_buttonDeactivate);
DDX_Control(pDX, IDC_START, m_buttonActivate);
DDX_Control(pDX, IDC_PHRASELIST, m_listPhrase);
DDX_Text(pDX, IDC_RECOEOCHO, m_strRecoEcho);
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CVCmdMenuDlg, CDialog)
//{{AFX_MSG_MAP(CVCmdMenuDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_START, OnActivate)
ON_BN_CLICKED(IDC_STOP, OnDeactivate)
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVCmdMenuDlg message handlers

// Return value of UseSpeech in registry, or -1 on read error.
int CVCmdMenuDlg::GetUseSpeech()
{
HKEY hKey;
DWORD dwType, dwSize, dwVal;
CString s;

dwType = REG_DWORD;
dwSize = sizeof(DWORD);

s.LoadString( IDS_KEYVOICE );

if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, s.GetBuffer(0), 0, KEY_READ, &hKey) ) {
CString sMsg;
AfxFormatString1( sMsg, IDS_ERROR14, s.GetBuffer(0) );
AfxMessageBox( sMsg );
return -1;
}

s.LoadString( IDS_VALUE );
if( ERROR_SUCCESS != RegQueryValueEx (hKey, s.GetBuffer(0), 0, &dwType, (LPBYTE)&dwVal, &dwSize) ) {
CString sMsg;
AfxFormatString1( sMsg, IDS_ERROR15, s.GetBuffer(0) );
AfxMessageBox( sMsg );
return -1;
}

RegCloseKey (hKey);

return (int)dwVal;
}

// Create a pointer to a voice command interface
// On error, show message box and return 0.
// On success, return valid pointer.
PIVOICECMD CVCmdMenuDlg::CreatePIVCmd()
{
PIVOICECMD pIVCmd = 0;

if ( S_OK != CoCreateInstance
(CLSID_VCmd, // voice command object class identifier
NULL,
CLSCTX_LOCAL_SERVER,
IID_IVoiceCmd, // voice command object interface identifier
(LPVOID*)&pIVCmd //ptr to voice command object interface
)
)
AfxMessageBox( IDS_ERROR1 );

return pIVCmd;
}

// See if default site is using IBM speech engine
// If not, ask user if we can change it.
// Show error message and return FALSE on any error
// Assume: gpIVoiceCommand has already been registered
BOOL CVCmdMenuDlg::CheckSelectIBMEngine()
{

BOOL bRc = FALSE;
PIVCMDATTRIBUTES pIVCmdAttr = 0;
GUID modeGuid;
BOOL bMBoxRc = FALSE;

if ( !gpIVoiceCommand )
return FALSE;

if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
AfxMessageBox( IDS_ERROR16 );
else {
if ( NOERROR != pIVCmdAttr->SRModeGet(&modeGuid) )
AfxMessageBox( IDS_ERROR17 );
else {
//check for US English navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeUS,modeGuid) ) {
theApp.LanguageID=LANG_ENGLISH;
theApp.SubLangID =SUBLANG_ENGLISH_US;
bRc=TRUE;
}

//check for UK English navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeUK,modeGuid) ) {
theApp.LanguageID=LANG_ENGLISH;
theApp.SubLangID =SUBLANG_ENGLISH_UK;
bRc=TRUE;
}

//check for German navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeGR,modeGuid) ) {
theApp.LanguageID=LANG_GERMAN;
theApp.SubLangID =SUBLANG_GERMAN;
bRc=TRUE;
}

//check for French navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeFR,modeGuid) ) {
theApp.LanguageID=LANG_FRENCH;
theApp.SubLangID =SUBLANG_FRENCH;
bRc=TRUE;
}

//check for Italian navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeIT,modeGuid) ) {
theApp.LanguageID=LANG_ITALIAN;
theApp.SubLangID =SUBLANG_ITALIAN;
bRc=TRUE;
}

//check for Spanish navigation mode
if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeES,modeGuid) ) {
theApp.LanguageID=LANG_SPANISH;
theApp.SubLangID =SUBLANG_SPANISH;
bRc=TRUE;
}

//prompt on unknown GUID mode
if ( !bRc )
bMBoxRc = AfxMessageBox(IDS_STRING151, MB_OKCANCEL);

if ( !bRc && bMBoxRc == IDOK ) {
if ( NOERROR != pIVCmdAttr->SRModeSet(CLSID_SREngineEnumIBMContinuousModeUS) ) {
// if ( NOERROR != pIVCmdAttr->SRModeSet(CLSID_SREngineEnumIBMContinuousModeGR) ) {
AfxMessageBox( IDS_ERROR18 );
bRc = FALSE;
}
else {
theApp.LanguageID=LANG_ENGLISH;
theApp.SubLangID =SUBLANG_ENGLISH_US;
// theApp.LanguageID=LANG_GERMAN;
// theApp.SubLangID =SUBLANG_GERMAN;
bRc = TRUE;
}
}
else if ( !bRc && bMBoxRc == IDCANCEL ) {
// Want to use whatever engine is set in site.
bRc = TRUE;
}
}
}

if ( pIVCmdAttr )
pIVCmdAttr->Release();

return bRc;
}

// Create a voice command menu for this app
// nAppState is the resource ID of a string specifying app state when menu should
// be active.
// dwFlags specifies how to create the menu
// Shows message box on any error and returns 0
// Returns pointer to menu object on success.
PIVCMDMENU CVCmdMenuDlg::CreateMainMenu( UINT nAppState, DWORD dwFlags )
{
PIVCMDMENU pIVCmdMenu = 0;
VCMDNAME VCmdName; // Command Name
LANGUAGE Language; // language to use
CString s;
int iLangStringID;

//findresourceex
// Get our app name from our resource file
s.LoadString( IDS_STRING148 );
// Truncate our name to field length
lstrcpy( VCmdName.szApplication,
(s.Left(VCMD_APPLEN)).GetBuffer(0)
);

// Get our app state from our resource file
if ( !s.LoadString( nAppState ) )
AfxMessageBox( IDS_ERROR19 );
// Truncate our state to field length
lstrcpy( VCmdName.szState,
(s.Left(VCMD_STATELEN)).GetBuffer(0)
);

// Specify United States English language model
Language.LanguageID = theApp.LanguageID;

switch(theApp.LanguageID)
{
case LANG_ENGLISH:
switch(theApp.SubLangID)
{
case SUBLANG_ENGLISH_US:
iLangStringID=IDS_Lang_US;
break;
case SUBLANG_ENGLISH_UK:
iLangStringID=IDS_Lang_UK;
break;
}
break;
case LANG_GERMAN:
iLangStringID=IDS_Lang_GR;
break;
case LANG_FRENCH:
iLangStringID=IDS_Lang_FR;
break;
case LANG_ITALIAN:
iLangStringID=IDS_Lang_IT;
break;
case LANG_SPANISH:
iLangStringID=IDS_Lang_ES;
break;
default:
iLangStringID=IDS_Lang_US;
break;
}

s.LoadString( iLangStringID );
lstrcpy (Language.szDialect,
(s.Left(LANG_LEN)).GetBuffer(0)
);

if ( NOERROR != gpIVoiceCommand->MenuCreate(&VCmdName,
&Language,
dwFlags,
&pIVCmdMenu
)
)
AfxMessageBox( IDS_ERROR4 );

return pIVCmdMenu;
}

// Initialize SAPI voice command interface on default site,
// register a notification sink, and create a temporary voice command menu.
// On success, global pointers
// gpIVoiceCommand
// gpVCmdNotifySink
// gpIVCmdMenu
// are non-zero and ready to be used.
// Error messages displayed as appropriate.
// Application exits if error reading required entries in registry
// If default site is not using IBM engine, user is given a chance to set it,
void CVCmdMenuDlg::OnInitSpeech()
{

/* ----------------------------------------------------------- */
/* Check the registry to see if user has installed and enabled */
/* SAPI voice recognition */
/* ----------------------------------------------------------- */
int nUseSpeech = GetUseSpeech();
switch( nUseSpeech ) {
case -1:
// Cannot find required key/value in registry. Something‘s wrong
// with user‘s install of SAPI etc.
AfxMessageBox( IDS_STRING147 );
//OnClose(); //don‘t do that !!! 11/05/96 pwa
this->EndDialog(0); //bye-bye due to errors 11/05/96 pwa
break;
case 0:
// User has installed SAPI speech, but it is not enabled.
// You should ask the user whether to continue.
// We‘re going to go ahead anyway.
// See SAPI Speech API Developer‘s Guide, Chapter 8.
case 1:
// User has installed and enabled SAPI speech
default:
// The key/value exists, but the value is unexpected...
break;
}

/* -------------------------------------------------------- */
/* Create an instance of the voice command and voice menu */
/* objects. */
/* -------------------------------------------------------- */
gpIVoiceCommand = 0;
gpVCmdNotifySink = 0;
gpIVCmdMenu = 0;

gpIVoiceCommand = CreatePIVCmd();

if ( gpIVoiceCommand ) {
/* -------------------------------------------------- */
/* Create the VCmd notification sink interface object */
/* ---------------------------------------------------*/
gpVCmdNotifySink = new CIVCmdNotifySink( this );
if ( 0 == gpVCmdNotifySink )
AfxMessageBox( IDS_ERROR2 );
else {
/* ------------------------------------------------------ */
/* Register the notification sink with the voice cmd obj. */
/* We are passing VCMDRF_ALLMESSAGES because we want our */
/* app to be notified of all possible notifications. */
/* ------------------------------------------------------ */
// Note: This version of the call uses the default
// site with default settings
if ( NOERROR != gpIVoiceCommand->Register(
"", // means voice input is from computer
gpVCmdNotifySink,// adr of voice-command object
// notification interface
IID_IVCmdNotifySink,// GUID of sink type being passed
VCMDRF_ALLMESSAGES,// send us all notification msgs
NULL // use the voice-site settings from the
// registry, or the defaults if there are none
)
)
AfxMessageBox( IDS_ERROR3 );
else {
// See if default engine is IBM. Let user select it.
if ( !CheckSelectIBMEngine() )
return;

// init the voice command list
InitListBox();
// Save current SAPI site enabled state. We‘ll restore it when we exit.
gdwSiteState = GetSiteState();
// Now, make sure SAPI site is enabled
SetSiteState( TRUE );

gpIVCmdMenu = CreateMainMenu( IDS_STRING149, VCMDMC_CREATE_TEMP );
}
}
}
}

void CVCmdMenuDlg::OnExitSpeech()
{
/* ------------------------------------------ */
/* Release the voice command menu interface */
/* ------------------------------------------ */
if (gpIVCmdMenu) {
gpIVCmdMenu->Release();
gpIVCmdMenu = 0;
}

/* ------------------------------------------ */
/* Restore the voice command enabled state */
/* before releasing voice command object */
/* ------------------------------------------ */
SetSiteState( gdwSiteState );

/* ------------------------------------------ */
/* Release the voice command object interface */
/* ------------------------------------------ */
if (gpIVoiceCommand) {
gpIVoiceCommand->Release();
gpIVoiceCommand = 0;
}

// Note: gpIVoiceCommand object releases our gpVCmdNotifySink object,
// which we "new"ed in OnInitSpeech(). Its release logic deletes it
// when the last (ie. one and only) reference is released, so we
// do not delete it here.

}

BOOL CVCmdMenuDlg::OnInitDialog()
{
m_strRecoEcho.LoadString( IDS_INITRECOECHO );

CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}

// Set the icon for this dialog. The framework does this automatically
// when the application‘s main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

OnInitSpeech(); // Initialize SAPI voice command speech recognition

return TRUE; // return TRUE unless you set the focus to a control
}

void CVCmdMenuDlg::InitListBox()
{
/********************************************************/
/* Initialize the phrase list box. */
/* This code depends on the phrases being consecutively */
/* numbered string resources between IDS_PhraseBase and */
/* IDS_PhraseLast. */
/********************************************************/
CString s;
int iPhraseBase, iPhraseLast;

switch(theApp.LanguageID)
{
case LANG_ENGLISH:
switch(theApp.SubLangID)
{
case SUBLANG_ENGLISH_US:
iPhraseBase=IDS_PhraseBase_US;
iPhraseLast=IDS_PhraseLast_US;
break;
case SUBLANG_ENGLISH_UK:
iPhraseBase=IDS_PhraseBase_UK;
iPhraseLast=IDS_PhraseLast_UK;
break;
}
break;
case LANG_GERMAN:
iPhraseBase=IDS_PhraseBase_GR;
iPhraseLast=IDS_PhraseLast_GR;
break;
case LANG_FRENCH:
iPhraseBase=IDS_PhraseBase_FR;
iPhraseLast=IDS_PhraseLast_FR;
break;
case LANG_ITALIAN:
iPhraseBase=IDS_PhraseBase_IT;
iPhraseLast=IDS_PhraseLast_IT;
break;
case LANG_SPANISH:
iPhraseBase=IDS_PhraseBase_ES;
iPhraseLast=IDS_PhraseLast_ES;
break;
default:
iPhraseBase=IDS_PhraseBase_US;
iPhraseLast=IDS_PhraseLast_US;
break;
}

for( int i = iPhraseBase + 1; i < iPhraseLast; i++ ) {
if ( s.LoadString(i) ) {
if ( LB_ERR == m_listPhrase.AddString( s.GetBuffer(0) ) ) {
AfxMessageBox( IDS_ERROR5 );
break;
}
}
}
m_listPhrase.SetSel( 0 ); // select the first phrase
m_buttonDeactivate.EnableWindow( FALSE );
}

void CVCmdMenuDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CVCmdMenuDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CVCmdMenuDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}

void CVCmdMenuDlg::OnActivate()
{
// TODO: Add your control notification handler code here

// If no phrases selected, then we can‘t build a voice command menu
int nCount = m_listPhrase.GetSelCount();
if ( 0 >= nCount ) {
AfxMessageBox( IDS_STRING141 );
return;
}

// If voice command menu setup ok
if ( VoiceCmdMenuEmpty()
&& VoiceCmdMenuFill()
&& VoiceCmdMenuActivate()
) {
// toggle buttons
m_buttonActivate.EnableWindow( FALSE );
m_buttonDeactivate.EnableWindow( TRUE );
// reinitialize recognized text area
m_strRecoEcho.LoadString( IDS_INITRECOECHO );
UpdateData( FALSE );
}
}

void CVCmdMenuDlg::OnDeactivate()
{
// TODO: Add your control notification handler code here
if ( gpIVCmdMenu )
if ( NOERROR != gpIVCmdMenu->Deactivate() )
AfxMessageBox( IDS_ERROR20 );

m_buttonActivate.EnableWindow( TRUE );
m_buttonDeactivate.EnableWindow( FALSE );

}


BOOL CVCmdMenuDlg::VoiceCmdMenuActivate()
{
HRESULT hResult;

// check initialization did not fail
if ( 0 == gpIVCmdMenu )
return FALSE;

// first argument is handle of window to associate with this menu. NULL makes it global to this application
// second argument is whether menu should be active when voice reco is "awake" (0) or "asleep" (VWGFLAG_ASLEEP)
hResult = gpIVCmdMenu->Activate( NULL, 0 );
if ( NOERROR != hResult ) {
AfxMessageBox( IDS_ERROR6 );
return FALSE;
} else return TRUE;

}

BOOL CVCmdMenuDlg::VoiceCmdMenuEmpty()
{
HRESULT hResult;
DWORD dwNum;

// check initialization did not fail
if ( 0 == gpIVCmdMenu )
return FALSE;

// get the number of items in a voice command menu
hResult = gpIVCmdMenu->Num( &dwNum );
if ( NOERROR != hResult ) {
AfxMessageBox( IDS_ERROR7 );
return FALSE;
}

// remove items from first parameter to first plus second parameter from a voice command menu
// if third parameter is VCMD_BY_IDENTIFIER, then second parameter is identifier of commands to remove
if ( dwNum ) {
hResult = gpIVCmdMenu->Remove( 1, dwNum, VCMD_BY_POSITION );
if ( NOERROR != hResult ) {
AfxMessageBox( IDS_ERROR8 );
return FALSE;
}
}

return TRUE;
}

BOOL CVCmdMenuDlg::VoiceCmdMenuFill()
{
HRESULT hResult;
SDATA data;
PVCMDCOMMAND pVCmdCmd;
DWORD dwNum, dwStart, dwSize, dwCatSize;
CHAR szCat[] = "Main";
int *nArraySelect;

// check initialization did not fail
if ( 0 == gpIVCmdMenu )
return FALSE;

dwNum = m_listPhrase.GetSelCount();
if ( 0 == dwNum ) {
AfxMessageBox( IDS_STRING142 );
return FALSE;
}
nArraySelect = (int *)CoTaskMemAlloc( dwNum* sizeof(int) );
if ( NULL == nArraySelect ) {
AfxMessageBox( IDS_ERROR9 );
return FALSE;
}
m_listPhrase.GetSelItems( dwNum, nArraySelect );

// SDATA can refer to an "array" of VCMDCOMMAND structures.
// We‘ll build this array be reallocating pVCmdCmd, once
// each time through our list loop below.
dwSize = 0;
pVCmdCmd = (PVCMDCOMMAND)CoTaskMemAlloc( dwSize );
if ( 0 == pVCmdCmd ) {
AfxMessageBox( IDS_ERROR10 );
return FALSE;
}

// The variable data at the end of VCMDCOMMAND structure must all begin on 32-bit boundaries
// See SAPI specification for more details
dwCatSize = 1 + lstrlen( szCat );
dwCatSize = (dwCatSize+3)&(~3);

for( int i = 0; i < (int)dwNum; i++ ) {
PCHAR pNext;
PVCMDCOMMAND pVCmdNew;
DWORD dwStrSize, dwAlignSize, dwNewSize;

// extend existing structure for next VCMDCOMMAND structure
dwStrSize = 1 + m_listPhrase.GetTextLen( nArraySelect[i] );
dwAlignSize = (dwStrSize+3)&(~3);
dwNewSize = dwSize + sizeof(VCMDCOMMAND) + 2*dwAlignSize + dwCatSize + sizeof(DWORD);
pVCmdCmd = (PVCMDCOMMAND)CoTaskMemRealloc( pVCmdCmd, dwNewSize );
if ( 0 == pVCmdCmd ) {
AfxMessageBox( IDS_ERROR11 );
return FALSE;
}
// fill in the new VCMDCOMMAND structure
pNext = (PCHAR)pVCmdCmd + dwSize;
memset( pNext, 0, dwNewSize - dwSize );
pVCmdNew = (PVCMDCOMMAND)pNext;
pVCmdNew->dwSize = dwNewSize - dwSize; // sizeof this structure
pVCmdNew->dwFlags = 0; // these flags can specify confirmaton, disabled. See SAPI spec.
pVCmdNew->dwCommandText= NULL; // use dwCommand to show voice command menu to user
pVCmdNew->dwActionSize = sizeof(DWORD); // size of action data
// fill in the variable data at end of new structure
pNext += sizeof(VCMDCOMMAND); // variable data starts at abdata[]
pVCmdNew->dwAction = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to app-unique action code
*(DWORD *)(pNext) = (DWORD)i; // make up an action code for this command
pNext += sizeof(DWORD);
pVCmdNew->dwCommand = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command string
if ( (int)dwStrSize != 1 + m_listPhrase.GetText(nArraySelect[i], (LPTSTR)pNext) ) {
AfxMessageBox( IDS_ERROR12 );
return FALSE;
}
pNext += dwAlignSize;
pVCmdNew->dwDescription = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command description
if ( (int)dwStrSize != 1 + m_listPhrase.GetText(nArraySelect[i], (LPTSTR)pNext) ) {
AfxMessageBox( IDS_ERROR12 );
return FALSE;
}
pNext += dwAlignSize;
pVCmdNew->dwCategory = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command category
strcpy( pNext, szCat );
dwSize = dwNewSize;
}

data.pData = pVCmdCmd;
data.dwSize = dwSize;

hResult = gpIVCmdMenu->Add( dwNum, data, &dwStart );
if ( NOERROR != hResult ) {
AfxMessageBox( IDS_ERROR13 );
return FALSE;
}

CoTaskMemFree( nArraySelect );
CoTaskMemFree( data.pData );
return TRUE;
}

void CVCmdMenuDlg::CommandRecognized( PSTR pszText )
{
m_strRecoEcho = pszText;
UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::CommandOther( PSTR pszText )
{
if ( NULL == pszText )
m_strRecoEcho.LoadString( IDS_NOTRECOED );
else {
m_strRecoEcho.LoadString( IDS_CMDOTHER );
m_strRecoEcho += pszText;
}
UpdateData( FALSE );
}
void CVCmdMenuDlg::TooNoisy()
{
m_strRecoEcho.LoadString( IDS_TOONOISY );
UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::NoSignal()
{
m_strRecoEcho.LoadString( IDS_NOSIGNAL );
UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::TooLoud()
{
m_strRecoEcho.LoadString( IDS_TOOLOUD );
UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::TooQuiet()
{
m_strRecoEcho.LoadString( IDS_TOOQUIET );
UpdateData( FALSE ); // send fields to dialog window
}

// Read enabled state of voice command site
// Show message box on error.
DWORD CVCmdMenuDlg::GetSiteState()
{
PIVCMDATTRIBUTES pIVCmdAttr = 0;
DWORD dwEnabled = 0;

if ( gpIVoiceCommand ) {
if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
AfxMessageBox( IDS_ERROR16 );
else {
if ( NOERROR != pIVCmdAttr->EnabledGet(&dwEnabled) )
AfxMessageBox( IDS_ERROR21 );
}
}

if ( pIVCmdAttr )
pIVCmdAttr->Release();

return dwEnabled;
}

// Set enabled state of voice command site
// Show message box on error.
void CVCmdMenuDlg::SetSiteState( DWORD dwEnabled )
{
PIVCMDATTRIBUTES pIVCmdAttr = 0;

if ( gpIVoiceCommand ) {
if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
AfxMessageBox( IDS_ERROR16 );
else {
if ( NOERROR != pIVCmdAttr->EnabledSet(dwEnabled) )
AfxMessageBox( IDS_ERROR22 );
}
}

if ( pIVCmdAttr )
pIVCmdAttr->Release();
}

void CVCmdMenuDlg::OnOK()
{
// TODO: Add extra validation here

// Restore site state and shut down voice reco objects...
OnExitSpeech();

CDialog::OnOK();
}

void CVCmdMenuDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default

// Restore site state and shut down voice reco objects...
OnExitSpeech();

CDialog::OnClose();
}

void CVCmdMenuDlg::WinHelp(DWORD dwData, UINT nCmd)
{
// TODO: Add your specialized code here and/or call the base class
return;
}

需要源碼的留下郵件,我來發,

再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow

IBM Voice CMDMenu語音命令控制技術 適用於Emmbbed IBM Viavoice的語音菜單,語音撥號