Using the CAPILIB Functions

CAPILIB provides a toolbox of functions to simplify your Word API programming tasks. This section takes a close look at these functions and how to use them to build Word operators, pass arrays, and customize Word.

The Word Command Buffer (WCB)

WCB is a data structure defined in WDCAPI.H. This structure is used by the various functions in CAPILIB to help build up the array of WDOPR parameters to be passed to the wdCommandDispatch function. The constant MaxArgs, found in WDCAPI.H, determines the maximum number of WDOPR parameters that can be built up. MaxArgs is safely set to 34, an argument count much greater than you'll probably ever need. cArgs is automatically incremented as WDOPR arguments are built up by the CAPILIB functions, and contains the actual count of the WDOPR arguments.


typedef struct
{
    short    cArgs;
    WDOPR    wdoprReturn;
    WDOPR    wdoprArgs[MaxArgs];
} WCB;

Functions in CAPILIB

There are eighteen functions in CAPILIB, which can be grouped into seven categories:

You should include the header file CAPILIB.H in modules that call these functions.

Initialize WCB

The first function initializes the WCB structure before building up the WDOPR arguments. The InitWCB function sets the cArgs count to 0 (zero) and sets up the return type. It is very important to call this function first; if cArgs is not initialized and set to the proper count, wdCommandDispatch will behave unpredictably.


// Windows
void InitWCB( WCB far *lpwcb, ushort retType, LPUCHAR lpBuffer, 
    ushort cBufferSize );

// Macintosh
void InitWCB( WCB *lpwcb, ushort retType, StringPtr lpBuffer, 
    ushort cBufferSize );

The parameters to InitWCB are as follows.

Parameter

Description

lpwcb

A pointer to the WCB to be initialized.

retType

The return type of the command. This lets the InitWCB function prepare the return WDOPR's contents.

lpBuffer

Pointer to the start of buffer. If the returned information will be
a string buffer, the return WDOPR will only contain a pointer to
a buffer.

cBufferSize

The return buffer's allocated length.


Add Dialog Fields

After InitWCB has been called, you build up WDOPR arguments one at a time by calling the other functions. Each of these functions increments the cArgs count and initializes the fields in a single WDOPR argument.

These four functions add field parameters for dialog commands:


// Windows
void AddShortDlgField( WCB far *lpwcb, short ShortVal, ushort FieldId,
    ushort fMode );
void AddLongDlgField( WCB far *lpwcb, long LongVal, ushort FieldId,
    ushort fMode );
void AddDoubleDlgField( WCB far *lpwcb, double DoubleVal,
    ushort FieldId, short fMode );
void AddStringDlgField( WCB far *lpwcb, LPUCHAR lpStr, ushort FieldId,
    ushort fMode, ushort cBufferSize );

// Macintosh
void AddShortDlgField( WCB *lpwcb, short ShortVal, ushort FieldId,
    ushort fMode );
void AddLongDlgField( WCB     *lpwcb, long LongVal, ushort FieldId,
    ushort fMode );
void AddDoubleDlgField( WCB *lpwcb, double DoubleVal, ushort FieldId,
    ushort fMode );
void AddStringDlgField( WCB *lpwcb, StringPtr lpStr, ushort FieldId,
    ushort fMode, ushort cBufferSize );

Here's a description of each of the parameters of these functions.

Parameter

Description

lpwcb

The address of the WCB structure.

ShortVal

The field's data, of the type indicated in the name of each function.

FieldId

The field's ID. A list of field ID constants is provided in WDFID.H, which should be included in modules calling the Word API functions. These constants have names that closely parallel the dialog command field names in WordBasic.

fMode

Indicates the input/output mode for the given dialog command field. Set this field using the constants INPUT, OUTPUT, or both.

cBufferSize

The allocated space for the string buffer.


Add Parameters

The next group of functions is called to build parameters for statements other than those that correspond to dialog boxes. The WDOPR argument in this case doesn't have field names, and the input/output information is irrelevant. For these reasons, only two parameters are passed to these functions: the WCB address, and the WDOPR argument data of the type indicated in the function's name.


// Windows
void AddShortParam( WCB far *lpwcb, short ShortVal );
void AddLongParam( WCB far *lpwcb, long LongVal );
void AddDoubleParam( WCB far *lpwcb, double DoubleVal );
void AddStringParam( WCB far *lpwcb, LPUCHAR lpStr );

// Macintosh
void AddShortParam( WCB *lpwcb, short ShortVal );
void AddLongParam( WCB *lpwcb, long LongVal );
void AddDoubleParam( WCB *lpwcb, double DoubleVal );
void AddStringParam( WCB *lpwcb, StringPtr lpStr );

Define Arrays

Three functions are provided to help you set up WDOPR arguments that pass arrays.


// Windows
ARRAY_DEF far * SetArrayDef( HANDLE *phArrDef, short cDimensions, ... );
void AddStringArray( WCB far *lpwcb, ARRAY_DEF far *ArrayDef, 
    LPUCHAR far *lpStrArray, ushort cBufferSize );
void AddDoubleArray( WCB far *lpwcb, ARRAY_DEF far *ArrayDef,
    double far *lpdblArray );

// Macintosh
ARRAY_DEF * SetArrayDef( Handle *phArrDef, short cDimensions, ... );
void AddStringArray( WCB *lpwcb, ARRAY_DEF *ArrayDef, StringPtr 
    *lpStrArray, ushort cBufferSize );
void AddDoubleArray( WCB *lpwcb, ARRAY_DEF *ArrayDef, double 
    *lpdblArray );

The first function, SetArrayDef, builds the ArrayDef parameter required in the WDOPR when arrays are passed. ARRAY_DEF contains information on the number of dimensions and the size of each dimension for an array. The other two functions, AddStringArray and AddDoubleArray, build the WDOPR argument, filling in the data structure with pointers to an array and its associated ARRAY_DEF. When adding a string array, one additional parameter is passed to indicate the allocated size of each string in the array. Note that all strings in an array are allocated to the same maximum size, although the actual null-terminated strings may be of a shorter length.

Note

SetArrayDef allocates memory. After using an array, your WLL function needs to free that memory. For example, given the array hArrayDef, a function should deallocate memory as follows:


// Windows
GlobalUnlock( hArrayDef );
GlobalFree( hArrayDef );

// Macintosh
HUnlock( hArrayDef );
DisposHandle( hArrayDef );

The following stripped-down Windows code fragments demonstrate how SetArrayDef can be used to build the array definition table for an array of strings. Note that this code is extracted from the example code on the Microsoft Word Developer's Kit disk; you might want to study the example in its entirety.


HANDLE          hArrayDef;
ARRAY_DEF far * ArrayDef;
LPSTR           lpStrArray[ARRAYSIZE]; 
char            strArray[ARRAYSIZE][64];

ArrayDef = SetArrayDef( &hArrayDef, 1, ARRAYSIZE );

InitWCB( &wcb, TypeShort, NULL, 0 );
AddStringArray( &wcb, ArrayDef, lpStrArray, 64 );

Call a WordBasic Statement or Function

This function uses a subset of the other CAPILIB functions to fill a WCB for a WordBasic statement or function that does not correspond to a dialog box; it then dispatches the command to Word and returns the result. You can use this as an efficient way to dispatch WordBasic statements and functions in your WLL.


// Windows
short CallCapi( LPWCB far *wcb, short CommandID, ushort retType, LPSTR lpBuffer, ushort cBufferSize, LPSTR lpszFormat, ... );

//Macintosh
short CallCapi( WCB *wcb, short CommandID, ushort retType, StringPtr lpBuffer, ushort cBufferSize, StringPtr lpszFormat, ... );

Parameter

Description

*wcb

Pointer to the WCB structure.

CommandID

The WordBasic statement or function to be called; CommandID cannot correspond to a dialog box.

retType

The return type of the WordBasic statement or function.

lpBuffer

Buffer to store the return string, if any.

cBufferSize

Size of the buffer specified by lpBuffer.

lpszFormat

String describing the type of the arguments passed to CommandID. This list should be a string of characters that identify the type of each argument that follows. Use the following characters:

i Integer

l Long

d Double

s String

For example, if the statement or function takes a string argument followed by an integer argument, lpszFormat would be "si"; the following argument list would be a string argument and an integer. CallCapi automatically parses this list and fills the WCB with the data in the specified order.

...

The list of arguments to dispatch with the statement, in the order specified by lpszFormat.


The following Macintosh example demonstrates how you can use CallCapi to dispatch the wdMsgBox statement in a single instruction.


CallCapi (&wcb, wdMsgBox, TypeVoid, NULL, 0, "ss", "Timer Hit!", "Examp WLL");

Register Functions in Word

The final group of functions provided in CAPILIB provides help with several common programming tasks in your WLL. These functions set up their WDOPR arguments and call wdCommandDispatch in the same way your code will. For this reason they provide excellent working examples of the use of the other CAPILIB functions.

To be callable from Word, functions must be registered with Word. The CAPIRegister function simplifies this task for you. The DocID parameter (passed in to wdAutoOpen), the name of your new function, and a description are the only parameters to this function.


// Windows
short CAPIRegister( short DocID, LPUCHAR lpszFunctionName, LPUCHAR
    lpszDescription );

// Macintosh
short CAPIRegister( short DocID, StringPtr lpszFunctionName, StringPtr 
    lpszDescription );

DocID is a document identifier. It is used to register functions in Word and to customize Word to assign registered functions to toolbar buttons, menus, and shortcut keys.

Just as you choose the names for macros in Word templates, the name you choose for each registered add-in function should be unique to avoid naming conflicts during a Word session. If two or more add-in functions in two or more WLLs are registered under the same name, Word will run the function in the WLL listed first in the list of loaded global templates and add-ins in the Templates And Add-ins dialog box (Templates command, File menu).

A description is not required. If you specify a null value for lpszDescription, CAPIRegister ignores that parameter.

Assign Functions in Word

The final group of functions helps you assign registered functions to toolbar buttons, menus, or shortcut keys. Other than the DocID, the parameters all correspond closely to parameters for the equivalent WordBasic statements AddButton, NewToolbar, ToolsCustomizeMenu, ToolsCustomizeMenuBar, and ToolsCustomizeKeyboard.


// Windows
short CAPIAddButton( short DocID, LPUCHAR lpszToolbar, short cPosition,
    LPUCHAR lpszMacro, LPUCHAR lpszFace ); 
short CAPIAddToolbar( short DocID, LPUCHAR lpszToolbar )
short CAPIAddMenu( short DocID, LPUCHAR lpszMenuName, short Position,
    short MenuType );
short CAPIAddMenuItem( short DocID, LPUCHAR lpszMenu, LPUCHAR lpszName,
    LPUCHAR lpszMenuText, short Position, short MenuType );
short CAPIAddKey( short DocID, short KeyCode, LPUCHAR lpszName );

// Macintosh
short CAPIAddButton( short DocID, StringPtr lpszToolbar, short 
    cPosition, StringPtr lpszMacro, StringPtr lpszFace );
short CAPIAddToolbar( short DocID, StringPtr lpszToolbar );
short CAPIAddMenu( short DocID, StringPtr lpszMenuName, short 
    Position, short MenuType );
short CAPIAddMenuItem( short DocID, StringPtr lpszMenu, StringPtr 
    lpszName, StringPtr lpszMenuText, short Position, short MenuType );
short CAPIAddKey( short DocID, short KeyCode, StringPtr lpszName );

When a WLL passes DocID as the context in which to customize Word, all customization is temporary; the template is not "dirtied" and all customization is removed automatically when the WLL is unloaded.

Note

If you want to make customization in Word permanent, pass the numeric value 0 (zero) to modify the Normal template or 1 to modify the active template (if other than the Normal template) instead of DocID. Note, however, that if you pass a context other than DocID, the template will be dirtied; you should include
a wdAutoRemove function in your WLL to deliberately clean up the Word environment when the WLL is unloaded.

For more information about these functions, see "Customizing Word with CAPILIB" later in this section.

Building Word Operators with CAPILIB

The following example code demonstrates the steps in building two WDOPR arguments for a call to wdCommandDispatch. The two WDOPR arguments pass the number of columns and the number of rows for a new table created by the WordBasic TableInsertTable statement. The WCB structure named wcb is first initialized by a call to InitWCB, the two WDOPR string field arguments are built up, and then wdCommandDispatch is called to perform the TableInsertTable statement. When activated, this block of code inserts a 4 by 12 table in the current document.


// Initialize the WCB - this zero's the WDOPR count
InitWCB( &wcb, TypeVoid, NULL, 0 );

// Build WDOPR arguments for number of columns and rows
AddStringDlgField( &wcb, "4", fidNumColumns, fMode, 0 );
AddStringDlgField( &wcb, "12", fidNumRows, fMode, 0 );

// Call into Word's TableInsertTable command
err = wdCommandDispatch ( wdTableInsertTable, CommandAction, 
    wcb.cArgs, wcb.wdoprArgs, lpwdoprNil );

The last parameter to wdCommandDispatch is lpwdoprNil. Take a look in WDCAPI.H to see how the lpwdoprNil data type is defined as a WDOPR pointer to a zero. Use this when the Word API command doesn't return a WDOPR argument in the last parameter to wdCommandDispatch.

Passing Arrays with CAPILIB

To use the CAPILIB functions to build a WDOPR that passes an array, follow this general procedure:

Example of Passing a Double Array

The following Windows code fragments demonstrate the passing of an array of doubles in a Word API function, using CAPILIB functions. Note that ArrayDef, in this case, is set up for a one-dimension array sized ARRAYSIZE. In the case of a multiple-dimensional array, you would pass different values to the SetArrayDef function.


// Related declarations
HANDLE            hArrayDef;
ARRAY_DEF far * ArrayDef;
double            array[ARRAYSIZE];

// Set the array definition
ArrayDef = SetArrayDef( &hArrayDef, 1, ARRAYSIZE );

// Build a double array WDOPR
InitWCB( &wcb, TypeVoid, NULL, 0 );
AddDoubleArray( &wcb, ArrayDef, array );

// Use wdCommandDispatch here

// Free allocated ArrayDef
GlobalUnlock( hArrayDef );
GlobalFree( hArrayDef );

Example of Passing a String Array

The following lines of Windows code illustrate the general procedure for handling string arrays using the CAPILIB module functions. The important concept to grasp here is the way the various parts of the WDOPR's data structure are loaded with the appropriate data. The string contents are contained in the character array strArray, pointers to each of these strings are loaded into lpStrArray, and the string array's dimensions and sizes are loaded into ArrayDef. Each of these
parts of the WDOPR data structure must be loaded correctly for passing
string array data.


// Related declarations
HANDLE            hArrayDef;
ARRAY_DEF far * ArrayDef;
LPSTR            lpStrArray[ARRAYSIZE]; 
char            strArray[ARRAYSIZE][MAXLENGTH];  

// Set the array definition
ArrayDef = SetArrayDef( &hArrayDef, 1, ARRAYSIZE );

// Set the array of LPSTR to point to a buffer
for( i = 0; i < ARRAYSIZE; i++ )
    lpStrArray[i] = strArray[i];

// Build a string array WDOPR
InitWCB( &wcb, TypeShort, NULL, 0 );
AddStringArray( &wcb, ArrayDef, lpStrArray, MAXLENGTH );

// Use wdCommandDispatch here

// Free allocated ArrayDef
GlobalUnlock( hArrayDef );
GlobalFree( hArrayDef );

Customizing Word with CAPILIB

A WLL function registered in Word can be called from any WordBasic macro, just like any built-in statement. You also can assign a new Word API function to
a toolbar button, menu item, or shortcut key. The proper place to make such an assignment is in the wdAutoOpen function. This function runs automatically when the WLL is loaded, making your function associations automatic. There are several wdCommandDispatch commands that let you make these assignments in a manner analogous to the way WordBasic works. Specific CAPILIB functions simplify the process even further.

Adding a Command

An add-in function registered in Word extends WordBasic and is immediately available as a new command that can be included as an instruction in any macro. Use the CAPIRegister function in CAPILIB to register your add-in function.

Note

A WLL function that requires arguments from a WordBasic macro cannot be registered in Word. This kind of function must be declared in the WordBasic macro with the WordBasic Declare statement.

Adding a Toolbar Button

The following lines of code demonstrate how a toolbar button labeled "Table," assigned to the new function MyTable, can be added to the standard toolbar using the appropriate CAPILIB function. This line of code would normally go in the wdAutoOpen function of a WLL to create the button when the WLL is loaded.


err = CAPIAddButton( DocID, "Standard", cPosition, "MyTable",
    "Table" );

A related function in CAPILIB, CAPIAddToolbar, lets you add your own toolbar, to which you can then add buttons. For example:


err = CAPIAddToolbar( DocID, "MyToolbar" );

Adding a Menu Item

You can easily add a menu item and assign a registered function to it. The CAPIAddMenuItem function in CAPILIB simplifies the process. For example, the following line of code adds a new menu item labeled "String Array Test" to the end of the File menu and assigns the function StringArray to it:


err = CAPIAddMenuItem( DocID, "File", "StringArray", "String Array
    Test", -1, 0 );

A related function, CAPIAddMenu, lets you add a new menu to the main
menu bar and assign to it a name that can be used to further build the menu
with CAPIAddMenuItem.

Adding a Shortcut Key

A registered Word API function can also be assigned to a shortcut key using
the CAPIAddKey function provided in CAPILIB. For example:


err = CAPIAddKey( DocID, KeyCode, "MyNewFunction" );

This line of code assigns the Word API function MyNewFunction to the shortcut key indicated by KeyCode in the current document. For a complete description of the various KeyCode integers, see ToolsCustomizeKeyboard in Part 2, "WordBasic Reference."