Using DLLs with PANORAMIC

Dy jdebord

Introduction

In the first issue of this magazine we have presented the PANORAMIC BASIC software. Here we describe how to call functions from dynamically loaded libraries (DLL).

Rules for using DLLs with PANORAMIC

  1. The DLL is loaded in memory by the instruction dll_on "xxx.dll", where xxx.dll is the name of the library.

    When the DLL is no longer necessary, the memory can be released by the instruction dll_off

  2. The general syntax for calling a function from a DLL is:

      result% = dll_calln("DllFunctionName", par1%, ..., parn%)
    

    where n is an integer from 0 to 7 which represents the number of parameters passed to the function. There are indeed 8 different routines:

      dll_call0("DllFunctionName")
      dll_call1("DllFunctionName", par1%)
      dll_call2("DllFunctionName", par1%, par%2)
      ..........................................
    

    As you can see, the first parameter must be a string with the name of the function to be called, followed by the n parameters of the function.

    Also note that :

    • Panoramic can only call functions in a DLL, not subroutines.

    • All function parameters must be passed as integer values.

    • All function called by the call_dll routines return an integer value.

  3. By default, all function parameters are passed by value. If the DLL function requires a parameter passed by reference, the Panoramic adr() function must be used. This function may be used with simple variables of integer, string or float type.

  4. At the present development stage of PANORAMIC, no array can be passed, neither by value nor by reference via adr().

  5. Passing strings to a DLL requires some caution. Strings are stored zero byte terminated, and adr(s$) passes a pointer to the string descriptor. You can write back into the string, but you must NEVER overwrite or write past the zero byte.

  6. The called DLL function must use the stdcall convention.

  7. The DLL function names are case sensitive and must therefore be specified with the exact case of their name.

Example : a random number generator

Introduction

The goal of this example is to implement in PANORAMIC the Mersenne Twister random number generator, which is one of the most reliable.

Since this generator is the default one in FreeBASIC, we will write the DLL in this language. Of course, other languages like Pascal or C could be used.

The FreeBASIC DLL

Here is the FreeBASIC source of our DLL (file ranmt.bas):

  ' *******************************************************************
  ' Mersenne Twister random number generator
  ' *******************************************************************
  extern "Windows-MS"
  function InitMT(Seed as integer) as integer export
  ' Initialize the generator
    randomize Seed
    InitMT = 0
  end function
  function RanMT(byref X as double) as integer export
  ' Return a random real in [0, 1)
    X = rnd
    RanMT = 0
  end function
  function IRanMT as integer export
  ' Return a random integer in [-2^31, 2^31 - 1]
    IRanMT = int((rnd - 0.5) * 4294967296.0)
  end function
  function IRanMT1(N as integer) as integer export
  ' Return a random integer in [0, N]
    IRanMT1 = int(rnd * (N + 1))
  end function
  function IRanMT2(A as integer, B as integer) as integer export
  ' Return a random integer in [A, B]
    IRanMT2 = A + int(rnd * (B - A + 1))
  end function
  end extern

We can notice that:

  1. The whole code is embedded in a block delimited by:

      extern "Windows-MS"
      ...................
      end extern
    
    This is necessary to ensure that the names of the functions are not modified when they are passed to the calling program.

  2. Each function returns an integer result. When the result is not obvious, we assign the value 0 to the function, as in InitMT and RanMT.

  3. The function RanMT should return a real number, but this is not accepted by PANORAMIC in its present stage. So, we affect the result to a real parameter X which is passed by reference.

    This function should be called by PANORAMIC as follows:

      dim i%, x
      dll_on "ranmt.dll"
      i% = dll_call1("RanMT", adr(x))
      print x
      dll_off
    
  4. We did not add the stdcall keyword, since it is the default calling convention in FreeBASIC.

The DLL is compiled with:

  fbc ranmt.bas -dll

We obtain two files: ranmt.dll and libranmt.dll.a. Only the first one is necessary for our application.

The PANORAMIC program

The following program uses the DLL to simulate a dice game:

  ' ---------------------------------------------------------
  ' Simulation of dice game with khi2 test
  '
  ' The DLL RANMT provides the "Mersenne Twister" random
  ' number generator
  ' ---------------------------------------------------------
  dim f%, nt%, i%, d%, n%(6), khi2, diff
  f% = 100      : ' Expected frequency for each number
  nt% = 6 * f%  : ' Total number of runs
  dll_on "ranmt.dll"
  ' Initialize random number generator
  ' (try different values)
  i% = dll_call1("InitMT", 123456789)
  ' Do nt% runs
  ' Each number should appear about f% times
  for i% = 1 to nt%
    d% = dll_call2("IRanMT2", 1, 6)
    n%(d%) = n%(d%) + 1
  next i%
  dll_off
  ' Compute khi2
  khi2 = 0
  for i% = 1 to 6
    diff = n%(i%) - f%
    khi2 = khi2 + diff * diff / f%
  next i%
  ' Display results
  print "Simulation of dice game"
  print "-----------------------"
  print
  for i% = 1 to 6
    print "Frequency of "; i%; " = "; n%(i%)
  next i%
  print
  print "khi2 = "; khi2
  end

The comparison between the observed frequency for each number and the expected frequency is performed by a χ² (khi2) test:

χ² = Σi=1..p (Oi - Ci)² / Ci

where p denotes the number of classes, Oi and Ci the observed and calculated (expected) frequencies, respectively. In our case, p = 6, Oi = n%(i%) and Ci = f%.

This sum has p - 1 = 5 degrees of freedom. In these conditions, the critical value of χ² having a 95% probability of being exceeded is 11.07

Results

Running the previous program in the PANORAMIC editor gives the following results:

  Simulation of dice game
  -----------------------
  
  Frequency of 1 = 98
  Frequency of 2 = 122
  Frequency of 3 = 97
  Frequency of 4 = 96
  Frequency of 5 = 81
  Frequency of 6 = 106
  
  khi2 = 9.1

The observed frequencies differ from the theoretical one, but the low χ² value shows that these differences are not statistically significant.

It is recommended to run the program with different initializations and increasing values of f%.

Conclusion

In spite of some limitations, which are likely to be overcome in the near future, the use of DLLs is an easy way to enhance the possibilities of the PANORAMIC language.

Acknowledgements

Once again, I would like to express my gratitude to the members of the french PANORAMIC forum especially:

  • Klaus, for writing the first version of the PANORAMIC calling rules. Klaus also provides his own DLLs on his web site.

  • D. J. Peters, for helpful advice on how to write the FreeBASIC code.

Powered by CMSimple | CMSimple Legal Notices | (X)html | css | Login | Template-Design: Lars Ellmauer | Template-Modified: Imortisoft ISD