/****************************************************************************
*
*
*    PROGRAM: DtSample.c
*
*    PURPOSE: Sample demonstrating the use DECtalk API's in Windows
*
*    FUNCTIONS:
*
*       About() - processes messages for "About" dialog box
*       destroyDectalk() - removes the list and shutsdown the dectalk threads 
*       HandleMenuPopup() - Logic for Menu enabling & disabling
*       HandleScrollBar() - Logic for processing Rate Slider
*       InitDectalk() - initiales the thread in a list and calls TTS_Startup()
*       InitWindows() - creates child window controls
*       MainWndProc() - processes messages
*       OpenNewFile() - opens a new file
*       ProcessCDError() - uses CommonDialogExtendedError() to output useful error messages
*       switchLangs() - switches dectalk lang threads
*       WinMain() - calls initialization function, processes message loop
*
*    COMMENTS:
*
*
*       The DECtalk APIs demonstrated in the sample include:
*
*       TextToSpeechStartupEx()         Initialize Text-To-Speech system
*       TextToSpeechSpeak()             Convert ASCII English to speech
*       TextToSpeechGetStatus()         Checking to see if speech is being produced
*       TextToSpeechSetRate()               Change Speaking Rate
*       TextToSpeechSetSpeaker()            Change Predefined speaking voice
*       TextToSpeechPause()             Pause speech output
*       TextToSpeechResume()                Resume speech output
*       TextToSpeechShutdown()          Shutdown Text-To-Speech system
*       TextToSpeechReset()             Remove all data in Text-To-Speech system and return
*                                           to initial state
*       TextToSpeechStartLang()         It checks for installed languages and loads into the ML engine
*       TextToSpeechSelectLang()        It selects a looaded language for a program thread
*       TextToSpeechEnumLangs()         This gives a structure of all availible languages and names of each one.
*
***************************************************************************************/
/* 001	MFG		10/01/1998		first revision for Windows CE	      */
/* 002  MFG     11/12/1998      removed stdio.h CE does not support it                */
/* 003  JHU     11/30/1998      Added ACCESS32 features(TYPING and HIGHLIGHTING MODE) */ 
/* 004	MFG	02/10/1999	Added Multi language capiblty			      */
/* 005  CAB     08/15/2000      Added check option to menu of voices, languages, speak*/
/* 006  CAB	08/15/2000	Changed MMSYSERR_ERROR to MMSYSERR_INVALPARAM for                           */
/*				error when it can't find dectalk dictionary.
/**************************************************************************************/

#include <windows.h>    // includes basic windows functionality
#include <commdlg.h>    // includes common dialog functionality
#include "resource.h"
#include "dlgs.h"       // includes common dialog template defines
//coment out for now
//#include "cderr.h"      // includes the common dialog error codes
#include <tchar.h>
#include <commctrl.h>

#include <string.h>     // includes string functions
#include <mmsystem.h>   // includes multimedia extensions
#include "dtsample.h"   // includes Dtsample header file
#include "ttsapi.h"     // includes TextToSpeech API definitions

//Global Varibales
//#if defined(UNDER_C
#define GWL_HINSTANCE	(-6)
typedef HANDLE HDROP;
//#define OFS_MAXPATHNAME 128
//#define OF_READ             0x00000000
//#endif


HWND hWndCB =NULL;       // Handle to a commandbar
HMENU hMenu =NULL;       // Handle to a commandbar menu

DWORD dVoice;			 // Checked voice in menu 
DWORD dRate;			 // Checked rate in menu
DWORD dSpeak;			 // Checked start,stop,pause in menu speak
	
HINSTANCE hInst = NULL;		//local copy of hInstance
HWND hWnd =NULL;				//Main Window handle

#define COMBOID	100

OPENFILENAME OpenFileName;
TCHAR        szFilter[] = TEXT("Text Files (*.TXT)\0*.TXT\0All Files (*.*)\0*.*\0");
TCHAR        szDirName[256]  = TEXT("");
TCHAR        szFile[256] = TEXT("\0");
TCHAR        szFileTitle[256];

TCHAR        szAppName[]  = TEXT("DtSample");
TCHAR        FileBuf[FILE_LEN+1];       // Buffer used to read in file.
char         SelBuf[FILE_LEN+1] = "\0"; //Buffer used to extract Edit control selected region, used to speak selected text

HWND         hDlgFR;
HWND         hwndEdit, hwndButton1, hwndButton2, hwndButton3;
HWND         hwndSliderRate, hwndStaticRate;
RECT         rect;

static       LPTTS_HANDLE_T phTTS[20] ;  /*  Text to Speech Handle used in every TextToSpeech Function Call*/
TTS_LANG_MAP* ptts_select = NULL;
TTS_LANG_MAP_START ttsstart;
LPLANG_ENUM languageINFO;
unsigned int current_rate = 200;        // ncs - Used for keeping track of the speaking rate


#ifdef ACCESS32
void update_mark(ULONG);
void TTSCallbackRoutine(LONG lParam1, LONG lParam2, DWORD dwInstanceParam, UINT uiMsg);
BOOL APIENTRY PrimaryTypingDlgProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
BOOL SpeakText( HANDLE );
FARPROC OldPrimaryTypingDlgProc;
int highlight = 1;      // ncs - Highlighting enabled by default
int menutalk  = 1;      // ncs - Menutalk enabled by default
int typing_mode = 1;    // ncs - Typing Mode enabled by default

typedef struct mark_pos_struct {
    ULONG start;
    ULONG end;
    struct mark_pos_struct *next_mark;
} MARK_POS;
MARK_POS *mark_pos = NULL;

#define     MIN_WPM     50
#else
#define     MIN_WPM     75
#endif


static TBBUTTON tbVIEWButton[] = {
	{ID_BUTTON1, ID_BUTTON1, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
	{ID_BUTTON2, ID_BUTTON2, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 1},
	{ID_BUTTON3, ID_BUTTON3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 2}
};

/****************************************************************************
*
*    FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
*
*    PURPOSE: calls initialization function, processes message loop
*
*    COMMENTS:
*
*
****************************************************************************/

int APIENTRY WinMain(
                     HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPWSTR lpCmdLine,
                     int nCmdShow )
{
    
    MSG msg;
    DWORD error;                        /* message                      */
    WNDCLASS  wc;

    char szText[80] ="\0";
   
    /* Fill in window class structure with parameters that describe the       */
    /* main window.                                                           */
    
    wc.lpfnWndProc = (WNDPROC)MainWndProc;/* retrieve messages forwindows of this class.*/
    wc.cbClsExtra = 0;                    /* No per-class extra data.           */
    wc.cbWndExtra = 0;                    /* No per-window extra data.          */
    wc.hInstance = hInstance;                  /* Application that owns the class.   */
    wc.style = CS_HREDRAW | CS_VREDRAW;  /* Class style(s).                    */
    wc.hIcon = NULL;
    wc.hCursor = NULL;
    wc.lpszMenuName =  NULL;         /* Not supported in windows CE */
    wc.lpszClassName = szAppName;         /* Name used in call to CreateWindow. */
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    
    /* Register the window class and return success/failure code. */
    
    if (!RegisterClass(&wc))
        error = GetLastError();
    
    hInst = hInstance;;

    /* Save the instance handle in static variable, which will be used in  */
    /* many subsequence calls from this application to Windows.            */
    
    /* Create a main window for this application instance.  */

    hWnd = CreateWindow(
        szAppName,							/* See RegisterClass() call.          */
        TEXT("DECtalk Sample Application"), /* Text for window title bar.         */
		WS_VISIBLE,
		CW_USEDEFAULT,						/* Default horizontal position.       */
        CW_USEDEFAULT,						/* Default vertical position.         */
        CW_USEDEFAULT,						/* Default width.                     */
        CW_USEDEFAULT,						/* Default height.                    */
        NULL,								/* Overlapped windows have no parent. */
        NULL,								/* Use the window class menu.         */
        hInstance,							/* This instance owns this window.    */
        NULL								/* Pointer not needed.                */
        );
		

    /* If window could not be created, return "failure" */
    
    if (!hWnd)
    {
        error = GetLastError();
        return (FALSE);
    }

 /* Make the window visible; update its client area; and return "success" */

    ShowWindow(hWnd,SW_SHOW);         /* Show the window                        */
	UpdateWindow(hWnd);               /* Sends WM_PAINT message                 */
	
    while (GetMessage(&msg,           /* message structure                      */
        NULL,                         /* handle of window receiving the message */
        0,                            /* lowest message to examine              */
        0)
        == TRUE)                      /* highest message to examine             */
    {
        TranslateMessage(&msg);       /* Translates virtual key codes           */
        DispatchMessage(&msg);        /* Dispatches message to window           */
    }
    
    return (msg.wParam);			  /* Returns the value from PostQuitMessage */
}


/****************************************************************************
*
*    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
*
*    PURPOSE:  Processes messages
*
*    COMMENTS:
*
*        This function processes all messags sent to the window.  When the
*        user choses one of the options from one of the menus, the command
*        is processed here and passed onto the function for that command.
*
****************************************************************************/

LONG APIENTRY MainWndProc(
                          HWND hWnd,					/* window handle                   */
                          UINT message,					/* type of message                 */
                          UINT wParam,					/* additional information          */
                          LONG lParam    )				/* additional information          */
{
    HDC hdc;
    PAINTSTRUCT ps;
    
    static  BOOL bPause = TRUE;         // TRUE = Pause displayed, False = Resume displayed
    static  BOOL bStatus = FALSE;       // TRUE = Audio dev in use, False = Audio dev not in use
	static	HDROP hDrop;
    static  int  cyborder ;
    static  short wSpos = 180;
    static  unsigned int uiID_Error_Msg;
    char szText[12] ="\0";
    TCHAR szError[132];
    int j=0;
    MMRESULT mmStatus;
    LPCTSTR lpszHelpFile = TEXT(DTALK_HELP_FILE_NAME);   // Name of DECtalk help file
    LPCTSTR lpszHelpTopic = TEXT("Sample applet, description");


    int idArray[3];
    int statArray[3];
    
#ifdef ACCESS32
    MARK_POS *next;
    MENUITEMINFO menuinfo;
#endif
    
    idArray[0]=STATUS_SPEAKING;
    
    switch (message)
    {
        
    case WM_CREATE:

	// Start by initializing the command bar

	GetClientRect(hWnd, &rect);
	hWndCB = CommandBar_Create(hInst, hWnd, 1); //mfgce
        CommandBar_AddBitmap(hWndCB, hInst, IDB_BUTTONS, 3, 0, 0);

#ifdef ACCESS32
	CommandBar_InsertMenubar(hWndCB, hInst,IDM_MAIN_MENU_CEA32, 0);
#else
	CommandBar_InsertMenubar(hWndCB, hInst,IDM_MAIN_MENU_CE1, 0);
#endif	// ACCESS32
	
	CommandBar_AddButtons(hWndCB, sizeof(tbVIEWButton)/sizeof(TBBUTTON), tbVIEWButton);
	CommandBar_AddAdornments(hWndCB,CMDBAR_HELP,0);

	hMenu	= CommandBar_GetMenu(hWndCB,0);

	InitWindows(hWnd);
		
	// Set initial check for menus
	dVoice = IDM_PAUL;
	dRate = IDM_SPEAK200;
	dSpeak = IDM_SPEAKSTOP;

	hMenu = CommandBar_GetMenu(hWndCB, 0);
	CheckMenuItem(hMenu, dVoice, MF_CHECKED); 
        CheckMenuItem(hMenu, dRate, MF_CHECKED);
	CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
        /*******************************************************************************************
        Register a private message to report DECtalk asychronous events.
        ***************************************************************************************8****/
        uiID_Error_Msg = RegisterWindowMessage(TEXT("DECtalkErrorMessage"));

        return InitDectalk(hWnd, &ttsstart);

    
	case WM_PAINT:      // Set up a display context to begin painting
        
        hdc  = BeginPaint (hWnd, &ps);
        EndPaint( hWnd, &ps );
        
        break;

#ifndef UNDER_CE //mfgdebug maybe removed in future
        

    case WM_SETFOCUS :
        SetFocus (hwndEdit) ;
        return FALSE ;
        
    case WM_SIZE :  //Reposition all child windows when moved or resized
        
        MoveWindow (hwndEdit, 0, 21, LOWORD (lParam),
         HIWORD (lParam)-21L, TRUE) ;
        MoveWindow (hwndButton1,  0, 0 , 75,20, TRUE) ;
        MoveWindow (hwndButton2, 75, 0 , 75,20, TRUE) ;
        MoveWindow (hwndButton3, 150, 0 , 75,20, TRUE) ;
        MoveWindow (hwndSliderRate, 230, 0 , 200,20, TRUE) ;
        MoveWindow (hwndStaticRate, 431, 0 , 120,20, TRUE) ;
        
        return FALSE ;
        
        
        
    case WM_INITMENUPOPUP: //Enable or gray menu items depending on current states
        
        HandleMenuPopup(wParam);
        
        return FALSE;
        
    case WM_HSCROLL:       // Rate slider control routine
        
        if (((HWND)lParam) == hwndSliderRate)
        {
            wSpos = HandleScrollBar(wParam,wSpos);  // Call Scroll Bar handling routine
            TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],(UINT)wSpos); // New rate returned in wSpos
            current_rate = wSpos;
            return FALSE;
        }
        break;
#endif	// UNDER_CE
       
    case WM_COMMAND:               /* message: command from application menu */
        
        if (wParam == 1 && HIWORD (lParam) == EN_ERRSPACE)
            MessageBox (hWnd, TEXT("EDIT control out of space."),
            TEXT("DECtalk Sample Application for Windows C E"),MB_OK | MB_ICONSTOP) ;
        
		if(LOWORD(wParam) >= IDM_LANG_BEGIN && LOWORD(wParam) < IDM_LANG_END)
        {
            switchLangs(hWnd, &ttsstart, wParam);   
        }
        else
        {
            switch( LOWORD( wParam ))
            {
            case IDM_NEW:      //menu file - open file
                    DrawMenuBar( hWnd);
					//_tcscpy( szFile, TEXT(""));			//reset file parameters
					//OpenFileName.lpstrFile = szFile;
					OpenFileName.lpstrFile = NULL;
					_tcscpy( szFile, TEXT("untitled.txt"));
					FileBuf[0] =TEXT('\0');
                    SendMessage(hwndEdit,WM_SETTEXT ,0,(LPARAM)((LPCTSTR)FileBuf));
                    InvalidateRect( hWnd, NULL, TRUE );
                 break;

            case IDM_OPENFILE:      //menu file - open file
                if ( OpenNewFile( hWnd ) == TRUE )
                {
                    DrawMenuBar( hWnd);
                    // reset the title in the title bar to reflect the
                    // new open file
                   // SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)((LPTSTR)OpenFileName.lpstrFile));
                    SendMessage(hwndEdit,WM_SETTEXT ,0,(LPARAM)((LPCTSTR)FileBuf));
                    InvalidateRect( hWnd, NULL, TRUE );
                }
                break;
             
			case IDM_SAVEASFILE:      //menu file -  save as file
				GetWindowText(hwndEdit,FileBuf,sizeof(FileBuf)/sizeof(TCHAR));
                if ( SaveNewFile( hWnd ,IDM_SAVEASFILE ) == TRUE )
                {
                    DrawMenuBar( hWnd);
                    SendMessage(hwndEdit,WM_SETTEXT ,0,(LPARAM)((LPCTSTR)FileBuf));
                    InvalidateRect( hWnd, NULL, TRUE );
                }
                break;

			case IDM_SAVEFILE:      //menu file - save file
				GetWindowText(hwndEdit,FileBuf,sizeof(FileBuf)/sizeof(TCHAR));
                if ( SaveNewFile( hWnd, IDM_SAVEFILE ) == TRUE )
                {
                    DrawMenuBar( hWnd);
                    SendMessage(hwndEdit,WM_SETTEXT ,0,(LPARAM)((LPCTSTR)FileBuf));
                    InvalidateRect( hWnd, NULL, TRUE );
                }
                break;


                /*  Edit menu selections - provides cut and paste to/from clipboard                       */
                
            case IDM_CUT:
                
                SendMessage(hwndEdit,WM_CUT,0,0L);
                break;
                
            case IDM_COPY:
                
                SendMessage(hwndEdit,WM_COPY,0,0L);
                break;
                
            case IDM_PASTE:
                
                SendMessage(hwndEdit,WM_PASTE,0,0L);
                break;
                
            case IDM_DELETE:
                
                SendMessage(hwndEdit,WM_CLEAR,0,0L);
                break;

#ifdef ACCESS32
                // Place the following in the #ifdef section so that these can
                // be stripped out for non ACCESS32 kits
			case IDM_HIGHLIGHT_ON:           
				highlight = 1;
                menuinfo.cbSize = sizeof(MENUITEMINFO);
                menuinfo.fMask = MIIM_STATE;				
				menuinfo.fState = MFS_CHECKED;					
				SetMenuItemInfo(hwndEdit, IDM_HIGHLIGHT_ON, FALSE, &menuinfo);			
                break;
			case IDM_HIGHLIGHT_OFF:
				highlight = 0;
                menuinfo.cbSize = sizeof(MENUITEMINFO);
                menuinfo.fMask = MIIM_STATE;				
				menuinfo.fState = 0;
               SetMenuItemInfo(hwndEdit, IDM_HIGHLIGHT_OFF, FALSE, &menuinfo);				
                break;
			case IDM_TYPING_ON:
                typing_mode = 1;
                menuinfo.cbSize = sizeof(MENUITEMINFO);
                menuinfo.fMask = MIIM_STATE;
                menuinfo.fState = MFS_CHECKED;
                SetMenuItemInfo(hwndEdit, IDM_TYPING_ON, FALSE, &menuinfo);
                break;
			case IDM_TYPING_OFF:
                typing_mode = 0;
                menuinfo.cbSize = sizeof(MENUITEMINFO);
                menuinfo.fMask = MIIM_STATE;
                menuinfo.fState = 0;
                SetMenuItemInfo(hwndEdit, IDM_TYPING_OFF, FALSE, &menuinfo);
                break;               
#endif	// ACCESS32
                
                /* Button window controls
                Button 1 is start
                Button 2 is pause / resume
                Button 3 is stop                */
			case IDC_NONE:
            case ID_BUTTON1:       //Start Button activated
            case IDM_SPEAKSTART:
                if (!bPause)
				{
					// ADDED to check menu item
					//CommandBar_DrawMenuBar(hWndCB, ID_BUTTON2);   
					//static TBBUTTON tbVIEWButton[] = {
					//{ID_BUTTON1, ID_BUTTON1, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
					//{ID_BUTTON2, ID_BUTTON2, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 1},
					//{ID_BUTTON3, ID_BUTTON3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 2}
					//};

					//hWndCB = CommandBar_Create(hInst, hWnd, 1); //mfgce
					//CommandBar_AddBitmap(hWndCB, hInst, IDB_BUTTONS, 3, 0, 0);
					//CommandBar_AddButtons(hWndCB, sizeof(tbVIEWButton)/sizeof(TBBUTTON), tbVIEWButton);
	

					hMenu = CommandBar_GetMenu(hWndCB, 0);
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED); 
					dSpeak = IDM_SPEAKSTART; 
					CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
					
					if ( TextToSpeechResume(phTTS[ptts_select->tts_lang_index]) == MMSYSERR_NOERROR )
					{
						bPause= TRUE;     // Toggle state from Resume back to Pause
						SendMessage(hwndButton2,WM_SETTEXT,(WPARAM)NULL,(LPARAM)"Pause");
					}
					
					// Uncheck play after it speaks
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED);
					dSpeak = IDM_SPEAKSTOP; 
					CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
					
					break;
				}
				else
				{
					// Just checking to make sure start is pressed only once.
					// ADDED to check menu item
					hMenu = CommandBar_GetMenu(hWndCB, 0);
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED); 
					dSpeak = IDM_SPEAKSTART; 
					CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
					// Don't want to load the queue up
					TextToSpeechGetStatus(phTTS[ptts_select->tts_lang_index], idArray, statArray, 1);
					bStatus = statArray[0];
					if ( !bStatus )
					{
#ifdef ACCESS32
						if (highlight)
							SpeakText(hWnd);    // Go and handle this with high-lighting 
						else {
#endif
							GetWindowText(hwndEdit,FileBuf,sizeof(FileBuf)/sizeof(TCHAR));
							TextToSpeechSpeak( phTTS[ptts_select->tts_lang_index],FileBuf, TTS_FORCE );
#ifdef ACCESS32
						}
#endif                
					}
					// Uncheck play after it speaks
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED);
					dSpeak = IDM_SPEAKSTOP; 
					CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
					break;
                }
            case ID_BUTTON2:       //Pause Resume  Button activated
            case IDM_SPEAKPAUSE:
                if(bPause)
                {
                    // ADDED to check menu item
					hMenu = CommandBar_GetMenu(hWndCB, 0);
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED); 
					dSpeak = IDM_SPEAKPAUSE; 
					CheckMenuItem(hMenu, dSpeak, MF_CHECKED);

					TextToSpeechGetStatus(phTTS[ptts_select->tts_lang_index], idArray, statArray, 1);
                    bStatus = statArray[0];     // Checking to see if there is speech running
                    if ( bStatus )
                    {
                        if ( TextToSpeechPause(phTTS[ptts_select->tts_lang_index]) == MMSYSERR_NOERROR )
                        {
                            bPause= FALSE;     // Toggle state from Pause to Resume
                            SendMessage(hwndButton2,WM_SETTEXT,(WPARAM)NULL,(LPARAM)"Resume");
                        }
                        break;
                    }
                }   
                else
                {
                    // ADDED to check menu item
					hMenu = CommandBar_GetMenu(hWndCB, 0);
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED); 
					dSpeak = IDM_SPEAKPAUSE; 
					CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED);
					
					if ( TextToSpeechResume(phTTS[ptts_select->tts_lang_index]) == MMSYSERR_NOERROR )
                    {
                        bPause= TRUE;     // Toggle state from Resume back to Pause
                        SendMessage(hwndButton2,WM_SETTEXT,(WPARAM)NULL,(LPARAM)"Pause");
                    }
                    break;
                }
                
            case ID_BUTTON3:       //Stop Button activated
            case IDM_SPEAKSTOP:
				// ADDED to check menu item
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dSpeak, MF_UNCHECKED); 
				dSpeak = IDM_SPEAKSTOP; 
				CheckMenuItem(hMenu, dSpeak, MF_CHECKED);
				
                if ( !bPause )
                {   // It seems that we have to first Resume before we can continue
                    // or else risk locking up the engine by executing reset without resume.
                    if ( TextToSpeechResume(phTTS[ptts_select->tts_lang_index]) == MMSYSERR_NOERROR )
                    {
                        bPause= TRUE;     // Toggle state from Resume back to Pause
                        SendMessage(hwndButton2,WM_SETTEXT,(WPARAM)NULL,(LPARAM)"Pause");
                    }
                }

				mmStatus = TextToSpeechReset(phTTS[ptts_select->tts_lang_index], FALSE);
                
                if ( mmStatus )
                    MessageBox( hWnd,szError,TEXT("TextToSpeechReset"),MB_OK | MB_ICONSTOP );

                break;
                
                //  Handle requests to change speaking voice1
            case  IDM_PAUL:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_PAUL; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],PAUL);
                break;
                
            case  IDM_HARRY:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_HARRY; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
                
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],HARRY);
                break;
                
            case  IDM_DENNIS:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_DENNIS; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],DENNIS);
                break;
                
            case  IDM_FRANK:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_FRANK; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
                
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],FRANK);
                break;
                
            case  IDM_RITA:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_RITA; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],RITA);
                break;
                
            case  IDM_BETTY:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_BETTY; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],BETTY);
                break;
                
            case  IDM_URSULA:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_URSULA; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],URSULA);
                break;
                
            case  IDM_WENDY:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_WENDY; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
				
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],WENDY);
                break;
                
            case  IDM_KIT:
                // Added to check voice
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dVoice, MF_UNCHECKED); 
				dVoice = IDM_KIT; 
				CheckMenuItem(hMenu, dVoice, MF_CHECKED);
                
				TextToSpeechSetSpeaker(phTTS[ptts_select->tts_lang_index],KIT);
                break;
                
                // Handle Speaking Rate
            case  IDM_SPEAK100:
                // Added to check rate
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dRate, MF_UNCHECKED); 
				dRate = IDM_SPEAK100; 
				CheckMenuItem(hMenu, dRate, MF_CHECKED);
				
				TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],100);
                HandleScrollBar(SB_UPDATE, 100);        // SB_UPDATE is NOT windows defined
                current_rate = 100;
                break;
                
            case  IDM_SPEAK200:
                // Added to check rate
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dRate, MF_UNCHECKED); 
				dRate = IDM_SPEAK200; 
				CheckMenuItem(hMenu, dRate, MF_CHECKED);

                TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],200);
                HandleScrollBar(SB_UPDATE, 200);        // SB_UPDATE is NOT windows defined
                current_rate = 200;
                break;
                
            case  IDM_SPEAK300:
                // Added to check rate
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dRate, MF_UNCHECKED); 
				dRate = IDM_SPEAK300; 
				CheckMenuItem(hMenu, dRate, MF_CHECKED);

                TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],300);
                HandleScrollBar(SB_UPDATE, 300);        // SB_UPDATE is NOT windows defined
                current_rate = 300;
                break;
                
            case  IDM_SPEAK400:
                // Added to check rate
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dRate, MF_UNCHECKED); 
				dRate = IDM_SPEAK400; 
				CheckMenuItem(hMenu, dRate, MF_CHECKED);

                TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],400);
                HandleScrollBar(SB_UPDATE, 400);        // SB_UPDATE is NOT windows defined
                current_rate = 400;
                break;
                
            case  IDM_SPEAK500:
                // Added to check rate
				hMenu = CommandBar_GetMenu(hWndCB, 0);
				CheckMenuItem(hMenu, dRate, MF_UNCHECKED); 
				dRate = IDM_SPEAK500; 
				CheckMenuItem(hMenu, dRate, MF_CHECKED);

                TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],500);
                HandleScrollBar(SB_UPDATE, 500);        // SB_UPDATE is NOT windows defined
                current_rate = 500;
                break;
                
                // Handle File - exit request
            case IDM_EXIT:
                
                DestroyWindow(hWnd);
                break;
                
                // Display about box
            case IDM_ABOUT:
                
                DialogBox(hInst,           /* current instance         */      
                    MAKEINTRESOURCE(IDD_ABOUT1), /* resource to use   */
					hWnd,                  /* parent handle            */
                    (DLGPROC)About);       /* About Process()          */
                break;
                
                // Invoke win help with DECtalk help file
            case IDM_HELP:
                
#ifndef UNDER_CE	// comment out for now mfgce        
               WinHelp( hWnd,
                    lpszHelpFile,
                    HELP_PARTIALKEY,
                    (DWORD)lpszHelpTopic );
#endif                
                break;
                
            default:
                break ;
                
            }
        } //else
        break;  // WM_COMMAND

    case WM_DESTROY:

#ifdef  ACCESS32
        mmStatus = TextToSpeechShutdown(phTTS[ptts_select->tts_lang_index]);
#endif
        
       mmStatus = destroyDectalk(ttsstart.start, ttsstart.size);
        
#ifdef ACCESS32
        /* Free mark_pos buffer */
        next = mark_pos;
        while (next != NULL) {
            mark_pos = next->next_mark;
            free(next);
            next = mark_pos;
        }
#endif // ACCESS32   
		
        PostQuitMessage(0);
        break;
        
    default:
        if (message ==  uiID_Error_Msg )
            
        {
            //TextToSpeechReset(phTTS, FALSE);
            switch (wParam)
            {
                
            case ERROR_IN_AUDIO_WRITE:
                MessageBox(hWnd, TEXT("Error in Writing Audio"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
                
            case ERROR_OPENING_WAVE_OUTPUT_DEVICE:
                MessageBox(hWnd, TEXT("Error Opening Wave Out Device"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
                
            case ERROR_GETTING_DEVICE_CAPABILITIES:
                MessageBox(hWnd, TEXT("Error Getting Audio Device Caps"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
                
            case ERROR_READING_DICTIONARY:
                MessageBox(hWnd, TEXT("Error Reading Dictionary File \n dectalk.dic"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
                
            case ERROR_WRITING_FILE:
                MessageBox(hWnd, TEXT("Error Writing File"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
                
            case ERROR_ALLOCATING_INDEX_MARK_MEMORY:
                MessageBox(hWnd, TEXT("Error allocating Index Mark Memory"), TEXT("Async Error"),MB_OK | MB_ICONSTOP);
                break;
            }
        }
    }  
    
    
    return (DefWindowProc(hWnd, message, wParam, lParam));
}

/****************************************************************************
*
*    FUNCTION: InitWindows()
*
*    PURPOSE:  Initialize all child windows. Draws buttons, sliders, edit control etc.
*
*    COMMENTS:
*
*
****************************************************************************/

BOOL  InitWindows(HWND hWnd)

{
   GetClientRect(hWnd,&rect);
    
   hwndEdit = CreateWindow (
        TEXT("EDIT"),                    /* See RegisterClass() call.          */
        TEXT(""),         /* default text in edit window         */
        WS_VISIBLE| WS_VSCROLL| ES_AUTOVSCROLL |ES_MULTILINE,
		10L,                        /* Default horizontal position.       */
		21L,                       /* Default vertical position.         */
		rect.right-10L,                /* Default width.                     */
		rect.bottom-21L,           /* Default height.                    */
        hWnd,                      /* Parent window                      */
        (HMENU)ID_EDITCTL,         /* Use the window class menu.         */
        (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ),   /* hInstance */
        NULL);

#ifdef ACCESS32
    // We need to get the edit box properties
    // Then look at PrimaryTypingDlgProc() to see how typing mode is done.
    OldPrimaryTypingDlgProc = (void *)GetWindowLong(hwndEdit, GWL_WNDPROC);
    SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG) PrimaryTypingDlgProc);
#endif

		wcscpy(szFile,TEXT("untitled.txt"));

    return (FALSE);
}




/****************************************************************************
*
*    FUNCTION: HandleScrollBar()
*
*    PURPOSE:  Handle all "Seaking Rate" Scroll Bar Logic
Line logic changes speaking rate in increments of 5 Words Per Minute
Page Logic Changes in 20 word per minutes
Thumbtrack is rounded to 5 WPM boundries
*
*    COMMENTS: The return value is the new selected rate in WPM
*
*
****************************************************************************/

SHORT  HandleScrollBar(WPARAM wParam, SHORT wSpos)


{
    
	TCHAR szText[12];

    switch(LOWORD(wParam))
    {
        
    case SB_PAGEDOWN:          // Increment Rate Slider by 20 to Max of 600
        if (wSpos > 580)
            wSpos = 600;
        else
            wSpos += 20;
        break;
        
    case SB_LINEDOWN:          // Increment Rate Slider by 5 to Max of 600
        if (wSpos > 595)
            wSpos = 600;
        else
            wSpos   += 5;
        break;
        
    case SB_PAGEUP:        // Decrement Rate Slider by 20 to Min of MIN_WPM
        if (wSpos < (MIN_WPM+20) )
            wSpos = MIN_WPM;
        else
            wSpos   -= 20;
        break;
        
    case SB_LINEUP:        // Increment Rate Slider by 5 to Max of MIN_WPM
        if (wSpos < (MIN_WPM+5) )
            wSpos = MIN_WPM;
        else
            wSpos   -= 5;
        break;
        
    case SB_TOP:               // Rate Slider to Max
        wSpos   =600;
        break;
        
    case SB_BOTTOM:        // Rate Slider to Min
        wSpos   = MIN_WPM;
        break;
        
    case SB_THUMBPOSITION:
    case SB_THUMBTRACK:
        wSpos = ((HIWORD(wParam))/5)*5;       // Round speaking rate to nearest 5
        
    default:
        break;
    }
    
    SetScrollPos(hwndSliderRate, SB_CTL, wSpos , TRUE)  ; // Set Slider Control position

    wsprintf(szText,TEXT("Rate %d WPM") ,wSpos );
    SetWindowText(hwndStaticRate,szText );   // Display Rate in Static control
    return (wSpos);
}

/****************************************************************************
*
*    FUNCTION: HandleMenuPopup()
*
*    PURPOSE:  Handle Edit menu popup logic. This Function grays or enables the
*              appropriate menu entries, depending on the current state of the system.
*
*
*
*    COMMENTS:
*
*
****************************************************************************/


void    HandleMenuPopup(WPARAM wParam) // wParam is handle of menu

{
    LONG lSelect;
    WORD wEnable ;
    
    if (IsClipboardFormatAvailable (CF_TEXT))
        EnableMenuItem((HANDLE)wParam, IDM_PASTE, MF_ENABLED);
    
    else   EnableMenuItem((HANDLE)wParam, IDM_PASTE,MF_GRAYED);
    
    /*Enable  menu cut, copy & delete menu items if data is selected */
    
    lSelect = SendMessage (hwndEdit, EM_GETSEL,0L, 0L) ;
    if (HIWORD (lSelect) != LOWORD (lSelect))
        wEnable= MF_ENABLED;
    else wEnable= MF_GRAYED ;
    
    EnableMenuItem ((HANDLE)wParam, IDM_CUT, wEnable);
    EnableMenuItem ((HANDLE)wParam, IDM_COPY, wEnable);
    EnableMenuItem ((HANDLE)wParam, IDM_DELETE, wEnable);
    return ;
}



/****************************************************************************
*
*    FUNCTION: About(HWND, UINT, UINT, LONG)
*
*    PURPOSE:  Processes messages for "About" dialog box
*
*    COMMENTS:
*
*       No initialization is needed for this particular dialog box, but TRUE
*       must be returned to Windows.
*
*       Wait for user to click on "Ok" button, then close the dialog box.
*
****************************************************************************/

BOOL APIENTRY About(
                    HWND hDlg,                              /* window handle of the dialog box */
                    UINT message,                           /* type of message                 */
                    UINT wParam,                            /* message-specific information    */
                    LONG lParam)
{
    switch (message)
    {
    case WM_INITDIALOG:                     /* message: initialize dialog box */
        return (TRUE);
        
    case WM_COMMAND:                        /* message: received a command */
        if (LOWORD(wParam) == IDOK          /* "OK" box selected?        */
            || LOWORD(wParam) == IDCANCEL)
        {                                   /* System menu close command? */
            EndDialog(hDlg, TRUE);          /* Exits the dialog box        */
           TextToSpeechSpeak( phTTS[ptts_select->tts_lang_index], TEXT("DECtalk Sample Application"), TTS_FORCE );
            return (TRUE);
        }
        break;
    }
    return (FALSE);                             /* Didn't process a message    */
    
}
/****************************************************************************
*
*    FUNCTION: SaveNewFile(HWND)
*
*    PURPOSE:  Invokes common dialog function to open a file and opens it.
*
*    COMMENTS:
*
*        This function initializes the OPENFILENAME structure and calls
*        the GetOpenFileName() common dialog function.
*
*    RETURN VALUES:
*        TRUE - The file name was obtained successfully
*        FALSE - No file name was obtained.
*
****************************************************************************/
BOOL SaveNewFile( HWND hWnd,unsigned int type)
{
    
	if (type == IDM_SAVEFILE)
	{
		if (wcscmp(szFile,TEXT("untitled.txt"))==0) //check if file has a name
		type = IDM_SAVEASFILE;
	}
	

    _tcscpy( szFileTitle, TEXT(""));

    OpenFileName.lStructSize      = sizeof(OPENFILENAME);
    OpenFileName.hwndOwner        = hWnd;
    OpenFileName.hInstance        = (HANDLE) hInst;
    OpenFileName.lpstrFilter      = szFilter;
    OpenFileName.lpstrCustomFilter = NULL;
    OpenFileName.nMaxCustFilter   = 0L;
    OpenFileName.nFilterIndex     = 1L;
    OpenFileName.lpstrFile        = szFile;
    OpenFileName.nMaxFile         = sizeof(szFile);
    OpenFileName.lpstrFileTitle   = szFileTitle;
    OpenFileName.nMaxFileTitle    = sizeof(szFileTitle);
    OpenFileName.lpstrInitialDir   = NULL;
    OpenFileName.lpstrTitle       = TEXT("Save As");
    OpenFileName.lpstrDefExt      = TEXT("*.txt");
    OpenFileName.nFileOffset      = 0;
    OpenFileName.nFileExtension   = 0;
    OpenFileName.lCustData        = 0;
    OpenFileName.Flags =  OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    


	if (type == IDM_SAVEFILE)
	{
						
		if (RdBufToFile( OpenFileName.lpstrFile, hWnd ))
				return TRUE;
		else
				return FALSE;

	}
	else
	{
		if (GetSaveFileName(&OpenFileName))
		{
			if (RdBufToFile( OpenFileName.lpstrFile, hWnd ))
				return TRUE;
			else
				return FALSE;
		}
		else
        return FALSE;
    }


}
/****************************************************************************************
* FUNCTION: RdBufToFile()
*
*    PURPOSE:  Opens and reads a file into FileBuf
*
*    COMMENTS:
*
*        This function
*
*    RETURN VALUES:
*        TRUE - The file was opened successfully and read into the buffer.
*        FALSE - No files were opened.
*
*
************************************************************************************/
BOOL RdBufToFile( LPTSTR lpszFile, HWND hWnd )

{
    
	HANDLE hFile;
	int cBufLen;
	DWORD dwRW;

	DWORD length = lstrlen(FileBuf);

	DWORD charlength = length * sizeof(char);

	char *pMBString = (char *)LocalAlloc(LPTR,(charlength + sizeof(char)));	//allocate fom heap


	wcstombs(pMBString,FileBuf,charlength);


	hFile = CreateFile(lpszFile, GENERIC_WRITE, FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	
	if (hFile == INVALID_HANDLE_VALUE)
    {
        MessageBox( hWnd, TEXT("File Save failed."), NULL, MB_OK );
		return FALSE;
    }
    else
	{
       cBufLen = WriteFile( hFile,pMBString,charlength, &dwRW, NULL);

	}
			
  
    if (cBufLen == -1)
    {
         MessageBox( hWnd, TEXT("Zero bytes read."), NULL, MB_OK );
        CloseHandle( hFile );
        return FALSE;
    }
    else
    {
        // close the file
        FileBuf[(int)length]='\0';
        CloseHandle( hFile );
     }
    

    return TRUE;
}

/****************************************************************************
*
*    FUNCTION: OpenNewFile(HWND)
*
*    PURPOSE:  Invokes common dialog function to open a file and opens it.
*
*    COMMENTS:
*
*        This function initializes the OPENFILENAME structure and calls
*        the GetOpenFileName() common dialog function.
*
*    RETURN VALUES:
*        TRUE - The file name was obtained successfully
*        FALSE - No file name was obtained.
*
****************************************************************************/
BOOL OpenNewFile( HWND hWnd)
{
    
    _tcscpy( szFile, TEXT(""));
    _tcscpy( szFileTitle, TEXT(""));

    OpenFileName.lStructSize      = sizeof(OPENFILENAME);
    OpenFileName.hwndOwner        = hWnd;
    OpenFileName.hInstance        = (HANDLE) hInst;
    OpenFileName.lpstrFilter      = szFilter;
    OpenFileName.lpstrCustomFilter = NULL;
    OpenFileName.nMaxCustFilter   = 0L;
    OpenFileName.nFilterIndex     = 1L;
    OpenFileName.lpstrFile        = szFile;
    OpenFileName.nMaxFile         = sizeof(szFile);
    OpenFileName.lpstrFileTitle   = szFileTitle;
    OpenFileName.nMaxFileTitle    = sizeof(szFileTitle);
    OpenFileName.lpstrInitialDir   = NULL;
    OpenFileName.lpstrTitle       = TEXT("Open a File");
    OpenFileName.lpstrDefExt      = TEXT("*.txt");
    OpenFileName.nFileOffset      = 0;
    OpenFileName.nFileExtension   = 0;
    OpenFileName.lCustData        = 0;
    OpenFileName.Flags =  OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    
    if (GetOpenFileName(&OpenFileName))
    {
        if (RdFileToBuf( OpenFileName.lpstrFile, hWnd ))
            return TRUE;
		else
            return FALSE;
	}
    else
    {
        return FALSE;
    }
    
}
/****************************************************************************************
* FUNCTION: RdFileToBuf()
*
*    PURPOSE:  Opens and reads a file into FileBuf
*
*    COMMENTS:
*
*        This function
*
*    RETURN VALUES:
*        TRUE - The file was opened successfully and read into the buffer.
*        FALSE - No files were opened.
*
*
************************************************************************************/
BOOL RdFileToBuf( LPTSTR lpszFile, HWND hWnd )
{
    
	HANDLE hFile;
	int cBufLen;
	DWORD dwRW,length;

	char *pMBString;


	hFile = CreateFile(lpszFile, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	length = GetFileSize(hFile,NULL);
	pMBString = (char *)LocalAlloc(LPTR,(length * (sizeof(char) + sizeof(char))));


	if(length > FILE_LEN)
	{
     MessageBox( hWnd, TEXT("File size too big!"), NULL, MB_OK );
	 return FALSE;
	}

	
	if (hFile == INVALID_HANDLE_VALUE)
    {
        MessageBox( hWnd, TEXT("File open failed."), NULL, MB_OK );
		return FALSE;
    }
    else
        cBufLen = ReadFile( hFile,pMBString,(length*(sizeof(char) + sizeof(char)) ), &dwRW, NULL);

		mbstowcs(FileBuf,pMBString,length);
				
  
    if (cBufLen == -1)
    {
         MessageBox( hWnd, TEXT("Zero bytes read."), NULL, MB_OK );
        // close the file (tek 24jul96)
       CloseHandle( hFile );
        return FALSE;
    }
    else
    {
        // close the file
        FileBuf[(int)length]='\0';
        CloseHandle( hFile );
     }
    
    return TRUE;
}


/****************************************************************************
*
*    FUNCTION: ProcessCDError(DWORD)
*
*    PURPOSE:  Processes errors from the common dialog functions.
*
*    COMMENTS:
*
*        This function is called whenever a common dialog function
*        fails.  The CommonDialogExtendedError() value is passed to
*        the function which maps the error value to a string table.
*        The string is loaded and displayed for the user.
*
*    RETURN VALUES:
*        void.
*
****************************************************************************/
/* comment out for now
id ProcessCDError(DWORD dwErrorCode, HWND hWnd)
{
    TCHAR  buf[256];

    WORD  wStringID;

    
    switch(dwErrorCode)
    {
    case CDERR_DIALOGFAILURE:    wStringID=IDS_DIALOGFAILURE;   break;
    case CDERR_STRUCTSIZE:   wStringID=IDS_STRUCTSIZE;			break;
    case CDERR_INITIALIZATION:  wStringID=IDS_INITIALIZATION;   break;
    case CDERR_NOTEMPLATE:   wStringID=IDS_NOTEMPLATE;			break;
    case CDERR_NOHINSTANCE:  wStringID=IDS_NOHINSTANCE;			break;
    case CDERR_LOADSTRFAILURE:  wStringID=IDS_LOADSTRFAILURE;   break;
    case CDERR_FINDRESFAILURE:  wStringID=IDS_FINDRESFAILURE;   break;
    case CDERR_LOADRESFAILURE:  wStringID=IDS_LOADRESFAILURE;   break;
    case CDERR_LOCKRESFAILURE:  wStringID=IDS_LOCKRESFAILURE;   break;
    case CDERR_MEMALLOCFAILURE: wStringID=IDS_MEMALLOCFAILURE;	break;
    case CDERR_MEMLOCKFAILURE:  wStringID=IDS_MEMLOCKFAILURE;   break;
    case CDERR_NOHOOK:       wStringID=IDS_NOHOOK;				break;
    case PDERR_SETUPFAILURE:     wStringID=IDS_SETUPFAILURE;    break;
    case PDERR_PARSEFAILURE:     wStringID=IDS_PARSEFAILURE;    break;
    case PDERR_RETDEFFAILURE:    wStringID=IDS_RETDEFFAILURE;   break;
    case PDERR_LOADDRVFAILURE:  wStringID=IDS_LOADDRVFAILURE;   break;
    case PDERR_GETDEVMODEFAIL:  wStringID=IDS_GETDEVMODEFAIL;   break;
    case PDERR_INITFAILURE:  wStringID=IDS_INITFAILURE;			break;
    case PDERR_NODEVICES:        wStringID=IDS_NODEVICES;       break;
    case PDERR_NODEFAULTPRN:     wStringID=IDS_NODEFAULTPRN;    break;
    case PDERR_DNDMMISMATCH:     wStringID=IDS_DNDMMISMATCH;    break;
    case PDERR_CREATEICFAILURE: wStringID=IDS_CREATEICFAILURE;	break;
    case PDERR_PRINTERNOTFOUND: wStringID=IDS_PRINTERNOTFOUND;	break;
    case CFERR_NOFONTS:      wStringID=IDS_NOFONTS;				break;
    case FNERR_SUBCLASSFAILURE: wStringID=IDS_SUBCLASSFAILURE;	break;
    case FNERR_INVALIDFILENAME: wStringID=IDS_INVALIDFILENAME;	break;
    case FNERR_BUFFERTOOSMALL:  wStringID=IDS_BUFFERTOOSMALL;   break;
        
    case 0:   //User may have hit CANCEL or we got a *very* random error
        return;
        
    default:
        wStringID=IDS_UNKNOWNERROR;
    }
   
    LoadString(NULL, wStringID, buf, sizeof(buf));
    MessageBox(hWnd, buf, NULL, MB_OK);

    return;
}

*/

#ifdef ACCESS32

/***********************************************************************************
*
* The following is for the TYPING DEMO feature
*
************************************************************************************/
BOOL APIENTRY PrimaryTypingDlgProc( HWND hWnd,
                                   UINT uiMsg,
                                   WPARAM wParam,
                                   LPARAM lParam )
{
    switch( uiMsg )
    {
    case WM_CHAR:
        if (typing_mode) {
            // Yes this is inefficient, but it shows how to use TextToSpeechGetRate()
            TextToSpeechGetRate(phTTS[ptts_select->tts_lang_index], &current_rate);
            TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index],350);
            TextToSpeechTyping(phTTS[ptts_select->tts_lang_index], wParam);
            TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index], current_rate);
        }
        break;
    }
    return CallWindowProc(OldPrimaryTypingDlgProc, hWnd, uiMsg, wParam, lParam);
}


/**********************************************************************
*
* The following is for the HIGHLIGHTING feature
*
***********************************************************************/

BOOL SpeakText( HANDLE hWnd )
{
    DWORD      dwTextLen=0 ;
	LPTSTR      lpEditText=NULL ;
    MMRESULT   mmStatus=0 ;
    TCHAR       szError[32]=_T("") ;
    TCHAR       lpEditIM[256]=_T("");
    ULONG           ptr = 0;
    ULONG           pos = 0;
    ULONG           mark = 2;
    TCHAR           temp[50]=_T("");
    MARK_POS        *next = mark_pos;
    BOOL            inbracket = FALSE;
    // tek 19jun97
   TCHAR           cPrevchar=_T('\0');
    
    while (next != NULL) {
        mark_pos = next->next_mark;
        free(next);
        next = mark_pos;
    }
    
    dwTextLen = SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
    lpEditText  = (TCHAR *)malloc((1 + dwTextLen) * sizeof(TCHAR)) ;
    SendMessage(hwndEdit, WM_GETTEXT,(WPARAM) dwTextLen +1, (LPARAM) lpEditText);
    
    if (highlight) {
        wcscpy(lpEditIM,_T("[:i m 1]"));
        ptr = wcslen(lpEditIM);
        
        next = malloc(sizeof(MARK_POS));
        next->next_mark = NULL;
        mark_pos = next;
        while (pos < wcslen(lpEditText)) {
            while ((lpEditText[pos] == _T(' ') || lpEditText[pos] == _T('\t') || lpEditText[pos] == _T('\n'))
                && ptr < 125 && pos < wcslen(lpEditText)) {
                lpEditIM[ptr++] = lpEditText[pos++];
            }
            next->start = pos;
            while (lpEditText[pos] != _T(' ') && lpEditText[pos] != _T('\n') && lpEditText[pos] != _T('\t')
                && ptr < 240 && pos < wcslen(lpEditText)) {
                if (lpEditText[pos] == _T('['))     inbracket = TRUE;
                if (lpEditText[pos] == _T(']'))     inbracket = FALSE;
                lpEditIM[ptr++] = lpEditText[pos++];
            }
            if (lpEditText[pos] == _T(' ') || lpEditText[pos] == _T('\n') || lpEditText[pos] == _T('\t')) {
                if (inbracket != TRUE) {
                    next->end = pos;
                    /* GL 05/14/1997 BATS#373 fix the table reading problem*/
                    lpEditIM[ptr++] = lpEditText[pos];
                    lpEditIM[ptr++] = _T('\0');         
                    wsprintf(temp,_T("[:i m %lu]"), mark++);
   
                    ptr += wcslen(temp) - 1;
                    wcscat(lpEditIM, temp);
                    pos++;
                    next->next_mark = malloc(sizeof(MARK_POS));
                    next = next->next_mark;
                    next->next_mark = NULL;
                    next->start = pos;
                } else {
                    lpEditIM[ptr++] = lpEditText[pos++];
                }
            }
            // tek 19jun97 try to break and speak at clause bdry..
            if (pos > 3)
                cPrevchar = lpEditText[pos-2];
            else
                cPrevchar = _T('\0');
            
            if ( (ptr > 224)
                ||( cPrevchar==_T('.') || cPrevchar==_T(',') || cPrevchar==_T('?') || cPrevchar==_T('!')) )
            {
                lpEditIM[ptr++] = _T('\0');
                mmStatus = TextToSpeechSpeak(phTTS[ptts_select->tts_lang_index], lpEditIM, TTS_NORMAL);
                if ( mmStatus ) {
					wsprintf( szError, _T("Error = %d"), mmStatus );                 
                    MessageBox( hWnd, szError, _T("TextToSpeechSpeak"), MB_OK | MB_ICONSTOP );
                    return TRUE;
                }
                ptr = 0;
            }
        }   // while loop
        
        if (ptr) {	
            lpEditIM[ptr++] = _T('\0');
            mmStatus = TextToSpeechSpeak(phTTS[ptts_select->tts_lang_index], lpEditIM, TTS_NORMAL);
            if ( mmStatus ) {
                wsprintf( szError, _T("Error = %d"), mmStatus );
                MessageBox( hWnd, szError, _T("TextToSpeechSpeak"), MB_OK | MB_ICONSTOP );
                return TRUE;
            }
            ptr = 0;
        }
        
        mmStatus = TextToSpeechSpeak(phTTS[ptts_select->tts_lang_index], _T(""), TTS_FORCE);
        if ( mmStatus ) {
            wsprintf( szError, _T("Error = %d"), mmStatus );
            MessageBox( hWnd, szError, _T("TextToSpeechSpeak"), MB_OK | MB_ICONSTOP );
            return TRUE;
        }
        
        free(lpEditText);
        
        if ( mmStatus ) {
            wsprintf( szError, _T("Error = %d"), mmStatus );
            MessageBox( hWnd, szError, _T("TextToSpeechSpeak"), MB_OK | MB_ICONSTOP );
            return TRUE;
        }
    } else {
        
        mmStatus = TextToSpeechSpeak(phTTS[ptts_select->tts_lang_index], lpEditText, TTS_FORCE);
        if ( mmStatus )
            MessageBox( hWnd,
            _T("Error in TTS Speak") ,
            _T("ERROR"),
            MB_OK | MB_ICONSTOP );
        free(lpEditText);
        
        if ( mmStatus )
        {
            wsprintf( szError, _T("Error = %d"), mmStatus );
            MessageBox( hWnd, szError, _T("TextToSpeechSpeak"), MB_OK | MB_ICONSTOP );
            return TRUE;
        }
    }
    return FALSE;
}


VOID TTSCallbackRoutine(LONG lParam1, LONG lParam2,
                        DWORD dwInstanceParam, UINT uiMsg) {
    
    switch( lParam1 )
    {
    case TTS_INDEX_MARK:
        update_mark(lParam2);
        break;
        
    case TTS_AUDIO_PLAY_STOP:
        update_mark(0xFFFFFFFF);
        break;
        
    case TTS_AUDIO_PLAY_START:
    case ERROR_OPENING_WAVE_OUTPUT_DEVICE:
    case ERROR_IN_AUDIO_WRITE:
    case ERROR_GETTING_DEVICE_CAPABILITIES:
    default:
        break;
    }
}


void update_mark(ULONG mark) {
    MARK_POS *next = mark_pos;
    ULONG pos;
    
    if (mark == 0xFFFFFFFFL) {
        PostMessage(hwndEdit, EM_SETSEL, (WPARAM)-1, (LPARAM) 0);
        PostMessage(hwndEdit, EM_SCROLLCARET, (WPARAM) 0, (LPARAM) 0);
        return;
    }
    if (next == NULL)       return;
    for (pos = 1; pos < mark; pos++) {
        if (next->next_mark == NULL)    return;
        next = next->next_mark;
    }
    if (highlight) {
        PostMessage(hwndEdit, EM_SETSEL, (WPARAM)next->start, (LPARAM) next->end);
        PostMessage(hwndEdit, EM_SCROLLCARET, (WPARAM) 0, (LPARAM) 0);
    }
    return;
}


#endif // ACCESS32

//*****************************************************************************
//  Initialize the Text to Speech system: Use Wave Mapper to allocate an
//  appropriate audio port, Since the "OWN_AUDIO_DEVICE" flag is not
//  set the audio device will be shared, (given up when not currently speaking)
//  Report open error will cause an asynchronous error message
//  ("DECtalkErrorMessage") to be sent to this window in case the
//  audio device is not available.
//
//      FUNCTION:InitDectalk(HWND, TTS_LANG_MAP_START*);
//      
//      FUCTIONALITY: it gets the number of languages from TTS_ENUM_LANGS() and 
//                        for each of those languages it adds it to the TTS_LANG_MAP.
//          The TTS_LANG_MAP is a list that MAPs the lang thread index to its menu ID.
//          InitDectalk() calls TextToSpeechStartLang() to get the index for the 
//          language thread.  That thread is startedup with TextToSpeechStartupEx()
//
//      PURPOSE:  sets up everything to call tts_startup correctly for multilanguage
//
//      COMMENTS:
//          This function calls TexttoSpeechEnumLangs to get the number of 
//              languages.  With the number of languages it then calls: 
//                  TextToSpeechStartLang
//                  TextToSpeechSelectLang
//                  TextToSpeechStartupEx
#ifdef ACCESS32
//                  Startup is not called in Access32 till the end because of
//                  TYPING demo which needs to own the Audio Device.
#endif
//                  For each language a menu is created:
//              The menu ID, the number given back by ttsSelectLang, and the 2
//                  letter string corispoding to the name are all shoved on a
//                  list of TTS_LANG_MAP.  This list is used to MAP the index
//                  of the thread of the language with the Menu ID
//              Then for each language, a menu is created.  
//
//Note: TextToSpeechEnumLangs' first LANGUAGE is supposed to be the DEFAULT language 
//    set in the registry. 
//    At the moment that is not the case so that the starting language is random
//
//      RETURN VALUES:
//       -1 - Error!
//       FALSE - OK
//*****************************************************************************

int InitDectalk(HWND hWnd, TTS_LANG_MAP_START* pTTSstart)
{
    unsigned int i, nTemp, nCurrentMenuID;
    TCHAR *szError = NULL;
	HMENU main_menu;
//    MENUITEMINFO menu_item;
    TTS_LANG_MAP* pTTScurrent = NULL;
    TTS_LANG_MAP* pTTSprev = NULL;
    MMRESULT mmStatus;

   EnableMenuItem(hMenu, IDM_LANG_US, MF_GRAYED );
   EnableMenuItem(hMenu, IDM_LANG_UK, MF_GRAYED );
   EnableMenuItem(hMenu, IDM_LANG_SP, MF_GRAYED );
   EnableMenuItem(hMenu, IDM_LANG_LA, MF_GRAYED );
   EnableMenuItem(hMenu, IDM_LANG_GR, MF_GRAYED );

    
    if(TextToSpeechEnumLangs(&languageINFO) == 0) 
    {
        MessageBox(NULL,TEXT("Unable to allocate Memory"),TEXT("Error"),MB_OK);
        return(-1);
    }

    if(languageINFO->MultiLang == FALSE) 
    {
        // we are in single language mode
#ifdef ACCESS32 
        mmStatus = TextToSpeechStartupEx(&phTTS[0], WAVE_MAPPER, REPORT_OPEN_ERROR | OWN_AUDIO_DEVICE, TTSCallbackRoutine, 0);
#else
        mmStatus = TextToSpeechStartupEx(&phTTS[0], WAVE_MAPPER, REPORT_OPEN_ERROR, NULL, 0);
#endif
	pTTScurrent = malloc(sizeof(TTS_LANG_MAP));
        if(pTTScurrent == NULL)
        {   
            MessageBox(NULL,TEXT("Unable to allocate Memory"),TEXT("Error"),MB_OK);
            return(-1);
        }
        pTTScurrent->tts_lang_index = 0;
	pTTScurrent->tts_lang_menu =  0;
        wcscpy(pTTScurrent->tts_lang_name, languageINFO->Entries[0].lang_code);

	if(wcscmp(pTTScurrent->tts_lang_name,TEXT("US"))==0)
	{
		EnableMenuItem(hMenu, IDM_LANG_US, MF_ENABLED );
		pTTScurrent->tts_lang_menu = IDM_LANG_US;
	}
	else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("SP"))==0)
	{
		EnableMenuItem(hMenu, IDM_LANG_SP, MF_ENABLED );
		pTTScurrent->tts_lang_menu = IDM_LANG_SP;
	}	
	else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("GR"))==0)
	{
		EnableMenuItem(hMenu, IDM_LANG_GR, MF_ENABLED );
		pTTScurrent->tts_lang_menu = IDM_LANG_GR;
	}	
	else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("UK"))==0)
	{
		EnableMenuItem(hMenu, IDM_LANG_UK, MF_ENABLED );
		pTTScurrent->tts_lang_menu = IDM_LANG_UK;
	}
	else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("LA"))==0)
	{
		EnableMenuItem(hMenu, IDM_LANG_LA, MF_ENABLED );
		pTTScurrent->tts_lang_menu = IDM_LANG_LA;
	}
		
		pTTScurrent->next = NULL;
        pTTSstart->start = pTTScurrent;
        pTTSstart->size = 1;				
		CheckMenuItem(hMenu,pTTScurrent->tts_lang_menu,MF_CHECKED);
        ptts_select = pTTScurrent;

        
    }
    else
    {
			
		main_menu=CommandBar_GetMenu(hWnd,0);
//		CommandBar_InsertMenubar(hWndCB, hInst,IDM_MAIN_MENU_CEA32, 0);

//    CommandBar_InsertMenubar(hWndCB, hInst, IDM_LANG_MENU,1);

        nCurrentMenuID = IDM_LANG_BEGIN;
        pTTSstart->start = NULL;
        pTTSstart->size = 0; 
       

		for(i = 0; i < languageINFO->Languages; i++)	
        {

           nTemp = TextToSpeechStartLang(languageINFO->Entries[i].lang_code);

            if((nTemp & TTS_LANG_ERROR) == 0)
            {

#ifndef ACCESS32
                TextToSpeechSelectLang(NULL, nTemp);
                mmStatus = TextToSpeechStartupEx(&phTTS[nTemp], WAVE_MAPPER, REPORT_OPEN_ERROR, NULL, 0);
#endif               

		       pTTScurrent = malloc(sizeof(TTS_LANG_MAP));
               if(pTTScurrent == NULL)
               {   
		    MessageBox(hWnd, TEXT("Out of memory!"), TEXT("Error"), MB_OK);
                    return(-1);
               }

               pTTScurrent->tts_lang_index = nTemp;
//              pTTScurrent->tts_lang_menu = nCurrentMenuID++;
		wcscpy(pTTScurrent->tts_lang_name, languageINFO->Entries[i].lang_code);

		if(wcscmp(pTTScurrent->tts_lang_name,TEXT("US"))==0)
		{
			EnableMenuItem(hMenu, IDM_LANG_US, MF_ENABLED );
			pTTScurrent->tts_lang_menu = IDM_LANG_US;
		}
		else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("SP"))==0)
		{
			EnableMenuItem(hMenu, IDM_LANG_SP, MF_ENABLED );
			pTTScurrent->tts_lang_menu = IDM_LANG_SP;
		}	
		else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("GR"))==0)
		{
			EnableMenuItem(hMenu, IDM_LANG_GR, MF_ENABLED );
			pTTScurrent->tts_lang_menu = IDM_LANG_GR;
		}	
		else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("UK"))==0)
		{
			EnableMenuItem(hMenu, IDM_LANG_UK, MF_ENABLED );
			pTTScurrent->tts_lang_menu = IDM_LANG_UK;
		}
		else if(wcscmp(pTTScurrent->tts_lang_name,TEXT("LA"))==0)
		{
			EnableMenuItem(hMenu, IDM_LANG_LA, MF_ENABLED );
			pTTScurrent->tts_lang_menu = IDM_LANG_LA;
		}

                pTTScurrent->next = NULL;
                if(pTTSstart->start == NULL)
                    pTTSstart->start = pTTScurrent;
                else 
                    pTTSprev->next = pTTScurrent;
                pTTSprev = pTTScurrent;
                pTTSstart->size++;
                
				if(i == 0)
                {
				CheckMenuItem(hMenu,pTTScurrent->tts_lang_menu,MF_CHECKED);
                    ptts_select = pTTScurrent;
                }
                if(pTTScurrent->tts_lang_menu == IDM_LANG_END)
                {
                    MessageBox(hWnd, TEXT("To many language dlls."), TEXT("Error"), MB_OK);
                    return(-1);
                }
            }
            
        }
#ifdef ACCESS32

        TextToSpeechSelectLang(NULL, ptts_select->tts_lang_index);
        mmStatus = TextToSpeechStartupEx(&phTTS[ptts_select->tts_lang_index], WAVE_MAPPER, REPORT_OPEN_ERROR | OWN_AUDIO_DEVICE, TTSCallbackRoutine, 0);
#endif  
    }
    if(pTTSstart->start == NULL)
    {
        MessageBox( hWnd, TEXT("No Languages Available"),TEXT("Error"), MB_OK | MB_ICONSTOP );
        return(-1); 
    }

    if ( mmStatus != MMSYSERR_NOERROR )
    {
	if (mmStatus == MMSYSERR_INVALPARAM)	// CAB 7/5/00
	{
		MessageBox( hWnd,TEXT("Dictionary not found, Shutting Down!"), TEXT("TTS statrup failed"), MB_OK | MB_ICONHAND );
		return( -1 );
	}	
	else if (mmStatus == MMSYSERR_NODRIVER)
	{
		MessageBox( hWnd, TEXT("No wave device present,\n Shutting Down!"), NULL, MB_OK | MB_ICONSTOP );
		return( -1 );
	}
	else 
	{
		swprintf( szError, TEXT("TTS startup failed\n\nError = %d\n\nExiting out of application"), mmStatus );
		MessageBox(hWnd, szError, TEXT("DtSample"), MB_OK | MB_ICONSTOP );
	}

	return( -1 );
    }
    return FALSE;
}
//*****************************************************************************
//
//      FUNCTION:destroyDectalk(TTS_LANG_MAP*, unsigned int size);
//
//      PURPOSE:  to get rid of the TTS_LANG_MAP and to shutdown each thread.
//
//      COMMENTS:
//                  This function is basically a recursive tree traversal.
//                      It goes down the list and when comes up it calles 
//                      TextToSpeechShutdown and then frees the pointer.
#ifdef ACCESS32
//  Note:   TextToSpeechShutdown is not really called for ACCESS32 here.
//          Sinse, OWN_AUDIO_DEVICE is on there is only one THREAD. 
#endif
//
//      RETURN VALUES:
//       mmSySERR_INVALHANDLE  - THis is bad!  Error!
//          1 - OK!
//*****************************************************************************

MMRESULT destroyDectalk(TTS_LANG_MAP* curr, unsigned int size)
{
    MMRESULT mmStatus;
    
    if(size == 0 || curr == NULL)
        return 1;
    mmStatus = destroyDectalk(curr->next, size - 1);
    if(mmStatus == 1)
    {
#ifndef ACCESS32
        mmStatus = TextToSpeechShutdown(phTTS[curr->tts_lang_index]);
#endif
        if(mmStatus == MMSYSERR_INVALHANDLE)
            return MMSYSERR_INVALHANDLE;
        free(curr);
        return 1;
    }
    else if(mmStatus == MMSYSERR_INVALHANDLE)
        return MMSYSERR_INVALHANDLE;

return 1;
}


//*****************************************************************************
//
//      FUNCTION:switchLANGs(HWND, TTS_LANG_MAP_START*, unsigned int size);
//
//      PURPOSE:  to switch to the correct thread.
//
//      COMMENTS:
//          this fuction:
//              looks for the pointer of the language to switch to
//              if its the same as ptts_select then return
//              unchecks the old menu and checks the new one
//              points ptts_select to the new language
//              sets the RATE to the current rate
//#ifdef ACCESS32
//      note:   for ACCESS32 it has to shutdown the previous thread and 
//              start a new one for that language.
//#endif
//
//              
//      note: Any message sent back from the program has to be in range of
//          IDM_LANG_BEGIN and IDM_LANG_END if they are to be processed by langSwitch
//      
//
//      RETURN VALUES:
//       mmSySERR_INVALHANDLE  - THis is bad!  Error!
//          1 - OK!
//*****************************************************************************

void switchLangs(HWND hWnd, TTS_LANG_MAP_START* pttsstart, unsigned int unNewMenuID)
{

//	HMENU main_menu = NULL;

    unsigned int i;
    TTS_LANG_MAP* pCurrent = pttsstart->start;
    MMRESULT mmStatus;

//		main_menu=CommandBar_GetMenu(hWnd,0);


	for(i = 0; i < pttsstart->size; i++)
    {
        if(pCurrent->tts_lang_menu == unNewMenuID)
            break;
        pCurrent = pCurrent->next;
    }

 
    if(pCurrent->tts_lang_menu != unNewMenuID)
    {               
	   MessageBox(hWnd, TEXT("The menu ID is not in the Language Map."),TEXT("Error"), MB_OK);
	   return;
    }
    else if(pCurrent == ptts_select){  //if the address are the same
	   return;
	}
	 else  //then you want to switch to the new language 
    {
    	CheckMenuItem(hMenu,ptts_select->tts_lang_menu,MF_BYCOMMAND | MF_UNCHECKED);     

#ifdef ACCESS32
        mmStatus = TextToSpeechShutdown(phTTS[ptts_select->tts_lang_index]);
        if(mmStatus == MMSYSERR_INVALHANDLE)
        {
            MessageBox(hWnd, _T("Text to Speech Handle was invalid"), _T("Error"), MB_OK);
            return;
        }
        ptts_select = pCurrent;
        TextToSpeechSelectLang(NULL, ptts_select->tts_lang_index);
        mmStatus = TextToSpeechStartupEx(&phTTS[ptts_select->tts_lang_index],
            WAVE_MAPPER, REPORT_OPEN_ERROR | OWN_AUDIO_DEVICE, TTSCallbackRoutine, 0);
        if(mmStatus == MMSYSERR_NOMEM)
        {           
            MessageBox(hWnd, _T("Memory allocation error."), _T("Error"), MB_OK);
            return;
        }
#else
        ptts_select = pCurrent;
#endif
       
		mmStatus = TextToSpeechSetRate(phTTS[ptts_select->tts_lang_index], current_rate);

        CheckMenuItem(hMenu, ptts_select->tts_lang_menu, MF_BYCOMMAND | MF_CHECKED);

		GetWindowText(hwndEdit,FileBuf,sizeof(FileBuf)/sizeof(TCHAR));

	 }
}