Adding Commands to a Voice Menu

After you create a voice-menu object, you can add commands to the menu by filling an array of VCMDCOMMAND structures, copying the address and size of the array into an SDATA structure, and passing the address of the SDATA structure to the IVCmdMenu::Add member function.

The example in this section shows how to add a new set of commands to a voice-menu object. The example consists of three functions: UseCommands, GetCommands, and NextCommand. The UseCommands function deactivates the voice menu, replaces any existing commands in the menu with a new set, and reactivates the menu.

One of the parameters to UseCommands is the address of a buffer containing the list of command strings to enter. UseCommands passes the address of the command-string buffer to the GetCommands function along with the address of an SDATA structure. The GetCommands function converts the buffer to an array of VCMDCOMMAND structures and copies the address and size of the array into the SDATA structure. The NextCommand function is a helper routine that GetCommands uses to retrieve individual command strings from the command buffer passed to UseCommands.

// UseCommands - adds commands to a voice-menu object, replacing any

// existing commands.

// Returns the result code returned by a voice-menu function.

// pszCommands - address of a null-terminated string of commands

// separated by \n or \r characters

// pMenu - address of the IVCmdMenu interface for the voice-menu object

HRESULT UseCommands (char *pszCommands, PIVCMDMENU pMenu)

{

HRESULT hRes;

SDATA data;

DWORD dwNum, dwStart;

hRes = pMenu->Deactivate(); // deactivate the menu

if (hRes) return hRes;

// Retrieve the number of commands in the menu.

hRes = pMenu->Num(&dwNum);

if (hRes) return hRes;

// Remove the existing commands from the menu.

if (dwNum)

hRes = pMenu->Remove (1, dwNum, VCMD_BY_POSITION);

if (hRes) return hRes;

// Call GetCommands, an application-defined function that fills an SDATA

// structure with information about the commands to add to the menu.

if (!GetCommands(pszCommands, &data, &dwNum))

return ResultFromScode (E_OUTOFMEMORY);

// Add the commands to the menu.

hRes = pMenu->Add (dwNum, data, &dwStart);

if (hRes) return hRes;

// Free the command data.

free (data.pData);

// Reactivate the menu.

hRes = pMenu->Activate(ghwndDialog, 0);

return hRes;

}

// GetCommands - takes a block of memory containing command strings and

// converts it into a list of VCMDCOMMAND structures.

// Returns TRUE if successful or FALSE otherwise.

// pszMemory - address of a null-terminated string of commands

// separated by \n or \r characters

// pData - address of an SDATA structure that receives the address and

// size of the memory containing the VCMDCOMMAND structures. The

// caller must free the memory by using the free function.

// pdwNumCommands - receives the count of VCMDCOMMAND structures in the

// memory block

BOOL GetCommands(char *pszMemory, PSDATA pData, DWORD *pdwNumCommands)

{

PSTR pTemp;

DWORD dwTotal, dwSize, dwSizeDesc, dwSizeCat;

DWORD dwSizeCmd;

PVCMDCOMMAND pCmd, pCmdNew;

CHAR *pszBegin;

DWORD dwCmdSize;

DWORD dwCmds = 0; // current count

DWORD dwCount = 1; // command number

char szCat[] = "Main";

dwTotal = dwSize = 0;

pTemp = (PSTR) malloc(0);

if (!pTemp)

return FALSE;

pCmd = (PVCMDCOMMAND) pTemp;

for( ;; ) {

// Retrieve the next command from the list of command strings.

pszMemory = NextCommand (pszMemory, &pszBegin, &dwCmdSize);

if (!pszMemory)

break; // no more

dwSize = sizeof(VCMDCOMMAND); // size of header

dwSizeCmd = (dwCmdSize + 1); // get command-string length

// Align the command string on a doubleword boundary.

dwSizeCmd += 3;

dwSizeCmd &= (~3);

dwSize += dwSizeCmd;

dwSizeDesc = (dwCmdSize + 1); // get description length

// Align the description on a doubleword boundary.

dwSizeDesc += 3;

dwSizeDesc &= (~3);

dwSize += dwSizeDesc;

dwSizeCat = lstrlen(szCat) + 1; // get category length

// Align the category string on a doubleword boundary.

dwSizeCat += 3;

dwSizeCat &= (~3);

dwSize += dwSizeCat;

dwSize += sizeof(DWORD); // action indicator

// Accumulate the total size of the command.

dwTotal += dwSize;

// Reallocate enough memory to hold the command.

pTemp = (PSTR) realloc((PVOID) pCmd, dwTotal);

// Fill the new VCMDCOMMAND structure.

pCmd = (PVCMDCOMMAND) pTemp;

pTemp += (dwTotal-dwSize);

pCmdNew = (PVCMDCOMMAND) pTemp;

memset (pCmdNew, 0, dwSize);

pCmdNew->dwSize = dwSize;

pCmdNew->dwFlags = 0;

pCmdNew->dwAction = (DWORD) (pCmdNew->abData - (PBYTE) pTemp);

pCmdNew->dwActionSize = sizeof(DWORD);

pCmdNew->dwCommandText = NULL;

// Point past the header to the beginning of the command data.

pTemp += (pCmdNew->abData - (PBYTE) pTemp);

// Set the action index.

*(DWORD *) pTemp = dwCount++;

pTemp += sizeof(DWORD);

// Set the command string.

pCmdNew->dwCommand = (DWORD) ((PBYTE) pTemp - (PBYTE) pCmdNew);

strncpy(pTemp, pszBegin, dwCmdSize);

pTemp += dwSizeCmd;

// Set the description.

pCmdNew->dwDescription =

(DWORD) ((PBYTE) pTemp - (PBYTE) pCmdNew);

strncpy(pTemp, pszBegin, dwCmdSize);

pTemp += dwSizeDesc;

// Set the category.

pCmdNew->dwCategory = (DWORD) ((PBYTE) pTemp - (PBYTE) pCmdNew);

strcpy(pTemp, szCat);

// Increment the count of commands.

dwCmds++;

}

pData-pData = (PVOID) pCmd;

pData-dwSize = dwTotal;

*pdwNumCommands = dwCmds;

return TRUE;

}

// NextCommand - finds the next command in a block of memory.

// Returns the address of the next command string in the block, or NULL

// if no command string is found.

// pszMemory - address of a null-terminated string of commands

// separated by \n or \r characters

// pBegin - receives the address of the next command string

// pdwSize - receives the number of bytes in the command string, not

// including any terminating NULL character

CHAR * NextCommand (CHAR *pszMemory, PCHAR *pBegin, DWORD *pdwSize)

{

DWORD i;

for( ;; ) {

// Try to find a non-newline character.

while ((*pszMemory == '\n') || (*pszMemory == '\r')) {

if (*pszMemory == '\0')

return NULL;

pszMemory++;

};

// Try to find a newline character.

for (i = 0;

(pszMemory[i] != '\n') && (pszMemory[i] != '\r') &&

(pszMemory[i] != '\0'); i++);

if (!i) {

if (!pszMemory[i])

return NULL; // end

pszMemory++;

continue; // try again

};

// A string was found. Return it.

*pBegin = pszMemory;

*pdwSize = i;

return pszMemory + i;

};

}