/*------------------------------------------------------------------------

  CAPILIB.C
  Library routines to support the Word's C-API     
 
------------------------------------------------------------------------*/

#include <windows.h>
#include <string.h> 
#include <stdarg.h>
#include "wdcapi.h"
#include "wdcmds.h"
#include "wdfid.h"
#include "capilib.h"
#include "config.h"

// InitWCB
// Initializes a word command buffer (WCB)
void InitWCB( WCB far *lpwcb,       // far pointer to the wcb
              ushort  retType,      // return type of the command 
              LPUCHAR lpBuffer,     // pointer to the return string (if any) 
              ushort  cBufferSize ) // size of return buffer
{
    _fmemset( lpwcb, 0, sizeof( WCB ));
    lpwcb->wdoprReturn.Type = retType;
    if (retType == TypeString)
        {
        lpwcb->wdoprReturn.String = lpBuffer;
        lpwcb->wdoprReturn.BufferSize = cBufferSize;
        }
}

// AddShortDlgField
// Adds a short dialog field to wdoprArgs
void AddShortDlgField( WCB far  *lpwcb,     // far pointer to wcb
                       short    ShortVal,   // value of short field
                       ushort   FieldId,    // dialog field ID
                       ushort   fMode )     // for input, output or both
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Short     = ShortVal;
    lpwcb->wdoprArgs[cArgs].Type      = TypeShort;
    lpwcb->wdoprArgs[cArgs].FieldId   = FieldId; 
    lpwcb->wdoprArgs[cArgs].ForInput  = fMode & INPUT;
    lpwcb->wdoprArgs[cArgs].ForOutput = (fMode & OUTPUT) ? 1 : 0; 
    lpwcb->cArgs++;
}

// AddLongDlgField
// Adds a long dialog field to wdoprArgs
void AddLongDlgField( WCB far *lpwcb,  // far pointer to wcb
                      long    LongVal, // value of long field
                      ushort  FieldId, // dialog field ID
                      ushort  fMode )  // for input, output or both
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Long      = LongVal;
    lpwcb->wdoprArgs[cArgs].Type      = TypeLong;
    lpwcb->wdoprArgs[cArgs].FieldId   = FieldId; 
    lpwcb->wdoprArgs[cArgs].ForInput  = fMode & INPUT;
    lpwcb->wdoprArgs[cArgs].ForOutput = (fMode & OUTPUT) ? 1 : 0; 
    lpwcb->cArgs++;
}

// AddDoubleDlgField
// Adds a double dialog field to wdoprArgs
void AddDoubleDlgField( WCB far *lpwcb,    // far pointer to wcb
                        double  DoubleVal, // value of double field
                        ushort  FieldId,   // dialog field ID
                        ushort  fMode )    // for input, output or both
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Double    = DoubleVal;
    lpwcb->wdoprArgs[cArgs].Type      = TypeDouble;
    lpwcb->wdoprArgs[cArgs].FieldId   = FieldId; 
    lpwcb->wdoprArgs[cArgs].ForInput  = fMode & INPUT;
    lpwcb->wdoprArgs[cArgs].ForOutput = (fMode & OUTPUT) ? 1 : 0; 
    lpwcb->cArgs++;
}

// AddStringDlgField
// Adds a string dialog field to wdoprArgs
void AddStringDlgField( WCB far *lpwcb,       // far pointer to Word Command Buffer
                        LPUCHAR lpStr,        // Pointer to the string to be passed
                        ushort  FieldId,      // Dialog Field ID
                        ushort  fMode,        // For input, output or both
                        ushort  cBufferSize ) // Size of buffer pointed by lpStr
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].String     = lpStr;
    lpwcb->wdoprArgs[cArgs].Type       = TypeString;
    lpwcb->wdoprArgs[cArgs].FieldId    = FieldId; 
    lpwcb->wdoprArgs[cArgs].ForInput   = fMode & INPUT;
    lpwcb->wdoprArgs[cArgs].ForOutput  = (fMode & OUTPUT) ? 1 : 0; 
    lpwcb->wdoprArgs[cArgs].BufferSize = cBufferSize;
    lpwcb->cArgs++;
}

// AddShortParam
// Adds a short parameter to wdoprArgs
void AddShortParam( WCB far *lpwcb,    // Pointer to Word Command Buffer
                    short   ShortVal ) // short parameter
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Short = ShortVal;
    lpwcb->wdoprArgs[cArgs].Type  = TypeShort;
    lpwcb->cArgs++;
}

// AddLongParam
// Adds a long parameter to wdoprArgs
void AddLongParam( WCB far *lpwcb,   // Pointer to Word Command Buffer
                   long    LongVal ) // long parameter
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Long = LongVal;
    lpwcb->wdoprArgs[cArgs].Type = TypeLong;
    lpwcb->cArgs++;
}

// AddDoubleParam
// Adds a double parameter to wdoprArgs
void AddDoubleParam( WCB far *lpwcb,      // Pointer to Word Command Buffer
                     double   DoubleVal ) // double parameter
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].Double = DoubleVal;
    lpwcb->wdoprArgs[cArgs].Type   = TypeDouble;
    lpwcb->cArgs++;
}

// AddStringParam
// Adds a string parameter to wdoprArgs
void AddStringParam( WCB far *lpwcb,  // Pointer to Word Command Buffer
                     LPUCHAR lpStr )  // string parameter
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].String = lpStr;
    lpwcb->wdoprArgs[cArgs].Type   = TypeString;
    lpwcb->cArgs++;
}

// CallCapi
// Set everything and make a non dialog command call
short CallCapi( WCB far *lpwcb,			// pointer to word command buffer
				short	uCmd,			// command to be called
              	ushort  retType,      	// return type of the command 
              	LPSTR	lpBuffer,		// Buffer to return return string (if any)
              	ushort	cBufferSize,	// Size of buffer pointed by lpBuffer
              	LPSTR	lpszFormat,		// Format string with argument prototype
				... )					// argument list
{ 
	va_list	marker;
	
	va_start(marker, lpszFormat);

	InitWCB( lpwcb, retType, lpBuffer, cBufferSize );
		
	while( *lpszFormat != (int) NULL )
	{
		switch( *lpszFormat )
		{
			case 'i':
				AddShortParam( lpwcb, va_arg(marker, short));
				break;
			case 'l':
				AddLongParam( lpwcb, va_arg(marker, long));
				break;
			case 'd':
				AddDoubleParam( lpwcb, va_arg(marker, double));
				break;
			case 's':
				AddStringParam( lpwcb, va_arg(marker, LPSTR));
				break;
			default: 
				return -1;
		}
		lpszFormat++;
	}

	va_end(marker);

	return wdCommandDispatch( uCmd, 0, lpwcb->cArgs, lpwcb->wdoprArgs, retType ? &( lpwcb->wdoprReturn ) : lpwdoprNil);
}

// SetArrayDef
// Sets an array definition structure.
// Returns a pointer to the ARRAY_DEF structure
ARRAY_DEF far * SetArrayDef( HANDLE far *phArrDef, // Pointer to handle to memory 
                             short cDimensions,    // Number of dimensions in the array
                             ... )                 // size of each dimension
{

	/* Va_arg requires a large memory model.	 
    * To use a small or medium memory model, define _WINDLL */

    short i;
    va_list marker;
    short far *arrDef;
    
    if( cDimensions < 1 )
        return NULL;
        
    if(( *phArrDef = GlobalAlloc( GHND, cDimensions + 1 )) == NULL )
        return NULL;
        
    arrDef = (short far *)GlobalLock( *phArrDef );
    *arrDef = cDimensions;

	va_start(marker, cDimensions);
    
    for( i = 1; i <= cDimensions; i++ )
    {
		arrDef[i] = va_arg(marker, short);
    }
        
	va_end(marker);

    return (ARRAY_DEF far *)arrDef;
}

// AddStringArray
// Adds a string array parameter to wdoprArgs
void AddStringArray( WCB       far *lpwcb,       // pointer to word command buffer
                     ARRAY_DEF far *ArrayDef,    // pointer to the array definition
                     LPUCHAR   far *lpStrArray,  // pointer to array of strings
                     ushort        cBufferSize ) // size string buffer
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].ArrayDef    = ArrayDef;
    lpwcb->wdoprArgs[cArgs].StringArray = lpStrArray;
    lpwcb->wdoprArgs[cArgs].Type        = TypeString;
    lpwcb->wdoprArgs[cArgs].IsArray     = 1;
    lpwcb->wdoprArgs[cArgs].BufferSize  = cBufferSize;
    lpwcb->cArgs++;
}

// AddDoubleArray
// Adds a double array parameter to wdoprArgs
void AddDoubleArray( WCB       far *lpwcb,       // pointer to word command buffer
                     ARRAY_DEF far *ArrayDef,    // pointer to array definition
                     double    far *lpdblArray ) // Pointer to the array
{
    short cArgs;

    cArgs = lpwcb->cArgs;
    lpwcb->wdoprArgs[cArgs].ArrayDef    = ArrayDef;
    lpwcb->wdoprArgs[cArgs].DoubleArray = lpdblArray;
    lpwcb->wdoprArgs[cArgs].Type        = TypeDouble;
    lpwcb->wdoprArgs[cArgs].IsArray     = 1;
    lpwcb->cArgs++;
}

// CAPIRegister
// Registers an exported function in Word
short CAPIRegister( short   DocID,             // Document ID
                    LPUCHAR lpszFunctionName,  // function to be registered 
                    LPUCHAR lpszDescription )  // Description for the function
{
    WCB wcb;
    
    InitWCB( &wcb, TypeShort, NULL, 0 ); 
    AddShortParam( &wcb, DocID );
    AddStringParam( &wcb, lpszFunctionName ); 
    if( lpszDescription != NULL )
    	AddStringParam( &wcb, lpszDescription ); 
    
    return wdCommandDispatch( wdAddCommand, 0, wcb.cArgs, 
                              wcb.wdoprArgs, lpwdoprNil );
}

// CAPIAddToolbar
// Creates a new toolbar in Word
short CAPIAddToolbar( short   nContext,     // Context (0, 1, or DocID)
                      LPUCHAR lpszToolbar ) // Name of new toolbar
{
    WCB wcb;
    
    InitWCB( &wcb, TypeShort, NULL, 0 );
    AddStringDlgField( &wcb, lpszToolbar, fidName, INPUT, 0 );
    AddShortDlgField( &wcb, nContext, fidContext, INPUT );
    return wdCommandDispatch( wdNewToolbar, CommandAction, wcb.cArgs, 
                              wcb.wdoprArgs, lpwdoprNil );
}

// CAPIAddButton
// Adds a new button to a Toolbar
short CAPIAddButton( short   nContext,    // Context (0, 1, or DocID)
                     LPUCHAR lpszToolbar, // Name of the toolbar
                     short   cPosition,   // Position to insert button
                     LPUCHAR lpszMacro,   // Command to assotiate with button
                     LPUCHAR lpszFace )   // face of the button (text only)
{
    WCB wcb;
    
    InitWCB( &wcb, TypeShort, NULL, 0 );
    AddStringParam( &wcb, lpszToolbar );
    AddShortParam( &wcb, cPosition );
    AddShortParam( &wcb, 1 );
    AddStringParam( &wcb, lpszMacro );
    AddStringParam( &wcb, lpszFace );
    AddShortParam( &wcb, nContext );
    
    return wdCommandDispatch( wdAddButton, 0, wcb.cArgs, 
                              wcb.wdoprArgs, lpwdoprNil );
}

// CAPIAddMenu
// Adds a new menu to the menu bar
short CAPIAddMenu( short   nContext,        // Context (0, 1, or DocID)
                   LPUCHAR lpszMenuName, // name of the menu
                   short   Position,     // position of the new menu
                   short   MenuType )    // type of menu
{
    WCB wcb;
    
    InitWCB( &wcb, TypeShort, NULL, 0 );
    AddStringDlgField( &wcb, lpszMenuName, fidMenuText, INPUT, 0 );
    AddShortDlgField( &wcb, Position, fidPosition, INPUT );
    AddShortDlgField( &wcb, 1, fidAdd, INPUT );
    AddShortDlgField( &wcb, MenuType, fidMenuType, INPUT );
    AddShortDlgField( &wcb, nContext, fidContext, INPUT );
    
    return wdCommandDispatch( wdToolsCustomizeMenuBar, CommandAction, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil );
}

// CAPIAddMenuItem
// Add a menu item to a menu
short CAPIAddMenuItem( short   nContext,     // Context (0, 1, or DocID)
                       LPUCHAR lpszMenu,     // name of the menu
                       LPUCHAR lpszName,     // command to add
                       LPUCHAR lpszMenuText, // menu item text
                       short   Position,     // positon in the menu
                       short   MenuType )    // type of the menu
{
    WCB wcb;
          
    InitWCB( &wcb, TypeShort, NULL, 0 );
    AddShortDlgField( &wcb, nContext, fidContext, INPUT ); 
    AddStringDlgField( &wcb, lpszMenu, fidMenu, INPUT, 0 );
    AddStringDlgField( &wcb, lpszName, fidName, INPUT, 0 );
    AddStringDlgField( &wcb, lpszMenuText, fidMenuText, INPUT, 0 );
    AddShortDlgField( &wcb, Position, fidPosition, INPUT );
    AddShortDlgField( &wcb, MenuType, fidMenuType, INPUT );
    AddShortDlgField( &wcb, 1, fidCategory, INPUT );
    AddShortDlgField( &wcb, 1, fidAdd, INPUT );
    
    return wdCommandDispatch( wdToolsCustomizeMenus, CommandAction, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil );
}   

// CAPIAddKey
// Assigns a key combination to a command
short CAPIAddKey( short   nContext,   // Context (0, 1, or DocID)
                  short   KeyCode,    // key combination to be set
                  LPUCHAR lpszName )  // command to assign to key
{
    WCB wcb;
    
    InitWCB( &wcb, TypeShort, NULL, 0 );
    AddShortDlgField( &wcb, KeyCode, fidKeyCode, INPUT );
    AddShortDlgField( &wcb, 1, fidCategory, INPUT );
    AddStringDlgField( &wcb, lpszName, fidName, INPUT, 0 );
    AddShortDlgField( &wcb, 1, fidAdd, INPUT );
    AddShortDlgField( &wcb, nContext, fidContext, INPUT );
    
    return wdCommandDispatch( wdToolsCustomizeKeyboard, CommandAction, wcb.cArgs, wcb.wdoprArgs, lpwdoprNil );
}   


#ifdef WIN32


static short (WINAPI *pfn_wdCommandDispatch) ();
short WINAPI wdCommandDispatch(short CommandID, // fci
						short DlgOptions, // grfDlg
						short cArgs,
						LPWDOPR lpwdoprArgs,
						LPWDOPR lpwdoprReturn)
{
	if (pfn_wdCommandDispatch == NULL)
		(FARPROC) pfn_wdCommandDispatch = GetProcAddress(GetModuleHandle(NULL), "wdCommandDispatch");
	return ((*pfn_wdCommandDispatch)(CommandID, DlgOptions, cArgs, lpwdoprArgs, lpwdoprReturn));
}

#endif
