#pragma inline                 // via ensamblador

#include <WinTen.h>
#include <Windows.h>
#include <dos.h>
#include <ClipApi.h>


// a workaround to use Borland and Clipper on doubles

LPWORD _parnd( WORD );
void _retnd( WORD, WORD, WORD, WORD );


#define AS_PASCAL  1

#define AS_VOID    0
#define AS_BYTE    1
#define AS_CHAR    2
#define AS_WORD    3
#define AS_INT     4
#define AS_BOOL    5
#define AS_HDC     6
#define AS_LONG    7
#define AS_STRING  8
#define AS_LPSTR   9
#define AS_PTR    10
#define AS_DOUBLE 11

typedef struct
{
   FARPROC farProc;
   BYTE bType;
   BYTE bReturn;
   BYTE bParams;
   BYTE bParam[ 15 ];
} STRFUNC;

typedef void ( * FUNCPTR )( void );

//----------------------------------------------------------------------------//

CLIPPER CallDll()
{
   STRFUNC * pStrFunc = ( STRFUNC * ) _parc( 1 );
   BYTE b, bStack = 0;
   WORD wAX, wDX;
   LPWORD pDouble;

   if( ! pStrFunc->farProc )
      return;

   for( b = 0; b < pStrFunc->bParams; b++ )
   {
      switch( pStrFunc->bParam[ b ] )
      {
         case AS_BYTE:
         case AS_CHAR:
              _parni( b + 2 );
              asm push ax;
              bStack += 2;
              break;

         case AS_WORD:
         case AS_INT:
         case AS_HDC:
              _parni( b + 2 );
              asm push ax;
              bStack += 2;
              break;

         case AS_BOOL:
              _parl( b + 2 );
              asm push ax;
              bStack += 2;
              break;

         case AS_LONG:
         case AS_PTR:
              _parnl( b + 2 );
              asm push dx;
              asm push ax;
              bStack += 4;
              break;

         case AS_LPSTR:
         case AS_STRING:
              _parc( b + 2 );
              asm push dx;
              asm push ax;
              bStack += 4;
              break;

         case AS_DOUBLE:
              pDouble = _parnd( b + 2 );
              _AX = pDouble[ 3 ];
              asm push ax;
              _AX = pDouble[ 2 ];
              asm push ax;
              _AX = pDouble[ 1 ];
              asm push ax;
              _AX = pDouble[ 0 ];
              asm push ax;
              bStack += 8;
              break;
      }
   }
   ( ( FUNCPTR ) pStrFunc->farProc )();
   wAX = _AX;
   wDX = _DX;

   if( pStrFunc->bType != AS_PASCAL )
      asm add sp, bStack;

   switch( pStrFunc->bReturn )
   {
      case AS_BYTE:
      case AS_CHAR:
           _retni( wAX & 0x00FF );
           break;

      case AS_WORD:
      case AS_INT:
           _retni( wAX );
           break;

      case AS_BOOL:
           _retl( wAX );
           break;

      case AS_LONG:
      case AS_PTR:
           _retnl( ( wDX << 8 ) || wAX );
           break;

      case AS_STRING:
      case AS_LPSTR:
           _retc( ( char * ) MK_FP( wDX, wAX ) );
           break;

      case AS_DOUBLE:
           pDouble = ( LPWORD ) MK_FP( wDX, wAX );
           _retnd( pDouble[ 0 ], pDouble[ 1 ], pDouble[ 2 ], pDouble[ 3 ] );
           break;
   }
}
