Tech Bulletin 117: DLLs and ASPECT: PASCAL Language Specifications

Procomm Plus -- ASPECT
Revision: 1.00 (04/10/96)
Author: ???


TECHNICAL BULLETIN #117 - Rev 1.00 (7/30/96)

==============================================================================
TITLE   : DLLs and Windows ASPECT: PASCAL Language Specifications
PRODUCT : Procomm Plus 4.x, 3.x
==============================================================================

Procomm Plus implements a powerful scripting language called the Windows
ASPECT Script Language (ASPECT).  One of ASPECT's strengths is the ability to
call functions embedded in Dynamic Link Libraries (DLLs) written and compiled
outside of ASPECT.  This paper focuses on writing DLLs for ASPECT using Turbo
Pascal for Windows (TPW) from Borland International, Inc.

ASPECT TO DLL PARAMETER SEQUENCE
ASPECT generates a standard parameter block for every DLL call that it makes.
This standard parameter block has five parameters, listed in order below.
When writing a DLL to be called from ASPECT, every exported function that is
to be accessible from within ASPECT should declare these parameters:

1. [HWnd] - a handle to the Procomm Plus main window.
2. [THandle] - a handle to the instance of Procomm Plus that made the DLL
   call.
3. [pointer to array[0..9] of pointer] - a pointer to an array of pointers to
   the data elements listed as parameters on the ASPECT script line that
   called the DLL function.

4. [pointer to array[0..9] of byte] - a pointer to an array of bytes.  Byte N
   of this array describes the type of element N stored in the array of data
   elements (i.e. parameter 3).  The range of values in this array follows
   this scheme:

   Byte Value   Meaning
   ---------------------------------------------
   0            nth element is an ASPECT string
   1            nth element is an ASPECT integer
   2            nth element is an ASPECT long
   3            nth element is an ASPECT float

5. [int] - an integer containing the count of parameters provided on the
   ASPECT script line calling the DLL function

AN EXAMPLE DLL
Here is the code for a DLL with a function that generates a random number.
Under a PASCAL style, stack-based parameter passing scheme, a variable number
of parameters is not normally possible; however, ASPECT provides an
array-based parameter passing scheme as described by the parameter block
above. To demonstrate the ability to pass a variable number of parameters, the
DLL function listed below makes certain assumptions about the provided
parameters based on the number of parameters that are available:

1. If two parameters are passed to the DLL function, the first parameter holds
   a number for seeding the random-number generator and the second parameter
   will hold the return value (i.e. the random number).

2. If one parameter is passed to the DLL function, the DLL function should
   seed the random number generator using the Randomize function from the TPW
   System Unit and the parameter will hold the return value (i.e. the random
   number). Sample DLL: RANDINT.PAS library RandInt; uses WinTypes;

const
  IntegerType = 1;
  LongType = 2;
  MaxWord: Word = 65535;

type
  pdatptrary = ^tdatptrary;
  tdatptrary = array[0..9] of pointer;
  ptypptrary = ^ttypptrary;
  ttypptrary = array[0..9] of byte;

function RandomInt(PWWnd: HWnd; PWInst: THandle; PData: pdatptrary;
   PType: ptypptrary; argcnt: integer): BOOL; export;
begin
   if (argcnt < 1) then
      begin                        {at least one arg?}
         RandomInt := FALSE;        {if not, return failure to Aspect}
         exit;
      end;
   if (argcnt > 1) then
      begin
         if ((PType^[0] <> LongType) or (PType^[1] <> IntegerType)) then
            begin
               RandomInt := FALSE;    {for two args, 1=long, 2=int}
               exit;                  {if not, return failure to Aspect}
            end;
         RandSeed := PLongint(PData^[0])^;       {seed generator}
         PWord(PData^[1])^ := Random(MaxWord);   {get the random number}
      end
   else
      begin
         if (PType^[0] <> IntegerType) then
            begin

               RandomInt := False;    {for one arg, 1=int}
               exit;                  {if not, return failure to Aspect}
            end;
         Randomize;                              {seed generator with time}
         PWord(PData^[0])^ := Random(MaxWord);   {get the random number}
      end;
      RandomInt := True;             {return success to aspect}
end;

exports
   RandomInt index 1;

begin
end.

Sample ASPECT script: RANDINT.WAS:
;ASPECT script demonstrating RANDINT.DLL
integer hdll, rnum
long seed = 1060665

proc cleanup
   dllfree hdll
   exit
endproc

proc main
string DLLPATH = "C:\PROWIN\ASPECT\RANDINT.DLL" ;path to the DLL

   when userexit call cleanup              ;point to cleanup routine
   dllload DLLPATH hdll                    ;load the DLL
   if (failure)
      usermsg "dllload failed"
      exit
   endif

   ;generate a random number letting the DLL use system time as seed
   dllcall hdll "RandomInt" rNum
   if (failure)
      usermsg "RandomInt call with system time seed failed"
      cleanup()
   else
      usermsg "RandomInt with system time seed returned %u" rNum
   endif

   ;generate a random number with the our seed
   dllcall hdll "RandomInt" seed rNum
   if (failure)
      usermsg "RandomInt call with our seed failed"
      cleanup()
   else
      usermsg "RandomInt with our seed returned %u" rNum
   endif

   cleanup()
endproc

==============================================================================
   To ensure that you have the latest version of this document, compare its
   revision number to that of the same document on any of our support sites.
  This technical bulletin may be copied and distributed freely as long as it
       is distributed in its entirety and it is not distributed for profit.
           Copyright (c) 1998 Quarterdeck  All rights reserved.
==============================================================================