|
|
#include "stdafx.h"
#include "resource.h"
#include <sapi.h>
#include <string.h>
#include "SRDlg.h"
#include <spddkhlp.h>
#include <initguid.h>
#include "helpresource.h"
#include "richedit.h"
#include "mlang.h"
#include "Lmcons.h"
static DWORD aKeywordIds[] = { // Control ID // Help Context ID
IDC_ADD, IDH_ADD, IDC_MODIFY, IDH_SETTINGS, IDC_DELETE, IDH_DELETE, IDC_TRN_ADVICE, IDH_NOHELP, IDC_USER, IDH_USER, IDC_MIC_ICON, IDH_NOHELP, IDC_COMBO_RECOGNIZERS, IDH_ENGINES, IDC_SR_ADV, IDH_SR_ADV, IDC_USERTRAINING, IDH_USERTRAINING, IDC_PROGRESS1, IDH_PROGRESS1, IDC_AUD_IN, IDH_AUD_IN, IDC_MICWIZ, IDH_MICWIZ, IDC_SR_ICON, IDH_NOHELP, IDC_SR_CAPTION, IDH_NOHELP, IDC_SR_LIST_CAP, IDH_NOHELP, IDC_TRAIN_GROUP, IDH_NOHELP, IDC_ADVICE, IDH_NOHELP, IDC_IN_GROUP, IDH_NOHELP, IDC_MIC_CAP, IDH_NOHELP, IDC_MIC_INST, IDH_NOHELP, 0, 0 };
/*****************************************************************************
* CSRDlg::CreateRecoContext * *---------------------------* * Description: * This creates a new instance of the recognizer with whatever is the * current defaults for the recognizer. * The "fInitialize" argument is FALSE by default. If set, it does * NOT attempt to set the m_pCurUserToken reco profile and instead * just picks up whatever CoCreateInstance() on the shared recognizer * gave it. * NOTE: The caller is responsible for displaying error messages to * the user when this fails. * Return: * S_OK * Failed HRESULT from recognizer/recocontext initialization functions ****************************************************************** BECKYW ***/ HRESULT CSRDlg::CreateRecoContext(BOOL *pfContextInitialized, BOOL fInitialize, ULONG ulFlags) { // Kill the reco context and notify sink first, if we have one
if ( m_cpRecoCtxt ) { m_cpRecoCtxt->SetNotifySink( NULL ); } m_cpRecoCtxt.Release();
HRESULT hr; // SOFTWARE ENGINEERING OPPORTUNITY (beckyw 8/24): This is a workaround for a
// bug that appears to repro only on my dev machine, in which the recostate
// needs to be inactive for this whole thing.
if ( m_cpRecoEngine ) { m_cpRecoEngine->SetRecoState( SPRST_INACTIVE ); }
if ( m_cpRecoEngine ) { SPRECOSTATE recostate; hr = m_cpRecoEngine->GetRecoState( &recostate );
// This is due to a SOFTWARE ENGINEERING OPPORTUNITY in which SetRecognizer( NULL )
// doesn't work if the recostate is SPRST_ACTIVE_ALWAYS.
// In this case, we temporarily switch the recostate
if ( SUCCEEDED( hr ) && (SPRST_ACTIVE_ALWAYS == recostate) ) { hr = m_cpRecoEngine->SetRecoState( SPRST_INACTIVE ); }
// Kick the recognizer
if ( SUCCEEDED( hr ) && (ulFlags & SRDLGF_RECOGNIZER) ) { hr = m_cpRecoEngine->SetRecognizer( NULL ); }
// Kick the audio input
if ( SUCCEEDED( hr ) && (ulFlags & SRDLGF_AUDIOINPUT)) { hr = m_cpRecoEngine->SetInput( NULL, TRUE ); }
// Set the recostate back if we changed it.
if ( (SPRST_ACTIVE_ALWAYS == recostate) ) { HRESULT hrRecoState = m_cpRecoEngine->SetRecoState( recostate ); if ( FAILED( hrRecoState ) ) { hr = hrRecoState; } } } else { hr = m_cpRecoEngine.CoCreateInstance( CLSID_SpSharedRecognizer ); }
if(!fInitialize && SUCCEEDED( hr )) { // Normally set to m_pCurUserToken
// When initializing this is not created yet so just set to default
hr = m_cpRecoEngine->SetRecoProfile(m_pCurUserToken); }
if ( SUCCEEDED( hr ) ) { hr = m_cpRecoEngine->CreateRecoContext(&m_cpRecoCtxt); } if ( SUCCEEDED( hr ) ) { hr = m_cpRecoCtxt->SetNotifyWindowMessage(m_hDlg, WM_RECOEVENT, 0, 0); }
if ( SUCCEEDED( hr ) ) { const ULONGLONG ullInterest = SPFEI(SPEI_SR_AUDIO_LEVEL); hr = m_cpRecoCtxt->SetInterest(ullInterest, ullInterest); }
// Set the pfContextInitialized flag if everything has gone OK;
// if something has not gone OK, clean up
if ( pfContextInitialized ) { // If we got here, the reco context has been initialized
*pfContextInitialized = SUCCEEDED( hr ); } if ( FAILED( hr )) { m_cpRecoCtxt.Release(); m_cpRecoEngine.Release();
return hr; }
#ifdef _DEBUG
// Let's make sure we actually have the right recognizer now
CComPtr<ISpObjectToken> cpCurDefaultToken; // What it should be
SpGetDefaultTokenFromCategoryId(SPCAT_RECOGNIZERS, &cpCurDefaultToken);
CComPtr<ISpObjectToken> cpRecognizerToken; m_cpRecoEngine->GetRecognizer( &cpRecognizerToken ); if ( cpRecognizerToken ) { CSpDynamicString dstrCurDefaultToken; cpCurDefaultToken->GetId( &dstrCurDefaultToken );
CSpDynamicString dstrRecognizerToken; cpRecognizerToken->GetId( &dstrRecognizerToken );
if ( 0 != wcsicmp( dstrCurDefaultToken, dstrRecognizerToken ) ) { OutputDebugString( L"Warning: We just created a recognizer that isn't the default!\n" ); } } #endif
// Now turn on the reco state for the volume meter
hr = m_cpRecoEngine->SetRecoState( SPRST_ACTIVE_ALWAYS );
return(hr); }
/*****************************************************************************
* SortCols * *-----------* * Description: * Comparison function for subitems in the reco list ****************************************************************** BRENTMID ***/ int CALLBACK SortCols( LPARAM pToken1, LPARAM pToken2, LPARAM pDefToken ) { USES_CONVERSION;
// Get the names
CSpDynamicString dstrDesc1; CSpDynamicString dstrDesc2; SpGetDescription( (ISpObjectToken *) pToken1, &dstrDesc1 ); SpGetDescription( (ISpObjectToken *) pToken2, &dstrDesc2 ); // First check if there is no description for either one.
// If there is no description, set it to "<no name>"
if ( !dstrDesc1.m_psz || !dstrDesc2.m_psz ) { WCHAR szNoName[ MAX_LOADSTRING ]; szNoName[0] = 0; ::LoadString( _Module.GetResourceInstance(), IDS_UNNAMED_RECOPROFILE, szNoName, sp_countof( szNoName ) ); USES_CONVERSION; if ( !dstrDesc1 ) { dstrDesc1 = szNoName; SpSetDescription( (ISpObjectToken *) pToken1, dstrDesc1 ); } if ( !dstrDesc2 ) { dstrDesc2 = szNoName; SpSetDescription( (ISpObjectToken *) pToken2, dstrDesc2 ); } }
if (pDefToken == pToken1) { return -1; // make sure pToken1 goes to top of list
} else if (pDefToken == pToken2) { return 1; // make sure pToken2 goes to top of list
}
// PREFIX: verify memory allocation
// if we failed a memory allocation somewhere return that they are equal so the sort will just leave them alone.
if ((NULL == dstrDesc1.m_psz) || (NULL == dstrDesc2.m_psz)) { return 0; }
return wcscmp(_wcslwr(dstrDesc1.m_psz), _wcslwr(dstrDesc2.m_psz)); }
/*****************************************************************************
* CSRDlg::RecoEvent * *-------------------* * Description: * Handles the SR events for the volume meter ****************************************************************** BRENTMID ***/ void CSRDlg::RecoEvent() { CSpEvent event; if (m_cpRecoCtxt) { while (event.GetFrom(m_cpRecoCtxt) == S_OK) { if (event.eEventId == SPEI_SR_AUDIO_LEVEL) { ULONG l = (ULONG)event.wParam; SendMessage( GetDlgItem ( m_hDlg, IDC_PROGRESS1 ), PBM_SETPOS, l, 0); } } } }
/*****************************************************************************
* TrySwitchDefaultEngine * *------------------------* * Description: * This function is called when we want to run some UI for the engine * the user has selected, but because we don't know which shared engine * is running and whether another app is using it we can't directly * create the UI. So this method temporarily switches the default recognizer, * and recreates the engine, and then checks its token. If another app * was using the engine we wouldn't be able to switch and we return S_FALSE. * A side effect of this method is that for the duration of the UI, the * default will be changed, even though the user hasn't yet pressed apply, * but there seems no good way round this. * * In the case that m_pCurRecoToken is actually the same token as the * one the currently-active recognizer uses, we don't need to create * a new recognizer and recocontext; instead we just return successfully. * Return: * S_OK * FAILED HRESULT of various functions * In particular, SPERR_ENGINE_BUSY means that someone else is * running the engine, so this couldn't be done. ****************************************************************** DAVEWOOD ***/ HRESULT CSRDlg::TrySwitchDefaultEngine( bool fShowErrorMessages) { HRESULT hr = S_OK; bool fMatch = false; // Set the new temporary default
if(SUCCEEDED(hr)) { hr = SpSetDefaultTokenForCategoryId(SPCAT_RECOGNIZERS, m_pCurRecoToken); }
if ( SUCCEEDED( hr ) && IsRecoTokenCurrentlyBeingUsed( m_pCurRecoToken ) ) { // No need to switch engine all over again: just keep the one in use
return S_OK; }
// Try to create the engine & context with the default
// then see if this was actually the engine we expected
if(SUCCEEDED(hr)) { hr = CreateRecoContext( ); }
if ( FAILED( hr ) && fShowErrorMessages ) { WCHAR szError[256]; szError[0] = '\0'; // What to complain about...
UINT uiErrorID = HRESULTToErrorID( hr );
if ( uiErrorID ) { LoadString(_Module.GetResourceInstance(), uiErrorID, szError, sp_countof(szError)); MessageBox(g_pSRDlg->m_hDlg, szError, m_szCaption, MB_ICONWARNING|g_dwIsRTLLayout); } }
return hr; }
/*****************************************************************************
* CSRDlg::ResetDefaultEngine * *----------------------------* * Description: * This function resets the engine default back to its original value. * If the engine already has the right token, it doesn't bother trying * to create the engine again and returns S_OK * Return: * S_OK * S_FALSE if the default was set back but no engine was created * FAILED HRESULT of SpSetDefaultTokenForCategoryId() ****************************************************************** DAVEWOOD ***/ HRESULT CSRDlg::ResetDefaultEngine( bool fShowErrorMessages ) { HRESULT hr = S_OK;
// Reset the old default
if(m_pDefaultRecToken) { hr = SpSetDefaultTokenForCategoryId(SPCAT_RECOGNIZERS, m_pDefaultRecToken); }
HRESULT hrRet = hr;
BOOL fContextInitialized = FALSE; if ( SUCCEEDED( hr ) ) { if ( IsRecoTokenCurrentlyBeingUsed( m_pDefaultRecToken ) ) { // No need to switch engine all over again: just keep the one in use
if ( m_cpRecoCtxt ) { fContextInitialized = TRUE; } else { hr = SPERR_UNINITIALIZED; } // The UI might have monkeyed with the recostate.
// Just in case, let's set it back to ACTIVE_ALWAYS
if ( SUCCEEDED( hr ) ) { hr = m_cpRecoEngine->SetRecoState( SPRST_ACTIVE_ALWAYS ); } } else { // Create the engine & context using the old default
hr = g_pSRDlg->CreateRecoContext( &fContextInitialized ); } }
if ( FAILED( hr ) ) { BOOL fContextInitialized = FALSE; hr = g_pSRDlg->CreateRecoContext( &fContextInitialized );
// Let's not complain about unsupported languages twice as this may be confusing
// to the user.
if ( FAILED( hr ) && ( SPERR_UNSUPPORTED_LANG != hr ) ) { RecoContextError( fContextInitialized, fShowErrorMessages, hr ); // The default was set back but no engine was successfully set up.
// A FAILED hresult is not necessary here since the user
// has been notified of the error
hrRet = S_FALSE; }
// Gray out all the buttons
::EnableWindow(::GetDlgItem(m_hDlg, IDC_USERTRAINING), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MICWIZ), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_SR_ADV), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MODIFY), FALSE); }
return hrRet; } /* CSRDlg::ResetDefaultEngine */
/*****************************************************************************
* CSRDlg::IsRecoTokenCurrentlyBeingUsed * *---------------------------------------* * Description: * Call GetRecognizer() on the recognizer currently in use, and * compare IDs ****************************************************************** BECKYW ****/ bool CSRDlg::IsRecoTokenCurrentlyBeingUsed( ISpObjectToken *pRecoToken ) { if ( !pRecoToken || !m_cpRecoEngine ) { return false; }
CComPtr<ISpObjectToken> cpRecoTokenInUse; HRESULT hr = m_cpRecoEngine->GetRecognizer( &cpRecoTokenInUse );
CSpDynamicString dstrTokenID; CSpDynamicString dstrTokenInUseID; if ( SUCCEEDED( hr ) ) { hr = pRecoToken->GetId( &dstrTokenID ); } if ( SUCCEEDED( hr ) ) { hr = cpRecoTokenInUse->GetId( &dstrTokenInUseID ); }
return ( SUCCEEDED( hr ) && (0 == wcscmp(dstrTokenID, dstrTokenInUseID)) ); } /* CSRDlg::IsRecoTokenCurrentlyBeingUsed */
/*****************************************************************************
* CSRDlg::HasRecognizerChanged * *------------------------------* * Description: * Look at the currently-requested default recognizer, compare against the * original default recognizer, and return true iff it is * different ****************************************************************** BECKYW ****/ bool CSRDlg::HasRecognizerChanged() { bool fChanged = false;
// Check the recognizer token
CSpDynamicString dstrCurDefaultRecognizerID; CSpDynamicString dstrCurSelectedRecognizerID; HRESULT hr = E_FAIL; if ( m_pDefaultRecToken ) { hr = m_pDefaultRecToken->GetId( &dstrCurDefaultRecognizerID ); } if ( SUCCEEDED( hr ) && m_pCurRecoToken ) { hr = m_pCurRecoToken->GetId( &dstrCurSelectedRecognizerID ); } if (SUCCEEDED( hr ) && ( 0 != wcsicmp( dstrCurDefaultRecognizerID, dstrCurSelectedRecognizerID ) )) { fChanged = true; }
return fChanged;
} /* CSRDlg::HasRecognizerChanged */
/*****************************************************************************
* CSRDlg::KickCPLUI * *-------------------* * Description: * Look at the currently-requested defaults, compare against the * original defaults, and enable the Apply button iff anything is * different ****************************************************************** BECKYW ****/ void CSRDlg::KickCPLUI() { // Check the default recognizer token
bool fChanged = HasRecognizerChanged();
// Check the default user token
CSpDynamicString dstrCurSelectedProfileID; HRESULT hr = E_FAIL; if ( m_pCurUserToken ) { hr = m_pCurUserToken->GetId( &dstrCurSelectedProfileID ); } if (SUCCEEDED( hr ) && m_dstrOldUserTokenId && ( 0 != wcsicmp( dstrCurSelectedProfileID, m_dstrOldUserTokenId ) )) { fChanged = true; }
// Check the audio input device
if ( m_pAudioDlg && m_pAudioDlg->IsAudioDeviceChanged() ) { fChanged = true; }
// If any tokens have been deleted, there has been a change
if ( m_iDeletedTokens > 0 ) { fChanged = true; }
// If any tokens have been added, there has been a change
if ( m_iAddedTokens > 0 ) { fChanged = true; }
// Tell the main propsheet
HWND hwndParent = ::GetParent( m_hDlg ); ::SendMessage( hwndParent, fChanged ? PSM_CHANGED : PSM_UNCHANGED, (WPARAM)(m_hDlg), 0 ); } /* CSRDlg::KickCPLUI */
/*****************************************************************************
* CSRDlg::RecoContextError * *--------------------------* * Description: * Reacts to an error generated by trying to create and set up the * recognition context within the CPL by displaying an error message * and graying out the UI. ****************************************************************** BECKYW ****/ void CSRDlg::RecoContextError( BOOL fRecoContextExists, BOOL fGiveErrorMessage, HRESULT hrRelevantError ) { // Complain about the appropriate problem, if needed
if ( fGiveErrorMessage ) { WCHAR szError[256]; szError[0] = '\0'; // Figure out what error to talk about
UINT uiErrorID = 0; if ( fRecoContextExists ) { // There is a reco context but it couldn't be turned on
uiErrorID = IDS_METER_WARNING; } else { uiErrorID = HRESULTToErrorID( hrRelevantError ); }
if ( uiErrorID ) { LoadString(_Module.GetResourceInstance(), uiErrorID, szError, sp_countof(szError)); MessageBox(m_hDlg, szError, m_szCaption, MB_ICONWARNING|g_dwIsRTLLayout); } }
// Gray out all the buttons
if ( !fRecoContextExists ) { ::EnableWindow(::GetDlgItem(m_hDlg, IDC_USERTRAINING), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MICWIZ), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_SR_ADV), FALSE); ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MODIFY), FALSE); } } /* CSRDlg::RecoContextError */
/*****************************************************************************
* CSRDlg::HRESULTToErrorID * *--------------------------* * Description: * Translates a failed HRESULT from a recognizer/recocontext * initializion into a resource string ID ****************************************************************** BECKYW ****/ UINT CSRDlg::HRESULTToErrorID( HRESULT hr ) { if ( SUCCEEDED( hr ) ) { return 0; }
// What to complain about...
UINT uiErrorID; switch( hr ) { case SPERR_ENGINE_BUSY: uiErrorID = IDS_ENGINE_IN_USE_WARNING; break; case SPERR_UNSUPPORTED_LANG: uiErrorID = IDS_UNSUPPORTED_LANG; break; default: // Generic error
uiErrorID = IDS_ENGINE_SWITCH_ERROR; break; }
return uiErrorID; } /* CSRDlg::HRESULTToErrorID */
/*****************************************************************************
* CSRDlg::IsProfileNameInvisible * *--------------------------------* * Description: * A profile name is "invisible" iff it is the name of an existing * profile AND it is on the pending deletes list AND it is does not * exist for any tokens off the pending deletes list ****************************************************************** BECKYW ****/ bool CSRDlg::IsProfileNameInvisible( WCHAR *pwszProfile ) { if ( !pwszProfile ) { return false; }
bool fIsInvisible = false; for ( int i=0; !fIsInvisible && (i < m_iDeletedTokens); i++ ) { ISpObjectToken *pDeletedToken = m_aDeletedTokens[i]; if ( !pDeletedToken ) { continue; }
CSpDynamicString dstrDeletedDesc; HRESULT hr = SpGetDescription( pDeletedToken, &dstrDeletedDesc ); if ( FAILED( hr ) ) { continue; }
if ( 0 == wcscmp( dstrDeletedDesc, pwszProfile ) ) { bool fOnList = false;
// Now go through everything on the recoprofile list
// that is visible to the user
int cItems = ListView_GetItemCount( m_hUserList ); for ( int j=0; !fOnList && (j < cItems); j++ ) { LVITEM lvitem; ::memset( &lvitem, 0, sizeof( lvitem ) ); lvitem.iItem = j; lvitem.mask = LVIF_PARAM; BOOL fSuccess = ListView_GetItem( m_hUserList, &lvitem ); ISpObjectToken *pVisibleToken = fSuccess ? (ISpObjectToken *) lvitem.lParam : NULL;
if ( pVisibleToken ) { CSpDynamicString dstrVisible; hr = SpGetDescription( pVisibleToken, &dstrVisible );
if ( SUCCEEDED( hr ) && (0 == wcscmp( dstrVisible, pwszProfile )) ) { fOnList = true; } } }
if ( !fOnList ) { // The name matches something on the deleted list,
// but it appears nowhere on the list of profiles visible
// to the user.
fIsInvisible = true; } } }
return fIsInvisible; } /* IsProfileNameInvisible */
/*****************************************************************************
* SRDlgProc * *-----------* * Description: * DLGPROC for managing recognition engines ****************************************************************** MIKEAR ***/ INT_PTR CALLBACK SRDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { SPDBG_FUNC( "SRDlgProc" );
USES_CONVERSION;
switch (uMsg) { case WM_RECOEVENT: { g_pSRDlg->RecoEvent(); break; } case WM_DRAWITEM: // draw the items
{ g_pSRDlg->OnDrawItem( hWnd, ( DRAWITEMSTRUCT * )lParam ); break; }
case WM_INITDIALOG: { g_pSRDlg->OnInitDialog(hWnd); break; }
case WM_DESTROY: { g_pSRDlg->OnDestroy();
break; }
// Handle the context sensitive help
case WM_CONTEXTMENU: { WinHelp((HWND) wParam, CPL_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)(LPWSTR) aKeywordIds); break; }
case WM_HELP: { WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, CPL_HELPFILE, HELP_WM_HELP,(DWORD_PTR)(LPWSTR) aKeywordIds); break; }
case WM_NOTIFY: switch (((NMHDR*)lParam)->code) { case LVN_DELETEITEM: { if (wParam != IDC_USER) { break; }
if (g_pSRDlg->m_fDontDelete) { break; }
ISpObjectToken *pToken = (ISpObjectToken*)(((NMLISTVIEW*)lParam)->lParam);
if (pToken) { pToken->Release(); } break; }
case LVN_ITEMCHANGED: { // Code ends up here when a profile is added, deleted, or changed
// We verify that we weren't selected before, but are now
// and then kill the current reco context, deactivate the engine, change the profile
// and fire everything back up again
if ( IDC_USER == wParam ) { LPNMLISTVIEW lplv = (LPNMLISTVIEW) lParam; if ( !(lplv->uOldState & LVIS_FOCUSED) && lplv->uNewState & LVIS_FOCUSED ) { if ( g_pSRDlg->m_cpRecoEngine && g_pSRDlg->m_cpRecoCtxt ) { HRESULT hr;
ISpObjectToken *pSelectedToken = (ISpObjectToken *) lplv->lParam;
hr = g_pSRDlg->m_cpRecoEngine->SetRecoState( SPRST_INACTIVE ); if ( SUCCEEDED( hr ) ) { hr = g_pSRDlg->m_cpRecoEngine->SetRecoProfile( pSelectedToken );
// Restart audio regardless of success of SetRecoProfile
g_pSRDlg->m_cpRecoEngine->SetRecoState(SPRST_ACTIVE_ALWAYS);
if ( FAILED( hr ) ) { WCHAR szError[256]; szError[0] = '\0'; LoadString(_Module.GetResourceInstance(), IDS_PROFILE_WARNING, szError, sp_countof(szError)); MessageBox(g_pSRDlg->m_hDlg, szError, g_pSRDlg->m_szCaption, MB_ICONWARNING|g_dwIsRTLLayout); } } if ( SUCCEEDED( hr ) ) { // This is now the new default
g_pSRDlg->m_pCurUserToken = pSelectedToken; g_pSRDlg->UserSelChange( lplv->iItem ); }
} } } break; } case PSN_APPLY: { g_pSRDlg->OnApply(); break; }
case PSN_QUERYCANCEL: // user clicks the Cancel button
{ g_pSRDlg->OnCancel(); break; }
} break;
case WM_COMMAND: if (CBN_SELCHANGE == HIWORD(wParam)) { g_pSRDlg->EngineSelChange(); } else if (HIWORD(wParam) == BN_CLICKED) { HRESULT hr = S_OK;
if (LOWORD(wParam) == IDC_MODIFY) // the "Modify" button
{ hr = g_pSRDlg->TrySwitchDefaultEngine( true );
if ( SUCCEEDED( hr ) ) { g_pSRDlg->ProfileProperties(); } // Switch back to original default, complaining about errors only if there
// wasn't a complaint from the call to TrySwitchDefaultEngine
hr = g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr )); }
else if (LOWORD(wParam) == IDC_ADD) // the "Add" button
{ // The engine we want to add this user for may not be the currently-
// running engine. Try and switch it, and complain if there's
// a problem
hr = g_pSRDlg->TrySwitchDefaultEngine( true );
if ( SUCCEEDED( hr ) ) { g_pSRDlg->CreateNewUser(); }
// Switch back to original default, but complain about errors
// only if the UI actually succeeded in showing
g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr ) ); }
else if (LOWORD(wParam) == IDC_DELETE) // the "Delete" button
{ g_pSRDlg->DeleteCurrentUser(); }
else if (LOWORD(wParam) == IDC_SR_ADV) { // The engine we want to display UI for may not be the currently
// running engine. Try and switch it
hr = g_pSRDlg->TrySwitchDefaultEngine( true );
if(SUCCEEDED(hr)) { // display the UI w/ the new temporary default
g_pSRDlg->m_pCurRecoToken->DisplayUI(hWnd, NULL, SPDUI_EngineProperties, NULL, 0, g_pSRDlg->m_cpRecoEngine); } // Switch back to original default, complaining about errors only if there
// wasn't a complaint from the call to TrySwitchDefaultEngine
hr = g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr )); }
else if(LOWORD(wParam) == IDC_USERTRAINING) { // The engine we want to display UI for may not be the currently
// running engine. Try and switch it
hr = g_pSRDlg->TrySwitchDefaultEngine( true ); if(SUCCEEDED(hr)) { // display the UI w/ the new temporary default
SPDBG_ASSERT( g_pSRDlg->m_cpRecoEngine ); g_pSRDlg->m_cpRecoEngine->DisplayUI(hWnd, NULL, SPDUI_UserTraining, NULL, 0); } // Switch back to original default, complaining about errors only if there
// wasn't a complaint from the call to TrySwitchDefaultEngine
hr = g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr )); }
else if(LOWORD(wParam) == IDC_MICWIZ) { // The engine we want to display UI for may not be the currently
// running engine. Try and switch it
hr = g_pSRDlg->TrySwitchDefaultEngine( true ); if(SUCCEEDED(hr)) { // display the UI w/ the new temporary default
SPDBG_ASSERT( g_pSRDlg->m_cpRecoEngine ); g_pSRDlg->m_cpRecoEngine->DisplayUI(hWnd, NULL, SPDUI_MicTraining, NULL, 0); }
// Switch back to original default, complaining about errors only if there
// wasn't a complaint from the call to TrySwitchDefaultEngine
hr = g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr )); }
else if (LOWORD(wParam) == IDC_AUD_IN) { // The m_pAudioDlg will be non-NULL only if the audio dialog
// has been previously brough up.
// Otherwise, we need a newly-initialized one
if ( !g_pSRDlg->m_pAudioDlg ) { g_pSRDlg->m_pAudioDlg = new CAudioDlg( eINPUT ); } ::DialogBoxParam( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDD_AUDIO_DEFAULT ), hWnd, AudioDlgProc, (LPARAM) g_pSRDlg->m_pAudioDlg );
if ( g_pSRDlg->m_pAudioDlg->IsAudioDeviceChangedSinceLastTime() ) { // Warn the user that he needs to apply the changes
WCHAR szWarning[MAX_LOADSTRING]; szWarning[0] = 0; LoadString( _Module.GetResourceInstance(), IDS_AUDIOIN_CHANGE_WARNING, szWarning, MAX_LOADSTRING); MessageBox( g_pSRDlg->GetHDlg(), szWarning, g_pSRDlg->m_szCaption, MB_ICONWARNING |g_dwIsRTLLayout); }
// Kick the Apply button
g_pSRDlg->KickCPLUI();
} } break; }
return FALSE; } /* SRDlgProc */
/****************************************************************************
* CSRDlg::CreateNewUser * *-------------------------* * Description: Adds a new speech user profile to the registry * * Returns: * ********************************************************************* RAL ***/
void CSRDlg::CreateNewUser() { SPDBG_FUNC("CSRDlg::CreateNewUser"); HRESULT hr = S_OK;
// Make sure that we haven't already added too many profiles to keep track of
if ( m_iAddedTokens >= iMaxAddedProfiles_c ) { WCHAR wszError[ MAX_LOADSTRING ]; ::LoadString( _Module.GetResourceInstance(), IDS_MAX_PROFILES_EXCEEDED, wszError, MAX_LOADSTRING ); ::MessageBox( m_hDlg, wszError, m_szCaption, MB_ICONEXCLAMATION | g_dwIsRTLLayout );
return; }
CComPtr<ISpObjectToken> cpNewToken; hr = SpCreateNewToken(SPCAT_RECOPROFILES, NULL, &cpNewToken);
if (SUCCEEDED(hr)) { if (!UserPropDlg(cpNewToken)) // User canceled!
{ cpNewToken->Remove(NULL); } else { //set the default
m_pCurUserToken = cpNewToken;
// Put the new token on the added tokens list
cpNewToken->GetId( &(m_aAddedTokens[ m_iAddedTokens++ ]) );
// make this the default after we edit it
ChangeDefaultUser(); // This will make sure that it gets displayed.
// Note that m_pCurUserToken will point an AddRefed ISpObjectToken *
// after the call to PopulateList()
PopulateList();
// Update the UI
KickCPLUI(); } } else { WCHAR szError[MAX_LOADSTRING]; szError[0] = 0; LoadString(_Module.GetResourceInstance(), IDS_RECOPROFILE_ADD_ERROR, szError, MAX_LOADSTRING); MessageBox( m_hDlg, szError, m_szCaption, MB_ICONWARNING | g_dwIsRTLLayout); }
// Only enable the delete button if there are 2 or more user profiles
int iNumUsers = (int)::SendMessage(m_hUserList, LVM_GETITEMCOUNT, 0, 0); if (iNumUsers < 2) { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), FALSE); } else { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), TRUE); }
// Sort the items initially
::SendMessage( m_hUserList, LVM_SORTITEMS, (LPARAM)m_pCurUserToken, LPARAM(&SortCols) ); }
/****************************************************************************
* CSRDlg::UserPropDlg * *-----------------------* * Description: This is for when a user wants to add a new profile * * Returns: * ********************************************************************* BRENTMID ***/
HRESULT CSRDlg::UserPropDlg(ISpObjectToken * pToken) { SPDBG_FUNC("CSRDlg::UserPropDlg"); HRESULT hr = S_OK;
CEnvrPropDlg Dlg(this, pToken);
hr = (HRESULT)DialogBoxParam(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDD_PROF_WIZ), m_hDlg, CEnvrPropDlg::DialogProc, (LPARAM)(&Dlg)); return hr; }
/****************************************************************************
* CEnvrPropDlg::InitDialog * *--------------------------* * Description: * * Returns: * ********************************************************************* RAL ***/
BOOL CEnvrPropDlg::InitDialog(HWND hDlg) { USES_CONVERSION; CSpDynamicString dstrDescription; m_hDlg = hDlg;
//
// Get the description if there is one...
//
SpGetDescription(m_cpToken, &dstrDescription);
if (dstrDescription) { ::SendDlgItemMessage(hDlg, IDC_USER_NAME, WM_SETTEXT, 0, (LPARAM) dstrDescription.m_psz); ::SendDlgItemMessage(hDlg, IDC_USER_NAME, EM_LIMITTEXT, UNLEN, 0); }
// We want the EN_CHANGE notifications from the edit control
::SendDlgItemMessage( hDlg, IDC_USER_NAME, EM_SETEVENTMASK, 0, ENM_CHANGE );
if (!m_isModify) { // Set the user name to the one in the registry, if found;
// otherwise set it to the user name
HKEY hkUserKey; LONG lUserOpen; WCHAR szUserName[ UNLEN + 1 ]; szUserName[0] = 0; DWORD dwUserLen = UNLEN + 1; lUserOpen = ::RegOpenKeyEx( HKEY_CURRENT_USER, L"Software\\Microsoft\\MS Setup (ACME)\\User Info", 0, KEY_READ, &hkUserKey ); if ( lUserOpen == ERROR_SUCCESS ) { lUserOpen = RegQueryValueEx( hkUserKey, L"DefName", NULL, NULL, (BYTE *) szUserName, &dwUserLen ); RegCloseKey(hkUserKey); }
if ( ERROR_SUCCESS != lUserOpen ) { // Just use the win32 user name
BOOL fSuccess = ::GetUserName( szUserName, &dwUserLen ); if ( !fSuccess ) { szUserName[0] = 0; } }
// Now put that in the edit box.
// First check to make sure the name is nonempty
// and enable the UI accordingly
WCHAR *pwch; for ( pwch = szUserName; *pwch && iswspace( *pwch ); pwch++ ) { } ::EnableWindow( ::GetDlgItem( m_hDlg, IDOK ), (0 != *pwch) ); ::EnableWindow( ::GetDlgItem( m_hDlg, ID_NEXT ), (0 != *pwch) ); // Set the edit box to have the user's name
// Need to use SETTEXTEX since this might contain wide chars
SETTEXTEX stx; stx.flags = ST_DEFAULT; stx.codepage = 1200; ::SendDlgItemMessage( m_hDlg, IDC_USER_NAME, EM_SETTEXTEX, (WPARAM) &stx, (LPARAM) szUserName );
}
::SetFocus(::GetDlgItem(hDlg, IDC_USER_NAME));
return TRUE; }
/****************************************************************************
* CEnvrPropDlg::ApplyChanges * *----------------------------* * Description: * * Returns: * ********************************************************************* RAL ***/
EPD_RETURN_VALUE CEnvrPropDlg::ApplyChanges() { USES_CONVERSION; SPDBG_FUNC("CEnvrPropDlg::ApplyChanges"); WCHAR szName[UNLEN + 1]; *szName = 0; GETTEXTEX gtex = { sp_countof(szName), GT_DEFAULT, 1200, NULL, NULL }; ::SendDlgItemMessage(m_hDlg, IDC_USER_NAME, EM_GETTEXTEX, (WPARAM)>ex, (LPARAM)szName);
if (*szName == 0) { return EPD_FAILED; }
// Check to see if this profile name already exists
CComPtr<IEnumSpObjectTokens> cpEnum; ISpObjectToken *pToken; CSpDynamicString dstrDescription; CSpDynamicString dInputString; CSpDynamicString dstrOldTok; bool isDuplicate = false; HRESULT hr = SpEnumTokens(SPCAT_RECOPROFILES, NULL, NULL, &cpEnum); // Get the description of the currently selected profile
dstrOldTok.Clear(); hr = SpGetDescription( m_pParent->m_pCurUserToken, &dstrOldTok ); while (cpEnum && cpEnum->Next(1, &pToken, NULL) == S_OK) { // Get the description of the enumerated token
dstrDescription.Clear(); hr = SpGetDescription( pToken, &dstrDescription );
pToken->Release();
// Get the input string
// PREFIX: verify memory alloc
if (NULL == (dInputString = szName)) { hr = E_OUTOFMEMORY; }
if ( SUCCEEDED(hr) ) { if ( wcscmp( dstrDescription.m_psz, dInputString.m_psz ) == 0 ) { // the name is duplicated
isDuplicate = true; } } }
if ( isDuplicate ) // this not a modify box and the user entered a duplicate name
{ return EPD_DUP; // tell the user about it
}
if (FAILED(SpSetDescription(m_cpToken, szName))) { return EPD_FAILED; }
return EPD_OK; }
/*****************************************************************************
* EnvrPropDialogProc * *--------------------* * Description: * Mesage handler for User Name dialog ****************************************************************** BRENTMID ***/ INT_PTR CALLBACK CEnvrPropDlg::DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { USES_CONVERSION;
static CSpUnicodeSupport unicode; CEnvrPropDlg * pThis = (CEnvrPropDlg *) unicode.GetWindowLongPtr(hDlg, GWLP_USERDATA); switch (message) { case WM_INITDIALOG: unicode.SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam); pThis = (CEnvrPropDlg *)lParam; return pThis->InitDialog(hDlg);
case WM_COMMAND: { if (( IDC_USER_NAME == LOWORD(wParam) ) && ( EN_CHANGE == HIWORD(wParam) )) { // Edit control contents have changed:
// See if we should enable the "finish" and "next" buttons by getting the
// text in the edit box and making sure it has at least one
// non-whitespace character
WCHAR szName[ UNLEN+1 ]; *szName = 0; GETTEXTEX gtex = { UNLEN, GT_DEFAULT, 1200, NULL, NULL }; ::SendDlgItemMessage(pThis->m_hDlg, IDC_USER_NAME, EM_GETTEXTEX, (WPARAM)>ex, (LPARAM)szName);
WCHAR *pch = szName; for ( ; *pch && iswspace( *pch ); pch++ ) { }
::EnableWindow( ::GetDlgItem( pThis->m_hDlg, IDOK ), (0 != *pch) ); ::EnableWindow( ::GetDlgItem( pThis->m_hDlg, ID_NEXT ), (0 != *pch) );
break; } if( LOWORD(wParam) == IDCANCEL ) { EndDialog(hDlg, FALSE); return TRUE; }
// user clicks the NEXT button
if ( (LOWORD( wParam ) == ID_NEXT) || (LOWORD( wParam ) == IDOK) ) { EPD_RETURN_VALUE eRet = pThis->ApplyChanges();
if ( eRet == EPD_OK ) { if ( ID_NEXT == LOWORD(wParam) ) { // Launch the micwiz, if we can
// Try to switch engines in case the user has changed engines
// without applying
HRESULT hr = g_pSRDlg->TrySwitchDefaultEngine( true );
if ( S_OK == hr ) { SPDBG_ASSERT( g_pSRDlg->m_cpRecoEngine );
if ( g_pSRDlg->m_cpRecoEngine ) { // Switch the recoprofile to the new one (might need to turn off
// recostate first
// Turn off recostate before calling SetRecoProfile() if necessary
SPRECOSTATE eOldRecoState = SPRST_INACTIVE; g_pSRDlg->m_cpRecoEngine->GetRecoState( &eOldRecoState ); HRESULT hrRecoState = S_OK; if ( SPRST_INACTIVE != eOldRecoState ) { hrRecoState = g_pSRDlg->m_cpRecoEngine->SetRecoState( SPRST_INACTIVE ); }
// Change to the newly-added recoprofile
HRESULT hrSetRecoProfile = E_FAIL; if ( SUCCEEDED( hrRecoState ) ) { hrSetRecoProfile = g_pSRDlg->m_cpRecoEngine->SetRecoProfile( pThis->m_cpToken ); // Restore the recostate
g_pSRDlg->m_cpRecoEngine->SetRecoState( eOldRecoState ); }
// Bring on the micwiz and the training wiz
// Follow the yellow brick road.
g_pSRDlg->m_cpRecoEngine->DisplayUI(hDlg, NULL, SPDUI_MicTraining, NULL, 0); if ( SUCCEEDED( hrSetRecoProfile ) ) { // Only want to train the profile if it actually _is_ this profile being
// used...
g_pSRDlg->m_cpRecoEngine->DisplayUI(hDlg, NULL, SPDUI_UserTraining, NULL, 0); } } }
// Switch back to original default, complaining about errors only if there
// wasn't a complaint from the call to TrySwitchDefaultEngine
hr = g_pSRDlg->ResetDefaultEngine( SUCCEEDED( hr )); }
// now we are done
EndDialog(hDlg, TRUE); } else if ( eRet == EPD_DUP ) // user tried to enter a duplicate name
{ // What name was added?
WCHAR szName[ UNLEN+1 ]; *szName = 0; GETTEXTEX gtex = { UNLEN, GT_DEFAULT, 1200, NULL, NULL }; ::SendDlgItemMessage(pThis->m_hDlg, IDC_USER_NAME, EM_GETTEXTEX, (WPARAM)>ex, (LPARAM)szName);
WCHAR pszDuplicate[MAX_LOADSTRING]; LoadString(_Module.GetResourceInstance(), g_pSRDlg->IsProfileNameInvisible( szName ) ? IDS_DUP_NAME_DELETED : IDS_DUP_NAME, pszDuplicate, MAX_LOADSTRING); MessageBox( hDlg, pszDuplicate, g_pSRDlg->m_szCaption, MB_ICONEXCLAMATION | g_dwIsRTLLayout ); }
} } break; } return FALSE; } /* UserNameDialogProc */
/*****************************************************************************
* CSRDlg::UserSelChange * *-------------------------* * Description: * Changes the deafult user ****************************************************************** BRENTMID ***/ void CSRDlg::UserSelChange( int iSelIndex ) { HRESULT hr = S_OK; SPDBG_FUNC( "CSRDlg::UserSelChange" );
// Get the selected item's token
LVITEM lvitem; lvitem.iItem = iSelIndex; lvitem.iSubItem = 0; lvitem.mask = LVIF_PARAM; ::SendMessage( m_hUserList, LVM_GETITEM, 0, (LPARAM) &lvitem ); ISpObjectToken *pToken = (ISpObjectToken *) lvitem.lParam;
if (pToken) { // Try to find the item in the list associated with the current default token
LVFINDINFO lvfi; if ( iSelIndex >= 0 ) { // Something was selected; this is the new default user
lvfi.flags = LVFI_PARAM; lvfi.lParam = (LPARAM) m_pCurUserToken; int iCurDefaultIndex = (int)::SendMessage( m_hUserList, LVM_FINDITEM, -1, (LPARAM) &lvfi ); if ( iCurDefaultIndex >= 0 ) { // The current default has been found in the list; remove its checkmark
SetCheckmark( m_hUserList, iCurDefaultIndex, false ); } SetCheckmark( m_hUserList, iSelIndex, true ); //set the default
m_pCurUserToken = pToken; m_iLastSelected = iSelIndex;
// Kick the Apply button
KickCPLUI(); } } } /* CSRDlg::UserSelChange */
/*****************************************************************************
* CSRDlg::DeleteCurrentUser * *-------------------------* * Description: * Deletes the default user ****************************************************************** BRENTMID ***/ void CSRDlg::DeleteCurrentUser() { // Make sure that we haven't already deleted too many profiles to keep track of
if ( m_iDeletedTokens >= iMaxDeletedProfiles_c ) { WCHAR wszError[ MAX_LOADSTRING ]; ::LoadString( _Module.GetResourceInstance(), IDS_MAX_PROFILES_EXCEEDED, wszError, MAX_LOADSTRING ); ::MessageBox( m_hDlg, wszError, m_szCaption, MB_ICONEXCLAMATION | g_dwIsRTLLayout ); return; }
// First confirm this action with the user
WCHAR pszAsk[ MAX_LOADSTRING ]; WCHAR pszWinTitle[ MAX_LOADSTRING ]; ::LoadString( _Module.GetResourceInstance(), IDS_ASK_CONFIRM, pszAsk, MAX_LOADSTRING ); ::LoadString( _Module.GetResourceInstance(), IDS_ASK_TITLE, pszWinTitle, MAX_LOADSTRING );
if ( MessageBox( m_hDlg, pszAsk, pszWinTitle, MB_YESNO | g_dwIsRTLLayout ) == IDNO ) { // User said no.
return; }
// We need to hang onto the current user token, since when the focus
// changes because of the delete, there will be a different m_pCurUserToken
ISpObjectToken *pTokenToDelete = m_pCurUserToken; SPDBG_ASSERT( pTokenToDelete ); if ( !pTokenToDelete ) { return; }
m_fDontDelete = TRUE;
// Try to find the item in the list associated with the current default token
LVFINDINFO lvfi; lvfi.flags = LVFI_PARAM; lvfi.lParam = (LPARAM) pTokenToDelete; int iCurDefaultIndex = (int)::SendMessage( m_hUserList, LVM_FINDITEM, -1, (LPARAM) &lvfi ); if ( iCurDefaultIndex >= 0 ) { // The current default has been found in the list; remove its checkmark
SetCheckmark( m_hUserList, iCurDefaultIndex, false ); } //remove the token
::SendMessage( m_hUserList, LVM_DELETEITEM, iCurDefaultIndex, NULL );
// now setup the new default
// Get the first item's token
LVITEM lvitem; lvitem.iItem = 0; lvitem.iSubItem = 0; lvitem.mask = LVIF_PARAM; ::SendMessage( m_hUserList, LVM_GETITEM, 0, (LPARAM) &lvitem ); ISpObjectToken *pToken = (ISpObjectToken *) lvitem.lParam;
// set the selected item.
// Focusing it will cause it to be the default
lvitem.state = LVIS_SELECTED | LVIS_FOCUSED; lvitem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; ::SendMessage( m_hUserList, LVM_SETITEMSTATE, 0, (LPARAM) &lvitem );
SetCheckmark( m_hUserList, 0, true ); // enable or disable the delete button based on # of profiles
int iNumUsers = (int)::SendMessage(m_hUserList, LVM_GETITEMCOUNT, 0, 0); if (iNumUsers < 2) { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), FALSE); } else { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), TRUE); }
//set the focus back to the user profiles
::SetFocus(GetDlgItem( m_hDlg, IDC_USER ));
// set the new default profile, inform the SR engine, and remove the old token
SpSetDefaultTokenForCategoryId(SPCAT_RECOPROFILES, m_pCurUserToken );
// Save the tokens in case the user clicks "Cancel"
m_aDeletedTokens[m_iDeletedTokens] = pTokenToDelete; // save the deleted token for possible "Cancel"
m_iDeletedTokens++; // increment the number deleted
KickCPLUI(); // Currently we immediately APPLY this deletion, since the user has already said "YES"
// when the were prompted to confirm the delete.
// If we want to have an "APPLY / CANCEL" thing happen, switch the #if 1 and #if 0
// send the appropriate message to the parent
HWND parentWin = ::GetParent( m_hDlg );
// now the last selected token is gone, so note that
m_iLastSelected = -1;
// Sort the items initially
::SendMessage( m_hUserList, LVM_SORTITEMS, (LPARAM)m_pCurUserToken, LPARAM(&SortCols) );
m_fDontDelete = FALSE; } /* CSRDlg::DeleteCurrentUser */
/*****************************************************************************
* CSRDlg::ProfileProperties * *-------------------------* * Description: * Modifies the properites through engine UI ****************************************************************** BRENTMID ***/
void CSRDlg::ProfileProperties() { if ( m_cpRecoEngine ) { m_cpRecoEngine->DisplayUI(m_hDlg, NULL, SPDUI_RecoProfileProperties, NULL, 0); } }
/*****************************************************************************
* CSRDlg::OnInitDialog * *----------------------* * Description: * Dialog Initialization ****************************************************************** MIKEAR ***/ void CSRDlg::OnInitDialog(HWND hWnd) { SPDBG_FUNC( "CSRDlg::OnInitDialog" ); USES_CONVERSION; SPDBG_ASSERT(IsWindow(hWnd));
m_hDlg = hWnd; // This will be the caption for all MessageBoxes
m_szCaption[0] = 0; ::LoadString( _Module.GetResourceInstance(), IDS_CAPTION, m_szCaption, sp_countof( m_szCaption ) );
m_hSRCombo = ::GetDlgItem( hWnd, IDC_COMBO_RECOGNIZERS ); SpInitTokenComboBox( m_hSRCombo, SPCAT_RECOGNIZERS );
// The first one in the list will be the current default
int iSelected = (int) ::SendMessage( m_hSRCombo, CB_GETCURSEL, 0, 0 ); ISpObjectToken *pCurDefault = (ISpObjectToken *) ::SendMessage( m_hSRCombo, CB_GETITEMDATA, iSelected, 0 ); m_pCurRecoToken = pCurDefault; m_pDefaultRecToken = pCurDefault;
// This simulates selecting the default engine - ensures the UI is setup correctly.
EngineSelChange(TRUE);
InitUserList( hWnd ); m_hUserList = ::GetDlgItem( hWnd, IDC_USER );
::SendMessage( m_hUserList, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM((int) LVSCW_AUTOSIZE, 0) );
int iNumUsers = (int)::SendMessage(m_hUserList, LVM_GETITEMCOUNT, 0, 0); if (iNumUsers < 2) { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), FALSE); } else { EnableWindow(GetDlgItem(m_hDlg, IDC_DELETE), TRUE); }
//set the focus back to the user profiles
::SetFocus(GetDlgItem( m_hDlg, IDC_USER ));
} /* CSRDlg::OnInitDialog */
/*****************************************************************************
* CSRDlg::SetCheckmark * *----------------------* * Description: * Sets the specified item in the list control to be either checked * or unchecked (as the default user) ******************************************************************************/ void CSRDlg::SetCheckmark( HWND hList, int iIndex, bool bCheck ) { ListView_SetCheckState( hList, iIndex, bCheck ); } /* CSRDlg::SetCheckmark */
/*****************************************************************************
* CSRDlg::OnDestroy * *-------------------* * Description: * Destruction ****************************************************************** MIKEAR ***/ void CSRDlg::OnDestroy() { SPDBG_FUNC( "CSRDlg::OnDestroy" );
// spuihelp will take care of releasing its own tokens
SpDestroyTokenComboBox( m_hSRCombo );
// The tokens kepts as itemdata in the reco profile list were
// released in the LVN_DELETEITEM code
// Shuts off the reco engine
ShutDown();
} /* CSRDlg::OnDestroy */
/*****************************************************************************
* CSRDlg::ShutDown * *------------------* * Description: * Shuts down by releasing the engine and reco context ****************************************************************** MIKEAR ***/ void CSRDlg::ShutDown() {
// Release objects
m_cpRecoCtxt.Release(); m_cpRecoEngine.Release();
} /* CSRDlg::ShutDown */
/************************************************************
* CSRDlg::InitUserList * * Description: * Initializes user list *********************************************** BRENTMID ***/ void CSRDlg::InitUserList(HWND hWnd) { const int iInitWidth_c = 260; // pixel width of "Description Column"
// Set up the "Description" column for the settings display
m_hUserList = ::GetDlgItem( hWnd, IDC_USER ); WCHAR pszColumnText[ UNLEN+1 ] = L""; LVCOLUMN lvc; lvc.mask = LVCF_FMT| LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
::LoadString( _Module.GetResourceInstance(), IDS_DESCRIPT, pszColumnText, UNLEN ); lvc.pszText = pszColumnText; lvc.iSubItem = 0; lvc.cx = iInitWidth_c; lvc.fmt = LVCFMT_LEFT; ListView_InsertColumn( m_hUserList, 1, &lvc );
// This should be a checkbox list
::SendMessage( m_hUserList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES );
PopulateList();
// Sort the items initially
::SendMessage( m_hUserList, LVM_SORTITEMS, (LPARAM)m_pCurUserToken, LPARAM(&SortCols) );
} // CSRDlg::InitUserList
/************************************************************
* CSRDlg::PopulateList * * Description: * Populates user list *********************************************** BRENTMID ***/ void CSRDlg::PopulateList() { USES_CONVERSION;
// Populate the list control
int iIndex = 0; LVITEM lvitem; CComPtr<IEnumSpObjectTokens> cpEnum; ISpObjectToken *pToken; WCHAR *pszAttrib = NULL;
HRESULT hr;
// this is to lazily init the user profile if there are none - DON'T REMOVE
if ( m_cpRecoEngine ) { CComPtr<ISpObjectToken> cpTempToken; m_cpRecoEngine->GetRecoProfile(&cpTempToken); }
// Now clear the list
ListView_DeleteAllItems( m_hUserList );
// We will list the tokens in the order they are enumerated
hr = SpEnumTokens(SPCAT_RECOPROFILES, NULL, NULL, &cpEnum);
if (hr == S_OK) { bool fSetDefault = false; while (cpEnum->Next(1, &pToken, NULL) == S_OK) { // first check to see if the token is in the "Deleted List"
bool f_isDel = false;
for (int iDel = 0; iDel < m_iDeletedTokens; iDel++) { CSpDynamicString dstrT1; CSpDynamicString dstrT2;
pToken->GetId( &dstrT1 ); m_aDeletedTokens[ iDel ]->GetId( &dstrT2 );
if (dstrT1.m_psz && dstrT2.m_psz && !wcscmp(dstrT1.m_psz, dstrT2.m_psz)) { f_isDel = true; } }
// if we should show it
if ( f_isDel ) { // This token has a refcounted reference to it on the deleted list:
// this reference should be released
pToken->Release(); } else { // Not a pending delete: We should show it
// now insert the token
lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; lvitem.iItem = iIndex; lvitem.iSubItem = 0; lvitem.lParam = (LPARAM) pToken; CSpDynamicString cUser; SpGetDescription(pToken, &cUser); lvitem.pszText = cUser; // if this is the default it should be selected/focused
if ( !fSetDefault ) { lvitem.state = LVIS_SELECTED | LVIS_FOCUSED; } else { lvitem.state = 0; } iIndex = (int)::SendMessage( m_hUserList, LVM_INSERTITEM, 0, (LPARAM) &lvitem );
// the default is the first token returned by cpEnum->Next
if ( !fSetDefault ) { fSetDefault = true; // Put the checkmark there
SetCheckmark( m_hUserList, iIndex, true ); m_pCurUserToken = pToken; // Set the m_dstrOldUserTokenId to the first default if it hasn't been set yet.
if ( !m_dstrOldUserTokenId ) { m_pCurUserToken->GetId( &m_dstrOldUserTokenId ); } } iIndex++; } }
// Autosize according to the strings now in the list
::SendMessage( m_hUserList, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM((int) LVSCW_AUTOSIZE, 0) ); }
// now find the default item so we can scroll to it
// Try to find the item in the list associated with the current default token
LVFINDINFO lvfi; lvfi.flags = LVFI_PARAM; lvfi.lParam = (LPARAM) m_pCurUserToken; int iCurDefaultIndex = (int)::SendMessage( m_hUserList, LVM_FINDITEM, -1, (LPARAM) &lvfi ); if ( iCurDefaultIndex >= 0 ) { // The current default has been found in the list; scroll to it
ListView_EnsureVisible( m_hUserList, iCurDefaultIndex, false ); } // Name the list view something appropriate
WCHAR pszListName[ MAX_LOADSTRING ]; ::LoadString( _Module.GetResourceInstance(), IDS_PROFILE_LIST_NAME, pszListName, MAX_LOADSTRING ); ::SendMessage( m_hUserList, WM_SETTEXT, 0, (LPARAM)pszListName ); }
/*****************************************************************************
* CSRDlg::OnApply * *-----------------* * Description: * Set user specified options ****************************************************************** MIKEAR ***/ void CSRDlg::OnApply() { SPDBG_FUNC( "CSRDlg::OnApply" );
int iSelected = (int) ::SendMessage( m_hSRCombo, CB_GETCURSEL, 0, 0 ); ULONG ulFlags = 0;
// Pick up the recognizer change, if any
bool fRecognizerChange = false; ISpObjectToken *pToken = NULL; if ( HasRecognizerChanged() ) { pToken = (ISpObjectToken *) ::SendMessage( m_hSRCombo, CB_GETITEMDATA, iSelected, 0 ); if ( CB_ERR == (LRESULT) pToken ) { pToken = NULL; }
HRESULT hrEngine = S_OK; if (pToken && (iSelected >=0)) { hrEngine = SpSetDefaultTokenForCategoryId(SPCAT_RECOGNIZERS, pToken ); if (FAILED(hrEngine)) { WCHAR szError[256]; szError[0] = '\0'; LoadString(_Module.GetResourceInstance(), IDS_DEFAULT_ENGINE_WARNING, szError, sp_countof(szError)); MessageBox(m_hDlg, szError, MB_OK, MB_ICONWARNING | g_dwIsRTLLayout); } else { fRecognizerChange = true; } } }
// Pick up any audio changes that may have been made
HRESULT hrAudio = S_OK; bool fAudioChange = false; if ( m_pAudioDlg ) { fAudioChange = m_pAudioDlg->IsAudioDeviceChanged();
if ( fAudioChange ) { hrAudio = m_pAudioDlg->OnApply(); }
if ( FAILED( hrAudio ) ) { WCHAR szError[256]; szError[0] = '\0'; LoadString(_Module.GetResourceInstance(), IDS_AUDIO_CHANGE_FAILED, szError, sp_countof(szError)); MessageBox(m_hDlg, szError, NULL, MB_ICONWARNING|g_dwIsRTLLayout); }
// Kill the audio dialog, as we are done with it.
delete m_pAudioDlg; m_pAudioDlg = NULL; } // Permanently delete any profiles the user has deleted
for (int iIndex = 0; iIndex < m_iDeletedTokens; iIndex++) { HRESULT hr = m_aDeletedTokens[iIndex]->Remove(NULL);
if (FAILED(hr)) { // might fail if a user has another app open
WCHAR szError[256]; szError[0] = '\0'; LoadString(_Module.GetResourceInstance(), IDS_REMOVE_WARNING, szError, sp_countof(szError)); MessageBox(m_hDlg, szError, MB_OK, MB_ICONWARNING|g_dwIsRTLLayout);
// This will make sure that the attempted deleted item shows up again
PopulateList(); } else { // The token is now removed, we can release it
m_aDeletedTokens[iIndex]->Release(); } } m_iDeletedTokens = 0;
// The added token list's tokens were added as they were put onto the list,
// so just clear the list so that they stay added at the end
m_iAddedTokens = 0;
// Now we don't care about the old user because of the apply
m_dstrOldUserTokenId.Clear(); m_pCurUserToken->GetId( &m_dstrOldUserTokenId ); ChangeDefaultUser();
// Kick the engine to pick up the changes.
// Note that the recoprofile change would have taken effect when
// we selected that list item, and that there is no way to
// pick up the audio changes right now since SetInput() is not
// implemented for shared engines.
if ( fRecognizerChange || fAudioChange ) { BOOL fRecoContextInitialized = FALSE;
if (fRecognizerChange) { ulFlags |= SRDLGF_RECOGNIZER; }
if (fAudioChange) { ulFlags |= SRDLGF_AUDIOINPUT; }
HRESULT hr = CreateRecoContext( &fRecoContextInitialized, FALSE, ulFlags); if ( FAILED( hr ) ) { RecoContextError( fRecoContextInitialized, TRUE, hr ); }
if ( fRecognizerChange ) { SPDBG_ASSERT( pToken ); m_pDefaultRecToken = pToken; }
EngineSelChange(); }
if(m_cpRecoEngine) { m_cpRecoEngine->SetRecoState( SPRST_ACTIVE ); }
} /* CSRDlg::OnApply */
/************************************************************
* CSRDlg::OnDrawItem * * Description: * Handles drawing items in the list view *********************************************** BRENTMID ***/ void CSRDlg::OnDrawItem( HWND hWnd, const DRAWITEMSTRUCT * pDrawStruct ) { RECT rcClip; LVITEM lvi; UINT uiFlags = ILD_TRANSPARENT; HIMAGELIST himl; int cxImage = 0, cyImage = 0; UINT uFirstColWidth;
// Get the item image to be displayed
lvi.mask = LVIF_IMAGE | LVIF_STATE | LVIF_PARAM; lvi.iItem = pDrawStruct->itemID; lvi.iSubItem = 0; ListView_GetItem(pDrawStruct->hwndItem, &lvi);
// We want to be drawing the current default as selected
LVFINDINFO lvfi; lvfi.flags = LVFI_PARAM; lvfi.lParam = (LPARAM) m_pCurUserToken; UINT uiCurDefaultIndex = (UINT)::SendMessage( m_hUserList, LVM_FINDITEM, -1, (LPARAM) &lvfi ); bool fSelected = (uiCurDefaultIndex == pDrawStruct->itemID); // Check to see if this item is selected
if ( fSelected ) { // Set the text background and foreground colors
SetTextColor(pDrawStruct->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetBkColor(pDrawStruct->hDC, GetSysColor(COLOR_HIGHLIGHT)); } else { // Set the text background and foreground colors to the standard window
// colors
SetTextColor(pDrawStruct->hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(pDrawStruct->hDC, GetSysColor(COLOR_WINDOW)); }
// Get the image list and draw the image.
// The image list will consist of the checked box and the unchecked box
// for the LVS_EX_CHECKBOXES style
himl = ListView_GetImageList(pDrawStruct->hwndItem, LVSIL_STATE); if (himl) { // For a LVS_EX_CHECKBOXES style, image 0 is unchecked and image 1 is checked
ImageList_Draw(himl, fSelected ? 1 : 0, pDrawStruct->hDC, pDrawStruct->rcItem.left, pDrawStruct->rcItem.top, uiFlags);
// Find out how big the image we just drew was
ImageList_GetIconSize(himl, &cxImage, &cyImage); }
// Calculate the width of the first column after the image width. If
// There was no image, then cxImage will be zero.
LVCOLUMN pColumn; pColumn.mask = LVCF_WIDTH; ::SendMessage( m_hUserList, LVM_GETCOLUMN, 0, (LPARAM)&pColumn );
int iColWidth = pColumn.cx; // pixel width of "Description Column"
uFirstColWidth = iColWidth - cxImage;
// Set up the new clipping rect for the first column text and draw it
rcClip.left = pDrawStruct->rcItem.left + cxImage; rcClip.right = pDrawStruct->rcItem.left + iColWidth; rcClip.top = pDrawStruct->rcItem.top; rcClip.bottom = pDrawStruct->rcItem.bottom;
ISpObjectToken *pToken = (ISpObjectToken *) lvi.lParam; CSpDynamicString dstrTokenName; SpGetDescription(pToken, &dstrTokenName);
DrawItemColumn(pDrawStruct->hDC, dstrTokenName, &rcClip);
// If we changed the colors for the selected item, undo it
if ( fSelected ) { // Set the text background and foreground colors
SetTextColor(pDrawStruct->hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(pDrawStruct->hDC, GetSysColor(COLOR_WINDOW)); }
// If the item is focused, now draw a focus rect around the entire row
if (pDrawStruct->itemState & ODS_FOCUS) { // Adjust the left edge to exclude the image
rcClip = pDrawStruct->rcItem; rcClip.left += cxImage;
// Draw the focus rect
if ( ::GetFocus() == m_hUserList ) { DrawFocusRect(pDrawStruct->hDC, &rcClip); } }
} // CSRDlg::OnDrawItem
/************************************************************
* CSRDlg::DrawItemColumn * * Description: * Handles drawing of the column data *********************************************** BRENTMID ***/ void CSRDlg::DrawItemColumn(HDC hdc, WCHAR* lpsz, LPRECT prcClip) { USES_CONVERSION;
int iHeight = 0; // Will cause CreateFont() to use default in case we
// don't get the height below
// Get the height of the text
if (hdc) { TEXTMETRIC tm; if (GetTextMetrics(hdc, &tm)) { iHeight = tm.tmHeight; } }
// link the font
LCID dwLCID = GetUserDefaultLCID();
// Pick an appropriate font. On Windows 2000, let the system fontlink.
DWORD dwVersion = GetVersion(); HFONT hfontNew = NULL; HFONT hfontOld = NULL;
if ( (dwVersion >= 0x80000000) || (LOBYTE(LOWORD(dwVersion)) < 5 ) ) { // Less than NT5: Figure out what font
WCHAR achCodePage[6]; UINT uiCodePage; if (0 != GetLocaleInfo(dwLCID, LOCALE_IDEFAULTANSICODEPAGE, achCodePage, 6)) { uiCodePage = _wtoi(achCodePage); } else { uiCodePage = GetACP(); } CComPtr<IMultiLanguage> cpMultiLanguage; MIMECPINFO MimeCpInfo; if ( SUCCEEDED(cpMultiLanguage.CoCreateInstance(CLSID_CMultiLanguage)) && SUCCEEDED(cpMultiLanguage->GetCodePageInfo(uiCodePage, &MimeCpInfo))) { USES_CONVERSION; hfontNew = CreateFont(iHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, MimeCpInfo.bGDICharset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, MimeCpInfo.wszProportionalFont); }
cpMultiLanguage.Release(); }
if ( hfontNew ) { hfontOld = (HFONT) ::SelectObject( hdc, hfontNew ); }
CSpDynamicString szString; CSpDynamicString szNewString;
// Check to see if the string fits in the clip rect. If not, truncate
// the string and add "...".
szString = lpsz; szNewString = CalcStringEllipsis(hdc, szString, UNLEN, prcClip->right - prcClip->left); szString = szNewString; // print the text
ExtTextOutW(hdc, prcClip->left + 2, prcClip->top + 2, ETO_CLIPPED | ETO_OPAQUE, prcClip, szString.m_psz, szString.Length(), NULL);
// Replace the old font
if ( hfontNew ) { ::SelectObject( hdc, hfontOld ); ::DeleteObject( hfontNew ); }
}
/************************************************************
* CSRDlg::CalcStringEllipsis * * Description: * If the text won't fit in the box, edit it, and make * it have ellipses *********************************************** BRENTMID ***/ CSpDynamicString CSRDlg::CalcStringEllipsis(HDC hdc, CSpDynamicString lpszString, int cchMax, UINT uColWidth) { USES_CONVERSION;
WCHAR szEllipsis[] = L"..."; SIZE sizeString; SIZE sizeEllipsis; int cbString; CSpDynamicString lpszTemp; BOOL fSuccess = FALSE;
// Adjust the column width to take into account the edges
uColWidth -= 4;
lpszTemp = lpszString;
// Get the width of the string in pixels
cbString = lpszTemp.Length(); if (!::GetTextExtentPoint32(hdc, lpszTemp, cbString, &sizeString)) { SPDBG_ASSERT(FALSE); }
// If the width of the string is greater than the column width shave
// the string and add the ellipsis
if ((ULONG)sizeString.cx > uColWidth) { if (!::GetTextExtentPoint32(hdc, szEllipsis, lstrlen(szEllipsis), &sizeEllipsis)) { SPDBG_ASSERT(FALSE); }
while ((cbString > 0) && (fSuccess == FALSE)) { lpszTemp[--cbString] = 0; if (!::GetTextExtentPoint32(hdc, lpszTemp, cbString, &sizeString)) { SPDBG_ASSERT(FALSE); } if ((ULONG)(sizeString.cx + sizeEllipsis.cx) <= uColWidth) { // The string with the ellipsis finally fits, now make sure
// there is enough room in the string for the ellipsis
if (cchMax >= (cbString + lstrlen(szEllipsis))) { // Concatenate the two strings and break out of the loop
lpszTemp.Append( szEllipsis ); lpszString = lpszTemp; fSuccess = TRUE; } } } } else { // No need to do anything, everything fits great.
fSuccess = TRUE; }
return (lpszString); } // CSRDlg::CalStringEllipsis
/************************************************************
* CSRDlg::ChangeDefaultUser * * Description: * Handles changes to the environment settings *********************************************** BRENTMID ***/ void CSRDlg::ChangeDefaultUser() { HRESULT hr; if (m_pCurUserToken) { hr = SpSetDefaultTokenForCategoryId(SPCAT_RECOPROFILES, m_pCurUserToken); }
// Sort the items initially
::SendMessage( m_hUserList, LVM_SORTITEMS, (LPARAM)m_pCurUserToken, LPARAM(&SortCols) );
} // CSRDlg::ChangeDefaultUser
/************************************************************
* CSRDlg::OnCancel * * Description: * Handles undoing changes to the environment settings *********************************************** BRENTMID ***/ void CSRDlg::OnCancel() { // Get the original user and make sure that is still the default.
// Note that in general m_pCurUserToken does not AddRef the
// ISpObjectToken it points to, so this is OK.
SpGetTokenFromId( m_dstrOldUserTokenId, &m_pCurUserToken );
ChangeDefaultUser(); // Set the old recoprofile so that none of the profiles added in this
// session will be in use:
// This allows us to roll back the adds below
// m_pCurUserToken does the trick since it is guaranteed to have
// been around before this session
if (m_cpRecoEngine) { m_cpRecoEngine->SetRecoState( SPRST_INACTIVE ); m_cpRecoEngine->SetRecoProfile( m_pCurUserToken ); m_cpRecoEngine->SetRecoState( SPRST_ACTIVE ); }
// Roll back and delete any new profiles added
int cItems = (int) ::SendMessage( m_hUserList, LVM_GETITEMCOUNT, 0, 0 ); LVITEM lvitem; for ( int i = 0; i < m_iAddedTokens; i++ ) { // Look for the list item with a ref out on this token.
// We need to do this because in order for a token to be successfully
// removed the only existing ref to that token has to call the Remove()
// method. The list is holding a ref to that item.
bool fFound = false; for ( int j=0; !fFound && (j < cItems); j++ ) { ::memset( &lvitem, 0, sizeof( lvitem ) ); lvitem.iItem = j; lvitem.mask = LVIF_PARAM; ::SendMessage( m_hUserList, LVM_GETITEM, 0, (LPARAM) &lvitem );
CSpDynamicString dstrItemId; ISpObjectToken *pItemToken = (ISpObjectToken *) lvitem.lParam; if ( pItemToken ) { HRESULT hrId = pItemToken->GetId( &dstrItemId ); if ( SUCCEEDED( hrId ) && dstrItemId && m_aAddedTokens[i] && ( 0 == wcscmp( dstrItemId, m_aAddedTokens[ i ] ) ) ) { // Should this fail, the profile just doesn't get removed: big deal
pItemToken->Remove( NULL ); fFound = true; } } } }
// We AddRefed it...
m_pCurUserToken->Release(); } // CSRDlg::OnCancel
/*****************************************************************************
* CSRDlg::EngineSelChange * *-------------------------* * Description: * This function updates the list box when the user selects a new engine. * If queries the token to see which UI items the engine supports. * The parameter fInitialize determines if the engine is actually created. * It does NOT actually change the default engine. ****************************************************************** MIKEAR ***/ void CSRDlg::EngineSelChange(BOOL fInitialize) { HRESULT hr = S_OK; SPDBG_FUNC( "CSRDlg::EngineSelChange" );
int iSelected = (int) ::SendMessage( m_hSRCombo, CB_GETCURSEL, 0, 0 ); ISpObjectToken *pToken = (ISpObjectToken *) ::SendMessage( m_hSRCombo, CB_GETITEMDATA, iSelected, 0 ); if ( CB_ERR == (LRESULT) pToken ) { pToken = NULL; }
if (pToken) { // Now the current reco token is the one we got off the currently-selected combobox item
m_pCurRecoToken = pToken;
// Kick the UI to enable the Apply button if necessary
KickCPLUI();
HRESULT hrRecoContextOK = S_OK; if(fInitialize) { BOOL fContextInitialized = FALSE; hrRecoContextOK = CreateRecoContext(&fContextInitialized, TRUE); if ( FAILED( hrRecoContextOK ) ) { RecoContextError( fContextInitialized, true, hrRecoContextOK ); } } if ( FAILED( hrRecoContextOK ) ) { // Don't continue, all the buttons are grayed out,
// which is what we want
return; } }
// Check for something being wrong, in which case we want to gray out all
// the UI and stop here.
// For instance, if we had trouble creating the reco context that's supposed to
// be on now (the one for m_pDefaultRecToken), we certainly shouldn't
// enable the UI buttons...
if ( !pToken || (!m_cpRecoCtxt && (pToken == m_pDefaultRecToken)) ) { RecoContextError( FALSE, FALSE ); return; }
// Determine if the training UI component is supported.
// We can pass the current reco engine in as an argument only
// if it's the same as the one who's token we're asking about.
IUnknown *punkObject = (pToken == m_pDefaultRecToken) ? m_cpRecoEngine : NULL; BOOL fSupported = FALSE; hr = pToken->IsUISupported(SPDUI_UserTraining, NULL, 0, punkObject, &fSupported); if (FAILED(hr)) { fSupported = FALSE; } ::EnableWindow(::GetDlgItem(m_hDlg, IDC_USERTRAINING), fSupported);
// Determine if the Mic Wiz UI component is supported
fSupported = FALSE; hr = pToken->IsUISupported(SPDUI_MicTraining, NULL, 0, punkObject, &fSupported); if (FAILED(hr)) { fSupported = FALSE; } ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MICWIZ), fSupported);
// Determine if the Engine Prop UI component is supported
fSupported = FALSE; hr = pToken->IsUISupported(SPDUI_EngineProperties, NULL, 0, punkObject, &fSupported); if (FAILED(hr)) { fSupported = FALSE; } ::EnableWindow(::GetDlgItem(m_hDlg, IDC_SR_ADV), fSupported);
// Determine if the Reco Profile Prop UI component is supported
fSupported = FALSE; hr = pToken->IsUISupported(SPDUI_RecoProfileProperties, NULL, 0, punkObject, &fSupported); if (FAILED(hr)) { fSupported = FALSE; } ::EnableWindow(::GetDlgItem(m_hDlg, IDC_MODIFY), fSupported); } /* CSRDlg::EngineSelChange */
/*****************************************************************************
* CSRDlg::IsCurRecoEngineAndCurRecoTokenMatch * *---------------------------------------------* * Description: * Returns true in pfMatch iff the m_pCurRecoToken is the same * as the token for m_cpRecoEngine. * Return: * S_OK * E_POINTER * Failed HRESULTs from any of the SAPI calls ****************************************************************** BECKYW ***/ HRESULT CSRDlg::IsCurRecoEngineAndCurRecoTokenMatch( bool *pfMatch ) { if ( !pfMatch ) { return E_POINTER; }
if ( !m_cpRecoEngine || !m_pCurRecoToken ) { return E_FAIL; }
*pfMatch = false;
// This gets the object token for the engine
CComPtr<ISpObjectToken> cpRecoEngineToken; HRESULT hr = m_cpRecoEngine->GetRecognizer( &cpRecoEngineToken ); WCHAR *pwszRecoEngineTokenID = NULL; WCHAR *pwszCurRecoTokenID = NULL; if ( SUCCEEDED( hr ) ) { hr = cpRecoEngineToken->GetId( &pwszRecoEngineTokenID ); } if ( SUCCEEDED( hr ) ) { hr = m_pCurRecoToken->GetId( &pwszCurRecoTokenID ); }
if ( pwszRecoEngineTokenID && pwszCurRecoTokenID ) { *pfMatch = ( 0 == wcscmp( pwszRecoEngineTokenID, pwszCurRecoTokenID ) ); }
return hr; } /* CSRDlg::IsCurRecoEngineAndCurRecoTokenMatch */
|