Unofficial SmallScript FAQ

Overview

This FAQ was written by me (Chris Double) to remind me about common problems and idioms while developing with SmallScript. There is a lot of knowledge on the SmallScript newsgroups and I wanted to document them in some way so it was easier for me to look things up.

In case it proves useful to others I've published it here. If you'd like to add, modify or discuss entries please contact Chris Double.

Note that the things mentioned here only represent my understanding of the issues. Don't hold me responsible for any errors or incorrect items here.

History

V1.0 - 17 Nov 2002 - Initial Version.
V1.1 - 18 Nov 2002 - Added class library questions regarding databases, tcp/ip, and COM.

Contents

Foreign Function Interface
   How do I call functions in a DLL?
   Calling a function in a DLL that takes float or double arguments isn't working.
   How do I wrap a C struct for passing to an FFI function?
   How do I convert an FFI return value to a structure?
   How to handle FFI Functions that have pointer arguments.
   How do I convert an FFI char* to a SmallScript String?

Class Library
   Are there any libraries for accessing Databases?
   Are there any facilities for interacting with COM/ActiveX?
   Are there any TCP/IP libraries?

Foreign Function Interface

Q. How do I call functions in a DLL?

A. The simplest method is to create a namespace and use the 'dll' keyword. This will make all functions exported from your DLL available. Taking this approach you do not need to write any foreign function definitions except under special circumstances. For example:

  namespace name: OpenGL dll: opengl32
  {
  }

Calling OpenGL methods now becomes as easy as referring to the functions as if they were native SmallScript functions:

  glViewport(0, 0, 400, 400).

Q. Calling a function in a DLL that takes float or double arguments isn't working.

A. David Simmons explains the reasoning behind this in message id yvexrXdjCHA.2252@minos.QKS.COM on comp.lang.smallscript. The basic problem is that the automatic marshalling provided by SmallScript can't determine how to pass floats without a hint. So in this situation you need to create a prototype which declares how the arguments are passed. Here's an example:

    Function [<$extern>
    glColor3d(<~double>a, <~double> b, <~double> c)
    ]

The '~' tells SmallScript to ignore the type information for the purposes of multi-method dispatch which makes things a little faster. The 'double' says the value is a Float that should be marshalled by value. The '<$extern>' states the function is external and located in a DLL.

Q. How do I wrap a C struct for passing to an FFI function?

A. Create a class where the fields are 'auto struct' fields. Following the 'auto struct' you can define the fields almost exactly as they appear in the original C struct. For example:

  class name: WSAData
	fields: auto struct 
                int16  wVersion,
		int16  wHighVersion,
                char   szDescription[257],
                char   szSystemStatus[129],
                ushort iMaxSockets,
                ushort iMaxUdpDlg,
                char*  lpVendorInfo;
  {
  }

You can nest structures as required. e.g.:

  class name: PARAMDESCEX
        fields: auto struct
                uint32 cBytes,
                VARIANT varDefaultValue;
  {
  }

  class name: PARAMDESC
        fields: auto struct
                PARAMDESCEX* pparamdescex,
                uint16 wParamFlags;
  {
  }

The structure can be created using the default constructor:

  |paramdesc| := PARAMDESC().
  paramdesc.wParamFlags := 0.

Q. How do I convert an FFI return value to a structure?

A. Use the 'SetStructToAddress' method. A common idiom is to provide a structure class with a 'fromAddress:' function that does this for you. For example:

  class name: ELEMDESC
        fields: auto struct
                TYPEDESC tdesc,
                PARAMDESC paramdesc,
                uint16 filler;
  {
    Function [
    fromAddress:  anAddress
      ^__new() SetStructToAddress(anAddress,md_nsbytes)
    ]
  }

An example of using this function would be:

  [
    |elemDescResult|
    someFunction(<&>elemDescResult).
    |elemDesc| := ELEMDESC fromAddress: elemDescResult.
    stdout << elemDesc.tdesc.vt; cr.
  ]

Q. How to handle FFI Functions that have pointer arguments.

A. FFI functions that take pointers for arguments do this for a couple of reasons.

The first is to return more than one value. This is commonly done in COM interfaces where an HRESULT is the actual return value and any futher return values are assigned to arguments passed in as pointers.

The second is to act as an 'in/out' value. That is, the item passed in contains initialization data which is then written to when the functions returns to provide additional return data.

Here are a couple of SmallScript examples:

  // Returning a value
  |myInt|
  getInt(<&>myInt).
  stdout << myInt; cr.

  // Providing a structure with some data set.
  |elemDesc| := ELEMDESC().
  elemDesc.filler := 20.
  doSomething(<&>ememDesc).
  stdout << elemDesc.tdesc.vt; cr.

The '<&> ' modifier tells SmallScript that the argument is an 'in/out' parameter and should be marshalled as a pointer.

Q. How do I convert an FFI char* to a SmallScript String?

A. The following code demonstrates how to convert a char* result from an FFI call to a String or WideString:

  |ffiString|
  getName(<&>ffiString).
  |str| := LPSTR in: ffiString at: 0.

  |ffiWideString|
  getNameW(<&>ffiWideString).
  |wideStr| := (LPWSTR in: ffiString at: 0) asWideString.

Class Library

Q. Are there any libraries for accessing Databases?

A. An example ships with SmallScript that uses SQLite. Apart from this your best best may be to access your database using the FFI or COM.

Q. Are there any facilities for interacting with COM/ActiveX?

A. SmallScript has quite a bit of COM interoperatability built in. You can create and call COM components. A program, written in SmallScript, to generate wrapper code from Type Libraries is available at Chris Double's SmallScript site. Looking at the generated code from that utility will give you a good start on how to use COM from SmallScript.

Q. Are there any TCP/IP libraries?

A. A third party library exists that provides TCP, UDP and Raw sockets. It is available from the SmallScript download page but more recent versions are available from the SmallScript news group. The author is Dino Rosati.